Project import
diff --git a/libbrillo/.clang-format b/libbrillo/.clang-format
new file mode 120000
index 0000000..f412743
--- /dev/null
+++ b/libbrillo/.clang-format
@@ -0,0 +1 @@
+../../build/tools/brillo-clang-format
\ No newline at end of file
diff --git a/libbrillo/Android.mk b/libbrillo/Android.mk
new file mode 100644
index 0000000..c7d2a29
--- /dev/null
+++ b/libbrillo/Android.mk
@@ -0,0 +1,408 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Default values for the USE flags. Override these USE flags from your product
+# by setting BRILLO_USE_* values. Note that we define local variables like
+# local_use_* to prevent leaking our default setting for other packages.
+local_use_dbus := $(if $(BRILLO_USE_DBUS),$(BRILLO_USE_DBUS),1)
+
+LOCAL_PATH := $(call my-dir)
+
+libbrillo_cpp_extension := .cc
+libbrillo_core_sources := \
+    brillo/backoff_entry.cc \
+    brillo/data_encoding.cc \
+    brillo/errors/error.cc \
+    brillo/errors/error_codes.cc \
+    brillo/flag_helper.cc \
+    brillo/key_value_store.cc \
+    brillo/message_loops/base_message_loop.cc \
+    brillo/message_loops/message_loop.cc \
+    brillo/message_loops/message_loop_utils.cc \
+    brillo/mime_utils.cc \
+    brillo/osrelease_reader.cc \
+    brillo/process.cc \
+    brillo/process_information.cc \
+    brillo/secure_blob.cc \
+    brillo/strings/string_utils.cc \
+    brillo/syslog_logging.cc \
+    brillo/type_name_undecorate.cc \
+    brillo/url_utils.cc \
+    brillo/userdb_utils.cc \
+    brillo/value_conversion.cc \
+
+libbrillo_linux_sources := \
+    brillo/asynchronous_signal_handler.cc \
+    brillo/daemons/daemon.cc \
+    brillo/file_utils.cc \
+    brillo/process_reaper.cc \
+
+libbrillo_binder_sources := \
+    brillo/binder_watcher.cc \
+
+libbrillo_dbus_sources := \
+    brillo/any.cc \
+    brillo/daemons/dbus_daemon.cc \
+    brillo/dbus/async_event_sequencer.cc \
+    brillo/dbus/data_serialization.cc \
+    brillo/dbus/dbus_connection.cc \
+    brillo/dbus/dbus_method_invoker.cc \
+    brillo/dbus/dbus_method_response.cc \
+    brillo/dbus/dbus_object.cc \
+    brillo/dbus/dbus_service_watcher.cc \
+    brillo/dbus/dbus_signal.cc \
+    brillo/dbus/exported_object_manager.cc \
+    brillo/dbus/exported_property_set.cc \
+    brillo/dbus/utils.cc \
+
+libbrillo_http_sources := \
+    brillo/http/curl_api.cc \
+    brillo/http/http_connection_curl.cc \
+    brillo/http/http_form_data.cc \
+    brillo/http/http_request.cc \
+    brillo/http/http_transport.cc \
+    brillo/http/http_transport_curl.cc \
+    brillo/http/http_utils.cc \
+
+libbrillo_policy_sources := \
+    policy/device_policy.cc \
+    policy/libpolicy.cc \
+
+libbrillo_stream_sources := \
+    brillo/streams/file_stream.cc \
+    brillo/streams/input_stream_set.cc \
+    brillo/streams/memory_containers.cc \
+    brillo/streams/memory_stream.cc \
+    brillo/streams/openssl_stream_bio.cc \
+    brillo/streams/stream.cc \
+    brillo/streams/stream_errors.cc \
+    brillo/streams/stream_utils.cc \
+    brillo/streams/tls_stream.cc \
+
+libbrillo_test_helpers_sources := \
+    brillo/http/http_connection_fake.cc \
+    brillo/http/http_transport_fake.cc \
+    brillo/message_loops/fake_message_loop.cc \
+    brillo/streams/fake_stream.cc \
+    brillo/unittest_utils.cc \
+
+libbrillo_test_sources := \
+    brillo/asynchronous_signal_handler_unittest.cc \
+    brillo/backoff_entry_unittest.cc \
+    brillo/data_encoding_unittest.cc \
+    brillo/errors/error_codes_unittest.cc \
+    brillo/errors/error_unittest.cc \
+    brillo/file_utils_unittest.cc \
+    brillo/flag_helper_unittest.cc \
+    brillo/http/http_connection_curl_unittest.cc \
+    brillo/http/http_form_data_unittest.cc \
+    brillo/http/http_request_unittest.cc \
+    brillo/http/http_transport_curl_unittest.cc \
+    brillo/http/http_utils_unittest.cc \
+    brillo/key_value_store_unittest.cc \
+    brillo/map_utils_unittest.cc \
+    brillo/message_loops/base_message_loop_unittest.cc \
+    brillo/message_loops/fake_message_loop_unittest.cc \
+    brillo/mime_utils_unittest.cc \
+    brillo/osrelease_reader_unittest.cc \
+    brillo/process_reaper_unittest.cc \
+    brillo/process_unittest.cc \
+    brillo/secure_blob_unittest.cc \
+    brillo/streams/fake_stream_unittest.cc \
+    brillo/streams/file_stream_unittest.cc \
+    brillo/streams/input_stream_set_unittest.cc \
+    brillo/streams/memory_containers_unittest.cc \
+    brillo/streams/memory_stream_unittest.cc \
+    brillo/streams/openssl_stream_bio_unittests.cc \
+    brillo/streams/stream_unittest.cc \
+    brillo/streams/stream_utils_unittest.cc \
+    brillo/strings/string_utils_unittest.cc \
+    brillo/type_name_undecorate_unittest.cc \
+    brillo/unittest_utils.cc \
+    brillo/url_utils_unittest.cc \
+    brillo/value_conversion_unittest.cc \
+
+libbrillo_dbus_test_sources := \
+    brillo/any_unittest.cc \
+    brillo/any_internal_impl_unittest.cc \
+    brillo/dbus/async_event_sequencer_unittest.cc \
+    brillo/dbus/data_serialization_unittest.cc \
+    brillo/dbus/dbus_method_invoker_unittest.cc \
+    brillo/dbus/dbus_object_unittest.cc \
+    brillo/dbus/dbus_param_reader_unittest.cc \
+    brillo/dbus/dbus_param_writer_unittest.cc \
+    brillo/dbus/dbus_signal_handler_unittest.cc \
+    brillo/dbus/exported_object_manager_unittest.cc \
+    brillo/dbus/exported_property_set_unittest.cc \
+    brillo/variant_dictionary_unittest.cc \
+
+libbrillo_CFLAGS := \
+    -Wall \
+    -Werror \
+    -DUSE_DBUS=$(local_use_dbus)
+libbrillo_CPPFLAGS :=
+libbrillo_includes :=
+libbrillo_shared_libraries := libchrome
+
+# Shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo
+LOCAL_SRC_FILES := $(libbrillo_core_sources) $(libbrillo_linux_sources)
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries)
+LOCAL_STATIC_LIBRARIES := libmodpb64 libgtest_prod
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared binder library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo-binder
+LOCAL_SRC_FILES := $(libbrillo_binder_sources)
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_SHARED_LIBRARIES := \
+    $(libbrillo_shared_libraries) \
+    libbinder \
+    libbrillo \
+    libutils
+LOCAL_STATIC_LIBRARIES := libgtest_prod
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_SHARED_LIBRARY)
+
+ifeq ($(local_use_dbus),1)
+
+# Shared dbus library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo-dbus
+LOCAL_SRC_FILES := $(libbrillo_dbus_sources)
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
+    libchrome-dbus libdbus
+LOCAL_STATIC_LIBRARIES := libgtest_prod
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) external/dbus
+include $(BUILD_SHARED_LIBRARY)
+
+endif  # local_use_dbus == 1
+
+# Shared minijail library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo-minijail
+LOCAL_SRC_FILES := brillo/minijail/minijail.cc \
+
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
+    libminijail
+LOCAL_STATIC_LIBRARIES := libgtest_prod
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared stream library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo-stream
+LOCAL_SRC_FILES := $(libbrillo_stream_sources)
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
+    libcrypto libssl
+LOCAL_STATIC_LIBRARIES := libgtest_prod
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared http library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo-http
+LOCAL_SRC_FILES := $(libbrillo_http_sources)
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
+    libbrillo-stream libcurl
+LOCAL_STATIC_LIBRARIES := libgtest_prod
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared policy library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo-policy
+LOCAL_SRC_FILES := $(libbrillo_policy_sources)
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries)
+LOCAL_STATIC_LIBRARIES := libgtest_prod
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_SHARED_LIBRARY)
+
+# Static library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo
+LOCAL_SRC_FILES := $(libbrillo_core_sources) $(libbrillo_linux_sources)
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_STATIC_LIBRARIES := $(libbrillo_shared_libraries) libmodpb64 libgtest_prod
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := $(LOCAL_STATIC_LIBRARIES)
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_STATIC_LIBRARY)
+
+# Static stream library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo-stream
+LOCAL_SRC_FILES := $(libbrillo_stream_sources)
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_STATIC_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
+    libcrypto libssl libgtest_prod
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := $(LOCAL_STATIC_LIBRARIES)
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_STATIC_LIBRARY)
+
+# Static test-helpers library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo-test-helpers
+LOCAL_SRC_FILES := $(libbrillo_test_helpers_sources)
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_STATIC_LIBRARIES := libgtest libgmock
+LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo libcurl \
+    libbrillo-http libbrillo-stream libcrypto
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -Wno-sign-compare
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_STATIC_LIBRARY)
+
+# Shared library for host
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo
+LOCAL_SRC_FILES := $(libbrillo_core_sources)
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries)
+LOCAL_STATIC_LIBRARIES := libmodpb64 libgtest_prod
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := \
+    -D__ANDROID_HOST__ \
+    $(libbrillo_CPPFLAGS)
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+ifeq ($(HOST_OS),linux)
+
+# Shared stream library for host
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo-stream
+LOCAL_SRC_FILES := $(libbrillo_stream_sources)
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
+    libcrypto libssl
+LOCAL_STATIC_LIBRARIES := libgtest_prod
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+# Shared http library for host
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo-http
+LOCAL_SRC_FILES := $(libbrillo_http_sources)
+LOCAL_C_INCLUDES := $(libbrillo_includes)
+LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \
+    libbrillo-stream libcurl-host
+LOCAL_STATIC_LIBRARIES := libgtest_prod
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS)
+LOCAL_CLANG := true
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+endif  # HOST_OS == linux
+
+# Unit tests.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(libbrillo_cpp_extension)
+LOCAL_MODULE := libbrillo_test
+LOCAL_MODULE_CLASS := NATIVE_TESTS
+generated_sources_dir := $(call local-generated-sources-dir)
+LOCAL_SRC_FILES := $(libbrillo_test_sources)
+LOCAL_C_INCLUDES := \
+    $(libbrillo_includes) \
+
+LOCAL_STATIC_LIBRARIES := libgtest libchrome_test_helpers \
+    libbrillo-test-helpers libgmock libBionicGtestMain
+LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo libcurl \
+    libbrillo-http libbrillo-stream libcrypto
+ifeq ($(local_use_dbus),1)
+LOCAL_SRC_FILES += $(libbrillo_dbus_test_sources)
+LOCAL_STATIC_LIBRARIES += libchrome_dbus_test_helpers
+LOCAL_SHARED_LIBRARIES += libbrillo-dbus libchrome-dbus libdbus
+endif  # local_use_dbus == 1
+LOCAL_CFLAGS := $(libbrillo_CFLAGS)
+LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -Wno-sign-compare
+LOCAL_CLANG := true
+include $(BUILD_NATIVE_TEST)
+
+# Run unit tests on target
+# ========================================================
+# We su shell because process tests try setting "illegal"
+# uid/gids and expecting failures, but root can legally
+# set those to any value.
+runtargettests: libbrillo_test
+	adb sync
+	adb shell su shell /data/nativetest/libbrillo_test/libbrillo_test
diff --git a/libbrillo/MODULE_LICENSE_BSD b/libbrillo/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libbrillo/MODULE_LICENSE_BSD
diff --git a/libbrillo/NOTICE b/libbrillo/NOTICE
new file mode 100644
index 0000000..b9e779f
--- /dev/null
+++ b/libbrillo/NOTICE
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/libbrillo/OWNERS b/libbrillo/OWNERS
new file mode 100644
index 0000000..8a548e2
--- /dev/null
+++ b/libbrillo/OWNERS
@@ -0,0 +1,4 @@
+set noparent
+avakulenko@chromium.org
+derat@chromium.org
+vapier@chromium.org
diff --git a/libbrillo/brillo/any.cc b/libbrillo/brillo/any.cc
new file mode 100644
index 0000000..f84badf
--- /dev/null
+++ b/libbrillo/brillo/any.cc
@@ -0,0 +1,79 @@
+// Copyright 2014 The Chromium OS 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 <brillo/any.h>
+
+#include <algorithm>
+
+namespace brillo {
+
+Any::Any() {
+}
+
+Any::Any(const Any& rhs) : data_buffer_(rhs.data_buffer_) {
+}
+
+// NOLINTNEXTLINE(build/c++11)
+Any::Any(Any&& rhs) : data_buffer_(std::move(rhs.data_buffer_)) {
+}
+
+Any::~Any() {
+}
+
+Any& Any::operator=(const Any& rhs) {
+  data_buffer_ = rhs.data_buffer_;
+  return *this;
+}
+
+// NOLINTNEXTLINE(build/c++11)
+Any& Any::operator=(Any&& rhs) {
+  data_buffer_ = std::move(rhs.data_buffer_);
+  return *this;
+}
+
+bool Any::operator==(const Any& rhs) const {
+  // Make sure both objects contain data of the same type.
+  if (strcmp(GetTypeTagInternal(), rhs.GetTypeTagInternal()) != 0)
+    return false;
+
+  if (IsEmpty())
+    return true;
+
+  return data_buffer_.GetDataPtr()->CompareEqual(rhs.data_buffer_.GetDataPtr());
+}
+
+const char* Any::GetTypeTagInternal() const {
+  if (!IsEmpty())
+    return data_buffer_.GetDataPtr()->GetTypeTag();
+
+  return "";
+}
+
+void Any::Swap(Any& other) {
+  std::swap(data_buffer_, other.data_buffer_);
+}
+
+bool Any::IsEmpty() const {
+  return data_buffer_.IsEmpty();
+}
+
+void Any::Clear() {
+  data_buffer_.Clear();
+}
+
+bool Any::IsConvertibleToInteger() const {
+  return !IsEmpty() && data_buffer_.GetDataPtr()->IsConvertibleToInteger();
+}
+
+intmax_t Any::GetAsInteger() const {
+  CHECK(!IsEmpty()) << "Must not be called on an empty Any";
+  return data_buffer_.GetDataPtr()->GetAsInteger();
+}
+
+void Any::AppendToDBusMessageWriter(dbus::MessageWriter* writer) const {
+  CHECK(!IsEmpty()) << "Must not be called on an empty Any";
+  data_buffer_.GetDataPtr()->AppendToDBusMessage(writer);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/any.h b/libbrillo/brillo/any.h
new file mode 100644
index 0000000..51016b5
--- /dev/null
+++ b/libbrillo/brillo/any.h
@@ -0,0 +1,214 @@
+// Copyright 2014 The Chromium OS 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 is an implementation of a "true" variant class in C++.
+// The brillo::Any class can hold any C++ type, but both the setter and
+// getter sites need to know the actual type of data.
+// Note that C-style arrays when stored in Any are reduced to simple
+// data pointers. Any will not copy a contents of the array.
+//    const int data[] = [1,2,3];
+//    Any v(data);  // stores const int*, effectively "Any v(&data[0]);"
+
+// brillo::Any is a value type. Which means, the data is copied into it
+// and Any owns it. The owned object (stored by value) will be destroyed
+// when Any is cleared or reassigned. The contained value type must be
+// copy-constructible. You can also store pointers and references to objects.
+// Storing pointers is trivial. In order to store a reference, you can
+// use helper functions std::ref() and std::cref() to create non-const and
+// const references respectively. In such a case, the type of contained data
+// will be std::reference_wrapper<T>. See 'References' unit tests in
+// any_unittest.cc for examples.
+
+#ifndef LIBBRILLO_BRILLO_ANY_H_
+#define LIBBRILLO_BRILLO_ANY_H_
+
+#include <brillo/any_internal_impl.h>
+
+#include <algorithm>
+
+#include <brillo/brillo_export.h>
+#include <brillo/type_name_undecorate.h>
+
+namespace dbus {
+class MessageWriter;
+}  // namespace dbus
+
+namespace brillo {
+
+class BRILLO_EXPORT Any final {
+ public:
+  Any();  // Do not inline to hide internal_details::Buffer from export table.
+  // Standard copy/move constructors. This is a value-class container
+  // that must be copy-constructible and movable. The copy constructors
+  // should not be marked as explicit.
+  Any(const Any& rhs);
+  Any(Any&& rhs);  // NOLINT(build/c++11)
+  // Typed constructor that stores a value of type T in the Any.
+  template<class T>
+  inline Any(T value) {  // NOLINT(runtime/explicit)
+    data_buffer_.Assign(std::move(value));
+  }
+
+  // Not declaring the destructor as virtual since this is a sealed class
+  // and there is no need to introduce a virtual table to it.
+  ~Any();
+
+  // Assignment operators.
+  Any& operator=(const Any& rhs);
+  Any& operator=(Any&& rhs);  // NOLINT(build/c++11)
+  template<class T>
+  inline Any& operator=(T value) {
+    data_buffer_.Assign(std::move(value));
+    return *this;
+  }
+
+  // Compares the contents of two Any objects for equality. Note that the
+  // contained type must be equality-comparable (must have operator== defined).
+  // If operator==() is not available for contained type, comparison operation
+  // always returns false (as if the data were different).
+  bool operator==(const Any& rhs) const;
+  inline bool operator!=(const Any& rhs) const { return !operator==(rhs); }
+
+  // Checks if the given type DestType can be obtained from the Any.
+  // For example, to check if Any has a 'double' value in it:
+  //  any.IsTypeCompatible<double>()
+  template<typename DestType>
+  bool IsTypeCompatible() const {
+    // Make sure the requested type DestType conforms to the storage
+    // requirements of Any. We always store the data by value, which means we
+    // strip away any references as well as cv-qualifiers. So, if the user
+    // stores "const int&", we actually store just an "int".
+    // When calling IsTypeCompatible, we need to do a similar "type cleansing"
+    // to make sure the requested type matches the type of data actually stored,
+    // so this "canonical" type is used for type checking below.
+    using CanonicalDestType = typename std::decay<DestType>::type;
+    const char* contained_type = GetTypeTagInternal();
+    if (strcmp(GetTypeTag<CanonicalDestType>(), contained_type) == 0)
+      return true;
+
+    if (!std::is_pointer<CanonicalDestType>::value)
+      return false;
+
+    // If asking for a const pointer from a variant containing non-const
+    // pointer, still satisfy the request. So, we need to remove the pointer
+    // specification first, then strip the const/volatile qualifiers, then
+    // re-add the pointer back, so "const int*" would become "int*".
+    using NonPointer = typename std::remove_pointer<CanonicalDestType>::type;
+    using CanonicalDestTypeNoConst = typename std::add_pointer<
+        typename std::remove_const<NonPointer>::type>::type;
+    if (strcmp(GetTypeTag<CanonicalDestTypeNoConst>(), contained_type) == 0)
+      return true;
+
+    using CanonicalDestTypeNoVolatile = typename std::add_pointer<
+        typename std::remove_volatile<NonPointer>::type>::type;
+    if (strcmp(GetTypeTag<CanonicalDestTypeNoVolatile>(), contained_type) == 0)
+      return true;
+
+    using CanonicalDestTypeNoConstOrVolatile = typename std::add_pointer<
+        typename std::remove_cv<NonPointer>::type>::type;
+    return strcmp(GetTypeTag<CanonicalDestTypeNoConstOrVolatile>(),
+                  contained_type) == 0;
+  }
+
+  // Returns immutable data contained in Any.
+  // Aborts if Any doesn't contain a value of type T, or trivially
+  // convertible to/compatible with it.
+  template<typename T>
+  const T& Get() const {
+    CHECK(IsTypeCompatible<T>())
+        << "Requesting value of type '" << brillo::GetUndecoratedTypeName<T>()
+        << "' from variant containing '" << GetUndecoratedTypeName()
+        << "'";
+    return data_buffer_.GetData<T>();
+  }
+
+  // Returns a copy of data in Any and returns true when that data is
+  // compatible with T.  Returns false if contained data is incompatible.
+  template<typename T>
+  bool GetValue(T* value) const {
+    if (!IsTypeCompatible<T>()) {
+      return false;
+    }
+    *value = Get<T>();
+    return true;
+  }
+
+  // Returns a pointer to mutable value of type T contained within Any.
+  // No data copying is made, the data pointed to is still owned by Any.
+  // If Any doesn't contain a value of type T, or trivially
+  // convertible/compatible to/with it, then it returns nullptr.
+  template<typename T>
+  T* GetPtr() {
+    if (!IsTypeCompatible<T>())
+      return nullptr;
+    return &(data_buffer_.GetData<T>());
+  }
+
+  // Returns a copy of the data contained in Any.
+  // If the Any doesn't contain a compatible value, the provided default
+  // |def_val| is returned instead.
+  template<typename T>
+  T TryGet(typename std::decay<T>::type const& def_val) const {
+    if (!IsTypeCompatible<T>())
+      return def_val;
+    return data_buffer_.GetData<T>();
+  }
+
+  // A convenience specialization of the above function where the default
+  // value of type T is returned in case the underlying Get() fails.
+  template<typename T>
+  T TryGet() const {
+    return TryGet<T>(typename std::decay<T>::type());
+  }
+
+  // Returns the undecorated name of the type contained within Any.
+  inline std::string GetUndecoratedTypeName() const {
+    return GetUndecoratedTypeNameForTag(GetTypeTagInternal());
+  }
+  // Swaps the value of this object with that of |other|.
+  void Swap(Any& other);
+  // Checks if Any is empty, that is, not containing a value of any type.
+  bool IsEmpty() const;
+  // Clears the Any and destroys any contained object. Makes it empty.
+  void Clear();
+  // Checks if Any contains a type convertible to integer.
+  // Any type that match std::is_integral<T> and std::is_enum<T> is accepted.
+  // That includes signed and unsigned char, short, int, long, etc as well as
+  // 'bool' and enumerated types.
+  // For 'integer' type, you can call GetAsInteger to do implicit type
+  // conversion to intmax_t.
+  bool IsConvertibleToInteger() const;
+  // For integral types and enums contained in the Any, get the integer value
+  // of data. This is a useful function to obtain an integer value when
+  // any can possibly have unspecified integer, such as 'short', 'unsigned long'
+  // and so on.
+  intmax_t GetAsInteger() const;
+  // Writes the contained data to D-Bus message writer, if the appropriate
+  // serialization method for contained data of the given type is provided
+  // (an appropriate specialization of AppendValueToWriter<T>() is available).
+  // Returns false if the Any is empty or if there is no serialization method
+  // defined for the contained data.
+  void AppendToDBusMessageWriter(dbus::MessageWriter* writer) const;
+
+ private:
+  // Returns a pointer to a static buffer containing type tag (sort of a type
+  // name) of the contained value.
+  const char* GetTypeTagInternal() const;
+
+  // The data buffer for contained object.
+  internal_details::Buffer data_buffer_;
+};
+
+}  // namespace brillo
+
+namespace std {
+
+// Specialize std::swap() algorithm for brillo::Any class.
+inline void swap(brillo::Any& lhs, brillo::Any& rhs) {
+  lhs.Swap(rhs);
+}
+
+}  // namespace std
+
+#endif  // LIBBRILLO_BRILLO_ANY_H_
diff --git a/libbrillo/brillo/any_internal_impl.h b/libbrillo/brillo/any_internal_impl.h
new file mode 100644
index 0000000..9309f5d
--- /dev/null
+++ b/libbrillo/brillo/any_internal_impl.h
@@ -0,0 +1,374 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Internal implementation of brillo::Any class.
+
+#ifndef LIBBRILLO_BRILLO_ANY_INTERNAL_IMPL_H_
+#define LIBBRILLO_BRILLO_ANY_INTERNAL_IMPL_H_
+
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
+
+#include <base/logging.h>
+#include <brillo/dbus/data_serialization.h>
+#include <brillo/type_name_undecorate.h>
+
+namespace brillo {
+
+namespace internal_details {
+
+// An extension to std::is_convertible to allow conversion from an enum to
+// an integral type which std::is_convertible does not indicate as supported.
+template <typename From, typename To>
+struct IsConvertible
+    : public std::integral_constant<
+          bool,
+          std::is_convertible<From, To>::value ||
+              (std::is_enum<From>::value && std::is_integral<To>::value)> {};
+
+// TryConvert is a helper function that does a safe compile-time conditional
+// type cast between data types that may not be always convertible.
+// From and To are the source and destination types.
+// The function returns true if conversion was possible/successful.
+template <typename From, typename To>
+inline typename std::enable_if<IsConvertible<From, To>::value, bool>::type
+TryConvert(const From& in, To* out) {
+  *out = static_cast<To>(in);
+  return true;
+}
+template <typename From, typename To>
+inline typename std::enable_if<!IsConvertible<From, To>::value, bool>::type
+TryConvert(const From& /* in */, To* /* out */) {
+  return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Provide a way to compare values of unspecified types without compiler errors
+// when no operator==() is provided for a given type. This is important to
+// allow Any class to have operator==(), yet still allowing arbitrary types
+// (not necessarily comparable) to be placed inside Any without resulting in
+// compile-time error.
+//
+// We achieve this in two ways. First, we provide a IsEqualityComparable<T>
+// class that can be used in compile-time conditions to determine if there is
+// operator==() defined that takes values of type T (or which can be implicitly
+// converted to type T). Secondly, this allows us to specialize a helper
+// compare function EqCompare<T>(v1, v2) to use operator==() for types that
+// are comparable, and just return false for those that are not.
+//
+// IsEqualityComparableHelper<T> is a helper class for implementing an
+// an STL-compatible IsEqualityComparable<T> containing a Boolean member |value|
+// which evaluates to true for comparable types and false otherwise.
+template<typename T>
+struct IsEqualityComparableHelper {
+  struct IntWrapper {
+    // A special structure that provides a constructor that takes an int.
+    // This way, an int argument passed to a function will be favored over
+    // IntWrapper when both overloads are provided.
+    // Also this constructor must NOT be explicit.
+    // NOLINTNEXTLINE(runtime/explicit)
+    // NOLINT: Allow implicit conversion from int.
+    IntWrapper(int /* dummy */) {}  // do nothing, NOLINT
+  };
+
+  // Here is an obscure trick to determine if a type U has operator==().
+  // We are providing two function prototypes for TriggerFunction. One that
+  // takes an argument of type IntWrapper (which is implicitly convertible from
+  // an int), and returns an std::false_type. This is a fall-back mechanism.
+  template<typename U>
+  static std::false_type TriggerFunction(IntWrapper dummy);
+
+  // The second overload of TriggerFunction takes an int (explicitly) and
+  // returns std::true_type. If both overloads are available, this one will be
+  // chosen when referencing it as TriggerFunction(0), since it is a better
+  // (more specific) match.
+  //
+  // However this overload is available only for types that support operator==.
+  // This is achieved by employing SFINAE mechanism inside a template function
+  // overload that refers to operator==() for two values of types U&. This is
+  // used inside decltype(), so no actual code is executed. If the types
+  // are not comparable, reference to "==" would fail and the compiler will
+  // simply ignore this overload due to SFIANE.
+  //
+  // The final little trick used here is the reliance on operator comma inside
+  // the decltype() expression. The result of the expression is always
+  // std::true_type(). The expression on the left of comma is just evaluated and
+  // discarded. If it evaluates successfully (i.e. the type has operator==), the
+  // return value of the function is set to be std::true_value. If it fails,
+  // the whole function prototype is discarded and is not available in the
+  // IsEqualityComparableHelper<T> class.
+  //
+  // Here we use std::declval<U&>() to make sure we have operator==() that takes
+  // lvalue references to type U which is not necessarily default-constructible.
+  template<typename U>
+  static decltype((std::declval<U&>() == std::declval<U&>()), std::true_type())
+  TriggerFunction(int dummy);
+
+  // Finally, use the return type of the overload of TriggerFunction that
+  // matches the argument (int) to be aliased to type |type|. If T is
+  // comparable, there will be two overloads and the more specific (int) will
+  // be chosen which returns std::true_value. If the type is non-comparable,
+  // there will be only one version of TriggerFunction available which
+  // returns std::false_value.
+  using type = decltype(TriggerFunction<T>(0));
+};
+
+// IsEqualityComparable<T> is simply a class that derives from either
+// std::true_value, if type T is comparable, or from std::false_value, if the
+// type is non-comparable. We just use |type| alias from
+// IsEqualityComparableHelper<T> as the base class.
+template<typename T>
+struct IsEqualityComparable : IsEqualityComparableHelper<T>::type {};
+
+// EqCompare() overload for non-comparable types. Always returns false.
+template<typename T>
+inline typename std::enable_if<!IsEqualityComparable<T>::value, bool>::type
+EqCompare(const T& /* v1 */, const T& /* v2 */) {
+  return false;
+}
+
+// EqCompare overload for comparable types. Calls operator==(v1, v2) to compare.
+template<typename T>
+inline typename std::enable_if<IsEqualityComparable<T>::value, bool>::type
+EqCompare(const T& v1, const T& v2) {
+  return (v1 == v2);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Buffer;  // Forward declaration of data buffer container.
+
+// Abstract base class for contained variant data.
+struct Data {
+  virtual ~Data() {}
+  // Returns the type tag (name) for the contained data.
+  virtual const char* GetTypeTag() const = 0;
+  // Copies the contained data to the output |buffer|.
+  virtual void CopyTo(Buffer* buffer) const = 0;
+  // Moves the contained data to the output |buffer|.
+  virtual void MoveTo(Buffer* buffer) = 0;
+  // Checks if the contained data is an integer type (not necessarily an 'int').
+  virtual bool IsConvertibleToInteger() const = 0;
+  // Gets the contained integral value as an integer.
+  virtual intmax_t GetAsInteger() const = 0;
+  // Writes the contained value to the D-Bus message buffer.
+  virtual void AppendToDBusMessage(dbus::MessageWriter* writer) const = 0;
+  // Compares if the two data containers have objects of the same value.
+  virtual bool CompareEqual(const Data* other_data) const = 0;
+};
+
+// Concrete implementation of variant data of type T.
+template<typename T>
+struct TypedData : public Data {
+  explicit TypedData(const T& value) : value_(value) {}
+  // NOLINTNEXTLINE(build/c++11)
+  explicit TypedData(T&& value) : value_(std::move(value)) {}
+
+  const char* GetTypeTag() const override { return brillo::GetTypeTag<T>(); }
+  void CopyTo(Buffer* buffer) const override;
+  void MoveTo(Buffer* buffer) override;
+  bool IsConvertibleToInteger() const override {
+    return std::is_integral<T>::value || std::is_enum<T>::value;
+  }
+  intmax_t GetAsInteger() const override {
+    intmax_t int_val = 0;
+    bool converted = TryConvert(value_, &int_val);
+    CHECK(converted) << "Unable to convert value of type '"
+                     << GetUndecoratedTypeName<T>() << "' to integer";
+    return int_val;
+  }
+
+  template<typename U>
+  static typename std::enable_if<dbus_utils::IsTypeSupported<U>::value>::type
+  AppendValueHelper(dbus::MessageWriter* writer, const U& value) {
+    brillo::dbus_utils::AppendValueToWriterAsVariant(writer, value);
+  }
+  template<typename U>
+  static typename std::enable_if<!dbus_utils::IsTypeSupported<U>::value>::type
+  AppendValueHelper(dbus::MessageWriter* /* writer */, const U& /* value */) {
+    LOG(FATAL) << "Type '" << GetUndecoratedTypeName<U>()
+               << "' is not supported by D-Bus";
+  }
+
+  void AppendToDBusMessage(dbus::MessageWriter* writer) const override {
+    return AppendValueHelper(writer, value_);
+  }
+
+  bool CompareEqual(const Data* other_data) const override {
+    return EqCompare<T>(value_,
+                        static_cast<const TypedData<T>*>(other_data)->value_);
+  }
+
+  // Special methods to copy/move data of the same type
+  // without reallocating the buffer.
+  void FastAssign(const T& source) { value_ = source; }
+  // NOLINTNEXTLINE(build/c++11)
+  void FastAssign(T&& source) { value_ = std::move(source); }
+
+  T value_;
+};
+
+// Buffer class that stores the contained variant data.
+// To improve performance and reduce memory fragmentation, small variants
+// are stored in pre-allocated memory buffers that are part of the Any class.
+// If the memory requirements are larger than the set limit or the type is
+// non-trivially copyable, then the contained class is allocated in a separate
+// memory block and the pointer to that memory is contained within this memory
+// buffer class.
+class Buffer final {
+ public:
+  enum StorageType { kExternal, kContained };
+  Buffer() : external_ptr_(nullptr), storage_(kExternal) {}
+  ~Buffer() { Clear(); }
+
+  Buffer(const Buffer& rhs) : Buffer() { rhs.CopyTo(this); }
+  // NOLINTNEXTLINE(build/c++11)
+  Buffer(Buffer&& rhs) : Buffer() { rhs.MoveTo(this); }
+  Buffer& operator=(const Buffer& rhs) {
+    rhs.CopyTo(this);
+    return *this;
+  }
+  // NOLINTNEXTLINE(build/c++11)
+  Buffer& operator=(Buffer&& rhs) {
+    rhs.MoveTo(this);
+    return *this;
+  }
+
+  // Returns the underlying pointer to contained data. Uses either the pointer
+  // or the raw data depending on |storage_| type.
+  inline Data* GetDataPtr() {
+    return (storage_ == kExternal) ? external_ptr_
+                                   : reinterpret_cast<Data*>(contained_buffer_);
+  }
+  inline const Data* GetDataPtr() const {
+    return (storage_ == kExternal)
+               ? external_ptr_
+               : reinterpret_cast<const Data*>(contained_buffer_);
+  }
+
+  // Destroys the contained object (and frees memory if needed).
+  void Clear() {
+    Data* data = GetDataPtr();
+    if (storage_ == kExternal) {
+      delete data;
+    } else {
+      // Call the destructor manually, since the object was constructed inline
+      // in the pre-allocated buffer. We still need to call the destructor
+      // to free any associated resources, but we can't call delete |data| here.
+      data->~Data();
+    }
+    external_ptr_ = nullptr;
+    storage_ = kExternal;
+  }
+
+  // Stores a value of type T.
+  template<typename T>
+  void Assign(T&& value) {  // NOLINT(build/c++11)
+    using Type = typename std::decay<T>::type;
+    using DataType = TypedData<Type>;
+    Data* ptr = GetDataPtr();
+    if (ptr && strcmp(ptr->GetTypeTag(), GetTypeTag<Type>()) == 0) {
+      // We assign the data to the variant container, which already
+      // has the data of the same type. Do fast copy/move with no memory
+      // reallocation.
+      DataType* typed_ptr = static_cast<DataType*>(ptr);
+      // NOLINTNEXTLINE(build/c++11)
+      typed_ptr->FastAssign(std::forward<T>(value));
+    } else {
+      Clear();
+      // TODO(avakulenko): [see crbug.com/379833]
+      // Unfortunately, GCC doesn't support std::is_trivially_copyable<T> yet,
+      // so using std::is_trivial instead, which is a bit more restrictive.
+      // Once GCC has support for is_trivially_copyable, update the following.
+      if (!std::is_trivial<Type>::value ||
+          sizeof(DataType) > sizeof(contained_buffer_)) {
+        // If it is too big or not trivially copyable, allocate it separately.
+        // NOLINTNEXTLINE(build/c++11)
+        external_ptr_ = new DataType(std::forward<T>(value));
+        storage_ = kExternal;
+      } else {
+        // Otherwise just use the pre-allocated buffer.
+        DataType* address = reinterpret_cast<DataType*>(contained_buffer_);
+        // Make sure we still call the copy/move constructor.
+        // Call the constructor manually by using placement 'new'.
+        // NOLINTNEXTLINE(build/c++11)
+        new (address) DataType(std::forward<T>(value));
+        storage_ = kContained;
+      }
+    }
+  }
+
+  // Helper methods to retrieve a reference to contained data.
+  // These assume that type checking has already been performed by Any
+  // so the type cast is valid and will succeed.
+  template<typename T>
+  const T& GetData() const {
+    using DataType = internal_details::TypedData<typename std::decay<T>::type>;
+    return static_cast<const DataType*>(GetDataPtr())->value_;
+  }
+  template<typename T>
+  T& GetData() {
+    using DataType = internal_details::TypedData<typename std::decay<T>::type>;
+    return static_cast<DataType*>(GetDataPtr())->value_;
+  }
+
+  // Returns true if the buffer has no contained data.
+  bool IsEmpty() const {
+    return (storage_ == kExternal && external_ptr_ == nullptr);
+  }
+
+  // Copies the data from the current buffer into the |destination|.
+  void CopyTo(Buffer* destination) const {
+    if (IsEmpty()) {
+      destination->Clear();
+    } else {
+      GetDataPtr()->CopyTo(destination);
+    }
+  }
+
+  // Moves the data from the current buffer into the |destination|.
+  void MoveTo(Buffer* destination) {
+    if (IsEmpty()) {
+      destination->Clear();
+    } else {
+      if (storage_ == kExternal) {
+        destination->Clear();
+        destination->storage_ = kExternal;
+        destination->external_ptr_ = external_ptr_;
+        external_ptr_ = nullptr;
+      } else {
+        GetDataPtr()->MoveTo(destination);
+      }
+    }
+  }
+
+  union {
+    // |external_ptr_| is a pointer to a larger object allocated in
+    // a separate memory block.
+    Data* external_ptr_;
+    // |contained_buffer_| is a pre-allocated buffer for smaller/simple objects.
+    // Pre-allocate enough memory to store objects as big as "double".
+    unsigned char contained_buffer_[sizeof(TypedData<double>)];
+  };
+  // Depending on a value of |storage_|, either |external_ptr_| or
+  // |contained_buffer_| above is used to get a pointer to memory containing
+  // the variant data.
+  StorageType storage_;  // Declare after the union to eliminate member padding.
+};
+
+template <typename T>
+void TypedData<T>::CopyTo(Buffer* buffer) const {
+  buffer->Assign(value_);
+}
+template <typename T>
+void TypedData<T>::MoveTo(Buffer* buffer) {
+  buffer->Assign(std::move(value_));
+}
+
+}  // namespace internal_details
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_ANY_INTERNAL_IMPL_H_
diff --git a/libbrillo/brillo/any_internal_impl_unittest.cc b/libbrillo/brillo/any_internal_impl_unittest.cc
new file mode 100644
index 0000000..6f7f512
--- /dev/null
+++ b/libbrillo/brillo/any_internal_impl_unittest.cc
@@ -0,0 +1,143 @@
+// Copyright 2014 The Chromium OS 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 <string>
+
+#include <brillo/any.h>
+#include <gtest/gtest.h>
+
+using brillo::internal_details::Buffer;
+using brillo::GetTypeTag;
+
+TEST(Buffer, Empty) {
+  Buffer buffer;
+  EXPECT_TRUE(buffer.IsEmpty());
+  EXPECT_EQ(Buffer::kExternal, buffer.storage_);
+  EXPECT_EQ(nullptr, buffer.GetDataPtr());
+}
+
+TEST(Buffer, Store_Int) {
+  Buffer buffer;
+  buffer.Assign(2);
+  EXPECT_FALSE(buffer.IsEmpty());
+  EXPECT_EQ(Buffer::kContained, buffer.storage_);
+  EXPECT_STREQ(GetTypeTag<int>(), buffer.GetDataPtr()->GetTypeTag());
+}
+
+TEST(Buffer, Store_Double) {
+  Buffer buffer;
+  buffer.Assign(2.3);
+  EXPECT_FALSE(buffer.IsEmpty());
+  EXPECT_EQ(Buffer::kContained, buffer.storage_);
+  EXPECT_STREQ(GetTypeTag<double>(), buffer.GetDataPtr()->GetTypeTag());
+}
+
+TEST(Buffer, Store_Pointers) {
+  Buffer buffer;
+  // nullptr
+  buffer.Assign(nullptr);
+  EXPECT_FALSE(buffer.IsEmpty());
+  EXPECT_EQ(Buffer::kContained, buffer.storage_);
+  EXPECT_STREQ(GetTypeTag<std::nullptr_t>(),
+               buffer.GetDataPtr()->GetTypeTag());
+
+  // char *
+  buffer.Assign("abcd");
+  EXPECT_FALSE(buffer.IsEmpty());
+  EXPECT_EQ(Buffer::kContained, buffer.storage_);
+  EXPECT_STREQ(GetTypeTag<const char*>(), buffer.GetDataPtr()->GetTypeTag());
+
+  // pointer to non-trivial object
+  class NonTrivial {
+   public:
+    virtual ~NonTrivial() {}
+  } non_trivial;
+  buffer.Assign(&non_trivial);
+  EXPECT_FALSE(buffer.IsEmpty());
+  EXPECT_EQ(Buffer::kContained, buffer.storage_);
+  EXPECT_STREQ(GetTypeTag<NonTrivial*>(), buffer.GetDataPtr()->GetTypeTag());
+}
+
+TEST(Buffer, Store_NonTrivialObjects) {
+  class NonTrivial {
+   public:
+    virtual ~NonTrivial() {}
+  } non_trivial;
+  Buffer buffer;
+  buffer.Assign(non_trivial);
+  EXPECT_FALSE(buffer.IsEmpty());
+  EXPECT_EQ(Buffer::kExternal, buffer.storage_);
+  EXPECT_STREQ(GetTypeTag<NonTrivial>(), buffer.GetDataPtr()->GetTypeTag());
+}
+
+TEST(Buffer, Store_Objects) {
+  Buffer buffer;
+
+  struct Small {
+    double d;
+  } small = {};
+  buffer.Assign(small);
+  EXPECT_FALSE(buffer.IsEmpty());
+  EXPECT_EQ(Buffer::kContained, buffer.storage_);
+  EXPECT_STREQ(GetTypeTag<Small>(), buffer.GetDataPtr()->GetTypeTag());
+
+  struct Large {
+    char c[20];
+  } large = {};
+  buffer.Assign(large);
+  EXPECT_FALSE(buffer.IsEmpty());
+  EXPECT_EQ(Buffer::kExternal, buffer.storage_);
+  EXPECT_STREQ(GetTypeTag<Large>(), buffer.GetDataPtr()->GetTypeTag());
+}
+
+TEST(Buffer, Copy) {
+  Buffer buffer1;
+  Buffer buffer2;
+
+  buffer1.Assign(30);
+  buffer1.CopyTo(&buffer2);
+  EXPECT_FALSE(buffer1.IsEmpty());
+  EXPECT_FALSE(buffer2.IsEmpty());
+  EXPECT_STREQ(GetTypeTag<int>(), buffer1.GetDataPtr()->GetTypeTag());
+  EXPECT_STREQ(GetTypeTag<int>(), buffer2.GetDataPtr()->GetTypeTag());
+  EXPECT_EQ(30, buffer1.GetData<int>());
+  EXPECT_EQ(30, buffer2.GetData<int>());
+
+  buffer1.Assign(std::string("abc"));
+  buffer1.CopyTo(&buffer2);
+  EXPECT_FALSE(buffer1.IsEmpty());
+  EXPECT_FALSE(buffer2.IsEmpty());
+  EXPECT_STREQ(GetTypeTag<std::string>(), buffer1.GetDataPtr()->GetTypeTag());
+  EXPECT_STREQ(GetTypeTag<std::string>(), buffer2.GetDataPtr()->GetTypeTag());
+  EXPECT_EQ("abc", buffer1.GetData<std::string>());
+  EXPECT_EQ("abc", buffer2.GetData<std::string>());
+}
+
+TEST(Buffer, Move) {
+  // Move operations essentially leave the source object in a state that is
+  // guaranteed to be safe for reuse or destruction. There is no other explicit
+  // guarantees on the exact state of the source after move (e.g. that the
+  // source Any will be Empty after the move is complete).
+  Buffer buffer1;
+  Buffer buffer2;
+
+  buffer1.Assign(30);
+  buffer1.MoveTo(&buffer2);
+  // Contained types aren't flushed, so the source Any doesn't become empty.
+  // The contained value is just moved, but for scalars this just copies
+  // the data and any retains the actual type.
+  EXPECT_FALSE(buffer1.IsEmpty());
+  EXPECT_FALSE(buffer2.IsEmpty());
+  EXPECT_STREQ(GetTypeTag<int>(), buffer2.GetDataPtr()->GetTypeTag());
+  EXPECT_EQ(30, buffer2.GetData<int>());
+
+  buffer1.Assign(std::string("abc"));
+  buffer1.MoveTo(&buffer2);
+  // External types are moved by just moving the pointer value from src to dest.
+  // This will make the source object effectively "Empty".
+  EXPECT_TRUE(buffer1.IsEmpty());
+  EXPECT_FALSE(buffer2.IsEmpty());
+  EXPECT_STREQ(GetTypeTag<std::string>(), buffer2.GetDataPtr()->GetTypeTag());
+  EXPECT_EQ("abc", buffer2.GetData<std::string>());
+}
diff --git a/libbrillo/brillo/any_unittest.cc b/libbrillo/brillo/any_unittest.cc
new file mode 100644
index 0000000..db89884
--- /dev/null
+++ b/libbrillo/brillo/any_unittest.cc
@@ -0,0 +1,323 @@
+// Copyright 2014 The Chromium OS 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 <algorithm>
+#include <functional>
+#include <string>
+#include <vector>
+
+#include <brillo/any.h>
+#include <gtest/gtest.h>
+
+using brillo::Any;
+
+TEST(Any, Empty) {
+  Any val;
+  EXPECT_TRUE(val.IsEmpty());
+
+  Any val2 = val;
+  EXPECT_TRUE(val.IsEmpty());
+  EXPECT_TRUE(val2.IsEmpty());
+
+  Any val3 = std::move(val);
+  EXPECT_TRUE(val.IsEmpty());
+  EXPECT_TRUE(val3.IsEmpty());
+}
+
+TEST(Any, SimpleTypes) {
+  Any val(20);
+  EXPECT_FALSE(val.IsEmpty());
+  EXPECT_TRUE(val.IsTypeCompatible<int>());
+  EXPECT_EQ(20, val.Get<int>());
+
+  Any val2(3.1415926);
+  EXPECT_FALSE(val2.IsEmpty());
+  EXPECT_TRUE(val2.IsTypeCompatible<double>());
+  EXPECT_FALSE(val2.IsTypeCompatible<int>());
+  EXPECT_DOUBLE_EQ(3.1415926, val2.Get<double>());
+
+  Any val3(std::string("blah"));
+  EXPECT_TRUE(val3.IsTypeCompatible<std::string>());
+  EXPECT_EQ("blah", val3.Get<std::string>());
+}
+
+TEST(Any, Clear) {
+  Any val('x');
+  EXPECT_FALSE(val.IsEmpty());
+  EXPECT_EQ('x', val.Get<char>());
+
+  val.Clear();
+  EXPECT_TRUE(val.IsEmpty());
+}
+
+TEST(Any, Assignments) {
+  Any val(20);
+  EXPECT_EQ(20, val.Get<int>());
+
+  val = 3.1415926;
+  EXPECT_FALSE(val.IsEmpty());
+  EXPECT_TRUE(val.IsTypeCompatible<double>());
+  EXPECT_DOUBLE_EQ(3.1415926, val.Get<double>());
+
+  val = std::string("blah");
+  EXPECT_EQ("blah", val.Get<std::string>());
+
+  Any val2;
+  EXPECT_TRUE(val2.IsEmpty());
+  val2 = val;
+  EXPECT_FALSE(val.IsEmpty());
+  EXPECT_FALSE(val2.IsEmpty());
+  EXPECT_EQ("blah", val.Get<std::string>());
+  EXPECT_EQ("blah", val2.Get<std::string>());
+  val.Clear();
+  EXPECT_TRUE(val.IsEmpty());
+  EXPECT_EQ("blah", val2.Get<std::string>());
+  val2.Clear();
+  EXPECT_TRUE(val2.IsEmpty());
+
+  val = std::vector<int>{100, 20, 3};
+  auto v = val.Get<std::vector<int>>();
+  EXPECT_EQ(100, v[0]);
+  EXPECT_EQ(20, v[1]);
+  EXPECT_EQ(3, v[2]);
+
+  val2 = std::move(val);
+  EXPECT_TRUE(val.IsEmpty());
+  EXPECT_TRUE(val2.IsTypeCompatible<std::vector<int>>());
+  EXPECT_EQ(3, val2.Get<std::vector<int>>().size());
+
+  val = val2;
+  EXPECT_TRUE(val.IsTypeCompatible<std::vector<int>>());
+  EXPECT_TRUE(val2.IsTypeCompatible<std::vector<int>>());
+  EXPECT_EQ(3, val.Get<std::vector<int>>().size());
+  EXPECT_EQ(3, val2.Get<std::vector<int>>().size());
+}
+
+TEST(Any, Enums) {
+  enum class Dummy { foo, bar, baz };
+  Any val(Dummy::bar);
+  EXPECT_FALSE(val.IsEmpty());
+  EXPECT_TRUE(val.IsConvertibleToInteger());
+  EXPECT_EQ(Dummy::bar, val.Get<Dummy>());
+  EXPECT_EQ(1, val.GetAsInteger());
+
+  val = Dummy::baz;
+  EXPECT_EQ(2, val.GetAsInteger());
+
+  val = Dummy::foo;
+  EXPECT_EQ(0, val.GetAsInteger());
+}
+
+TEST(Any, Integers) {
+  Any val(14);
+  EXPECT_TRUE(val.IsConvertibleToInteger());
+  EXPECT_EQ(14, val.Get<int>());
+  EXPECT_EQ(14, val.GetAsInteger());
+
+  val = '\x40';
+  EXPECT_TRUE(val.IsConvertibleToInteger());
+  EXPECT_EQ(64, val.Get<char>());
+  EXPECT_EQ(64, val.GetAsInteger());
+
+  val = static_cast<uint16_t>(65535);
+  EXPECT_TRUE(val.IsConvertibleToInteger());
+  EXPECT_EQ(65535, val.Get<uint16_t>());
+  EXPECT_EQ(65535, val.GetAsInteger());
+
+  val = static_cast<uint64_t>(0xFFFFFFFFFFFFFFFFULL);
+  EXPECT_TRUE(val.IsConvertibleToInteger());
+  EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, val.Get<uint64_t>());
+  EXPECT_EQ(-1, val.GetAsInteger());
+
+  val = "abc";
+  EXPECT_FALSE(val.IsConvertibleToInteger());
+
+  int a = 5;
+  val = &a;
+  EXPECT_FALSE(val.IsConvertibleToInteger());
+}
+
+TEST(Any, Pointers) {
+  Any val("abc");  // const char*
+  EXPECT_FALSE(val.IsTypeCompatible<char*>());
+  EXPECT_TRUE(val.IsTypeCompatible<const char*>());
+  EXPECT_FALSE(val.IsTypeCompatible<volatile char*>());
+  EXPECT_TRUE(val.IsTypeCompatible<volatile const char*>());
+  EXPECT_STREQ("abc", val.Get<const char*>());
+
+  int a = 10;
+  val = &a;
+  EXPECT_TRUE(val.IsTypeCompatible<int*>());
+  EXPECT_TRUE(val.IsTypeCompatible<const int*>());
+  EXPECT_TRUE(val.IsTypeCompatible<volatile int*>());
+  EXPECT_TRUE(val.IsTypeCompatible<volatile const int*>());
+  EXPECT_EQ(10, *val.Get<const int*>());
+  *val.Get<int*>() = 3;
+  EXPECT_EQ(3, a);
+}
+
+TEST(Any, Arrays) {
+  // The following test are here to validate the array-to-pointer decay rules.
+  // Since Any does not store the contents of a C-style array, just a pointer
+  // to the data, putting array data into Any could be dangerous.
+  // Make sure the array's lifetime exceeds that of an Any containing the
+  // pointer to the array data.
+  // If you want to store the array with data, use corresponding value types
+  // such as std::vector or a struct containing C-style array as a member.
+
+  int int_array[] = {1, 2, 3};  // int*
+  Any val = int_array;
+  EXPECT_TRUE(val.IsTypeCompatible<int*>());
+  EXPECT_TRUE(val.IsTypeCompatible<const int*>());
+  EXPECT_TRUE(val.IsTypeCompatible<int[]>());
+  EXPECT_TRUE(val.IsTypeCompatible<const int[]>());
+  EXPECT_EQ(3, val.Get<int*>()[2]);
+
+  const int const_int_array[] = {10, 20, 30};  // const int*
+  val = const_int_array;
+  EXPECT_FALSE(val.IsTypeCompatible<int*>());
+  EXPECT_TRUE(val.IsTypeCompatible<const int*>());
+  EXPECT_FALSE(val.IsTypeCompatible<int[]>());
+  EXPECT_TRUE(val.IsTypeCompatible<const int[]>());
+  EXPECT_EQ(30, val.Get<const int*>()[2]);
+}
+
+TEST(Any, References) {
+  // Passing references to object via Any might be error-prone or the
+  // semantics could be unfamiliar to other developers. In many cases,
+  // using pointers instead of references are more conventional and easier
+  // to understand. Even though the cases of passing references are quite
+  // explicit on both storing and retrieving ends, you might want to
+  // use pointers instead anyway.
+
+  int a = 5;
+  Any val(std::ref(a));  // int&
+  EXPECT_EQ(5, val.Get<std::reference_wrapper<int>>().get());
+  val.Get<std::reference_wrapper<int>>().get() = 7;
+  EXPECT_EQ(7, val.Get<std::reference_wrapper<int>>().get());
+  EXPECT_EQ(7, a);
+
+  Any val2(std::cref(a));  // const int&
+  EXPECT_EQ(7, val2.Get<std::reference_wrapper<const int>>().get());
+
+  a = 10;
+  EXPECT_EQ(10, val.Get<std::reference_wrapper<int>>().get());
+  EXPECT_EQ(10, val2.Get<std::reference_wrapper<const int>>().get());
+}
+
+TEST(Any, CustomTypes) {
+  struct Person {
+    std::string name;
+    int age;
+  };
+  Any val(Person{"Jack", 40});
+  Any val2 = val;
+  EXPECT_EQ("Jack", val.Get<Person>().name);
+  val.GetPtr<Person>()->name = "Joe";
+  val.GetPtr<Person>()->age /= 2;
+  EXPECT_EQ("Joe", val.Get<Person>().name);
+  EXPECT_EQ(20, val.Get<Person>().age);
+  EXPECT_EQ("Jack", val2.Get<Person>().name);
+  EXPECT_EQ(40, val2.Get<Person>().age);
+}
+
+TEST(Any, Swap) {
+  Any val(12);
+  Any val2(2.7);
+  EXPECT_EQ(12, val.Get<int>());
+  EXPECT_EQ(2.7, val2.Get<double>());
+
+  val.Swap(val2);
+  EXPECT_EQ(2.7, val.Get<double>());
+  EXPECT_EQ(12, val2.Get<int>());
+
+  std::swap(val, val2);
+  EXPECT_EQ(12, val.Get<int>());
+  EXPECT_EQ(2.7, val2.Get<double>());
+}
+
+TEST(Any, TypeMismatch) {
+  Any val(12);
+  EXPECT_DEATH(val.Get<double>(),
+               "Requesting value of type 'double' from variant containing "
+               "'int'");
+
+  val = std::string("123");
+  EXPECT_DEATH(val.GetAsInteger(),
+               "Unable to convert value of type 'std::.*' to integer");
+
+  Any empty;
+  EXPECT_DEATH(empty.GetAsInteger(), "Must not be called on an empty Any");
+}
+
+TEST(Any, TryGet) {
+  Any val(12);
+  Any empty;
+  EXPECT_EQ("dummy", val.TryGet<std::string>("dummy"));
+  EXPECT_EQ(12, val.TryGet<int>(17));
+  EXPECT_EQ(17, empty.TryGet<int>(17));
+}
+
+TEST(Any, Compare_Int) {
+  Any int1{12};
+  Any int2{12};
+  Any int3{20};
+  EXPECT_EQ(int1, int2);
+  EXPECT_NE(int2, int3);
+}
+
+TEST(Any, Compare_String) {
+  Any str1{std::string{"foo"}};
+  Any str2{std::string{"foo"}};
+  Any str3{std::string{"bar"}};
+  EXPECT_EQ(str1, str2);
+  EXPECT_NE(str2, str3);
+}
+
+TEST(Any, Compare_Array) {
+  Any vec1{std::vector<int>{1, 2}};
+  Any vec2{std::vector<int>{1, 2}};
+  Any vec3{std::vector<int>{1, 2, 3}};
+  EXPECT_EQ(vec1, vec2);
+  EXPECT_NE(vec2, vec3);
+}
+
+TEST(Any, Compare_Empty) {
+  Any empty1;
+  Any empty2;
+  Any int1{1};
+  EXPECT_EQ(empty1, empty2);
+  EXPECT_NE(int1, empty1);
+  EXPECT_NE(empty2, int1);
+}
+
+TEST(Any, Compare_NonComparable) {
+  struct Person {
+    std::string name;
+    int age;
+  };
+  Any person1(Person{"Jack", 40});
+  Any person2 = person1;
+  Any person3(Person{"Jill", 20});
+  EXPECT_NE(person1, person2);
+  EXPECT_NE(person1, person3);
+  EXPECT_NE(person2, person3);
+}
+
+TEST(Any, GetUndecoratedTypeName) {
+  Any val;
+  EXPECT_TRUE(val.GetUndecoratedTypeName().empty());
+
+  val = 1;
+  EXPECT_EQ(brillo::GetUndecoratedTypeName<int>(),
+            val.GetUndecoratedTypeName());
+
+  val = 3.1415926;
+  EXPECT_EQ(brillo::GetUndecoratedTypeName<double>(),
+            val.GetUndecoratedTypeName());
+
+  val = std::string("blah");
+  EXPECT_EQ(brillo::GetUndecoratedTypeName<std::string>(),
+            val.GetUndecoratedTypeName());
+}
diff --git a/libbrillo/brillo/asynchronous_signal_handler.cc b/libbrillo/brillo/asynchronous_signal_handler.cc
new file mode 100644
index 0000000..b8ec529
--- /dev/null
+++ b/libbrillo/brillo/asynchronous_signal_handler.cc
@@ -0,0 +1,108 @@
+// Copyright 2014 The Chromium OS 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 "brillo/asynchronous_signal_handler.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <base/bind.h>
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <base/posix/eintr_wrapper.h>
+
+namespace {
+const int kInvalidDescriptor = -1;
+}  // namespace
+
+namespace brillo {
+
+AsynchronousSignalHandler::AsynchronousSignalHandler()
+    : descriptor_(kInvalidDescriptor) {
+  CHECK_EQ(sigemptyset(&signal_mask_), 0) << "Failed to initialize signal mask";
+  CHECK_EQ(sigemptyset(&saved_signal_mask_), 0)
+      << "Failed to initialize signal mask";
+}
+
+AsynchronousSignalHandler::~AsynchronousSignalHandler() {
+  if (descriptor_ != kInvalidDescriptor) {
+    MessageLoop::current()->CancelTask(fd_watcher_task_);
+
+    if (IGNORE_EINTR(close(descriptor_)) != 0)
+      PLOG(WARNING) << "Failed to close file descriptor";
+
+    descriptor_ = kInvalidDescriptor;
+    CHECK_EQ(0, sigprocmask(SIG_SETMASK, &saved_signal_mask_, nullptr));
+  }
+}
+
+void AsynchronousSignalHandler::Init() {
+  CHECK_EQ(kInvalidDescriptor, descriptor_);
+  CHECK_EQ(0, sigprocmask(SIG_BLOCK, &signal_mask_, &saved_signal_mask_));
+  descriptor_ =
+      signalfd(descriptor_, &signal_mask_, SFD_CLOEXEC | SFD_NONBLOCK);
+  CHECK_NE(kInvalidDescriptor, descriptor_);
+  fd_watcher_task_ = MessageLoop::current()->WatchFileDescriptor(
+      FROM_HERE,
+      descriptor_,
+      MessageLoop::WatchMode::kWatchRead,
+      true,
+      base::Bind(&AsynchronousSignalHandler::OnFileCanReadWithoutBlocking,
+                 base::Unretained(this)));
+  CHECK(fd_watcher_task_ != MessageLoop::kTaskIdNull)
+      << "Watching shutdown pipe failed.";
+}
+
+void AsynchronousSignalHandler::RegisterHandler(int signal,
+                                                const SignalHandler& callback) {
+  registered_callbacks_[signal] = callback;
+  CHECK_EQ(0, sigaddset(&signal_mask_, signal));
+  UpdateSignals();
+}
+
+void AsynchronousSignalHandler::UnregisterHandler(int signal) {
+  Callbacks::iterator callback_it = registered_callbacks_.find(signal);
+  if (callback_it != registered_callbacks_.end()) {
+    registered_callbacks_.erase(callback_it);
+    ResetSignal(signal);
+  }
+}
+
+void AsynchronousSignalHandler::OnFileCanReadWithoutBlocking() {
+  struct signalfd_siginfo info;
+  while (base::ReadFromFD(descriptor_,
+                          reinterpret_cast<char*>(&info), sizeof(info))) {
+    int signal = info.ssi_signo;
+    Callbacks::iterator callback_it = registered_callbacks_.find(signal);
+    if (callback_it == registered_callbacks_.end()) {
+      LOG(WARNING) << "Unable to find a signal handler for signal: " << signal;
+      // Can happen if a signal has been called multiple time, and the callback
+      // asked to be unregistered the first time.
+      continue;
+    }
+    const SignalHandler& callback = callback_it->second;
+    bool must_unregister = callback.Run(info);
+    if (must_unregister) {
+      UnregisterHandler(signal);
+    }
+  }
+}
+
+void AsynchronousSignalHandler::ResetSignal(int signal) {
+  CHECK_EQ(0, sigdelset(&signal_mask_, signal));
+  UpdateSignals();
+}
+
+void AsynchronousSignalHandler::UpdateSignals() {
+  if (descriptor_ != kInvalidDescriptor) {
+    CHECK_EQ(0, sigprocmask(SIG_SETMASK, &saved_signal_mask_, nullptr));
+    CHECK_EQ(0, sigprocmask(SIG_BLOCK, &signal_mask_, nullptr));
+    CHECK_EQ(descriptor_,
+             signalfd(descriptor_, &signal_mask_, SFD_CLOEXEC | SFD_NONBLOCK));
+  }
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/asynchronous_signal_handler.h b/libbrillo/brillo/asynchronous_signal_handler.h
new file mode 100644
index 0000000..ceae1ff
--- /dev/null
+++ b/libbrillo/brillo/asynchronous_signal_handler.h
@@ -0,0 +1,74 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_ASYNCHRONOUS_SIGNAL_HANDLER_H_
+#define LIBBRILLO_BRILLO_ASYNCHRONOUS_SIGNAL_HANDLER_H_
+
+#include <signal.h>
+#include <sys/signalfd.h>
+
+#include <map>
+
+#include <base/callback.h>
+#include <base/compiler_specific.h>
+#include <base/macros.h>
+#include <base/message_loop/message_loop.h>
+#include <brillo/asynchronous_signal_handler_interface.h>
+#include <brillo/brillo_export.h>
+#include <brillo/message_loops/message_loop.h>
+
+namespace brillo {
+// Sets up signal handlers for registered signals, and converts signal receipt
+// into a write on a pipe. Watches that pipe for data and, when some appears,
+// execute the associated callback.
+class BRILLO_EXPORT AsynchronousSignalHandler final :
+    public AsynchronousSignalHandlerInterface {
+ public:
+  AsynchronousSignalHandler();
+  ~AsynchronousSignalHandler() override;
+
+  using AsynchronousSignalHandlerInterface::SignalHandler;
+
+  // Initialize the handler.
+  void Init();
+
+  // AsynchronousSignalHandlerInterface overrides.
+  void RegisterHandler(int signal, const SignalHandler& callback) override;
+  void UnregisterHandler(int signal) override;
+
+ private:
+  // Called from the main loop when we can read from |descriptor_|, indicated
+  // that a signal was processed.
+  void OnFileCanReadWithoutBlocking();
+
+  // Controller used to manage watching of signalling pipe.
+  MessageLoop::TaskId fd_watcher_task_{MessageLoop::kTaskIdNull};
+
+  // The registered callbacks.
+  typedef std::map<int, SignalHandler> Callbacks;
+  Callbacks registered_callbacks_;
+
+  // File descriptor for accepting signals indicated by |signal_mask_|.
+  int descriptor_;
+
+  // A set of signals to be handled after the dispatcher is running.
+  sigset_t signal_mask_;
+
+  // A copy of the signal mask before the dispatcher starts, which will be
+  // used to restore to the original state when the dispatcher stops.
+  sigset_t saved_signal_mask_;
+
+  // Resets the given signal to its default behavior. Doesn't touch
+  // |registered_callbacks_|.
+  BRILLO_PRIVATE void ResetSignal(int signal);
+
+  // Updates the set of signals that this handler listens to.
+  BRILLO_PRIVATE void UpdateSignals();
+
+  DISALLOW_COPY_AND_ASSIGN(AsynchronousSignalHandler);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_ASYNCHRONOUS_SIGNAL_HANDLER_H_
diff --git a/libbrillo/brillo/asynchronous_signal_handler_interface.h b/libbrillo/brillo/asynchronous_signal_handler_interface.h
new file mode 100644
index 0000000..ef0012d
--- /dev/null
+++ b/libbrillo/brillo/asynchronous_signal_handler_interface.h
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_ASYNCHRONOUS_SIGNAL_HANDLER_INTERFACE_H_
+#define LIBBRILLO_BRILLO_ASYNCHRONOUS_SIGNAL_HANDLER_INTERFACE_H_
+
+#include <sys/signalfd.h>
+
+#include <base/callback.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+// Sets up signal handlers for registered signals, and converts signal receipt
+// into a write on a pipe. Watches that pipe for data and, when some appears,
+// execute the associated callback.
+class BRILLO_EXPORT AsynchronousSignalHandlerInterface {
+ public:
+  virtual ~AsynchronousSignalHandlerInterface() = default;
+
+  // The callback called when a signal is received.
+  using SignalHandler = base::Callback<bool(const struct signalfd_siginfo&)>;
+
+  // Register a new handler for the given |signal|, replacing any previously
+  // registered handler. |callback| will be called on the thread the
+  // |AsynchronousSignalHandlerInterface| implementation is bound to when a
+  // signal is received. The received |signalfd_siginfo| will be passed to
+  // |callback|. |callback| must returns |true| if the signal handler must be
+  // unregistered, and |false| otherwise. Due to an implementation detail, you
+  // cannot set any sigaction flags you might be accustomed to using. This might
+  // matter if you hoped to use SA_NOCLDSTOP to avoid getting a SIGCHLD when a
+  // child process receives a SIGSTOP.
+  virtual void RegisterHandler(int signal, const SignalHandler& callback) = 0;
+
+  // Unregister a previously registered handler for the given |signal|.
+  virtual void UnregisterHandler(int signal) = 0;
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_ASYNCHRONOUS_SIGNAL_HANDLER_INTERFACE_H_
diff --git a/libbrillo/brillo/asynchronous_signal_handler_unittest.cc b/libbrillo/brillo/asynchronous_signal_handler_unittest.cc
new file mode 100644
index 0000000..ec3b061
--- /dev/null
+++ b/libbrillo/brillo/asynchronous_signal_handler_unittest.cc
@@ -0,0 +1,138 @@
+// Copyright 2014 The Chromium OS 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 "brillo/asynchronous_signal_handler.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include <base/bind.h>
+#include <base/macros.h>
+#include <base/message_loop/message_loop.h>
+#include <base/run_loop.h>
+#include <brillo/message_loops/base_message_loop.h>
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+class AsynchronousSignalHandlerTest : public ::testing::Test {
+ public:
+  AsynchronousSignalHandlerTest() {}
+  virtual ~AsynchronousSignalHandlerTest() {}
+
+  virtual void SetUp() {
+    brillo_loop_.SetAsCurrent();
+    handler_.Init();
+  }
+
+  virtual void TearDown() {}
+
+  bool RecordInfoAndQuit(bool response, const struct signalfd_siginfo& info) {
+    infos_.push_back(info);
+    brillo_loop_.PostTask(FROM_HERE, brillo_loop_.QuitClosure());
+    return response;
+  }
+
+ protected:
+  base::MessageLoopForIO base_loop_;
+  BaseMessageLoop brillo_loop_{&base_loop_};
+  std::vector<struct signalfd_siginfo> infos_;
+  AsynchronousSignalHandler handler_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AsynchronousSignalHandlerTest);
+};
+
+TEST_F(AsynchronousSignalHandlerTest, CheckTerm) {
+  handler_.RegisterHandler(
+      SIGTERM,
+      base::Bind(&AsynchronousSignalHandlerTest::RecordInfoAndQuit,
+                 base::Unretained(this),
+                 true));
+  EXPECT_EQ(0, infos_.size());
+  EXPECT_EQ(0, kill(getpid(), SIGTERM));
+
+  // Spin the message loop.
+  MessageLoop::current()->Run();
+
+  ASSERT_EQ(1, infos_.size());
+  EXPECT_EQ(SIGTERM, infos_[0].ssi_signo);
+}
+
+TEST_F(AsynchronousSignalHandlerTest, CheckSignalUnregistration) {
+  handler_.RegisterHandler(
+      SIGCHLD,
+      base::Bind(&AsynchronousSignalHandlerTest::RecordInfoAndQuit,
+                 base::Unretained(this),
+                 true));
+  EXPECT_EQ(0, infos_.size());
+  EXPECT_EQ(0, kill(getpid(), SIGCHLD));
+
+  // Spin the message loop.
+  MessageLoop::current()->Run();
+
+  ASSERT_EQ(1, infos_.size());
+  EXPECT_EQ(SIGCHLD, infos_[0].ssi_signo);
+
+  EXPECT_EQ(0, kill(getpid(), SIGCHLD));
+
+  // Run the loop with a timeout, as no message are expected.
+  brillo_loop_.PostDelayedTask(FROM_HERE,
+                               base::Bind(&MessageLoop::BreakLoop,
+                                          base::Unretained(&brillo_loop_)),
+                               base::TimeDelta::FromMilliseconds(10));
+  MessageLoop::current()->Run();
+
+  // The signal handle should have been unregistered. No new message are
+  // expected.
+  EXPECT_EQ(1, infos_.size());
+}
+
+TEST_F(AsynchronousSignalHandlerTest, CheckMultipleSignal) {
+  const uint8_t NB_SIGNALS = 5;
+  handler_.RegisterHandler(
+      SIGCHLD,
+      base::Bind(&AsynchronousSignalHandlerTest::RecordInfoAndQuit,
+                 base::Unretained(this),
+                 false));
+  EXPECT_EQ(0, infos_.size());
+  for (int i = 0; i < NB_SIGNALS; ++i) {
+    EXPECT_EQ(0, kill(getpid(), SIGCHLD));
+
+    // Spin the message loop.
+    MessageLoop::current()->Run();
+  }
+
+  ASSERT_EQ(NB_SIGNALS, infos_.size());
+  for (int i = 0; i < NB_SIGNALS; ++i) {
+    EXPECT_EQ(SIGCHLD, infos_[i].ssi_signo);
+  }
+}
+
+TEST_F(AsynchronousSignalHandlerTest, CheckChld) {
+  handler_.RegisterHandler(
+      SIGCHLD,
+      base::Bind(&AsynchronousSignalHandlerTest::RecordInfoAndQuit,
+                 base::Unretained(this),
+                 false));
+  pid_t child_pid = fork();
+  if (child_pid == 0) {
+    _Exit(EXIT_SUCCESS);
+  }
+
+  EXPECT_EQ(0, infos_.size());
+  // Spin the message loop.
+  MessageLoop::current()->Run();
+
+  ASSERT_EQ(1, infos_.size());
+  EXPECT_EQ(SIGCHLD, infos_[0].ssi_signo);
+  EXPECT_EQ(child_pid, infos_[0].ssi_pid);
+  EXPECT_EQ(static_cast<int>(CLD_EXITED), infos_[0].ssi_code);
+  EXPECT_EQ(EXIT_SUCCESS, infos_[0].ssi_status);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/backoff_entry.cc b/libbrillo/brillo/backoff_entry.cc
new file mode 100644
index 0000000..8b36287
--- /dev/null
+++ b/libbrillo/brillo/backoff_entry.cc
@@ -0,0 +1,167 @@
+// Copyright 2015 The Chromium OS 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 <brillo/backoff_entry.h>
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+#include <base/logging.h>
+#include <base/numerics/safe_math.h>
+#include <base/rand_util.h>
+
+namespace brillo {
+
+BackoffEntry::BackoffEntry(const BackoffEntry::Policy* const policy)
+    : policy_(policy) {
+  DCHECK(policy_);
+  Reset();
+}
+
+void BackoffEntry::InformOfRequest(bool succeeded) {
+  if (!succeeded) {
+    ++failure_count_;
+    exponential_backoff_release_time_ = CalculateReleaseTime();
+  } else {
+    // We slowly decay the number of times delayed instead of
+    // resetting it to 0 in order to stay stable if we receive
+    // successes interleaved between lots of failures.  Note that in
+    // the normal case, the calculated release time (in the next
+    // statement) will be in the past once the method returns.
+    if (failure_count_ > 0)
+      --failure_count_;
+
+    // The reason why we are not just cutting the release time to
+    // ImplGetTimeNow() is on the one hand, it would unset a release
+    // time set by SetCustomReleaseTime and on the other we would like
+    // to push every request up to our "horizon" when dealing with
+    // multiple in-flight requests. Ex: If we send three requests and
+    // we receive 2 failures and 1 success. The success that follows
+    // those failures will not reset the release time, further
+    // requests will then need to wait the delay caused by the 2
+    // failures.
+    base::TimeDelta delay;
+    if (policy_->always_use_initial_delay)
+      delay = base::TimeDelta::FromMilliseconds(policy_->initial_delay_ms);
+    exponential_backoff_release_time_ = std::max(
+        ImplGetTimeNow() + delay, exponential_backoff_release_time_);
+  }
+}
+
+bool BackoffEntry::ShouldRejectRequest() const {
+  return exponential_backoff_release_time_ > ImplGetTimeNow();
+}
+
+base::TimeDelta BackoffEntry::GetTimeUntilRelease() const {
+  base::TimeTicks now = ImplGetTimeNow();
+  if (exponential_backoff_release_time_ <= now)
+    return base::TimeDelta();
+  return exponential_backoff_release_time_ - now;
+}
+
+base::TimeTicks BackoffEntry::GetReleaseTime() const {
+  return exponential_backoff_release_time_;
+}
+
+void BackoffEntry::SetCustomReleaseTime(const base::TimeTicks& release_time) {
+  exponential_backoff_release_time_ = release_time;
+}
+
+bool BackoffEntry::CanDiscard() const {
+  if (policy_->entry_lifetime_ms == -1)
+    return false;
+
+  base::TimeTicks now = ImplGetTimeNow();
+
+  int64_t unused_since_ms =
+      (now - exponential_backoff_release_time_).InMilliseconds();
+
+  // Release time is further than now, we are managing it.
+  if (unused_since_ms < 0)
+    return false;
+
+  if (failure_count_ > 0) {
+    // Need to keep track of failures until maximum back-off period
+    // has passed (since further failures can add to back-off).
+    return unused_since_ms >= std::max(policy_->maximum_backoff_ms,
+                                       policy_->entry_lifetime_ms);
+  }
+
+  // Otherwise, consider the entry is outdated if it hasn't been used for the
+  // specified lifetime period.
+  return unused_since_ms >= policy_->entry_lifetime_ms;
+}
+
+void BackoffEntry::Reset() {
+  failure_count_ = 0;
+
+  // We leave exponential_backoff_release_time_ unset, meaning 0. We could
+  // initialize to ImplGetTimeNow() but because it's a virtual method it's
+  // not safe to call in the constructor (and the constructor calls Reset()).
+  // The effects are the same, i.e. ShouldRejectRequest() will return false
+  // right after Reset().
+  exponential_backoff_release_time_ = base::TimeTicks();
+}
+
+base::TimeTicks BackoffEntry::ImplGetTimeNow() const {
+  return base::TimeTicks::Now();
+}
+
+base::TimeTicks BackoffEntry::CalculateReleaseTime() const {
+  int effective_failure_count =
+      std::max(0, failure_count_ - policy_->num_errors_to_ignore);
+
+  // If always_use_initial_delay is true, it's equivalent to
+  // the effective_failure_count always being one greater than when it's false.
+  if (policy_->always_use_initial_delay)
+    ++effective_failure_count;
+
+  if (effective_failure_count == 0) {
+    // Never reduce previously set release horizon, e.g. due to Retry-After
+    // header.
+    return std::max(ImplGetTimeNow(), exponential_backoff_release_time_);
+  }
+
+  // The delay is calculated with this formula:
+  // delay = initial_backoff * multiply_factor^(
+  //     effective_failure_count - 1) * Uniform(1 - jitter_factor, 1]
+  // Note: if the failure count is too high, |delay_ms| will become infinity
+  // after the exponential calculation, and then NaN after the jitter is
+  // accounted for. Both cases are handled by using CheckedNumeric<int64_t> to
+  // perform the conversion to integers.
+  double delay_ms = policy_->initial_delay_ms;
+  delay_ms *= pow(policy_->multiply_factor, effective_failure_count - 1);
+  delay_ms -= base::RandDouble() * policy_->jitter_factor * delay_ms;
+
+  // Do overflow checking in microseconds, the internal unit of TimeTicks.
+  const int64_t kTimeTicksNowUs =
+      (ImplGetTimeNow() - base::TimeTicks()).InMicroseconds();
+  base::internal::CheckedNumeric<int64_t> calculated_release_time_us =
+      delay_ms + 0.5;
+  calculated_release_time_us *= base::Time::kMicrosecondsPerMillisecond;
+  calculated_release_time_us += kTimeTicksNowUs;
+
+  const int64_t kMaxTime = std::numeric_limits<int64_t>::max();
+  base::internal::CheckedNumeric<int64_t> maximum_release_time_us = kMaxTime;
+  if (policy_->maximum_backoff_ms >= 0) {
+    maximum_release_time_us = policy_->maximum_backoff_ms;
+    maximum_release_time_us *= base::Time::kMicrosecondsPerMillisecond;
+    maximum_release_time_us += kTimeTicksNowUs;
+  }
+
+  // Decide between maximum release time and calculated release time, accounting
+  // for overflow with both.
+  int64_t release_time_us = std::min(
+      calculated_release_time_us.ValueOrDefault(kMaxTime),
+      maximum_release_time_us.ValueOrDefault(kMaxTime));
+
+  // Never reduce previously set release horizon, e.g. due to Retry-After
+  // header.
+  return std::max(
+      base::TimeTicks() + base::TimeDelta::FromMicroseconds(release_time_us),
+      exponential_backoff_release_time_);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/backoff_entry.h b/libbrillo/brillo/backoff_entry.h
new file mode 100644
index 0000000..82cc953
--- /dev/null
+++ b/libbrillo/brillo/backoff_entry.h
@@ -0,0 +1,115 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_BACKOFF_ENTRY_H_
+#define LIBBRILLO_BRILLO_BACKOFF_ENTRY_H_
+
+#include <base/time/time.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+// Provides the core logic needed for randomized exponential back-off
+// on requests to a given resource, given a back-off policy.
+//
+// This class is largely taken from net/base/backoff_entry.h from Chromium.
+// TODO(avakulenko): Consider packaging portions of Chrome's //net functionality
+// into the current libchrome library.
+class BRILLO_EXPORT BackoffEntry {
+ public:
+  // The set of parameters that define a back-off policy.
+  struct Policy {
+    // Number of initial errors (in sequence) to ignore before applying
+    // exponential back-off rules.
+    int num_errors_to_ignore;
+
+    // Initial delay.  The interpretation of this value depends on
+    // always_use_initial_delay.  It's either how long we wait between
+    // requests before backoff starts, or how much we delay the first request
+    // after backoff starts.
+    int initial_delay_ms;
+
+    // Factor by which the waiting time will be multiplied.
+    double multiply_factor;
+
+    // Fuzzing percentage. ex: 10% will spread requests randomly
+    // between 90%-100% of the calculated time.
+    double jitter_factor;
+
+    // Maximum amount of time we are willing to delay our request, -1
+    // for no maximum.
+    int64_t maximum_backoff_ms;
+
+    // Time to keep an entry from being discarded even when it
+    // has no significant state, -1 to never discard.
+    int64_t entry_lifetime_ms;
+
+    // If true, we always use a delay of initial_delay_ms, even before
+    // we've seen num_errors_to_ignore errors.  Otherwise, initial_delay_ms
+    // is the first delay once we start exponential backoff.
+    //
+    // So if we're ignoring 1 error, we'll see (N, N, Nm, Nm^2, ...) if true,
+    // and (0, 0, N, Nm, ...) when false, where N is initial_backoff_ms and
+    // m is multiply_factor, assuming we've already seen one success.
+    bool always_use_initial_delay;
+  };
+
+  // Lifetime of policy must enclose lifetime of BackoffEntry. The
+  // pointer must be valid but is not dereferenced during construction.
+  explicit BackoffEntry(const Policy* const policy);
+  virtual ~BackoffEntry() = default;
+
+  // Inform this item that a request for the network resource it is
+  // tracking was made, and whether it failed or succeeded.
+  void InformOfRequest(bool succeeded);
+
+  // Returns true if a request for the resource this item tracks should
+  // be rejected at the present time due to exponential back-off policy.
+  bool ShouldRejectRequest() const;
+
+  // Returns the absolute time after which this entry (given its present
+  // state) will no longer reject requests.
+  base::TimeTicks GetReleaseTime() const;
+
+  // Returns the time until a request can be sent.
+  base::TimeDelta GetTimeUntilRelease() const;
+
+  // Causes this object reject requests until the specified absolute time.
+  // This can be used to e.g. implement support for a Retry-After header.
+  void SetCustomReleaseTime(const base::TimeTicks& release_time);
+
+  // Returns true if this object has no significant state (i.e. you could
+  // just as well start with a fresh BackoffEntry object), and hasn't
+  // had for Policy::entry_lifetime_ms.
+  bool CanDiscard() const;
+
+  // Resets this entry to a fresh (as if just constructed) state.
+  void Reset();
+
+  // Returns the failure count for this entry.
+  int failure_count() const { return failure_count_; }
+
+ protected:
+  // Equivalent to TimeTicks::Now(), virtual so unit tests can override.
+  virtual base::TimeTicks ImplGetTimeNow() const;
+
+ private:
+  // Calculates when requests should again be allowed through.
+  base::TimeTicks CalculateReleaseTime() const;
+
+  // Timestamp calculated by the exponential back-off algorithm at which we are
+  // allowed to start sending requests again.
+  base::TimeTicks exponential_backoff_release_time_;
+
+  // Counts request errors; decremented on success.
+  int failure_count_;
+
+  const Policy* const policy_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackoffEntry);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_BACKOFF_ENTRY_H_
diff --git a/libbrillo/brillo/backoff_entry_unittest.cc b/libbrillo/brillo/backoff_entry_unittest.cc
new file mode 100644
index 0000000..dcfa0b2
--- /dev/null
+++ b/libbrillo/brillo/backoff_entry_unittest.cc
@@ -0,0 +1,311 @@
+// Copyright 2015 The Chromium OS 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 <brillo/backoff_entry.h>
+#include <gtest/gtest.h>
+
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace brillo {
+
+BackoffEntry::Policy base_policy = { 0, 1000, 2.0, 0.0, 20000, 2000, false };
+
+class TestBackoffEntry : public BackoffEntry {
+ public:
+  explicit TestBackoffEntry(const Policy* const policy)
+      : BackoffEntry(policy),
+        now_(TimeTicks()) {
+    // Work around initialization in constructor not picking up
+    // fake time.
+    SetCustomReleaseTime(TimeTicks());
+  }
+
+  ~TestBackoffEntry() override {}
+
+  TimeTicks ImplGetTimeNow() const override { return now_; }
+
+  void set_now(const TimeTicks& now) {
+    now_ = now;
+  }
+
+ private:
+  TimeTicks now_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestBackoffEntry);
+};
+
+TEST(BackoffEntryTest, BaseTest) {
+  TestBackoffEntry entry(&base_policy);
+  EXPECT_FALSE(entry.ShouldRejectRequest());
+  EXPECT_EQ(TimeDelta(), entry.GetTimeUntilRelease());
+
+  entry.InformOfRequest(false);
+  EXPECT_TRUE(entry.ShouldRejectRequest());
+  EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
+}
+
+TEST(BackoffEntryTest, CanDiscardNeverExpires) {
+  BackoffEntry::Policy never_expires_policy = base_policy;
+  never_expires_policy.entry_lifetime_ms = -1;
+  TestBackoffEntry never_expires(&never_expires_policy);
+  EXPECT_FALSE(never_expires.CanDiscard());
+  never_expires.set_now(TimeTicks() + TimeDelta::FromDays(100));
+  EXPECT_FALSE(never_expires.CanDiscard());
+}
+
+TEST(BackoffEntryTest, CanDiscard) {
+  TestBackoffEntry entry(&base_policy);
+  // Because lifetime is non-zero, we shouldn't be able to discard yet.
+  EXPECT_FALSE(entry.CanDiscard());
+
+  // Test the "being used" case.
+  entry.InformOfRequest(false);
+  EXPECT_FALSE(entry.CanDiscard());
+
+  // Test the case where there are errors but we can time out.
+  entry.set_now(
+      entry.GetReleaseTime() + TimeDelta::FromMilliseconds(1));
+  EXPECT_FALSE(entry.CanDiscard());
+  entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(
+      base_policy.maximum_backoff_ms + 1));
+  EXPECT_TRUE(entry.CanDiscard());
+
+  // Test the final case (no errors, dependent only on specified lifetime).
+  entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(
+      base_policy.entry_lifetime_ms - 1));
+  entry.InformOfRequest(true);
+  EXPECT_FALSE(entry.CanDiscard());
+  entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(
+      base_policy.entry_lifetime_ms));
+  EXPECT_TRUE(entry.CanDiscard());
+}
+
+TEST(BackoffEntryTest, CanDiscardAlwaysDelay) {
+  BackoffEntry::Policy always_delay_policy = base_policy;
+  always_delay_policy.always_use_initial_delay = true;
+  always_delay_policy.entry_lifetime_ms = 0;
+
+  TestBackoffEntry entry(&always_delay_policy);
+
+  // Because lifetime is non-zero, we shouldn't be able to discard yet.
+  entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(2000));
+  EXPECT_TRUE(entry.CanDiscard());
+
+  // Even with no failures, we wait until the delay before we allow discard.
+  entry.InformOfRequest(true);
+  EXPECT_FALSE(entry.CanDiscard());
+
+  // Wait until the delay expires, and we can discard the entry again.
+  entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(1000));
+  EXPECT_TRUE(entry.CanDiscard());
+}
+
+TEST(BackoffEntryTest, CanDiscardNotStored) {
+  BackoffEntry::Policy no_store_policy = base_policy;
+  no_store_policy.entry_lifetime_ms = 0;
+  TestBackoffEntry not_stored(&no_store_policy);
+  EXPECT_TRUE(not_stored.CanDiscard());
+}
+
+TEST(BackoffEntryTest, ShouldIgnoreFirstTwo) {
+  BackoffEntry::Policy lenient_policy = base_policy;
+  lenient_policy.num_errors_to_ignore = 2;
+
+  BackoffEntry entry(&lenient_policy);
+
+  entry.InformOfRequest(false);
+  EXPECT_FALSE(entry.ShouldRejectRequest());
+
+  entry.InformOfRequest(false);
+  EXPECT_FALSE(entry.ShouldRejectRequest());
+
+  entry.InformOfRequest(false);
+  EXPECT_TRUE(entry.ShouldRejectRequest());
+}
+
+TEST(BackoffEntryTest, ReleaseTimeCalculation) {
+  TestBackoffEntry entry(&base_policy);
+
+  // With zero errors, should return "now".
+  TimeTicks result = entry.GetReleaseTime();
+  EXPECT_EQ(entry.ImplGetTimeNow(), result);
+
+  // 1 error.
+  entry.InformOfRequest(false);
+  result = entry.GetReleaseTime();
+  EXPECT_EQ(entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(1000), result);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
+
+  // 2 errors.
+  entry.InformOfRequest(false);
+  result = entry.GetReleaseTime();
+  EXPECT_EQ(entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(2000), result);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease());
+
+  // 3 errors.
+  entry.InformOfRequest(false);
+  result = entry.GetReleaseTime();
+  EXPECT_EQ(entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(4000), result);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(4000), entry.GetTimeUntilRelease());
+
+  // 6 errors (to check it doesn't pass maximum).
+  entry.InformOfRequest(false);
+  entry.InformOfRequest(false);
+  entry.InformOfRequest(false);
+  result = entry.GetReleaseTime();
+  EXPECT_EQ(
+      entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(20000), result);
+}
+
+TEST(BackoffEntryTest, ReleaseTimeCalculationAlwaysDelay) {
+  BackoffEntry::Policy always_delay_policy = base_policy;
+  always_delay_policy.always_use_initial_delay = true;
+  always_delay_policy.num_errors_to_ignore = 2;
+
+  TestBackoffEntry entry(&always_delay_policy);
+
+  // With previous requests, should return "now".
+  TimeTicks result = entry.GetReleaseTime();
+  EXPECT_EQ(TimeDelta(), entry.GetTimeUntilRelease());
+
+  // 1 error.
+  entry.InformOfRequest(false);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
+
+  // 2 errors.
+  entry.InformOfRequest(false);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
+
+  // 3 errors, exponential backoff starts.
+  entry.InformOfRequest(false);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease());
+
+  // 4 errors.
+  entry.InformOfRequest(false);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(4000), entry.GetTimeUntilRelease());
+
+  // 8 errors (to check it doesn't pass maximum).
+  entry.InformOfRequest(false);
+  entry.InformOfRequest(false);
+  entry.InformOfRequest(false);
+  entry.InformOfRequest(false);
+  result = entry.GetReleaseTime();
+  EXPECT_EQ(TimeDelta::FromMilliseconds(20000), entry.GetTimeUntilRelease());
+}
+
+TEST(BackoffEntryTest, ReleaseTimeCalculationWithJitter) {
+  for (int i = 0; i < 10; ++i) {
+    BackoffEntry::Policy jittery_policy = base_policy;
+    jittery_policy.jitter_factor = 0.2;
+
+    TestBackoffEntry entry(&jittery_policy);
+
+    entry.InformOfRequest(false);
+    entry.InformOfRequest(false);
+    entry.InformOfRequest(false);
+    TimeTicks result = entry.GetReleaseTime();
+    EXPECT_LE(
+        entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(3200), result);
+    EXPECT_GE(
+        entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(4000), result);
+  }
+}
+
+TEST(BackoffEntryTest, FailureThenSuccess) {
+  TestBackoffEntry entry(&base_policy);
+
+  // Failure count 1, establishes horizon.
+  entry.InformOfRequest(false);
+  TimeTicks release_time = entry.GetReleaseTime();
+  EXPECT_EQ(TimeTicks() + TimeDelta::FromMilliseconds(1000), release_time);
+
+  // Success, failure count 0, should not advance past
+  // the horizon that was already set.
+  entry.set_now(release_time - TimeDelta::FromMilliseconds(200));
+  entry.InformOfRequest(true);
+  EXPECT_EQ(release_time, entry.GetReleaseTime());
+
+  // Failure, failure count 1.
+  entry.InformOfRequest(false);
+  EXPECT_EQ(release_time + TimeDelta::FromMilliseconds(800),
+            entry.GetReleaseTime());
+}
+
+TEST(BackoffEntryTest, FailureThenSuccessAlwaysDelay) {
+  BackoffEntry::Policy always_delay_policy = base_policy;
+  always_delay_policy.always_use_initial_delay = true;
+  always_delay_policy.num_errors_to_ignore = 1;
+
+  TestBackoffEntry entry(&always_delay_policy);
+
+  // Failure count 1.
+  entry.InformOfRequest(false);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
+
+  // Failure count 2.
+  entry.InformOfRequest(false);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease());
+  entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(2000));
+
+  // Success.  We should go back to the original delay.
+  entry.InformOfRequest(true);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease());
+
+  // Failure count reaches 2 again.  We should increase the delay once more.
+  entry.InformOfRequest(false);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease());
+  entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(2000));
+}
+
+TEST(BackoffEntryTest, RetainCustomHorizon) {
+  TestBackoffEntry custom(&base_policy);
+  TimeTicks custom_horizon = TimeTicks() + TimeDelta::FromDays(3);
+  custom.SetCustomReleaseTime(custom_horizon);
+  custom.InformOfRequest(false);
+  custom.InformOfRequest(true);
+  custom.set_now(TimeTicks() + TimeDelta::FromDays(2));
+  custom.InformOfRequest(false);
+  custom.InformOfRequest(true);
+  EXPECT_EQ(custom_horizon, custom.GetReleaseTime());
+
+  // Now check that once we are at or past the custom horizon,
+  // we get normal behavior.
+  custom.set_now(TimeTicks() + TimeDelta::FromDays(3));
+  custom.InformOfRequest(false);
+  EXPECT_EQ(
+      TimeTicks() + TimeDelta::FromDays(3) + TimeDelta::FromMilliseconds(1000),
+      custom.GetReleaseTime());
+}
+
+TEST(BackoffEntryTest, RetainCustomHorizonWhenInitialErrorsIgnored) {
+  // Regression test for a bug discovered during code review.
+  BackoffEntry::Policy lenient_policy = base_policy;
+  lenient_policy.num_errors_to_ignore = 1;
+  TestBackoffEntry custom(&lenient_policy);
+  TimeTicks custom_horizon = TimeTicks() + TimeDelta::FromDays(3);
+  custom.SetCustomReleaseTime(custom_horizon);
+  custom.InformOfRequest(false);  // This must not reset the horizon.
+  EXPECT_EQ(custom_horizon, custom.GetReleaseTime());
+}
+
+TEST(BackoffEntryTest, OverflowProtection) {
+  BackoffEntry::Policy large_multiply_policy = base_policy;
+  large_multiply_policy.multiply_factor = 256;
+  TestBackoffEntry custom(&large_multiply_policy);
+
+  // Trigger enough failures such that more than 11 bits of exponent are used
+  // to represent the exponential backoff intermediate values. Given a multiply
+  // factor of 256 (2^8), 129 iterations is enough: 2^(8*(129-1)) = 2^1024.
+  for (int i = 0; i < 129; ++i) {
+    custom.set_now(custom.ImplGetTimeNow() + custom.GetTimeUntilRelease());
+    custom.InformOfRequest(false);
+    ASSERT_TRUE(custom.ShouldRejectRequest());
+  }
+
+  // Max delay should still be respected.
+  EXPECT_EQ(20000, custom.GetTimeUntilRelease().InMilliseconds());
+}
+
+}  // namespace
diff --git a/libbrillo/brillo/bind_lambda.h b/libbrillo/brillo/bind_lambda.h
new file mode 100644
index 0000000..50ac095
--- /dev/null
+++ b/libbrillo/brillo/bind_lambda.h
@@ -0,0 +1,63 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_BIND_LAMBDA_H_
+#define LIBBRILLO_BRILLO_BIND_LAMBDA_H_
+
+#include <base/bind.h>
+
+////////////////////////////////////////////////////////////////////////////////
+// This file is an extension to base/bind_internal.h and adds a RunnableAdapter
+// class specialization that wraps a functor (including lambda objects), so
+// they can be used in base::Callback/base::Bind constructs.
+// By including this file you will gain the ability to write expressions like:
+//    base::Callback<int(int)> callback = base::Bind([](int value) {
+//      return value * value;
+//    });
+////////////////////////////////////////////////////////////////////////////////
+namespace base {
+namespace internal {
+
+// LambdaAdapter is a helper class that specializes on different function call
+// signatures and provides the RunType and Run() method required by
+// RunnableAdapter<> class.
+template <typename Lambda, typename Sig>
+class LambdaAdapter;
+
+// R(...)
+template <typename Lambda, typename R, typename... Args>
+class LambdaAdapter<Lambda, R(Lambda::*)(Args... args)> {
+ public:
+  typedef R(RunType)(Args...);
+  explicit LambdaAdapter(Lambda lambda) : lambda_(lambda) {}
+  R Run(Args... args) { return lambda_(std::forward<Args>(args)...); }
+
+ private:
+  Lambda lambda_;
+};
+
+// R(...) const
+template <typename Lambda, typename R, typename... Args>
+class LambdaAdapter<Lambda, R(Lambda::*)(Args... args) const> {
+ public:
+  typedef R(RunType)(Args...);
+  explicit LambdaAdapter(Lambda lambda) : lambda_(lambda) {}
+  R Run(Args... args) { return lambda_(std::forward<Args>(args)...); }
+
+ private:
+  Lambda lambda_;
+};
+
+template <typename Lambda>
+class RunnableAdapter
+    : public LambdaAdapter<Lambda, decltype(&Lambda::operator())> {
+ public:
+  explicit RunnableAdapter(Lambda lambda)
+      : LambdaAdapter<Lambda, decltype(&Lambda::operator())>(lambda) {}
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // LIBBRILLO_BRILLO_BIND_LAMBDA_H_
diff --git a/libbrillo/brillo/binder_watcher.cc b/libbrillo/brillo/binder_watcher.cc
new file mode 100644
index 0000000..9752204
--- /dev/null
+++ b/libbrillo/brillo/binder_watcher.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <brillo/binder_watcher.h>
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+
+using android::IPCThreadState;
+using android::ProcessState;
+
+namespace {
+// Called from the message loop whenever the binder file descriptor is ready.
+void OnBinderReadReady() {
+  IPCThreadState::self()->handlePolledCommands();
+}
+}  // namespace
+
+namespace brillo {
+
+BinderWatcher::BinderWatcher(MessageLoop* message_loop)
+    : message_loop_(message_loop) {}
+
+BinderWatcher::BinderWatcher() : message_loop_(nullptr) {}
+
+BinderWatcher::~BinderWatcher() {
+  if (task_id_ != MessageLoop::kTaskIdNull)
+    message_loop_->CancelTask(task_id_);
+}
+
+bool BinderWatcher::Init() {
+  if (!message_loop_)
+    message_loop_ = MessageLoop::current();
+  if (!message_loop_) {
+    LOG(ERROR) << "Must initialize a brillo::MessageLoop to use BinderWatcher";
+    return false;
+  }
+
+  int binder_fd = -1;
+  ProcessState::self()->setThreadPoolMaxThreadCount(0);
+  IPCThreadState::self()->disableBackgroundScheduling(true);
+  int err = IPCThreadState::self()->setupPolling(&binder_fd);
+  if (err != 0) {
+    LOG(ERROR) << "Error setting up binder polling: "
+               << logging::SystemErrorCodeToString(err);
+    return false;
+  }
+  if (binder_fd < 0) {
+    LOG(ERROR) << "Invalid binder FD " << binder_fd;
+    return false;
+  }
+  VLOG(1) << "Got binder FD " << binder_fd;
+
+  task_id_ = message_loop_->WatchFileDescriptor(
+      FROM_HERE,
+      binder_fd,
+      MessageLoop::kWatchRead,
+      true /* persistent */,
+      base::Bind(&OnBinderReadReady));
+  if (task_id_ == MessageLoop::kTaskIdNull) {
+    LOG(ERROR) << "Failed to watch binder FD";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/binder_watcher.h b/libbrillo/brillo/binder_watcher.h
new file mode 100644
index 0000000..ece999d
--- /dev/null
+++ b/libbrillo/brillo/binder_watcher.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBBRILLO_BRILLO_BINDER_WATCHER_H_
+#define LIBBRILLO_BRILLO_BINDER_WATCHER_H_
+
+#include <base/macros.h>
+#include <brillo/message_loops/message_loop.h>
+
+namespace brillo {
+
+// Bridge between libbinder and brillo::MessageLoop. Construct at startup to
+// make the message loop watch for binder events and pass them to libbinder.
+class BinderWatcher final {
+ public:
+  // Construct the BinderWatcher using the passed |message_loop| if not null or
+  // the current MessageLoop otherwise.
+  explicit BinderWatcher(MessageLoop* message_loop);
+  BinderWatcher();
+  ~BinderWatcher();
+
+  // Initializes the object, returning true on success.
+  bool Init();
+
+ private:
+  MessageLoop::TaskId task_id_{MessageLoop::kTaskIdNull};
+  MessageLoop* message_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(BinderWatcher);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_BINDER_WATCHER_H_
diff --git a/libbrillo/brillo/brillo_export.h b/libbrillo/brillo/brillo_export.h
new file mode 100644
index 0000000..0e1f834
--- /dev/null
+++ b/libbrillo/brillo/brillo_export.h
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_BRILLO_EXPORT_H_
+#define LIBBRILLO_BRILLO_BRILLO_EXPORT_H_
+
+// Use BRILLO_EXPORT attribute to decorate your classes, methods and variables
+// that need to be exported out of libbrillo. By default, any symbol not
+// explicitly marked with BRILLO_EXPORT attribute is not exported.
+
+// Put BRILLO_EXPORT in front of methods or variables and in between the
+// class and the tag name:
+/*
+
+BRILLO_EXPORT void foo();
+
+class BRILLO_EXPORT Bar {
+ public:
+  void baz();  // Exported since it is a member of an exported class.
+};
+
+*/
+
+// Exporting a class automatically exports all of its members. However there are
+// no export entries for non-static member variables since they are not accessed
+// directly, but rather through "this" pointer. Class methods, type information,
+// virtual table (if any), and static member variables are exported.
+
+// Finally, template functions and template members of a class may not be
+// inlined by the compiler automatically and the out-of-line version will not
+// be exported and fail to link. Marking those inline explicitly might help.
+// Alternatively, exporting specific instantiation of the template could be
+// used with "extern template" and combining this with BRILLO_EXPORT.
+#define BRILLO_EXPORT __attribute__((__visibility__("default")))
+
+// On occasion you might need to disable exporting a particular symbol if
+// you don't want the clients to see it. For example, you can explicitly
+// hide a member of an exported class:
+/*
+
+class BRILLO_EXPORT Foo {
+ public:
+  void bar();  // Exported since it is a member of an exported class.
+
+ private:
+  BRILLO_PRIVATE void baz();  // Explicitly removed from export table.
+};
+
+*/
+
+// Note that even though a class may have a private member it doesn't mean
+// that it must not be exported, since the compiler might still need it.
+// For example, an inline public method calling a private method will not link
+// if that private method is not exported.
+// So be careful with hiding members if you don't want to deal with obscure
+// linker errors.
+#define BRILLO_PRIVATE __attribute__((__visibility__("hidden")))
+
+#endif  // LIBBRILLO_BRILLO_BRILLO_EXPORT_H_
diff --git a/libbrillo/brillo/cryptohome.cc b/libbrillo/brillo/cryptohome.cc
new file mode 100644
index 0000000..49a4a88
--- /dev/null
+++ b/libbrillo/brillo/cryptohome.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2012 The Chromium OS 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 "brillo/cryptohome.h"
+
+#include <openssl/sha.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <cstring>
+#include <limits>
+#include <vector>
+
+#include <base/files/file_util.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/stringprintf.h>
+
+using base::FilePath;
+
+namespace brillo {
+namespace cryptohome {
+namespace home {
+
+const char kGuestUserName[] = "$guest";
+
+static char g_user_home_prefix[PATH_MAX] = "/home/user/";
+static char g_root_home_prefix[PATH_MAX] = "/home/root/";
+static char g_system_salt_path[PATH_MAX] = "/home/.shadow/salt";
+
+static std::string* salt = nullptr;
+
+static bool EnsureSystemSaltIsLoaded() {
+  if (salt && !salt->empty())
+    return true;
+  FilePath salt_path(g_system_salt_path);
+  int64_t file_size;
+  if (!base::GetFileSize(salt_path, &file_size)) {
+    PLOG(ERROR) << "Could not get size of system salt: " << g_system_salt_path;
+    return false;
+  }
+  if (file_size > static_cast<int64_t>(std::numeric_limits<int>::max())) {
+    LOG(ERROR) << "System salt too large: " << file_size;
+    return false;
+  }
+  std::vector<char> buf;
+  buf.resize(file_size);
+  unsigned int data_read = base::ReadFile(salt_path, buf.data(), file_size);
+  if (data_read != file_size) {
+    PLOG(ERROR) << "Could not read entire file: " << data_read
+                << " != " << file_size;
+    return false;
+  }
+
+  if (!salt)
+    salt = new std::string();
+  salt->assign(buf.data(), file_size);
+  return true;
+}
+
+std::string SanitizeUserName(const std::string& username) {
+  if (!EnsureSystemSaltIsLoaded())
+    return std::string();
+
+  unsigned char binmd[SHA_DIGEST_LENGTH];
+  std::string lowercase(username);
+  std::transform(
+      lowercase.begin(), lowercase.end(), lowercase.begin(), ::tolower);
+  SHA_CTX ctx;
+  SHA1_Init(&ctx);
+  SHA1_Update(&ctx, salt->data(), salt->size());
+  SHA1_Update(&ctx, lowercase.data(), lowercase.size());
+  SHA1_Final(binmd, &ctx);
+  std::string final = base::HexEncode(binmd, sizeof(binmd));
+  // Stay compatible with CryptoLib::HexEncodeToBuffer()
+  std::transform(final.begin(), final.end(), final.begin(), ::tolower);
+  return final;
+}
+
+FilePath GetUserPathPrefix() {
+  return FilePath(g_user_home_prefix);
+}
+
+FilePath GetRootPathPrefix() {
+  return FilePath(g_root_home_prefix);
+}
+
+FilePath GetHashedUserPath(const std::string& hashed_username) {
+  return FilePath(
+      base::StringPrintf("%s%s", g_user_home_prefix, hashed_username.c_str()));
+}
+
+FilePath GetUserPath(const std::string& username) {
+  if (!EnsureSystemSaltIsLoaded())
+    return FilePath("");
+  return GetHashedUserPath(SanitizeUserName(username));
+}
+
+FilePath GetRootPath(const std::string& username) {
+  if (!EnsureSystemSaltIsLoaded())
+    return FilePath("");
+  return FilePath(base::StringPrintf(
+      "%s%s", g_root_home_prefix, SanitizeUserName(username).c_str()));
+}
+
+FilePath GetDaemonPath(const std::string& username, const std::string& daemon) {
+  if (!EnsureSystemSaltIsLoaded())
+    return FilePath("");
+  return GetRootPath(username).Append(daemon);
+}
+
+bool IsSanitizedUserName(const std::string& sanitized) {
+  std::vector<uint8_t> bytes;
+  return (sanitized.length() == 2 * SHA_DIGEST_LENGTH) &&
+         base::HexStringToBytes(sanitized, &bytes);
+}
+
+void SetUserHomePrefix(const std::string& prefix) {
+  if (prefix.length() < sizeof(g_user_home_prefix)) {
+    snprintf(
+        g_user_home_prefix, sizeof(g_user_home_prefix), "%s", prefix.c_str());
+  }
+}
+
+void SetRootHomePrefix(const std::string& prefix) {
+  if (prefix.length() < sizeof(g_root_home_prefix)) {
+    snprintf(
+        g_root_home_prefix, sizeof(g_root_home_prefix), "%s", prefix.c_str());
+  }
+}
+
+std::string* GetSystemSalt() {
+  return salt;
+}
+
+void SetSystemSalt(std::string* value) {
+  salt = value;
+}
+
+}  // namespace home
+}  // namespace cryptohome
+}  // namespace brillo
diff --git a/libbrillo/brillo/cryptohome.h b/libbrillo/brillo/cryptohome.h
new file mode 100644
index 0000000..caca31b
--- /dev/null
+++ b/libbrillo/brillo/cryptohome.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium OS 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 LIBBRILLO_BRILLO_CRYPTOHOME_H_
+#define LIBBRILLO_BRILLO_CRYPTOHOME_H_
+
+#include <string>
+
+#include <base/files/file_path.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+namespace cryptohome {
+namespace home {
+
+BRILLO_EXPORT extern const char kGuestUserName[];
+
+// Returns the common prefix under which the mount points for user homes are
+// created.
+BRILLO_EXPORT base::FilePath GetUserPathPrefix();
+
+// Returns the common prefix under which the mount points for root homes are
+// created.
+BRILLO_EXPORT base::FilePath GetRootPathPrefix();
+
+// Returns the path at which the user home for |username| will be mounted.
+// Returns "" for failures.
+BRILLO_EXPORT base::FilePath GetUserPath(const std::string& username);
+
+// Returns the path at which the user home for |hashed_username| will be
+// mounted. Useful when you already have the username hashed.
+// Returns "" for failures.
+BRILLO_EXPORT base::FilePath GetHashedUserPath(
+    const std::string& hashed_username);
+
+// Returns the path at which the root home for |username| will be mounted.
+// Returns "" for failures.
+BRILLO_EXPORT base::FilePath GetRootPath(const std::string& username);
+
+// Returns the path at which the daemon |daemon| should store per-user data.
+BRILLO_EXPORT base::FilePath GetDaemonPath(const std::string& username,
+                                           const std::string& daemon);
+
+// Checks whether |sanitized| has the format of a sanitized username.
+BRILLO_EXPORT bool IsSanitizedUserName(const std::string& sanitized);
+
+// Returns a sanitized form of |username|. For x != y, SanitizeUserName(x) !=
+// SanitizeUserName(y).
+BRILLO_EXPORT std::string SanitizeUserName(const std::string& username);
+
+// Overrides the common prefix under which the mount points for user homes are
+// created. This is used for testing only.
+BRILLO_EXPORT void SetUserHomePrefix(const std::string& prefix);
+
+// Overrides the common prefix under which the mount points for root homes are
+// created. This is used for testing only.
+BRILLO_EXPORT void SetRootHomePrefix(const std::string& prefix);
+
+// Overrides the contents of the system salt.
+// salt should be non-NULL and non-empty when attempting to avoid filesystem
+// usage in tests.
+// Note:
+// (1) Never mix usage with SetSystemSaltPath().
+// (2) Ownership of the pointer stays with the caller.
+BRILLO_EXPORT void SetSystemSalt(std::string* salt);
+
+// Returns the system salt.
+BRILLO_EXPORT std::string* GetSystemSalt();
+
+}  // namespace home
+}  // namespace cryptohome
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_CRYPTOHOME_H_
diff --git a/libbrillo/brillo/daemons/daemon.cc b/libbrillo/brillo/daemons/daemon.cc
new file mode 100644
index 0000000..7c7e996
--- /dev/null
+++ b/libbrillo/brillo/daemons/daemon.cc
@@ -0,0 +1,92 @@
+// Copyright 2014 The Chromium OS 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 <brillo/daemons/daemon.h>
+
+#include <sysexits.h>
+
+#include <base/bind.h>
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include <base/run_loop.h>
+
+namespace brillo {
+
+Daemon::Daemon() : exit_code_{EX_OK} {
+  message_loop_.SetAsCurrent();
+}
+
+Daemon::~Daemon() {
+}
+
+int Daemon::Run() {
+  int exit_code = OnInit();
+  if (exit_code != EX_OK)
+    return exit_code;
+
+  message_loop_.Run();
+
+  OnShutdown(&exit_code_);
+
+  // base::RunLoop::QuitClosure() causes the message loop to quit
+  // immediately, even if pending tasks are still queued.
+  // Run a secondary loop to make sure all those are processed.
+  // This becomes important when working with D-Bus since dbus::Bus does
+  // a bunch of clean-up tasks asynchronously when shutting down.
+  while (message_loop_.RunOnce(false /* may_block */)) {}
+
+  return exit_code_;
+}
+
+void Daemon::Quit() { QuitWithExitCode(EX_OK); }
+
+void Daemon::QuitWithExitCode(int exit_code) {
+  exit_code_ = exit_code;
+  message_loop_.PostTask(FROM_HERE, QuitClosure());
+}
+
+void Daemon::RegisterHandler(
+    int signal,
+    const AsynchronousSignalHandlerInterface::SignalHandler& callback) {
+  async_signal_handler_.RegisterHandler(signal, callback);
+}
+
+void Daemon::UnregisterHandler(int signal) {
+  async_signal_handler_.UnregisterHandler(signal);
+}
+
+int Daemon::OnInit() {
+  async_signal_handler_.Init();
+  for (int signal : {SIGTERM, SIGINT}) {
+    async_signal_handler_.RegisterHandler(
+        signal, base::Bind(&Daemon::Shutdown, base::Unretained(this)));
+  }
+  async_signal_handler_.RegisterHandler(
+      SIGHUP, base::Bind(&Daemon::Restart, base::Unretained(this)));
+  return EX_OK;
+}
+
+void Daemon::OnShutdown(int* /* exit_code */) {
+  // Do nothing.
+}
+
+bool Daemon::OnRestart() {
+  // Not handled.
+  return false;  // Returning false will shut down the daemon instead.
+}
+
+bool Daemon::Shutdown(const signalfd_siginfo& /* info */) {
+  Quit();
+  return true;  // Unregister the signal handler.
+}
+
+bool Daemon::Restart(const signalfd_siginfo& /* info */) {
+  if (OnRestart())
+    return false;  // Keep listening to the signal.
+  Quit();
+  return true;  // Unregister the signal handler.
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/daemons/daemon.h b/libbrillo/brillo/daemons/daemon.h
new file mode 100644
index 0000000..8a11f0f
--- /dev/null
+++ b/libbrillo/brillo/daemons/daemon.h
@@ -0,0 +1,114 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DAEMONS_DAEMON_H_
+#define LIBBRILLO_BRILLO_DAEMONS_DAEMON_H_
+
+#include <string>
+
+#include <base/at_exit.h>
+#include <base/macros.h>
+#include <base/message_loop/message_loop.h>
+#include <brillo/asynchronous_signal_handler.h>
+#include <brillo/brillo_export.h>
+#include <brillo/message_loops/base_message_loop.h>
+
+struct signalfd_siginfo;
+
+namespace brillo {
+
+// Daemon is a simple base class for system daemons. It provides a lot
+// of useful facilities such as a message loop, handling of SIGTERM, SIGINT, and
+// SIGHUP system signals.
+// You can use this class directly to implement your daemon or you can
+// specialize it by creating your own class and deriving it from
+// brillo::Daemon. Override some of the virtual methods provide to fine-tune
+// its behavior to suit your daemon's needs.
+class BRILLO_EXPORT Daemon : public AsynchronousSignalHandlerInterface {
+ public:
+  Daemon();
+  virtual ~Daemon();
+
+  // Performs proper initialization of the daemon and runs the message loop.
+  // Blocks until the daemon is finished. The return value is the error
+  // code that should be returned from daemon's main(). Returns EX_OK (0) on
+  // success.
+  virtual int Run();
+
+  // Can be used by call-backs to trigger shut-down of a running message loop.
+  // Calls QuiteWithExitCode(EX_OK);
+  // WARNING: This method (as well as QuitWithExitCode) can only be called when
+  // the message loop is running (that is, during Daemon::Run() call). Calling
+  // these methods before (e.g. during OnInit()) or after (e.g in OnShutdown())
+  // will lead to abnormal process termination.
+  void Quit();
+
+  // |exit_code| is the status code to be returned when the daemon process
+  // quits. See the warning for Quit() above regarding the allowed scope for
+  // this method.
+  void QuitWithExitCode(int exit_code);
+
+  // AsynchronousSignalHandlerInterface overrides.
+  // Register/unregister custom signal handlers for the daemon. The semantics
+  // are identical to AsynchronousSignalHandler::RegisterHandler and
+  // AsynchronousSignalHandler::UnregisterHandler, except that handlers for
+  // SIGTERM, SIGINT, and SIGHUP cannot be modified.
+  void RegisterHandler(
+      int signal, const
+      AsynchronousSignalHandlerInterface::SignalHandler& callback) override;
+  void UnregisterHandler(int signal) override;
+
+ protected:
+  // Overload to provide your own initialization code that should happen just
+  // before running the message loop. Return EX_OK (0) on success or any other
+  // non-zero error codes. If an error is returned, the message loop execution
+  // is aborted and Daemon::Run() exits early.
+  // When overloading, make sure you call the base implementation of OnInit().
+  virtual int OnInit();
+  // Called when the message loops exits and before Daemon::Run() returns.
+  // Overload to clean up the data that was set up during OnInit().
+  // |return_code| contains the current error code that will be returned from
+  // Run(). You can override this value with your own error code if needed.
+  // When overloading, make sure you call the base implementation of
+  // OnShutdown().
+  virtual void OnShutdown(int* exit_code);
+  // Called when the SIGHUP signal is received. In response to this call, your
+  // daemon could reset/reload the configuration and re-initialize its state
+  // as if the process has been reloaded.
+  // Return true if the signal was processed successfully and the daemon
+  // reset its configuration. Returning false will force the daemon to
+  // quit (and subsequently relaunched by an upstart job, if one is configured).
+  // The default implementation just returns false (unhandled), which terminates
+  // the daemon, so do not call the base implementation of OnRestart() from
+  // your overload.
+  virtual bool OnRestart();
+
+  // Returns a delegate to Quit() method in the base::RunLoop instance.
+  base::Closure QuitClosure() const {
+    return message_loop_.QuitClosure();
+  }
+
+ private:
+  // Called when SIGTERM/SIGINT signals are received.
+  bool Shutdown(const signalfd_siginfo& info);
+  // Called when SIGHUP signal is received.
+  bool Restart(const signalfd_siginfo& info);
+
+  // |at_exit_manager_| must be first to make sure it is initialized before
+  // other members, especially the |message_loop_|.
+  base::AtExitManager at_exit_manager_;
+  // The brillo wrapper for the base message loop.
+  BaseMessageLoop message_loop_;
+  // A helper to dispatch signal handlers asynchronously, so that the main
+  // system signal handler returns as soon as possible.
+  AsynchronousSignalHandler async_signal_handler_;
+  // Process exit code specified in QuitWithExitCode() method call.
+  int exit_code_;
+
+  DISALLOW_COPY_AND_ASSIGN(Daemon);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DAEMONS_DAEMON_H_
diff --git a/libbrillo/brillo/daemons/dbus_daemon.cc b/libbrillo/brillo/daemons/dbus_daemon.cc
new file mode 100644
index 0000000..a48b288
--- /dev/null
+++ b/libbrillo/brillo/daemons/dbus_daemon.cc
@@ -0,0 +1,82 @@
+// Copyright 2014 The Chromium OS 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 <brillo/daemons/dbus_daemon.h>
+
+#include <sysexits.h>
+
+#include <base/bind.h>
+#include <brillo/dbus/async_event_sequencer.h>
+#include <brillo/dbus/exported_object_manager.h>
+
+using brillo::dbus_utils::AsyncEventSequencer;
+using brillo::dbus_utils::ExportedObjectManager;
+
+namespace brillo {
+
+DBusDaemon::DBusDaemon() {
+}
+
+int DBusDaemon::OnInit() {
+  int exit_code = Daemon::OnInit();
+  if (exit_code != EX_OK)
+    return exit_code;
+
+  bus_ = dbus_connection_.Connect();
+  CHECK(bus_);
+
+  return exit_code;
+}
+
+DBusServiceDaemon::DBusServiceDaemon(const std::string& service_name)
+    : service_name_(service_name) {
+}
+
+DBusServiceDaemon::DBusServiceDaemon(
+    const std::string& service_name,
+    const dbus::ObjectPath& object_manager_path)
+    : service_name_(service_name), object_manager_path_(object_manager_path) {
+}
+
+DBusServiceDaemon::DBusServiceDaemon(const std::string& service_name,
+                                     base::StringPiece object_manager_path)
+    : DBusServiceDaemon(service_name,
+                        dbus::ObjectPath(object_manager_path.as_string())) {
+}
+
+int DBusServiceDaemon::OnInit() {
+  int exit_code = DBusDaemon::OnInit();
+  if (exit_code != EX_OK)
+    return exit_code;
+
+  scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
+  if (object_manager_path_.IsValid()) {
+    object_manager_.reset(
+        new ExportedObjectManager(bus_, object_manager_path_));
+    object_manager_->RegisterAsync(
+        sequencer->GetHandler("ObjectManager.RegisterAsync() failed.", true));
+  }
+  RegisterDBusObjectsAsync(sequencer.get());
+  sequencer->OnAllTasksCompletedCall({
+      base::Bind(&DBusServiceDaemon::TakeServiceOwnership,
+                 base::Unretained(this))
+  });
+  return EX_OK;
+}
+
+void DBusServiceDaemon::RegisterDBusObjectsAsync(
+    dbus_utils::AsyncEventSequencer* /* sequencer */) {
+  // Do nothing here.
+  // Overload this method to export custom D-Bus objects at daemon startup.
+}
+
+void DBusServiceDaemon::TakeServiceOwnership(bool success) {
+  // Success should always be true since we've said that failures are fatal.
+  CHECK(success) << "Init of one or more objects has failed.";
+  CHECK(bus_->RequestOwnershipAndBlock(service_name_,
+                                       dbus::Bus::REQUIRE_PRIMARY))
+      << "Unable to take ownership of " << service_name_;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/daemons/dbus_daemon.h b/libbrillo/brillo/daemons/dbus_daemon.h
new file mode 100644
index 0000000..25ce306
--- /dev/null
+++ b/libbrillo/brillo/daemons/dbus_daemon.h
@@ -0,0 +1,93 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DAEMONS_DBUS_DAEMON_H_
+#define LIBBRILLO_BRILLO_DAEMONS_DBUS_DAEMON_H_
+
+#include <memory>
+#include <string>
+
+#include <base/strings/string_piece.h>
+#include <base/memory/ref_counted.h>
+#include <brillo/brillo_export.h>
+#include <brillo/daemons/daemon.h>
+#include <brillo/dbus/dbus_connection.h>
+#include <brillo/dbus/exported_object_manager.h>
+#include <dbus/bus.h>
+
+namespace brillo {
+
+namespace dbus_utils {
+class AsyncEventSequencer;
+}  // namespace dbus_utils
+
+// DBusDaemon adds D-Bus support to Daemon.
+// Derive your daemon from this class if you want D-Bus client services in your
+// daemon (consuming other D-Bus objects). Currently uses a SYSTEM bus.
+class BRILLO_EXPORT DBusDaemon : public Daemon {
+ public:
+  DBusDaemon();
+  ~DBusDaemon() override = default;
+
+ protected:
+  // Calls the base OnInit() and then instantiates dbus::Bus and establishes
+  // a D-Bus connection.
+  int OnInit() override;
+
+  // A reference to the |dbus_connection_| bus object often used by derived
+  // classes.
+  scoped_refptr<dbus::Bus> bus_;
+
+ private:
+  DBusConnection dbus_connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(DBusDaemon);
+};
+
+// DBusServiceDaemon adds D-Bus service support to DBusDaemon.
+// Derive your daemon from this class if your daemon exposes D-Bus objects.
+// Provides an ExportedObjectManager to announce your object/interface creation
+// and destruction.
+class BRILLO_EXPORT DBusServiceDaemon : public DBusDaemon {
+ public:
+  // Constructs the daemon.
+  // |service_name| is the name of D-Bus service provided by the daemon.
+  // |object_manager_path_| is a well-known D-Bus object path for
+  // ExportedObjectManager object.
+  // If |object_manager_path_| is not specified, then ExportedObjectManager is
+  // not created and is not available as part of the D-Bus service.
+  explicit DBusServiceDaemon(const std::string& service_name);
+  DBusServiceDaemon(const std::string& service_name,
+                    const dbus::ObjectPath& object_manager_path);
+  DBusServiceDaemon(const std::string& service_name,
+                    base::StringPiece object_manager_path);
+
+ protected:
+  // OnInit() overload exporting D-Bus objects. Exports the contained
+  // ExportedObjectManager object and calls RegisterDBusObjectsAsync() to let
+  // you provide additional D-Bus objects.
+  int OnInit() override;
+
+  // Overload this method to export your custom D-Bus objects at startup.
+  // Objects exported in this way will finish exporting before we claim the
+  // daemon's service name on DBus.
+  virtual void RegisterDBusObjectsAsync(
+      dbus_utils::AsyncEventSequencer* sequencer);
+
+  std::string service_name_;
+  dbus::ObjectPath object_manager_path_;
+  std::unique_ptr<dbus_utils::ExportedObjectManager> object_manager_;
+
+ private:
+  // A callback that will be called when all the D-Bus objects/interfaces are
+  // exported successfully and the daemon is ready to claim the D-Bus service
+  // ownership.
+  void TakeServiceOwnership(bool success);
+
+  DISALLOW_COPY_AND_ASSIGN(DBusServiceDaemon);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DAEMONS_DBUS_DAEMON_H_
diff --git a/libbrillo/brillo/data_encoding.cc b/libbrillo/brillo/data_encoding.cc
new file mode 100644
index 0000000..f3e95f8
--- /dev/null
+++ b/libbrillo/brillo/data_encoding.cc
@@ -0,0 +1,154 @@
+// Copyright 2014 The Chromium OS 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 <brillo/data_encoding.h>
+#include <modp_b64/modp_b64.h>
+
+#include <memory>
+
+#include <base/logging.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+#include <brillo/strings/string_utils.h>
+
+namespace {
+
+inline int HexToDec(int hex) {
+  int dec = -1;
+  if (hex >= '0' && hex <= '9') {
+    dec = hex - '0';
+  } else if (hex >= 'A' && hex <= 'F') {
+    dec = hex - 'A' + 10;
+  } else if (hex >= 'a' && hex <= 'f') {
+    dec = hex - 'a' + 10;
+  }
+  return dec;
+}
+
+// Helper for Base64Encode() and Base64EncodeWrapLines().
+std::string Base64EncodeHelper(const void* data, size_t size) {
+  std::vector<char> buffer;
+  buffer.resize(modp_b64_encode_len(size));
+  size_t out_size = modp_b64_encode(buffer.data(),
+                                    static_cast<const char*>(data),
+                                    size);
+  return std::string{buffer.begin(), buffer.begin() + out_size};
+}
+
+}  // namespace
+
+/////////////////////////////////////////////////////////////////////////
+namespace brillo {
+namespace data_encoding {
+
+std::string UrlEncode(const char* data, bool encodeSpaceAsPlus) {
+  std::string result;
+
+  while (*data) {
+    char c = *data++;
+    // According to RFC3986 (http://www.faqs.org/rfcs/rfc3986.html),
+    // section 2.3. - Unreserved Characters
+    if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
+        (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' ||
+        c == '~') {
+      result += c;
+    } else if (c == ' ' && encodeSpaceAsPlus) {
+      // For historical reasons, some URLs have spaces encoded as '+',
+      // this also applies to form data encoded as
+      // 'application/x-www-form-urlencoded'
+      result += '+';
+    } else {
+      base::StringAppendF(&result,
+                          "%%%02X",
+                          static_cast<unsigned char>(c));  // Encode as %NN
+    }
+  }
+  return result;
+}
+
+std::string UrlDecode(const char* data) {
+  std::string result;
+  while (*data) {
+    char c = *data++;
+    int part1 = 0, part2 = 0;
+    // HexToDec would return -1 even for character 0 (end of string),
+    // so it is safe to access data[0] and data[1] without overrunning the buf.
+    if (c == '%' && (part1 = HexToDec(data[0])) >= 0 &&
+        (part2 = HexToDec(data[1])) >= 0) {
+      c = static_cast<char>((part1 << 4) | part2);
+      data += 2;
+    } else if (c == '+') {
+      c = ' ';
+    }
+    result += c;
+  }
+  return result;
+}
+
+std::string WebParamsEncode(const WebParamList& params,
+                            bool encodeSpaceAsPlus) {
+  std::vector<std::string> pairs;
+  pairs.reserve(params.size());
+  for (const auto& p : params) {
+    std::string key = UrlEncode(p.first.c_str(), encodeSpaceAsPlus);
+    std::string value = UrlEncode(p.second.c_str(), encodeSpaceAsPlus);
+    pairs.push_back(brillo::string_utils::Join("=", key, value));
+  }
+
+  return brillo::string_utils::Join("&", pairs);
+}
+
+WebParamList WebParamsDecode(const std::string& data) {
+  WebParamList result;
+  std::vector<std::string> params = brillo::string_utils::Split(data, "&");
+  for (const auto& p : params) {
+    auto pair = brillo::string_utils::SplitAtFirst(p, "=");
+    result.emplace_back(UrlDecode(pair.first.c_str()),
+                        UrlDecode(pair.second.c_str()));
+  }
+  return result;
+}
+
+std::string Base64Encode(const void* data, size_t size) {
+  return Base64EncodeHelper(data, size);
+}
+
+std::string Base64EncodeWrapLines(const void* data, size_t size) {
+  std::string unwrapped = Base64EncodeHelper(data, size);
+  std::string wrapped;
+
+  for (size_t i = 0; i < unwrapped.size(); i += 64) {
+    wrapped.append(unwrapped, i, 64);
+    wrapped.append("\n");
+  }
+  return wrapped;
+}
+
+bool Base64Decode(const std::string& input, brillo::Blob* output) {
+  std::string temp_buffer;
+  const std::string* data = &input;
+  if (input.find_first_of("\r\n") != std::string::npos) {
+    base::ReplaceChars(input, "\n", "", &temp_buffer);
+    base::ReplaceChars(temp_buffer, "\r", "", &temp_buffer);
+    data = &temp_buffer;
+  }
+  // base64 decoded data has 25% fewer bytes than the original (since every
+  // 3 source octets are encoded as 4 characters in base64).
+  // modp_b64_decode_len provides an upper estimate of the size of the output
+  // data.
+  output->resize(modp_b64_decode_len(data->size()));
+
+  size_t size_read = modp_b64_decode(reinterpret_cast<char*>(output->data()),
+                                     data->data(), data->size());
+  if (size_read == MODP_B64_ERROR) {
+    output->resize(0);
+    return false;
+  }
+  output->resize(size_read);
+
+  return true;
+}
+
+}  // namespace data_encoding
+}  // namespace brillo
diff --git a/libbrillo/brillo/data_encoding.h b/libbrillo/brillo/data_encoding.h
new file mode 100644
index 0000000..95d266c
--- /dev/null
+++ b/libbrillo/brillo/data_encoding.h
@@ -0,0 +1,82 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DATA_ENCODING_H_
+#define LIBBRILLO_BRILLO_DATA_ENCODING_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <brillo/brillo_export.h>
+#include <brillo/secure_blob.h>
+
+namespace brillo {
+namespace data_encoding {
+
+using WebParamList = std::vector<std::pair<std::string, std::string>>;
+
+// Encode/escape string to be used in the query portion of a URL.
+// If |encodeSpaceAsPlus| is set to true, spaces are encoded as '+' instead
+// of "%20"
+BRILLO_EXPORT std::string UrlEncode(const char* data, bool encodeSpaceAsPlus);
+
+inline std::string UrlEncode(const char* data) {
+  return UrlEncode(data, true);
+}
+
+// Decodes/unescapes a URL. Replaces all %XX sequences with actual characters.
+// Also replaces '+' with spaces.
+BRILLO_EXPORT std::string UrlDecode(const char* data);
+
+// Converts a list of key-value pairs into a string compatible with
+// 'application/x-www-form-urlencoded' content encoding.
+BRILLO_EXPORT std::string WebParamsEncode(const WebParamList& params,
+                                          bool encodeSpaceAsPlus);
+
+inline std::string WebParamsEncode(const WebParamList& params) {
+  return WebParamsEncode(params, true);
+}
+
+// Parses a string of '&'-delimited key-value pairs (separated by '=') and
+// encoded in a way compatible with 'application/x-www-form-urlencoded'
+// content encoding.
+BRILLO_EXPORT WebParamList WebParamsDecode(const std::string& data);
+
+// Encodes binary data using base64-encoding.
+BRILLO_EXPORT std::string Base64Encode(const void* data, size_t size);
+
+// Encodes binary data using base64-encoding and wraps lines at 64 character
+// boundary using LF as required by PEM (RFC 1421) specification.
+BRILLO_EXPORT std::string Base64EncodeWrapLines(const void* data, size_t size);
+
+// Decodes the input string from Base64.
+BRILLO_EXPORT bool Base64Decode(const std::string& input, brillo::Blob* output);
+
+// Helper wrappers to use std::string and brillo::Blob as binary data
+// containers.
+inline std::string Base64Encode(const brillo::Blob& input) {
+  return Base64Encode(input.data(), input.size());
+}
+inline std::string Base64EncodeWrapLines(const brillo::Blob& input) {
+  return Base64EncodeWrapLines(input.data(), input.size());
+}
+inline std::string Base64Encode(const std::string& input) {
+  return Base64Encode(input.data(), input.size());
+}
+inline std::string Base64EncodeWrapLines(const std::string& input) {
+  return Base64EncodeWrapLines(input.data(), input.size());
+}
+inline bool Base64Decode(const std::string& input, std::string* output) {
+  brillo::Blob blob;
+  if (!Base64Decode(input, &blob))
+    return false;
+  *output = std::string{blob.begin(), blob.end()};
+  return true;
+}
+
+}  // namespace data_encoding
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DATA_ENCODING_H_
diff --git a/libbrillo/brillo/data_encoding_unittest.cc b/libbrillo/brillo/data_encoding_unittest.cc
new file mode 100644
index 0000000..cb73da6
--- /dev/null
+++ b/libbrillo/brillo/data_encoding_unittest.cc
@@ -0,0 +1,147 @@
+// Copyright (c) 2011 The Chromium OS 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 <brillo/data_encoding.h>
+
+#include <algorithm>
+#include <numeric>
+
+#include <gtest/gtest.h>
+
+namespace brillo {
+namespace data_encoding {
+
+TEST(data_encoding, UrlEncoding) {
+  std::string test = "\"http://sample/path/0014.html \"";
+  std::string encoded = UrlEncode(test.c_str());
+  EXPECT_EQ("%22http%3A%2F%2Fsample%2Fpath%2F0014.html+%22", encoded);
+  EXPECT_EQ(test, UrlDecode(encoded.c_str()));
+
+  test = "\"http://sample/path/0014.html \"";
+  encoded = UrlEncode(test.c_str(), false);
+  EXPECT_EQ("%22http%3A%2F%2Fsample%2Fpath%2F0014.html%20%22", encoded);
+  EXPECT_EQ(test, UrlDecode(encoded.c_str()));
+}
+
+TEST(data_encoding, WebParamsEncoding) {
+  std::string encoded =
+      WebParamsEncode({{"q", "test"}, {"path", "/usr/bin"}, {"#", "%"}});
+  EXPECT_EQ("q=test&path=%2Fusr%2Fbin&%23=%25", encoded);
+
+  auto params = WebParamsDecode(encoded);
+  EXPECT_EQ(3, params.size());
+  EXPECT_EQ("q", params[0].first);
+  EXPECT_EQ("test", params[0].second);
+  EXPECT_EQ("path", params[1].first);
+  EXPECT_EQ("/usr/bin", params[1].second);
+  EXPECT_EQ("#", params[2].first);
+  EXPECT_EQ("%", params[2].second);
+}
+
+TEST(data_encoding, Base64Encode) {
+  const std::string text1 = "hello world";
+  const std::string encoded1 = "aGVsbG8gd29ybGQ=";
+
+  const std::string text2 =
+      "Lorem ipsum dolor sit amet, facilisis erat nec aliquam, scelerisque "
+      "molestie commodo. Viverra tincidunt integer erat ipsum, integer "
+      "molestie, arcu in, sit mauris ac a sed sit etiam.";
+  const std::string encoded2 =
+      "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGZhY2lsaXNpcyBlcmF0IG5lYyBhbGlxdWF"
+      "tLCBzY2VsZXJpc3F1ZSBtb2xlc3RpZSBjb21tb2RvLiBWaXZlcnJhIHRpbmNpZHVudCBpbn"
+      "RlZ2VyIGVyYXQgaXBzdW0sIGludGVnZXIgbW9sZXN0aWUsIGFyY3UgaW4sIHNpdCBtYXVya"
+      "XMgYWMgYSBzZWQgc2l0IGV0aWFtLg==";
+
+  brillo::Blob data3(256);
+  std::iota(data3.begin(), data3.end(), 0);  // Fills the buffer with 0x00-0xFF.
+  const std::string encoded3 =
+      "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ"
+      "1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaW"
+      "prbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en"
+      "6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU"
+      "1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==";
+
+  EXPECT_EQ(encoded1, Base64Encode(text1));
+  EXPECT_EQ(encoded2, Base64Encode(text2));
+  EXPECT_EQ(encoded3, Base64Encode(data3));
+}
+
+TEST(data_encoding, Base64EncodeWrapLines) {
+  const std::string text1 = "hello world";
+  const std::string encoded1 = "aGVsbG8gd29ybGQ=\n";
+
+  const std::string text2 =
+      "Lorem ipsum dolor sit amet, facilisis erat nec aliquam, scelerisque "
+      "molestie commodo. Viverra tincidunt integer erat ipsum, integer "
+      "molestie, arcu in, sit mauris ac a sed sit etiam.";
+  const std::string encoded2 =
+      "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGZhY2lsaXNpcyBlcmF0IG5lYyBh\n"
+      "bGlxdWFtLCBzY2VsZXJpc3F1ZSBtb2xlc3RpZSBjb21tb2RvLiBWaXZlcnJhIHRp\n"
+      "bmNpZHVudCBpbnRlZ2VyIGVyYXQgaXBzdW0sIGludGVnZXIgbW9sZXN0aWUsIGFy\n"
+      "Y3UgaW4sIHNpdCBtYXVyaXMgYWMgYSBzZWQgc2l0IGV0aWFtLg==\n";
+
+  brillo::Blob data3(256);
+  std::iota(data3.begin(), data3.end(), 0);  // Fills the buffer with 0x00-0xFF.
+  const std::string encoded3 =
+      "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4v\n"
+      "MDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5f\n"
+      "YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P\n"
+      "kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/\n"
+      "wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v\n"
+      "8PHy8/T19vf4+fr7/P3+/w==\n";
+
+  EXPECT_EQ(encoded1, Base64EncodeWrapLines(text1));
+  EXPECT_EQ(encoded2, Base64EncodeWrapLines(text2));
+  EXPECT_EQ(encoded3, Base64EncodeWrapLines(data3));
+}
+
+TEST(data_encoding, Base64Decode) {
+  const std::string encoded1 = "dGVzdCBzdHJpbmc=";
+
+  const std::string encoded2 =
+      "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGZhY2lsaXNpcyBlcmF0IG5lYyBh\n"
+      "bGlxdWFtLCBzY2VsZXJpc3F1ZSBtb2xlc3RpZSBjb21tb2RvLiBWaXZlcnJhIHRp\r\n"
+      "bmNpZHVudCBpbnRlZ2VyIGVyYXQgaXBzdW0sIGludGVnZXIgbW9sZXN0aWUsIGFy\r"
+      "Y3UgaW4sIHNpdCBtYXVyaXMgYWMgYSBzZWQgc2l0IGV0aWFt\n"
+      "Lg==\n\n\n";
+  const std::string decoded2 =
+      "Lorem ipsum dolor sit amet, facilisis erat nec aliquam, scelerisque "
+      "molestie commodo. Viverra tincidunt integer erat ipsum, integer "
+      "molestie, arcu in, sit mauris ac a sed sit etiam.";
+
+  const std::string encoded3 =
+      "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ"
+      "1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaW"
+      "prbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en"
+      "6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU"
+      "1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==";
+  brillo::Blob decoded3(256);
+  std::iota(decoded3.begin(), decoded3.end(), 0);  // Fill with 0x00..0xFF.
+
+  std::string decoded;
+  EXPECT_TRUE(Base64Decode(encoded1, &decoded));
+  EXPECT_EQ("test string", decoded);
+
+  EXPECT_TRUE(Base64Decode(encoded2, &decoded));
+  EXPECT_EQ(decoded2, decoded);
+
+  brillo::Blob decoded_blob;
+  EXPECT_TRUE(Base64Decode(encoded3, &decoded_blob));
+  EXPECT_EQ(decoded3, decoded_blob);
+
+  EXPECT_FALSE(Base64Decode("A", &decoded_blob));
+  EXPECT_TRUE(decoded_blob.empty());
+
+  EXPECT_TRUE(Base64Decode("/w==", &decoded_blob));
+  EXPECT_EQ((brillo::Blob{0xFF}), decoded_blob);
+
+  EXPECT_TRUE(Base64Decode("//8=", &decoded_blob));
+  EXPECT_EQ((brillo::Blob{0xFF, 0xFF}), decoded_blob);
+
+  EXPECT_FALSE(Base64Decode("AAECAwQFB,cI", &decoded_blob));
+  EXPECT_TRUE(decoded_blob.empty());
+}
+
+}  // namespace data_encoding
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/async_event_sequencer.cc b/libbrillo/brillo/dbus/async_event_sequencer.cc
new file mode 100644
index 0000000..8861e21
--- /dev/null
+++ b/libbrillo/brillo/dbus/async_event_sequencer.cc
@@ -0,0 +1,131 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/async_event_sequencer.h>
+
+namespace brillo {
+
+namespace dbus_utils {
+
+AsyncEventSequencer::AsyncEventSequencer() {
+}
+AsyncEventSequencer::~AsyncEventSequencer() {
+}
+
+AsyncEventSequencer::Handler AsyncEventSequencer::GetHandler(
+    const std::string& descriptive_message,
+    bool failure_is_fatal) {
+  CHECK(!started_) << "Cannot create handlers after OnAllTasksCompletedCall()";
+  int unique_registration_id = ++registration_counter_;
+  outstanding_registrations_.insert(unique_registration_id);
+  return base::Bind(&AsyncEventSequencer::HandleFinish,
+                    this,
+                    unique_registration_id,
+                    descriptive_message,
+                    failure_is_fatal);
+}
+
+AsyncEventSequencer::ExportHandler AsyncEventSequencer::GetExportHandler(
+    const std::string& interface_name,
+    const std::string& method_name,
+    const std::string& descriptive_message,
+    bool failure_is_fatal) {
+  auto finish_handler = GetHandler(descriptive_message, failure_is_fatal);
+  return base::Bind(&AsyncEventSequencer::HandleDBusMethodExported,
+                    this,
+                    finish_handler,
+                    interface_name,
+                    method_name);
+}
+
+void AsyncEventSequencer::OnAllTasksCompletedCall(
+    std::vector<CompletionAction> actions) {
+  CHECK(!started_) << "OnAllTasksCompletedCall called twice!";
+  started_ = true;
+  completion_actions_.assign(actions.begin(), actions.end());
+  // All of our callbacks might have been called already.
+  PossiblyRunCompletionActions();
+}
+
+namespace {
+void IgnoreSuccess(const AsyncEventSequencer::CompletionTask& task,
+                   bool /*success*/) {
+  task.Run();
+}
+void DoNothing(bool /* success */) {
+}
+}  // namespace
+
+AsyncEventSequencer::CompletionAction AsyncEventSequencer::WrapCompletionTask(
+    const CompletionTask& task) {
+  return base::Bind(&IgnoreSuccess, task);
+}
+
+AsyncEventSequencer::CompletionAction
+AsyncEventSequencer::GetDefaultCompletionAction() {
+  return base::Bind(&DoNothing);
+}
+
+void AsyncEventSequencer::HandleFinish(int registration_number,
+                                       const std::string& error_message,
+                                       bool failure_is_fatal,
+                                       bool success) {
+  RetireRegistration(registration_number);
+  CheckForFailure(failure_is_fatal, success, error_message);
+  PossiblyRunCompletionActions();
+}
+
+void AsyncEventSequencer::HandleDBusMethodExported(
+    const AsyncEventSequencer::Handler& finish_handler,
+    const std::string& expected_interface_name,
+    const std::string& expected_method_name,
+    const std::string& actual_interface_name,
+    const std::string& actual_method_name,
+    bool success) {
+  CHECK_EQ(expected_method_name, actual_method_name)
+      << "Exported DBus method '" << actual_method_name << "' "
+      << "but expected '" << expected_method_name << "'";
+  CHECK_EQ(expected_interface_name, actual_interface_name)
+      << "Exported method DBus interface '" << actual_interface_name << "' "
+      << "but expected '" << expected_interface_name << "'";
+  finish_handler.Run(success);
+}
+
+void AsyncEventSequencer::RetireRegistration(int registration_number) {
+  const size_t handlers_retired =
+      outstanding_registrations_.erase(registration_number);
+  CHECK_EQ(1U, handlers_retired) << "Tried to retire invalid handler "
+                                 << registration_number << ")";
+}
+
+void AsyncEventSequencer::CheckForFailure(bool failure_is_fatal,
+                                          bool success,
+                                          const std::string& error_message) {
+  if (failure_is_fatal) {
+    CHECK(success) << error_message;
+  }
+  if (!success) {
+    LOG(ERROR) << error_message;
+    had_failures_ = true;
+  }
+}
+
+void AsyncEventSequencer::PossiblyRunCompletionActions() {
+  if (!started_ || !outstanding_registrations_.empty()) {
+    // Don't run completion actions if we have any outstanding
+    // Handlers outstanding or if any more handlers might
+    // be scheduled in the future.
+    return;
+  }
+  for (const auto& completion_action : completion_actions_) {
+    // Should this be put on the message loop or run directly?
+    completion_action.Run(!had_failures_);
+  }
+  // Discard our references to those actions.
+  completion_actions_.clear();
+}
+
+}  // namespace dbus_utils
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/async_event_sequencer.h b/libbrillo/brillo/dbus/async_event_sequencer.h
new file mode 100644
index 0000000..c817b55
--- /dev/null
+++ b/libbrillo/brillo/dbus/async_event_sequencer.h
@@ -0,0 +1,113 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_ASYNC_EVENT_SEQUENCER_H_
+#define LIBBRILLO_BRILLO_DBUS_ASYNC_EVENT_SEQUENCER_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+namespace dbus_utils {
+
+// A helper class for coordinating the multiple async tasks.  A consumer
+// may grab any number of callbacks via Get*Handler() and schedule a list
+// of completion actions to take.  When all handlers obtained via Get*Handler()
+// have been called, the AsyncEventSequencer will call its CompletionActions.
+//
+// Usage:
+//
+// void Init(const base::Callback<void(bool success)> cb) {
+//   scoped_refptr<AsyncEventSequencer> sequencer(
+//       new AsyncEventSequencer());
+//   one_delegate_needing_init_.Init(sequencer->GetHandler(
+//       "my delegate failed to init", false));
+//   dbus_init_delegate_.Init(sequencer->GetExportHandler(
+//       "org.test.Interface", "ExposedMethodName",
+//       "another delegate is flaky", false));
+//   sequencer->OnAllTasksCompletedCall({cb});
+// }
+class BRILLO_EXPORT AsyncEventSequencer
+    : public base::RefCounted<AsyncEventSequencer> {
+ public:
+  using Handler = base::Callback<void(bool success)>;
+  using ExportHandler = base::Callback<void(const std::string& interface_name,
+                                            const std::string& method_name,
+                                            bool success)>;
+  using CompletionAction = base::Callback<void(bool all_succeeded)>;
+  using CompletionTask = base::Callback<void(void)>;
+
+  AsyncEventSequencer();
+
+  // Get a Finished handler callback.  Each callback is "unique" in the sense
+  // that subsequent calls to GetHandler() will create new handlers
+  // which will need to be called before completion actions are run.
+  Handler GetHandler(const std::string& descriptive_message,
+                     bool failure_is_fatal);
+
+  // Like GetHandler except with a signature tailored to
+  // ExportedObject's ExportMethod callback requirements.  Will also assert
+  // that the passed interface/method names from ExportedObject are correct.
+  ExportHandler GetExportHandler(const std::string& interface_name,
+                                 const std::string& method_name,
+                                 const std::string& descriptive_message,
+                                 bool failure_is_fatal);
+
+  // Once all handlers obtained via GetHandler have run,
+  // we'll run each CompletionAction, then discard our references.
+  // No more handlers may be obtained after this call.
+  void OnAllTasksCompletedCall(std::vector<CompletionAction> actions);
+
+  // Wrap a CompletionTask with a function that discards the result.
+  // This CompletionTask retains no references to the AsyncEventSequencer.
+  static CompletionAction WrapCompletionTask(const CompletionTask& task);
+  // Create a default CompletionAction that doesn't do anything when called.
+  static CompletionAction GetDefaultCompletionAction();
+
+ private:
+  // We'll partially bind this function before giving it back via
+  // GetHandler.  Note that the returned callbacks have
+  // references to *this, which gives us the neat property that we'll
+  // destroy *this only when all our callbacks have been destroyed.
+  BRILLO_PRIVATE void HandleFinish(int registration_number,
+                                   const std::string& error_message,
+                                   bool failure_is_fatal,
+                                   bool success);
+  // Similar to HandleFinish.
+  BRILLO_PRIVATE void HandleDBusMethodExported(
+      const Handler& finish_handler,
+      const std::string& expected_interface_name,
+      const std::string& expected_method_name,
+      const std::string& actual_interface_name,
+      const std::string& actual_method_name,
+      bool success);
+  BRILLO_PRIVATE void RetireRegistration(int registration_number);
+  BRILLO_PRIVATE void CheckForFailure(bool failure_is_fatal,
+                                      bool success,
+                                      const std::string& error_message);
+  BRILLO_PRIVATE void PossiblyRunCompletionActions();
+
+  bool started_{false};
+  int registration_counter_{0};
+  std::set<int> outstanding_registrations_;
+  std::vector<CompletionAction> completion_actions_;
+  bool had_failures_{false};
+  // Ref counted objects have private destructors.
+  ~AsyncEventSequencer();
+  friend class base::RefCounted<AsyncEventSequencer>;
+  DISALLOW_COPY_AND_ASSIGN(AsyncEventSequencer);
+};
+
+}  // namespace dbus_utils
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_ASYNC_EVENT_SEQUENCER_H_
diff --git a/libbrillo/brillo/dbus/async_event_sequencer_unittest.cc b/libbrillo/brillo/dbus/async_event_sequencer_unittest.cc
new file mode 100644
index 0000000..5f4c0e2
--- /dev/null
+++ b/libbrillo/brillo/dbus/async_event_sequencer_unittest.cc
@@ -0,0 +1,96 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/async_event_sequencer.h>
+
+#include <base/bind_helpers.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+namespace dbus_utils {
+
+namespace {
+
+const char kTestInterface[] = "org.test.if";
+const char kTestMethod1[] = "TestMethod1";
+const char kTestMethod2[] = "TestMethod2";
+
+}  // namespace
+
+class AsyncEventSequencerTest : public ::testing::Test {
+ public:
+  MOCK_METHOD1(HandleCompletion, void(bool all_succeeded));
+
+  void SetUp() {
+    aec_ = new AsyncEventSequencer();
+    cb_ = base::Bind(&AsyncEventSequencerTest::HandleCompletion,
+                     base::Unretained(this));
+  }
+
+  scoped_refptr<AsyncEventSequencer> aec_;
+  AsyncEventSequencer::CompletionAction cb_;
+};
+
+TEST_F(AsyncEventSequencerTest, WaitForCompletionActions) {
+  auto finished_handler = aec_->GetHandler("handler failed", false);
+  finished_handler.Run(true);
+  EXPECT_CALL(*this, HandleCompletion(true)).Times(1);
+  aec_->OnAllTasksCompletedCall({cb_});
+}
+
+TEST_F(AsyncEventSequencerTest, MultiInitActionsSucceed) {
+  auto finished_handler1 = aec_->GetHandler("handler failed", false);
+  auto finished_handler2 = aec_->GetHandler("handler failed", false);
+  aec_->OnAllTasksCompletedCall({cb_});
+  finished_handler1.Run(true);
+  EXPECT_CALL(*this, HandleCompletion(true)).Times(1);
+  finished_handler2.Run(true);
+}
+
+TEST_F(AsyncEventSequencerTest, SomeInitActionsFail) {
+  auto finished_handler1 = aec_->GetHandler("handler failed", false);
+  auto finished_handler2 = aec_->GetHandler("handler failed", false);
+  aec_->OnAllTasksCompletedCall({cb_});
+  finished_handler1.Run(false);
+  EXPECT_CALL(*this, HandleCompletion(false)).Times(1);
+  finished_handler2.Run(true);
+}
+
+TEST_F(AsyncEventSequencerTest, MultiDBusActionsSucceed) {
+  auto handler1 = aec_->GetExportHandler(
+      kTestInterface, kTestMethod1, "method export failed", false);
+  auto handler2 = aec_->GetExportHandler(
+      kTestInterface, kTestMethod2, "method export failed", false);
+  aec_->OnAllTasksCompletedCall({cb_});
+  handler1.Run(kTestInterface, kTestMethod1, true);
+  EXPECT_CALL(*this, HandleCompletion(true)).Times(1);
+  handler2.Run(kTestInterface, kTestMethod2, true);
+}
+
+TEST_F(AsyncEventSequencerTest, SomeDBusActionsFail) {
+  auto handler1 = aec_->GetExportHandler(
+      kTestInterface, kTestMethod1, "method export failed", false);
+  auto handler2 = aec_->GetExportHandler(
+      kTestInterface, kTestMethod2, "method export failed", false);
+  aec_->OnAllTasksCompletedCall({cb_});
+  handler1.Run(kTestInterface, kTestMethod1, true);
+  EXPECT_CALL(*this, HandleCompletion(false)).Times(1);
+  handler2.Run(kTestInterface, kTestMethod2, false);
+}
+
+TEST_F(AsyncEventSequencerTest, MixedActions) {
+  auto handler1 = aec_->GetExportHandler(
+      kTestInterface, kTestMethod1, "method export failed", false);
+  auto handler2 = aec_->GetHandler("handler failed", false);
+  aec_->OnAllTasksCompletedCall({cb_});
+  handler1.Run(kTestInterface, kTestMethod1, true);
+  EXPECT_CALL(*this, HandleCompletion(true)).Times(1);
+  handler2.Run(true);
+}
+
+}  // namespace dbus_utils
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/data_serialization.cc b/libbrillo/brillo/dbus/data_serialization.cc
new file mode 100644
index 0000000..86d1c63
--- /dev/null
+++ b/libbrillo/brillo/dbus/data_serialization.cc
@@ -0,0 +1,324 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/data_serialization.h>
+
+#include <base/logging.h>
+#include <brillo/any.h>
+#include <brillo/variant_dictionary.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+void AppendValueToWriter(dbus::MessageWriter* writer, bool value) {
+  writer->AppendBool(value);
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer, uint8_t value) {
+  writer->AppendByte(value);
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer, int16_t value) {
+  writer->AppendInt16(value);
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer, uint16_t value) {
+  writer->AppendUint16(value);
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer, int32_t value) {
+  writer->AppendInt32(value);
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer, uint32_t value) {
+  writer->AppendUint32(value);
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer, int64_t value) {
+  writer->AppendInt64(value);
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer, uint64_t value) {
+  writer->AppendUint64(value);
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer, double value) {
+  writer->AppendDouble(value);
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer,
+                         const std::string& value) {
+  writer->AppendString(value);
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer, const char* value) {
+  AppendValueToWriter(writer, std::string(value));
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer,
+                         const dbus::ObjectPath& value) {
+  writer->AppendObjectPath(value);
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer,
+                         const dbus::FileDescriptor& value) {
+  writer->AppendFileDescriptor(value);
+}
+
+void AppendValueToWriter(dbus::MessageWriter* writer,
+                         const brillo::Any& value) {
+  value.AppendToDBusMessageWriter(writer);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool PopValueFromReader(dbus::MessageReader* reader, bool* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
+         reader->PopBool(value);
+}
+
+bool PopValueFromReader(dbus::MessageReader* reader, uint8_t* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
+         reader->PopByte(value);
+}
+
+bool PopValueFromReader(dbus::MessageReader* reader, int16_t* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
+         reader->PopInt16(value);
+}
+
+bool PopValueFromReader(dbus::MessageReader* reader, uint16_t* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
+         reader->PopUint16(value);
+}
+
+bool PopValueFromReader(dbus::MessageReader* reader, int32_t* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
+         reader->PopInt32(value);
+}
+
+bool PopValueFromReader(dbus::MessageReader* reader, uint32_t* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
+         reader->PopUint32(value);
+}
+
+bool PopValueFromReader(dbus::MessageReader* reader, int64_t* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
+         reader->PopInt64(value);
+}
+
+bool PopValueFromReader(dbus::MessageReader* reader, uint64_t* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
+         reader->PopUint64(value);
+}
+
+bool PopValueFromReader(dbus::MessageReader* reader, double* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
+         reader->PopDouble(value);
+}
+
+bool PopValueFromReader(dbus::MessageReader* reader, std::string* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
+         reader->PopString(value);
+}
+
+bool PopValueFromReader(dbus::MessageReader* reader, dbus::ObjectPath* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
+         reader->PopObjectPath(value);
+}
+
+bool PopValueFromReader(dbus::MessageReader* reader,
+                        dbus::FileDescriptor* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  bool ok = details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
+            reader->PopFileDescriptor(value);
+  if (ok)
+    value->CheckValidity();
+  return ok;
+}
+
+namespace {
+
+// Helper methods for PopValueFromReader(dbus::MessageReader*, Any*)
+// implementation. Pops a value of particular type from |reader| and assigns
+// it to |value| of type Any.
+template<typename T>
+bool PopTypedValueFromReader(dbus::MessageReader* reader,
+                             brillo::Any* value) {
+  T data{};
+  if (!PopValueFromReader(reader, &data))
+    return false;
+  *value = std::move(data);
+  return true;
+}
+
+// std::vector<T> overload.
+template<typename T>
+bool PopTypedArrayFromReader(dbus::MessageReader* reader,
+                             brillo::Any* value) {
+  return PopTypedValueFromReader<std::vector<T>>(reader, value);
+}
+
+// std::map<KEY, VALUE> overload.
+template<typename KEY, typename VALUE>
+bool PopTypedMapFromReader(dbus::MessageReader* reader, brillo::Any* value) {
+  return PopTypedValueFromReader<std::map<KEY, VALUE>>(reader, value);
+}
+
+// Helper methods for reading common ARRAY signatures into a Variant.
+// Note that only common types are supported. If an additional specific
+// type signature is required, feel free to add support for it.
+bool PopArrayValueFromReader(dbus::MessageReader* reader,
+                             brillo::Any* value) {
+  std::string signature = reader->GetDataSignature();
+  if (signature == "ab")
+    return PopTypedArrayFromReader<bool>(reader, value);
+  else if (signature == "ay")
+    return PopTypedArrayFromReader<uint8_t>(reader, value);
+  else if (signature == "an")
+    return PopTypedArrayFromReader<int16_t>(reader, value);
+  else if (signature == "aq")
+    return PopTypedArrayFromReader<uint16_t>(reader, value);
+  else if (signature == "ai")
+    return PopTypedArrayFromReader<int32_t>(reader, value);
+  else if (signature == "au")
+    return PopTypedArrayFromReader<uint32_t>(reader, value);
+  else if (signature == "ax")
+    return PopTypedArrayFromReader<int64_t>(reader, value);
+  else if (signature == "at")
+    return PopTypedArrayFromReader<uint64_t>(reader, value);
+  else if (signature == "ad")
+    return PopTypedArrayFromReader<double>(reader, value);
+  else if (signature == "as")
+    return PopTypedArrayFromReader<std::string>(reader, value);
+  else if (signature == "ao")
+    return PopTypedArrayFromReader<dbus::ObjectPath>(reader, value);
+  else if (signature == "av")
+    return PopTypedArrayFromReader<brillo::Any>(reader, value);
+  else if (signature == "a{ss}")
+    return PopTypedMapFromReader<std::string, std::string>(reader, value);
+  else if (signature == "a{sv}")
+    return PopTypedValueFromReader<brillo::VariantDictionary>(reader, value);
+  else if (signature == "aa{ss}")
+    return PopTypedArrayFromReader<
+        std::map<std::string, std::string>>(reader, value);
+  else if (signature == "aa{sv}")
+    return PopTypedArrayFromReader<brillo::VariantDictionary>(reader, value);
+  else if (signature == "a{sa{ss}}")
+    return PopTypedMapFromReader<
+        std::string, std::map<std::string, std::string>>(reader, value);
+  else if (signature == "a{sa{sv}}")
+    return PopTypedMapFromReader<
+        std::string, brillo::VariantDictionary>(reader, value);
+  else if (signature == "a{say}")
+    return PopTypedMapFromReader<
+        std::string, std::vector<uint8_t>>(reader, value);
+  else if (signature == "a{uv}")
+    return PopTypedMapFromReader<uint32_t, brillo::Any>(reader, value);
+  else if (signature == "a(su)")
+    return PopTypedArrayFromReader<
+        std::tuple<std::string, uint32_t>>(reader, value);
+  else if (signature == "a{uu}")
+    return PopTypedMapFromReader<uint32_t, uint32_t>(reader, value);
+  else if (signature == "a(uu)")
+    return PopTypedArrayFromReader<
+        std::tuple<uint32_t, uint32_t>>(reader, value);
+
+  // When a use case for particular array signature is found, feel free
+  // to add handing for it here.
+  LOG(ERROR) << "Variant de-serialization of array containing data of "
+             << "type '" << signature << "' is not yet supported";
+  return false;
+}
+
+// Helper methods for reading common STRUCT signatures into a Variant.
+// Note that only common types are supported. If an additional specific
+// type signature is required, feel free to add support for it.
+bool PopStructValueFromReader(dbus::MessageReader* reader,
+                              brillo::Any* value) {
+  std::string signature = reader->GetDataSignature();
+  if (signature == "(ii)")
+    return PopTypedValueFromReader<std::tuple<int, int>>(reader, value);
+  else if (signature == "(ss)")
+    return PopTypedValueFromReader<std::tuple<std::string, std::string>>(reader,
+                                                                         value);
+  else if (signature == "(ub)")
+    return PopTypedValueFromReader<std::tuple<uint32_t, bool>>(reader, value);
+  else if (signature == "(uu)")
+    return PopTypedValueFromReader<std::tuple<uint32_t, uint32_t>>(reader,
+                                                                   value);
+
+  // When a use case for particular struct signature is found, feel free
+  // to add handing for it here.
+  LOG(ERROR) << "Variant de-serialization of structs of type '" << signature
+             << "' is not yet supported";
+  return false;
+}
+
+}  // anonymous namespace
+
+bool PopValueFromReader(dbus::MessageReader* reader, brillo::Any* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader))
+    return false;
+
+  switch (reader->GetDataType()) {
+    case dbus::Message::BYTE:
+      return PopTypedValueFromReader<uint8_t>(reader, value);
+    case dbus::Message::BOOL:
+      return PopTypedValueFromReader<bool>(reader, value);
+    case dbus::Message::INT16:
+      return PopTypedValueFromReader<int16_t>(reader, value);
+    case dbus::Message::UINT16:
+      return PopTypedValueFromReader<uint16_t>(reader, value);
+    case dbus::Message::INT32:
+      return PopTypedValueFromReader<int32_t>(reader, value);
+    case dbus::Message::UINT32:
+      return PopTypedValueFromReader<uint32_t>(reader, value);
+    case dbus::Message::INT64:
+      return PopTypedValueFromReader<int64_t>(reader, value);
+    case dbus::Message::UINT64:
+      return PopTypedValueFromReader<uint64_t>(reader, value);
+    case dbus::Message::DOUBLE:
+      return PopTypedValueFromReader<double>(reader, value);
+    case dbus::Message::STRING:
+      return PopTypedValueFromReader<std::string>(reader, value);
+    case dbus::Message::OBJECT_PATH:
+      return PopTypedValueFromReader<dbus::ObjectPath>(reader, value);
+    case dbus::Message::ARRAY:
+      return PopArrayValueFromReader(reader, value);
+    case dbus::Message::STRUCT:
+      return PopStructValueFromReader(reader, value);
+    case dbus::Message::DICT_ENTRY:
+      LOG(ERROR) << "Variant of DICT_ENTRY is invalid";
+      return false;
+    case dbus::Message::VARIANT:
+      LOG(ERROR) << "Variant containing a variant is invalid";
+      return false;
+    case dbus::Message::UNIX_FD:
+      CHECK(dbus::IsDBusTypeUnixFdSupported()) << "UNIX_FD data not supported";
+      // dbus::FileDescriptor is not a copyable type. Cannot be returned via
+      // brillo::Any. Fail here.
+      LOG(ERROR) << "Cannot return FileDescriptor via Any";
+      return false;
+    default:
+      LOG(FATAL) << "Unknown D-Bus data type: " << variant_reader.GetDataType();
+      return false;
+  }
+  return true;
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/data_serialization.h b/libbrillo/brillo/dbus/data_serialization.h
new file mode 100644
index 0000000..7d10fe5
--- /dev/null
+++ b/libbrillo/brillo/dbus/data_serialization.h
@@ -0,0 +1,851 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_
+#define LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_
+
+// The main functionality provided by this header file is methods to serialize
+// native C++ data over D-Bus. This includes three major parts:
+// - Methods to get the D-Bus signature for a given C++ type:
+//     std::string GetDBusSignature<T>();
+// - Methods to write arbitrary C++ data to D-Bus MessageWriter:
+//     void AppendValueToWriter(dbus::MessageWriter* writer, const T& value);
+//     void AppendValueToWriterAsVariant(dbus::MessageWriter*, const T&);
+// - Methods to read arbitrary C++ data from D-Bus MessageReader:
+//     bool PopValueFromReader(dbus::MessageReader* reader, T* value);
+//     bool PopVariantValueFromReader(dbus::MessageReader* reader, T* value);
+//
+// There are a number of overloads to handle C++ equivalents of basic D-Bus
+// types:
+//   D-Bus Type  | D-Bus Signature | Native C++ type
+//  --------------------------------------------------
+//   BYTE        |        y        |  uint8_t
+//   BOOL        |        b        |  bool
+//   INT16       |        n        |  int16_t
+//   UINT16      |        q        |  uint16_t
+//   INT32       |        i        |  int32_t (int)
+//   UINT32      |        u        |  uint32_t (unsigned)
+//   INT64       |        x        |  int64_t
+//   UINT64      |        t        |  uint64_t
+//   DOUBLE      |        d        |  double
+//   STRING      |        s        |  std::string
+//   OBJECT_PATH |        o        |  dbus::ObjectPath
+//   ARRAY       |        aT       |  std::vector<T>
+//   STRUCT      |       (UV)      |  std::pair<U,V>
+//               |     (UVW...)    |  std::tuple<U,V,W,...>
+//   DICT        |       a{KV}     |  std::map<K,V>
+//   VARIANT     |        v        |  brillo::Any
+//   UNIX_FD     |        h        |  dbus::FileDescriptor
+//   SIGNATURE   |        g        |  (unsupported)
+//
+// Additional overloads/specialization can be provided for custom types.
+// In order to do that, provide overloads of AppendValueToWriter() and
+// PopValueFromReader() functions in brillo::dbus_utils namespace for the
+// CustomType. As well as a template specialization of DBusType<> for the same
+// CustomType. This specialization must provide three static functions:
+//  - static std::string GetSignature();
+//  - static void Write(dbus::MessageWriter* writer, const CustomType& value);
+//  - static bool Read(dbus::MessageReader* reader, CustomType* value);
+// See an example in DBusUtils.CustomStruct unit test in
+// brillo/dbus/data_serialization_unittest.cc.
+
+#include <map>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include <base/logging.h>
+#include <brillo/brillo_export.h>
+#include <brillo/type_name_undecorate.h>
+#include <dbus/message.h>
+
+namespace google {
+namespace protobuf {
+class MessageLite;
+}  // namespace protobuf
+}  // namespace google
+
+namespace brillo {
+
+// Forward-declare only. Can't include any.h right now because it needs
+// AppendValueToWriter() declared below.
+class Any;
+
+namespace dbus_utils {
+
+// Base class for DBusType<T> for T not supported by D-Bus. This used to
+// implement IsTypeSupported<> below.
+struct Unsupported {};
+
+// Generic definition of DBusType<T> which will be specialized for particular
+// types later.
+// The second template parameter is used only in SFINAE situations to resolve
+// class hierarchy chains for protobuf-derived classes. This type is defaulted
+// to be 'void' in all other cases and simply ignored.
+// See DBusType specialization for google::protobuf::MessageLite below for more
+// detailed information.
+template<typename T, typename = void>
+struct DBusType : public Unsupported {};
+
+// A helper type trait to determine if all of the types listed in Types... are
+// supported by D-Bus. This is a generic forward-declaration which will be
+// specialized for different type combinations.
+template<typename... Types>
+struct IsTypeSupported;
+
+// Both T and the Types... must be supported for the complete set to be
+// supported.
+template<typename T, typename... Types>
+struct IsTypeSupported<T, Types...>
+    : public std::integral_constant<
+          bool,
+          IsTypeSupported<T>::value && IsTypeSupported<Types...>::value> {};
+
+// For a single type T, check if DBusType<T> derives from Unsupported.
+// If it does, then the type is not supported by the D-Bus.
+template<typename T>
+struct IsTypeSupported<T>
+    : public std::integral_constant<
+          bool,
+          !std::is_base_of<Unsupported, DBusType<T>>::value> {};
+
+// Empty set is not supported.
+template<>
+struct IsTypeSupported<> : public std::false_type {};
+
+//----------------------------------------------------------------------------
+// AppendValueToWriter<T>(dbus::MessageWriter* writer, const T& value)
+// Write the |value| of type T to D-Bus message.
+// Explicitly delete the overloads for scalar types that are not supported by
+// D-Bus.
+void AppendValueToWriter(dbus::MessageWriter* writer, char value) = delete;
+void AppendValueToWriter(dbus::MessageWriter* writer, float value) = delete;
+
+//----------------------------------------------------------------------------
+// PopValueFromReader<T>(dbus::MessageWriter* writer, T* value)
+// Reads the |value| of type T from D-Bus message.
+// Explicitly delete the overloads for scalar types that are not supported by
+// D-Bus.
+void PopValueFromReader(dbus::MessageReader* reader, char* value) = delete;
+void PopValueFromReader(dbus::MessageReader* reader, float* value) = delete;
+
+//----------------------------------------------------------------------------
+// Get D-Bus data signature from C++ data types.
+// Specializations of a generic GetDBusSignature<T>() provide signature strings
+// for native C++ types. This function is available only for type supported
+// by D-Bus.
+template<typename T>
+inline typename std::enable_if<IsTypeSupported<T>::value, std::string>::type
+GetDBusSignature() {
+  return DBusType<T>::GetSignature();
+}
+
+namespace details {
+// Helper method used by the many overloads of PopValueFromReader().
+// If the current value in the reader is of Variant type, the method descends
+// into the Variant and updates the |*reader_ref| with the transient
+// |variant_reader| MessageReader instance passed in.
+// Returns false if it fails to descend into the Variant.
+inline bool DescendIntoVariantIfPresent(dbus::MessageReader** reader_ref,
+                                        dbus::MessageReader* variant_reader) {
+  if ((*reader_ref)->GetDataType() != dbus::Message::VARIANT)
+    return true;
+  if (!(*reader_ref)->PopVariant(variant_reader))
+    return false;
+  *reader_ref = variant_reader;
+  return true;
+}
+
+// Helper method to format the type string of an array.
+// Essentially it adds "a" in front of |element_signature|.
+inline std::string GetArrayDBusSignature(const std::string& element_signature) {
+  return DBUS_TYPE_ARRAY_AS_STRING + element_signature;
+}
+
+// Helper method to get a signature string for DICT_ENTRY.
+// Returns "{KV}", where "K" and "V" are the type signatures for types
+// KEY/VALUE. For example, GetDBusDictEntryType<std::string, int>() would return
+// "{si}".
+template<typename KEY, typename VALUE>
+inline std::string GetDBusDictEntryType() {
+  return DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING +
+         GetDBusSignature<KEY>() + GetDBusSignature<VALUE>() +
+         DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
+}
+
+}  // namespace details
+
+//=============================================================================
+// Specializations/overloads for AppendValueToWriter, PopValueFromReader and
+// DBusType<T> for various C++ types that can be serialized over D-Bus.
+
+// bool -----------------------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         bool value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        bool* value);
+
+template<>
+struct DBusType<bool> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_BOOLEAN_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, bool value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, bool* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// uint8_t --------------------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         uint8_t value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        uint8_t* value);
+
+template<>
+struct DBusType<uint8_t> {
+  inline static std::string GetSignature() { return DBUS_TYPE_BYTE_AS_STRING; }
+  inline static void Write(dbus::MessageWriter* writer, uint8_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, uint8_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// int16_t --------------------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         int16_t value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        int16_t* value);
+
+template<>
+struct DBusType<int16_t> {
+  inline static std::string GetSignature() { return DBUS_TYPE_INT16_AS_STRING; }
+  inline static void Write(dbus::MessageWriter* writer, int16_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, int16_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// uint16_t -------------------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         uint16_t value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        uint16_t* value);
+
+template<>
+struct DBusType<uint16_t> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_UINT16_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, uint16_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, uint16_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// int32_t --------------------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         int32_t value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        int32_t* value);
+
+template<>
+struct DBusType<int32_t> {
+  inline static std::string GetSignature() { return DBUS_TYPE_INT32_AS_STRING; }
+  inline static void Write(dbus::MessageWriter* writer, int32_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, int32_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// uint32_t -------------------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         uint32_t value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        uint32_t* value);
+
+template<>
+struct DBusType<uint32_t> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_UINT32_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, uint32_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, uint32_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// int64_t --------------------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         int64_t value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        int64_t* value);
+
+template<>
+struct DBusType<int64_t> {
+  inline static std::string GetSignature() { return DBUS_TYPE_INT64_AS_STRING; }
+  inline static void Write(dbus::MessageWriter* writer, int64_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, int64_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// uint64_t -------------------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         uint64_t value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        uint64_t* value);
+
+template<>
+struct DBusType<uint64_t> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_UINT64_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, uint64_t value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, uint64_t* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// double ---------------------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         double value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        double* value);
+
+template<>
+struct DBusType<double> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_DOUBLE_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, double value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, double* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// std::string ----------------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         const std::string& value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        std::string* value);
+
+template<>
+struct DBusType<std::string> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_STRING_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const std::string& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, std::string* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// const char*
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         const char* value);
+
+template<>
+struct DBusType<const char*> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_STRING_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, const char* value) {
+    AppendValueToWriter(writer, value);
+  }
+};
+
+// const char[]
+template<>
+struct DBusType<const char[]> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_STRING_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer, const char* value) {
+    AppendValueToWriter(writer, value);
+  }
+};
+
+// dbus::ObjectPath -----------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         const dbus::ObjectPath& value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        dbus::ObjectPath* value);
+
+template<>
+struct DBusType<dbus::ObjectPath> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_OBJECT_PATH_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const dbus::ObjectPath& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader,
+                          dbus::ObjectPath* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// dbus::FileDescriptor -------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         const dbus::FileDescriptor& value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        dbus::FileDescriptor* value);
+
+template<>
+struct DBusType<dbus::FileDescriptor> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_UNIX_FD_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const dbus::FileDescriptor& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader,
+                          dbus::FileDescriptor* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// brillo::Any --------------------------------------------------------------
+BRILLO_EXPORT void AppendValueToWriter(dbus::MessageWriter* writer,
+                                         const brillo::Any& value);
+BRILLO_EXPORT bool PopValueFromReader(dbus::MessageReader* reader,
+                                        brillo::Any* value);
+
+template<>
+struct DBusType<brillo::Any> {
+  inline static std::string GetSignature() {
+    return DBUS_TYPE_VARIANT_AS_STRING;
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const brillo::Any& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, brillo::Any* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// std::vector = D-Bus ARRAY. -------------------------------------------------
+template<typename T, typename ALLOC>
+typename std::enable_if<IsTypeSupported<T>::value>::type AppendValueToWriter(
+    dbus::MessageWriter* writer,
+    const std::vector<T, ALLOC>& value) {
+  dbus::MessageWriter array_writer(nullptr);
+  writer->OpenArray(GetDBusSignature<T>(), &array_writer);
+  for (const auto& element : value) {
+    // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
+    // binding to AppendValueToWriter() to the point of instantiation of this
+    // template.
+    DBusType<T>::Write(&array_writer, element);
+  }
+  writer->CloseContainer(&array_writer);
+}
+
+template<typename T, typename ALLOC>
+typename std::enable_if<IsTypeSupported<T>::value, bool>::type
+PopValueFromReader(dbus::MessageReader* reader, std::vector<T, ALLOC>* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  dbus::MessageReader array_reader(nullptr);
+  if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
+      !reader->PopArray(&array_reader))
+    return false;
+  value->clear();
+  while (array_reader.HasMoreData()) {
+    T data;
+    // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
+    // binding to PopValueFromReader() to the point of instantiation of this
+    // template.
+    if (!DBusType<T>::Read(&array_reader, &data))
+      return false;
+    value->push_back(std::move(data));
+  }
+  return true;
+}
+
+namespace details {
+// DBusArrayType<> is a helper base class for DBusType<vector<T>> that provides
+// GetSignature/Write/Read methods for T types that are supported by D-Bus
+// and not having those methods for types that are not supported by D-Bus.
+template<bool inner_type_supported, typename T, typename ALLOC>
+struct DBusArrayType {
+  // Returns "aT", where "T" is the signature string for type T.
+  inline static std::string GetSignature() {
+    return GetArrayDBusSignature(GetDBusSignature<T>());
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const std::vector<T, ALLOC>& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader,
+                          std::vector<T, ALLOC>* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// Explicit specialization for unsupported type T.
+template<typename T, typename ALLOC>
+struct DBusArrayType<false, T, ALLOC> : public Unsupported {};
+
+}  // namespace details
+
+template<typename T, typename ALLOC>
+struct DBusType<std::vector<T, ALLOC>>
+    : public details::DBusArrayType<IsTypeSupported<T>::value, T, ALLOC> {};
+
+// std::pair = D-Bus STRUCT with two elements. --------------------------------
+namespace details {
+
+// Helper class to get a D-Bus signature of a list of types.
+// For example, TupleTraits<int32_t, bool, std::string>::GetSignature() will
+// return "ibs".
+template<typename... Types>
+struct TupleTraits;
+
+template<typename FirstType, typename... RestOfTypes>
+struct TupleTraits<FirstType, RestOfTypes...> {
+  static std::string GetSignature() {
+    return GetDBusSignature<FirstType>() +
+           TupleTraits<RestOfTypes...>::GetSignature();
+  }
+};
+
+template<>
+struct TupleTraits<> {
+  static std::string GetSignature() { return std::string{}; }
+};
+
+}  // namespace details
+
+template<typename... Types>
+inline std::string GetStructDBusSignature() {
+  // Returns "(T...)", where "T..." is the signature strings for types T...
+  return DBUS_STRUCT_BEGIN_CHAR_AS_STRING +
+         details::TupleTraits<Types...>::GetSignature() +
+         DBUS_STRUCT_END_CHAR_AS_STRING;
+}
+
+template<typename U, typename V>
+typename std::enable_if<IsTypeSupported<U, V>::value>::type AppendValueToWriter(
+    dbus::MessageWriter* writer,
+    const std::pair<U, V>& value) {
+  dbus::MessageWriter struct_writer(nullptr);
+  writer->OpenStruct(&struct_writer);
+  // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
+  // binding to AppendValueToWriter() to the point of instantiation of this
+  // template.
+  DBusType<U>::Write(&struct_writer, value.first);
+  DBusType<V>::Write(&struct_writer, value.second);
+  writer->CloseContainer(&struct_writer);
+}
+
+template<typename U, typename V>
+typename std::enable_if<IsTypeSupported<U, V>::value, bool>::type
+PopValueFromReader(dbus::MessageReader* reader, std::pair<U, V>* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  dbus::MessageReader struct_reader(nullptr);
+  if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
+      !reader->PopStruct(&struct_reader))
+    return false;
+  // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
+  // binding to PopValueFromReader() to the point of instantiation of this
+  // template.
+  return DBusType<U>::Read(&struct_reader, &value->first) &&
+         DBusType<V>::Read(&struct_reader, &value->second);
+}
+
+namespace details {
+
+// DBusArrayType<> is a helper base class for DBusType<pair<U, V>> that provides
+// GetSignature/Write/Read methods for types that are supported by D-Bus
+// and not having those methods for types that are not supported by D-Bus.
+template<bool inner_type_supported, typename U, typename V>
+struct DBusPairType {
+  // Returns "(UV)", where "U" and "V" are the signature strings for types U, V.
+  inline static std::string GetSignature() {
+    return GetStructDBusSignature<U, V>();
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const std::pair<U, V>& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, std::pair<U, V>* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// Either U, or V, or both are not supported by D-Bus.
+template<typename U, typename V>
+struct DBusPairType<false, U, V> : public Unsupported {};
+
+}  // namespace details
+
+template<typename U, typename V>
+struct DBusType<std::pair<U, V>>
+    : public details::DBusPairType<IsTypeSupported<U, V>::value, U, V> {};
+
+// std::tuple = D-Bus STRUCT with arbitrary number of members. ----------------
+namespace details {
+
+// TupleIterator<I, N, T...> is a helper class to iterate over all the elements
+// of a tuple<T...> from index I to N. TupleIterator<>::Read and ::Write methods
+// are called for each element of the tuple and iteration continues until I == N
+// in which case the specialization for I==N below stops the recursion.
+template<size_t I, size_t N, typename... T>
+struct TupleIterator {
+  // Tuple is just a convenience alias to a tuple containing elements of type T.
+  using Tuple = std::tuple<T...>;
+  // ValueType is the type of the element at index I.
+  using ValueType = typename std::tuple_element<I, Tuple>::type;
+
+  // Write the tuple element at index I to D-Bus message.
+  static void Write(dbus::MessageWriter* writer, const Tuple& value) {
+    // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
+    // binding to AppendValueToWriter() to the point of instantiation of this
+    // template.
+    DBusType<ValueType>::Write(writer, std::get<I>(value));
+    TupleIterator<I + 1, N, T...>::Write(writer, value);
+  }
+
+  // Read the tuple element at index I from D-Bus message.
+  static bool Read(dbus::MessageReader* reader, Tuple* value) {
+    // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
+    // binding to PopValueFromReader() to the point of instantiation of this
+    // template.
+    return DBusType<ValueType>::Read(reader, &std::get<I>(*value)) &&
+           TupleIterator<I + 1, N, T...>::Read(reader, value);
+  }
+};
+
+// Specialization to end the iteration when the index reaches the last element.
+template<size_t N, typename... T>
+struct TupleIterator<N, N, T...> {
+  using Tuple = std::tuple<T...>;
+  static void Write(dbus::MessageWriter* /* writer */,
+                    const Tuple& /* value */) {}
+  static bool Read(dbus::MessageReader* /* reader */,
+                   Tuple* /* value */) { return true; }
+};
+
+}  // namespace details
+
+template<typename... T>
+typename std::enable_if<IsTypeSupported<T...>::value>::type AppendValueToWriter(
+    dbus::MessageWriter* writer,
+    const std::tuple<T...>& value) {
+  dbus::MessageWriter struct_writer(nullptr);
+  writer->OpenStruct(&struct_writer);
+  details::TupleIterator<0, sizeof...(T), T...>::Write(&struct_writer, value);
+  writer->CloseContainer(&struct_writer);
+}
+
+template<typename... T>
+typename std::enable_if<IsTypeSupported<T...>::value, bool>::type
+PopValueFromReader(dbus::MessageReader* reader, std::tuple<T...>* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  dbus::MessageReader struct_reader(nullptr);
+  if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
+      !reader->PopStruct(&struct_reader))
+    return false;
+  return details::TupleIterator<0, sizeof...(T), T...>::Read(&struct_reader,
+                                                             value);
+}
+
+namespace details {
+
+// DBusTupleType<> is a helper base class for DBusType<tuple<T...>> that
+// provides GetSignature/Write/Read methods for types that are supported by
+// D-Bus and not having those methods for types that are not supported by D-Bus.
+template<bool inner_type_supported, typename... T>
+struct DBusTupleType {
+  // Returns "(T...)", where "T..." are the signature strings for types T...
+  inline static std::string GetSignature() {
+    return GetStructDBusSignature<T...>();
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const std::tuple<T...>& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader,
+                          std::tuple<T...>* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// Some/all of types T... are not supported by D-Bus.
+template<typename... T>
+struct DBusTupleType<false, T...> : public Unsupported {};
+
+}  // namespace details
+
+template<typename... T>
+struct DBusType<std::tuple<T...>>
+    : public details::DBusTupleType<IsTypeSupported<T...>::value, T...> {};
+
+// std::map = D-Bus ARRAY of DICT_ENTRY. --------------------------------------
+template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
+typename std::enable_if<IsTypeSupported<KEY, VALUE>::value>::type
+AppendValueToWriter(dbus::MessageWriter* writer,
+                    const std::map<KEY, VALUE, PRED, ALLOC>& value) {
+  dbus::MessageWriter dict_writer(nullptr);
+  writer->OpenArray(details::GetDBusDictEntryType<KEY, VALUE>(), &dict_writer);
+  for (const auto& pair : value) {
+    dbus::MessageWriter entry_writer(nullptr);
+    dict_writer.OpenDictEntry(&entry_writer);
+    // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
+    // binding to AppendValueToWriter() to the point of instantiation of this
+    // template.
+    DBusType<KEY>::Write(&entry_writer, pair.first);
+    DBusType<VALUE>::Write(&entry_writer, pair.second);
+    dict_writer.CloseContainer(&entry_writer);
+  }
+  writer->CloseContainer(&dict_writer);
+}
+
+template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
+typename std::enable_if<IsTypeSupported<KEY, VALUE>::value, bool>::type
+PopValueFromReader(dbus::MessageReader* reader,
+                   std::map<KEY, VALUE, PRED, ALLOC>* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  dbus::MessageReader array_reader(nullptr);
+  if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
+      !reader->PopArray(&array_reader))
+    return false;
+  value->clear();
+  while (array_reader.HasMoreData()) {
+    dbus::MessageReader dict_entry_reader(nullptr);
+    if (!array_reader.PopDictEntry(&dict_entry_reader))
+      return false;
+    KEY key;
+    VALUE data;
+    // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
+    // binding to PopValueFromReader() to the point of instantiation of this
+    // template.
+    if (!DBusType<KEY>::Read(&dict_entry_reader, &key) ||
+        !DBusType<VALUE>::Read(&dict_entry_reader, &data))
+      return false;
+    value->emplace(std::move(key), std::move(data));
+  }
+  return true;
+}
+
+namespace details {
+
+// DBusArrayType<> is a helper base class for DBusType<map<K, V>> that provides
+// GetSignature/Write/Read methods for T types that are supported by D-Bus
+// and not having those methods for types that are not supported by D-Bus.
+template<bool inner_types_supported,
+         typename KEY,
+         typename VALUE,
+         typename PRED,
+         typename ALLOC>
+struct DBusMapType {
+  // Returns "a{KV}", where "K" and "V" are the signature strings for types
+  // KEY/VALUE.
+  inline static std::string GetSignature() {
+    return GetArrayDBusSignature(GetDBusDictEntryType<KEY, VALUE>());
+  }
+  inline static void Write(dbus::MessageWriter* writer,
+                           const std::map<KEY, VALUE, PRED, ALLOC>& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader,
+                          std::map<KEY, VALUE, PRED, ALLOC>* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+// Types KEY, VALUE or both are not supported by D-Bus.
+template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
+struct DBusMapType<false, KEY, VALUE, PRED, ALLOC> : public Unsupported {};
+
+}  // namespace details
+
+template<typename KEY, typename VALUE, typename PRED, typename ALLOC>
+struct DBusType<std::map<KEY, VALUE, PRED, ALLOC>>
+    : public details::DBusMapType<IsTypeSupported<KEY, VALUE>::value,
+                                  KEY,
+                                  VALUE,
+                                  PRED,
+                                  ALLOC> {};
+
+//----------------------------------------------------------------------------
+// AppendValueToWriterAsVariant<T>(dbus::MessageWriter* writer, const T& value)
+// Write the |value| of type T to D-Bus message as a VARIANT.
+// This overload is provided only if T is supported by D-Bus.
+template<typename T>
+typename std::enable_if<IsTypeSupported<T>::value>::type
+AppendValueToWriterAsVariant(dbus::MessageWriter* writer, const T& value) {
+  std::string data_type = GetDBusSignature<T>();
+  dbus::MessageWriter variant_writer(nullptr);
+  writer->OpenVariant(data_type, &variant_writer);
+  // Use DBusType<T>::Write() instead of AppendValueToWriter() to delay
+  // binding to AppendValueToWriter() to the point of instantiation of this
+  // template.
+  DBusType<T>::Write(&variant_writer, value);
+  writer->CloseContainer(&variant_writer);
+}
+
+// Special case: do not allow to write a Variant containing a Variant.
+// Just redirect to normal AppendValueToWriter().
+inline void AppendValueToWriterAsVariant(dbus::MessageWriter* writer,
+                                         const brillo::Any& value) {
+  return AppendValueToWriter(writer, value);
+}
+
+//----------------------------------------------------------------------------
+// PopVariantValueFromReader<T>(dbus::MessageWriter* writer, T* value)
+// Reads a Variant containing the |value| of type T from D-Bus message.
+// Note that the generic PopValueFromReader<T>(...) can do this too.
+// This method is provided for two reasons:
+//   1. For API symmetry with AppendValueToWriter/AppendValueToWriterAsVariant.
+//   2. To be used when it is important to assert that the data was sent
+//      specifically as a Variant.
+// This overload is provided only if T is supported by D-Bus.
+template<typename T>
+typename std::enable_if<IsTypeSupported<T>::value, bool>::type
+PopVariantValueFromReader(dbus::MessageReader* reader, T* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  if (!reader->PopVariant(&variant_reader))
+    return false;
+  // Use DBusType<T>::Read() instead of PopValueFromReader() to delay
+  // binding to PopValueFromReader() to the point of instantiation of this
+  // template.
+  return DBusType<T>::Read(&variant_reader, value);
+}
+
+// Special handling of request to read a Variant of Variant.
+inline bool PopVariantValueFromReader(dbus::MessageReader* reader, Any* value) {
+  return PopValueFromReader(reader, value);
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_DATA_SERIALIZATION_H_
diff --git a/libbrillo/brillo/dbus/data_serialization_unittest.cc b/libbrillo/brillo/dbus/data_serialization_unittest.cc
new file mode 100644
index 0000000..1acae60
--- /dev/null
+++ b/libbrillo/brillo/dbus/data_serialization_unittest.cc
@@ -0,0 +1,753 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/data_serialization.h>
+
+#include <limits>
+
+#include <brillo/variant_dictionary.h>
+#include <gtest/gtest.h>
+
+using dbus::FileDescriptor;
+using dbus::Message;
+using dbus::MessageReader;
+using dbus::MessageWriter;
+using dbus::ObjectPath;
+using dbus::Response;
+
+namespace brillo {
+namespace dbus_utils {
+
+TEST(DBusUtils, Supported_BasicTypes) {
+  EXPECT_TRUE(IsTypeSupported<bool>::value);
+  EXPECT_TRUE(IsTypeSupported<uint8_t>::value);
+  EXPECT_TRUE(IsTypeSupported<int16_t>::value);
+  EXPECT_TRUE(IsTypeSupported<uint16_t>::value);
+  EXPECT_TRUE(IsTypeSupported<int32_t>::value);
+  EXPECT_TRUE(IsTypeSupported<uint32_t>::value);
+  EXPECT_TRUE(IsTypeSupported<int64_t>::value);
+  EXPECT_TRUE(IsTypeSupported<uint64_t>::value);
+  EXPECT_TRUE(IsTypeSupported<double>::value);
+  EXPECT_TRUE(IsTypeSupported<std::string>::value);
+  EXPECT_TRUE(IsTypeSupported<ObjectPath>::value);
+  EXPECT_TRUE(IsTypeSupported<FileDescriptor>::value);
+  EXPECT_TRUE(IsTypeSupported<Any>::value);
+}
+
+TEST(DBusUtils, Unsupported_BasicTypes) {
+  EXPECT_FALSE(IsTypeSupported<char>::value);
+  EXPECT_FALSE(IsTypeSupported<float>::value);
+}
+
+TEST(DBusUtils, Supported_ComplexTypes) {
+  EXPECT_TRUE(IsTypeSupported<std::vector<bool>>::value);
+  EXPECT_TRUE(IsTypeSupported<std::vector<uint8_t>>::value);
+  EXPECT_TRUE((IsTypeSupported<std::pair<int16_t, double>>::value));
+  EXPECT_TRUE(
+      (IsTypeSupported<std::map<uint16_t, std::vector<int64_t>>>::value));
+  EXPECT_TRUE((IsTypeSupported<std::tuple<bool, double, int32_t>>::value));
+}
+
+TEST(DBusUtils, Unsupported_ComplexTypes) {
+  EXPECT_FALSE(IsTypeSupported<std::vector<char>>::value);
+  EXPECT_FALSE((IsTypeSupported<std::pair<int16_t, float>>::value));
+  EXPECT_FALSE((IsTypeSupported<std::pair<char, int32_t>>::value));
+  EXPECT_FALSE((IsTypeSupported<std::map<int16_t, float>>::value));
+  EXPECT_FALSE((IsTypeSupported<std::map<char, int32_t>>::value));
+  EXPECT_FALSE((IsTypeSupported<std::tuple<bool, char, int32_t>>::value));
+}
+
+TEST(DBusUtils, Supported_TypeSet) {
+  EXPECT_TRUE((IsTypeSupported<int32_t, double, std::string>::value));
+  EXPECT_TRUE((IsTypeSupported<bool, std::vector<int32_t>, uint8_t>::value));
+}
+
+TEST(DBusUtils, Unupported_TypeSet) {
+  EXPECT_FALSE((IsTypeSupported<int32_t, double, std::string, char>::value));
+  EXPECT_FALSE(
+      (IsTypeSupported<bool, std::pair<std::vector<float>, uint8_t>>::value));
+  EXPECT_FALSE((IsTypeSupported<char, double, std::string, int16_t>::value));
+  EXPECT_FALSE((IsTypeSupported<char, std::vector<float>, float>::value));
+}
+
+TEST(DBusUtils, Signatures_BasicTypes) {
+  EXPECT_EQ("b", GetDBusSignature<bool>());
+  EXPECT_EQ("y", GetDBusSignature<uint8_t>());
+  EXPECT_EQ("n", GetDBusSignature<int16_t>());
+  EXPECT_EQ("q", GetDBusSignature<uint16_t>());
+  EXPECT_EQ("i", GetDBusSignature<int32_t>());
+  EXPECT_EQ("u", GetDBusSignature<uint32_t>());
+  EXPECT_EQ("x", GetDBusSignature<int64_t>());
+  EXPECT_EQ("t", GetDBusSignature<uint64_t>());
+  EXPECT_EQ("d", GetDBusSignature<double>());
+  EXPECT_EQ("s", GetDBusSignature<std::string>());
+  EXPECT_EQ("o", GetDBusSignature<ObjectPath>());
+  EXPECT_EQ("h", GetDBusSignature<FileDescriptor>());
+  EXPECT_EQ("v", GetDBusSignature<Any>());
+}
+
+TEST(DBusUtils, Signatures_Arrays) {
+  EXPECT_EQ("ab", GetDBusSignature<std::vector<bool>>());
+  EXPECT_EQ("ay", GetDBusSignature<std::vector<uint8_t>>());
+  EXPECT_EQ("an", GetDBusSignature<std::vector<int16_t>>());
+  EXPECT_EQ("aq", GetDBusSignature<std::vector<uint16_t>>());
+  EXPECT_EQ("ai", GetDBusSignature<std::vector<int32_t>>());
+  EXPECT_EQ("au", GetDBusSignature<std::vector<uint32_t>>());
+  EXPECT_EQ("ax", GetDBusSignature<std::vector<int64_t>>());
+  EXPECT_EQ("at", GetDBusSignature<std::vector<uint64_t>>());
+  EXPECT_EQ("ad", GetDBusSignature<std::vector<double>>());
+  EXPECT_EQ("as", GetDBusSignature<std::vector<std::string>>());
+  EXPECT_EQ("ao", GetDBusSignature<std::vector<ObjectPath>>());
+  EXPECT_EQ("ah", GetDBusSignature<std::vector<FileDescriptor>>());
+  EXPECT_EQ("av", GetDBusSignature<std::vector<Any>>());
+  EXPECT_EQ("a(is)",
+            (GetDBusSignature<std::vector<std::pair<int, std::string>>>()));
+  EXPECT_EQ("aad", GetDBusSignature<std::vector<std::vector<double>>>());
+}
+
+TEST(DBusUtils, Signatures_Maps) {
+  EXPECT_EQ("a{sb}", (GetDBusSignature<std::map<std::string, bool>>()));
+  EXPECT_EQ("a{ss}", (GetDBusSignature<std::map<std::string, std::string>>()));
+  EXPECT_EQ("a{sv}", (GetDBusSignature<std::map<std::string, Any>>()));
+  EXPECT_EQ("a{id}", (GetDBusSignature<std::map<int, double>>()));
+  EXPECT_EQ(
+      "a{ia{ss}}",
+      (GetDBusSignature<std::map<int, std::map<std::string, std::string>>>()));
+}
+
+TEST(DBusUtils, Signatures_Pairs) {
+  EXPECT_EQ("(sb)", (GetDBusSignature<std::pair<std::string, bool>>()));
+  EXPECT_EQ("(sv)", (GetDBusSignature<std::pair<std::string, Any>>()));
+  EXPECT_EQ("(id)", (GetDBusSignature<std::pair<int, double>>()));
+}
+
+TEST(DBusUtils, Signatures_Tuples) {
+  EXPECT_EQ("(i)", (GetDBusSignature<std::tuple<int>>()));
+  EXPECT_EQ("(sv)", (GetDBusSignature<std::tuple<std::string, Any>>()));
+  EXPECT_EQ("(id(si))",
+            (GetDBusSignature<
+                std::tuple<int, double, std::tuple<std::string, int>>>()));
+}
+
+// Test that a byte can be properly written and read. We only have this
+// test for byte, as repeating this for other basic types is too redundant.
+TEST(DBusUtils, AppendAndPopByte) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  AppendValueToWriter(&writer, uint8_t{123});
+  EXPECT_EQ("y", message->GetSignature());
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(reader.HasMoreData());  // Should have data to read.
+  EXPECT_EQ(Message::BYTE, reader.GetDataType());
+
+  bool bool_value = false;
+  // Should fail as the type is not bool here.
+  EXPECT_FALSE(PopValueFromReader(&reader, &bool_value));
+
+  uint8_t byte_value = 0;
+  EXPECT_TRUE(PopValueFromReader(&reader, &byte_value));
+  EXPECT_EQ(123, byte_value);          // Should match with the input.
+  EXPECT_FALSE(reader.HasMoreData());  // Should not have more data to read.
+
+  // Try to get another byte. Should fail.
+  EXPECT_FALSE(PopValueFromReader(&reader, &byte_value));
+}
+
+// Check all basic types can be properly written and read.
+TEST(DBusUtils, AppendAndPopBasicDataTypes) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+
+  // Append 0, true, 2, 3, 4, 5, 6, 7, 8.0, "string", "/object/path".
+  AppendValueToWriter(&writer, uint8_t{0});
+  AppendValueToWriter(&writer, bool{true});
+  AppendValueToWriter(&writer, int16_t{2});
+  AppendValueToWriter(&writer, uint16_t{3});
+  AppendValueToWriter(&writer, int32_t{4});
+  AppendValueToWriter(&writer, uint32_t{5});
+  AppendValueToWriter(&writer, int64_t{6});
+  AppendValueToWriter(&writer, uint64_t{7});
+  AppendValueToWriter(&writer, double{8.0});
+  AppendValueToWriter(&writer, std::string{"string"});
+  AppendValueToWriter(&writer, ObjectPath{"/object/path"});
+
+  EXPECT_EQ("ybnqiuxtdso", message->GetSignature());
+
+  uint8_t byte_value = 0;
+  bool bool_value = false;
+  int16_t int16_value = 0;
+  uint16_t uint16_value = 0;
+  int32_t int32_value = 0;
+  uint32_t uint32_value = 0;
+  int64_t int64_value = 0;
+  uint64_t uint64_value = 0;
+  double double_value = 0;
+  std::string string_value;
+  ObjectPath object_path_value;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(reader.HasMoreData());
+  EXPECT_TRUE(PopValueFromReader(&reader, &byte_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &bool_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &int16_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &uint16_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &int32_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &uint32_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &int64_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &uint64_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &double_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &string_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &object_path_value));
+  EXPECT_FALSE(reader.HasMoreData());
+
+  // 0, true, 2, 3, 4, 5, 6, 7, 8, "string", "/object/path" should be returned.
+  EXPECT_EQ(0, byte_value);
+  EXPECT_TRUE(bool_value);
+  EXPECT_EQ(2, int16_value);
+  EXPECT_EQ(3U, uint16_value);
+  EXPECT_EQ(4, int32_value);
+  EXPECT_EQ(5U, uint32_value);
+  EXPECT_EQ(6, int64_value);
+  EXPECT_EQ(7U, uint64_value);
+  EXPECT_DOUBLE_EQ(8.0, double_value);
+  EXPECT_EQ("string", string_value);
+  EXPECT_EQ(ObjectPath{"/object/path"}, object_path_value);
+}
+
+// Check all basic types can be properly written and read.
+TEST(DBusUtils, AppendAndPopFileDescriptor) {
+  if (!dbus::IsDBusTypeUnixFdSupported()) {
+    LOG(WARNING) << "FD passing is not supported";
+    return;
+  }
+
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+
+  // Append stdout.
+  FileDescriptor temp(1);
+  // Descriptor should not be valid until checked.
+  EXPECT_FALSE(temp.is_valid());
+  // NB: thread IO requirements not relevant for unit tests.
+  temp.CheckValidity();
+  EXPECT_TRUE(temp.is_valid());
+  AppendValueToWriter(&writer, temp);
+
+  EXPECT_EQ("h", message->GetSignature());
+
+  FileDescriptor fd_value;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(reader.HasMoreData());
+  EXPECT_TRUE(PopValueFromReader(&reader, &fd_value));
+  EXPECT_FALSE(reader.HasMoreData());
+  // Descriptor is automatically checked for validity as part of
+  // PopValueFromReader() call.
+  EXPECT_TRUE(fd_value.is_valid());
+}
+
+// Check all variant types can be properly written and read.
+TEST(DBusUtils, AppendAndPopVariantDataTypes) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+
+  // Append 10, false, 12, 13, 14, 15, 16, 17, 18.5, "data", "/obj/path".
+  AppendValueToWriterAsVariant(&writer, uint8_t{10});
+  AppendValueToWriterAsVariant(&writer, bool{false});
+  AppendValueToWriterAsVariant(&writer, int16_t{12});
+  AppendValueToWriterAsVariant(&writer, uint16_t{13});
+  AppendValueToWriterAsVariant(&writer, int32_t{14});
+  AppendValueToWriterAsVariant(&writer, uint32_t{15});
+  AppendValueToWriterAsVariant(&writer, int64_t{16});
+  AppendValueToWriterAsVariant(&writer, uint64_t{17});
+  AppendValueToWriterAsVariant(&writer, double{18.5});
+  AppendValueToWriterAsVariant(&writer, std::string{"data"});
+  AppendValueToWriterAsVariant(&writer, ObjectPath{"/obj/path"});
+  AppendValueToWriterAsVariant(&writer, Any{17});
+  AppendValueToWriterAsVariant(&writer,
+                               Any{std::vector<std::vector<int>>{{6, 7}}});
+
+  EXPECT_EQ("vvvvvvvvvvvvv", message->GetSignature());
+
+  uint8_t byte_value = 0;
+  bool bool_value = true;
+  int16_t int16_value = 0;
+  uint16_t uint16_value = 0;
+  int32_t int32_value = 0;
+  uint32_t uint32_value = 0;
+  int64_t int64_value = 0;
+  uint64_t uint64_value = 0;
+  double double_value = 0;
+  std::string string_value;
+  ObjectPath object_path_value;
+  Any any_value;
+  Any any_vector_vector;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(reader.HasMoreData());
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &byte_value));
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &bool_value));
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &int16_value));
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &uint16_value));
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &int32_value));
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &uint32_value));
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &int64_value));
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &uint64_value));
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &double_value));
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &string_value));
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &object_path_value));
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &any_value));
+  // Not implemented.
+  EXPECT_FALSE(PopVariantValueFromReader(&reader, &any_vector_vector));
+  EXPECT_FALSE(reader.HasMoreData());
+
+  EXPECT_EQ(10, byte_value);
+  EXPECT_FALSE(bool_value);
+  EXPECT_EQ(12, int16_value);
+  EXPECT_EQ(13U, uint16_value);
+  EXPECT_EQ(14, int32_value);
+  EXPECT_EQ(15U, uint32_value);
+  EXPECT_EQ(16, int64_value);
+  EXPECT_EQ(17U, uint64_value);
+  EXPECT_DOUBLE_EQ(18.5, double_value);
+  EXPECT_EQ("data", string_value);
+  EXPECT_EQ(ObjectPath{"/obj/path"}, object_path_value);
+  EXPECT_EQ(17, any_value.Get<int>());
+  EXPECT_TRUE(any_vector_vector.IsEmpty());
+}
+
+TEST(DBusUtils, AppendAndPopBasicAny) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+
+  // Append 10, true, 12, 13, 14, 15, 16, 17, 18.5, "data", "/obj/path".
+  AppendValueToWriter(&writer, Any(uint8_t{10}));
+  AppendValueToWriter(&writer, Any(bool{true}));
+  AppendValueToWriter(&writer, Any(int16_t{12}));
+  AppendValueToWriter(&writer, Any(uint16_t{13}));
+  AppendValueToWriter(&writer, Any(int32_t{14}));
+  AppendValueToWriter(&writer, Any(uint32_t{15}));
+  AppendValueToWriter(&writer, Any(int64_t{16}));
+  AppendValueToWriter(&writer, Any(uint64_t{17}));
+  AppendValueToWriter(&writer, Any(double{18.5}));
+  AppendValueToWriter(&writer, Any(std::string{"data"}));
+  AppendValueToWriter(&writer, Any(ObjectPath{"/obj/path"}));
+  EXPECT_EQ("vvvvvvvvvvv", message->GetSignature());
+
+  Any byte_value;
+  Any bool_value;
+  Any int16_value;
+  Any uint16_value;
+  Any int32_value;
+  Any uint32_value;
+  Any int64_value;
+  Any uint64_value;
+  Any double_value;
+  Any string_value;
+  Any object_path_value;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(reader.HasMoreData());
+  EXPECT_TRUE(PopValueFromReader(&reader, &byte_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &bool_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &int16_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &uint16_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &int32_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &uint32_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &int64_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &uint64_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &double_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &string_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &object_path_value));
+  EXPECT_FALSE(reader.HasMoreData());
+
+  // Must be: 10, true, 12, 13, 14, 15, 16, 17, 18.5, "data", "/obj/path".
+  EXPECT_EQ(10, byte_value.Get<uint8_t>());
+  EXPECT_TRUE(bool_value.Get<bool>());
+  EXPECT_EQ(12, int16_value.Get<int16_t>());
+  EXPECT_EQ(13U, uint16_value.Get<uint16_t>());
+  EXPECT_EQ(14, int32_value.Get<int32_t>());
+  EXPECT_EQ(15U, uint32_value.Get<uint32_t>());
+  EXPECT_EQ(16, int64_value.Get<int64_t>());
+  EXPECT_EQ(17U, uint64_value.Get<uint64_t>());
+  EXPECT_DOUBLE_EQ(18.5, double_value.Get<double>());
+  EXPECT_EQ("data", string_value.Get<std::string>());
+  EXPECT_EQ(ObjectPath{"/obj/path"}, object_path_value.Get<ObjectPath>());
+}
+
+TEST(DBusUtils, ArrayOfBytes) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  std::vector<uint8_t> bytes{1, 2, 3};
+  AppendValueToWriter(&writer, bytes);
+
+  EXPECT_EQ("ay", message->GetSignature());
+
+  MessageReader reader(message.get());
+  std::vector<uint8_t> bytes_out;
+  EXPECT_TRUE(PopValueFromReader(&reader, &bytes_out));
+  EXPECT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(bytes, bytes_out);
+}
+
+TEST(DBusUtils, ArrayOfBytes_Empty) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  std::vector<uint8_t> bytes;
+  AppendValueToWriter(&writer, bytes);
+
+  EXPECT_EQ("ay", message->GetSignature());
+
+  MessageReader reader(message.get());
+  std::vector<uint8_t> bytes_out;
+  EXPECT_TRUE(PopValueFromReader(&reader, &bytes_out));
+  EXPECT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(bytes, bytes_out);
+}
+
+TEST(DBusUtils, ArrayOfStrings) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  std::vector<std::string> strings{"foo", "bar", "baz"};
+  AppendValueToWriter(&writer, strings);
+
+  EXPECT_EQ("as", message->GetSignature());
+
+  MessageReader reader(message.get());
+  std::vector<std::string> strings_out;
+  EXPECT_TRUE(PopValueFromReader(&reader, &strings_out));
+  EXPECT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(strings, strings_out);
+}
+
+TEST(DBusUtils, ArrayOfInt64) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  std::vector<int64_t> values{-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5,
+                              std::numeric_limits<int64_t>::min(),
+                              std::numeric_limits<int64_t>::max()};
+  AppendValueToWriter(&writer, values);
+
+  EXPECT_EQ("ax", message->GetSignature());
+
+  MessageReader reader(message.get());
+  std::vector<int64_t> values_out;
+  EXPECT_TRUE(PopValueFromReader(&reader, &values_out));
+  EXPECT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(values, values_out);
+}
+
+TEST(DBusUtils, ArrayOfObjectPaths) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  std::vector<ObjectPath> object_paths{
+      ObjectPath("/object/path/1"),
+      ObjectPath("/object/path/2"),
+      ObjectPath("/object/path/3"),
+  };
+  AppendValueToWriter(&writer, object_paths);
+
+  EXPECT_EQ("ao", message->GetSignature());
+
+  MessageReader reader(message.get());
+  std::vector<ObjectPath> object_paths_out;
+  EXPECT_TRUE(PopValueFromReader(&reader, &object_paths_out));
+  EXPECT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(object_paths, object_paths_out);
+}
+
+TEST(DBusUtils, ArraysAsVariant) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  std::vector<int> int_array{1, 2, 3};
+  std::vector<std::string> str_array{"foo", "bar", "baz"};
+  std::vector<double> dbl_array_empty{};
+  std::map<std::string, std::string> dict_ss{{"k1", "v1"}, {"k2", "v2"}};
+  VariantDictionary dict_sv{{"k1", 1}, {"k2", "v2"}};
+  AppendValueToWriterAsVariant(&writer, int_array);
+  AppendValueToWriterAsVariant(&writer, str_array);
+  AppendValueToWriterAsVariant(&writer, dbl_array_empty);
+  AppendValueToWriterAsVariant(&writer, dict_ss);
+  AppendValueToWriterAsVariant(&writer, dict_sv);
+
+  EXPECT_EQ("vvvvv", message->GetSignature());
+
+  Any int_array_out;
+  Any str_array_out;
+  Any dbl_array_out;
+  Any dict_ss_out;
+  Any dict_sv_out;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &int_array_out));
+  EXPECT_TRUE(PopValueFromReader(&reader, &str_array_out));
+  EXPECT_TRUE(PopValueFromReader(&reader, &dbl_array_out));
+  EXPECT_TRUE(PopValueFromReader(&reader, &dict_ss_out));
+  EXPECT_TRUE(PopValueFromReader(&reader, &dict_sv_out));
+  EXPECT_FALSE(reader.HasMoreData());
+
+  EXPECT_EQ(int_array, int_array_out.Get<std::vector<int>>());
+  EXPECT_EQ(str_array, str_array_out.Get<std::vector<std::string>>());
+  EXPECT_EQ(dbl_array_empty, dbl_array_out.Get<std::vector<double>>());
+  EXPECT_EQ(dict_ss, (dict_ss_out.Get<std::map<std::string, std::string>>()));
+  EXPECT_EQ(dict_sv["k1"].Get<int>(),
+            dict_sv_out.Get<VariantDictionary>().at("k1").Get<int>());
+  EXPECT_EQ(dict_sv["k2"].Get<const char*>(),
+            dict_sv_out.Get<VariantDictionary>().at("k2").Get<std::string>());
+}
+
+TEST(DBusUtils, VariantDictionary) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  VariantDictionary values{
+      {"key1", uint8_t{10}},
+      {"key2", bool{true}},
+      {"key3", int16_t{12}},
+      {"key4", uint16_t{13}},
+      {"key5", int32_t{14}},
+      {"key6", uint32_t{15}},
+      {"key7", int64_t{16}},
+      {"key8", uint64_t{17}},
+      {"key9", double{18.5}},
+      {"keyA", std::string{"data"}},
+      {"keyB", ObjectPath{"/obj/path"}},
+  };
+  AppendValueToWriter(&writer, values);
+
+  EXPECT_EQ("a{sv}", message->GetSignature());
+
+  MessageReader reader(message.get());
+  VariantDictionary values_out;
+  EXPECT_TRUE(PopValueFromReader(&reader, &values_out));
+  EXPECT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(values.size(), values_out.size());
+  EXPECT_EQ(values["key1"].Get<uint8_t>(), values_out["key1"].Get<uint8_t>());
+  EXPECT_EQ(values["key2"].Get<bool>(), values_out["key2"].Get<bool>());
+  EXPECT_EQ(values["key3"].Get<int16_t>(), values_out["key3"].Get<int16_t>());
+  EXPECT_EQ(values["key4"].Get<uint16_t>(), values_out["key4"].Get<uint16_t>());
+  EXPECT_EQ(values["key5"].Get<int32_t>(), values_out["key5"].Get<int32_t>());
+  EXPECT_EQ(values["key6"].Get<uint32_t>(), values_out["key6"].Get<uint32_t>());
+  EXPECT_EQ(values["key7"].Get<int64_t>(), values_out["key7"].Get<int64_t>());
+  EXPECT_EQ(values["key8"].Get<uint64_t>(), values_out["key8"].Get<uint64_t>());
+  EXPECT_EQ(values["key9"].Get<double>(), values_out["key9"].Get<double>());
+  EXPECT_EQ(values["keyA"].Get<std::string>(),
+            values_out["keyA"].Get<std::string>());
+  EXPECT_EQ(values["keyB"].Get<ObjectPath>(),
+            values_out["keyB"].Get<ObjectPath>());
+}
+
+TEST(DBusUtils, StringToStringMap) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  std::map<std::string, std::string> values{
+      {"key1", "value1"},
+      {"key2", "value2"},
+      {"key3", "value3"},
+      {"key4", "value4"},
+      {"key5", "value5"},
+  };
+  AppendValueToWriter(&writer, values);
+
+  EXPECT_EQ("a{ss}", message->GetSignature());
+
+  MessageReader reader(message.get());
+  std::map<std::string, std::string> values_out;
+  EXPECT_TRUE(PopValueFromReader(&reader, &values_out));
+  EXPECT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(values, values_out);
+}
+
+TEST(DBusUtils, Pair) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  std::pair<std::string, int> struct1{"value2", 3};
+  AppendValueToWriter(&writer, struct1);
+  std::pair<int, std::pair<int, int>> struct2{1, {2, 3}};
+  AppendValueToWriter(&writer, struct2);
+
+  EXPECT_EQ("(si)(i(ii))", message->GetSignature());
+
+  std::pair<std::string, int> struct1_out;
+  std::pair<int, std::pair<int, int>> struct2_out;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &struct1_out));
+  EXPECT_TRUE(PopValueFromReader(&reader, &struct2_out));
+  EXPECT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(struct1, struct1_out);
+  EXPECT_EQ(struct2, struct2_out);
+}
+
+TEST(DBusUtils, Tuple) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  std::tuple<std::string, int> struct1{"value2", 3};
+  AppendValueToWriter(&writer, struct1);
+  std::tuple<int, std::string, std::vector<std::pair<int, int>>> struct2{
+    1, "a", {{2, 3}}
+  };
+  AppendValueToWriter(&writer, struct2);
+
+  EXPECT_EQ("(si)(isa(ii))", message->GetSignature());
+
+  std::tuple<std::string, int> struct1_out;
+  std::tuple<int, std::string, std::vector<std::pair<int, int>>> struct2_out;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &struct1_out));
+  EXPECT_TRUE(PopValueFromReader(&reader, &struct2_out));
+  EXPECT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(struct1, struct1_out);
+  EXPECT_EQ(struct2, struct2_out);
+}
+
+TEST(DBusUtils, ReinterpretVariant) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  std::vector<std::string> str_array{"foo", "bar", "baz"};
+  std::map<std::string, std::string> dict_ss{{"k1", "v1"}, {"k2", "v2"}};
+  VariantDictionary dict_sv{{"k1", "v1"}, {"k2", "v2"}};
+  AppendValueToWriterAsVariant(&writer, 123);
+  AppendValueToWriterAsVariant(&writer, str_array);
+  AppendValueToWriterAsVariant(&writer, 1.7);
+  AppendValueToWriterAsVariant(&writer, dict_ss);
+  AppendValueToWriter(&writer, dict_sv);
+
+  EXPECT_EQ("vvvva{sv}", message->GetSignature());
+
+  int int_out = 0;
+  std::vector<std::string> str_array_out;
+  double dbl_out = 0.0;
+  std::map<std::string, std::string> dict_ss_out;
+  std::map<std::string, std::string> dict_ss_out2;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &int_out));
+  EXPECT_TRUE(PopValueFromReader(&reader, &str_array_out));
+  EXPECT_TRUE(PopValueFromReader(&reader, &dbl_out));
+  EXPECT_TRUE(PopValueFromReader(&reader, &dict_ss_out));
+  EXPECT_TRUE(PopValueFromReader(&reader,
+                                 &dict_ss_out2));  // Read "a{sv}" as "a{ss}".
+  EXPECT_FALSE(reader.HasMoreData());
+
+  EXPECT_EQ(123, int_out);
+  EXPECT_EQ(str_array, str_array_out);
+  EXPECT_DOUBLE_EQ(1.7, dbl_out);
+  EXPECT_EQ(dict_ss, dict_ss_out);
+  EXPECT_EQ(dict_ss, dict_ss_out2);
+}
+
+// Test handling of custom data types.
+struct Person {
+  std::string first_name;
+  std::string last_name;
+  int age;
+  // Provide == operator so we can easily compare arrays of Person.
+  bool operator==(const Person& rhs) const {
+    return first_name == rhs.first_name && last_name == rhs.last_name &&
+           age == rhs.age;
+  }
+};
+
+// Overload AppendValueToWriter() for "Person" structure.
+void AppendValueToWriter(dbus::MessageWriter* writer, const Person& value) {
+  dbus::MessageWriter struct_writer(nullptr);
+  writer->OpenStruct(&struct_writer);
+  AppendValueToWriter(&struct_writer, value.first_name);
+  AppendValueToWriter(&struct_writer, value.last_name);
+  AppendValueToWriter(&struct_writer, value.age);
+  writer->CloseContainer(&struct_writer);
+}
+
+// Overload PopValueFromReader() for "Person" structure.
+bool PopValueFromReader(dbus::MessageReader* reader, Person* value) {
+  dbus::MessageReader variant_reader(nullptr);
+  dbus::MessageReader struct_reader(nullptr);
+  if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader) ||
+      !reader->PopStruct(&struct_reader))
+    return false;
+  return PopValueFromReader(&struct_reader, &value->first_name) &&
+         PopValueFromReader(&struct_reader, &value->last_name) &&
+         PopValueFromReader(&struct_reader, &value->age);
+}
+
+// Specialize DBusType<T> for "Person" structure.
+template<>
+struct DBusType<Person> {
+  inline static std::string GetSignature() {
+    return GetStructDBusSignature<std::string, std::string, int>();
+  }
+  inline static void Write(dbus::MessageWriter* writer, const Person& value) {
+    AppendValueToWriter(writer, value);
+  }
+  inline static bool Read(dbus::MessageReader* reader, Person* value) {
+    return PopValueFromReader(reader, value);
+  }
+};
+
+TEST(DBusUtils, CustomStruct) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  std::vector<Person> people{{"John", "Doe", 32}, {"Jane", "Smith", 48}};
+  AppendValueToWriter(&writer, people);
+  AppendValueToWriterAsVariant(&writer, people);
+  AppendValueToWriterAsVariant(&writer, people);
+
+  EXPECT_EQ("a(ssi)vv", message->GetSignature());
+
+  std::vector<Person> people_out1;
+  std::vector<Person> people_out2;
+  std::vector<Person> people_out3;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &people_out1));
+  EXPECT_TRUE(PopValueFromReader(&reader, &people_out2));
+  EXPECT_TRUE(PopVariantValueFromReader(&reader, &people_out3));
+  EXPECT_FALSE(reader.HasMoreData());
+
+  EXPECT_EQ(people, people_out1);
+  EXPECT_EQ(people, people_out2);
+  EXPECT_EQ(people, people_out3);
+}
+
+TEST(DBusUtils, CustomStructInComplexTypes) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  std::vector<Person> people{{"John", "Doe", 32}, {"Jane", "Smith", 48}};
+  std::vector<std::map<int, Person>> data{
+    {
+      {1, Person{"John", "Doe", 32}},
+      {2, Person{"Jane", "Smith", 48}},
+    }
+  };
+  AppendValueToWriter(&writer, data);
+
+  EXPECT_EQ("aa{i(ssi)}", message->GetSignature());
+
+  std::vector<std::map<int, Person>> data_out;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &data_out));
+  EXPECT_FALSE(reader.HasMoreData());
+
+  EXPECT_EQ(data, data_out);
+}
+
+TEST(DBusUtils, EmptyVariant) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  EXPECT_DEATH(AppendValueToWriter(&writer, Any{}),
+               "Must not be called on an empty Any");
+}
+
+TEST(DBusUtils, IncompatibleVariant) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  EXPECT_DEATH(AppendValueToWriter(&writer, Any{2.2f}),
+               "Type 'float' is not supported by D-Bus");
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/dbus_connection.cc b/libbrillo/brillo/dbus/dbus_connection.cc
new file mode 100644
index 0000000..b60cf44
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_connection.cc
@@ -0,0 +1,58 @@
+// Copyright 2016 The Chromium OS 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 <brillo/dbus/dbus_connection.h>
+
+#include <sysexits.h>
+
+#include <base/bind.h>
+#include <brillo/dbus/async_event_sequencer.h>
+#include <brillo/dbus/exported_object_manager.h>
+
+using brillo::dbus_utils::AsyncEventSequencer;
+using brillo::dbus_utils::ExportedObjectManager;
+
+namespace brillo {
+
+DBusConnection::DBusConnection() {
+}
+
+DBusConnection::~DBusConnection() {
+  if (bus_)
+    bus_->ShutdownAndBlock();
+}
+
+scoped_refptr<dbus::Bus> DBusConnection::Connect() {
+  return ConnectWithTimeout(base::TimeDelta());
+}
+
+scoped_refptr<dbus::Bus> DBusConnection::ConnectWithTimeout(
+    base::TimeDelta timeout) {
+  if (bus_)
+    return bus_;
+
+  base::TimeTicks deadline = base::TimeTicks::Now() + timeout;
+
+  dbus::Bus::Options options;
+  options.bus_type = dbus::Bus::SYSTEM;
+
+  scoped_refptr<dbus::Bus> bus = new dbus::Bus(options);
+
+  do {
+    if (bus->Connect()) {
+      bus_ = bus;
+      return bus_;
+    }
+    LOG(WARNING) << "Failed to get system bus.";
+    // Wait 1 second to prevent trashing the device while waiting for the
+    // dbus-daemon to start.
+    sleep(1);
+  } while (base::TimeTicks::Now() < deadline);
+
+  LOG(ERROR) << "Failed to get system bus after " << timeout.InSeconds()
+             << " seconds.";
+  return nullptr;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/dbus_connection.h b/libbrillo/brillo/dbus/dbus_connection.h
new file mode 100644
index 0000000..aecf434
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_connection.h
@@ -0,0 +1,40 @@
+// Copyright 2016 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_DBUS_CONNECTION_H_
+#define LIBBRILLO_BRILLO_DBUS_DBUS_CONNECTION_H_
+
+#include <base/memory/ref_counted.h>
+#include <base/time/time.h>
+#include <dbus/bus.h>
+
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+// DBusConnection adds D-Bus support to Daemon.
+class BRILLO_EXPORT DBusConnection final {
+ public:
+  DBusConnection();
+  ~DBusConnection();
+
+  // Instantiates dbus::Bus and establishes a D-Bus connection. Returns a
+  // reference to the connected bus, or an empty pointer in case of error.
+  scoped_refptr<dbus::Bus> Connect();
+
+  // Instantiates dbus::Bus and tries to establish a D-Bus connection for up to
+  // |timeout|. If the connection can't be established after the timeout, fails
+  // returning an empty pointer.
+  scoped_refptr<dbus::Bus> ConnectWithTimeout(base::TimeDelta timeout);
+
+ private:
+  scoped_refptr<dbus::Bus> bus_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DBusConnection);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DAEMONS_DBUS_DAEMON_H_
diff --git a/libbrillo/brillo/dbus/dbus_method_invoker.cc b/libbrillo/brillo/dbus/dbus_method_invoker.cc
new file mode 100644
index 0000000..94002c2
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_method_invoker.cc
@@ -0,0 +1,23 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/dbus_method_invoker.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+void TranslateErrorResponse(const AsyncErrorCallback& callback,
+                            dbus::ErrorResponse* resp) {
+  if (!callback.is_null()) {
+    ErrorPtr error;
+    dbus::MessageReader reader(resp);
+    std::string error_message;
+    if (ExtractMessageParameters(&reader, &error, &error_message))
+      AddDBusError(&error, resp->GetErrorName(), error_message);
+    callback.Run(error.get());
+  }
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/dbus_method_invoker.h b/libbrillo/brillo/dbus/dbus_method_invoker.h
new file mode 100644
index 0000000..f3d0e6b
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_method_invoker.h
@@ -0,0 +1,324 @@
+// Copyright 2014 The Chromium OS 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 file provides a way to call D-Bus methods on objects in remote processes
+// as if they were native C++ function calls.
+
+// CallMethodAndBlock (along with CallMethodAndBlockWithTimeout) lets you call
+// a D-Bus method synchronously and pass all the required parameters as C++
+// function arguments. CallMethodAndBlock relies on automatic C++ to D-Bus data
+// serialization implemented in brillo/dbus/data_serialization.h.
+// CallMethodAndBlock invokes the D-Bus method and returns the Response.
+
+// The method call response should be parsed with ExtractMethodCallResults().
+// The method takes an optional list of pointers to the expected return values
+// of the D-Bus method.
+
+// CallMethod and CallMethodWithTimeout are similar to CallMethodAndBlock but
+// make the calls asynchronously. They take two callbacks: one for successful
+// method invocation and the second is for error conditions.
+
+// Here is an example of synchronous calls:
+// Call "std::string MyInterface::MyMethod(int, double)" over D-Bus:
+
+//  using brillo::dbus_utils::CallMethodAndBlock;
+//  using brillo::dbus_utils::ExtractMethodCallResults;
+//
+//  brillo::ErrorPtr error;
+//  auto resp = CallMethodAndBlock(obj,
+//                                 "org.chromium.MyService.MyInterface",
+//                                 "MyMethod",
+//                                 &error,
+//                                 2, 8.7);
+//  std::string return_value;
+//  if (resp && ExtractMethodCallResults(resp.get(), &error, &return_value)) {
+//    // Use the |return_value|.
+//  } else {
+//    // An error occurred. Use |error| to get details.
+//  }
+
+// And here is how to call D-Bus methods asynchronously:
+// Call "std::string MyInterface::MyMethod(int, double)" over D-Bus:
+
+//  using brillo::dbus_utils::CallMethod;
+//  using brillo::dbus_utils::ExtractMethodCallResults;
+//
+//  void OnSuccess(const std::string& return_value) {
+//    // Use the |return_value|.
+//  }
+//
+//  void OnError(brillo::Error* error) {
+//    // An error occurred. Use |error| to get details.
+//  }
+//
+//  brillo::dbus_utils::CallMethod(obj,
+//                                   "org.chromium.MyService.MyInterface",
+//                                   "MyMethod",
+//                                   base::Bind(OnSuccess),
+//                                   base::Bind(OnError),
+//                                   2, 8.7);
+
+#ifndef LIBBRILLO_BRILLO_DBUS_DBUS_METHOD_INVOKER_H_
+#define LIBBRILLO_BRILLO_DBUS_DBUS_METHOD_INVOKER_H_
+
+#include <memory>
+#include <string>
+#include <tuple>
+
+#include <base/bind.h>
+#include <brillo/dbus/dbus_param_reader.h>
+#include <brillo/dbus/dbus_param_writer.h>
+#include <brillo/dbus/utils.h>
+#include <brillo/errors/error.h>
+#include <brillo/errors/error_codes.h>
+#include <brillo/brillo_export.h>
+#include <dbus/file_descriptor.h>
+#include <dbus/message.h>
+#include <dbus/object_proxy.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+// A helper method to dispatch a blocking D-Bus method call. Can specify
+// zero or more method call arguments in |args| which will be sent over D-Bus.
+// This method sends a D-Bus message and blocks for a time period specified
+// in |timeout_ms| while waiting for a reply. The time out is in milliseconds or
+// -1 (DBUS_TIMEOUT_USE_DEFAULT) for default, or DBUS_TIMEOUT_INFINITE for no
+// timeout. If a timeout occurs, the response object contains an error object
+// with DBUS_ERROR_NO_REPLY error code (those constants come from libdbus
+// [dbus/dbus.h]).
+// Returns a dbus::Response object on success. On failure, returns nullptr and
+// fills in additional error details into the |error| object.
+template<typename... Args>
+inline std::unique_ptr<dbus::Response> CallMethodAndBlockWithTimeout(
+    int timeout_ms,
+    dbus::ObjectProxy* object,
+    const std::string& interface_name,
+    const std::string& method_name,
+    ErrorPtr* error,
+    const Args&... args) {
+  dbus::MethodCall method_call(interface_name, method_name);
+  // Add method arguments to the message buffer.
+  dbus::MessageWriter writer(&method_call);
+  DBusParamWriter::Append(&writer, args...);
+  dbus::ScopedDBusError dbus_error;
+  auto response = object->CallMethodAndBlockWithErrorDetails(
+      &method_call, timeout_ms, &dbus_error);
+  if (!response) {
+    if (dbus_error.is_set()) {
+      Error::AddTo(error,
+                   FROM_HERE,
+                   errors::dbus::kDomain,
+                   dbus_error.name(),
+                   dbus_error.message());
+    } else {
+      Error::AddToPrintf(error,
+                         FROM_HERE,
+                         errors::dbus::kDomain,
+                         DBUS_ERROR_FAILED,
+                         "Failed to call D-Bus method: %s.%s",
+                         interface_name.c_str(),
+                         method_name.c_str());
+    }
+  }
+  return response;
+}
+
+// Same as CallMethodAndBlockWithTimeout() but uses a default timeout value.
+template<typename... Args>
+inline std::unique_ptr<dbus::Response> CallMethodAndBlock(
+    dbus::ObjectProxy* object,
+    const std::string& interface_name,
+    const std::string& method_name,
+    ErrorPtr* error,
+    const Args&... args) {
+  return CallMethodAndBlockWithTimeout(dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                                       object,
+                                       interface_name,
+                                       method_name,
+                                       error,
+                                       args...);
+}
+
+namespace internal {
+// In order to support non-copyable dbus::FileDescriptor, we have this
+// internal::HackMove() helper function that does really nothing for normal
+// types but uses Pass() for file descriptors so we can move them out from
+// the temporaries created inside DBusParamReader<...>::Invoke().
+// If only libchrome supported real rvalues so we can just do std::move() and
+// be done with it.
+template <typename T>
+inline const T& HackMove(const T& val) {
+  return val;
+}
+
+// Even though |val| here is passed as const&, the actual value is created
+// inside DBusParamReader<...>::Invoke() and is temporary in nature, so it is
+// safe to move the file descriptor out of |val|. That's why we are doing
+// const_cast here. It is a bit hacky, but there is no negative side effects.
+inline dbus::FileDescriptor HackMove(const dbus::FileDescriptor& val) {
+  return std::move(const_cast<dbus::FileDescriptor&>(val));
+}
+}  // namespace internal
+
+// Extracts the parameters of |ResultTypes...| types from the message reader
+// and puts the values in the resulting |tuple|. Returns false on error and
+// provides additional error details in |error| object.
+template<typename... ResultTypes>
+inline bool ExtractMessageParametersAsTuple(
+    dbus::MessageReader* reader,
+    ErrorPtr* error,
+    std::tuple<ResultTypes...>* val_tuple) {
+  auto callback = [val_tuple](const ResultTypes&... params) {
+    *val_tuple = std::forward_as_tuple(internal::HackMove(params)...);
+  };
+  return DBusParamReader<false, ResultTypes...>::Invoke(
+      callback, reader, error);
+}
+// Overload of ExtractMessageParametersAsTuple to handle reference types in
+// tuples created with std::tie().
+template<typename... ResultTypes>
+inline bool ExtractMessageParametersAsTuple(
+    dbus::MessageReader* reader,
+    ErrorPtr* error,
+    std::tuple<ResultTypes&...>* ref_tuple) {
+  auto callback = [ref_tuple](const ResultTypes&... params) {
+    *ref_tuple = std::forward_as_tuple(internal::HackMove(params)...);
+  };
+  return DBusParamReader<false, ResultTypes...>::Invoke(
+      callback, reader, error);
+}
+
+// A helper method to extract a list of values from a message buffer.
+// The function will return false and provide detailed error information on
+// failure. It fails if the D-Bus message buffer (represented by the |reader|)
+// contains too many, too few parameters or the parameters are of wrong types
+// (signatures).
+// The usage pattern is as follows:
+//
+//  int32_t data1;
+//  std::string data2;
+//  ErrorPtr error;
+//  if (ExtractMessageParameters(reader, &error, &data1, &data2)) { ... }
+//
+// The above example extracts an Int32 and a String from D-Bus message buffer.
+template<typename... ResultTypes>
+inline bool ExtractMessageParameters(dbus::MessageReader* reader,
+                                     ErrorPtr* error,
+                                     ResultTypes*... results) {
+  auto ref_tuple = std::tie(*results...);
+  return ExtractMessageParametersAsTuple<ResultTypes...>(
+      reader, error, &ref_tuple);
+}
+
+// Convenient helper method to extract return value(s) of a D-Bus method call.
+// |results| must be zero or more pointers to data expected to be returned
+// from the method called. If an error occurs, returns false and provides
+// additional details in |error| object.
+//
+// It is OK to call this method even if the D-Bus method doesn't expect
+// any return values. Just do not specify any output |results|. In this case,
+// ExtractMethodCallResults() will verify that the method didn't return any
+// data in the |message|.
+template<typename... ResultTypes>
+inline bool ExtractMethodCallResults(dbus::Message* message,
+                                     ErrorPtr* error,
+                                     ResultTypes*... results) {
+  CHECK(message) << "Unable to extract parameters from a NULL message.";
+
+  dbus::MessageReader reader(message);
+  if (message->GetMessageType() == dbus::Message::MESSAGE_ERROR) {
+    std::string error_message;
+    if (ExtractMessageParameters(&reader, error, &error_message))
+      AddDBusError(error, message->GetErrorName(), error_message);
+    return false;
+  }
+  return ExtractMessageParameters(&reader, error, results...);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Asynchronous method invocation support
+
+using AsyncErrorCallback = base::Callback<void(Error* error)>;
+
+// A helper function that translates dbus::ErrorResponse response
+// from D-Bus into brillo::Error* and invokes the |callback|.
+void BRILLO_EXPORT TranslateErrorResponse(const AsyncErrorCallback& callback,
+                                            dbus::ErrorResponse* resp);
+
+// A helper function that translates dbus::Response from D-Bus into
+// a list of C++ values passed as parameters to |success_callback|. If the
+// response message doesn't have the correct number of parameters, or they
+// are of wrong types, an error is sent to |error_callback|.
+template<typename... OutArgs>
+void TranslateSuccessResponse(
+    const base::Callback<void(OutArgs...)>& success_callback,
+    const AsyncErrorCallback& error_callback,
+    dbus::Response* resp) {
+  auto callback = [&success_callback](const OutArgs&... params) {
+    if (!success_callback.is_null()) {
+      success_callback.Run(params...);
+    }
+  };
+  ErrorPtr error;
+  dbus::MessageReader reader(resp);
+  if (!DBusParamReader<false, OutArgs...>::Invoke(callback, &reader, &error) &&
+      !error_callback.is_null()) {
+    error_callback.Run(error.get());
+  }
+}
+
+// A helper method to dispatch a non-blocking D-Bus method call. Can specify
+// zero or more method call arguments in |params| which will be sent over D-Bus.
+// This method sends a D-Bus message and returns immediately.
+// When the remote method returns successfully, the success callback is
+// invoked with the return value(s), if any.
+// On error, the error callback is called. Note, the error callback can be
+// called synchronously (before CallMethodWithTimeout returns) if there was
+// a problem invoking a method (e.g. object or method doesn't exist).
+// If the response is not received within |timeout_ms|, an error callback is
+// called with DBUS_ERROR_NO_REPLY error code.
+template<typename... InArgs, typename... OutArgs>
+inline void CallMethodWithTimeout(
+    int timeout_ms,
+    dbus::ObjectProxy* object,
+    const std::string& interface_name,
+    const std::string& method_name,
+    const base::Callback<void(OutArgs...)>& success_callback,
+    const AsyncErrorCallback& error_callback,
+    const InArgs&... params) {
+  dbus::MethodCall method_call(interface_name, method_name);
+  dbus::MessageWriter writer(&method_call);
+  DBusParamWriter::Append(&writer, params...);
+
+  dbus::ObjectProxy::ErrorCallback dbus_error_callback =
+      base::Bind(&TranslateErrorResponse, error_callback);
+  dbus::ObjectProxy::ResponseCallback dbus_success_callback = base::Bind(
+      &TranslateSuccessResponse<OutArgs...>, success_callback, error_callback);
+
+  object->CallMethodWithErrorCallback(
+      &method_call, timeout_ms, dbus_success_callback, dbus_error_callback);
+}
+
+// Same as CallMethodWithTimeout() but uses a default timeout value.
+template<typename... InArgs, typename... OutArgs>
+inline void CallMethod(dbus::ObjectProxy* object,
+                       const std::string& interface_name,
+                       const std::string& method_name,
+                       const base::Callback<void(OutArgs...)>& success_callback,
+                       const AsyncErrorCallback& error_callback,
+                       const InArgs&... params) {
+  return CallMethodWithTimeout(dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                               object,
+                               interface_name,
+                               method_name,
+                               success_callback,
+                               error_callback,
+                               params...);
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_METHOD_INVOKER_H_
diff --git a/libbrillo/brillo/dbus/dbus_method_invoker_unittest.cc b/libbrillo/brillo/dbus/dbus_method_invoker_unittest.cc
new file mode 100644
index 0000000..bb653fd
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_method_invoker_unittest.cc
@@ -0,0 +1,318 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/dbus_method_invoker.h>
+
+#include <string>
+
+#include <brillo/bind_lambda.h>
+#include <dbus/mock_bus.h>
+#include <dbus/mock_object_proxy.h>
+#include <dbus/scoped_dbus_error.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::AnyNumber;
+using testing::InSequence;
+using testing::Invoke;
+using testing::Return;
+using testing::_;
+
+using dbus::MessageReader;
+using dbus::MessageWriter;
+using dbus::Response;
+
+namespace brillo {
+namespace dbus_utils {
+
+const char kTestPath[] = "/test/path";
+const char kTestServiceName[] = "org.test.Object";
+const char kTestInterface[] = "org.test.Object.TestInterface";
+const char kTestMethod1[] = "TestMethod1";
+const char kTestMethod2[] = "TestMethod2";
+const char kTestMethod4[] = "TestMethod4";
+
+class DBusMethodInvokerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    dbus::Bus::Options options;
+    options.bus_type = dbus::Bus::SYSTEM;
+    bus_ = new dbus::MockBus(options);
+    // By default, don't worry about threading assertions.
+    EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
+    EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
+    // Use a mock exported object.
+    mock_object_proxy_ = new dbus::MockObjectProxy(
+        bus_.get(), kTestServiceName, dbus::ObjectPath(kTestPath));
+    EXPECT_CALL(*bus_,
+                GetObjectProxy(kTestServiceName, dbus::ObjectPath(kTestPath)))
+        .WillRepeatedly(Return(mock_object_proxy_.get()));
+    int def_timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
+    EXPECT_CALL(*mock_object_proxy_,
+                MockCallMethodAndBlockWithErrorDetails(_, def_timeout_ms, _))
+        .WillRepeatedly(Invoke(this, &DBusMethodInvokerTest::CreateResponse));
+  }
+
+  void TearDown() override { bus_ = nullptr; }
+
+  Response* CreateResponse(dbus::MethodCall* method_call,
+                           int /* timeout_ms */,
+                           dbus::ScopedDBusError* dbus_error) {
+    if (method_call->GetInterface() == kTestInterface) {
+      if (method_call->GetMember() == kTestMethod1) {
+        MessageReader reader(method_call);
+        int v1, v2;
+        // Input: two ints.
+        // Output: sum of the ints converted to string.
+        if (reader.PopInt32(&v1) && reader.PopInt32(&v2)) {
+          auto response = Response::CreateEmpty();
+          MessageWriter writer(response.get());
+          writer.AppendString(std::to_string(v1 + v2));
+          return response.release();
+        }
+      } else if (method_call->GetMember() == kTestMethod2) {
+        method_call->SetSerial(123);
+        dbus_set_error(dbus_error->get(), "org.MyError", "My error message");
+        return nullptr;
+      } else if (method_call->GetMember() == kTestMethod4) {
+        method_call->SetSerial(123);
+        MessageReader reader(method_call);
+        dbus::FileDescriptor fd;
+        if (reader.PopFileDescriptor(&fd)) {
+          auto response = Response::CreateEmpty();
+          MessageWriter writer(response.get());
+          fd.CheckValidity();
+          writer.AppendFileDescriptor(fd);
+          return response.release();
+        }
+      }
+    }
+
+    LOG(ERROR) << "Unexpected method call: " << method_call->ToString();
+    return nullptr;
+  }
+
+  std::string CallTestMethod(int v1, int v2) {
+    std::unique_ptr<dbus::Response> response =
+        brillo::dbus_utils::CallMethodAndBlock(mock_object_proxy_.get(),
+                                               kTestInterface, kTestMethod1,
+                                               nullptr, v1, v2);
+    EXPECT_NE(nullptr, response.get());
+    std::string result;
+    using brillo::dbus_utils::ExtractMethodCallResults;
+    EXPECT_TRUE(ExtractMethodCallResults(response.get(), nullptr, &result));
+    return result;
+  }
+
+  // Sends a file descriptor received over D-Bus back to the caller.
+  dbus::FileDescriptor EchoFD(const dbus::FileDescriptor& fd_in) {
+    std::unique_ptr<dbus::Response> response =
+        brillo::dbus_utils::CallMethodAndBlock(mock_object_proxy_.get(),
+                                               kTestInterface, kTestMethod4,
+                                               nullptr, fd_in);
+    EXPECT_NE(nullptr, response.get());
+    dbus::FileDescriptor fd_out;
+    using brillo::dbus_utils::ExtractMethodCallResults;
+    EXPECT_TRUE(ExtractMethodCallResults(response.get(), nullptr, &fd_out));
+    return fd_out;
+  }
+
+  scoped_refptr<dbus::MockBus> bus_;
+  scoped_refptr<dbus::MockObjectProxy> mock_object_proxy_;
+};
+
+TEST_F(DBusMethodInvokerTest, TestSuccess) {
+  EXPECT_EQ("4", CallTestMethod(2, 2));
+  EXPECT_EQ("10", CallTestMethod(3, 7));
+  EXPECT_EQ("-4", CallTestMethod(13, -17));
+}
+
+TEST_F(DBusMethodInvokerTest, TestFailure) {
+  brillo::ErrorPtr error;
+  std::unique_ptr<dbus::Response> response =
+      brillo::dbus_utils::CallMethodAndBlock(
+          mock_object_proxy_.get(), kTestInterface, kTestMethod2, &error);
+  EXPECT_EQ(nullptr, response.get());
+  EXPECT_EQ(brillo::errors::dbus::kDomain, error->GetDomain());
+  EXPECT_EQ("org.MyError", error->GetCode());
+  EXPECT_EQ("My error message", error->GetMessage());
+}
+
+TEST_F(DBusMethodInvokerTest, TestFileDescriptors) {
+  // Passing a file descriptor over D-Bus would effectively duplicate the fd.
+  // So the resulting file descriptor value would be different but it still
+  // should be valid.
+  dbus::FileDescriptor fd_stdin(0);
+  fd_stdin.CheckValidity();
+  EXPECT_NE(fd_stdin.value(), EchoFD(fd_stdin).value());
+  dbus::FileDescriptor fd_stdout(1);
+  fd_stdout.CheckValidity();
+  EXPECT_NE(fd_stdout.value(), EchoFD(fd_stdout).value());
+  dbus::FileDescriptor fd_stderr(2);
+  fd_stderr.CheckValidity();
+  EXPECT_NE(fd_stderr.value(), EchoFD(fd_stderr).value());
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Asynchronous method invocation support
+
+class AsyncDBusMethodInvokerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    dbus::Bus::Options options;
+    options.bus_type = dbus::Bus::SYSTEM;
+    bus_ = new dbus::MockBus(options);
+    // By default, don't worry about threading assertions.
+    EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
+    EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
+    // Use a mock exported object.
+    mock_object_proxy_ = new dbus::MockObjectProxy(
+        bus_.get(), kTestServiceName, dbus::ObjectPath(kTestPath));
+    EXPECT_CALL(*bus_,
+                GetObjectProxy(kTestServiceName, dbus::ObjectPath(kTestPath)))
+        .WillRepeatedly(Return(mock_object_proxy_.get()));
+    int def_timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
+    EXPECT_CALL(*mock_object_proxy_,
+                CallMethodWithErrorCallback(_, def_timeout_ms, _, _))
+        .WillRepeatedly(Invoke(this, &AsyncDBusMethodInvokerTest::HandleCall));
+  }
+
+  void TearDown() override { bus_ = nullptr; }
+
+  void HandleCall(dbus::MethodCall* method_call,
+                  int /* timeout_ms */,
+                  dbus::ObjectProxy::ResponseCallback success_callback,
+                  dbus::ObjectProxy::ErrorCallback error_callback) {
+    if (method_call->GetInterface() == kTestInterface) {
+      if (method_call->GetMember() == kTestMethod1) {
+        MessageReader reader(method_call);
+        int v1, v2;
+        // Input: two ints.
+        // Output: sum of the ints converted to string.
+        if (reader.PopInt32(&v1) && reader.PopInt32(&v2)) {
+          auto response = Response::CreateEmpty();
+          MessageWriter writer(response.get());
+          writer.AppendString(std::to_string(v1 + v2));
+          success_callback.Run(response.get());
+        }
+        return;
+      } else if (method_call->GetMember() == kTestMethod2) {
+        method_call->SetSerial(123);
+        auto error_response = dbus::ErrorResponse::FromMethodCall(
+            method_call, "org.MyError", "My error message");
+        error_callback.Run(error_response.get());
+        return;
+      }
+    }
+
+    LOG(FATAL) << "Unexpected method call: " << method_call->ToString();
+  }
+
+  base::Callback<void(const std::string&)> SuccessCallback(
+      const std::string& in_result, int* in_counter) {
+    return base::Bind(
+        [](const std::string& result,
+           int* counter,
+           const std::string& actual_result) {
+          (*counter)++;
+          EXPECT_EQ(result, actual_result);
+        },
+        in_result,
+        base::Unretained(in_counter));
+  }
+
+  base::Callback<void(const std::string&)> SuccessCallback(int* in_counter) {
+    return base::Bind(
+        [](int* counter, const std::string& actual_result) {
+          (*counter)++;
+          EXPECT_EQ("", actual_result);
+        },
+        base::Unretained(in_counter));
+  }
+
+  AsyncErrorCallback ErrorCallback(int* in_counter) {
+    return base::Bind(
+        [](int* counter, brillo::Error* error) {
+          (*counter)++;
+          EXPECT_NE(nullptr, error);
+          EXPECT_EQ("", error->GetDomain());
+          EXPECT_EQ("", error->GetCode());
+          EXPECT_EQ("", error->GetMessage());
+        },
+        base::Unretained(in_counter));
+  }
+
+  AsyncErrorCallback ErrorCallback(const std::string& domain,
+                                   const std::string& code,
+                                   const std::string& message,
+                                   int* in_counter) {
+    return base::Bind(
+        [](const std::string& domain,
+           const std::string& code,
+           const std::string& message,
+           int* counter,
+           brillo::Error* error) {
+          (*counter)++;
+          EXPECT_NE(nullptr, error);
+          EXPECT_EQ(domain, error->GetDomain());
+          EXPECT_EQ(code, error->GetCode());
+          EXPECT_EQ(message, error->GetMessage());
+        },
+        domain,
+        code,
+        message,
+        base::Unretained(in_counter));
+  }
+
+  scoped_refptr<dbus::MockBus> bus_;
+  scoped_refptr<dbus::MockObjectProxy> mock_object_proxy_;
+};
+
+TEST_F(AsyncDBusMethodInvokerTest, TestSuccess) {
+  int error_count = 0;
+  int success_count = 0;
+  brillo::dbus_utils::CallMethod(
+      mock_object_proxy_.get(),
+      kTestInterface,
+      kTestMethod1,
+      base::Bind(SuccessCallback("4", &success_count)),
+      base::Bind(ErrorCallback(&error_count)),
+      2, 2);
+  brillo::dbus_utils::CallMethod(
+      mock_object_proxy_.get(),
+      kTestInterface,
+      kTestMethod1,
+      base::Bind(SuccessCallback("10", &success_count)),
+      base::Bind(ErrorCallback(&error_count)),
+      3, 7);
+  brillo::dbus_utils::CallMethod(
+      mock_object_proxy_.get(),
+      kTestInterface,
+      kTestMethod1,
+      base::Bind(SuccessCallback("-4", &success_count)),
+      base::Bind(ErrorCallback(&error_count)),
+      13, -17);
+  EXPECT_EQ(0, error_count);
+  EXPECT_EQ(3, success_count);
+}
+
+TEST_F(AsyncDBusMethodInvokerTest, TestFailure) {
+  int error_count = 0;
+  int success_count = 0;
+  brillo::dbus_utils::CallMethod(
+      mock_object_proxy_.get(),
+      kTestInterface,
+      kTestMethod2,
+      base::Bind(SuccessCallback(&success_count)),
+      base::Bind(ErrorCallback(brillo::errors::dbus::kDomain,
+                               "org.MyError",
+                               "My error message",
+                               &error_count)),
+      2, 2);
+  EXPECT_EQ(1, error_count);
+  EXPECT_EQ(0, success_count);
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/dbus_method_response.cc b/libbrillo/brillo/dbus/dbus_method_response.cc
new file mode 100644
index 0000000..265f9f3
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_method_response.cc
@@ -0,0 +1,65 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/dbus_method_response.h>
+
+#include <brillo/dbus/utils.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+DBusMethodResponseBase::DBusMethodResponseBase(dbus::MethodCall* method_call,
+                                               ResponseSender sender)
+    : sender_(sender), method_call_(method_call) {
+}
+
+DBusMethodResponseBase::~DBusMethodResponseBase() {
+  if (method_call_) {
+    // Response hasn't been sent by the handler. Abort the call.
+    Abort();
+  }
+}
+
+void DBusMethodResponseBase::ReplyWithError(const brillo::Error* error) {
+  CheckCanSendResponse();
+  auto response = GetDBusError(method_call_, error);
+  SendRawResponse(std::move(response));
+}
+
+void DBusMethodResponseBase::ReplyWithError(
+    const tracked_objects::Location& location,
+    const std::string& error_domain,
+    const std::string& error_code,
+    const std::string& error_message) {
+  ErrorPtr error;
+  Error::AddTo(&error, location, error_domain, error_code, error_message);
+  ReplyWithError(error.get());
+}
+
+void DBusMethodResponseBase::Abort() {
+  SendRawResponse(std::unique_ptr<dbus::Response>());
+}
+
+void DBusMethodResponseBase::SendRawResponse(
+    std::unique_ptr<dbus::Response> response) {
+  CheckCanSendResponse();
+  method_call_ = nullptr;  // Mark response as sent.
+  sender_.Run(std::move(response));
+}
+
+std::unique_ptr<dbus::Response>
+DBusMethodResponseBase::CreateCustomResponse() const {
+  return dbus::Response::FromMethodCall(method_call_);
+}
+
+bool DBusMethodResponseBase::IsResponseSent() const {
+  return (method_call_ == nullptr);
+}
+
+void DBusMethodResponseBase::CheckCanSendResponse() const {
+  CHECK(method_call_) << "Response already sent";
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/dbus_method_response.h b/libbrillo/brillo/dbus/dbus_method_response.h
new file mode 100644
index 0000000..0a9ef08
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_method_response.h
@@ -0,0 +1,98 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_DBUS_METHOD_RESPONSE_H_
+#define LIBBRILLO_BRILLO_DBUS_DBUS_METHOD_RESPONSE_H_
+
+#include <string>
+
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+#include <brillo/dbus/dbus_param_writer.h>
+#include <brillo/errors/error.h>
+#include <dbus/exported_object.h>
+#include <dbus/message.h>
+
+namespace brillo {
+
+class Error;
+
+namespace dbus_utils {
+
+using ResponseSender = dbus::ExportedObject::ResponseSender;
+
+// DBusMethodResponseBase is a helper class used with asynchronous D-Bus method
+// handlers to encapsulate the information needed to send the method call
+// response when it is available.
+class BRILLO_EXPORT DBusMethodResponseBase {
+ public:
+  DBusMethodResponseBase(dbus::MethodCall* method_call, ResponseSender sender);
+  virtual ~DBusMethodResponseBase();
+
+  // Sends an error response. Marshals the |error| object over D-Bus.
+  // If |error| is from the "dbus" error domain, takes the |error_code| from
+  // |error| and uses it as the DBus error name.
+  // For error is from other domains, the full error information (domain, error
+  // code, error message) is encoded into the D-Bus error message and returned
+  // to the caller as "org.freedesktop.DBus.Failed".
+  void ReplyWithError(const brillo::Error* error);
+
+  // Constructs brillo::Error object from the parameters specified and send
+  // the error information over D-Bus using the method above.
+  void ReplyWithError(const tracked_objects::Location& location,
+                      const std::string& error_domain,
+                      const std::string& error_code,
+                      const std::string& error_message);
+
+  // Sends a raw D-Bus response message.
+  void SendRawResponse(std::unique_ptr<dbus::Response> response);
+
+  // Creates a custom response object for the current method call.
+  std::unique_ptr<dbus::Response> CreateCustomResponse() const;
+
+  // Checks if the response has been sent already.
+  bool IsResponseSent() const;
+
+ protected:
+  void CheckCanSendResponse() const;
+
+  // Aborts the method execution. Does not send any response message.
+  void Abort();
+
+ private:
+  // A callback to be called to send the method call response message.
+  ResponseSender sender_;
+  // |method_call_| is actually owned by |sender_| (it is embedded as unique_ptr
+  // in the bound parameter list in the Callback). We set it to nullptr after
+  // the method call response has been sent to ensure we can't possibly try
+  // to send a response again somehow.
+  dbus::MethodCall* method_call_;
+
+  DISALLOW_COPY_AND_ASSIGN(DBusMethodResponseBase);
+};
+
+// DBusMethodResponse is an explicitly-typed version of DBusMethodResponse.
+// Using DBusMethodResponse<Types...> indicates the types a D-Bus method
+// is expected to return.
+template<typename... Types>
+class DBusMethodResponse : public DBusMethodResponseBase {
+ public:
+  // Make the base class's custom constructor available to DBusMethodResponse.
+  using DBusMethodResponseBase::DBusMethodResponseBase;
+
+  // Sends the a successful response. |return_values| can contain a list
+  // of return values to be sent to the caller.
+  inline void Return(const Types&... return_values) {
+    CheckCanSendResponse();
+    auto response = CreateCustomResponse();
+    dbus::MessageWriter writer(response.get());
+    DBusParamWriter::Append(&writer, return_values...);
+    SendRawResponse(std::move(response));
+  }
+};
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_METHOD_RESPONSE_H_
diff --git a/libbrillo/brillo/dbus/dbus_object.cc b/libbrillo/brillo/dbus/dbus_object.cc
new file mode 100644
index 0000000..59350a5
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_object.cc
@@ -0,0 +1,279 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/dbus_object.h>
+
+#include <vector>
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <brillo/dbus/async_event_sequencer.h>
+#include <brillo/dbus/exported_object_manager.h>
+#include <brillo/dbus/exported_property_set.h>
+#include <dbus/property.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+//////////////////////////////////////////////////////////////////////////////
+
+DBusInterface::DBusInterface(DBusObject* dbus_object,
+                             const std::string& interface_name)
+    : dbus_object_(dbus_object), interface_name_(interface_name) {
+}
+
+void DBusInterface::AddProperty(const std::string& property_name,
+                                ExportedPropertyBase* prop_base) {
+  dbus_object_->property_set_.RegisterProperty(
+      interface_name_, property_name, prop_base);
+}
+
+void DBusInterface::ExportAsync(
+    ExportedObjectManager* object_manager,
+    dbus::Bus* /* bus */,
+    dbus::ExportedObject* exported_object,
+    const dbus::ObjectPath& object_path,
+    const AsyncEventSequencer::CompletionAction& completion_callback) {
+  VLOG(1) << "Registering D-Bus interface '" << interface_name_ << "' for '"
+          << object_path.value() << "'";
+  scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
+  for (const auto& pair : handlers_) {
+    std::string method_name = pair.first;
+    VLOG(1) << "Exporting method: " << interface_name_ << "." << method_name;
+    std::string export_error = "Failed exporting " + method_name + " method";
+    auto export_handler = sequencer->GetExportHandler(
+        interface_name_, method_name, export_error, true);
+    auto method_handler =
+        base::Bind(&DBusInterface::HandleMethodCall, base::Unretained(this));
+    exported_object->ExportMethod(
+        interface_name_, method_name, method_handler, export_handler);
+  }
+
+  std::vector<AsyncEventSequencer::CompletionAction> actions;
+  if (object_manager) {
+    auto property_writer_callback =
+        dbus_object_->property_set_.GetPropertyWriter(interface_name_);
+    actions.push_back(
+        base::Bind(&DBusInterface::ClaimInterface,
+                   weak_factory_.GetWeakPtr(),
+                   object_manager->AsWeakPtr(),
+                   object_path,
+                   property_writer_callback));
+  }
+  actions.push_back(completion_callback);
+  sequencer->OnAllTasksCompletedCall(actions);
+}
+
+void DBusInterface::ExportAndBlock(
+    ExportedObjectManager* object_manager,
+    dbus::Bus* /* bus */,
+    dbus::ExportedObject* exported_object,
+    const dbus::ObjectPath& object_path) {
+  VLOG(1) << "Registering D-Bus interface '" << interface_name_ << "' for '"
+          << object_path.value() << "'";
+  for (const auto& pair : handlers_) {
+    std::string method_name = pair.first;
+    VLOG(1) << "Exporting method: " << interface_name_ << "." << method_name;
+    auto method_handler =
+        base::Bind(&DBusInterface::HandleMethodCall, base::Unretained(this));
+    if (!exported_object->ExportMethodAndBlock(
+            interface_name_, method_name, method_handler)) {
+        LOG(FATAL) << "Failed exporting " << method_name << " method";
+    }
+  }
+
+  if (object_manager) {
+    auto property_writer_callback =
+        dbus_object_->property_set_.GetPropertyWriter(interface_name_);
+    ClaimInterface(object_manager->AsWeakPtr(),
+                   object_path,
+                   property_writer_callback,
+                   true);
+  }
+}
+
+void DBusInterface::ClaimInterface(
+      base::WeakPtr<ExportedObjectManager> object_manager,
+      const dbus::ObjectPath& object_path,
+      const ExportedPropertySet::PropertyWriter& writer,
+      bool all_succeeded) {
+  if (!all_succeeded || !object_manager) {
+    LOG(ERROR) << "Skipping claiming interface: " << interface_name_;
+    return;
+  }
+  object_manager->ClaimInterface(object_path, interface_name_, writer);
+  release_interface_cb_.ReplaceClosure(
+      base::Bind(&ExportedObjectManager::ReleaseInterface,
+                 object_manager, object_path, interface_name_));
+}
+
+void DBusInterface::HandleMethodCall(dbus::MethodCall* method_call,
+                                     ResponseSender sender) {
+  std::string method_name = method_call->GetMember();
+  // Make a local copy of |interface_name_| because calling HandleMethod()
+  // can potentially kill this interface object...
+  std::string interface_name = interface_name_;
+  VLOG(1) << "Received method call request: " << interface_name << "."
+          << method_name << "(" << method_call->GetSignature() << ")";
+  auto pair = handlers_.find(method_name);
+  if (pair == handlers_.end()) {
+    auto response =
+        dbus::ErrorResponse::FromMethodCall(method_call,
+                                            DBUS_ERROR_UNKNOWN_METHOD,
+                                            "Unknown method: " + method_name);
+    sender.Run(std::move(response));
+    return;
+  }
+  VLOG(1) << "Dispatching DBus method call: " << method_name;
+  pair->second->HandleMethod(method_call, sender);
+}
+
+void DBusInterface::AddHandlerImpl(
+    const std::string& method_name,
+    std::unique_ptr<DBusInterfaceMethodHandlerInterface> handler) {
+  VLOG(1) << "Declaring method handler: " << interface_name_ << "."
+          << method_name;
+  auto res = handlers_.insert(std::make_pair(method_name, std::move(handler)));
+  CHECK(res.second) << "Method '" << method_name << "' already exists";
+}
+
+void DBusInterface::AddSignalImpl(
+    const std::string& signal_name,
+    const std::shared_ptr<DBusSignalBase>& signal) {
+  VLOG(1) << "Declaring a signal sink: " << interface_name_ << "."
+          << signal_name;
+  CHECK(signals_.insert(std::make_pair(signal_name, signal)).second)
+      << "The signal '" << signal_name << "' is already registered";
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+DBusObject::DBusObject(ExportedObjectManager* object_manager,
+                       const scoped_refptr<dbus::Bus>& bus,
+                       const dbus::ObjectPath& object_path)
+    : property_set_(bus.get()), bus_(bus), object_path_(object_path) {
+  if (object_manager)
+    object_manager_ = object_manager->AsWeakPtr();
+}
+
+DBusObject::~DBusObject() {
+  if (exported_object_)
+    exported_object_->Unregister();
+}
+
+DBusInterface* DBusObject::AddOrGetInterface(
+    const std::string& interface_name) {
+  auto iter = interfaces_.find(interface_name);
+  if (iter == interfaces_.end()) {
+    VLOG(1) << "Adding an interface '" << interface_name << "' to object '"
+            << object_path_.value() << "'.";
+    // Interface doesn't exist yet. Create one...
+    std::unique_ptr<DBusInterface> new_itf(
+        new DBusInterface(this, interface_name));
+    iter = interfaces_.insert(std::make_pair(interface_name,
+                                             std::move(new_itf))).first;
+  }
+  return iter->second.get();
+}
+
+DBusInterface* DBusObject::FindInterface(
+    const std::string& interface_name) const {
+  auto itf_iter = interfaces_.find(interface_name);
+  return (itf_iter == interfaces_.end()) ? nullptr : itf_iter->second.get();
+}
+
+void DBusObject::RegisterAsync(
+    const AsyncEventSequencer::CompletionAction& completion_callback) {
+  VLOG(1) << "Registering D-Bus object '" << object_path_.value() << "'.";
+  CHECK(exported_object_ == nullptr) << "Object already registered.";
+  scoped_refptr<AsyncEventSequencer> sequencer(new AsyncEventSequencer());
+  exported_object_ = bus_->GetExportedObject(object_path_);
+
+  // Add the org.freedesktop.DBus.Properties interface to the object.
+  DBusInterface* prop_interface = AddOrGetInterface(dbus::kPropertiesInterface);
+  prop_interface->AddSimpleMethodHandler(
+      dbus::kPropertiesGetAll,
+      base::Unretained(&property_set_),
+      &ExportedPropertySet::HandleGetAll);
+  prop_interface->AddSimpleMethodHandlerWithError(
+      dbus::kPropertiesGet,
+      base::Unretained(&property_set_),
+      &ExportedPropertySet::HandleGet);
+  prop_interface->AddSimpleMethodHandlerWithError(
+      dbus::kPropertiesSet,
+      base::Unretained(&property_set_),
+      &ExportedPropertySet::HandleSet);
+  property_set_.OnPropertiesInterfaceExported(prop_interface);
+
+  // Export interface methods
+  for (const auto& pair : interfaces_) {
+    pair.second->ExportAsync(
+        object_manager_.get(),
+        bus_.get(),
+        exported_object_,
+        object_path_,
+        sequencer->GetHandler("Failed to export interface " + pair.first,
+                              false));
+  }
+
+  sequencer->OnAllTasksCompletedCall({completion_callback});
+}
+
+void DBusObject::RegisterAndBlock() {
+  VLOG(1) << "Registering D-Bus object '" << object_path_.value() << "'.";
+  CHECK(exported_object_ == nullptr) << "Object already registered.";
+  exported_object_ = bus_->GetExportedObject(object_path_);
+
+  // Add the org.freedesktop.DBus.Properties interface to the object.
+  DBusInterface* prop_interface = AddOrGetInterface(dbus::kPropertiesInterface);
+  prop_interface->AddSimpleMethodHandler(
+      dbus::kPropertiesGetAll,
+      base::Unretained(&property_set_),
+      &ExportedPropertySet::HandleGetAll);
+  prop_interface->AddSimpleMethodHandlerWithError(
+      dbus::kPropertiesGet,
+      base::Unretained(&property_set_),
+      &ExportedPropertySet::HandleGet);
+  prop_interface->AddSimpleMethodHandlerWithError(
+      dbus::kPropertiesSet,
+      base::Unretained(&property_set_),
+      &ExportedPropertySet::HandleSet);
+  property_set_.OnPropertiesInterfaceExported(prop_interface);
+
+  // Export interface methods
+  for (const auto& pair : interfaces_) {
+    pair.second->ExportAndBlock(
+        object_manager_.get(),
+        bus_.get(),
+        exported_object_,
+        object_path_);
+  }
+}
+
+void DBusObject::UnregisterAsync() {
+  VLOG(1) << "Unregistering D-Bus object '" << object_path_.value() << "'.";
+  CHECK(exported_object_ != nullptr) << "Object not registered.";
+
+  // This will unregister the object path from the bus.
+  exported_object_->Unregister();
+  // This will remove |exported_object_| from bus's object table. This function
+  // will also post a task to unregister |exported_object_| (same as the call
+  // above), which will be a no-op since it is already done by then.
+  // By doing both in here, the object path is guarantee to be reusable upon
+  // return from this function.
+  bus_->UnregisterExportedObject(object_path_);
+  exported_object_ = nullptr;
+}
+
+bool DBusObject::SendSignal(dbus::Signal* signal) {
+  if (exported_object_) {
+    exported_object_->SendSignal(signal);
+    return true;
+  }
+  LOG(ERROR) << "Trying to send a signal from an object that is not exported";
+  return false;
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/dbus_object.h b/libbrillo/brillo/dbus/dbus_object.h
new file mode 100644
index 0000000..6cd34dd
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_object.h
@@ -0,0 +1,579 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// DBusObject is a special helper class that simplifies the implementation of
+// D-Bus objects in C++. It provides an easy way to define interfaces with
+// methods and properties and offloads a lot of work to register the object and
+// all of its interfaces, to marshal method calls (by converting D-Bus method
+// parameters to native C++ types and invoking native method handlers), etc.
+
+// The basic usage pattern of this class is as follows:
+/*
+class MyDbusObject {
+ public:
+  MyDbusObject(ExportedObjectManager* object_manager,
+               const scoped_refptr<dbus::Bus>& bus)
+      : dbus_object_(object_manager, bus,
+                     dbus::ObjectPath("/org/chromium/my_obj")) {}
+
+  void Init(const AsyncEventSequencer::CompletionAction& callback) {
+    DBusInterface* my_interface =
+        dbus_object_.AddOrGetInterface("org.chromium.MyInterface");
+    my_interface->AddSimpleMethodHandler("Method1", this,
+                                         &MyDbusObject::Method1);
+    my_interface->AddSimpleMethodHandlerWithError("Method2", this,
+                                                  &MyDbusObject::Method2);
+    my_interface->AddMethodHandler("Method3", this, &MyDbusObject::Method3);
+    my_interface->AddProperty("Property1", &prop1_);
+    my_interface->AddProperty("Property2", &prop2_);
+    prop1_.SetValue("prop1_value");
+    prop2_.SetValue(50);
+    // Register the object by exporting its methods and properties and
+    // exposing them to D-Bus clients.
+    dbus_object_.RegisterAsync(callback);
+  }
+
+ private:
+  DBusObject dbus_object_;
+
+  // Make sure the properties outlive the DBusObject they are registered with.
+  brillo::dbus_utils::ExportedProperty<std::string> prop1_;
+  brillo::dbus_utils::ExportedProperty<int> prop2_;
+  int Method1() { return 5; }
+  bool Method2(brillo::ErrorPtr* error, const std::string& message);
+  void Method3(std::unique_ptr<DBusMethodResponse<int_32>> response,
+               const std::string& message) {
+    if (message.empty()) {
+       response->ReplyWithError(brillo::errors::dbus::kDomain,
+                                DBUS_ERROR_INVALID_ARGS,
+                                "Message string cannot be empty");
+       return;
+    }
+    int32_t message_len = message.length();
+    response->Return(message_len);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(MyDbusObject);
+};
+*/
+
+#ifndef LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_H_
+#define LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_H_
+
+#include <map>
+#include <string>
+
+#include <base/bind.h>
+#include <base/callback_helpers.h>
+#include <base/macros.h>
+#include <base/memory/weak_ptr.h>
+#include <brillo/brillo_export.h>
+#include <brillo/dbus/async_event_sequencer.h>
+#include <brillo/dbus/dbus_object_internal_impl.h>
+#include <brillo/dbus/dbus_signal.h>
+#include <brillo/dbus/exported_property_set.h>
+#include <brillo/errors/error.h>
+#include <dbus/bus.h>
+#include <dbus/exported_object.h>
+#include <dbus/message.h>
+#include <dbus/object_path.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+class ExportedObjectManager;
+class ExportedPropertyBase;
+class DBusObject;
+
+// This is an implementation proxy class for a D-Bus interface of an object.
+// The important functionality for the users is the ability to add D-Bus method
+// handlers and define D-Bus object properties. This is achieved by using one
+// of the overload of AddSimpleMethodHandler()/AddMethodHandler() and
+// AddProperty() respectively.
+// There are three overloads for DBusInterface::AddSimpleMethodHandler() and
+// AddMethodHandler() each:
+//  1. That takes a handler as base::Callback
+//  2. That takes a static function
+//  3. That takes a class instance pointer and a class member function
+// The signature of the handler for AddSimpleMethodHandler must be one of:
+//    R(Args... args)                     [IN only]
+//    void(Args... args)                  [IN/OUT]
+// The signature of the handler for AddSimpleMethodHandlerWithError must be:
+//    bool(ErrorPtr* error, Args... args) [IN/OUT]
+// The signature of the handler for AddSimpleMethodHandlerWithErrorAndMessage:
+//    bool(ErrorPtr* error, dbus::Message* msg, Args... args) [IN/OUT]
+// The signature of the handler for AddMethodHandler must be:
+//    void(std::unique_ptr<DBusMethodResponse<T...>> response,
+//         Args... args) [IN]
+// The signature of the handler for AddMethodHandlerWithMessage must be:
+//    void(std::unique_ptr<DBusMethodResponse<T...>> response,
+//         dbus::Message* msg, Args... args) [IN]
+// There is also an AddRawMethodHandler() call that lets provide a custom
+// handler that can parse its own input parameter and construct a custom
+// response.
+// The signature of the handler for AddRawMethodHandler must be:
+//    void(dbus::MethodCall* method_call, ResponseSender sender)
+class BRILLO_EXPORT DBusInterface final {
+ public:
+  DBusInterface(DBusObject* dbus_object, const std::string& interface_name);
+
+  // Register sync DBus method handler for |method_name| as base::Callback.
+  template<typename R, typename... Args>
+  inline void AddSimpleMethodHandler(
+      const std::string& method_name,
+      const base::Callback<R(Args...)>& handler) {
+    Handler<SimpleDBusInterfaceMethodHandler<R, Args...>>::Add(
+        this, method_name, handler);
+  }
+
+  // Register sync D-Bus method handler for |method_name| as a static
+  // function.
+  template<typename R, typename... Args>
+  inline void AddSimpleMethodHandler(const std::string& method_name,
+                                     R(*handler)(Args...)) {
+    Handler<SimpleDBusInterfaceMethodHandler<R, Args...>>::Add(
+        this, method_name, base::Bind(handler));
+  }
+
+  // Register sync D-Bus method handler for |method_name| as a class member
+  // function.
+  template<typename Instance, typename Class, typename R, typename... Args>
+  inline void AddSimpleMethodHandler(const std::string& method_name,
+                                     Instance instance,
+                                     R(Class::*handler)(Args...)) {
+    Handler<SimpleDBusInterfaceMethodHandler<R, Args...>>::Add(
+        this, method_name, base::Bind(handler, instance));
+  }
+
+  // Same as above but for const-method of a class.
+  template<typename Instance, typename Class, typename R, typename... Args>
+  inline void AddSimpleMethodHandler(const std::string& method_name,
+                                     Instance instance,
+                                     R(Class::*handler)(Args...) const) {
+    Handler<SimpleDBusInterfaceMethodHandler<R, Args...>>::Add(
+        this, method_name, base::Bind(handler, instance));
+  }
+
+  // Register sync DBus method handler for |method_name| as base::Callback.
+  template<typename... Args>
+  inline void AddSimpleMethodHandlerWithError(
+      const std::string& method_name,
+      const base::Callback<bool(ErrorPtr*, Args...)>& handler) {
+    Handler<SimpleDBusInterfaceMethodHandlerWithError<Args...>>::Add(
+        this, method_name, handler);
+  }
+
+  // Register sync D-Bus method handler for |method_name| as a static
+  // function.
+  template<typename... Args>
+  inline void AddSimpleMethodHandlerWithError(
+      const std::string& method_name,
+      bool(*handler)(ErrorPtr*, Args...)) {
+    Handler<SimpleDBusInterfaceMethodHandlerWithError<Args...>>::Add(
+        this, method_name, base::Bind(handler));
+  }
+
+  // Register sync D-Bus method handler for |method_name| as a class member
+  // function.
+  template<typename Instance, typename Class, typename... Args>
+  inline void AddSimpleMethodHandlerWithError(
+      const std::string& method_name,
+      Instance instance,
+      bool(Class::*handler)(ErrorPtr*, Args...)) {
+    Handler<SimpleDBusInterfaceMethodHandlerWithError<Args...>>::Add(
+        this, method_name, base::Bind(handler, instance));
+  }
+
+  // Same as above but for const-method of a class.
+  template<typename Instance, typename Class, typename... Args>
+  inline void AddSimpleMethodHandlerWithError(
+      const std::string& method_name,
+      Instance instance,
+      bool(Class::*handler)(ErrorPtr*, Args...) const) {
+    Handler<SimpleDBusInterfaceMethodHandlerWithError<Args...>>::Add(
+        this, method_name, base::Bind(handler, instance));
+  }
+
+  // Register sync DBus method handler for |method_name| as base::Callback.
+  // Passing the method sender as a first parameter to the callback.
+  template<typename... Args>
+  inline void AddSimpleMethodHandlerWithErrorAndMessage(
+      const std::string& method_name,
+      const base::Callback<bool(ErrorPtr*, dbus::Message*, Args...)>&
+          handler) {
+    Handler<SimpleDBusInterfaceMethodHandlerWithErrorAndMessage<Args...>>::Add(
+        this, method_name, handler);
+  }
+
+  // Register sync D-Bus method handler for |method_name| as a static
+  // function. Passing the method D-Bus message as the second parameter to the
+  // callback.
+  template<typename... Args>
+  inline void AddSimpleMethodHandlerWithErrorAndMessage(
+      const std::string& method_name,
+      bool(*handler)(ErrorPtr*, dbus::Message*, Args...)) {
+    Handler<SimpleDBusInterfaceMethodHandlerWithErrorAndMessage<Args...>>::Add(
+        this, method_name, base::Bind(handler));
+  }
+
+  // Register sync D-Bus method handler for |method_name| as a class member
+  // function. Passing the method D-Bus message as the second parameter to the
+  // callback.
+  template<typename Instance, typename Class, typename... Args>
+  inline void AddSimpleMethodHandlerWithErrorAndMessage(
+      const std::string& method_name,
+      Instance instance,
+      bool(Class::*handler)(ErrorPtr*, dbus::Message*, Args...)) {
+    Handler<SimpleDBusInterfaceMethodHandlerWithErrorAndMessage<Args...>>::Add(
+        this, method_name, base::Bind(handler, instance));
+  }
+
+  // Same as above but for const-method of a class.
+  template<typename Instance, typename Class, typename... Args>
+  inline void AddSimpleMethodHandlerWithErrorAndMessage(
+      const std::string& method_name,
+      Instance instance,
+      bool(Class::*handler)(ErrorPtr*, dbus::Message*, Args...) const) {
+    Handler<SimpleDBusInterfaceMethodHandlerWithErrorAndMessage<Args...>>::Add(
+        this, method_name, base::Bind(handler, instance));
+  }
+
+  // Register an async DBus method handler for |method_name| as base::Callback.
+  template<typename Response, typename... Args>
+  inline void AddMethodHandler(
+      const std::string& method_name,
+      const base::Callback<void(std::unique_ptr<Response>, Args...)>& handler) {
+    static_assert(std::is_base_of<DBusMethodResponseBase, Response>::value,
+                  "Response must be DBusMethodResponse<T...>");
+    Handler<DBusInterfaceMethodHandler<Response, Args...>>::Add(
+        this, method_name, handler);
+  }
+
+  // Register an async D-Bus method handler for |method_name| as a static
+  // function.
+  template<typename Response, typename... Args>
+  inline void AddMethodHandler(
+      const std::string& method_name,
+      void (*handler)(std::unique_ptr<Response>, Args...)) {
+    static_assert(std::is_base_of<DBusMethodResponseBase, Response>::value,
+                  "Response must be DBusMethodResponse<T...>");
+    Handler<DBusInterfaceMethodHandler<Response, Args...>>::Add(
+        this, method_name, base::Bind(handler));
+  }
+
+  // Register an async D-Bus method handler for |method_name| as a class member
+  // function.
+  template<typename Response,
+           typename Instance,
+           typename Class,
+           typename... Args>
+  inline void AddMethodHandler(
+      const std::string& method_name,
+      Instance instance,
+      void(Class::*handler)(std::unique_ptr<Response>, Args...)) {
+    static_assert(std::is_base_of<DBusMethodResponseBase, Response>::value,
+                  "Response must be DBusMethodResponse<T...>");
+    Handler<DBusInterfaceMethodHandler<Response, Args...>>::Add(
+        this, method_name, base::Bind(handler, instance));
+  }
+
+  // Same as above but for const-method of a class.
+  template<typename Response,
+           typename Instance,
+           typename Class,
+           typename... Args>
+  inline void AddMethodHandler(
+      const std::string& method_name,
+      Instance instance,
+      void(Class::*handler)(std::unique_ptr<Response>, Args...) const) {
+    static_assert(std::is_base_of<DBusMethodResponseBase, Response>::value,
+                  "Response must be DBusMethodResponse<T...>");
+    Handler<DBusInterfaceMethodHandler<Response, Args...>>::Add(
+        this, method_name, base::Bind(handler, instance));
+  }
+
+  // Register an async DBus method handler for |method_name| as base::Callback.
+  template<typename Response, typename... Args>
+  inline void AddMethodHandlerWithMessage(
+      const std::string& method_name,
+      const base::Callback<void(std::unique_ptr<Response>, dbus::Message*,
+                                Args...)>& handler) {
+    static_assert(std::is_base_of<DBusMethodResponseBase, Response>::value,
+                  "Response must be DBusMethodResponse<T...>");
+    Handler<DBusInterfaceMethodHandlerWithMessage<Response, Args...>>::Add(
+        this, method_name, handler);
+  }
+
+  // Register an async D-Bus method handler for |method_name| as a static
+  // function.
+  template<typename Response, typename... Args>
+  inline void AddMethodHandlerWithMessage(
+      const std::string& method_name,
+      void (*handler)(std::unique_ptr<Response>, dbus::Message*, Args...)) {
+    static_assert(std::is_base_of<DBusMethodResponseBase, Response>::value,
+                  "Response must be DBusMethodResponse<T...>");
+    Handler<DBusInterfaceMethodHandlerWithMessage<Response, Args...>>::Add(
+        this, method_name, base::Bind(handler));
+  }
+
+  // Register an async D-Bus method handler for |method_name| as a class member
+  // function.
+  template<typename Response,
+           typename Instance,
+           typename Class,
+           typename... Args>
+  inline void AddMethodHandlerWithMessage(
+      const std::string& method_name,
+      Instance instance,
+      void(Class::*handler)(std::unique_ptr<Response>,
+                            dbus::Message*, Args...)) {
+    static_assert(std::is_base_of<DBusMethodResponseBase, Response>::value,
+                  "Response must be DBusMethodResponse<T...>");
+    Handler<DBusInterfaceMethodHandlerWithMessage<Response, Args...>>::Add(
+        this, method_name, base::Bind(handler, instance));
+  }
+
+  // Same as above but for const-method of a class.
+  template<typename Response,
+           typename Instance,
+           typename Class,
+           typename... Args>
+  inline void AddMethodHandlerWithMessage(
+      const std::string& method_name,
+      Instance instance,
+      void(Class::*handler)(std::unique_ptr<Response>, dbus::Message*,
+                            Args...) const) {
+    static_assert(std::is_base_of<DBusMethodResponseBase, Response>::value,
+                  "Response must be DBusMethodResponse<T...>");
+    Handler<DBusInterfaceMethodHandlerWithMessage<Response, Args...>>::Add(
+        this, method_name, base::Bind(handler, instance));
+  }
+
+  // Register a raw D-Bus method handler for |method_name| as base::Callback.
+  inline void AddRawMethodHandler(
+      const std::string& method_name,
+      const base::Callback<void(dbus::MethodCall*, ResponseSender)>& handler) {
+    Handler<RawDBusInterfaceMethodHandler>::Add(this, method_name, handler);
+  }
+
+  // Register a raw D-Bus method handler for |method_name| as a class member
+  // function.
+  template<typename Instance, typename Class>
+  inline void AddRawMethodHandler(
+      const std::string& method_name,
+      Instance instance,
+      void(Class::*handler)(dbus::MethodCall*, ResponseSender)) {
+    Handler<RawDBusInterfaceMethodHandler>::Add(
+        this, method_name, base::Bind(handler, instance));
+  }
+
+  // Register a D-Bus property.
+  void AddProperty(const std::string& property_name,
+                   ExportedPropertyBase* prop_base);
+
+  // Registers a D-Bus signal that has a specified number and types (|Args|) of
+  // arguments. Returns a weak pointer to the DBusSignal object which can be
+  // used to send the signal on this interface when needed:
+  /*
+    DBusInterface* itf = dbus_object->AddOrGetInterface("Interface");
+    auto signal = itf->RegisterSignal<int, bool>("MySignal");
+    ...
+    // Send the Interface.MySig(12, true) signal.
+    if (signal.lock()->Send(12, true)) { ... }
+  */
+  // Or if the signal signature is long or complex, you can alias the
+  // DBusSignal<Args...> signal type and use RegisterSignalOfType method
+  // instead:
+  /*
+    DBusInterface* itf = dbus_object->AddOrGetInterface("Interface");
+    using MySignal = DBusSignal<int, bool>;
+    auto signal = itf->RegisterSignalOfType<MySignal>("MySignal");
+    ...
+    // Send the Interface.MySig(12, true) signal.
+    if (signal.lock()->Send(12, true)) { ... }
+  */
+  // If the signal with the given name was already registered, the existing
+  // copy of the signal proxy object is returned as long as the method signature
+  // of the original signal matches the current call. If it doesn't, the method
+  // aborts.
+
+  // RegisterSignalOfType can be used to create a signal if the type of the
+  // complete DBusSignal<Args...> class which is pre-defined/aliased earlier.
+  template<typename DBusSignalType>
+  inline std::weak_ptr<DBusSignalType> RegisterSignalOfType(
+      const std::string& signal_name) {
+    auto signal = std::make_shared<DBusSignalType>(
+        dbus_object_, interface_name_, signal_name);
+    AddSignalImpl(signal_name, signal);
+    return signal;
+  }
+
+  // For simple signal arguments, you can specify their types directly in
+  // RegisterSignal<t1, t2, ...>():
+  //  auto signal = itf->RegisterSignal<int>("SignalName");
+  // This will create a callback signal object that expects one int argument.
+  template<typename... Args>
+  inline std::weak_ptr<DBusSignal<Args...>> RegisterSignal(
+      const std::string& signal_name) {
+    return RegisterSignalOfType<DBusSignal<Args...>>(signal_name);
+  }
+
+ private:
+  // Helper to create an instance of DBusInterfaceMethodHandlerInterface-derived
+  // handler and add it to the method handler map of the interface.
+  // This makes the actual AddXXXMethodHandler() methods very light-weight and
+  // easier to provide different overloads for various method handler kinds.
+  // Using struct here to allow partial specialization on HandlerType while
+  // letting the compiler to deduce the type of the callback without explicitly
+  // specifying it.
+  template<typename HandlerType>
+  struct Handler {
+    template<typename CallbackType>
+    inline static void Add(DBusInterface* self,
+                           const std::string& method_name,
+                           const CallbackType& callback) {
+      std::unique_ptr<DBusInterfaceMethodHandlerInterface> sync_method_handler(
+          new HandlerType(callback));
+      self->AddHandlerImpl(method_name, std::move(sync_method_handler));
+    }
+  };
+  // A generic D-Bus method handler for the interface. It extracts the method
+  // name from |method_call|, looks up a registered handler from |handlers_|
+  // map and dispatched the call to that handler.
+  void HandleMethodCall(dbus::MethodCall* method_call, ResponseSender sender);
+  // Helper to add a handler for method |method_name| to the |handlers_| map.
+  // Not marked BRILLO_PRIVATE because it needs to be called by the inline
+  // template functions AddMethodHandler(...)
+  void AddHandlerImpl(
+      const std::string& method_name,
+      std::unique_ptr<DBusInterfaceMethodHandlerInterface> handler);
+  // Helper to add a signal object to the |signals_| map.
+  // Not marked BRILLO_PRIVATE because it needs to be called by the inline
+  // template function RegisterSignalOfType(...)
+  void AddSignalImpl(const std::string& signal_name,
+                     const std::shared_ptr<DBusSignalBase>& signal);
+  // Exports all the methods and properties of this interface and claims the
+  // D-Bus interface.
+  // object_manager - ExportedObjectManager instance that notifies D-Bus
+  //                  listeners of a new interface being claimed.
+  // exported_object - instance of D-Bus object the interface is being added to.
+  // object_path - D-Bus object path for the object instance.
+  // interface_name - name of interface being registered.
+  // completion_callback - a callback to be called when the asynchronous
+  //                       registration operation is completed.
+  BRILLO_PRIVATE void ExportAsync(
+      ExportedObjectManager* object_manager,
+      dbus::Bus* bus,
+      dbus::ExportedObject* exported_object,
+      const dbus::ObjectPath& object_path,
+      const AsyncEventSequencer::CompletionAction& completion_callback);
+  // Exports all the methods and properties of this interface and claims the
+  // D-Bus interface synchronously.
+  // object_manager - ExportedObjectManager instance that notifies D-Bus
+  //                  listeners of a new interface being claimed.
+  // exported_object - instance of D-Bus object the interface is being added to.
+  // object_path - D-Bus object path for the object instance.
+  // interface_name - name of interface being registered.
+  BRILLO_PRIVATE void ExportAndBlock(
+      ExportedObjectManager* object_manager,
+      dbus::Bus* bus,
+      dbus::ExportedObject* exported_object,
+      const dbus::ObjectPath& object_path);
+
+  BRILLO_PRIVATE void ClaimInterface(
+      base::WeakPtr<ExportedObjectManager> object_manager,
+      const dbus::ObjectPath& object_path,
+      const ExportedPropertySet::PropertyWriter& writer,
+      bool all_succeeded);
+
+  // Method registration map.
+  std::map<std::string, std::unique_ptr<DBusInterfaceMethodHandlerInterface>>
+      handlers_;
+  // Signal registration map.
+  std::map<std::string, std::shared_ptr<DBusSignalBase>> signals_;
+
+  friend class DBusObject;
+  friend class DBusInterfaceTestHelper;
+  DBusObject* dbus_object_;
+  std::string interface_name_;
+  base::ScopedClosureRunner release_interface_cb_;
+
+  base::WeakPtrFactory<DBusInterface> weak_factory_{this};
+  DISALLOW_COPY_AND_ASSIGN(DBusInterface);
+};
+
+// A D-Bus object implementation class. Manages the interfaces implemented
+// by this object.
+class BRILLO_EXPORT DBusObject {
+ public:
+  // object_manager - ExportedObjectManager instance that notifies D-Bus
+  //                  listeners of a new interface being claimed and property
+  //                  changes on those interfaces.
+  // object_path - D-Bus object path for the object instance.
+  DBusObject(ExportedObjectManager* object_manager,
+             const scoped_refptr<dbus::Bus>& bus,
+             const dbus::ObjectPath& object_path);
+  virtual ~DBusObject();
+
+  // Returns an proxy handler for the interface |interface_name|. If the
+  // interface proxy does not exist yet, it will be automatically created.
+  DBusInterface* AddOrGetInterface(const std::string& interface_name);
+
+  // Finds an interface with the given name. Returns nullptr if there is no
+  // interface registered by this name.
+  DBusInterface* FindInterface(const std::string& interface_name) const;
+
+  // Registers the object instance with D-Bus. This is an asynchronous call
+  // that will call |completion_callback| when the object and all of its
+  // interfaces are registered.
+  virtual void RegisterAsync(
+      const AsyncEventSequencer::CompletionAction& completion_callback);
+
+  // Registers the object instance with D-Bus. This is call is synchronous and
+  // will block until the object and all of its interfaces are registered.
+  virtual void RegisterAndBlock();
+
+  // Unregister the object instance with D-Bus.  This will unregister the
+  // |exported_object_| and its path from the bus.  The destruction of
+  // |exported_object_| will be deferred in an async task posted by the bus.
+  // It is guarantee that upon return from this call a new DBusObject with the
+  // same object path can be created/registered.
+  virtual void UnregisterAsync();
+
+  // Returns the ExportedObjectManager proxy, if any. If DBusObject has been
+  // constructed without an object manager, this method returns an empty
+  // smart pointer (containing nullptr).
+  const base::WeakPtr<ExportedObjectManager>& GetObjectManager() const {
+    return object_manager_;
+  }
+
+  // Sends a signal from the exported D-Bus object.
+  bool SendSignal(dbus::Signal* signal);
+
+  // Returns the reference to dbus::Bus this object is associated with.
+  scoped_refptr<dbus::Bus> GetBus() { return bus_; }
+
+ private:
+  // A map of all the interfaces added to this object.
+  std::map<std::string, std::unique_ptr<DBusInterface>> interfaces_;
+  // Exported property set for properties registered with the interfaces
+  // implemented by this D-Bus object.
+  ExportedPropertySet property_set_;
+  // Delegate object implementing org.freedesktop.DBus.ObjectManager interface.
+  base::WeakPtr<ExportedObjectManager> object_manager_;
+  // D-Bus bus object.
+  scoped_refptr<dbus::Bus> bus_;
+  // D-Bus object path for this object.
+  dbus::ObjectPath object_path_;
+  // D-Bus object instance once this object is successfully exported.
+  dbus::ExportedObject* exported_object_ = nullptr;  // weak; owned by |bus_|.
+
+  friend class DBusInterface;
+  DISALLOW_COPY_AND_ASSIGN(DBusObject);
+};
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_H_
diff --git a/libbrillo/brillo/dbus/dbus_object_internal_impl.h b/libbrillo/brillo/dbus/dbus_object_internal_impl.h
new file mode 100644
index 0000000..3c5e8d7
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_object_internal_impl.h
@@ -0,0 +1,363 @@
+// Copyright 2014 The Chromium OS 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 file provides internal implementation details of dispatching D-Bus
+// method calls to a D-Bus object methods by reading the expected parameter
+// values from D-Bus message buffer then invoking a native C++ callback with
+// those parameters passed in. If the callback returns a value, that value is
+// sent back to the caller of D-Bus method via the response message.
+
+// This is achieved by redirecting the parsing of parameter values from D-Bus
+// message buffer to DBusParamReader helper class.
+// DBusParamReader de-serializes the parameter values from the D-Bus message
+// and calls the provided native C++ callback with those arguments.
+// However it expects the callback with a simple signature like this:
+//    void callback(Args...);
+// The method handlers for DBusObject, on the other hand, have one of the
+// following signatures:
+//    void handler(Args...);
+//    ReturnType handler(Args...);
+//    bool handler(ErrorPtr* error, Args...);
+//    void handler(std::unique_ptr<DBusMethodResponse<T1, T2,...>>, Args...);
+//
+// To make this all work, we craft a simple callback suitable for
+// DBusParamReader using a lambda in DBusInvoker::Invoke() and redirect the call
+// to the appropriate method handler using additional data captured by the
+// lambda object.
+
+#ifndef LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_
+#define LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_
+
+#include <memory>
+#include <string>
+#include <type_traits>
+
+#include <brillo/dbus/data_serialization.h>
+#include <brillo/dbus/dbus_method_response.h>
+#include <brillo/dbus/dbus_param_reader.h>
+#include <brillo/dbus/dbus_param_writer.h>
+#include <brillo/dbus/utils.h>
+#include <brillo/errors/error.h>
+#include <dbus/message.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+// This is an abstract base class to allow dispatching a native C++ callback
+// method when a corresponding D-Bus method is called.
+class DBusInterfaceMethodHandlerInterface {
+ public:
+  virtual ~DBusInterfaceMethodHandlerInterface() = default;
+
+  // Returns true if the method has been handled synchronously (whether or not
+  // a success or error response message had been sent).
+  virtual void HandleMethod(dbus::MethodCall* method_call,
+                            ResponseSender sender) = 0;
+};
+
+// This is a special implementation of DBusInterfaceMethodHandlerInterface for
+// extremely simple synchronous method handlers that cannot possibly fail
+// (that is, they do not send an error response).
+// The handler is expected to take an arbitrary number of arguments of type
+// |Args...| which can contain both inputs (passed in by value or constant
+// reference) and outputs (passed in as pointers)...
+// It may also return a single value of type R (or could be a void function if
+// no return value is to be sent to the caller). If the handler has a return
+// value, then it cannot have any output parameters in its parameter list.
+// The signature of the callback handler is expected to be:
+//    R(Args...)
+template<typename R, typename... Args>
+class SimpleDBusInterfaceMethodHandler
+    : public DBusInterfaceMethodHandlerInterface {
+ public:
+  // A constructor that takes a |handler| to be called when HandleMethod()
+  // virtual function is invoked.
+  explicit SimpleDBusInterfaceMethodHandler(
+      const base::Callback<R(Args...)>& handler) : handler_(handler) {}
+
+  void HandleMethod(dbus::MethodCall* method_call,
+                    ResponseSender sender) override {
+    DBusMethodResponse<R> method_response(method_call, sender);
+    auto invoke_callback = [this, &method_response](const Args&... args) {
+      method_response.Return(handler_.Run(args...));
+    };
+
+    ErrorPtr param_reader_error;
+    dbus::MessageReader reader(method_call);
+    // The handler is expected a return value, don't allow output parameters.
+    if (!DBusParamReader<false, Args...>::Invoke(
+            invoke_callback, &reader, &param_reader_error)) {
+      // Error parsing method arguments.
+      method_response.ReplyWithError(param_reader_error.get());
+    }
+  }
+
+ private:
+  // C++ callback to be called when a DBus method is dispatched.
+  base::Callback<R(Args...)> handler_;
+  DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandler);
+};
+
+// Specialization of SimpleDBusInterfaceMethodHandlerInterface for
+// R=void (methods with no return values).
+template<typename... Args>
+class SimpleDBusInterfaceMethodHandler<void, Args...>
+    : public DBusInterfaceMethodHandlerInterface {
+ public:
+  // A constructor that takes a |handler| to be called when HandleMethod()
+  // virtual function is invoked.
+  explicit SimpleDBusInterfaceMethodHandler(
+      const base::Callback<void(Args...)>& handler) : handler_(handler) {}
+
+  void HandleMethod(dbus::MethodCall* method_call,
+                    ResponseSender sender) override {
+    DBusMethodResponseBase method_response(method_call, sender);
+    auto invoke_callback = [this, &method_response](const Args&... args) {
+      handler_.Run(args...);
+      auto response = method_response.CreateCustomResponse();
+      dbus::MessageWriter writer(response.get());
+      DBusParamWriter::AppendDBusOutParams(&writer, args...);
+      method_response.SendRawResponse(std::move(response));
+    };
+
+    ErrorPtr param_reader_error;
+    dbus::MessageReader reader(method_call);
+    if (!DBusParamReader<true, Args...>::Invoke(
+            invoke_callback, &reader, &param_reader_error)) {
+      // Error parsing method arguments.
+      method_response.ReplyWithError(param_reader_error.get());
+    }
+  }
+
+ private:
+  // C++ callback to be called when a DBus method is dispatched.
+  base::Callback<void(Args...)> handler_;
+  DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandler);
+};
+
+// An implementation of DBusInterfaceMethodHandlerInterface for simple
+// synchronous method handlers that may fail and return an error response
+// message.
+// The handler is expected to take an arbitrary number of arguments of type
+// |Args...| which can contain both inputs (passed in by value or constant
+// reference) and outputs (passed in as pointers)...
+// In case of an error, the handler must return false and set the error details
+// into the |error| object provided.
+// The signature of the callback handler is expected to be:
+//    bool(ErrorPtr*, Args...)
+template<typename... Args>
+class SimpleDBusInterfaceMethodHandlerWithError
+    : public DBusInterfaceMethodHandlerInterface {
+ public:
+  // A constructor that takes a |handler| to be called when HandleMethod()
+  // virtual function is invoked.
+  explicit SimpleDBusInterfaceMethodHandlerWithError(
+      const base::Callback<bool(ErrorPtr*, Args...)>& handler)
+      : handler_(handler) {}
+
+  void HandleMethod(dbus::MethodCall* method_call,
+                    ResponseSender sender) override {
+    DBusMethodResponseBase method_response(method_call, sender);
+    auto invoke_callback = [this, &method_response](const Args&... args) {
+      ErrorPtr error;
+      if (!handler_.Run(&error, args...)) {
+        method_response.ReplyWithError(error.get());
+      } else {
+        auto response = method_response.CreateCustomResponse();
+        dbus::MessageWriter writer(response.get());
+        DBusParamWriter::AppendDBusOutParams(&writer, args...);
+        method_response.SendRawResponse(std::move(response));
+      }
+    };
+
+    ErrorPtr param_reader_error;
+    dbus::MessageReader reader(method_call);
+    if (!DBusParamReader<true, Args...>::Invoke(
+            invoke_callback, &reader, &param_reader_error)) {
+      // Error parsing method arguments.
+      method_response.ReplyWithError(param_reader_error.get());
+    }
+  }
+
+ private:
+  // C++ callback to be called when a DBus method is dispatched.
+  base::Callback<bool(ErrorPtr*, Args...)> handler_;
+  DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandlerWithError);
+};
+
+// An implementation of SimpleDBusInterfaceMethodHandlerWithErrorAndMessage
+// which is almost identical to SimpleDBusInterfaceMethodHandlerWithError with
+// the exception that the callback takes an additional parameter - raw D-Bus
+// message used to invoke the method handler.
+// The handler is expected to take an arbitrary number of arguments of type
+// |Args...| which can contain both inputs (passed in by value or constant
+// reference) and outputs (passed in as pointers)...
+// In case of an error, the handler must return false and set the error details
+// into the |error| object provided.
+// The signature of the callback handler is expected to be:
+//    bool(ErrorPtr*, dbus::Message*, Args...)
+template<typename... Args>
+class SimpleDBusInterfaceMethodHandlerWithErrorAndMessage
+    : public DBusInterfaceMethodHandlerInterface {
+ public:
+  // A constructor that takes a |handler| to be called when HandleMethod()
+  // virtual function is invoked.
+  explicit SimpleDBusInterfaceMethodHandlerWithErrorAndMessage(
+      const base::Callback<bool(ErrorPtr*, dbus::Message*, Args...)>& handler)
+      : handler_(handler) {}
+
+  void HandleMethod(dbus::MethodCall* method_call,
+                    ResponseSender sender) override {
+    DBusMethodResponseBase method_response(method_call, sender);
+    auto invoke_callback =
+        [this, method_call, &method_response](const Args&... args) {
+      ErrorPtr error;
+      if (!handler_.Run(&error, method_call, args...)) {
+        method_response.ReplyWithError(error.get());
+      } else {
+        auto response = method_response.CreateCustomResponse();
+        dbus::MessageWriter writer(response.get());
+        DBusParamWriter::AppendDBusOutParams(&writer, args...);
+        method_response.SendRawResponse(std::move(response));
+      }
+    };
+
+    ErrorPtr param_reader_error;
+    dbus::MessageReader reader(method_call);
+    if (!DBusParamReader<true, Args...>::Invoke(
+            invoke_callback, &reader, &param_reader_error)) {
+      // Error parsing method arguments.
+      method_response.ReplyWithError(param_reader_error.get());
+    }
+  }
+
+ private:
+  // C++ callback to be called when a DBus method is dispatched.
+  base::Callback<bool(ErrorPtr*, dbus::Message*, Args...)> handler_;
+  DISALLOW_COPY_AND_ASSIGN(SimpleDBusInterfaceMethodHandlerWithErrorAndMessage);
+};
+
+// An implementation of DBusInterfaceMethodHandlerInterface for more generic
+// (and possibly asynchronous) method handlers. The handler is expected
+// to take an arbitrary number of input arguments of type |Args...| and send
+// the method call response (including a possible error response) using
+// the provided DBusMethodResponse object.
+// The signature of the callback handler is expected to be:
+//    void(std::unique_ptr<DBusMethodResponse<RetTypes...>, Args...)
+template<typename Response, typename... Args>
+class DBusInterfaceMethodHandler : public DBusInterfaceMethodHandlerInterface {
+ public:
+  // A constructor that takes a |handler| to be called when HandleMethod()
+  // virtual function is invoked.
+  explicit DBusInterfaceMethodHandler(
+      const base::Callback<void(std::unique_ptr<Response>, Args...)>& handler)
+      : handler_(handler) {}
+
+  // This method forwards the call to |handler_| after extracting the required
+  // arguments from the DBus message buffer specified in |method_call|.
+  // The output parameters of |handler_| (if any) are sent back to the called.
+  void HandleMethod(dbus::MethodCall* method_call,
+                    ResponseSender sender) override {
+    auto invoke_callback = [this, method_call, &sender](const Args&... args) {
+      std::unique_ptr<Response> response(new Response(method_call, sender));
+      handler_.Run(std::move(response), args...);
+    };
+
+    ErrorPtr param_reader_error;
+    dbus::MessageReader reader(method_call);
+    if (!DBusParamReader<false, Args...>::Invoke(
+            invoke_callback, &reader, &param_reader_error)) {
+      // Error parsing method arguments.
+      DBusMethodResponseBase method_response(method_call, sender);
+      method_response.ReplyWithError(param_reader_error.get());
+    }
+  }
+
+ private:
+  // C++ callback to be called when a D-Bus method is dispatched.
+  base::Callback<void(std::unique_ptr<Response>, Args...)> handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(DBusInterfaceMethodHandler);
+};
+
+// An implementation of DBusInterfaceMethodHandlerWithMessage which is almost
+// identical to AddSimpleMethodHandlerWithError with the exception that the
+// callback takes an additional parameter - raw D-Bus message.
+// The handler is expected to take an arbitrary number of input arguments of
+// type |Args...| and send the method call response (including a possible error
+// response) using the provided DBusMethodResponse object.
+// The signature of the callback handler is expected to be:
+//    void(std::unique_ptr<DBusMethodResponse<RetTypes...>, dbus::Message*,
+//         Args...);
+template<typename Response, typename... Args>
+class DBusInterfaceMethodHandlerWithMessage
+    : public DBusInterfaceMethodHandlerInterface {
+ public:
+  // A constructor that takes a |handler| to be called when HandleMethod()
+  // virtual function is invoked.
+  explicit DBusInterfaceMethodHandlerWithMessage(
+      const base::Callback<void(std::unique_ptr<Response>, dbus::Message*,
+                                Args...)>& handler)
+      : handler_(handler) {}
+
+  // This method forwards the call to |handler_| after extracting the required
+  // arguments from the DBus message buffer specified in |method_call|.
+  // The output parameters of |handler_| (if any) are sent back to the called.
+  void HandleMethod(dbus::MethodCall* method_call,
+                    ResponseSender sender) override {
+    auto invoke_callback = [this, method_call, &sender](const Args&... args) {
+      std::unique_ptr<Response> response(new Response(method_call, sender));
+      handler_.Run(std::move(response), method_call, args...);
+    };
+
+    ErrorPtr param_reader_error;
+    dbus::MessageReader reader(method_call);
+    if (!DBusParamReader<false, Args...>::Invoke(
+            invoke_callback, &reader, &param_reader_error)) {
+      // Error parsing method arguments.
+      DBusMethodResponseBase method_response(method_call, sender);
+      method_response.ReplyWithError(param_reader_error.get());
+    }
+  }
+
+ private:
+  // C++ callback to be called when a D-Bus method is dispatched.
+  base::Callback<void(std::unique_ptr<Response>,
+                      dbus::Message*, Args...)> handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(DBusInterfaceMethodHandlerWithMessage);
+};
+
+// An implementation of DBusInterfaceMethodHandlerInterface that has custom
+// processing of both input and output parameters. This class is used by
+// DBusObject::AddRawMethodHandler and expects the callback to be of the
+// following signature:
+//    void(dbus::MethodCall*, ResponseSender)
+// It will be up to the callback to parse the input parameters from the
+// message buffer and construct the D-Bus Response object.
+class RawDBusInterfaceMethodHandler
+    : public DBusInterfaceMethodHandlerInterface {
+ public:
+  // A constructor that takes a |handler| to be called when HandleMethod()
+  // virtual function is invoked.
+  explicit RawDBusInterfaceMethodHandler(
+      const base::Callback<void(dbus::MethodCall*, ResponseSender)>& handler)
+      : handler_(handler) {}
+
+  void HandleMethod(dbus::MethodCall* method_call,
+                    ResponseSender sender) override {
+    handler_.Run(method_call, sender);
+  }
+
+ private:
+  // C++ callback to be called when a D-Bus method is dispatched.
+  base::Callback<void(dbus::MethodCall*, ResponseSender)> handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(RawDBusInterfaceMethodHandler);
+};
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_INTERNAL_IMPL_H_
diff --git a/libbrillo/brillo/dbus/dbus_object_test_helpers.h b/libbrillo/brillo/dbus/dbus_object_test_helpers.h
new file mode 100644
index 0000000..59c4a06
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_object_test_helpers.h
@@ -0,0 +1,143 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Helper utilities to simplify testing of D-Bus object implementations.
+// Since the method handlers could now be asynchronous, they use callbacks to
+// provide method return values. This makes it really difficult to invoke
+// such handlers in unit tests (even if they are actually synchronous but
+// still use DBusMethodResponse to send back the method results).
+// This file provide testing-only helpers to make calling D-Bus method handlers
+// easier.
+#ifndef LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_TEST_HELPERS_H_
+#define LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_TEST_HELPERS_H_
+
+#include <base/bind.h>
+#include <base/memory/weak_ptr.h>
+#include <brillo/dbus/dbus_method_invoker.h>
+#include <brillo/dbus/dbus_object.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+// Helper friend class to call DBusInterface::HandleMethodCall() since it is
+// a private method of the class and we don't want to make it public.
+class DBusInterfaceTestHelper final {
+ public:
+  static void HandleMethodCall(DBusInterface* itf,
+                               dbus::MethodCall* method_call,
+                               ResponseSender sender) {
+    itf->HandleMethodCall(method_call, sender);
+  }
+};
+
+namespace testing {
+
+// This is a simple class that has weak pointer semantics and holds an
+// instance of D-Bus method call response message. We use this in tests
+// to get the response in case the handler processes a method call request
+// synchronously. Otherwise the ResponseHolder object will be destroyed and
+// ResponseHolder::ReceiveResponse() will not be called since we bind the
+// callback to the object instance via a weak pointer.
+struct ResponseHolder final : public base::SupportsWeakPtr<ResponseHolder> {
+  void ReceiveResponse(std::unique_ptr<dbus::Response> response) {
+    response_ = std::move(response);
+  }
+
+  std::unique_ptr<dbus::Response> response_;
+};
+
+// Dispatches a D-Bus method call to the corresponding handler.
+// Used mostly for testing purposes. This method is inlined so that it is
+// not included in the shipping code of libbrillo, and included at the
+// call sites. Returns a response from the method handler or nullptr if the
+// method hasn't provided the response message immediately
+// (i.e. it is asynchronous).
+inline std::unique_ptr<dbus::Response> CallMethod(
+    const DBusObject& object, dbus::MethodCall* method_call) {
+  DBusInterface* itf = object.FindInterface(method_call->GetInterface());
+  std::unique_ptr<dbus::Response> response;
+  if (!itf) {
+    response = CreateDBusErrorResponse(
+        method_call,
+        DBUS_ERROR_UNKNOWN_INTERFACE,
+        "Interface you invoked a method on isn't known by the object.");
+  } else {
+    ResponseHolder response_holder;
+    DBusInterfaceTestHelper::HandleMethodCall(
+      itf, method_call, base::Bind(&ResponseHolder::ReceiveResponse,
+                                   response_holder.AsWeakPtr()));
+    response = std::move(response_holder.response_);
+  }
+  return response;
+}
+
+// MethodHandlerInvoker is similar to CallMethod() function above, except
+// it allows the callers to invoke the method handlers directly bypassing
+// the DBusObject/DBusInterface infrastructure.
+// This works only on synchronous methods though. The handler must reply
+// before the handler exits.
+template<typename RetType>
+struct MethodHandlerInvoker {
+  // MethodHandlerInvoker<RetType>::Call() calls a member |method| of a class
+  // |instance| and passes the |args| to it. The method's return value provided
+  // via handler's DBusMethodResponse is then extracted and returned.
+  // If the method handler returns an error, the error information is passed
+  // to the caller via the |error| object (and the method returns a default
+  // value of type RetType as a placeholder).
+  // If the method handler asynchronous and did not provide a reply (success or
+  // error) before the handler exits, this method aborts with a CHECK().
+  template<class Class, typename... Params, typename... Args>
+  static RetType Call(
+      ErrorPtr* error,
+      Class* instance,
+      void(Class::*method)(std::unique_ptr<DBusMethodResponse<RetType>>,
+                           Params...),
+      Args... args) {
+    ResponseHolder response_holder;
+    dbus::MethodCall method_call("test.interface", "TestMethod");
+    method_call.SetSerial(123);
+    std::unique_ptr<DBusMethodResponse<RetType>> method_response{
+      new DBusMethodResponse<RetType>(
+        &method_call, base::Bind(&ResponseHolder::ReceiveResponse,
+                                 response_holder.AsWeakPtr()))
+    };
+    (instance->*method)(std::move(method_response), args...);
+    CHECK(response_holder.response_.get())
+        << "No response received. Asynchronous methods are not supported.";
+    RetType ret_val;
+    ExtractMethodCallResults(response_holder.response_.get(), error, &ret_val);
+    return ret_val;
+  }
+};
+
+// Specialization of MethodHandlerInvoker for methods that do not return
+// values (void methods).
+template<>
+struct MethodHandlerInvoker<void> {
+  template<class Class, typename... Params, typename... Args>
+  static void Call(
+      ErrorPtr* error,
+      Class* instance,
+      void(Class::*method)(std::unique_ptr<DBusMethodResponse<>>, Params...),
+      Args... args) {
+    ResponseHolder response_holder;
+    dbus::MethodCall method_call("test.interface", "TestMethod");
+    method_call.SetSerial(123);
+    std::unique_ptr<DBusMethodResponse<>> method_response{
+      new DBusMethodResponse<>(&method_call,
+                               base::Bind(&ResponseHolder::ReceiveResponse,
+                                          response_holder.AsWeakPtr()))
+    };
+    (instance->*method)(std::move(method_response), args...);
+    CHECK(response_holder.response_.get())
+        << "No response received. Asynchronous methods are not supported.";
+    ExtractMethodCallResults(response_holder.response_.get(), error);
+  }
+};
+
+}  // namespace testing
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_OBJECT_TEST_HELPERS_H_
diff --git a/libbrillo/brillo/dbus/dbus_object_unittest.cc b/libbrillo/brillo/dbus/dbus_object_unittest.cc
new file mode 100644
index 0000000..eaec3d8
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_object_unittest.cc
@@ -0,0 +1,392 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/dbus_object.h>
+
+#include <memory>
+
+#include <base/bind.h>
+#include <brillo/dbus/dbus_object_test_helpers.h>
+#include <brillo/dbus/mock_exported_object_manager.h>
+#include <dbus/message.h>
+#include <dbus/property.h>
+#include <dbus/object_path.h>
+#include <dbus/mock_bus.h>
+#include <dbus/mock_exported_object.h>
+
+using ::testing::AnyNumber;
+using ::testing::Return;
+using ::testing::Invoke;
+using ::testing::Mock;
+using ::testing::_;
+
+namespace brillo {
+namespace dbus_utils {
+
+namespace {
+
+const char kMethodsExportedOn[] = "/export";
+
+const char kTestInterface1[] = "org.chromium.Test.MathInterface";
+const char kTestMethod_Add[] = "Add";
+const char kTestMethod_Negate[] = "Negate";
+const char kTestMethod_Positive[] = "Positive";
+const char kTestMethod_AddSubtract[] = "AddSubtract";
+
+const char kTestInterface2[] = "org.chromium.Test.StringInterface";
+const char kTestMethod_StrLen[] = "StrLen";
+const char kTestMethod_CheckNonEmpty[] = "CheckNonEmpty";
+
+const char kTestInterface3[] = "org.chromium.Test.NoOpInterface";
+const char kTestMethod_NoOp[] = "NoOp";
+const char kTestMethod_WithMessage[] = "TestWithMessage";
+const char kTestMethod_WithMessageAsync[] = "TestWithMessageAsync";
+
+struct Calc {
+  int Add(int x, int y) { return x + y; }
+  int Negate(int x) { return -x; }
+  void Positive(std::unique_ptr<DBusMethodResponse<double>> response,
+                double x) {
+    if (x >= 0.0) {
+      response->Return(x);
+      return;
+    }
+    ErrorPtr error;
+    Error::AddTo(&error, FROM_HERE, "test", "not_positive",
+                 "Negative value passed in");
+    response->ReplyWithError(error.get());
+  }
+  void AddSubtract(int x, int y, int* sum, int* diff) {
+    *sum = x + y;
+    *diff = x - y;
+  }
+};
+
+int StrLen(const std::string& str) {
+  return str.size();
+}
+
+bool CheckNonEmpty(ErrorPtr* error, const std::string& str) {
+  if (!str.empty())
+    return true;
+  Error::AddTo(error, FROM_HERE, "test", "string_empty", "String is empty");
+  return false;
+}
+
+void NoOp() {}
+
+bool TestWithMessage(ErrorPtr* /* error */,
+                     dbus::Message* message,
+                     std::string* str) {
+  *str = message->GetSender();
+  return true;
+}
+
+void TestWithMessageAsync(
+    std::unique_ptr<DBusMethodResponse<std::string>> response,
+    dbus::Message* message) {
+  response->Return(message->GetSender());
+}
+
+}  // namespace
+
+class DBusObjectTest : public ::testing::Test {
+ public:
+  virtual void SetUp() {
+    dbus::Bus::Options options;
+    options.bus_type = dbus::Bus::SYSTEM;
+    bus_ = new dbus::MockBus(options);
+    // By default, don't worry about threading assertions.
+    EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
+    EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
+    // Use a mock exported object.
+    const dbus::ObjectPath kMethodsExportedOnPath{
+        std::string{kMethodsExportedOn}};
+    mock_exported_object_ =
+        new dbus::MockExportedObject(bus_.get(), kMethodsExportedOnPath);
+    EXPECT_CALL(*bus_, GetExportedObject(kMethodsExportedOnPath))
+        .Times(AnyNumber())
+        .WillRepeatedly(Return(mock_exported_object_.get()));
+    EXPECT_CALL(*mock_exported_object_, ExportMethod(_, _, _, _))
+        .Times(AnyNumber());
+    EXPECT_CALL(*mock_exported_object_, Unregister()).Times(1);
+
+    dbus_object_ = std::unique_ptr<DBusObject>(
+        new DBusObject(nullptr, bus_, kMethodsExportedOnPath));
+
+    DBusInterface* itf1 = dbus_object_->AddOrGetInterface(kTestInterface1);
+    itf1->AddSimpleMethodHandler(
+        kTestMethod_Add, base::Unretained(&calc_), &Calc::Add);
+    itf1->AddSimpleMethodHandler(
+        kTestMethod_Negate, base::Unretained(&calc_), &Calc::Negate);
+    itf1->AddMethodHandler(
+        kTestMethod_Positive, base::Unretained(&calc_), &Calc::Positive);
+    itf1->AddSimpleMethodHandler(
+        kTestMethod_AddSubtract, base::Unretained(&calc_), &Calc::AddSubtract);
+    DBusInterface* itf2 = dbus_object_->AddOrGetInterface(kTestInterface2);
+    itf2->AddSimpleMethodHandler(kTestMethod_StrLen, StrLen);
+    itf2->AddSimpleMethodHandlerWithError(kTestMethod_CheckNonEmpty,
+                                          CheckNonEmpty);
+    DBusInterface* itf3 = dbus_object_->AddOrGetInterface(kTestInterface3);
+    base::Callback<void()> noop_callback = base::Bind(NoOp);
+    itf3->AddSimpleMethodHandler(kTestMethod_NoOp, noop_callback);
+    itf3->AddSimpleMethodHandlerWithErrorAndMessage(
+        kTestMethod_WithMessage, base::Bind(&TestWithMessage));
+    itf3->AddMethodHandlerWithMessage(kTestMethod_WithMessageAsync,
+                                      base::Bind(&TestWithMessageAsync));
+
+    dbus_object_->RegisterAsync(
+        AsyncEventSequencer::GetDefaultCompletionAction());
+  }
+
+  void ExpectError(dbus::Response* response, const std::string& expected_code) {
+    EXPECT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+    EXPECT_EQ(expected_code, response->GetErrorName());
+  }
+
+  scoped_refptr<dbus::MockBus> bus_;
+  scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
+  std::unique_ptr<DBusObject> dbus_object_;
+  Calc calc_;
+};
+
+TEST_F(DBusObjectTest, Add) {
+  dbus::MethodCall method_call(kTestInterface1, kTestMethod_Add);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendInt32(2);
+  writer.AppendInt32(3);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  dbus::MessageReader reader(response.get());
+  int result;
+  ASSERT_TRUE(reader.PopInt32(&result));
+  ASSERT_FALSE(reader.HasMoreData());
+  ASSERT_EQ(5, result);
+}
+
+TEST_F(DBusObjectTest, Negate) {
+  dbus::MethodCall method_call(kTestInterface1, kTestMethod_Negate);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendInt32(98765);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  dbus::MessageReader reader(response.get());
+  int result;
+  ASSERT_TRUE(reader.PopInt32(&result));
+  ASSERT_FALSE(reader.HasMoreData());
+  ASSERT_EQ(-98765, result);
+}
+
+TEST_F(DBusObjectTest, PositiveSuccess) {
+  dbus::MethodCall method_call(kTestInterface1, kTestMethod_Positive);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendDouble(17.5);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  dbus::MessageReader reader(response.get());
+  double result;
+  ASSERT_TRUE(reader.PopDouble(&result));
+  ASSERT_FALSE(reader.HasMoreData());
+  ASSERT_DOUBLE_EQ(17.5, result);
+}
+
+TEST_F(DBusObjectTest, PositiveFailure) {
+  dbus::MethodCall method_call(kTestInterface1, kTestMethod_Positive);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendDouble(-23.2);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  ExpectError(response.get(), DBUS_ERROR_FAILED);
+}
+
+TEST_F(DBusObjectTest, AddSubtract) {
+  dbus::MethodCall method_call(kTestInterface1, kTestMethod_AddSubtract);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendInt32(2);
+  writer.AppendInt32(3);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  dbus::MessageReader reader(response.get());
+  int sum = 0, diff = 0;
+  ASSERT_TRUE(reader.PopInt32(&sum));
+  ASSERT_TRUE(reader.PopInt32(&diff));
+  ASSERT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(5, sum);
+  EXPECT_EQ(-1, diff);
+}
+
+TEST_F(DBusObjectTest, StrLen0) {
+  dbus::MethodCall method_call(kTestInterface2, kTestMethod_StrLen);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString("");
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  dbus::MessageReader reader(response.get());
+  int result;
+  ASSERT_TRUE(reader.PopInt32(&result));
+  ASSERT_FALSE(reader.HasMoreData());
+  ASSERT_EQ(0, result);
+}
+
+TEST_F(DBusObjectTest, StrLen4) {
+  dbus::MethodCall method_call(kTestInterface2, kTestMethod_StrLen);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString("test");
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  dbus::MessageReader reader(response.get());
+  int result;
+  ASSERT_TRUE(reader.PopInt32(&result));
+  ASSERT_FALSE(reader.HasMoreData());
+  ASSERT_EQ(4, result);
+}
+
+TEST_F(DBusObjectTest, CheckNonEmpty_Success) {
+  dbus::MethodCall method_call(kTestInterface2, kTestMethod_CheckNonEmpty);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString("test");
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  ASSERT_EQ(dbus::Message::MESSAGE_METHOD_RETURN, response->GetMessageType());
+  dbus::MessageReader reader(response.get());
+  EXPECT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(DBusObjectTest, CheckNonEmpty_Failure) {
+  dbus::MethodCall method_call(kTestInterface2, kTestMethod_CheckNonEmpty);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString("");
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+  ErrorPtr error;
+  ExtractMethodCallResults(response.get(), &error);
+  ASSERT_NE(nullptr, error.get());
+  EXPECT_EQ("test", error->GetDomain());
+  EXPECT_EQ("string_empty", error->GetCode());
+  EXPECT_EQ("String is empty", error->GetMessage());
+}
+
+TEST_F(DBusObjectTest, CheckNonEmpty_MissingParams) {
+  dbus::MethodCall method_call(kTestInterface2, kTestMethod_CheckNonEmpty);
+  method_call.SetSerial(123);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+  dbus::MessageReader reader(response.get());
+  std::string message;
+  ASSERT_TRUE(reader.PopString(&message));
+  EXPECT_EQ(DBUS_ERROR_INVALID_ARGS, response->GetErrorName());
+  EXPECT_EQ("Too few parameters in a method call", message);
+  EXPECT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(DBusObjectTest, NoOp) {
+  dbus::MethodCall method_call(kTestInterface3, kTestMethod_NoOp);
+  method_call.SetSerial(123);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  dbus::MessageReader reader(response.get());
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(DBusObjectTest, TestWithMessage) {
+  const std::string sender{":1.2345"};
+  dbus::MethodCall method_call(kTestInterface3, kTestMethod_WithMessage);
+  method_call.SetSerial(123);
+  method_call.SetSender(sender);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  dbus::MessageReader reader(response.get());
+  std::string message;
+  ASSERT_TRUE(reader.PopString(&message));
+  ASSERT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(sender, message);
+}
+
+TEST_F(DBusObjectTest, TestWithMessageAsync) {
+  const std::string sender{":6.7890"};
+  dbus::MethodCall method_call(kTestInterface3, kTestMethod_WithMessageAsync);
+  method_call.SetSerial(123);
+  method_call.SetSender(sender);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  dbus::MessageReader reader(response.get());
+  std::string message;
+  ASSERT_TRUE(reader.PopString(&message));
+  ASSERT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(sender, message);
+}
+
+TEST_F(DBusObjectTest, TooFewParams) {
+  dbus::MethodCall method_call(kTestInterface1, kTestMethod_Add);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendInt32(2);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  ExpectError(response.get(), DBUS_ERROR_INVALID_ARGS);
+}
+
+TEST_F(DBusObjectTest, TooManyParams) {
+  dbus::MethodCall method_call(kTestInterface1, kTestMethod_Add);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendInt32(1);
+  writer.AppendInt32(2);
+  writer.AppendInt32(3);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  ExpectError(response.get(), DBUS_ERROR_INVALID_ARGS);
+}
+
+TEST_F(DBusObjectTest, ParamTypeMismatch) {
+  dbus::MethodCall method_call(kTestInterface1, kTestMethod_Add);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendInt32(1);
+  writer.AppendBool(false);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  ExpectError(response.get(), DBUS_ERROR_INVALID_ARGS);
+}
+
+TEST_F(DBusObjectTest, ParamAsVariant) {
+  dbus::MethodCall method_call(kTestInterface1, kTestMethod_Add);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendVariantOfInt32(10);
+  writer.AppendVariantOfInt32(3);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  dbus::MessageReader reader(response.get());
+  int result;
+  ASSERT_TRUE(reader.PopInt32(&result));
+  ASSERT_FALSE(reader.HasMoreData());
+  ASSERT_EQ(13, result);
+}
+
+TEST_F(DBusObjectTest, UnknownMethod) {
+  dbus::MethodCall method_call(kTestInterface2, kTestMethod_Add);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendInt32(1);
+  writer.AppendBool(false);
+  auto response = testing::CallMethod(*dbus_object_, &method_call);
+  ExpectError(response.get(), DBUS_ERROR_UNKNOWN_METHOD);
+}
+
+TEST_F(DBusObjectTest, ShouldReleaseOnlyClaimedInterfaces) {
+  const dbus::ObjectPath kObjectManagerPath{std::string{"/"}};
+  const dbus::ObjectPath kMethodsExportedOnPath{
+      std::string{kMethodsExportedOn}};
+  MockExportedObjectManager mock_object_manager{bus_, kObjectManagerPath};
+  dbus_object_ = std::unique_ptr<DBusObject>(
+      new DBusObject(&mock_object_manager, bus_, kMethodsExportedOnPath));
+  EXPECT_CALL(mock_object_manager, ClaimInterface(_, _, _)).Times(0);
+  EXPECT_CALL(mock_object_manager, ReleaseInterface(_, _)).Times(0);
+  DBusInterface* itf1 = dbus_object_->AddOrGetInterface(kTestInterface1);
+  itf1->AddSimpleMethodHandler(
+      kTestMethod_Add, base::Unretained(&calc_), &Calc::Add);
+  // When we tear down our DBusObject, it should release only interfaces it has
+  // previously claimed.  This prevents a check failing inside the
+  // ExportedObjectManager.  Since no interfaces have finished exporting
+  // handlers, nothing should be released.
+  dbus_object_.reset();
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/dbus_param_reader.h b/libbrillo/brillo/dbus/dbus_param_reader.h
new file mode 100644
index 0000000..228cfb6
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_param_reader.h
@@ -0,0 +1,165 @@
+// Copyright 2014 The Chromium OS 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 file provides generic method to parse function call arguments from
+// D-Bus message buffer and subsequently invokes a provided native C++ callback
+// with the parameter values passed as the callback arguments.
+
+// This functionality is achieved by parsing method arguments one by one,
+// left to right from the C++ callback's type signature, and moving the parsed
+// arguments to the back to the next call to DBusInvoke::Invoke's arguments as
+// const refs.  Each iteration has one fewer template specialization arguments,
+// until there is only the return type remaining and we fall through to either
+// the void or the non-void final specialization.
+
+#ifndef LIBBRILLO_BRILLO_DBUS_DBUS_PARAM_READER_H_
+#define LIBBRILLO_BRILLO_DBUS_DBUS_PARAM_READER_H_
+
+#include <type_traits>
+
+#include <brillo/dbus/data_serialization.h>
+#include <brillo/dbus/utils.h>
+#include <brillo/errors/error.h>
+#include <brillo/errors/error_codes.h>
+#include <dbus/message.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+// A generic DBusParamReader stub class which allows us to specialize on
+// a variable list of expected function parameters later on.
+// This struct in itself is not used. But its concrete template specializations
+// defined below are.
+// |allow_out_params| controls whether DBusParamReader allows the parameter
+// list to contain OUT parameters (pointers).
+template<bool allow_out_params, typename...>
+struct DBusParamReader;
+
+// A generic specialization of DBusParamReader to handle variable function
+// parameters. This specialization pops one parameter off the D-Bus message
+// buffer and calls other specializations of DBusParamReader with fewer
+// parameters to pop the remaining parameters.
+//  CurrentParam  - the type of the current method parameter we are processing.
+//  RestOfParams  - the types of remaining parameters to be processed.
+template<bool allow_out_params, typename CurrentParam, typename... RestOfParams>
+struct DBusParamReader<allow_out_params, CurrentParam, RestOfParams...> {
+  // DBusParamReader::Invoke() is a member function that actually extracts the
+  // current parameter from the message buffer.
+  //  handler     - the C++ callback functor to be called when all the
+  //                parameters are processed.
+  //  method_call - D-Bus method call object we are processing.
+  //  reader      - D-Bus message reader to pop the current argument value from.
+  //  args...     - the callback parameters processed so far.
+  template<typename CallbackType, typename... Args>
+  static bool Invoke(const CallbackType& handler,
+                     dbus::MessageReader* reader,
+                     ErrorPtr* error,
+                     const Args&... args) {
+    return InvokeHelper<CurrentParam, CallbackType, Args...>(
+        handler, reader, error, static_cast<const Args&>(args)...);
+  }
+
+  //
+  // There are two specializations of this function:
+  //  1. For the case where ParamType is a value type (D-Bus IN parameter).
+  //  2. For the case where ParamType is a pointer (D-Bus OUT parameter).
+  // In the second case, the parameter is not popped off the message reader,
+  // since we do not expect the client to provide any data for it.
+  // However after the final handler is called, the values for the OUT
+  // parameters should be sent back in the method call response message.
+
+  // Overload 1: ParamType is not a pointer.
+  template<typename ParamType, typename CallbackType, typename... Args>
+  static typename std::enable_if<!std::is_pointer<ParamType>::value, bool>::type
+  InvokeHelper(const CallbackType& handler,
+               dbus::MessageReader* reader,
+               ErrorPtr* error,
+               const Args&... args) {
+    if (!reader->HasMoreData()) {
+      Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+                   DBUS_ERROR_INVALID_ARGS,
+                   "Too few parameters in a method call");
+      return false;
+    }
+    // ParamType could be a reference type (e.g. 'const std::string&').
+    // Here we need a value type so we can create an object of this type and
+    // pop the value off the message buffer into. Using std::decay<> to get
+    // the value type. If ParamType is already a value type, ParamValueType will
+    // be the same as ParamType.
+    using ParamValueType = typename std::decay<ParamType>::type;
+    // The variable to hold the value of the current parameter we reading from
+    // the message buffer.
+    ParamValueType current_param;
+    if (!DBusType<ParamValueType>::Read(reader, &current_param)) {
+      Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+                   DBUS_ERROR_INVALID_ARGS,
+                   "Method parameter type mismatch");
+      return false;
+    }
+    // Call DBusParamReader::Invoke() to process the rest of parameters.
+    // Note that this is not a recursive call because it is calling a different
+    // method of a different class. We exclude the current parameter type
+    // (ParamType) from DBusParamReader<> template parameter list and forward
+    // all the parameters to the arguments of Invoke() and append the current
+    // parameter to the end of the parameter list. We pass it as a const
+    // reference to allow to use move-only types such as std::unique_ptr<> and
+    // to eliminate unnecessarily copying data.
+    return DBusParamReader<allow_out_params, RestOfParams...>::Invoke(
+        handler, reader, error,
+        static_cast<const Args&>(args)...,
+        static_cast<const ParamValueType&>(current_param));
+  }
+
+  // Overload 2: ParamType is a pointer.
+  template<typename ParamType, typename CallbackType, typename... Args>
+  static typename std::enable_if<allow_out_params &&
+                                 std::is_pointer<ParamType>::value, bool>::type
+      InvokeHelper(const CallbackType& handler,
+                   dbus::MessageReader* reader,
+                   ErrorPtr* error,
+                   const Args&... args) {
+    // ParamType is a pointer. This is expected to be an output parameter.
+    // Create storage for it and the handler will provide a value for it.
+    using ParamValueType = typename std::remove_pointer<ParamType>::type;
+    // The variable to hold the value of the current parameter we are passing
+    // to the handler.
+    ParamValueType current_param{};  // Default-initialize the value.
+    // Call DBusParamReader::Invoke() to process the rest of parameters.
+    // Note that this is not a recursive call because it is calling a different
+    // method of a different class. We exclude the current parameter type
+    // (ParamType) from DBusParamReader<> template parameter list and forward
+    // all the parameters to the arguments of Invoke() and append the current
+    // parameter to the end of the parameter list.
+    return DBusParamReader<allow_out_params, RestOfParams...>::Invoke(
+        handler, reader, error,
+        static_cast<const Args&>(args)...,
+        &current_param);
+  }
+};  // struct DBusParamReader<ParamType, RestOfParams...>
+
+// The final specialization of DBusParamReader<> used when no more parameters
+// are expected in the message buffer. Actually dispatches the call to the
+// handler with all the accumulated arguments.
+template<bool allow_out_params>
+struct DBusParamReader<allow_out_params> {
+  template<typename CallbackType, typename... Args>
+  static bool Invoke(const CallbackType& handler,
+                     dbus::MessageReader* reader,
+                     ErrorPtr* error,
+                     const Args&... args) {
+    if (reader->HasMoreData()) {
+      Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+                   DBUS_ERROR_INVALID_ARGS,
+                   "Too many parameters in a method call");
+      return false;
+    }
+    handler(args...);
+    return true;
+  }
+};  // struct DBusParamReader<>
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_PARAM_READER_H_
diff --git a/libbrillo/brillo/dbus/dbus_param_reader_unittest.cc b/libbrillo/brillo/dbus/dbus_param_reader_unittest.cc
new file mode 100644
index 0000000..fd9f243
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_param_reader_unittest.cc
@@ -0,0 +1,253 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/dbus_param_reader.h>
+
+#include <string>
+
+#include <brillo/variant_dictionary.h>
+#include <gtest/gtest.h>
+
+using dbus::MessageReader;
+using dbus::MessageWriter;
+using dbus::Response;
+
+namespace brillo {
+namespace dbus_utils {
+
+TEST(DBusParamReader, NoArgs) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageReader reader(message.get());
+  bool called = false;
+  auto callback = [&called]() { called = true; };
+  EXPECT_TRUE(DBusParamReader<false>::Invoke(callback, &reader, nullptr));
+  EXPECT_TRUE(called);
+}
+
+TEST(DBusParamReader, OneArg) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  AppendValueToWriter(&writer, 123);
+  MessageReader reader(message.get());
+  bool called = false;
+  auto callback = [&called](int param1) {
+    EXPECT_EQ(123, param1);
+    called = true;
+  };
+  EXPECT_TRUE(
+      (DBusParamReader<false, int>::Invoke(callback, &reader, nullptr)));
+  EXPECT_TRUE(called);
+}
+
+TEST(DBusParamReader, ManyArgs) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  AppendValueToWriter(&writer, true);
+  AppendValueToWriter(&writer, 1972);
+  AppendValueToWriter(&writer,
+                      VariantDictionary{{"key", std::string{"value"}}});
+  MessageReader reader(message.get());
+  bool called = false;
+  auto callback = [&called](bool p1, int p2, const VariantDictionary& p3) {
+    EXPECT_TRUE(p1);
+    EXPECT_EQ(1972, p2);
+    EXPECT_EQ(1, p3.size());
+    EXPECT_EQ("value", p3.find("key")->second.Get<std::string>());
+    called = true;
+  };
+  EXPECT_TRUE((DBusParamReader<false, bool, int, VariantDictionary>::Invoke(
+      callback, &reader, nullptr)));
+  EXPECT_TRUE(called);
+}
+
+TEST(DBusParamReader, TooManyArgs) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  AppendValueToWriter(&writer, true);
+  AppendValueToWriter(&writer, 1972);
+  AppendValueToWriter(&writer,
+                      VariantDictionary{{"key", std::string{"value"}}});
+  MessageReader reader(message.get());
+  bool called = false;
+  auto callback = [&called](bool param1, int param2) {
+    EXPECT_TRUE(param1);
+    EXPECT_EQ(1972, param2);
+    called = true;
+  };
+  ErrorPtr error;
+  EXPECT_FALSE(
+      (DBusParamReader<false, bool, int>::Invoke(callback, &reader, &error)));
+  EXPECT_FALSE(called);
+  EXPECT_EQ(errors::dbus::kDomain, error->GetDomain());
+  EXPECT_EQ(DBUS_ERROR_INVALID_ARGS, error->GetCode());
+  EXPECT_EQ("Too many parameters in a method call", error->GetMessage());
+}
+
+TEST(DBusParamReader, TooFewArgs) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  AppendValueToWriter(&writer, true);
+  MessageReader reader(message.get());
+  bool called = false;
+  auto callback = [&called](bool param1, int param2) {
+    EXPECT_TRUE(param1);
+    EXPECT_EQ(1972, param2);
+    called = true;
+  };
+  ErrorPtr error;
+  EXPECT_FALSE(
+      (DBusParamReader<false, bool, int>::Invoke(callback, &reader, &error)));
+  EXPECT_FALSE(called);
+  EXPECT_EQ(errors::dbus::kDomain, error->GetDomain());
+  EXPECT_EQ(DBUS_ERROR_INVALID_ARGS, error->GetCode());
+  EXPECT_EQ("Too few parameters in a method call", error->GetMessage());
+}
+
+TEST(DBusParamReader, TypeMismatch) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  AppendValueToWriter(&writer, true);
+  AppendValueToWriter(&writer, 1972);
+  MessageReader reader(message.get());
+  bool called = false;
+  auto callback = [&called](bool param1, double param2) {
+    EXPECT_TRUE(param1);
+    EXPECT_DOUBLE_EQ(1972.0, param2);
+    called = true;
+  };
+  ErrorPtr error;
+  EXPECT_FALSE((
+      DBusParamReader<false, bool, double>::Invoke(callback, &reader, &error)));
+  EXPECT_FALSE(called);
+  EXPECT_EQ(errors::dbus::kDomain, error->GetDomain());
+  EXPECT_EQ(DBUS_ERROR_INVALID_ARGS, error->GetCode());
+  EXPECT_EQ("Method parameter type mismatch", error->GetMessage());
+}
+
+TEST(DBusParamReader, NoArgs_With_OUT) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageReader reader(message.get());
+  bool called = false;
+  auto callback = [&called](int* param1) {
+    EXPECT_EQ(0, *param1);
+    called = true;
+  };
+  EXPECT_TRUE(
+      (DBusParamReader<true, int*>::Invoke(callback, &reader, nullptr)));
+  EXPECT_TRUE(called);
+}
+
+TEST(DBusParamReader, OneArg_Before_OUT) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  AppendValueToWriter(&writer, 123);
+  MessageReader reader(message.get());
+  bool called = false;
+  auto callback = [&called](int param1, double* param2) {
+    EXPECT_EQ(123, param1);
+    EXPECT_DOUBLE_EQ(0.0, *param2);
+    called = true;
+  };
+  EXPECT_TRUE((
+      DBusParamReader<true, int, double*>::Invoke(callback, &reader, nullptr)));
+  EXPECT_TRUE(called);
+}
+
+TEST(DBusParamReader, OneArg_After_OUT) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  AppendValueToWriter(&writer, 123);
+  MessageReader reader(message.get());
+  bool called = false;
+  auto callback = [&called](double* param1, int param2) {
+    EXPECT_DOUBLE_EQ(0.0, *param1);
+    EXPECT_EQ(123, param2);
+    called = true;
+  };
+  EXPECT_TRUE((
+      DBusParamReader<true, double*, int>::Invoke(callback, &reader, nullptr)));
+  EXPECT_TRUE(called);
+}
+
+TEST(DBusParamReader, ManyArgs_With_OUT) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  AppendValueToWriter(&writer, true);
+  AppendValueToWriter(&writer, 1972);
+  AppendValueToWriter(&writer,
+                      VariantDictionary{{"key", std::string{"value"}}});
+  MessageReader reader(message.get());
+  bool called = false;
+  auto callback = [&called](bool p1,
+                            std::string* p2,
+                            int p3,
+                            int* p4,
+                            const VariantDictionary& p5,
+                            bool* p6) {
+    EXPECT_TRUE(p1);
+    EXPECT_EQ("", *p2);
+    EXPECT_EQ(1972, p3);
+    EXPECT_EQ(0, *p4);
+    EXPECT_EQ(1, p5.size());
+    EXPECT_EQ("value", p5.find("key")->second.Get<std::string>());
+    EXPECT_FALSE(*p6);
+    called = true;
+  };
+  EXPECT_TRUE((DBusParamReader<true,
+                               bool,
+                               std::string*,
+                               int,
+                               int*,
+                               VariantDictionary,
+                               bool*>::Invoke(callback, &reader, nullptr)));
+  EXPECT_TRUE(called);
+}
+
+TEST(DBusParamReader, TooManyArgs_With_OUT) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  AppendValueToWriter(&writer, true);
+  AppendValueToWriter(&writer, 1972);
+  AppendValueToWriter(&writer,
+                      VariantDictionary{{"key", std::string{"value"}}});
+  MessageReader reader(message.get());
+  bool called = false;
+  auto callback = [&called](bool param1, int param2, int* param3) {
+    EXPECT_TRUE(param1);
+    EXPECT_EQ(1972, param2);
+    EXPECT_EQ(0, *param3);
+    called = true;
+  };
+  ErrorPtr error;
+  EXPECT_FALSE((DBusParamReader<true, bool, int, int*>::Invoke(
+      callback, &reader, &error)));
+  EXPECT_FALSE(called);
+  EXPECT_EQ(errors::dbus::kDomain, error->GetDomain());
+  EXPECT_EQ(DBUS_ERROR_INVALID_ARGS, error->GetCode());
+  EXPECT_EQ("Too many parameters in a method call", error->GetMessage());
+}
+
+TEST(DBusParamReader, TooFewArgs_With_OUT) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  AppendValueToWriter(&writer, true);
+  MessageReader reader(message.get());
+  bool called = false;
+  auto callback = [&called](bool param1, int param2, int* param3) {
+    EXPECT_TRUE(param1);
+    EXPECT_EQ(1972, param2);
+    EXPECT_EQ(0, *param3);
+    called = true;
+  };
+  ErrorPtr error;
+  EXPECT_FALSE((DBusParamReader<true, bool, int, int*>::Invoke(
+      callback, &reader, &error)));
+  EXPECT_FALSE(called);
+  EXPECT_EQ(errors::dbus::kDomain, error->GetDomain());
+  EXPECT_EQ(DBUS_ERROR_INVALID_ARGS, error->GetCode());
+  EXPECT_EQ("Too few parameters in a method call", error->GetMessage());
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/dbus_param_writer.h b/libbrillo/brillo/dbus/dbus_param_writer.h
new file mode 100644
index 0000000..7c7f45e
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_param_writer.h
@@ -0,0 +1,80 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// DBusParamWriter::Append(writer, ...) provides functionality opposite
+// to that of DBusParamReader. It writes each of the arguments to D-Bus message
+// writer and return true if successful.
+
+// DBusParamWriter::AppendDBusOutParams(writer, ...) is similar to Append()
+// but is used to send out the D-Bus OUT (pointer type) parameters in a D-Bus
+// method response message. This method skips any non-pointer parameters and
+// only appends the data for arguments that are pointers.
+
+#ifndef LIBBRILLO_BRILLO_DBUS_DBUS_PARAM_WRITER_H_
+#define LIBBRILLO_BRILLO_DBUS_DBUS_PARAM_WRITER_H_
+
+#include <brillo/dbus/data_serialization.h>
+#include <dbus/message.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+class DBusParamWriter final {
+ public:
+  // Generic writer method that takes 1 or more arguments. It recursively calls
+  // itself (each time with one fewer arguments) until no more is left.
+  template<typename ParamType, typename... RestOfParams>
+  static void Append(dbus::MessageWriter* writer,
+                     const ParamType& param,
+                     const RestOfParams&... rest) {
+    // Append the current |param| to D-Bus, then call Append() with one
+    // fewer arguments, until none is left and stand-alone version of
+    // Append(dbus::MessageWriter*) is called to end the iteration.
+    DBusType<ParamType>::Write(writer, param);
+    Append(writer, rest...);
+  }
+
+  // The final overload of DBusParamWriter::Append() used when no more
+  // parameters are remaining to be written.
+  // Does nothing and finishes meta-recursion.
+  static void Append(dbus::MessageWriter* /*writer*/) {}
+
+  // Generic writer method that takes 1 or more arguments. It recursively calls
+  // itself (each time with one fewer arguments) until no more is left.
+  // Handles non-pointer parameter by just skipping over it.
+  template<typename ParamType, typename... RestOfParams>
+  static void AppendDBusOutParams(dbus::MessageWriter* writer,
+                                  const ParamType& /* param */,
+                                  const RestOfParams&... rest) {
+    // Skip the current |param| and call Append() with one fewer arguments,
+    // until none is left and stand-alone version of
+    // AppendDBusOutParams(dbus::MessageWriter*) is called to end the iteration.
+    AppendDBusOutParams(writer, rest...);
+  }
+
+  // Generic writer method that takes 1 or more arguments. It recursively calls
+  // itself (each time with one fewer arguments) until no more is left.
+  // Handles only a parameter of pointer type and writes the data pointed to
+  // to the output message buffer.
+  template<typename ParamType, typename... RestOfParams>
+  static void AppendDBusOutParams(dbus::MessageWriter* writer,
+                                  ParamType* param,
+                                  const RestOfParams&... rest) {
+    // Append the current |param| to D-Bus, then call Append() with one
+    // fewer arguments, until none is left and stand-alone version of
+    // Append(dbus::MessageWriter*) is called to end the iteration.
+    DBusType<ParamType>::Write(writer, *param);
+    AppendDBusOutParams(writer, rest...);
+  }
+
+  // The final overload of DBusParamWriter::AppendDBusOutParams() used when no
+  // more parameters are remaining to be written.
+  // Does nothing and finishes meta-recursion.
+  static void AppendDBusOutParams(dbus::MessageWriter* /*writer*/) {}
+};
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_PARAM_WRITER_H_
diff --git a/libbrillo/brillo/dbus/dbus_param_writer_unittest.cc b/libbrillo/brillo/dbus/dbus_param_writer_unittest.cc
new file mode 100644
index 0000000..6ab863a
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_param_writer_unittest.cc
@@ -0,0 +1,189 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/dbus_param_writer.h>
+
+#include <string>
+
+#include <brillo/any.h>
+#include <gtest/gtest.h>
+
+using dbus::MessageReader;
+using dbus::MessageWriter;
+using dbus::ObjectPath;
+using dbus::Response;
+
+namespace brillo {
+namespace dbus_utils {
+
+TEST(DBusParamWriter, Append_NoArgs) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  DBusParamWriter::Append(&writer);
+  EXPECT_EQ("", message->GetSignature());
+}
+
+TEST(DBusParamWriter, Append_OneArg) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  DBusParamWriter::Append(&writer, int32_t{2});
+  EXPECT_EQ("i", message->GetSignature());
+  DBusParamWriter::Append(&writer, std::string{"foo"});
+  EXPECT_EQ("is", message->GetSignature());
+  DBusParamWriter::Append(&writer, ObjectPath{"/o"});
+  EXPECT_EQ("iso", message->GetSignature());
+
+  int32_t int_value = 0;
+  std::string string_value;
+  ObjectPath path_value;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &int_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &string_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &path_value));
+
+  EXPECT_EQ(2, int_value);
+  EXPECT_EQ("foo", string_value);
+  EXPECT_EQ(ObjectPath{"/o"}, path_value);
+}
+
+TEST(DBusParamWriter, Append_ManyArgs) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  DBusParamWriter::Append(&writer, int32_t{9}, Any{7.5}, true);
+  EXPECT_EQ("ivb", message->GetSignature());
+
+  int32_t int_value = 0;
+  Any variant_value;
+  bool bool_value = false;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &int_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &variant_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &bool_value));
+
+  EXPECT_EQ(9, int_value);
+  EXPECT_DOUBLE_EQ(7.5, variant_value.Get<double>());
+  EXPECT_TRUE(bool_value);
+}
+
+TEST(DBusParamWriter, AppendDBusOutParams_NoArgs) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  DBusParamWriter::AppendDBusOutParams(&writer);
+  EXPECT_EQ("", message->GetSignature());
+}
+
+TEST(DBusParamWriter, AppendDBusOutParams_OneArg) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  int32_t int_value_in{5};
+  std::string string_value_in{"bar"};
+  ObjectPath path_value_in{"/obj/path"};
+
+  DBusParamWriter::AppendDBusOutParams(&writer, &int_value_in);
+  EXPECT_EQ("i", message->GetSignature());
+  DBusParamWriter::AppendDBusOutParams(&writer, &string_value_in);
+  EXPECT_EQ("is", message->GetSignature());
+  DBusParamWriter::AppendDBusOutParams(&writer, &path_value_in);
+  EXPECT_EQ("iso", message->GetSignature());
+
+  int32_t int_value = 0;
+  std::string string_value;
+  ObjectPath path_value;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &int_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &string_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &path_value));
+
+  EXPECT_EQ(5, int_value);
+  EXPECT_EQ("bar", string_value);
+  EXPECT_EQ(ObjectPath{"/obj/path"}, path_value);
+}
+
+TEST(DBusParamWriter, AppendDBusOutParams_ManyArgs) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  int32_t int_value_in{8};
+  Any variant_value_in{8.5};
+  bool bool_value_in{true};
+  DBusParamWriter::AppendDBusOutParams(
+      &writer, &int_value_in, &variant_value_in, &bool_value_in);
+  EXPECT_EQ("ivb", message->GetSignature());
+
+  int32_t int_value = 0;
+  Any variant_value;
+  bool bool_value = false;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &int_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &variant_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &bool_value));
+
+  EXPECT_EQ(8, int_value);
+  EXPECT_DOUBLE_EQ(8.5, variant_value.Get<double>());
+  EXPECT_TRUE(bool_value);
+}
+
+TEST(DBusParamWriter, AppendDBusOutParams_Mixed_NoArgs) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  DBusParamWriter::AppendDBusOutParams(&writer, 3, 5);
+  EXPECT_EQ("", message->GetSignature());
+}
+
+TEST(DBusParamWriter, AppendDBusOutParams_Mixed_OneArg) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  int32_t int_value_in{5};
+  std::string str_value_in{"bar"};
+  ObjectPath path_value_in{"/obj"};
+
+  DBusParamWriter::AppendDBusOutParams(&writer, 2, &int_value_in);
+  EXPECT_EQ("i", message->GetSignature());
+  DBusParamWriter::AppendDBusOutParams(&writer, &str_value_in, 0);
+  EXPECT_EQ("is", message->GetSignature());
+  DBusParamWriter::AppendDBusOutParams(&writer, 1, &path_value_in, 2);
+  EXPECT_EQ("iso", message->GetSignature());
+
+  int32_t int_value = 0;
+  std::string string_value;
+  ObjectPath path_value;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &int_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &string_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &path_value));
+
+  EXPECT_EQ(5, int_value);
+  EXPECT_EQ("bar", string_value);
+  EXPECT_EQ(ObjectPath{"/obj"}, path_value);
+}
+
+TEST(DBusParamWriter, AppendDBusOutParams_Mixed_ManyArgs) {
+  std::unique_ptr<Response> message = Response::CreateEmpty();
+  MessageWriter writer(message.get());
+  int32_t int_value_in{8};
+  Any variant_value_in{7.5};
+  bool bool_value_in{true};
+  DBusParamWriter::AppendDBusOutParams(
+      &writer, 0, &int_value_in, 1, &variant_value_in, 2, &bool_value_in, 3);
+  EXPECT_EQ("ivb", message->GetSignature());
+
+  int32_t int_value = 0;
+  Any variant_value;
+  bool bool_value = false;
+
+  MessageReader reader(message.get());
+  EXPECT_TRUE(PopValueFromReader(&reader, &int_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &variant_value));
+  EXPECT_TRUE(PopValueFromReader(&reader, &bool_value));
+
+  EXPECT_EQ(8, int_value);
+  EXPECT_DOUBLE_EQ(7.5, variant_value.Get<double>());
+  EXPECT_TRUE(bool_value);
+}
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/dbus_property.h b/libbrillo/brillo/dbus/dbus_property.h
new file mode 100644
index 0000000..01b850d
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_property.h
@@ -0,0 +1,94 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_DBUS_PROPERTY_H_
+#define LIBBRILLO_BRILLO_DBUS_DBUS_PROPERTY_H_
+
+#include <brillo/dbus/data_serialization.h>
+#include <dbus/property.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+// Re-implementation of dbus::Property<T> that can handle any type supported by
+// D-Bus data serialization layer, such as vectors, maps, tuples, etc.
+// This class is pretty much a copy of dbus::Property<T> from dbus/property.h
+// except that it provides the implementations for PopValueFromReader and
+// AppendSetValueToWriter.
+template<class T>
+class Property : public dbus::PropertyBase {
+ public:
+  Property() = default;
+
+  // Retrieves the cached value.
+  const T& value() const { return value_; }
+
+  // Requests an updated value from the remote object incurring a
+  // round-trip. |callback| will be called when the new value is available.
+  // This may not be implemented by some interfaces.
+  void Get(dbus::PropertySet::GetCallback callback) {
+    property_set()->Get(this, callback);
+  }
+
+  // Synchronous vesion of Get().
+  bool GetAndBlock() {
+    return property_set()->GetAndBlock(this);
+  }
+
+  // Requests that the remote object change the property value to |value|,
+  // |callback| will be called to indicate the success or failure of the
+  // request, however the new value may not be available depending on the
+  // remote object.
+  void Set(const T& value, dbus::PropertySet::SetCallback callback) {
+    set_value_ = value;
+    property_set()->Set(this, callback);
+  }
+
+  // Synchronous version of Set().
+  bool SetAndBlock(const T& value) {
+    set_value_ = value;
+    return property_set()->SetAndBlock(this);
+  }
+
+  // Method used by PropertySet to retrieve the value from a MessageReader,
+  // no knowledge of the contained type is required, this method returns
+  // true if its expected type was found, false if not.
+  bool PopValueFromReader(dbus::MessageReader* reader) override {
+    return PopVariantValueFromReader(reader, &value_);
+  }
+
+  // Method used by PropertySet to append the set value to a MessageWriter,
+  // no knowledge of the contained type is required.
+  // Implementation provided by specialization.
+  void AppendSetValueToWriter(dbus::MessageWriter* writer) override {
+    AppendValueToWriterAsVariant(writer, set_value_);
+  }
+
+  // Method used by test and stub implementations of dbus::PropertySet::Set
+  // to replace the property value with the set value without using a
+  // dbus::MessageReader.
+  void ReplaceValueWithSetValue() override {
+    value_ = set_value_;
+    property_set()->NotifyPropertyChanged(name());
+  }
+
+  // Method used by test and stub implementations to directly set the
+  // value of a property.
+  void ReplaceValue(const T& value) {
+    value_ = value;
+    property_set()->NotifyPropertyChanged(name());
+  }
+
+ private:
+  // Current cached value of the property.
+  T value_;
+
+  // Replacement value of the property.
+  T set_value_;
+};
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_PROPERTY_H_
diff --git a/libbrillo/brillo/dbus/dbus_service_watcher.cc b/libbrillo/brillo/dbus/dbus_service_watcher.cc
new file mode 100644
index 0000000..ede2e6e
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_service_watcher.cc
@@ -0,0 +1,39 @@
+// Copyright 2015 The Chromium OS 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 <brillo/dbus/dbus_service_watcher.h>
+
+#include <base/bind.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+DBusServiceWatcher::DBusServiceWatcher(
+    scoped_refptr<dbus::Bus> bus,
+    const std::string& connection_name,
+    const base::Closure& on_connection_vanish)
+    : bus_{bus},
+      connection_name_{connection_name},
+      on_connection_vanish_{on_connection_vanish} {
+  monitoring_callback_ = base::Bind(
+      &DBusServiceWatcher::OnServiceOwnerChange, weak_factory_.GetWeakPtr());
+  // Register to listen, and then request the current owner;
+  bus_->ListenForServiceOwnerChange(connection_name_, monitoring_callback_);
+  bus_->GetServiceOwner(connection_name_, monitoring_callback_);
+}
+
+DBusServiceWatcher::~DBusServiceWatcher() {
+  bus_->UnlistenForServiceOwnerChange(
+      connection_name_, monitoring_callback_);
+}
+
+void DBusServiceWatcher::OnServiceOwnerChange(
+    const std::string& service_owner) {
+  if (service_owner.empty()) {
+    on_connection_vanish_.Run();
+  }
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/dbus_service_watcher.h b/libbrillo/brillo/dbus/dbus_service_watcher.h
new file mode 100644
index 0000000..0031771
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_service_watcher.h
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_DBUS_SERVICE_WATCHER_H_
+#define LIBBRILLO_BRILLO_DBUS_DBUS_SERVICE_WATCHER_H_
+
+#include <string>
+
+#include <base/callback.h>
+#include <base/macros.h>
+#include <base/memory/ref_counted.h>
+#include <base/memory/weak_ptr.h>
+#include <brillo/brillo_export.h>
+#include <dbus/bus.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+// DBusServiceWatcher just asks the bus to notify us when the owner of a remote
+// DBus connection transitions to the empty string.  After registering a
+// callback to be notified of name owner transitions, for the given
+// |connection_name|, DBusServiceWatcher asks for the current owner.  If at any
+// point an empty string is found for the connection name owner,
+// DBusServiceWatcher will call back to notify of the connection vanishing.
+//
+// The chief value of this class is that it manages the lifetime of the
+// registered callback in the Bus, because failure to remove callbacks will
+// cause the Bus to crash the process on destruction.
+class BRILLO_EXPORT DBusServiceWatcher {
+ public:
+  DBusServiceWatcher(scoped_refptr<dbus::Bus> bus,
+                     const std::string& connection_name,
+                     const base::Closure& on_connection_vanish);
+  virtual ~DBusServiceWatcher();
+  virtual std::string connection_name() const { return connection_name_; }
+
+ private:
+  void OnServiceOwnerChange(const std::string& service_owner);
+
+  scoped_refptr<dbus::Bus> bus_;
+  const std::string connection_name_;
+  dbus::Bus::GetServiceOwnerCallback monitoring_callback_;
+  base::Closure on_connection_vanish_;
+
+  base::WeakPtrFactory<DBusServiceWatcher> weak_factory_{this};
+  DISALLOW_COPY_AND_ASSIGN(DBusServiceWatcher);
+};
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_SERVICE_WATCHER_H_
diff --git a/libbrillo/brillo/dbus/dbus_signal.cc b/libbrillo/brillo/dbus/dbus_signal.cc
new file mode 100644
index 0000000..d227bd7
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_signal.cc
@@ -0,0 +1,28 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/dbus_signal.h>
+
+#include <brillo/dbus/dbus_object.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+DBusSignalBase::DBusSignalBase(DBusObject* dbus_object,
+                               const std::string& interface_name,
+                               const std::string& signal_name)
+    : interface_name_(interface_name),
+      signal_name_(signal_name),
+      dbus_object_(dbus_object) {
+}
+
+bool DBusSignalBase::SendSignal(dbus::Signal* signal) const {
+  // This sends the signal asynchronously.  However, the raw message inside
+  // the signal object is ref-counted, so we're fine to pass a stack-allocated
+  // Signal object here.
+  return dbus_object_->SendSignal(signal);
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/dbus_signal.h b/libbrillo/brillo/dbus/dbus_signal.h
new file mode 100644
index 0000000..bda322a
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_signal.h
@@ -0,0 +1,68 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_DBUS_SIGNAL_H_
+#define LIBBRILLO_BRILLO_DBUS_DBUS_SIGNAL_H_
+
+#include <string>
+#include <typeinfo>
+
+#include <base/bind.h>
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+#include <brillo/dbus/dbus_param_writer.h>
+#include <dbus/message.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+class DBusObject;
+
+// Base class for D-Bus signal proxy classes.
+// Used mostly to store the polymorphic DBusSignal<...> in a single map
+// container inside DBusInterface object.
+class BRILLO_EXPORT DBusSignalBase {
+ public:
+  DBusSignalBase(DBusObject* dbus_object,
+                 const std::string& interface_name,
+                 const std::string& signal_name);
+  virtual ~DBusSignalBase() = default;
+
+ protected:
+  bool SendSignal(dbus::Signal* signal) const;
+
+  std::string interface_name_;
+  std::string signal_name_;
+
+ private:
+  DBusObject* dbus_object_;
+
+  DISALLOW_COPY_AND_ASSIGN(DBusSignalBase);
+};
+
+// DBusSignal<...> is a concrete signal proxy class that knows about the
+// exact number of signal arguments and their types.
+template<typename... Args>
+class DBusSignal : public DBusSignalBase {
+ public:
+  // Expose the custom constructor from DBusSignalBase.
+  using DBusSignalBase::DBusSignalBase;
+  ~DBusSignal() override = default;
+
+  // DBusSignal<...>::Send(...) dispatches the signal with the given arguments.
+  bool Send(const Args&... args) const {
+    dbus::Signal signal(interface_name_, signal_name_);
+    dbus::MessageWriter signal_writer(&signal);
+    DBusParamWriter::Append(&signal_writer, args...);
+    return SendSignal(&signal);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DBusSignal);
+};
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_SIGNAL_H_
diff --git a/libbrillo/brillo/dbus/dbus_signal_handler.h b/libbrillo/brillo/dbus/dbus_signal_handler.h
new file mode 100644
index 0000000..9c3246c
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_signal_handler.h
@@ -0,0 +1,70 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_DBUS_SIGNAL_HANDLER_H_
+#define LIBBRILLO_BRILLO_DBUS_DBUS_SIGNAL_HANDLER_H_
+
+#include <string>
+
+#include <brillo/bind_lambda.h>
+#include <brillo/dbus/dbus_param_reader.h>
+#include <dbus/message.h>
+#include <dbus/object_proxy.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+// brillo::dbus_utils::ConnectToSignal() is a helper function similar to
+// dbus::ObjectProxy::ConnectToSignal() but the |signal_callback| is an actual
+// C++ signal handler with expected signal parameters as native method args.
+//
+// brillo::dbus_utils::ConnectToSignal() actually registers a stub signal
+// handler with D-Bus which has a standard signature that matches
+// dbus::ObjectProxy::SignalCallback.
+//
+// When a D-Bus signal is emitted, the stub handler is invoked, which unpacks
+// the expected parameters from dbus::Signal message and then calls
+// |signal_callback| with unpacked arguments.
+//
+// If the signal message doesn't contain correct number or types of arguments,
+// an error message is logged to the system log and the signal is ignored
+// (|signal_callback| is not invoked).
+template<typename... Args>
+void ConnectToSignal(
+    dbus::ObjectProxy* object_proxy,
+    const std::string& interface_name,
+    const std::string& signal_name,
+    base::Callback<void(Args...)> signal_callback,
+    dbus::ObjectProxy::OnConnectedCallback on_connected_callback) {
+  // Raw signal handler stub method. When called, unpacks the signal arguments
+  // from |signal| message buffer and redirects the call to
+  // |signal_callback_wrapper| which, in turn, would call the user-provided
+  // |signal_callback|.
+  auto dbus_signal_callback = [](
+      const base::Callback<void(Args...)>& signal_callback,
+      dbus::Signal* signal) {
+    // DBusParamReader::Invoke() needs a functor object, not a base::Callback.
+    // Wrap the callback with lambda so we can redirect the call.
+    auto signal_callback_wrapper = [signal_callback](const Args&... args) {
+      if (!signal_callback.is_null()) {
+        signal_callback.Run(args...);
+      }
+    };
+
+    dbus::MessageReader reader(signal);
+    DBusParamReader<false, Args...>::Invoke(
+        signal_callback_wrapper, &reader, nullptr);
+  };
+
+  // Register our stub handler with D-Bus ObjectProxy.
+  object_proxy->ConnectToSignal(interface_name,
+                                signal_name,
+                                base::Bind(dbus_signal_callback, signal_callback),
+                                on_connected_callback);
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_DBUS_SIGNAL_HANDLER_H_
diff --git a/libbrillo/brillo/dbus/dbus_signal_handler_unittest.cc b/libbrillo/brillo/dbus/dbus_signal_handler_unittest.cc
new file mode 100644
index 0000000..e0bea10
--- /dev/null
+++ b/libbrillo/brillo/dbus/dbus_signal_handler_unittest.cc
@@ -0,0 +1,145 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/dbus_signal_handler.h>
+
+#include <string>
+
+#include <brillo/bind_lambda.h>
+#include <brillo/dbus/dbus_param_writer.h>
+#include <dbus/mock_bus.h>
+#include <dbus/mock_object_proxy.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::AnyNumber;
+using testing::Return;
+using testing::SaveArg;
+using testing::_;
+
+namespace brillo {
+namespace dbus_utils {
+
+const char kTestPath[] = "/test/path";
+const char kTestServiceName[] = "org.test.Object";
+const char kInterface[] = "org.test.Object.TestInterface";
+const char kSignal[] = "TestSignal";
+
+class DBusSignalHandlerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    dbus::Bus::Options options;
+    options.bus_type = dbus::Bus::SYSTEM;
+    bus_ = new dbus::MockBus(options);
+    // By default, don't worry about threading assertions.
+    EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
+    EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
+    // Use a mock object proxy.
+    mock_object_proxy_ = new dbus::MockObjectProxy(
+        bus_.get(), kTestServiceName, dbus::ObjectPath(kTestPath));
+    EXPECT_CALL(*bus_,
+                GetObjectProxy(kTestServiceName, dbus::ObjectPath(kTestPath)))
+        .WillRepeatedly(Return(mock_object_proxy_.get()));
+  }
+
+  void TearDown() override { bus_ = nullptr; }
+
+ protected:
+  template<typename SignalHandlerSink, typename... Args>
+  void CallSignal(SignalHandlerSink* sink, Args... args) {
+    dbus::ObjectProxy::SignalCallback signal_callback;
+    EXPECT_CALL(*mock_object_proxy_, ConnectToSignal(kInterface, kSignal, _, _))
+        .WillOnce(SaveArg<2>(&signal_callback));
+
+    brillo::dbus_utils::ConnectToSignal(
+        mock_object_proxy_.get(),
+        kInterface,
+        kSignal,
+        base::Bind(&SignalHandlerSink::Handler, base::Unretained(sink)),
+        {});
+
+    dbus::Signal signal(kInterface, kSignal);
+    dbus::MessageWriter writer(&signal);
+    DBusParamWriter::Append(&writer, args...);
+    signal_callback.Run(&signal);
+  }
+
+  scoped_refptr<dbus::MockBus> bus_;
+  scoped_refptr<dbus::MockObjectProxy> mock_object_proxy_;
+};
+
+TEST_F(DBusSignalHandlerTest, ConnectToSignal) {
+  EXPECT_CALL(*mock_object_proxy_, ConnectToSignal(kInterface, kSignal, _, _))
+      .Times(1);
+
+  brillo::dbus_utils::ConnectToSignal(
+      mock_object_proxy_.get(), kInterface, kSignal, base::Closure{}, {});
+}
+
+TEST_F(DBusSignalHandlerTest, CallSignal_3Args) {
+  class SignalHandlerSink {
+   public:
+    MOCK_METHOD3(Handler, void(int, int, double));
+  } sink;
+
+  EXPECT_CALL(sink, Handler(10, 20, 30.5)).Times(1);
+  CallSignal(&sink, 10, 20, 30.5);
+}
+
+TEST_F(DBusSignalHandlerTest, CallSignal_2Args) {
+  class SignalHandlerSink {
+   public:
+    // Take string both by reference and by value to make sure this works too.
+    MOCK_METHOD2(Handler, void(const std::string&, std::string));
+  } sink;
+
+  EXPECT_CALL(sink, Handler(std::string{"foo"}, std::string{"bar"})).Times(1);
+  CallSignal(&sink, std::string{"foo"}, std::string{"bar"});
+}
+
+TEST_F(DBusSignalHandlerTest, CallSignal_NoArgs) {
+  class SignalHandlerSink {
+   public:
+    MOCK_METHOD0(Handler, void());
+  } sink;
+
+  EXPECT_CALL(sink, Handler()).Times(1);
+  CallSignal(&sink);
+}
+
+TEST_F(DBusSignalHandlerTest, CallSignal_Error_TooManyArgs) {
+  class SignalHandlerSink {
+   public:
+    MOCK_METHOD0(Handler, void());
+  } sink;
+
+  // Handler() expects no args, but we send an int.
+  EXPECT_CALL(sink, Handler()).Times(0);
+  CallSignal(&sink, 5);
+}
+
+TEST_F(DBusSignalHandlerTest, CallSignal_Error_TooFewArgs) {
+  class SignalHandlerSink {
+   public:
+    MOCK_METHOD2(Handler, void(std::string, bool));
+  } sink;
+
+  // Handler() expects 2 args while we send it just one.
+  EXPECT_CALL(sink, Handler(_, _)).Times(0);
+  CallSignal(&sink, std::string{"bar"});
+}
+
+TEST_F(DBusSignalHandlerTest, CallSignal_Error_TypeMismatchArgs) {
+  class SignalHandlerSink {
+   public:
+    MOCK_METHOD2(Handler, void(std::string, bool));
+  } sink;
+
+  // Handler() expects "sb" while we send it "ii".
+  EXPECT_CALL(sink, Handler(_, _)).Times(0);
+  CallSignal(&sink, 1, 2);
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/exported_object_manager.cc b/libbrillo/brillo/dbus/exported_object_manager.cc
new file mode 100644
index 0000000..61dae68
--- /dev/null
+++ b/libbrillo/brillo/dbus/exported_object_manager.cc
@@ -0,0 +1,105 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/exported_object_manager.h>
+
+#include <vector>
+
+#include <brillo/dbus/async_event_sequencer.h>
+#include <dbus/object_manager.h>
+
+using brillo::dbus_utils::AsyncEventSequencer;
+
+namespace brillo {
+
+namespace dbus_utils {
+
+ExportedObjectManager::ExportedObjectManager(scoped_refptr<dbus::Bus> bus,
+                                             const dbus::ObjectPath& path)
+    : bus_(bus), dbus_object_(nullptr, bus, path) {
+}
+
+void ExportedObjectManager::RegisterAsync(
+    const AsyncEventSequencer::CompletionAction& completion_callback) {
+  VLOG(1) << "Registering object manager";
+  bus_->AssertOnOriginThread();
+  DBusInterface* itf =
+      dbus_object_.AddOrGetInterface(dbus::kObjectManagerInterface);
+  itf->AddSimpleMethodHandler(dbus::kObjectManagerGetManagedObjects,
+                              base::Unretained(this),
+                              &ExportedObjectManager::HandleGetManagedObjects);
+
+  signal_itf_added_ = itf->RegisterSignalOfType<SignalInterfacesAdded>(
+      dbus::kObjectManagerInterfacesAdded);
+  signal_itf_removed_ = itf->RegisterSignalOfType<SignalInterfacesRemoved>(
+      dbus::kObjectManagerInterfacesRemoved);
+  dbus_object_.RegisterAsync(completion_callback);
+}
+
+void ExportedObjectManager::ClaimInterface(
+    const dbus::ObjectPath& path,
+    const std::string& interface_name,
+    const ExportedPropertySet::PropertyWriter& property_writer) {
+  bus_->AssertOnOriginThread();
+  // We're sending signals that look like:
+  //   org.freedesktop.DBus.ObjectManager.InterfacesAdded (
+  //       OBJPATH object_path,
+  //       DICT<STRING,DICT<STRING,VARIANT>> interfaces_and_properties);
+  VariantDictionary property_dict;
+  property_writer.Run(&property_dict);
+  std::map<std::string, VariantDictionary> interfaces_and_properties{
+      {interface_name, property_dict}
+  };
+  signal_itf_added_.lock()->Send(path, interfaces_and_properties);
+  registered_objects_[path][interface_name] = property_writer;
+}
+
+void ExportedObjectManager::ReleaseInterface(
+    const dbus::ObjectPath& path,
+    const std::string& interface_name) {
+  bus_->AssertOnOriginThread();
+  auto interfaces_for_path_itr = registered_objects_.find(path);
+  CHECK(interfaces_for_path_itr != registered_objects_.end())
+      << "Attempting to signal interface removal for path " << path.value()
+      << " which was never registered.";
+  auto& interfaces_for_path = interfaces_for_path_itr->second;
+  auto property_for_interface_itr = interfaces_for_path.find(interface_name);
+  CHECK(property_for_interface_itr != interfaces_for_path.end())
+      << "Attempted to remove interface " << interface_name << " from "
+      << path.value() << ", but this interface was never registered.";
+  interfaces_for_path.erase(interface_name);
+  if (interfaces_for_path.empty())
+    registered_objects_.erase(path);
+
+  // We're sending signals that look like:
+  //   org.freedesktop.DBus.ObjectManager.InterfacesRemoved (
+  //       OBJPATH object_path, ARRAY<STRING> interfaces);
+  signal_itf_removed_.lock()->Send(path,
+                                   std::vector<std::string>{interface_name});
+}
+
+ExportedObjectManager::ObjectMap
+ExportedObjectManager::HandleGetManagedObjects() {
+  // Implements the GetManagedObjects method:
+  //
+  // org.freedesktop.DBus.ObjectManager.GetManagedObjects (
+  //     out DICT<OBJPATH,
+  //              DICT<STRING,
+  //                   DICT<STRING,VARIANT>>> )
+  bus_->AssertOnOriginThread();
+  ExportedObjectManager::ObjectMap objects;
+  for (const auto path_pair : registered_objects_) {
+    std::map<std::string, VariantDictionary>& interfaces =
+        objects[path_pair.first];
+    const InterfaceProperties& interface2properties = path_pair.second;
+    for (const auto interface : interface2properties) {
+      interface.second.Run(&interfaces[interface.first]);
+    }
+  }
+  return objects;
+}
+
+}  // namespace dbus_utils
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/exported_object_manager.h b/libbrillo/brillo/dbus/exported_object_manager.h
new file mode 100644
index 0000000..01dab5b
--- /dev/null
+++ b/libbrillo/brillo/dbus/exported_object_manager.h
@@ -0,0 +1,135 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_EXPORTED_OBJECT_MANAGER_H_
+#define LIBBRILLO_BRILLO_DBUS_EXPORTED_OBJECT_MANAGER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/callback.h>
+#include <base/memory/weak_ptr.h>
+#include <brillo/brillo_export.h>
+#include <brillo/dbus/dbus_object.h>
+#include <brillo/dbus/exported_property_set.h>
+#include <brillo/variant_dictionary.h>
+#include <dbus/bus.h>
+#include <dbus/exported_object.h>
+#include <dbus/message.h>
+#include <dbus/object_path.h>
+
+namespace brillo {
+
+namespace dbus_utils {
+
+// ExportedObjectManager is a delegate that implements the
+// org.freedesktop.DBus.ObjectManager interface on behalf of another
+// object. It handles sending signals when new interfaces are added.
+//
+// This class is very similar to the ExportedPropertySet class, except that
+// it allows objects to expose an object manager interface rather than the
+// properties interface.
+//
+//  Example usage:
+//
+//   class ExampleObjectManager {
+//    public:
+//     ExampleObjectManager(dbus::Bus* bus)
+//         : object_manager_(bus, "/my/objects/path") { }
+//
+//     void RegisterAsync(const CompletionAction& cb) {
+//          object_manager_.RegisterAsync(cb);
+//     }
+//     void ClaimInterface(const dbus::ObjectPath& path,
+//                         const std::string& interface_name,
+//                         const ExportedPropertySet::PropertyWriter& writer) {
+//       object_manager_->ClaimInterface(...);
+//     }
+//     void ReleaseInterface(const dbus::ObjectPath& path,
+//                           const std::string& interface_name) {
+//       object_manager_->ReleaseInterface(...);
+//     }
+//
+//    private:
+//     ExportedObjectManager object_manager_;
+//   };
+//
+//   class MyObjectClaimingAnInterface {
+//    public:
+//     MyObjectClaimingAnInterface(ExampleObjectManager* object_manager)
+//       : object_manager_(object_manager) {}
+//
+//     void OnInitFinish(bool success) {
+//       if (!success) { /* handle that */ }
+//       object_manager_->ClaimInterface(
+//           my_path_, my_interface_, my_properties_.GetWriter());
+//     }
+//
+//    private:
+//     struct Properties : public ExportedPropertySet {
+//      public:
+//       /* Lots of interesting properties. */
+//     };
+//
+//     Properties my_properties_;
+//     ExampleObjectManager* object_manager_;
+//   };
+class BRILLO_EXPORT ExportedObjectManager
+    : public base::SupportsWeakPtr<ExportedObjectManager> {
+ public:
+  using ObjectMap =
+      std::map<dbus::ObjectPath, std::map<std::string, VariantDictionary>>;
+  using InterfaceProperties =
+      std::map<std::string, ExportedPropertySet::PropertyWriter>;
+
+  ExportedObjectManager(scoped_refptr<dbus::Bus> bus,
+                        const dbus::ObjectPath& path);
+  virtual ~ExportedObjectManager() = default;
+
+  // Registers methods implementing the ObjectManager interface on the object
+  // exported on the path given in the constructor. Must be called on the
+  // origin thread.
+  virtual void RegisterAsync(
+      const brillo::dbus_utils::AsyncEventSequencer::CompletionAction&
+          completion_callback);
+
+  // Trigger a signal that |path| has added an interface |interface_name|
+  // with properties as given by |writer|.
+  virtual void ClaimInterface(
+      const dbus::ObjectPath& path,
+      const std::string& interface_name,
+      const ExportedPropertySet::PropertyWriter& writer);
+
+  // Trigger a signal that |path| has removed an interface |interface_name|.
+  virtual void ReleaseInterface(const dbus::ObjectPath& path,
+                                const std::string& interface_name);
+
+  const scoped_refptr<dbus::Bus>& GetBus() const { return bus_; }
+
+ private:
+  BRILLO_PRIVATE ObjectMap HandleGetManagedObjects();
+
+  scoped_refptr<dbus::Bus> bus_;
+  brillo::dbus_utils::DBusObject dbus_object_;
+  // Tracks all objects currently known to the ExportedObjectManager.
+  std::map<dbus::ObjectPath, InterfaceProperties> registered_objects_;
+
+  using SignalInterfacesAdded =
+      DBusSignal<dbus::ObjectPath, std::map<std::string, VariantDictionary>>;
+  using SignalInterfacesRemoved =
+      DBusSignal<dbus::ObjectPath, std::vector<std::string>>;
+
+  std::weak_ptr<SignalInterfacesAdded> signal_itf_added_;
+  std::weak_ptr<SignalInterfacesRemoved> signal_itf_removed_;
+
+  friend class ExportedObjectManagerTest;
+  DISALLOW_COPY_AND_ASSIGN(ExportedObjectManager);
+};
+
+}  // namespace dbus_utils
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_EXPORTED_OBJECT_MANAGER_H_
diff --git a/libbrillo/brillo/dbus/exported_object_manager_unittest.cc b/libbrillo/brillo/dbus/exported_object_manager_unittest.cc
new file mode 100644
index 0000000..00fe108
--- /dev/null
+++ b/libbrillo/brillo/dbus/exported_object_manager_unittest.cc
@@ -0,0 +1,194 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/exported_object_manager.h>
+
+#include <base/bind.h>
+#include <brillo/dbus/dbus_object_test_helpers.h>
+#include <brillo/dbus/utils.h>
+#include <dbus/mock_bus.h>
+#include <dbus/mock_exported_object.h>
+#include <dbus/object_manager.h>
+#include <dbus/object_path.h>
+#include <gtest/gtest.h>
+
+using ::testing::AnyNumber;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::_;
+
+namespace brillo {
+
+namespace dbus_utils {
+
+namespace {
+
+const dbus::ObjectPath kTestPath(std::string("/test/om_path"));
+const dbus::ObjectPath kClaimedTestPath(std::string("/test/claimed_path"));
+const std::string kClaimedInterface("claimed.interface");
+const std::string kTestPropertyName("PropertyName");
+const std::string kTestPropertyValue("PropertyValue");
+
+void WriteTestPropertyDict(VariantDictionary* dict) {
+  dict->insert(std::make_pair(kTestPropertyName, Any(kTestPropertyValue)));
+}
+
+void ReadTestPropertyDict(dbus::MessageReader* reader) {
+  dbus::MessageReader all_properties(nullptr);
+  dbus::MessageReader each_property(nullptr);
+  ASSERT_TRUE(reader->PopArray(&all_properties));
+  ASSERT_TRUE(all_properties.PopDictEntry(&each_property));
+  std::string property_name;
+  std::string property_value;
+  ASSERT_TRUE(each_property.PopString(&property_name));
+  ASSERT_TRUE(each_property.PopVariantOfString(&property_value));
+  EXPECT_FALSE(each_property.HasMoreData());
+  EXPECT_FALSE(all_properties.HasMoreData());
+  EXPECT_EQ(property_name, kTestPropertyName);
+  EXPECT_EQ(property_value, kTestPropertyValue);
+}
+
+void VerifyInterfaceClaimSignal(dbus::Signal* signal) {
+  EXPECT_EQ(signal->GetInterface(), std::string(dbus::kObjectManagerInterface));
+  EXPECT_EQ(signal->GetMember(),
+            std::string(dbus::kObjectManagerInterfacesAdded));
+  //   org.freedesktop.DBus.ObjectManager.InterfacesAdded (
+  //       OBJPATH object_path,
+  //       DICT<STRING,DICT<STRING,VARIANT>> interfaces_and_properties);
+  dbus::MessageReader reader(signal);
+  dbus::MessageReader all_interfaces(nullptr);
+  dbus::MessageReader each_interface(nullptr);
+  dbus::ObjectPath path;
+  ASSERT_TRUE(reader.PopObjectPath(&path));
+  ASSERT_TRUE(reader.PopArray(&all_interfaces));
+  ASSERT_TRUE(all_interfaces.PopDictEntry(&each_interface));
+  std::string interface_name;
+  ASSERT_TRUE(each_interface.PopString(&interface_name));
+  ReadTestPropertyDict(&each_interface);
+  EXPECT_FALSE(each_interface.HasMoreData());
+  EXPECT_FALSE(all_interfaces.HasMoreData());
+  EXPECT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(interface_name, kClaimedInterface);
+  EXPECT_EQ(path, kClaimedTestPath);
+}
+
+void VerifyInterfaceDropSignal(dbus::Signal* signal) {
+  EXPECT_EQ(signal->GetInterface(), std::string(dbus::kObjectManagerInterface));
+  EXPECT_EQ(signal->GetMember(),
+            std::string(dbus::kObjectManagerInterfacesRemoved));
+  //   org.freedesktop.DBus.ObjectManager.InterfacesRemoved (
+  //       OBJPATH object_path, ARRAY<STRING> interfaces);
+  dbus::MessageReader reader(signal);
+  dbus::MessageReader each_interface(nullptr);
+  dbus::ObjectPath path;
+  ASSERT_TRUE(reader.PopObjectPath(&path));
+  ASSERT_TRUE(reader.PopArray(&each_interface));
+  std::string interface_name;
+  ASSERT_TRUE(each_interface.PopString(&interface_name));
+  EXPECT_FALSE(each_interface.HasMoreData());
+  EXPECT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(interface_name, kClaimedInterface);
+  EXPECT_EQ(path, kClaimedTestPath);
+}
+
+}  // namespace
+
+class ExportedObjectManagerTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    dbus::Bus::Options options;
+    options.bus_type = dbus::Bus::SYSTEM;
+    bus_ = new dbus::MockBus(options);
+    // By default, don't worry about threading assertions.
+    EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
+    EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
+    // Use a mock exported object.
+    mock_exported_object_ = new dbus::MockExportedObject(bus_.get(), kTestPath);
+    EXPECT_CALL(*bus_, GetExportedObject(kTestPath)).Times(1).WillOnce(
+        Return(mock_exported_object_.get()));
+    EXPECT_CALL(*mock_exported_object_, ExportMethod(_, _, _, _))
+        .Times(AnyNumber());
+    om_.reset(new ExportedObjectManager(bus_.get(), kTestPath));
+    property_writer_ = base::Bind(&WriteTestPropertyDict);
+    om_->RegisterAsync(AsyncEventSequencer::GetDefaultCompletionAction());
+  }
+
+  void TearDown() override {
+    EXPECT_CALL(*mock_exported_object_, Unregister()).Times(1);
+    om_.reset();
+    bus_ = nullptr;
+  }
+
+  std::unique_ptr<dbus::Response> CallHandleGetManagedObjects() {
+    dbus::MethodCall method_call(dbus::kObjectManagerInterface,
+                                 dbus::kObjectManagerGetManagedObjects);
+    method_call.SetSerial(1234);
+    return brillo::dbus_utils::testing::CallMethod(om_->dbus_object_,
+                                                   &method_call);
+  }
+
+  scoped_refptr<dbus::MockBus> bus_;
+  scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
+  std::unique_ptr<ExportedObjectManager> om_;
+  ExportedPropertySet::PropertyWriter property_writer_;
+};
+
+TEST_F(ExportedObjectManagerTest, ClaimInterfaceSendsSignals) {
+  EXPECT_CALL(*mock_exported_object_, SendSignal(_))
+      .Times(1).WillOnce(Invoke(&VerifyInterfaceClaimSignal));
+  om_->ClaimInterface(kClaimedTestPath, kClaimedInterface, property_writer_);
+}
+
+TEST_F(ExportedObjectManagerTest, ReleaseInterfaceSendsSignals) {
+  InSequence dummy;
+  EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(1);
+  EXPECT_CALL(*mock_exported_object_, SendSignal(_))
+      .Times(1).WillOnce(Invoke(&VerifyInterfaceDropSignal));
+  om_->ClaimInterface(kClaimedTestPath, kClaimedInterface, property_writer_);
+  om_->ReleaseInterface(kClaimedTestPath, kClaimedInterface);
+}
+
+TEST_F(ExportedObjectManagerTest, GetManagedObjectsResponseEmptyCorrectness) {
+  auto response = CallHandleGetManagedObjects();
+  dbus::MessageReader reader(response.get());
+  dbus::MessageReader all_paths(nullptr);
+  ASSERT_TRUE(reader.PopArray(&all_paths));
+  EXPECT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedObjectManagerTest, GetManagedObjectsResponseCorrectness) {
+  // org.freedesktop.DBus.ObjectManager.GetManagedObjects (
+  //     out DICT<OBJPATH,
+  //              DICT<STRING,
+  //                   DICT<STRING,VARIANT>>> )
+  EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(1);
+  om_->ClaimInterface(kClaimedTestPath, kClaimedInterface, property_writer_);
+  auto response = CallHandleGetManagedObjects();
+  dbus::MessageReader reader(response.get());
+  dbus::MessageReader all_paths(nullptr);
+  dbus::MessageReader each_path(nullptr);
+  dbus::MessageReader all_interfaces(nullptr);
+  dbus::MessageReader each_interface(nullptr);
+  ASSERT_TRUE(reader.PopArray(&all_paths));
+  ASSERT_TRUE(all_paths.PopDictEntry(&each_path));
+  dbus::ObjectPath path;
+  ASSERT_TRUE(each_path.PopObjectPath(&path));
+  ASSERT_TRUE(each_path.PopArray(&all_interfaces));
+  ASSERT_TRUE(all_interfaces.PopDictEntry(&each_interface));
+  std::string interface_name;
+  ASSERT_TRUE(each_interface.PopString(&interface_name));
+  ReadTestPropertyDict(&each_interface);
+  EXPECT_FALSE(each_interface.HasMoreData());
+  EXPECT_FALSE(all_interfaces.HasMoreData());
+  EXPECT_FALSE(each_path.HasMoreData());
+  EXPECT_FALSE(all_paths.HasMoreData());
+  EXPECT_FALSE(reader.HasMoreData());
+  EXPECT_EQ(path, kClaimedTestPath);
+  EXPECT_EQ(interface_name, kClaimedInterface);
+}
+
+}  // namespace dbus_utils
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/exported_property_set.cc b/libbrillo/brillo/dbus/exported_property_set.cc
new file mode 100644
index 0000000..8d6ae65
--- /dev/null
+++ b/libbrillo/brillo/dbus/exported_property_set.cc
@@ -0,0 +1,174 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/exported_property_set.h>
+
+#include <base/bind.h>
+#include <dbus/bus.h>
+#include <dbus/property.h>  // For kPropertyInterface
+
+#include <brillo/dbus/async_event_sequencer.h>
+#include <brillo/dbus/dbus_object.h>
+#include <brillo/errors/error_codes.h>
+
+using brillo::dbus_utils::AsyncEventSequencer;
+
+namespace brillo {
+
+namespace dbus_utils {
+
+ExportedPropertySet::ExportedPropertySet(dbus::Bus* bus)
+    : bus_(bus), weak_ptr_factory_(this) {
+}
+
+void ExportedPropertySet::OnPropertiesInterfaceExported(
+    DBusInterface* prop_interface) {
+  signal_properties_changed_ =
+      prop_interface->RegisterSignalOfType<SignalPropertiesChanged>(
+          dbus::kPropertiesChanged);
+}
+
+ExportedPropertySet::PropertyWriter ExportedPropertySet::GetPropertyWriter(
+    const std::string& interface_name) {
+  return base::Bind(&ExportedPropertySet::WritePropertiesToDict,
+                    weak_ptr_factory_.GetWeakPtr(),
+                    interface_name);
+}
+
+void ExportedPropertySet::RegisterProperty(
+    const std::string& interface_name,
+    const std::string& property_name,
+    ExportedPropertyBase* exported_property) {
+  bus_->AssertOnOriginThread();
+  auto& prop_map = properties_[interface_name];
+  auto res = prop_map.insert(std::make_pair(property_name, exported_property));
+  CHECK(res.second) << "Property '" << property_name << "' already exists";
+  // Technically, the property set exists longer than the properties themselves,
+  // so we could use Unretained here rather than a weak pointer.
+  ExportedPropertyBase::OnUpdateCallback cb =
+      base::Bind(&ExportedPropertySet::HandlePropertyUpdated,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 interface_name,
+                 property_name);
+  exported_property->SetUpdateCallback(cb);
+}
+
+VariantDictionary ExportedPropertySet::HandleGetAll(
+    const std::string& interface_name) {
+  bus_->AssertOnOriginThread();
+  return GetInterfaceProperties(interface_name);
+}
+
+VariantDictionary ExportedPropertySet::GetInterfaceProperties(
+    const std::string& interface_name) const {
+  VariantDictionary properties;
+  auto property_map_itr = properties_.find(interface_name);
+  if (property_map_itr != properties_.end()) {
+    for (const auto& kv : property_map_itr->second)
+      properties.insert(std::make_pair(kv.first, kv.second->GetValue()));
+  }
+  return properties;
+}
+
+void ExportedPropertySet::WritePropertiesToDict(
+    const std::string& interface_name,
+    VariantDictionary* dict) {
+  *dict = GetInterfaceProperties(interface_name);
+}
+
+bool ExportedPropertySet::HandleGet(brillo::ErrorPtr* error,
+                                    const std::string& interface_name,
+                                    const std::string& property_name,
+                                    brillo::Any* result) {
+  bus_->AssertOnOriginThread();
+  auto property_map_itr = properties_.find(interface_name);
+  if (property_map_itr == properties_.end()) {
+    brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+                         DBUS_ERROR_UNKNOWN_INTERFACE,
+                         "No such interface on object.");
+    return false;
+  }
+  LOG(INFO) << "Looking for " << property_name << " on " << interface_name;
+  auto property_itr = property_map_itr->second.find(property_name);
+  if (property_itr == property_map_itr->second.end()) {
+    brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+                         DBUS_ERROR_UNKNOWN_PROPERTY,
+                         "No such property on interface.");
+    return false;
+  }
+  *result = property_itr->second->GetValue();
+  return true;
+}
+
+bool ExportedPropertySet::HandleSet(brillo::ErrorPtr* error,
+                                    const std::string& interface_name,
+                                    const std::string& property_name,
+                                    const brillo::Any& value) {
+  bus_->AssertOnOriginThread();
+  auto property_map_itr = properties_.find(interface_name);
+  if (property_map_itr == properties_.end()) {
+    brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+                         DBUS_ERROR_UNKNOWN_INTERFACE,
+                         "No such interface on object.");
+    return false;
+  }
+  LOG(INFO) << "Looking for " << property_name << " on " << interface_name;
+  auto property_itr = property_map_itr->second.find(property_name);
+  if (property_itr == property_map_itr->second.end()) {
+    brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+                         DBUS_ERROR_UNKNOWN_PROPERTY,
+                         "No such property on interface.");
+    return false;
+  }
+
+  return property_itr->second->SetValue(error, value);
+}
+
+void ExportedPropertySet::HandlePropertyUpdated(
+    const std::string& interface_name,
+    const std::string& property_name,
+    const ExportedPropertyBase* exported_property) {
+  bus_->AssertOnOriginThread();
+  // Send signal only if the object has been exported successfully.
+  // This could happen when a property value is changed (which triggers
+  // the notification) before D-Bus interface is completely exported/claimed.
+  auto signal = signal_properties_changed_.lock();
+  if (!signal)
+    return;
+  VariantDictionary changed_properties{
+      {property_name, exported_property->GetValue()}};
+  // The interface specification tells us to include this list of properties
+  // which have changed, but for whom no value is conveyed.  Currently, we
+  // don't do anything interesting here.
+  std::vector<std::string> invalidated_properties;  // empty.
+  signal->Send(interface_name, changed_properties, invalidated_properties);
+}
+
+void ExportedPropertyBase::NotifyPropertyChanged() {
+  // These is a brief period after the construction of an ExportedProperty
+  // when this callback is not initialized because the property has not
+  // been registered with the parent ExportedPropertySet.  During this period
+  // users should be initializing values via SetValue, and no notifications
+  // should be triggered by the ExportedPropertySet.
+  if (!on_update_callback_.is_null()) {
+    on_update_callback_.Run(this);
+  }
+}
+
+void ExportedPropertyBase::SetUpdateCallback(const OnUpdateCallback& cb) {
+  on_update_callback_ = cb;
+}
+
+void ExportedPropertyBase::SetAccessMode(
+    ExportedPropertyBase::Access access_mode) {
+  access_mode_ = access_mode;
+}
+
+ExportedPropertyBase::Access ExportedPropertyBase::GetAccessMode() const {
+  return access_mode_;
+}
+
+}  // namespace dbus_utils
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/exported_property_set.h b/libbrillo/brillo/dbus/exported_property_set.h
new file mode 100644
index 0000000..f10511f
--- /dev/null
+++ b/libbrillo/brillo/dbus/exported_property_set.h
@@ -0,0 +1,226 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_EXPORTED_PROPERTY_SET_H_
+#define LIBBRILLO_BRILLO_DBUS_EXPORTED_PROPERTY_SET_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/memory/weak_ptr.h>
+#include <brillo/any.h>
+#include <brillo/brillo_export.h>
+#include <brillo/dbus/dbus_signal.h>
+#include <brillo/errors/error.h>
+#include <brillo/errors/error_codes.h>
+#include <brillo/variant_dictionary.h>
+#include <dbus/exported_object.h>
+#include <dbus/message.h>
+
+namespace brillo {
+
+namespace dbus_utils {
+
+// This class may be used to implement the org.freedesktop.DBus.Properties
+// interface.  It sends the update signal on property updates:
+//
+//   org.freedesktop.DBus.Properties.PropertiesChanged (
+//       STRING interface_name,
+//       DICT<STRING,VARIANT> changed_properties,
+//       ARRAY<STRING> invalidated_properties);
+//
+//
+// and implements the required methods of the interface:
+//
+//   org.freedesktop.DBus.Properties.Get(in STRING interface_name,
+//                                       in STRING property_name,
+//                                       out VARIANT value);
+//   org.freedesktop.DBus.Properties.Set(in STRING interface_name,
+//                                       in STRING property_name,
+//                                       in VARIANT value);
+//   org.freedesktop.DBus.Properties.GetAll(in STRING interface_name,
+//                                          out DICT<STRING,VARIANT> props);
+//
+//  This class is very similar to the PropertySet class in Chrome, except that
+//  it allows objects to expose properties rather than to consume them.
+//  It is used as part of DBusObject to implement D-Bus object properties on
+//  registered interfaces. See description of DBusObject class for more details.
+
+class DBusInterface;
+class DBusObject;
+
+class BRILLO_EXPORT ExportedPropertyBase {
+ public:
+  enum class Access {
+    kReadOnly,
+    kWriteOnly,
+    kReadWrite,
+  };
+
+  ExportedPropertyBase() = default;
+  virtual ~ExportedPropertyBase() = default;
+
+  using OnUpdateCallback = base::Callback<void(const ExportedPropertyBase*)>;
+
+  // Called by ExportedPropertySet to register a callback.  This callback
+  // triggers ExportedPropertySet to send a signal from the properties
+  // interface of the exported object.
+  virtual void SetUpdateCallback(const OnUpdateCallback& cb);
+
+  // Returns the contained value as Any.
+  virtual brillo::Any GetValue() const = 0;
+
+  virtual bool SetValue(brillo::ErrorPtr* error,
+                        const brillo::Any& value) = 0;
+
+  void SetAccessMode(Access access_mode);
+  Access GetAccessMode() const;
+
+ protected:
+  // Notify the listeners of OnUpdateCallback that the property has changed.
+  void NotifyPropertyChanged();
+
+ private:
+  OnUpdateCallback on_update_callback_;
+  // Default to read-only.
+  Access access_mode_{Access::kReadOnly};
+};
+
+class BRILLO_EXPORT ExportedPropertySet {
+ public:
+  using PropertyWriter = base::Callback<void(VariantDictionary* dict)>;
+
+  explicit ExportedPropertySet(dbus::Bus* bus);
+  virtual ~ExportedPropertySet() = default;
+
+  // Called to notify ExportedPropertySet that the Properties interface of the
+  // D-Bus object has been exported successfully and property notification
+  // signals can be sent out.
+  void OnPropertiesInterfaceExported(DBusInterface* prop_interface);
+
+  // Return a callback that knows how to write this property set's properties
+  // to a message.  This writer retains a weak pointer to this, and must
+  // only be invoked on the same thread as the rest of ExportedPropertySet.
+  PropertyWriter GetPropertyWriter(const std::string& interface_name);
+
+  void RegisterProperty(const std::string& interface_name,
+                        const std::string& property_name,
+                        ExportedPropertyBase* exported_property);
+
+  // D-Bus methods for org.freedesktop.DBus.Properties interface.
+  VariantDictionary HandleGetAll(const std::string& interface_name);
+  bool HandleGet(brillo::ErrorPtr* error,
+                 const std::string& interface_name,
+                 const std::string& property_name,
+                 brillo::Any* result);
+  // While Properties.Set has a handler to complete the interface,  we don't
+  // support writable properties.  This is almost a feature, since bindings for
+  // many languages don't support errors coming back from invalid writes.
+  // Instead, use setters in exposed interfaces.
+  bool HandleSet(brillo::ErrorPtr* error,
+                 const std::string& interface_name,
+                 const std::string& property_name,
+                 const brillo::Any& value);
+  // Returns a string-to-variant map of all the properties for the given
+  // interface and their values.
+  VariantDictionary GetInterfaceProperties(
+      const std::string& interface_name) const;
+
+ private:
+  // Used to write the dictionary of string->variant to a message.
+  // This dictionary represents the property name/value pairs for the
+  // given interface.
+  BRILLO_PRIVATE void WritePropertiesToDict(const std::string& interface_name,
+                                            VariantDictionary* dict);
+  BRILLO_PRIVATE void HandlePropertyUpdated(
+      const std::string& interface_name,
+      const std::string& property_name,
+      const ExportedPropertyBase* exported_property);
+
+  dbus::Bus* bus_;  // weak; owned by outer DBusObject containing this object.
+  // This is a map from interface name -> property name -> pointer to property.
+  std::map<std::string, std::map<std::string, ExportedPropertyBase*>>
+      properties_;
+
+  // D-Bus callbacks may last longer the property set exporting those methods.
+  base::WeakPtrFactory<ExportedPropertySet> weak_ptr_factory_;
+
+  using SignalPropertiesChanged =
+      DBusSignal<std::string, VariantDictionary, std::vector<std::string>>;
+
+  std::weak_ptr<SignalPropertiesChanged> signal_properties_changed_;
+
+  friend class DBusObject;
+  friend class ExportedPropertySetTest;
+  DISALLOW_COPY_AND_ASSIGN(ExportedPropertySet);
+};
+
+template<typename T>
+class ExportedProperty : public ExportedPropertyBase {
+ public:
+  ExportedProperty() = default;
+  ~ExportedProperty() override = default;
+
+  // Retrieves the current value.
+  const T& value() const { return value_; }
+
+  // Set the value exposed to remote applications.  This triggers notifications
+  // of changes over the Properties interface.
+  void SetValue(const T& new_value) {
+    if (value_ != new_value) {
+      value_ = new_value;
+      this->NotifyPropertyChanged();
+    }
+  }
+
+  // Set the validator for value checking when setting the property by remote
+  // application.
+  void SetValidator(
+      const base::Callback<bool(brillo::ErrorPtr*, const T&)>& validator) {
+    validator_ = validator;
+  }
+
+  // Implementation provided by specialization.
+  brillo::Any GetValue() const override { return value_; }
+
+  bool SetValue(brillo::ErrorPtr* error,
+                const brillo::Any& value) override {
+    if (GetAccessMode() == ExportedPropertyBase::Access::kReadOnly) {
+      brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+                           DBUS_ERROR_PROPERTY_READ_ONLY,
+                           "Property is read-only.");
+      return false;
+    }
+    if (!value.IsTypeCompatible<T>()) {
+      brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+                           DBUS_ERROR_INVALID_ARGS,
+                           "Argument type mismatched.");
+      return false;
+    }
+    if (value_ == value.Get<T>()) {
+      // No change to the property value, nothing to be done.
+      return true;
+    }
+    if (!validator_.is_null() && !validator_.Run(error, value.Get<T>())) {
+      return false;
+    }
+    value_ = value.Get<T>();
+    return true;
+  }
+
+ private:
+  T value_{};
+  base::Callback<bool(brillo::ErrorPtr*, const T&)> validator_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExportedProperty);
+};
+
+}  // namespace dbus_utils
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_EXPORTED_PROPERTY_SET_H_
diff --git a/libbrillo/brillo/dbus/exported_property_set_unittest.cc b/libbrillo/brillo/dbus/exported_property_set_unittest.cc
new file mode 100644
index 0000000..9233b4a
--- /dev/null
+++ b/libbrillo/brillo/dbus/exported_property_set_unittest.cc
@@ -0,0 +1,592 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/exported_property_set.h>
+
+#include <string>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/macros.h>
+#include <brillo/dbus/dbus_object.h>
+#include <brillo/dbus/dbus_object_test_helpers.h>
+#include <brillo/errors/error_codes.h>
+#include <dbus/message.h>
+#include <dbus/property.h>
+#include <dbus/object_path.h>
+#include <dbus/mock_bus.h>
+#include <dbus/mock_exported_object.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using ::testing::AnyNumber;
+using ::testing::Return;
+using ::testing::Invoke;
+using ::testing::_;
+using ::testing::Unused;
+
+namespace brillo {
+
+namespace dbus_utils {
+
+namespace {
+
+const char kBoolPropName[] = "BoolProp";
+const char kUint8PropName[] = "Uint8Prop";
+const char kInt16PropName[] = "Int16Prop";
+const char kUint16PropName[] = "Uint16Prop";
+const char kInt32PropName[] = "Int32Prop";
+const char kUint32PropName[] = "Uint32Prop";
+const char kInt64PropName[] = "Int64Prop";
+const char kUint64PropName[] = "Uint64Prop";
+const char kDoublePropName[] = "DoubleProp";
+const char kStringPropName[] = "StringProp";
+const char kPathPropName[] = "PathProp";
+const char kStringListPropName[] = "StringListProp";
+const char kPathListPropName[] = "PathListProp";
+const char kUint8ListPropName[] = "Uint8ListProp";
+
+const char kTestInterface1[] = "org.chromium.TestInterface1";
+const char kTestInterface2[] = "org.chromium.TestInterface2";
+const char kTestInterface3[] = "org.chromium.TestInterface3";
+
+const std::string kTestString("lies");
+const dbus::ObjectPath kMethodsExportedOnPath(std::string("/export"));
+const dbus::ObjectPath kTestObjectPathInit(std::string("/path_init"));
+const dbus::ObjectPath kTestObjectPathUpdate(std::string("/path_update"));
+
+}  // namespace
+
+class ExportedPropertySetTest : public ::testing::Test {
+ public:
+  struct Properties {
+   public:
+    ExportedProperty<bool> bool_prop_;
+    ExportedProperty<uint8_t> uint8_prop_;
+    ExportedProperty<int16_t> int16_prop_;
+    ExportedProperty<uint16_t> uint16_prop_;
+    ExportedProperty<int32_t> int32_prop_;
+    ExportedProperty<uint32_t> uint32_prop_;
+    ExportedProperty<int64_t> int64_prop_;
+    ExportedProperty<uint64_t> uint64_prop_;
+    ExportedProperty<double> double_prop_;
+    ExportedProperty<std::string> string_prop_;
+    ExportedProperty<dbus::ObjectPath> path_prop_;
+    ExportedProperty<std::vector<std::string>> stringlist_prop_;
+    ExportedProperty<std::vector<dbus::ObjectPath>> pathlist_prop_;
+    ExportedProperty<std::vector<uint8_t>> uint8list_prop_;
+
+    Properties(scoped_refptr<dbus::Bus> bus, const dbus::ObjectPath& path)
+        : dbus_object_(nullptr, bus, path) {
+      // The empty string is not a valid value for an ObjectPath.
+      path_prop_.SetValue(kTestObjectPathInit);
+      DBusInterface* itf1 = dbus_object_.AddOrGetInterface(kTestInterface1);
+      itf1->AddProperty(kBoolPropName, &bool_prop_);
+      itf1->AddProperty(kUint8PropName, &uint8_prop_);
+      itf1->AddProperty(kInt16PropName, &int16_prop_);
+      // I chose this weird grouping because N=2 is about all the permutations
+      // of GetAll that I want to anticipate.
+      DBusInterface* itf2 = dbus_object_.AddOrGetInterface(kTestInterface2);
+      itf2->AddProperty(kUint16PropName, &uint16_prop_);
+      itf2->AddProperty(kInt32PropName, &int32_prop_);
+      DBusInterface* itf3 = dbus_object_.AddOrGetInterface(kTestInterface3);
+      itf3->AddProperty(kUint32PropName, &uint32_prop_);
+      itf3->AddProperty(kInt64PropName, &int64_prop_);
+      itf3->AddProperty(kUint64PropName, &uint64_prop_);
+      itf3->AddProperty(kDoublePropName, &double_prop_);
+      itf3->AddProperty(kStringPropName, &string_prop_);
+      itf3->AddProperty(kPathPropName, &path_prop_);
+      itf3->AddProperty(kStringListPropName, &stringlist_prop_);
+      itf3->AddProperty(kPathListPropName, &pathlist_prop_);
+      itf3->AddProperty(kUint8ListPropName, &uint8list_prop_);
+      dbus_object_.RegisterAsync(
+          AsyncEventSequencer::GetDefaultCompletionAction());
+    }
+    virtual ~Properties() {}
+
+    DBusObject dbus_object_;
+  };
+
+  void SetUp() override {
+    dbus::Bus::Options options;
+    options.bus_type = dbus::Bus::SYSTEM;
+    bus_ = new dbus::MockBus(options);
+    // By default, don't worry about threading assertions.
+    EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
+    EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
+    // Use a mock exported object.
+    mock_exported_object_ =
+        new dbus::MockExportedObject(bus_.get(), kMethodsExportedOnPath);
+    EXPECT_CALL(*bus_, GetExportedObject(kMethodsExportedOnPath))
+        .Times(1).WillOnce(Return(mock_exported_object_.get()));
+
+    EXPECT_CALL(*mock_exported_object_,
+                ExportMethod(dbus::kPropertiesInterface, _, _, _)).Times(3);
+    p_.reset(new Properties(bus_, kMethodsExportedOnPath));
+  }
+
+  void TearDown() override {
+    EXPECT_CALL(*mock_exported_object_, Unregister()).Times(1);
+  }
+
+  void AssertMethodReturnsError(dbus::MethodCall* method_call) {
+    method_call->SetSerial(123);
+    auto response = testing::CallMethod(p_->dbus_object_, method_call);
+    ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+  }
+
+  std::unique_ptr<dbus::Response> GetPropertyOnInterface(
+      const std::string& interface_name,
+      const std::string& property_name) {
+    dbus::MethodCall method_call(dbus::kPropertiesInterface,
+                                 dbus::kPropertiesGet);
+    method_call.SetSerial(123);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendString(interface_name);
+    writer.AppendString(property_name);
+    return testing::CallMethod(p_->dbus_object_, &method_call);
+  }
+
+  std::unique_ptr<dbus::Response> SetPropertyOnInterface(
+      const std::string& interface_name,
+      const std::string& property_name,
+      const brillo::Any& value) {
+    dbus::MethodCall method_call(dbus::kPropertiesInterface,
+                                 dbus::kPropertiesSet);
+    method_call.SetSerial(123);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendString(interface_name);
+    writer.AppendString(property_name);
+    dbus_utils::AppendValueToWriter(&writer, value);
+    return testing::CallMethod(p_->dbus_object_, &method_call);
+  }
+
+  std::unique_ptr<dbus::Response> last_response_;
+  scoped_refptr<dbus::MockBus> bus_;
+  scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
+  std::unique_ptr<Properties> p_;
+};
+
+template<typename T>
+class PropertyValidatorObserver {
+ public:
+  PropertyValidatorObserver()
+      : validate_property_callback_(
+            base::Bind(&PropertyValidatorObserver::ValidateProperty,
+                       base::Unretained(this))) {}
+  virtual ~PropertyValidatorObserver() {}
+
+  MOCK_METHOD2_T(ValidateProperty,
+                 bool(brillo::ErrorPtr* error, const T& value));
+
+  const base::Callback<bool(brillo::ErrorPtr*, const T&)>&
+  validate_property_callback() const {
+    return validate_property_callback_;
+  }
+
+ private:
+  base::Callback<bool(brillo::ErrorPtr*, const T&)>
+      validate_property_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(PropertyValidatorObserver);
+};
+
+TEST_F(ExportedPropertySetTest, UpdateNotifications) {
+  EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(14);
+  p_->bool_prop_.SetValue(true);
+  p_->uint8_prop_.SetValue(1);
+  p_->int16_prop_.SetValue(1);
+  p_->uint16_prop_.SetValue(1);
+  p_->int32_prop_.SetValue(1);
+  p_->uint32_prop_.SetValue(1);
+  p_->int64_prop_.SetValue(1);
+  p_->uint64_prop_.SetValue(1);
+  p_->double_prop_.SetValue(1.0);
+  p_->string_prop_.SetValue(kTestString);
+  p_->path_prop_.SetValue(kTestObjectPathUpdate);
+  p_->stringlist_prop_.SetValue({kTestString});
+  p_->pathlist_prop_.SetValue({kTestObjectPathUpdate});
+  p_->uint8list_prop_.SetValue({1});
+}
+
+TEST_F(ExportedPropertySetTest, UpdateToSameValue) {
+  EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(1);
+  p_->bool_prop_.SetValue(true);
+  p_->bool_prop_.SetValue(true);
+}
+
+TEST_F(ExportedPropertySetTest, GetAllNoArgs) {
+  dbus::MethodCall method_call(dbus::kPropertiesInterface,
+                               dbus::kPropertiesGetAll);
+  AssertMethodReturnsError(&method_call);
+}
+
+TEST_F(ExportedPropertySetTest, GetAllInvalidInterface) {
+  dbus::MethodCall method_call(dbus::kPropertiesInterface,
+                               dbus::kPropertiesGetAll);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString("org.chromium.BadInterface");
+  auto response = testing::CallMethod(p_->dbus_object_, &method_call);
+  dbus::MessageReader response_reader(response.get());
+  dbus::MessageReader dict_reader(nullptr);
+  ASSERT_TRUE(response_reader.PopArray(&dict_reader));
+  // The response should just be a an empty array, since there are no properties
+  // on this interface.  The spec doesn't say much about error conditions here,
+  // so I'm going to assume this is a valid implementation.
+  ASSERT_FALSE(dict_reader.HasMoreData());
+  ASSERT_FALSE(response_reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetAllExtraArgs) {
+  dbus::MethodCall method_call(dbus::kPropertiesInterface,
+                               dbus::kPropertiesGetAll);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString(kTestInterface1);
+  writer.AppendString(kTestInterface1);
+  AssertMethodReturnsError(&method_call);
+}
+
+TEST_F(ExportedPropertySetTest, GetAllCorrectness) {
+  dbus::MethodCall method_call(dbus::kPropertiesInterface,
+                               dbus::kPropertiesGetAll);
+  method_call.SetSerial(123);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString(kTestInterface2);
+  auto response = testing::CallMethod(p_->dbus_object_, &method_call);
+  dbus::MessageReader response_reader(response.get());
+  dbus::MessageReader dict_reader(nullptr);
+  dbus::MessageReader entry_reader(nullptr);
+  ASSERT_TRUE(response_reader.PopArray(&dict_reader));
+  ASSERT_TRUE(dict_reader.PopDictEntry(&entry_reader));
+  std::string property_name;
+  ASSERT_TRUE(entry_reader.PopString(&property_name));
+  uint16_t value16;
+  int32_t value32;
+  if (property_name.compare(kUint16PropName) == 0) {
+    ASSERT_TRUE(entry_reader.PopVariantOfUint16(&value16));
+    ASSERT_FALSE(entry_reader.HasMoreData());
+    ASSERT_TRUE(dict_reader.PopDictEntry(&entry_reader));
+    ASSERT_TRUE(entry_reader.PopString(&property_name));
+    ASSERT_EQ(property_name.compare(kInt32PropName), 0);
+    ASSERT_TRUE(entry_reader.PopVariantOfInt32(&value32));
+  } else {
+    ASSERT_EQ(property_name.compare(kInt32PropName), 0);
+    ASSERT_TRUE(entry_reader.PopVariantOfInt32(&value32));
+    ASSERT_FALSE(entry_reader.HasMoreData());
+    ASSERT_TRUE(dict_reader.PopDictEntry(&entry_reader));
+    ASSERT_TRUE(entry_reader.PopString(&property_name));
+    ASSERT_EQ(property_name.compare(kUint16PropName), 0);
+    ASSERT_TRUE(entry_reader.PopVariantOfUint16(&value16));
+  }
+  ASSERT_FALSE(entry_reader.HasMoreData());
+  ASSERT_FALSE(dict_reader.HasMoreData());
+  ASSERT_FALSE(response_reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetNoArgs) {
+  dbus::MethodCall method_call(dbus::kPropertiesInterface,
+                               dbus::kPropertiesGet);
+  AssertMethodReturnsError(&method_call);
+}
+
+TEST_F(ExportedPropertySetTest, GetInvalidInterface) {
+  dbus::MethodCall method_call(dbus::kPropertiesInterface,
+                               dbus::kPropertiesGet);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString("org.chromium.BadInterface");
+  writer.AppendString(kInt16PropName);
+  AssertMethodReturnsError(&method_call);
+}
+
+TEST_F(ExportedPropertySetTest, GetBadPropertyName) {
+  dbus::MethodCall method_call(dbus::kPropertiesInterface,
+                               dbus::kPropertiesGet);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString(kTestInterface1);
+  writer.AppendString("IAmNotAProperty");
+  AssertMethodReturnsError(&method_call);
+}
+
+TEST_F(ExportedPropertySetTest, GetPropIfMismatch) {
+  dbus::MethodCall method_call(dbus::kPropertiesInterface,
+                               dbus::kPropertiesGet);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString(kTestInterface1);
+  writer.AppendString(kStringPropName);
+  AssertMethodReturnsError(&method_call);
+}
+
+TEST_F(ExportedPropertySetTest, GetNoPropertyName) {
+  dbus::MethodCall method_call(dbus::kPropertiesInterface,
+                               dbus::kPropertiesGet);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString(kTestInterface1);
+  AssertMethodReturnsError(&method_call);
+}
+
+TEST_F(ExportedPropertySetTest, GetExtraArgs) {
+  dbus::MethodCall method_call(dbus::kPropertiesInterface,
+                               dbus::kPropertiesGet);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendString(kTestInterface1);
+  writer.AppendString(kBoolPropName);
+  writer.AppendString("Extra param");
+  AssertMethodReturnsError(&method_call);
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithBool) {
+  auto response = GetPropertyOnInterface(kTestInterface1, kBoolPropName);
+  dbus::MessageReader reader(response.get());
+  bool value;
+  ASSERT_TRUE(reader.PopVariantOfBool(&value));
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithUint8) {
+  auto response = GetPropertyOnInterface(kTestInterface1, kUint8PropName);
+  dbus::MessageReader reader(response.get());
+  uint8_t value;
+  ASSERT_TRUE(reader.PopVariantOfByte(&value));
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithInt16) {
+  auto response = GetPropertyOnInterface(kTestInterface1, kInt16PropName);
+  dbus::MessageReader reader(response.get());
+  int16_t value;
+  ASSERT_TRUE(reader.PopVariantOfInt16(&value));
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithUint16) {
+  auto response = GetPropertyOnInterface(kTestInterface2, kUint16PropName);
+  dbus::MessageReader reader(response.get());
+  uint16_t value;
+  ASSERT_TRUE(reader.PopVariantOfUint16(&value));
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithInt32) {
+  auto response = GetPropertyOnInterface(kTestInterface2, kInt32PropName);
+  dbus::MessageReader reader(response.get());
+  int32_t value;
+  ASSERT_TRUE(reader.PopVariantOfInt32(&value));
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithUint32) {
+  auto response = GetPropertyOnInterface(kTestInterface3, kUint32PropName);
+  dbus::MessageReader reader(response.get());
+  uint32_t value;
+  ASSERT_TRUE(reader.PopVariantOfUint32(&value));
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithInt64) {
+  auto response = GetPropertyOnInterface(kTestInterface3, kInt64PropName);
+  dbus::MessageReader reader(response.get());
+  int64_t value;
+  ASSERT_TRUE(reader.PopVariantOfInt64(&value));
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithUint64) {
+  auto response = GetPropertyOnInterface(kTestInterface3, kUint64PropName);
+  dbus::MessageReader reader(response.get());
+  uint64_t value;
+  ASSERT_TRUE(reader.PopVariantOfUint64(&value));
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithDouble) {
+  auto response = GetPropertyOnInterface(kTestInterface3, kDoublePropName);
+  dbus::MessageReader reader(response.get());
+  double value;
+  ASSERT_TRUE(reader.PopVariantOfDouble(&value));
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithString) {
+  auto response = GetPropertyOnInterface(kTestInterface3, kStringPropName);
+  dbus::MessageReader reader(response.get());
+  std::string value;
+  ASSERT_TRUE(reader.PopVariantOfString(&value));
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithPath) {
+  auto response = GetPropertyOnInterface(kTestInterface3, kPathPropName);
+  dbus::MessageReader reader(response.get());
+  dbus::ObjectPath value;
+  ASSERT_TRUE(reader.PopVariantOfObjectPath(&value));
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithStringList) {
+  auto response = GetPropertyOnInterface(kTestInterface3, kStringListPropName);
+  dbus::MessageReader reader(response.get());
+  dbus::MessageReader variant_reader(nullptr);
+  std::vector<std::string> value;
+  ASSERT_TRUE(reader.PopVariant(&variant_reader));
+  ASSERT_TRUE(variant_reader.PopArrayOfStrings(&value));
+  ASSERT_FALSE(variant_reader.HasMoreData());
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithPathList) {
+  auto response = GetPropertyOnInterface(kTestInterface3, kPathListPropName);
+  dbus::MessageReader reader(response.get());
+  dbus::MessageReader variant_reader(nullptr);
+  std::vector<dbus::ObjectPath> value;
+  ASSERT_TRUE(reader.PopVariant(&variant_reader));
+  ASSERT_TRUE(variant_reader.PopArrayOfObjectPaths(&value));
+  ASSERT_FALSE(variant_reader.HasMoreData());
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, GetWorksWithUint8List) {
+  auto response = GetPropertyOnInterface(kTestInterface3, kPathListPropName);
+  dbus::MessageReader reader(response.get());
+  dbus::MessageReader variant_reader(nullptr);
+  const uint8_t* buffer;
+  size_t buffer_len;
+  ASSERT_TRUE(reader.PopVariant(&variant_reader));
+  // |buffer| remains under the control of the MessageReader.
+  ASSERT_TRUE(variant_reader.PopArrayOfBytes(&buffer, &buffer_len));
+  ASSERT_FALSE(variant_reader.HasMoreData());
+  ASSERT_FALSE(reader.HasMoreData());
+}
+
+TEST_F(ExportedPropertySetTest, SetInvalidInterface) {
+  auto response = SetPropertyOnInterface(
+      "BadInterfaceName", kStringPropName, brillo::Any(kTestString));
+  ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+  ASSERT_EQ(DBUS_ERROR_UNKNOWN_INTERFACE, response->GetErrorName());
+}
+
+TEST_F(ExportedPropertySetTest, SetBadPropertyName) {
+  auto response = SetPropertyOnInterface(
+      kTestInterface3, "IAmNotAProperty", brillo::Any(kTestString));
+  ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+  ASSERT_EQ(DBUS_ERROR_UNKNOWN_PROPERTY, response->GetErrorName());
+}
+
+TEST_F(ExportedPropertySetTest, SetFailsWithReadOnlyProperty) {
+  auto response = SetPropertyOnInterface(
+      kTestInterface3, kStringPropName, brillo::Any(kTestString));
+  ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+  ASSERT_EQ(DBUS_ERROR_PROPERTY_READ_ONLY, response->GetErrorName());
+}
+
+TEST_F(ExportedPropertySetTest, SetFailsWithMismatchedValueType) {
+  p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
+  auto response = SetPropertyOnInterface(
+      kTestInterface3, kStringPropName, brillo::Any(true));
+  ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+  ASSERT_EQ(DBUS_ERROR_INVALID_ARGS, response->GetErrorName());
+}
+
+namespace {
+
+bool SetInvalidProperty(brillo::ErrorPtr* error, Unused) {
+  brillo::Error::AddTo(error, FROM_HERE, errors::dbus::kDomain,
+                       DBUS_ERROR_INVALID_ARGS, "Invalid value");
+  return false;
+}
+
+}  // namespace
+
+TEST_F(ExportedPropertySetTest, SetFailsWithValidator) {
+  PropertyValidatorObserver<std::string> property_validator;
+  p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
+  p_->string_prop_.SetValidator(
+      property_validator.validate_property_callback());
+
+  brillo::ErrorPtr error = brillo::Error::Create(
+      FROM_HERE, errors::dbus::kDomain, DBUS_ERROR_INVALID_ARGS, "");
+  EXPECT_CALL(property_validator, ValidateProperty(_, kTestString))
+      .WillOnce(Invoke(SetInvalidProperty));
+  auto response = SetPropertyOnInterface(
+      kTestInterface3, kStringPropName, brillo::Any(kTestString));
+  ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+  ASSERT_EQ(DBUS_ERROR_INVALID_ARGS, response->GetErrorName());
+}
+
+TEST_F(ExportedPropertySetTest, SetWorksWithValidator) {
+  PropertyValidatorObserver<std::string> property_validator;
+  p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
+  p_->string_prop_.SetValidator(
+      property_validator.validate_property_callback());
+
+  EXPECT_CALL(property_validator, ValidateProperty(_, kTestString))
+      .WillOnce(Return(true));
+  auto response = SetPropertyOnInterface(
+      kTestInterface3, kStringPropName, brillo::Any(kTestString));
+  ASSERT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+  ASSERT_EQ(kTestString, p_->string_prop_.value());
+}
+
+TEST_F(ExportedPropertySetTest, SetWorksWithSameValue) {
+  PropertyValidatorObserver<std::string> property_validator;
+  p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
+  p_->string_prop_.SetValidator(
+      property_validator.validate_property_callback());
+  EXPECT_CALL(*mock_exported_object_, SendSignal(_)).Times(1);
+  p_->string_prop_.SetValue(kTestString);
+
+  // No need to validate the value if it is the same as the current one.
+  EXPECT_CALL(property_validator, ValidateProperty(_, _)).Times(0);
+  auto response = SetPropertyOnInterface(
+      kTestInterface3, kStringPropName, brillo::Any(kTestString));
+  ASSERT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+  ASSERT_EQ(kTestString, p_->string_prop_.value());
+}
+
+TEST_F(ExportedPropertySetTest, SetWorksWithoutValidator) {
+  p_->string_prop_.SetAccessMode(ExportedPropertyBase::Access::kReadWrite);
+  auto response = SetPropertyOnInterface(
+      kTestInterface3, kStringPropName, brillo::Any(kTestString));
+  ASSERT_NE(dbus::Message::MESSAGE_ERROR, response->GetMessageType());
+  ASSERT_EQ(kTestString, p_->string_prop_.value());
+}
+
+namespace {
+
+void VerifySignal(dbus::Signal* signal) {
+  ASSERT_NE(signal, nullptr);
+  std::string interface_name;
+  std::string property_name;
+  uint8_t value;
+  dbus::MessageReader reader(signal);
+  dbus::MessageReader array_reader(signal);
+  dbus::MessageReader dict_reader(signal);
+  ASSERT_TRUE(reader.PopString(&interface_name));
+  ASSERT_TRUE(reader.PopArray(&array_reader));
+  ASSERT_TRUE(array_reader.PopDictEntry(&dict_reader));
+  ASSERT_TRUE(dict_reader.PopString(&property_name));
+  ASSERT_TRUE(dict_reader.PopVariantOfByte(&value));
+  ASSERT_FALSE(dict_reader.HasMoreData());
+  ASSERT_FALSE(array_reader.HasMoreData());
+  ASSERT_TRUE(reader.HasMoreData());
+  // Read the (empty) list of invalidated property names.
+  ASSERT_TRUE(reader.PopArray(&array_reader));
+  ASSERT_FALSE(array_reader.HasMoreData());
+  ASSERT_FALSE(reader.HasMoreData());
+  ASSERT_EQ(value, 57);
+  ASSERT_EQ(property_name, std::string(kUint8PropName));
+  ASSERT_EQ(interface_name, std::string(kTestInterface1));
+}
+
+}  // namespace
+
+TEST_F(ExportedPropertySetTest, SignalsAreParsable) {
+  EXPECT_CALL(*mock_exported_object_, SendSignal(_))
+      .Times(1).WillOnce(Invoke(&VerifySignal));
+  p_->uint8_prop_.SetValue(57);
+}
+
+}  // namespace dbus_utils
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/mock_dbus_object.h b/libbrillo/brillo/dbus/mock_dbus_object.h
new file mode 100644
index 0000000..82e2fc7
--- /dev/null
+++ b/libbrillo/brillo/dbus/mock_dbus_object.h
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_MOCK_DBUS_OBJECT_H_
+#define LIBBRILLO_BRILLO_DBUS_MOCK_DBUS_OBJECT_H_
+
+#include <string>
+
+#include <brillo/dbus/async_event_sequencer.h>
+#include <brillo/dbus/dbus_object.h>
+#include <gmock/gmock.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+class MockDBusObject : public DBusObject {
+ public:
+  MockDBusObject(ExportedObjectManager* object_manager,
+                 const scoped_refptr<dbus::Bus>& bus,
+                 const dbus::ObjectPath& object_path)
+      : DBusObject(object_manager, bus, object_path) {}
+  ~MockDBusObject() override = default;
+
+  MOCK_METHOD1(RegisterAsync,
+               void(const AsyncEventSequencer::CompletionAction&));
+};  // class MockDBusObject
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_MOCK_DBUS_OBJECT_H_
diff --git a/libbrillo/brillo/dbus/mock_exported_object_manager.h b/libbrillo/brillo/dbus/mock_exported_object_manager.h
new file mode 100644
index 0000000..d8abc0a
--- /dev/null
+++ b/libbrillo/brillo/dbus/mock_exported_object_manager.h
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_MOCK_EXPORTED_OBJECT_MANAGER_H_
+#define LIBBRILLO_BRILLO_DBUS_MOCK_EXPORTED_OBJECT_MANAGER_H_
+
+#include <string>
+
+#include <brillo/dbus/async_event_sequencer.h>
+#include <brillo/dbus/exported_object_manager.h>
+#include <dbus/object_path.h>
+#include <gmock/gmock.h>
+
+namespace brillo {
+
+namespace dbus_utils {
+
+class MockExportedObjectManager : public ExportedObjectManager {
+ public:
+  using CompletionAction =
+      brillo::dbus_utils::AsyncEventSequencer::CompletionAction;
+
+  using ExportedObjectManager::ExportedObjectManager;
+  ~MockExportedObjectManager() override = default;
+
+  MOCK_METHOD1(RegisterAsync,
+               void(const CompletionAction& completion_callback));
+  MOCK_METHOD3(ClaimInterface,
+               void(const dbus::ObjectPath& path,
+                    const std::string& interface_name,
+                    const ExportedPropertySet::PropertyWriter& writer));
+  MOCK_METHOD2(ReleaseInterface,
+               void(const dbus::ObjectPath& path,
+                    const std::string& interface_name));
+};
+
+}  // namespace dbus_utils
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_MOCK_EXPORTED_OBJECT_MANAGER_H_
diff --git a/libbrillo/brillo/dbus/test.proto b/libbrillo/brillo/dbus/test.proto
new file mode 100644
index 0000000..84607a3
--- /dev/null
+++ b/libbrillo/brillo/dbus/test.proto
@@ -0,0 +1,8 @@
+option optimize_for = LITE_RUNTIME;
+
+package dbus_utils_test;
+
+message TestMessage {
+  optional int32 foo = 1;
+  optional string bar = 2;
+}
diff --git a/libbrillo/brillo/dbus/utils.cc b/libbrillo/brillo/dbus/utils.cc
new file mode 100644
index 0000000..c9bb4db
--- /dev/null
+++ b/libbrillo/brillo/dbus/utils.cc
@@ -0,0 +1,93 @@
+// Copyright 2014 The Chromium OS 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 <brillo/dbus/utils.h>
+
+#include <tuple>
+#include <vector>
+
+#include <base/bind.h>
+#include <brillo/errors/error_codes.h>
+#include <brillo/strings/string_utils.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+std::unique_ptr<dbus::Response> CreateDBusErrorResponse(
+    dbus::MethodCall* method_call,
+    const std::string& error_name,
+    const std::string& error_message) {
+  return dbus::ErrorResponse::FromMethodCall(method_call, error_name,
+                                             error_message);
+}
+
+std::unique_ptr<dbus::Response> GetDBusError(dbus::MethodCall* method_call,
+                                             const brillo::Error* error) {
+  CHECK(error) << "Error object must be specified";
+  std::string error_name = DBUS_ERROR_FAILED;  // Default error code.
+  std::string error_message;
+
+  // Special case for "dbus" error domain.
+  // Pop the error code and message from the error chain and use them as the
+  // actual D-Bus error message.
+  if (error->GetDomain() == errors::dbus::kDomain) {
+    error_name = error->GetCode();
+    error_message = error->GetMessage();
+    error = error->GetInnerError();
+  }
+
+  // Append any inner errors to the error message.
+  while (error) {
+    // Format error string as "domain/code:message".
+    if (!error_message.empty())
+      error_message += ';';
+    error_message +=
+        error->GetDomain() + '/' + error->GetCode() + ':' + error->GetMessage();
+    error = error->GetInnerError();
+  }
+  return CreateDBusErrorResponse(method_call, error_name, error_message);
+}
+
+void AddDBusError(brillo::ErrorPtr* error,
+                  const std::string& dbus_error_name,
+                  const std::string& dbus_error_message) {
+  std::vector<std::string> parts = string_utils::Split(dbus_error_message, ";");
+  std::vector<std::tuple<std::string, std::string, std::string>> errors;
+  for (const std::string& part : parts) {
+    // Each part should be in format of "domain/code:message"
+    size_t slash_pos = part.find('/');
+    size_t colon_pos = part.find(':');
+    if (slash_pos != std::string::npos && colon_pos != std::string::npos &&
+        slash_pos < colon_pos) {
+      // If we have both '/' and ':' and in proper order, then we have a
+      // correctly encoded error object.
+      std::string domain = part.substr(0, slash_pos);
+      std::string code = part.substr(slash_pos + 1, colon_pos - slash_pos - 1);
+      std::string message = part.substr(colon_pos + 1);
+      errors.emplace_back(domain, code, message);
+    } else if (slash_pos == std::string::npos &&
+               colon_pos == std::string::npos && errors.empty()) {
+      // If we don't have both '/' and ':' and this is the first error object,
+      // then we had a D-Bus error at the top of the error chain.
+      errors.emplace_back(errors::dbus::kDomain, dbus_error_name, part);
+    } else {
+      // We have a malformed part. The whole D-Bus error was most likely
+      // not generated by GetDBusError(). To be safe, stop parsing it
+      // and return the error as received from D-Bus.
+      errors.clear();  // Remove any errors accumulated so far.
+      errors.emplace_back(
+          errors::dbus::kDomain, dbus_error_name, dbus_error_message);
+      break;
+    }
+  }
+
+  // Go backwards and add the parsed errors to the error chain.
+  for (auto it = errors.crbegin(); it != errors.crend(); ++it) {
+    Error::AddTo(
+        error, FROM_HERE, std::get<0>(*it), std::get<1>(*it), std::get<2>(*it));
+  }
+}
+
+}  // namespace dbus_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/dbus/utils.h b/libbrillo/brillo/dbus/utils.h
new file mode 100644
index 0000000..a548756
--- /dev/null
+++ b/libbrillo/brillo/dbus/utils.h
@@ -0,0 +1,44 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_DBUS_UTILS_H_
+#define LIBBRILLO_BRILLO_DBUS_UTILS_H_
+
+#include <memory>
+#include <string>
+
+#include <brillo/brillo_export.h>
+#include <brillo/errors/error.h>
+#include <dbus/exported_object.h>
+#include <dbus/message.h>
+#include <dbus/scoped_dbus_error.h>
+
+namespace brillo {
+namespace dbus_utils {
+
+// A helper function to create a D-Bus error response object as unique_ptr<>.
+BRILLO_EXPORT std::unique_ptr<dbus::Response> CreateDBusErrorResponse(
+    dbus::MethodCall* method_call,
+    const std::string& error_name,
+    const std::string& error_message);
+
+// Create a D-Bus error response object from brillo::Error. If the last
+// error in the error chain belongs to "dbus" error domain, its error code
+// and message are directly translated to D-Bus error code and message.
+// Any inner errors are formatted as "domain/code:message" string and appended
+// to the D-Bus error message, delimited by semi-colons.
+BRILLO_EXPORT std::unique_ptr<dbus::Response> GetDBusError(
+    dbus::MethodCall* method_call,
+    const brillo::Error* error);
+
+// AddDBusError() is the opposite of GetDBusError(). It de-serializes the Error
+// object received over D-Bus.
+BRILLO_EXPORT void AddDBusError(brillo::ErrorPtr* error,
+                                const std::string& dbus_error_name,
+                                const std::string& dbus_error_message);
+
+}  // namespace dbus_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_DBUS_UTILS_H_
diff --git a/libbrillo/brillo/errors/error.cc b/libbrillo/brillo/errors/error.cc
new file mode 100644
index 0000000..1236220
--- /dev/null
+++ b/libbrillo/brillo/errors/error.cc
@@ -0,0 +1,138 @@
+// Copyright 2014 The Chromium OS 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 <brillo/errors/error.h>
+
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+
+using brillo::Error;
+using brillo::ErrorPtr;
+
+namespace {
+inline void LogError(const tracked_objects::Location& location,
+                     const std::string& domain,
+                     const std::string& code,
+                     const std::string& message) {
+  // Use logging::LogMessage() directly instead of LOG(ERROR) to substitute
+  // the current error location with the location passed in to the Error object.
+  // This way the log will contain the actual location of the error, and not
+  // as if it always comes from brillo/errors/error.cc(22).
+  logging::LogMessage(
+      location.file_name(), location.line_number(), logging::LOG_ERROR).stream()
+      << location.function_name() << "(...): "
+      << "Domain=" << domain << ", Code=" << code << ", Message=" << message;
+}
+}  // anonymous namespace
+
+ErrorPtr Error::Create(const tracked_objects::Location& location,
+                       const std::string& domain,
+                       const std::string& code,
+                       const std::string& message) {
+  return Create(location, domain, code, message, ErrorPtr());
+}
+
+ErrorPtr Error::Create(const tracked_objects::Location& location,
+                       const std::string& domain,
+                       const std::string& code,
+                       const std::string& message,
+                       ErrorPtr inner_error) {
+  LogError(location, domain, code, message);
+  return ErrorPtr(
+      new Error(location, domain, code, message, std::move(inner_error)));
+}
+
+void Error::AddTo(ErrorPtr* error,
+                  const tracked_objects::Location& location,
+                  const std::string& domain,
+                  const std::string& code,
+                  const std::string& message) {
+  if (error) {
+    *error = Create(location, domain, code, message, std::move(*error));
+  } else {
+    // Create already logs the error, but if |error| is nullptr,
+    // we still want to log the error...
+    LogError(location, domain, code, message);
+  }
+}
+
+void Error::AddToPrintf(ErrorPtr* error,
+                        const tracked_objects::Location& location,
+                        const std::string& domain,
+                        const std::string& code,
+                        const char* format,
+                        ...) {
+  va_list ap;
+  va_start(ap, format);
+  std::string message = base::StringPrintV(format, ap);
+  va_end(ap);
+  AddTo(error, location, domain, code, message);
+}
+
+ErrorPtr Error::Clone() const {
+  ErrorPtr inner_error = inner_error_ ? inner_error_->Clone() : nullptr;
+  return ErrorPtr(
+      new Error(location_, domain_, code_, message_, std::move(inner_error)));
+}
+
+bool Error::HasDomain(const std::string& domain) const {
+  return FindErrorOfDomain(this, domain) != nullptr;
+}
+
+bool Error::HasError(const std::string& domain, const std::string& code) const {
+  return FindError(this, domain, code) != nullptr;
+}
+
+const Error* Error::GetFirstError() const {
+  const Error* err = this;
+  while (err->GetInnerError())
+    err = err->GetInnerError();
+  return err;
+}
+
+Error::Error(const tracked_objects::Location& location,
+             const std::string& domain,
+             const std::string& code,
+             const std::string& message,
+             ErrorPtr inner_error)
+    : Error{tracked_objects::LocationSnapshot{location},
+            domain,
+            code,
+            message,
+            std::move(inner_error)} {
+}
+
+Error::Error(const tracked_objects::LocationSnapshot& location,
+             const std::string& domain,
+             const std::string& code,
+             const std::string& message,
+             ErrorPtr inner_error)
+    : domain_(domain),
+      code_(code),
+      message_(message),
+      location_(location),
+      inner_error_(std::move(inner_error)) {
+}
+
+const Error* Error::FindErrorOfDomain(const Error* error_chain_start,
+                                      const std::string& domain) {
+  while (error_chain_start) {
+    if (error_chain_start->GetDomain() == domain)
+      break;
+    error_chain_start = error_chain_start->GetInnerError();
+  }
+  return error_chain_start;
+}
+
+const Error* Error::FindError(const Error* error_chain_start,
+                              const std::string& domain,
+                              const std::string& code) {
+  while (error_chain_start) {
+    if (error_chain_start->GetDomain() == domain &&
+        error_chain_start->GetCode() == code)
+      break;
+    error_chain_start = error_chain_start->GetInnerError();
+  }
+  return error_chain_start;
+}
diff --git a/libbrillo/brillo/errors/error.h b/libbrillo/brillo/errors/error.h
new file mode 100644
index 0000000..4cf60f5
--- /dev/null
+++ b/libbrillo/brillo/errors/error.h
@@ -0,0 +1,129 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_ERRORS_ERROR_H_
+#define LIBBRILLO_BRILLO_ERRORS_ERROR_H_
+
+#include <memory>
+#include <string>
+
+#include <base/macros.h>
+#include <base/tracked_objects.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+class Error;  // Forward declaration.
+
+using ErrorPtr = std::unique_ptr<Error>;
+
+class BRILLO_EXPORT Error {
+ public:
+  virtual ~Error() = default;
+
+  // Creates an instance of Error class.
+  static ErrorPtr Create(const tracked_objects::Location& location,
+                         const std::string& domain,
+                         const std::string& code,
+                         const std::string& message);
+  static ErrorPtr Create(const tracked_objects::Location& location,
+                         const std::string& domain,
+                         const std::string& code,
+                         const std::string& message,
+                         ErrorPtr inner_error);
+  // If |error| is not nullptr, creates another instance of Error class,
+  // initializes it with specified arguments and adds it to the head of
+  // the error chain pointed to by |error|.
+  static void AddTo(ErrorPtr* error,
+                    const tracked_objects::Location& location,
+                    const std::string& domain,
+                    const std::string& code,
+                    const std::string& message);
+  // Same as the Error::AddTo above, but allows to pass in a printf-like
+  // format string and optional parameters to format the error message.
+  static void AddToPrintf(ErrorPtr* error,
+                          const tracked_objects::Location& location,
+                          const std::string& domain,
+                          const std::string& code,
+                          const char* format,
+                          ...) PRINTF_FORMAT(5, 6);
+
+  // Clones error with all inner errors.
+  ErrorPtr Clone() const;
+
+  // Returns the error domain, code and message
+  const std::string& GetDomain() const { return domain_; }
+  const std::string& GetCode() const { return code_; }
+  const std::string& GetMessage() const { return message_; }
+
+  // Returns the location of the error in the source code.
+  const tracked_objects::LocationSnapshot& GetLocation() const {
+    return location_;
+  }
+
+  // Checks if this or any of the inner errors in the chain has the specified
+  // error domain.
+  bool HasDomain(const std::string& domain) const;
+
+  // Checks if this or any of the inner errors in the chain matches the
+  // specified error domain and code.
+  bool HasError(const std::string& domain, const std::string& code) const;
+
+  // Gets a pointer to the inner error, if present. Returns nullptr otherwise.
+  const Error* GetInnerError() const { return inner_error_.get(); }
+
+  // Gets a pointer to the first error occurred.
+  // Returns itself if no inner error are available.
+  const Error* GetFirstError() const;
+
+  // Finds an error object of particular domain in the error chain stating at
+  // |error_chain_start|. Returns the a pointer to the first matching error
+  // object found.
+  // Returns nullptr if no match is found.
+  // This method is safe to call on a nullptr |error_chain_start| in which case
+  // the result will also be nullptr.
+  static const Error* FindErrorOfDomain(const Error* error_chain_start,
+                                        const std::string& domain);
+  // Finds an error of particular domain with the given code in the error chain
+  // stating at |error_chain_start|. Returns the pointer to the first matching
+  // error object.
+  // Returns nullptr if no match is found or if |error_chain_start| is nullptr.
+  static const Error* FindError(const Error* error_chain_start,
+                                const std::string& domain,
+                                const std::string& code);
+
+ protected:
+  // Constructor is protected since this object is supposed to be
+  // created via the Create factory methods.
+  Error(const tracked_objects::Location& location,
+        const std::string& domain,
+        const std::string& code,
+        const std::string& message,
+        ErrorPtr inner_error);
+
+  Error(const tracked_objects::LocationSnapshot& location,
+        const std::string& domain,
+        const std::string& code,
+        const std::string& message,
+        ErrorPtr inner_error);
+
+  // Error domain. The domain defines the scopes for error codes.
+  // Two errors with the same code but different domains are different errors.
+  std::string domain_;
+  // Error code. A unique error code identifier within the given domain.
+  std::string code_;
+  // Human-readable error message.
+  std::string message_;
+  // Error origin in the source code.
+  tracked_objects::LocationSnapshot location_;
+  // Pointer to inner error, if any. This forms a chain of errors.
+  ErrorPtr inner_error_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Error);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_ERRORS_ERROR_H_
diff --git a/libbrillo/brillo/errors/error_codes.cc b/libbrillo/brillo/errors/error_codes.cc
new file mode 100644
index 0000000..4e48b4e
--- /dev/null
+++ b/libbrillo/brillo/errors/error_codes.cc
@@ -0,0 +1,225 @@
+// Copyright 2014 The Chromium OS 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 <brillo/errors/error_codes.h>
+
+#include <base/posix/safe_strerror.h>
+
+namespace brillo {
+namespace errors {
+
+namespace dbus {
+const char kDomain[] = "dbus";
+}  // namespace dbus
+
+namespace json {
+const char kDomain[] = "json_parser";
+const char kParseError[] = "json_parse_error";
+const char kObjectExpected[] = "json_object_expected";
+}  // namespace json
+
+namespace http {
+const char kDomain[] = "http";
+}  // namespace http
+
+namespace system {
+const char kDomain[] = "system";
+
+namespace {
+const struct ErrorMapEntry {
+  const char* error_code;
+  int errnum;
+} error_map[] = {
+#define ERROR_ENTRY(err) { #err, err }
+  ERROR_ENTRY(EPERM),            // Operation not permitted
+  ERROR_ENTRY(ENOENT),           // No such file or directory
+  ERROR_ENTRY(ESRCH),            // No such process
+  ERROR_ENTRY(EINTR),            // Interrupted system call
+  ERROR_ENTRY(EIO),              // I/O error
+  ERROR_ENTRY(ENXIO),            // No such device or address
+  ERROR_ENTRY(E2BIG),            // Argument list too long
+  ERROR_ENTRY(ENOEXEC),          // Exec format error
+  ERROR_ENTRY(EBADF),            // Bad file number
+  ERROR_ENTRY(ECHILD),           // No child processes
+  ERROR_ENTRY(EAGAIN),           // Try again
+  ERROR_ENTRY(ENOMEM),           // Out of memory
+  ERROR_ENTRY(EACCES),           // Permission denied
+  ERROR_ENTRY(EFAULT),           // Bad address
+  ERROR_ENTRY(ENOTBLK),          // Block device required
+  ERROR_ENTRY(EBUSY),            // Device or resource busy
+  ERROR_ENTRY(EEXIST),           // File exists
+  ERROR_ENTRY(EXDEV),            // Cross-device link
+  ERROR_ENTRY(ENODEV),           // No such device
+  ERROR_ENTRY(ENOTDIR),          // Not a directory
+  ERROR_ENTRY(EISDIR),           // Is a directory
+  ERROR_ENTRY(EINVAL),           // Invalid argument
+  ERROR_ENTRY(ENFILE),           // File table overflow
+  ERROR_ENTRY(EMFILE),           // Too many open files
+  ERROR_ENTRY(ENOTTY),           // Not a typewriter
+  ERROR_ENTRY(ETXTBSY),          // Text file busy
+  ERROR_ENTRY(EFBIG),            // File too large
+  ERROR_ENTRY(ENOSPC),           // No space left on device
+  ERROR_ENTRY(ESPIPE),           // Illegal seek
+  ERROR_ENTRY(EROFS),            // Read-only file system
+  ERROR_ENTRY(EMLINK),           // Too many links
+  ERROR_ENTRY(EPIPE),            // Broken pipe
+  ERROR_ENTRY(EDOM),             // Math argument out of domain of func
+  ERROR_ENTRY(ERANGE),           // Math result not representable
+  ERROR_ENTRY(EDEADLK),          // Resource deadlock would occur
+  ERROR_ENTRY(ENAMETOOLONG),     // File name too long
+  ERROR_ENTRY(ENOLCK),           // No record locks available
+  ERROR_ENTRY(ENOSYS),           // Function not implemented
+  ERROR_ENTRY(ENOTEMPTY),        // Directory not empty
+  ERROR_ENTRY(ELOOP),            // Too many symbolic links encountered
+  ERROR_ENTRY(ENOMSG),           // No message of desired type
+  ERROR_ENTRY(EIDRM),            // Identifier removed
+#ifdef __linux__
+  ERROR_ENTRY(ECHRNG),           // Channel number out of range
+  ERROR_ENTRY(EL2NSYNC),         // Level 2 not synchronized
+  ERROR_ENTRY(EL3HLT),           // Level 3 halted
+  ERROR_ENTRY(EL3RST),           // Level 3 reset
+  ERROR_ENTRY(ELNRNG),           // Link number out of range
+  ERROR_ENTRY(EUNATCH),          // Protocol driver not attached
+  ERROR_ENTRY(ENOCSI),           // No CSI structure available
+  ERROR_ENTRY(EL2HLT),           // Level 2 halted
+  ERROR_ENTRY(EBADE),            // Invalid exchange
+  ERROR_ENTRY(EBADR),            // Invalid request descriptor
+  ERROR_ENTRY(EXFULL),           // Exchange full
+  ERROR_ENTRY(ENOANO),           // No anode
+  ERROR_ENTRY(EBADRQC),          // Invalid request code
+  ERROR_ENTRY(EBADSLT),          // Invalid slot
+  ERROR_ENTRY(EBFONT),           // Bad font file format
+#endif  // __linux__
+  ERROR_ENTRY(ENOSTR),           // Device not a stream
+  ERROR_ENTRY(ENODATA),          // No data available
+  ERROR_ENTRY(ETIME),            // Timer expired
+  ERROR_ENTRY(ENOSR),            // Out of streams resources
+#ifdef __linux__
+  ERROR_ENTRY(ENONET),           // Machine is not on the network
+  ERROR_ENTRY(ENOPKG),           // Package not installed
+#endif  // __linux__
+  ERROR_ENTRY(EREMOTE),          // Object is remote
+  ERROR_ENTRY(ENOLINK),          // Link has been severed
+#ifdef __linux__
+  ERROR_ENTRY(EADV),             // Advertise error
+  ERROR_ENTRY(ESRMNT),           // Srmount error
+  ERROR_ENTRY(ECOMM),            // Communication error on send
+#endif  // __linux__
+  ERROR_ENTRY(EPROTO),           // Protocol error
+  ERROR_ENTRY(EMULTIHOP),        // Multihop attempted
+#ifdef __linux__
+  ERROR_ENTRY(EDOTDOT),          // RFS specific error
+#endif  // __linux__
+  ERROR_ENTRY(EBADMSG),          // Not a data message
+  ERROR_ENTRY(EOVERFLOW),        // Value too large for defined data type
+#ifdef __linux__
+  ERROR_ENTRY(ENOTUNIQ),         // Name not unique on network
+  ERROR_ENTRY(EBADFD),           // File descriptor in bad state
+  ERROR_ENTRY(EREMCHG),          // Remote address changed
+  ERROR_ENTRY(ELIBACC),          // Can not access a needed shared library
+  ERROR_ENTRY(ELIBBAD),          // Accessing a corrupted shared library
+  ERROR_ENTRY(ELIBSCN),          // .lib section in a.out corrupted
+  ERROR_ENTRY(ELIBMAX),          // Attempting to link in too many shared libs.
+  ERROR_ENTRY(ELIBEXEC),         // Cannot exec a shared library directly
+#endif  // __linux__
+  ERROR_ENTRY(EILSEQ),           // Illegal byte sequence
+#ifdef __linux__
+  ERROR_ENTRY(ERESTART),         // Interrupted system call should be restarted
+  ERROR_ENTRY(ESTRPIPE),         // Streams pipe error
+#endif  // __linux__
+  ERROR_ENTRY(EUSERS),           // Too many users
+  ERROR_ENTRY(ENOTSOCK),         // Socket operation on non-socket
+  ERROR_ENTRY(EDESTADDRREQ),     // Destination address required
+  ERROR_ENTRY(EMSGSIZE),         // Message too long
+  ERROR_ENTRY(EPROTOTYPE),       // Protocol wrong type for socket
+  ERROR_ENTRY(ENOPROTOOPT),      // Protocol not available
+  ERROR_ENTRY(EPROTONOSUPPORT),  // Protocol not supported
+  ERROR_ENTRY(ESOCKTNOSUPPORT),  // Socket type not supported
+  ERROR_ENTRY(EOPNOTSUPP),       // Operation not supported o/transport endpoint
+  ERROR_ENTRY(EPFNOSUPPORT),     // Protocol family not supported
+  ERROR_ENTRY(EAFNOSUPPORT),     // Address family not supported by protocol
+  ERROR_ENTRY(EADDRINUSE),       // Address already in use
+  ERROR_ENTRY(EADDRNOTAVAIL),    // Cannot assign requested address
+  ERROR_ENTRY(ENETDOWN),         // Network is down
+  ERROR_ENTRY(ENETUNREACH),      // Network is unreachable
+  ERROR_ENTRY(ENETRESET),        // Network dropped connection because of reset
+  ERROR_ENTRY(ECONNABORTED),     // Software caused connection abort
+  ERROR_ENTRY(ECONNRESET),       // Connection reset by peer
+  ERROR_ENTRY(ENOBUFS),          // No buffer space available
+  ERROR_ENTRY(EISCONN),          // Transport endpoint is already connected
+  ERROR_ENTRY(ENOTCONN),         // Transport endpoint is not connected
+  ERROR_ENTRY(ESHUTDOWN),        // Cannot send after transp. endpoint shutdown
+  ERROR_ENTRY(ETOOMANYREFS),     // Too many references: cannot splice
+  ERROR_ENTRY(ETIMEDOUT),        // Connection timed out
+  ERROR_ENTRY(ECONNREFUSED),     // Connection refused
+  ERROR_ENTRY(EHOSTDOWN),        // Host is down
+  ERROR_ENTRY(EHOSTUNREACH),     // No route to host
+  ERROR_ENTRY(EALREADY),         // Operation already in progress
+  ERROR_ENTRY(EINPROGRESS),      // Operation now in progress
+  ERROR_ENTRY(ESTALE),           // Stale file handle
+#ifdef __linux__
+  ERROR_ENTRY(EUCLEAN),          // Structure needs cleaning
+  ERROR_ENTRY(ENOTNAM),          // Not a XENIX named type file
+  ERROR_ENTRY(ENAVAIL),          // No XENIX semaphores available
+  ERROR_ENTRY(EISNAM),           // Is a named type file
+  ERROR_ENTRY(EREMOTEIO),        // Remote I/O error
+#endif  // __linux__
+  ERROR_ENTRY(EDQUOT),           // Quota exceeded
+#ifdef __linux__
+  ERROR_ENTRY(ENOMEDIUM),        // No medium found
+  ERROR_ENTRY(EMEDIUMTYPE),      // Wrong medium type
+#endif  // __linux__
+  ERROR_ENTRY(ECANCELED),        // Operation Canceled
+#ifdef __linux__
+  ERROR_ENTRY(ENOKEY),           // Required key not available
+  ERROR_ENTRY(EKEYEXPIRED),      // Key has expired
+  ERROR_ENTRY(EKEYREVOKED),      // Key has been revoked
+  ERROR_ENTRY(EKEYREJECTED),     // Key was rejected by service
+#endif  // __linux__
+  ERROR_ENTRY(EOWNERDEAD),       // Owner died
+  ERROR_ENTRY(ENOTRECOVERABLE),  // State not recoverable
+#ifdef __linux__
+  ERROR_ENTRY(ERFKILL),          // Operation not possible due to RF-kill
+  ERROR_ENTRY(EHWPOISON),        // Memory page has hardware error
+#endif  // __linux__
+#undef ERROR_ENTRY
+  // This list comes from <errno.h> system header. The elements are ordered
+  // by increasing errnum values which is the same order used in the header
+  // file. So, when new error codes are added to glibc, it should be relatively
+  // easy to identify them and add them to this list.
+};
+
+// Gets the error code string from system error code. If unknown system error
+// number is provided, returns an empty string.
+std::string ErrorCodeFromSystemError(int errnum) {
+  std::string error_code;
+  for (const ErrorMapEntry& entry : error_map) {
+    if (entry.errnum == errnum) {
+      error_code = entry.error_code;
+      break;
+    }
+  }
+  return error_code;
+}
+
+}  // anonymous namespace
+
+void AddSystemError(ErrorPtr* error,
+                    const tracked_objects::Location& location,
+                    int errnum) {
+  std::string message = base::safe_strerror(errnum);
+  std::string code = ErrorCodeFromSystemError(errnum);
+  if (message.empty())
+    message = "Unknown error " + std::to_string(errnum);
+
+  if (code.empty())
+    code = "error_" + std::to_string(errnum);
+
+  Error::AddTo(error, location, kDomain, code, message);
+}
+
+}  // namespace system
+
+}  // namespace errors
+}  // namespace brillo
diff --git a/libbrillo/brillo/errors/error_codes.h b/libbrillo/brillo/errors/error_codes.h
new file mode 100644
index 0000000..a9964f6
--- /dev/null
+++ b/libbrillo/brillo/errors/error_codes.h
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_ERRORS_ERROR_CODES_H_
+#define LIBBRILLO_BRILLO_ERRORS_ERROR_CODES_H_
+
+#include <string>
+
+#include <brillo/brillo_export.h>
+#include <brillo/errors/error.h>
+
+namespace brillo {
+namespace errors {
+
+namespace dbus {
+BRILLO_EXPORT extern const char kDomain[];
+}  // namespace dbus
+
+namespace json {
+BRILLO_EXPORT extern const char kDomain[];
+BRILLO_EXPORT extern const char kParseError[];
+BRILLO_EXPORT extern const char kObjectExpected[];
+}  // namespace json
+
+namespace http {
+BRILLO_EXPORT extern const char kDomain[];
+}  // namespace http
+
+namespace system {
+BRILLO_EXPORT extern const char kDomain[];
+
+// Adds an Error object to the error chain identified by |error|, using
+// the system error code (see "errno").
+BRILLO_EXPORT void AddSystemError(ErrorPtr* error,
+                                  const tracked_objects::Location& location,
+                                  int errnum);
+}  // namespace system
+
+}  // namespace errors
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_ERRORS_ERROR_CODES_H_
diff --git a/libbrillo/brillo/errors/error_codes_unittest.cc b/libbrillo/brillo/errors/error_codes_unittest.cc
new file mode 100644
index 0000000..2baa28f
--- /dev/null
+++ b/libbrillo/brillo/errors/error_codes_unittest.cc
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium OS 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 <brillo/errors/error_codes.h>
+
+#include <gtest/gtest.h>
+
+using brillo::errors::system::AddSystemError;
+
+TEST(SystemErrorCodes, AddTo) {
+  brillo::ErrorPtr error;
+
+  AddSystemError(&error, FROM_HERE, ENOENT);
+  EXPECT_EQ(brillo::errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("ENOENT", error->GetCode());
+  EXPECT_EQ("No such file or directory", error->GetMessage());
+  error.reset();
+
+  AddSystemError(&error, FROM_HERE, EPROTO);
+  EXPECT_EQ(brillo::errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("EPROTO", error->GetCode());
+  EXPECT_EQ("Protocol error", error->GetMessage());
+  error.reset();
+}
+
+TEST(SystemErrorCodes, AddTo_UnknownError) {
+  brillo::ErrorPtr error;
+  AddSystemError(&error, FROM_HERE, 10000);
+  EXPECT_EQ(brillo::errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("error_10000", error->GetCode());
+  EXPECT_EQ("Unknown error 10000", error->GetMessage());
+}
diff --git a/libbrillo/brillo/errors/error_unittest.cc b/libbrillo/brillo/errors/error_unittest.cc
new file mode 100644
index 0000000..517dab5
--- /dev/null
+++ b/libbrillo/brillo/errors/error_unittest.cc
@@ -0,0 +1,83 @@
+// Copyright 2014 The Chromium OS 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 <brillo/errors/error.h>
+
+#include <gtest/gtest.h>
+
+using brillo::Error;
+
+namespace {
+
+brillo::ErrorPtr GenerateNetworkError() {
+  tracked_objects::Location loc("GenerateNetworkError",
+                                "error_unittest.cc",
+                                15,
+                                ::tracked_objects::GetProgramCounter());
+  return Error::Create(loc, "network", "not_found", "Resource not found");
+}
+
+brillo::ErrorPtr GenerateHttpError() {
+  brillo::ErrorPtr inner = GenerateNetworkError();
+  return Error::Create(FROM_HERE, "HTTP", "404", "Not found", std::move(inner));
+}
+
+}  // namespace
+
+TEST(Error, Single) {
+  brillo::ErrorPtr err = GenerateNetworkError();
+  EXPECT_EQ("network", err->GetDomain());
+  EXPECT_EQ("not_found", err->GetCode());
+  EXPECT_EQ("Resource not found", err->GetMessage());
+  EXPECT_EQ("GenerateNetworkError", err->GetLocation().function_name);
+  EXPECT_EQ("error_unittest.cc", err->GetLocation().file_name);
+  EXPECT_EQ(15, err->GetLocation().line_number);
+  EXPECT_EQ(nullptr, err->GetInnerError());
+  EXPECT_TRUE(err->HasDomain("network"));
+  EXPECT_FALSE(err->HasDomain("HTTP"));
+  EXPECT_FALSE(err->HasDomain("foo"));
+  EXPECT_TRUE(err->HasError("network", "not_found"));
+  EXPECT_FALSE(err->HasError("network", "404"));
+  EXPECT_FALSE(err->HasError("HTTP", "404"));
+  EXPECT_FALSE(err->HasError("HTTP", "not_found"));
+  EXPECT_FALSE(err->HasError("foo", "bar"));
+}
+
+TEST(Error, Nested) {
+  brillo::ErrorPtr err = GenerateHttpError();
+  EXPECT_EQ("HTTP", err->GetDomain());
+  EXPECT_EQ("404", err->GetCode());
+  EXPECT_EQ("Not found", err->GetMessage());
+  EXPECT_NE(nullptr, err->GetInnerError());
+  EXPECT_EQ("network", err->GetInnerError()->GetDomain());
+  EXPECT_TRUE(err->HasDomain("network"));
+  EXPECT_TRUE(err->HasDomain("HTTP"));
+  EXPECT_FALSE(err->HasDomain("foo"));
+  EXPECT_TRUE(err->HasError("network", "not_found"));
+  EXPECT_FALSE(err->HasError("network", "404"));
+  EXPECT_TRUE(err->HasError("HTTP", "404"));
+  EXPECT_FALSE(err->HasError("HTTP", "not_found"));
+  EXPECT_FALSE(err->HasError("foo", "bar"));
+}
+
+TEST(Error, Clone) {
+  brillo::ErrorPtr err = GenerateHttpError();
+  brillo::ErrorPtr clone = err->Clone();
+  const brillo::Error* error1 = err.get();
+  const brillo::Error* error2 = clone.get();
+  while (error1 && error2) {
+    EXPECT_NE(error1, error2);
+    EXPECT_EQ(error1->GetDomain(), error2->GetDomain());
+    EXPECT_EQ(error1->GetCode(), error2->GetCode());
+    EXPECT_EQ(error1->GetMessage(), error2->GetMessage());
+    EXPECT_EQ(error1->GetLocation().function_name,
+              error2->GetLocation().function_name);
+    EXPECT_EQ(error1->GetLocation().file_name, error2->GetLocation().file_name);
+    EXPECT_EQ(error1->GetLocation().line_number,
+              error2->GetLocation().line_number);
+    error1 = error1->GetInnerError();
+    error2 = error2->GetInnerError();
+  }
+  EXPECT_EQ(error1, error2);
+}
diff --git a/libbrillo/brillo/file_utils.cc b/libbrillo/brillo/file_utils.cc
new file mode 100644
index 0000000..24ed347
--- /dev/null
+++ b/libbrillo/brillo/file_utils.cc
@@ -0,0 +1,165 @@
+// Copyright 2014 The Chromium OS 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 "brillo/file_utils.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/files/scoped_file.h>
+#include <base/logging.h>
+#include <base/posix/eintr_wrapper.h>
+
+namespace brillo {
+
+namespace {
+
+enum {
+  kPermissions600 = S_IRUSR | S_IWUSR,
+  kPermissions777 = S_IRWXU | S_IRWXG | S_IRWXO
+};
+
+// Verify that base file permission enums are compatible with S_Ixxx. If these
+// asserts ever fail, we'll need to ensure that users of these functions switch
+// away from using base permission enums and add a note to the function comments
+// indicating that base enums can not be used.
+static_assert(base::FILE_PERMISSION_READ_BY_USER == S_IRUSR,
+              "base file permissions don't match unistd.h permissions");
+static_assert(base::FILE_PERMISSION_WRITE_BY_USER == S_IWUSR,
+              "base file permissions don't match unistd.h permissions");
+static_assert(base::FILE_PERMISSION_EXECUTE_BY_USER == S_IXUSR,
+              "base file permissions don't match unistd.h permissions");
+static_assert(base::FILE_PERMISSION_READ_BY_GROUP == S_IRGRP,
+              "base file permissions don't match unistd.h permissions");
+static_assert(base::FILE_PERMISSION_WRITE_BY_GROUP == S_IWGRP,
+              "base file permissions don't match unistd.h permissions");
+static_assert(base::FILE_PERMISSION_EXECUTE_BY_GROUP == S_IXGRP,
+              "base file permissions don't match unistd.h permissions");
+static_assert(base::FILE_PERMISSION_READ_BY_OTHERS == S_IROTH,
+              "base file permissions don't match unistd.h permissions");
+static_assert(base::FILE_PERMISSION_WRITE_BY_OTHERS == S_IWOTH,
+              "base file permissions don't match unistd.h permissions");
+static_assert(base::FILE_PERMISSION_EXECUTE_BY_OTHERS == S_IXOTH,
+              "base file permissions don't match unistd.h permissions");
+
+enum RegularFileOrDeleteResult {
+  kFailure = 0,      // Failed to delete whatever was at the path.
+  kRegularFile = 1,  // Regular file existed and was unchanged.
+  kEmpty = 2         // Anything that was at the path has been deleted.
+};
+
+// Checks if a regular file owned by |uid| and |gid| exists at |path|, otherwise
+// deletes anything that might be at |path|. Returns a RegularFileOrDeleteResult
+// enum indicating what is at |path| after the function finishes.
+RegularFileOrDeleteResult RegularFileOrDelete(const base::FilePath& path,
+                                              uid_t uid,
+                                              gid_t gid) {
+  // Check for symlinks by setting O_NOFOLLOW and checking for ELOOP. This lets
+  // us use the safer fstat() instead of having to use lstat().
+  base::ScopedFD scoped_fd(HANDLE_EINTR(openat(
+      AT_FDCWD, path.value().c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)));
+  bool path_not_empty = (errno == ELOOP || scoped_fd != -1);
+
+  // If there is a file/directory at |path|, see if it matches our criteria.
+  if (scoped_fd != -1) {
+    struct stat file_stat;
+    if (fstat(scoped_fd.get(), &file_stat) != -1 &&
+        S_ISREG(file_stat.st_mode) && file_stat.st_uid == uid &&
+        file_stat.st_gid == gid) {
+      return kRegularFile;
+    }
+  }
+
+  // If we get here and anything was at |path|, try to delete it so we can put
+  // our file there.
+  if (path_not_empty) {
+    if (!base::DeleteFile(path, true)) {
+      PLOG(WARNING) << "Failed to delete entity at \"" << path.value() << '"';
+      return kFailure;
+    }
+  }
+
+  return kEmpty;
+}
+
+// Handles common touch functionality but also provides an optional |fd_out|
+// so that any further modifications to the file (e.g. permissions) can safely
+// use the fd rather than the path. |fd_out| will only be set if a new file
+// is created, otherwise it will be unchanged.
+// If |fd_out| is null, this function will close the file, otherwise it's
+// expected that |fd_out| will close the file when it goes out of scope.
+bool TouchFileInternal(const base::FilePath& path,
+                       uid_t uid,
+                       gid_t gid,
+                       base::ScopedFD* fd_out) {
+  RegularFileOrDeleteResult result = RegularFileOrDelete(path, uid, gid);
+  switch (result) {
+    case kFailure:
+      return false;
+    case kRegularFile:
+      return true;
+    case kEmpty:
+      break;
+  }
+
+  // base::CreateDirectory() returns true if the directory already existed.
+  if (!base::CreateDirectory(path.DirName())) {
+    PLOG(WARNING) << "Failed to create directory for \"" << path.value() << '"';
+    return false;
+  }
+
+  // Create the file as owner-only initially.
+  base::ScopedFD scoped_fd(
+      HANDLE_EINTR(openat(AT_FDCWD,
+                          path.value().c_str(),
+                          O_RDONLY | O_NOFOLLOW | O_CREAT | O_EXCL | O_CLOEXEC,
+                          kPermissions600)));
+  if (scoped_fd == -1) {
+    PLOG(WARNING) << "Failed to create file \"" << path.value() << '"';
+    return false;
+  }
+
+  if (fd_out) {
+    fd_out->swap(scoped_fd);
+  }
+  return true;
+}
+
+}  // namespace
+
+bool TouchFile(const base::FilePath& path,
+               int new_file_permissions,
+               uid_t uid,
+               gid_t gid) {
+  // Make sure |permissions| doesn't have any out-of-range bits.
+  if (new_file_permissions & ~kPermissions777) {
+    LOG(WARNING) << "Illegal permissions: " << new_file_permissions;
+    return false;
+  }
+
+  base::ScopedFD scoped_fd;
+  if (!TouchFileInternal(path, uid, gid, &scoped_fd)) {
+    return false;
+  }
+
+  // scoped_fd is valid only if a new file was created.
+  if (scoped_fd != -1 &&
+      HANDLE_EINTR(fchmod(scoped_fd.get(), new_file_permissions)) == -1) {
+    PLOG(WARNING) << "Failed to set permissions for \"" << path.value() << '"';
+    base::DeleteFile(path, false);
+    return false;
+  }
+
+  return true;
+}
+
+bool TouchFile(const base::FilePath& path) {
+  // Use TouchFile() instead of TouchFileInternal() to explicitly set
+  // permissions to 600 in case umask is set strangely.
+  return TouchFile(path, kPermissions600, geteuid(), getegid());
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/file_utils.h b/libbrillo/brillo/file_utils.h
new file mode 100644
index 0000000..60e0cdc
--- /dev/null
+++ b/libbrillo/brillo/file_utils.h
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_FILE_UTILS_H_
+#define LIBBRILLO_BRILLO_FILE_UTILS_H_
+
+#include <sys/types.h>
+
+#include <base/files/file_path.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+// Ensures a regular file owned by user |uid| and group |gid| exists at |path|.
+// Any other entity at |path| will be deleted and replaced with an empty
+// regular file. If a new file is needed, any missing parent directories will
+// be created, and the file will be assigned |new_file_permissions|.
+// Should be safe to use in all directories, including tmpdirs with the sticky
+// bit set.
+// Returns true if the file existed or was able to be created.
+BRILLO_EXPORT bool TouchFile(const base::FilePath& path,
+                             int new_file_permissions,
+                             uid_t uid,
+                             gid_t gid);
+
+// Convenience version of TouchFile() defaulting to 600 permissions and the
+// current euid/egid.
+// Should be safe to use in all directories, including tmpdirs with the sticky
+// bit set.
+BRILLO_EXPORT bool TouchFile(const base::FilePath& path);
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_FILE_UTILS_H_
diff --git a/libbrillo/brillo/file_utils_unittest.cc b/libbrillo/brillo/file_utils_unittest.cc
new file mode 100644
index 0000000..f8898a0
--- /dev/null
+++ b/libbrillo/brillo/file_utils_unittest.cc
@@ -0,0 +1,135 @@
+// Copyright 2014 The Chromium OS 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 "brillo/file_utils.h"
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+class FileUtilsTest : public testing::Test {
+ public:
+  FileUtilsTest() {
+    CHECK(temp_dir_.CreateUniqueTempDir());
+    file_path_ = temp_dir_.path().Append("test.temp");
+  }
+
+ protected:
+  base::FilePath file_path_;
+  base::ScopedTempDir temp_dir_;
+
+  // Writes |contents| to |file_path_|. Pulled into a separate function just
+  // to improve readability of tests.
+  void WriteFile(const std::string& contents) {
+    EXPECT_EQ(contents.length(),
+              base::WriteFile(file_path_, contents.c_str(), contents.length()));
+  }
+
+  // Verifies that the file at |file_path_| exists and contains |contents|.
+  void ExpectFileContains(const std::string& contents) {
+    EXPECT_TRUE(base::PathExists(file_path_));
+    std::string new_contents;
+    EXPECT_TRUE(base::ReadFileToString(file_path_, &new_contents));
+    EXPECT_EQ(contents, new_contents);
+  }
+
+  // Verifies that the file at |file_path_| has |permissions|.
+  void ExpectFilePermissions(int permissions) {
+    int actual_permissions;
+    EXPECT_TRUE(base::GetPosixFilePermissions(file_path_, &actual_permissions));
+    EXPECT_EQ(permissions, actual_permissions);
+  }
+};
+
+namespace {
+
+enum {
+  kPermissions600 =
+      base::FILE_PERMISSION_READ_BY_USER | base::FILE_PERMISSION_WRITE_BY_USER,
+  kPermissions700 = base::FILE_PERMISSION_USER_MASK,
+  kPermissions777 = base::FILE_PERMISSION_MASK
+};
+
+}  // namespace
+
+TEST_F(FileUtilsTest, TouchFileCreate) {
+  EXPECT_TRUE(TouchFile(file_path_));
+  ExpectFileContains("");
+  ExpectFilePermissions(kPermissions600);
+}
+
+TEST_F(FileUtilsTest, TouchFileCreateThroughUmask) {
+  mode_t old_umask = umask(kPermissions777);
+  EXPECT_TRUE(TouchFile(file_path_));
+  umask(old_umask);
+  ExpectFileContains("");
+  ExpectFilePermissions(kPermissions600);
+}
+
+TEST_F(FileUtilsTest, TouchFileCreateDirectoryStructure) {
+  file_path_ = temp_dir_.path().Append("foo/bar/baz/test.temp");
+  EXPECT_TRUE(TouchFile(file_path_));
+  ExpectFileContains("");
+}
+
+TEST_F(FileUtilsTest, TouchFileExisting) {
+  WriteFile("abcd");
+  EXPECT_TRUE(TouchFile(file_path_));
+  ExpectFileContains("abcd");
+}
+
+TEST_F(FileUtilsTest, TouchFileReplaceDirectory) {
+  EXPECT_TRUE(base::CreateDirectory(file_path_));
+  EXPECT_TRUE(TouchFile(file_path_));
+  EXPECT_FALSE(base::DirectoryExists(file_path_));
+  ExpectFileContains("");
+}
+
+TEST_F(FileUtilsTest, TouchFileReplaceSymlink) {
+  base::FilePath symlink_target = temp_dir_.path().Append("target.temp");
+  EXPECT_TRUE(base::CreateSymbolicLink(symlink_target, file_path_));
+  EXPECT_TRUE(TouchFile(file_path_));
+  EXPECT_FALSE(base::IsLink(file_path_));
+  ExpectFileContains("");
+}
+
+TEST_F(FileUtilsTest, TouchFileReplaceOtherUser) {
+  WriteFile("abcd");
+  EXPECT_TRUE(TouchFile(file_path_, kPermissions777, geteuid() + 1, getegid()));
+  ExpectFileContains("");
+}
+
+TEST_F(FileUtilsTest, TouchFileReplaceOtherGroup) {
+  WriteFile("abcd");
+  EXPECT_TRUE(TouchFile(file_path_, kPermissions777, geteuid(), getegid() + 1));
+  ExpectFileContains("");
+}
+
+TEST_F(FileUtilsTest, TouchFileCreateWithAllPermissions) {
+  EXPECT_TRUE(TouchFile(file_path_, kPermissions777, geteuid(), getegid()));
+  ExpectFileContains("");
+  ExpectFilePermissions(kPermissions777);
+}
+
+TEST_F(FileUtilsTest, TouchFileCreateWithOwnerPermissions) {
+  EXPECT_TRUE(TouchFile(file_path_, kPermissions700, geteuid(), getegid()));
+  ExpectFileContains("");
+  ExpectFilePermissions(kPermissions700);
+}
+
+TEST_F(FileUtilsTest, TouchFileExistingPermissionsUnchanged) {
+  EXPECT_TRUE(TouchFile(file_path_, kPermissions777, geteuid(), getegid()));
+  EXPECT_TRUE(TouchFile(file_path_, kPermissions700, geteuid(), getegid()));
+  ExpectFileContains("");
+  ExpectFilePermissions(kPermissions777);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/flag_helper.cc b/libbrillo/brillo/flag_helper.cc
new file mode 100644
index 0000000..bb51818
--- /dev/null
+++ b/libbrillo/brillo/flag_helper.cc
@@ -0,0 +1,267 @@
+// Copyright 2014 The Chromium OS 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 "brillo/flag_helper.h"
+
+#include <memory>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <sysexits.h>
+
+#include <base/base_switches.h>
+#include <base/command_line.h>
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+#include <base/strings/string_number_conversions.h>
+
+namespace brillo {
+
+Flag::Flag(const char* name,
+           const char* default_value,
+           const char* help,
+           bool visible)
+    : name_(name),
+      default_value_(default_value),
+      help_(help),
+      visible_(visible) {
+}
+
+class HelpFlag : public brillo::Flag {
+ public:
+  HelpFlag() : Flag("help", "false", "Show this help message", true) {}
+
+  bool SetValue(const std::string& /* value */) override { return true; };
+  const char* GetType() const override { return "bool"; }
+};
+
+BoolFlag::BoolFlag(const char* name,
+                   bool* value,
+                   bool* no_value,
+                   const char* default_value,
+                   const char* help,
+                   bool visible)
+    : Flag(name, default_value, help, visible),
+      value_(value),
+      no_value_(no_value) {
+}
+
+bool BoolFlag::SetValue(const std::string& value) {
+  if (value.empty()) {
+    *value_ = true;
+  } else {
+    if (!value.compare("true"))
+      *value_ = true;
+    else if (!value.compare("false"))
+      *value_ = false;
+    else
+      return false;
+  }
+
+  *no_value_ = !*value_;
+
+  return true;
+}
+
+const char* BoolFlag::GetType() const {
+  return "bool";
+}
+
+Int32Flag::Int32Flag(const char* name,
+                     int* value,
+                     const char* default_value,
+                     const char* help,
+                     bool visible)
+    : Flag(name, default_value, help, visible), value_(value) {
+}
+
+bool Int32Flag::SetValue(const std::string& value) {
+  return base::StringToInt(value, value_);
+}
+
+const char* Int32Flag::GetType() const {
+  return "int";
+}
+
+Int64Flag::Int64Flag(const char* name,
+                     int64_t* value,
+                     const char* default_value,
+                     const char* help,
+                     bool visible)
+    : Flag(name, default_value, help, visible), value_(value) {
+}
+
+bool Int64Flag::SetValue(const std::string& value) {
+  return base::StringToInt64(value, value_);
+}
+
+const char* Int64Flag::GetType() const {
+  return "int64";
+}
+
+UInt64Flag::UInt64Flag(const char* name,
+                       uint64_t* value,
+                       const char* default_value,
+                       const char* help,
+                       bool visible)
+    : Flag(name, default_value, help, visible), value_(value) {
+}
+
+bool UInt64Flag::SetValue(const std::string& value) {
+  return base::StringToUint64(value, value_);
+}
+
+const char* UInt64Flag::GetType() const {
+  return "uint64";
+}
+
+DoubleFlag::DoubleFlag(const char* name,
+                       double* value,
+                       const char* default_value,
+                       const char* help,
+                       bool visible)
+    : Flag(name, default_value, help, visible), value_(value) {
+}
+
+bool DoubleFlag::SetValue(const std::string& value) {
+  return base::StringToDouble(value, value_);
+}
+
+const char* DoubleFlag::GetType() const {
+  return "double";
+}
+
+StringFlag::StringFlag(const char* name,
+                       std::string* value,
+                       const char* default_value,
+                       const char* help,
+                       bool visible)
+    : Flag(name, default_value, help, visible), value_(value) {
+}
+
+bool StringFlag::SetValue(const std::string& value) {
+  value_->assign(value);
+
+  return true;
+}
+
+const char* StringFlag::GetType() const {
+  return "string";
+}
+
+namespace {
+brillo::FlagHelper* instance_ = nullptr;
+}  // namespace
+
+FlagHelper::FlagHelper() : command_line_(nullptr) {
+  AddFlag(std::unique_ptr<Flag>(new HelpFlag()));
+}
+
+FlagHelper::~FlagHelper() {
+}
+
+brillo::FlagHelper* FlagHelper::GetInstance() {
+  if (!instance_)
+    instance_ = new FlagHelper();
+
+  return instance_;
+}
+
+void FlagHelper::ResetForTesting() {
+  delete instance_;
+  instance_ = nullptr;
+}
+
+void FlagHelper::Init(int argc,
+                      const char* const* argv,
+                      std::string help_usage) {
+  brillo::FlagHelper* helper = GetInstance();
+  if (!helper->command_line_) {
+    if (!base::CommandLine::InitializedForCurrentProcess())
+      base::CommandLine::Init(argc, argv);
+    helper->command_line_ = base::CommandLine::ForCurrentProcess();
+  }
+
+  GetInstance()->SetUsageMessage(help_usage);
+
+  GetInstance()->UpdateFlagValues();
+}
+
+void FlagHelper::UpdateFlagValues() {
+  std::string error_msg;
+  int error_code = EX_OK;
+
+  // Check that base::CommandLine has been initialized.
+  CHECK(base::CommandLine::InitializedForCurrentProcess());
+
+  // If the --help flag exists, print out help message and exit.
+  if (command_line_->HasSwitch("help")) {
+    puts(GetHelpMessage().c_str());
+    exit(EX_OK);
+  }
+
+  // Iterate over the base::CommandLine switches.  Update the value
+  // of the corresponding Flag if it exists, or output an error message
+  // if the flag wasn't defined.
+  const base::CommandLine::SwitchMap& switch_map = command_line_->GetSwitches();
+
+  for (const auto& pair : switch_map) {
+    const std::string& key = pair.first;
+    // Make sure we allow the standard logging switches (--v and --vmodule).
+    if (key == switches::kV || key == switches::kVModule)
+      continue;
+
+    const std::string& value = pair.second;
+
+    auto df_it = defined_flags_.find(key);
+    if (df_it != defined_flags_.end()) {
+      Flag* flag = df_it->second.get();
+      if (!flag->SetValue(value)) {
+        base::StringAppendF(
+            &error_msg,
+            "ERROR: illegal value '%s' specified for %s flag '%s'\n",
+            value.c_str(),
+            flag->GetType(),
+            flag->name_);
+        error_code = EX_DATAERR;
+      }
+    } else {
+      base::StringAppendF(
+          &error_msg, "ERROR: unknown command line flag '%s'\n", key.c_str());
+      error_code = EX_USAGE;
+    }
+  }
+
+  if (error_code != EX_OK) {
+    puts(error_msg.c_str());
+    exit(error_code);
+  }
+}
+
+void FlagHelper::AddFlag(std::unique_ptr<Flag> flag) {
+  defined_flags_.emplace(flag->name_, std::move(flag));
+}
+
+void FlagHelper::SetUsageMessage(std::string help_usage) {
+  help_usage_.assign(std::move(help_usage));
+}
+
+std::string FlagHelper::GetHelpMessage() const {
+  std::string help = help_usage_;
+  help.append("\n\n");
+  for (const auto& pair : defined_flags_) {
+    const Flag* flag = pair.second.get();
+    if (flag->visible_) {
+      base::StringAppendF(&help,
+                          "  --%s  (%s)  type: %s  default: %s\n",
+                          flag->name_,
+                          flag->help_,
+                          flag->GetType(),
+                          flag->default_value_);
+    }
+  }
+  return help;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/flag_helper.h b/libbrillo/brillo/flag_helper.h
new file mode 100644
index 0000000..810a00c
--- /dev/null
+++ b/libbrillo/brillo/flag_helper.h
@@ -0,0 +1,274 @@
+// Copyright 2014 The Chromium OS 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 is a helper class for dealing with command line flags.  It uses
+// base/command_line.h to parse flags from argv, but provides an API similar
+// to gflags.  Command line arguments with either '-' or '--' prefixes are
+// treated as flags.  Flags can optionally have a value set using an '='
+// delimeter, e.g. "--flag=value".  An argument of "--" will terminate flag
+// parsing, so that any subsequent arguments will be treated as non-flag
+// arguments, regardless of prefix.  Non-flag arguments are outside the scope
+// of this class, and can instead be accessed through the GetArgs() function
+// of the base::CommandLine singleton after FlagHelper initialization.
+//
+// The FlagHelper class will automatically take care of the --help flag, as
+// well as aborting the program when unknown flags are passed to the
+// application and when passed in parameters cannot be correctly parsed to
+// their respective types.  Developers define flags at compile time using the
+// following macros from within main():
+//
+//    DEFINE_bool(name, default_value, help)
+//    DEFINE_int32(name, default_value, help)
+//    DEFINE_int64(name, default_value, help)
+//    DEFINE_uint64(name, default_value, help)
+//    DEFINE_double(name, default_value, help)
+//    DEFINE_string(name, default_value, help)
+//
+// Using the macro will create a scoped variable of the appropriate type
+// with the name FLAGS_<name>, that can be used to access the flag's
+// value within the program.  Here is an example of how the FlagHelper
+// class is to be used:
+//
+// --
+//
+//  #include <brillo/flag_helper.h>
+//  #include <stdio.h>
+//
+//  int main(int argc, char** argv) {
+//    DEFINE_int32(example, 0, "Example int flag");
+//    brillo::FlagHelper::Init(argc, argv, "Test application.");
+//
+//    printf("You passed in %d to --example command line flag\n",
+//           FLAGS_example);
+//    return 0;
+//  }
+//
+// --
+//
+// In order to update the FLAGS_xxxx values from their defaults to the
+// values passed in to the command line, Init(...) must be called after
+// all the DEFINE_xxxx macros have instantiated the variables.
+
+#ifndef LIBBRILLO_BRILLO_FLAG_HELPER_H_
+#define LIBBRILLO_BRILLO_FLAG_HELPER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include <base/command_line.h>
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+// The corresponding class representation of a command line flag, used
+// to keep track of pointers to the FLAGS_xxxx variables so that they
+// can be updated.
+class Flag {
+ public:
+  Flag(const char* name,
+       const char* default_value,
+       const char* help,
+       bool visible);
+  virtual ~Flag() = default;
+
+  // Sets the associated FLAGS_xxxx value, taking into account the flag type
+  virtual bool SetValue(const std::string& value) = 0;
+
+  // Returns the type of the flag as a char array, for use in the help message
+  virtual const char* GetType() const = 0;
+
+  const char* name_;
+  const char* default_value_;
+  const char* help_;
+  bool visible_;
+};
+
+class BRILLO_EXPORT BoolFlag final : public Flag {
+ public:
+  BoolFlag(const char* name,
+           bool* value,
+           bool* no_value,
+           const char* default_value,
+           const char* help,
+           bool visible);
+  bool SetValue(const std::string& value) override;
+
+  const char* GetType() const override;
+
+ private:
+  bool* value_;
+  bool* no_value_;
+};
+
+class BRILLO_EXPORT Int32Flag final : public Flag {
+ public:
+  Int32Flag(const char* name,
+            int* value,
+            const char* default_value,
+            const char* help,
+            bool visible);
+  bool SetValue(const std::string& value) override;
+
+  const char* GetType() const override;
+
+ private:
+  int* value_;
+};
+
+class BRILLO_EXPORT Int64Flag final : public Flag {
+ public:
+  Int64Flag(const char* name,
+            int64_t* value,
+            const char* default_value,
+            const char* help,
+            bool visible);
+  bool SetValue(const std::string& value) override;
+
+  const char* GetType() const override;
+
+ private:
+  int64_t* value_;
+};
+
+class BRILLO_EXPORT UInt64Flag final : public Flag {
+ public:
+  UInt64Flag(const char* name,
+             uint64_t* value,
+             const char* default_value,
+             const char* help,
+             bool visible);
+  bool SetValue(const std::string& value) override;
+
+  const char* GetType() const override;
+
+ private:
+  uint64_t* value_;
+};
+
+class BRILLO_EXPORT DoubleFlag final : public Flag {
+ public:
+  DoubleFlag(const char* name,
+             double* value,
+             const char* default_value,
+             const char* help,
+             bool visible);
+  bool SetValue(const std::string& value) override;
+
+  const char* GetType() const override;
+
+ private:
+  double* value_;
+};
+
+class BRILLO_EXPORT StringFlag final : public Flag {
+ public:
+  StringFlag(const char* name,
+             std::string* value,
+             const char* default_value,
+             const char* help,
+             bool visible);
+  bool SetValue(const std::string& value) override;
+
+  const char* GetType() const override;
+
+ private:
+  std::string* value_;
+};
+
+// The following macros are to be used from within main() to create
+// scoped FLAGS_xxxx variables for easier access to command line flag
+// values.  FLAGS_noxxxx variables are also created, which are used to
+// set bool flags to false.  Creating the FLAGS_noxxxx variables here
+// will also ensure a compiler error will be thrown if another flag
+// is created with a conflicting name.
+#define DEFINE_type(type, classtype, name, value, help)                     \
+  type FLAGS_##name = value;                                                \
+  brillo::FlagHelper::GetInstance()->AddFlag(std::unique_ptr<brillo::Flag>( \
+      new brillo::classtype(#name, &FLAGS_##name, #value, help, true)));
+
+#define DEFINE_int32(name, value, help) \
+  DEFINE_type(int, Int32Flag, name, value, help)
+#define DEFINE_int64(name, value, help) \
+  DEFINE_type(int64_t, Int64Flag, name, value, help)
+#define DEFINE_uint64(name, value, help) \
+  DEFINE_type(uint64_t, UInt64Flag, name, value, help)
+#define DEFINE_double(name, value, help) \
+  DEFINE_type(double, DoubleFlag, name, value, help)
+#define DEFINE_string(name, value, help) \
+  DEFINE_type(std::string, StringFlag, name, value, help)
+
+// Due to the FLAGS_no##name variables, can't re-use the same DEFINE_type macro
+// for defining bool flags
+#define DEFINE_bool(name, value, help)                                  \
+  bool FLAGS_##name = value;                                            \
+  bool FLAGS_no##name = !(value);                                       \
+  brillo::FlagHelper::GetInstance()->AddFlag(                           \
+      std::unique_ptr<brillo::Flag>(new brillo::BoolFlag(               \
+          #name, &FLAGS_##name, &FLAGS_no##name, #value, help, true))); \
+  brillo::FlagHelper::GetInstance()->AddFlag(                           \
+      std::unique_ptr<brillo::Flag>(new brillo::BoolFlag(               \
+          "no" #name, &FLAGS_no##name, &FLAGS_##name, #value, help, false)));
+
+// The FlagHelper class is a singleton class used for registering command
+// line flags and pointers to their associated scoped variables, so that
+// the variables can be updated once the command line arguments have been
+// parsed by base::CommandLine.
+class BRILLO_EXPORT FlagHelper final {
+ public:
+  // The singleton accessor function.
+  static FlagHelper* GetInstance();
+
+  // Resets the singleton object.  Developers shouldn't ever need to use this,
+  // however it is required to be run at the end of every unit test to prevent
+  // Flag definitions from carrying over from previous tests.
+  static void ResetForTesting();
+
+  // Initializes the base::CommandLine class, then calls UpdateFlagValues().
+  static void Init(int argc, const char* const* argv, std::string help_usage);
+
+  // Only to be used for running unit tests.
+  void set_command_line_for_testing(base::CommandLine* command_line) {
+    command_line_ = command_line;
+  }
+
+  // Checks all the parsed command line flags.  This iterates over the switch
+  // map from base::CommandLine, and finds the corresponding Flag in order to
+  // update the FLAGS_xxxx values to the parsed value.  If the --help flag is
+  // passed in, it outputs a help message and exits the program.  If an unknown
+  // flag is passed in, it outputs an error message and exits the program with
+  // exit code EX_USAGE.
+  void UpdateFlagValues();
+
+  // Adds a flag to be tracked and updated once the command line is actually
+  // parsed.  This function is an implementation detail, and is not meant
+  // to be used directly by developers.  Developers should instead use the
+  // DEFINE_xxxx macros to register a command line flag.
+  void AddFlag(std::unique_ptr<Flag> flag);
+
+  // Sets the usage message, which is prepended to the --help message.
+  void SetUsageMessage(std::string help_usage);
+
+ private:
+  FlagHelper();
+  ~FlagHelper();
+
+  // Generates a help message from the Usage Message and registered flags.
+  std::string GetHelpMessage() const;
+
+  std::string help_usage_;
+  std::map<std::string, std::unique_ptr<Flag>> defined_flags_;
+
+  // base::CommandLine object for parsing the command line switches.  This
+  // object isn't owned by this class, so don't need to delete it in the
+  // destructor.
+  base::CommandLine* command_line_;
+
+  DISALLOW_COPY_AND_ASSIGN(FlagHelper);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_FLAG_HELPER_H_
diff --git a/libbrillo/brillo/flag_helper_unittest.cc b/libbrillo/brillo/flag_helper_unittest.cc
new file mode 100644
index 0000000..29c6429
--- /dev/null
+++ b/libbrillo/brillo/flag_helper_unittest.cc
@@ -0,0 +1,362 @@
+// Copyright 2014 The Chromium OS 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 <cstdint>
+#include <cstdio>
+#include <sysexits.h>
+
+#include <base/command_line.h>
+#include <base/macros.h>
+#include <brillo/flag_helper.h>
+
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+class FlagHelperTest : public ::testing::Test {
+ public:
+  FlagHelperTest() {}
+  ~FlagHelperTest() override { brillo::FlagHelper::ResetForTesting(); }
+  static void SetUpTestCase() { base::CommandLine::Init(0, nullptr); }
+};
+
+// Test that the DEFINE_xxxx macros can create the respective variables
+// correctly with the default value.
+TEST_F(FlagHelperTest, Defaults) {
+  DEFINE_bool(bool1, true, "Test bool flag");
+  DEFINE_bool(bool2, false, "Test bool flag");
+  DEFINE_int32(int32_1, INT32_MIN, "Test int32 flag");
+  DEFINE_int32(int32_2, 0, "Test int32 flag");
+  DEFINE_int32(int32_3, INT32_MAX, "Test int32 flag");
+  DEFINE_int64(int64_1, INT64_MIN, "Test int64 flag");
+  DEFINE_int64(int64_2, 0, "Test int64 flag");
+  DEFINE_int64(int64_3, INT64_MAX, "Test int64 flag");
+  DEFINE_uint64(uint64_1, 0, "Test uint64 flag");
+  DEFINE_uint64(uint64_2, UINT_LEAST64_MAX, "Test uint64 flag");
+  DEFINE_double(double_1, -100.5, "Test double flag");
+  DEFINE_double(double_2, 0, "Test double flag");
+  DEFINE_double(double_3, 100.5, "Test double flag");
+  DEFINE_string(string_1, "", "Test string flag");
+  DEFINE_string(string_2, "value", "Test string flag");
+
+  const char* argv[] = {"test_program"};
+  base::CommandLine command_line(arraysize(argv), argv);
+
+  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+      &command_line);
+  brillo::FlagHelper::Init(arraysize(argv), argv, "TestDefaultTrue");
+
+  EXPECT_TRUE(FLAGS_bool1);
+  EXPECT_FALSE(FLAGS_bool2);
+  EXPECT_EQ(FLAGS_int32_1, INT32_MIN);
+  EXPECT_EQ(FLAGS_int32_2, 0);
+  EXPECT_EQ(FLAGS_int32_3, INT32_MAX);
+  EXPECT_EQ(FLAGS_int64_1, INT64_MIN);
+  EXPECT_EQ(FLAGS_int64_2, 0);
+  EXPECT_EQ(FLAGS_int64_3, INT64_MAX);
+  EXPECT_EQ(FLAGS_uint64_1, 0);
+  EXPECT_EQ(FLAGS_uint64_2, UINT_LEAST64_MAX);
+  EXPECT_DOUBLE_EQ(FLAGS_double_1, -100.5);
+  EXPECT_DOUBLE_EQ(FLAGS_double_2, 0);
+  EXPECT_DOUBLE_EQ(FLAGS_double_3, 100.5);
+  EXPECT_STREQ(FLAGS_string_1.c_str(), "");
+  EXPECT_STREQ(FLAGS_string_2.c_str(), "value");
+}
+
+// Test that command line flag values are parsed and update the flag
+// variable values correctly when using double '--' flags
+TEST_F(FlagHelperTest, SetValueDoubleDash) {
+  DEFINE_bool(bool1, false, "Test bool flag");
+  DEFINE_bool(bool2, true, "Test bool flag");
+  DEFINE_bool(bool3, false, "Test bool flag");
+  DEFINE_bool(bool4, true, "Test bool flag");
+  DEFINE_int32(int32_1, 1, "Test int32 flag");
+  DEFINE_int32(int32_2, 1, "Test int32 flag");
+  DEFINE_int32(int32_3, 1, "Test int32 flag");
+  DEFINE_int64(int64_1, 1, "Test int64 flag");
+  DEFINE_int64(int64_2, 1, "Test int64 flag");
+  DEFINE_int64(int64_3, 1, "Test int64 flag");
+  DEFINE_uint64(uint64_1, 1, "Test uint64 flag");
+  DEFINE_uint64(uint64_2, 1, "Test uint64 flag");
+  DEFINE_double(double_1, 1, "Test double flag");
+  DEFINE_double(double_2, 1, "Test double flag");
+  DEFINE_double(double_3, 1, "Test double flag");
+  DEFINE_string(string_1, "default", "Test string flag");
+  DEFINE_string(string_2, "default", "Test string flag");
+
+  const char* argv[] = {"test_program",
+                        "--bool1",
+                        "--nobool2",
+                        "--bool3=true",
+                        "--bool4=false",
+                        "--int32_1=-2147483648",
+                        "--int32_2=0",
+                        "--int32_3=2147483647",
+                        "--int64_1=-9223372036854775808",
+                        "--int64_2=0",
+                        "--int64_3=9223372036854775807",
+                        "--uint64_1=0",
+                        "--uint64_2=18446744073709551615",
+                        "--double_1=-100.5",
+                        "--double_2=0",
+                        "--double_3=100.5",
+                        "--string_1=",
+                        "--string_2=value"};
+  base::CommandLine command_line(arraysize(argv), argv);
+
+  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+      &command_line);
+  brillo::FlagHelper::Init(arraysize(argv), argv, "TestDefaultTrue");
+
+  EXPECT_TRUE(FLAGS_bool1);
+  EXPECT_FALSE(FLAGS_bool2);
+  EXPECT_TRUE(FLAGS_bool3);
+  EXPECT_FALSE(FLAGS_bool4);
+  EXPECT_EQ(FLAGS_int32_1, INT32_MIN);
+  EXPECT_EQ(FLAGS_int32_2, 0);
+  EXPECT_EQ(FLAGS_int32_3, INT32_MAX);
+  EXPECT_EQ(FLAGS_int64_1, INT64_MIN);
+  EXPECT_EQ(FLAGS_int64_2, 0);
+  EXPECT_EQ(FLAGS_int64_3, INT64_MAX);
+  EXPECT_EQ(FLAGS_uint64_1, 0);
+  EXPECT_EQ(FLAGS_uint64_2, UINT_LEAST64_MAX);
+  EXPECT_DOUBLE_EQ(FLAGS_double_1, -100.5);
+  EXPECT_DOUBLE_EQ(FLAGS_double_2, 0);
+  EXPECT_DOUBLE_EQ(FLAGS_double_3, 100.5);
+  EXPECT_STREQ(FLAGS_string_1.c_str(), "");
+  EXPECT_STREQ(FLAGS_string_2.c_str(), "value");
+}
+
+// Test that command line flag values are parsed and update the flag
+// variable values correctly when using single '-' flags
+TEST_F(FlagHelperTest, SetValueSingleDash) {
+  DEFINE_bool(bool1, false, "Test bool flag");
+  DEFINE_bool(bool2, true, "Test bool flag");
+  DEFINE_int32(int32_1, 1, "Test int32 flag");
+  DEFINE_int32(int32_2, 1, "Test int32 flag");
+  DEFINE_int32(int32_3, 1, "Test int32 flag");
+  DEFINE_int64(int64_1, 1, "Test int64 flag");
+  DEFINE_int64(int64_2, 1, "Test int64 flag");
+  DEFINE_int64(int64_3, 1, "Test int64 flag");
+  DEFINE_uint64(uint64_1, 1, "Test uint64 flag");
+  DEFINE_uint64(uint64_2, 1, "Test uint64 flag");
+  DEFINE_double(double_1, 1, "Test double flag");
+  DEFINE_double(double_2, 1, "Test double flag");
+  DEFINE_double(double_3, 1, "Test double flag");
+  DEFINE_string(string_1, "default", "Test string flag");
+  DEFINE_string(string_2, "default", "Test string flag");
+
+  const char* argv[] = {"test_program",
+                        "-bool1",
+                        "-nobool2",
+                        "-int32_1=-2147483648",
+                        "-int32_2=0",
+                        "-int32_3=2147483647",
+                        "-int64_1=-9223372036854775808",
+                        "-int64_2=0",
+                        "-int64_3=9223372036854775807",
+                        "-uint64_1=0",
+                        "-uint64_2=18446744073709551615",
+                        "-double_1=-100.5",
+                        "-double_2=0",
+                        "-double_3=100.5",
+                        "-string_1=",
+                        "-string_2=value"};
+  base::CommandLine command_line(arraysize(argv), argv);
+
+  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+      &command_line);
+  brillo::FlagHelper::Init(arraysize(argv), argv, "TestDefaultTrue");
+
+  EXPECT_TRUE(FLAGS_bool1);
+  EXPECT_FALSE(FLAGS_bool2);
+  EXPECT_EQ(FLAGS_int32_1, INT32_MIN);
+  EXPECT_EQ(FLAGS_int32_2, 0);
+  EXPECT_EQ(FLAGS_int32_3, INT32_MAX);
+  EXPECT_EQ(FLAGS_int64_1, INT64_MIN);
+  EXPECT_EQ(FLAGS_int64_2, 0);
+  EXPECT_EQ(FLAGS_int64_3, INT64_MAX);
+  EXPECT_EQ(FLAGS_uint64_1, 0);
+  EXPECT_EQ(FLAGS_uint64_2, UINT_LEAST64_MAX);
+  EXPECT_DOUBLE_EQ(FLAGS_double_1, -100.5);
+  EXPECT_DOUBLE_EQ(FLAGS_double_2, 0);
+  EXPECT_DOUBLE_EQ(FLAGS_double_3, 100.5);
+  EXPECT_STREQ(FLAGS_string_1.c_str(), "");
+  EXPECT_STREQ(FLAGS_string_2.c_str(), "value");
+}
+
+// Test that a duplicated flag on the command line picks up the last
+// value set.
+TEST_F(FlagHelperTest, DuplicateSetValue) {
+  DEFINE_int32(int32_1, 0, "Test in32 flag");
+
+  const char* argv[] = {"test_program", "--int32_1=5", "--int32_1=10"};
+  base::CommandLine command_line(arraysize(argv), argv);
+
+  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+      &command_line);
+  brillo::FlagHelper::Init(arraysize(argv), argv, "TestDuplicateSetvalue");
+
+  EXPECT_EQ(FLAGS_int32_1, 10);
+}
+
+// Test that flags set after the -- marker are not parsed as command line flags
+TEST_F(FlagHelperTest, FlagTerminator) {
+  DEFINE_int32(int32_1, 0, "Test int32 flag");
+
+  const char* argv[] = {"test_program", "--int32_1=5", "--", "--int32_1=10"};
+  base::CommandLine command_line(arraysize(argv), argv);
+
+  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+      &command_line);
+  brillo::FlagHelper::Init(arraysize(argv), argv, "TestFlagTerminator");
+
+  EXPECT_EQ(FLAGS_int32_1, 5);
+}
+
+// Test that help messages are generated correctly when the --help flag
+// is passed to the program.
+TEST_F(FlagHelperTest, HelpMessage) {
+  DEFINE_bool(bool_1, true, "Test bool flag");
+  DEFINE_int32(int_1, 0, "Test int flag");
+  DEFINE_int64(int64_1, 0, "Test int64 flag");
+  DEFINE_uint64(uint64_1, 0, "Test uint64 flag");
+  DEFINE_double(double_1, 0, "Test double flag");
+  DEFINE_string(string_1, "", "Test string flag");
+
+  const char* argv[] = {"test_program", "--int_1=value", "--help"};
+  base::CommandLine command_line(arraysize(argv), argv);
+
+  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+      &command_line);
+
+  FILE* orig = stdout;
+  stdout = stderr;
+
+  ASSERT_EXIT(
+      brillo::FlagHelper::Init(arraysize(argv), argv, "TestHelpMessage"),
+      ::testing::ExitedWithCode(EX_OK),
+      "TestHelpMessage\n\n"
+      "  --bool_1  \\(Test bool flag\\)  type: bool  default: true\n"
+      "  --double_1  \\(Test double flag\\)  type: double  default: 0\n"
+      "  --help  \\(Show this help message\\)  type: bool  default: false\n"
+      "  --int64_1  \\(Test int64 flag\\)  type: int64  default: 0\n"
+      "  --int_1  \\(Test int flag\\)  type: int  default: 0\n"
+      "  --string_1  \\(Test string flag\\)  type: string  default: \"\"\n"
+      "  --uint64_1  \\(Test uint64 flag\\)  type: uint64  default: 0\n");
+
+  stdout = orig;
+}
+
+// Test that passing in unknown command line flags causes the program
+// to exit with EX_USAGE error code and corresponding error message.
+TEST_F(FlagHelperTest, UnknownFlag) {
+  const char* argv[] = {"test_program", "--flag=value"};
+  base::CommandLine command_line(arraysize(argv), argv);
+
+  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+      &command_line);
+
+  FILE* orig = stdout;
+  stdout = stderr;
+
+  ASSERT_EXIT(brillo::FlagHelper::Init(arraysize(argv), argv, "TestIntExit"),
+              ::testing::ExitedWithCode(EX_USAGE),
+              "ERROR: unknown command line flag 'flag'");
+
+  stdout = orig;
+}
+
+// Test that when passing an incorrect/unparsable type to a command line flag,
+// the program exits with code EX_DATAERR and outputs a corresponding message.
+TEST_F(FlagHelperTest, BoolParseError) {
+  DEFINE_bool(bool_1, 0, "Test bool flag");
+
+  const char* argv[] = {"test_program", "--bool_1=value"};
+  base::CommandLine command_line(arraysize(argv), argv);
+
+  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+      &command_line);
+
+  FILE* orig = stdout;
+  stdout = stderr;
+
+  ASSERT_EXIT(
+      brillo::FlagHelper::Init(arraysize(argv), argv, "TestBoolParseError"),
+      ::testing::ExitedWithCode(EX_DATAERR),
+      "ERROR: illegal value 'value' specified for bool flag 'bool_1'");
+
+  stdout = orig;
+}
+
+// Test that when passing an incorrect/unparsable type to a command line flag,
+// the program exits with code EX_DATAERR and outputs a corresponding message.
+TEST_F(FlagHelperTest, Int32ParseError) {
+  DEFINE_int32(int_1, 0, "Test int flag");
+
+  const char* argv[] = {"test_program", "--int_1=value"};
+  base::CommandLine command_line(arraysize(argv), argv);
+
+  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+      &command_line);
+
+  FILE* orig = stdout;
+  stdout = stderr;
+
+  ASSERT_EXIT(brillo::FlagHelper::Init(arraysize(argv),
+                                       argv,
+                                       "TestInt32ParseError"),
+              ::testing::ExitedWithCode(EX_DATAERR),
+              "ERROR: illegal value 'value' specified for int flag 'int_1'");
+
+  stdout = orig;
+}
+
+// Test that when passing an incorrect/unparsable type to a command line flag,
+// the program exits with code EX_DATAERR and outputs a corresponding message.
+TEST_F(FlagHelperTest, Int64ParseError) {
+  DEFINE_int64(int64_1, 0, "Test int64 flag");
+
+  const char* argv[] = {"test_program", "--int64_1=value"};
+  base::CommandLine command_line(arraysize(argv), argv);
+
+  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+      &command_line);
+
+  FILE* orig = stdout;
+  stdout = stderr;
+
+  ASSERT_EXIT(
+      brillo::FlagHelper::Init(arraysize(argv), argv, "TestInt64ParseError"),
+      ::testing::ExitedWithCode(EX_DATAERR),
+      "ERROR: illegal value 'value' specified for int64 flag "
+      "'int64_1'");
+
+  stdout = orig;
+}
+
+// Test that when passing an incorrect/unparsable type to a command line flag,
+// the program exits with code EX_DATAERR and outputs a corresponding message.
+TEST_F(FlagHelperTest, UInt64ParseError) {
+  DEFINE_uint64(uint64_1, 0, "Test uint64 flag");
+
+  const char* argv[] = {"test_program", "--uint64_1=value"};
+  base::CommandLine command_line(arraysize(argv), argv);
+
+  brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+      &command_line);
+
+  FILE* orig = stdout;
+  stdout = stderr;
+
+  ASSERT_EXIT(
+      brillo::FlagHelper::Init(arraysize(argv), argv, "TestUInt64ParseError"),
+      ::testing::ExitedWithCode(EX_DATAERR),
+      "ERROR: illegal value 'value' specified for uint64 flag "
+      "'uint64_1'");
+
+  stdout = orig;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/glib/abstract_dbus_service.cc b/libbrillo/brillo/glib/abstract_dbus_service.cc
new file mode 100644
index 0000000..c5ed27d
--- /dev/null
+++ b/libbrillo/brillo/glib/abstract_dbus_service.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2010 The Chromium OS 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 <base/logging.h>
+
+#include "brillo/glib/abstract_dbus_service.h"
+
+namespace brillo {
+namespace dbus {
+
+bool AbstractDbusService::Register(const brillo::dbus::BusConnection& conn) {
+  return RegisterExclusiveService(conn,
+                                  service_interface(),
+                                  service_name(),
+                                  service_path(),
+                                  service_object());
+}
+
+bool AbstractDbusService::Run() {
+  if (!main_loop()) {
+    LOG(ERROR) << "No run loop. Call Initialize before use.";
+    return false;
+  }
+  ::g_main_loop_run(main_loop());
+  DLOG(INFO) << "Run() completed";
+  return true;
+}
+
+bool AbstractDbusService::Shutdown() {
+  ::g_main_loop_quit(main_loop());
+  return true;
+}
+
+}  // namespace dbus
+}  // namespace brillo
diff --git a/libbrillo/brillo/glib/abstract_dbus_service.h b/libbrillo/brillo/glib/abstract_dbus_service.h
new file mode 100644
index 0000000..c40b658
--- /dev/null
+++ b/libbrillo/brillo/glib/abstract_dbus_service.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2010 The Chromium OS 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 LIBBRILLO_BRILLO_GLIB_ABSTRACT_DBUS_SERVICE_H_
+#define LIBBRILLO_BRILLO_GLIB_ABSTRACT_DBUS_SERVICE_H_
+
+#include <brillo/brillo_export.h>
+#include <brillo/glib/dbus.h>
+
+namespace brillo {
+
+// \precondition No functions in the dbus namespace can be called before
+// ::g_type_init();
+
+namespace dbus {
+class BRILLO_EXPORT AbstractDbusService {
+ public:
+  virtual ~AbstractDbusService() {}
+
+  // Setup the wrapped GObject and the GMainLoop
+  virtual bool Initialize() = 0;
+  virtual bool Reset() = 0;
+
+  // Registers the GObject as a service with the system DBus
+  // TODO(wad) make this testable by making BusConn and Proxy
+  //           subclassing friendly.
+  virtual bool Register(const brillo::dbus::BusConnection& conn);
+
+  // Starts the run loop
+  virtual bool Run();
+
+  // Stops the run loop
+  virtual bool Shutdown();
+
+  // Used internally during registration to set the
+  // proper service information.
+  virtual const char* service_name() const = 0;
+  virtual const char* service_path() const = 0;
+  virtual const char* service_interface() const = 0;
+  virtual GObject* service_object() const = 0;
+
+ protected:
+  virtual GMainLoop* main_loop() = 0;
+};
+
+}  // namespace dbus
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_GLIB_ABSTRACT_DBUS_SERVICE_H_
diff --git a/libbrillo/brillo/glib/dbus.cc b/libbrillo/brillo/glib/dbus.cc
new file mode 100644
index 0000000..c56a88c
--- /dev/null
+++ b/libbrillo/brillo/glib/dbus.cc
@@ -0,0 +1,356 @@
+// Copyright (c) 2009 The Chromium OS 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 "brillo/glib/dbus.h"
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-bindings.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+
+namespace brillo {
+namespace dbus {
+
+bool CallPtrArray(const Proxy& proxy,
+                  const char* method,
+                  glib::ScopedPtrArray<const char*>* result) {
+  glib::ScopedError error;
+
+  ::GType g_type_array = ::dbus_g_type_get_collection("GPtrArray",
+                                                       DBUS_TYPE_G_OBJECT_PATH);
+
+
+  if (!::dbus_g_proxy_call(proxy.gproxy(), method, &Resetter(&error).lvalue(),
+                           G_TYPE_INVALID, g_type_array,
+                           &Resetter(result).lvalue(), G_TYPE_INVALID)) {
+    LOG(WARNING) << "CallPtrArray failed: "
+        << (error->message ? error->message : "Unknown Error.");
+    return false;
+  }
+
+  return true;
+}
+
+BusConnection GetSystemBusConnection() {
+  glib::ScopedError error;
+  ::DBusGConnection* result = ::dbus_g_bus_get(DBUS_BUS_SYSTEM,
+                                               &Resetter(&error).lvalue());
+  if (!result) {
+    LOG(ERROR) << "dbus_g_bus_get(DBUS_BUS_SYSTEM) failed: "
+               << ((error.get() && error->message) ?
+                   error->message : "Unknown Error");
+    return BusConnection(nullptr);
+  }
+  // Set to not exit when system bus is disconnected.
+  // This fixes the problem where when the dbus daemon is stopped, exit is
+  // called which kills Chrome.
+  ::dbus_connection_set_exit_on_disconnect(
+      ::dbus_g_connection_get_connection(result), FALSE);
+  return BusConnection(result);
+}
+
+BusConnection GetPrivateBusConnection(const char* address) {
+  // Since dbus-glib does not have an API like dbus_g_connection_open_private(),
+  // we have to implement our own.
+
+  // We have to call _dbus_g_value_types_init() to register standard marshalers
+  // just like as dbus_g_bus_get() and dbus_g_connection_open() do, but the
+  // function is not exported. So we call GetPrivateBusConnection() which calls
+  // dbus_g_bus_get() here instead. Note that if we don't call
+  // _dbus_g_value_types_init(), we might get "WARNING **: No demarshaller
+  // registered for type xxxxx" error and might not be able to handle incoming
+  // signals nor method calls.
+  {
+    BusConnection system_bus_connection = GetSystemBusConnection();
+    if (!system_bus_connection.HasConnection()) {
+      return system_bus_connection;  // returns NULL connection.
+    }
+  }
+
+  ::DBusError error;
+  ::dbus_error_init(&error);
+
+  ::DBusGConnection* result = nullptr;
+  ::DBusConnection* raw_connection
+        = ::dbus_connection_open_private(address, &error);
+  if (!raw_connection) {
+    LOG(WARNING) << "dbus_connection_open_private failed: " << address;
+    return BusConnection(nullptr);
+  }
+
+  if (!::dbus_bus_register(raw_connection, &error)) {
+    LOG(ERROR) << "dbus_bus_register failed: "
+               << (error.message ? error.message : "Unknown Error.");
+    ::dbus_error_free(&error);
+    // TODO(yusukes): We don't call dbus_connection_close() nor g_object_unref()
+    // here for now since these calls might interfere with IBusBus connections
+    // in libcros and Chrome. See the comment in ~InputMethodStatusConnection()
+    // function in platform/cros/chromeos_input_method.cc for details.
+    return BusConnection(nullptr);
+  }
+
+  ::dbus_connection_setup_with_g_main(
+      raw_connection, nullptr /* default context */);
+
+  // A reference count of |raw_connection| is transferred to |result|. You don't
+  // have to (and should not) unref the |raw_connection|.
+  result = ::dbus_connection_get_g_connection(raw_connection);
+  CHECK(result);
+
+  ::dbus_connection_set_exit_on_disconnect(
+      ::dbus_g_connection_get_connection(result), FALSE);
+
+  return BusConnection(result);
+}
+
+bool RetrieveProperties(const Proxy& proxy,
+                        const char* interface,
+                        glib::ScopedHashTable* result) {
+  glib::ScopedError error;
+
+  if (!::dbus_g_proxy_call(proxy.gproxy(), "GetAll", &Resetter(&error).lvalue(),
+                           G_TYPE_STRING, interface, G_TYPE_INVALID,
+                           ::dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
+                                                 G_TYPE_VALUE),
+                           &Resetter(result).lvalue(), G_TYPE_INVALID)) {
+    LOG(WARNING) << "RetrieveProperties failed: "
+        << (error->message ? error->message : "Unknown Error.");
+    return false;
+  }
+  return true;
+}
+
+Proxy::Proxy()
+    : object_(nullptr) {
+}
+
+// Set |connect_to_name_owner| true if you'd like to use
+// dbus_g_proxy_new_for_name_owner() rather than dbus_g_proxy_new_for_name().
+Proxy::Proxy(const BusConnection& connection,
+             const char* name,
+             const char* path,
+             const char* interface,
+             bool connect_to_name_owner)
+    : object_(GetGProxy(
+        connection, name, path, interface, connect_to_name_owner)) {
+}
+
+// Equivalent to Proxy(connection, name, path, interface, false).
+Proxy::Proxy(const BusConnection& connection,
+             const char* name,
+             const char* path,
+             const char* interface)
+    : object_(GetGProxy(connection, name, path, interface, false)) {
+}
+
+// Creates a peer proxy using dbus_g_proxy_new_for_peer.
+Proxy::Proxy(const BusConnection& connection,
+             const char* path,
+             const char* interface)
+    : object_(GetGPeerProxy(connection, path, interface)) {
+}
+
+Proxy::Proxy(const Proxy& x)
+    : object_(x.object_) {
+  if (object_)
+    ::g_object_ref(object_);
+}
+
+Proxy::~Proxy() {
+  if (object_)
+    ::g_object_unref(object_);
+}
+
+/* static */
+Proxy::value_type Proxy::GetGProxy(const BusConnection& connection,
+                                   const char* name,
+                                   const char* path,
+                                   const char* interface,
+                                   bool connect_to_name_owner) {
+  value_type result = nullptr;
+  if (connect_to_name_owner) {
+    glib::ScopedError error;
+    result = ::dbus_g_proxy_new_for_name_owner(connection.object_,
+                                               name,
+                                               path,
+                                               interface,
+                                               &Resetter(&error).lvalue());
+    if (!result) {
+      DLOG(ERROR) << "Failed to construct proxy: "
+                  << (error->message ? error->message : "Unknown Error")
+                  << ": " << path;
+    }
+  } else {
+    result = ::dbus_g_proxy_new_for_name(connection.object_,
+                                         name,
+                                         path,
+                                         interface);
+    if (!result) {
+      LOG(ERROR) << "Failed to construct proxy: " << path;
+    }
+  }
+  return result;
+}
+
+/* static */
+Proxy::value_type Proxy::GetGPeerProxy(const BusConnection& connection,
+                                       const char* path,
+                                       const char* interface) {
+  value_type result = ::dbus_g_proxy_new_for_peer(connection.object_,
+                                                  path,
+                                                  interface);
+  if (!result)
+    LOG(ERROR) << "Failed to construct peer proxy: " << path;
+
+  return result;
+}
+
+bool RegisterExclusiveService(const BusConnection& connection,
+                              const char* interface_name,
+                              const char* service_name,
+                              const char* service_path,
+                              GObject* object) {
+  CHECK(object);
+  CHECK(interface_name);
+  CHECK(service_name);
+  // Create a proxy to DBus itself so that we can request to become a
+  // service name owner and then register an object at the related service path.
+  Proxy proxy = brillo::dbus::Proxy(connection,
+                                      DBUS_SERVICE_DBUS,
+                                      DBUS_PATH_DBUS,
+                                      DBUS_INTERFACE_DBUS);
+  // Exclusivity is determined by replacing any existing
+  // service, not queuing, and ensuring we are the primary
+  // owner after the name is ours.
+  glib::ScopedError err;
+  guint result = 0;
+  // TODO(wad) determine if we are moving away from using generated functions
+  if (!org_freedesktop_DBus_request_name(proxy.gproxy(),
+                                         service_name,
+                                         0,
+                                         &result,
+                                         &Resetter(&err).lvalue())) {
+    LOG(ERROR) << "Unable to request service name: "
+               << (err->message ? err->message : "Unknown Error.");
+    return false;
+  }
+
+  // Handle the error codes, releasing the name if exclusivity conditions
+  // are not met.
+  bool needs_release = false;
+  if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+    LOG(ERROR) << "Failed to become the primary owner. Releasing . . .";
+    needs_release = true;
+  }
+  if (result == DBUS_REQUEST_NAME_REPLY_EXISTS) {
+    LOG(ERROR) << "Service name exists: " << service_name;
+    return false;
+  } else if (result == DBUS_REQUEST_NAME_REPLY_IN_QUEUE) {
+    LOG(ERROR) << "Service name request enqueued despite our flags. Releasing";
+    needs_release = true;
+  }
+  LOG_IF(WARNING, result == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER)
+    << "Service name already owned by this process";
+  if (needs_release) {
+    if (!org_freedesktop_DBus_release_name(
+           proxy.gproxy(),
+           service_name,
+           &result,
+           &Resetter(&err).lvalue())) {
+      LOG(ERROR) << "Unabled to release service name: "
+                 << (err->message ? err->message : "Unknown Error.");
+    }
+    DLOG(INFO) << "ReleaseName returned code " << result;
+    return false;
+  }
+
+  // Determine a path from the service name and register the object.
+  dbus_g_connection_register_g_object(connection.g_connection(),
+                                      service_path,
+                                      object);
+  return true;
+}
+
+void CallMethodWithNoArguments(const char* service_name,
+                               const char* path,
+                               const char* interface_name,
+                               const char* method_name) {
+  Proxy proxy(dbus::GetSystemBusConnection(),
+              service_name,
+              path,
+              interface_name);
+  ::dbus_g_proxy_call_no_reply(proxy.gproxy(), method_name, G_TYPE_INVALID);
+}
+
+void SignalWatcher::StartMonitoring(const std::string& interface,
+                                    const std::string& signal) {
+  DCHECK(interface_.empty()) << "StartMonitoring() must be called only once";
+  interface_ = interface;
+  signal_ = signal;
+
+  // Snoop on D-Bus messages so we can get notified about signals.
+  DBusConnection* dbus_conn = dbus_g_connection_get_connection(
+      GetSystemBusConnection().g_connection());
+  DCHECK(dbus_conn);
+
+  DBusError error;
+  dbus_error_init(&error);
+  dbus_bus_add_match(dbus_conn, GetDBusMatchString().c_str(), &error);
+  if (dbus_error_is_set(&error)) {
+    LOG(DFATAL) << "Got error while adding D-Bus match rule: " << error.name
+                << " (" << error.message << ")";
+  }
+
+  if (!dbus_connection_add_filter(dbus_conn,
+                                  &SignalWatcher::FilterDBusMessage,
+                                  this,        // user_data
+                                  nullptr)) {  // free_data_function
+    LOG(DFATAL) << "Unable to add D-Bus filter";
+  }
+}
+
+SignalWatcher::~SignalWatcher() {
+  if (interface_.empty())
+    return;
+
+  DBusConnection* dbus_conn = dbus_g_connection_get_connection(
+      dbus::GetSystemBusConnection().g_connection());
+  DCHECK(dbus_conn);
+
+  dbus_connection_remove_filter(dbus_conn,
+                                &SignalWatcher::FilterDBusMessage,
+                                this);
+
+  DBusError error;
+  dbus_error_init(&error);
+  dbus_bus_remove_match(dbus_conn, GetDBusMatchString().c_str(), &error);
+  if (dbus_error_is_set(&error)) {
+    LOG(DFATAL) << "Got error while removing D-Bus match rule: " << error.name
+                << " (" << error.message << ")";
+  }
+}
+
+std::string SignalWatcher::GetDBusMatchString() const {
+  return base::StringPrintf("type='signal', interface='%s', member='%s'",
+                            interface_.c_str(), signal_.c_str());
+}
+
+/* static */
+DBusHandlerResult SignalWatcher::FilterDBusMessage(DBusConnection* dbus_conn,
+                                                   DBusMessage* message,
+                                                   void* data) {
+  SignalWatcher* self = static_cast<SignalWatcher*>(data);
+  if (dbus_message_is_signal(
+          message, self->interface_.c_str(), self->signal_.c_str())) {
+    self->OnSignal(message);
+    return DBUS_HANDLER_RESULT_HANDLED;
+  } else {
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
+}
+
+}  // namespace dbus
+}  // namespace brillo
diff --git a/libbrillo/brillo/glib/dbus.h b/libbrillo/brillo/glib/dbus.h
new file mode 100644
index 0000000..6006009
--- /dev/null
+++ b/libbrillo/brillo/glib/dbus.h
@@ -0,0 +1,468 @@
+// Copyright (c) 2009 The Chromium OS 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 LIBBRILLO_BRILLO_GLIB_DBUS_H_
+#define LIBBRILLO_BRILLO_GLIB_DBUS_H_
+
+#include <dbus/dbus-glib.h>
+#include <glib-object.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/logging.h"
+#include <brillo/brillo_export.h>
+#include <brillo/glib/object.h>
+
+struct DBusMessage;
+struct DBusConnection;
+
+namespace brillo {
+
+// \precondition No functions in the dbus namespace can be called before
+// ::g_type_init();
+
+namespace dbus {
+
+// \brief   BusConnection manages the ref-count for a ::DBusGConnection*.
+//
+// A BusConnection has reference semantics bound to a particular communication
+// bus.
+//
+// \models Copyable, Assignable
+// \related GetSystemBusConnection()
+
+class BRILLO_EXPORT BusConnection {
+ public:
+  typedef ::DBusGConnection* value_type;
+
+  BusConnection(const BusConnection& x) : object_(x.object_) {
+    if (object_)
+      ::dbus_g_connection_ref(object_);
+  }
+
+  ~BusConnection() {
+    if (object_)
+      ::dbus_g_connection_unref(object_);
+  }
+
+  BusConnection& operator=(BusConnection x) {
+    swap(*this, x);
+    return *this;
+  }
+
+  const value_type& g_connection() const {
+    DCHECK(object_) << "referencing an empty connection";
+    return object_;
+  }
+
+  operator bool() const { return object_; }
+
+  bool HasConnection() const { return object_; }
+
+ private:
+  friend void swap(BusConnection& x, BusConnection& y);
+
+  friend class Proxy;
+  friend BusConnection GetSystemBusConnection();
+  friend BusConnection GetPrivateBusConnection(const char* address);
+
+  // Constructor takes ownership
+  BRILLO_PRIVATE explicit BusConnection(::DBusGConnection* x) : object_(x) {}
+
+  value_type object_;
+};
+
+inline void swap(BusConnection& x, BusConnection& y) {
+  std::swap(x.object_, y.object_);
+}
+
+// \brief Proxy manages the ref-count for a ::DBusGProxy*.
+//
+// Proxy has reference semantics and represents a connection to on object on
+// the bus. A proxy object is constructed with a connection to a bus, a name
+// to an entity on the bus, a path to an object owned by the entity, and an
+// interface protocol name used to communicate with the object.
+
+class BRILLO_EXPORT Proxy {
+ public:
+  typedef ::DBusGProxy* value_type;
+
+  Proxy();
+
+  // Set |connect_to_name_owner| true if you'd like to use
+  // dbus_g_proxy_new_for_name_owner() rather than dbus_g_proxy_new_for_name().
+  Proxy(const BusConnection& connection,
+        const char* name,
+        const char* path,
+        const char* interface,
+        bool connect_to_name_owner);
+
+  // Equivalent to Proxy(connection, name, path, interface, false).
+  Proxy(const BusConnection& connection,
+        const char* name,
+        const char* path,
+        const char* interface);
+
+  // Creates a peer proxy using dbus_g_proxy_new_for_peer.
+  Proxy(const BusConnection& connection,
+        const char* path,
+        const char* interface);
+
+  Proxy(const Proxy& x);
+
+  ~Proxy();
+
+  Proxy& operator=(Proxy x) {
+    swap(*this, x);
+    return *this;
+  }
+
+  const char* path() const {
+    DCHECK(object_) << "referencing an empty proxy";
+    return ::dbus_g_proxy_get_path(object_);
+  }
+
+  // gproxy() returns a reference to the underlying ::DBusGProxy*. As this
+  // library evolves, the gproxy() will be moved to be private.
+
+  const value_type& gproxy() const {
+    DCHECK(object_) << "referencing an empty proxy";
+    return object_;
+  }
+
+  operator bool() const { return object_; }
+
+ private:
+  BRILLO_PRIVATE static value_type GetGProxy(const BusConnection& connection,
+                                             const char* name,
+                                             const char* path,
+                                             const char* interface,
+                                             bool connect_to_name_owner);
+
+  BRILLO_PRIVATE static value_type GetGPeerProxy(
+      const BusConnection& connection,
+      const char* path,
+      const char* interface);
+
+  BRILLO_PRIVATE operator int() const;  // for safe bool cast
+  friend void swap(Proxy& x, Proxy& y);
+
+  value_type object_;
+};
+
+inline void swap(Proxy& x, Proxy& y) {
+  std::swap(x.object_, y.object_);
+}
+
+// \brief RegisterExclusiveService configures a GObject to run as a service on
+//  a supplied ::BusConnection.
+//
+//  RegisterExclusiveService encapsulates the process of configuring the
+//  supplied \param object at \param service_path on the \param connection.
+//  Exclusivity is ensured by replacing any existing services at that named
+//  location and confirming that the connection is the primary owner.
+//
+//  Type information for the \param object must be installed with
+//  dbus_g_object_type_install_info prior to use.
+
+BRILLO_EXPORT bool RegisterExclusiveService(const BusConnection& connection,
+                                            const char* interface_name,
+                                            const char* service_name,
+                                            const char* service_path,
+                                            GObject* object);
+
+template<typename F>  // F is a function signature
+class MonitorConnection;
+
+template<typename A1>
+class MonitorConnection<void(A1)> {
+ public:
+  MonitorConnection(const Proxy& proxy,
+                    const char* name,
+                    void (*monitor)(void*, A1),
+                    void* object)
+      : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
+
+  static void Run(::DBusGProxy*, A1 x, MonitorConnection* self) {
+    self->monitor_(self->object_, x);
+  }
+  const Proxy& proxy() const { return proxy_; }
+  const std::string& name() const { return name_; }
+
+ private:
+  Proxy proxy_;
+  std::string name_;
+  void (*monitor_)(void*, A1);
+  void* object_;
+};
+
+template<typename A1, typename A2>
+class MonitorConnection<void(A1, A2)> {
+ public:
+  MonitorConnection(const Proxy& proxy,
+                    const char* name,
+                    void (*monitor)(void*, A1, A2),
+                    void* object)
+      : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
+
+  static void Run(::DBusGProxy*, A1 x, A2 y, MonitorConnection* self) {
+    self->monitor_(self->object_, x, y);
+  }
+  const Proxy& proxy() const { return proxy_; }
+  const std::string& name() const { return name_; }
+
+ private:
+  Proxy proxy_;
+  std::string name_;
+  void (*monitor_)(void*, A1, A2);
+  void* object_;
+};
+
+template<typename A1, typename A2, typename A3>
+class MonitorConnection<void(A1, A2, A3)> {
+ public:
+  MonitorConnection(const Proxy& proxy,
+                    const char* name,
+                    void (*monitor)(void*, A1, A2, A3),
+                    void* object)
+      : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
+
+  static void Run(::DBusGProxy*, A1 x, A2 y, A3 z, MonitorConnection* self) {
+    self->monitor_(self->object_, x, y, z);
+  }
+  const Proxy& proxy() const { return proxy_; }
+  const std::string& name() const { return name_; }
+
+ private:
+  Proxy proxy_;
+  std::string name_;
+  void (*monitor_)(void*, A1, A2, A3);
+  void* object_;
+};
+
+template<typename A1, typename A2, typename A3, typename A4>
+class MonitorConnection<void(A1, A2, A3, A4)> {
+ public:
+  MonitorConnection(const Proxy& proxy,
+                    const char* name,
+                    void (*monitor)(void*, A1, A2, A3, A4),
+                    void* object)
+      : proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
+
+  static void Run(::DBusGProxy*,
+                  A1 x,
+                  A2 y,
+                  A3 z,
+                  A4 w,
+                  MonitorConnection* self) {
+    self->monitor_(self->object_, x, y, z, w);
+  }
+  const Proxy& proxy() const { return proxy_; }
+  const std::string& name() const { return name_; }
+
+ private:
+  Proxy proxy_;
+  std::string name_;
+  void (*monitor_)(void*, A1, A2, A3, A4);
+  void* object_;
+};
+
+template<typename A1>
+MonitorConnection<void(A1)>* Monitor(const Proxy& proxy,
+                                     const char* name,
+                                     void (*monitor)(void*, A1),
+                                     void* object) {
+  typedef MonitorConnection<void(A1)> ConnectionType;
+
+  ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
+
+  ::dbus_g_proxy_add_signal(
+      proxy.gproxy(), name, glib::type_to_gtypeid<A1>(), G_TYPE_INVALID);
+  ::dbus_g_proxy_connect_signal(
+      proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
+  return result;
+}
+
+template<typename A1, typename A2>
+MonitorConnection<void(A1, A2)>* Monitor(const Proxy& proxy,
+                                         const char* name,
+                                         void (*monitor)(void*, A1, A2),
+                                         void* object) {
+  typedef MonitorConnection<void(A1, A2)> ConnectionType;
+
+  ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
+
+  ::dbus_g_proxy_add_signal(proxy.gproxy(),
+                            name,
+                            glib::type_to_gtypeid<A1>(),
+                            glib::type_to_gtypeid<A2>(),
+                            G_TYPE_INVALID);
+  ::dbus_g_proxy_connect_signal(
+      proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
+  return result;
+}
+
+template<typename A1, typename A2, typename A3>
+MonitorConnection<void(A1, A2, A3)>* Monitor(const Proxy& proxy,
+                                             const char* name,
+                                             void (*monitor)(void*, A1, A2, A3),
+                                             void* object) {
+  typedef MonitorConnection<void(A1, A2, A3)> ConnectionType;
+
+  ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
+
+  ::dbus_g_proxy_add_signal(proxy.gproxy(),
+                            name,
+                            glib::type_to_gtypeid<A1>(),
+                            glib::type_to_gtypeid<A2>(),
+                            glib::type_to_gtypeid<A3>(),
+                            G_TYPE_INVALID);
+  ::dbus_g_proxy_connect_signal(
+      proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
+  return result;
+}
+
+template<typename A1, typename A2, typename A3, typename A4>
+MonitorConnection<void(A1, A2, A3, A4)>* Monitor(
+    const Proxy& proxy,
+    const char* name,
+    void (*monitor)(void*, A1, A2, A3, A4),
+    void* object) {
+  typedef MonitorConnection<void(A1, A2, A3, A4)> ConnectionType;
+
+  ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
+
+  ::dbus_g_proxy_add_signal(proxy.gproxy(),
+                            name,
+                            glib::type_to_gtypeid<A1>(),
+                            glib::type_to_gtypeid<A2>(),
+                            glib::type_to_gtypeid<A3>(),
+                            glib::type_to_gtypeid<A4>(),
+                            G_TYPE_INVALID);
+  ::dbus_g_proxy_connect_signal(
+      proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
+  return result;
+}
+
+template<typename F>
+void Disconnect(MonitorConnection<F>* connection) {
+  typedef MonitorConnection<F> ConnectionType;
+
+  ::dbus_g_proxy_disconnect_signal(connection->proxy().gproxy(),
+                                   connection->name().c_str(),
+                                   G_CALLBACK(&ConnectionType::Run),
+                                   connection);
+  delete connection;
+}
+
+// \brief call_PtrArray() invokes a method on a proxy returning a
+//  glib::PtrArray.
+//
+// CallPtrArray is the first instance of what is likely to be a general
+// way to make method calls to a proxy. It will likely be replaced with
+// something like Call(proxy, method, arg1, arg2, ..., ResultType*) in the
+// future. However, I don't yet have enough cases to generalize from.
+
+BRILLO_EXPORT bool CallPtrArray(const Proxy& proxy,
+                                  const char* method,
+                                  glib::ScopedPtrArray<const char*>* result);
+
+// \brief RetrieveProperty() retrieves a property of an object associated with a
+//  proxy.
+//
+// Given a proxy to an object supporting the org.freedesktop.DBus.Properties
+// interface, the RetrieveProperty() call will retrieve a property of the
+// specified interface on the object storing it in \param result and returning
+// \true. If the dbus call fails or the object returned is not of type \param T,
+// then \false is returned and \param result is unchanged.
+//
+// \example
+// Proxy proxy(GetSystemBusConnection(),
+//             "org.freedesktop.DeviceKit.Power", // A named entity on the bus
+//             battery_name,  // Path to a battery on the bus
+//             "org.freedesktop.DBus.Properties") // Properties interface
+//
+// double x;
+// if (RetrieveProperty(proxy,
+//                      "org.freedesktop.DeviceKit.Power.Device",
+//                      "percentage")
+//   std::cout << "Battery charge is " << x << "% of capacity.";
+// \end_example
+
+template<typename T>
+inline bool RetrieveProperty(const Proxy& proxy,
+                             const char* interface,
+                             const char* property,
+                             T* result) {
+  glib::ScopedError error;
+  glib::Value value;
+
+  if (!::dbus_g_proxy_call(proxy.gproxy(), "Get", &Resetter(&error).lvalue(),
+                           G_TYPE_STRING, interface,
+                           G_TYPE_STRING, property,
+                           G_TYPE_INVALID,
+                           G_TYPE_VALUE, &value,
+                           G_TYPE_INVALID)) {
+    LOG(ERROR) << "Getting property failed: "
+               << (error->message ? error->message : "Unknown Error.");
+    return false;
+  }
+  return glib::Retrieve(value, result);
+}
+
+// \brief RetrieveProperties returns a HashTable of all properties for the
+// specified interface.
+
+BRILLO_EXPORT bool RetrieveProperties(const Proxy& proxy,
+                                      const char* interface,
+                                      glib::ScopedHashTable* result);
+
+// \brief Returns a connection to the system bus.
+
+BRILLO_EXPORT BusConnection GetSystemBusConnection();
+
+// \brief Returns a private connection to a bus at |address|.
+
+BRILLO_EXPORT BusConnection GetPrivateBusConnection(const char* address);
+
+// \brief Calls a method |method_name| with no arguments per the given |path|
+// and |interface_name|.  Ignores return value.
+
+BRILLO_EXPORT void CallMethodWithNoArguments(const char* service_name,
+                                             const char* path,
+                                             const char* interface_name,
+                                             const char* method_name);
+
+// \brief Low-level signal monitor base class.
+//
+// Used when there is no definite named signal sender (that Proxy
+// could be used for).
+
+class BRILLO_EXPORT SignalWatcher {
+ public:
+  SignalWatcher() {}
+  ~SignalWatcher();
+  void StartMonitoring(const std::string& interface, const std::string& signal);
+
+ private:
+  // Callback invoked on the given signal arrival.
+  virtual void OnSignal(DBusMessage* message) = 0;
+
+  // Returns a string matching the D-Bus messages that we want to listen for.
+  BRILLO_PRIVATE std::string GetDBusMatchString() const;
+
+  // A D-Bus message filter to receive signals.
+  BRILLO_PRIVATE static DBusHandlerResult FilterDBusMessage(
+      DBusConnection* dbus_conn,
+      DBusMessage* message,
+      void* data);
+  std::string interface_;
+  std::string signal_;
+};
+
+}  // namespace dbus
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_GLIB_DBUS_H_
diff --git a/libbrillo/brillo/glib/object.h b/libbrillo/brillo/glib/object.h
new file mode 100644
index 0000000..dfa96b6
--- /dev/null
+++ b/libbrillo/brillo/glib/object.h
@@ -0,0 +1,508 @@
+// Copyright (c) 2009 The Chromium OS 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 LIBBRILLO_BRILLO_GLIB_OBJECT_H_
+#define LIBBRILLO_BRILLO_GLIB_OBJECT_H_
+
+#include <glib-object.h>
+#include <stdint.h>
+
+#include <base/logging.h>
+#include <base/macros.h>
+
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+
+namespace brillo {
+
+namespace details {  // NOLINT
+
+// \brief ResetHelper is a private class for use with Resetter().
+//
+// ResetHelper passes ownership of a pointer to a scoped pointer type with reset
+// on destruction.
+
+template <typename T>  // T models ScopedPtr
+class ResetHelper {
+ public:
+  typedef typename T::element_type element_type;
+
+  explicit ResetHelper(T* x)
+      : ptr_(nullptr),
+        scoped_(x) {
+  }
+  ~ResetHelper() {
+    scoped_->reset(ptr_);
+  }
+  element_type*& lvalue() {
+    return ptr_;
+  }
+
+ private:
+  element_type* ptr_;
+  T* scoped_;
+};
+
+}  // namespace details
+
+// \brief Resetter() is a utility function for passing pointers to
+//  scoped pointers.
+//
+// The Resetter() function return a temporary object containing an lvalue of
+// \code T::element_type which can be assigned to. When the temporary object
+// destructs, the associated scoped pointer is reset with the lvalue. It is of
+// general use when a pointer is returned as an out-argument.
+//
+// \example
+// void function(int** x) {
+//   *x = new int(10);
+// }
+// ...
+// std::unique_ptr<int> x;
+// function(Resetter(x).lvalue());
+//
+// \end_example
+
+template <typename T>  // T models ScopedPtr
+details::ResetHelper<T> Resetter(T* x) {
+  return details::ResetHelper<T>(x);
+}
+
+// \precondition No functions in the glib namespace can be called before
+// ::g_type_init();
+
+namespace glib {
+
+// \brief type_to_gtypeid is a type function mapping from a canonical type to
+// the GType typeid for the associated GType (see type_to_gtype).
+
+template <typename T> ::GType type_to_gtypeid();
+
+template < >
+inline ::GType type_to_gtypeid<const char*>() {
+  return G_TYPE_STRING;
+}
+template < >
+inline ::GType type_to_gtypeid<char*>() {
+  return G_TYPE_STRING;
+}
+template < >
+inline ::GType type_to_gtypeid< ::uint8_t>() {
+  return G_TYPE_UCHAR;
+}
+template < >
+inline ::GType type_to_gtypeid<double>() {
+  return G_TYPE_DOUBLE;
+}
+template < >
+inline ::GType type_to_gtypeid<bool>() {
+  return G_TYPE_BOOLEAN;
+}
+class Value;
+template < >
+inline ::GType type_to_gtypeid<const Value*>() {
+  return G_TYPE_VALUE;
+}
+
+template < >
+inline ::GType type_to_gtypeid< ::uint32_t>() {
+  // REVISIT (seanparent) : There currently isn't any G_TYPE_UINT32, this code
+  // assumes sizeof(guint) == sizeof(guint32). Need a static_assert to assert
+  // that.
+  return G_TYPE_UINT;
+}
+
+template < >
+inline ::GType type_to_gtypeid< ::int64_t>() {
+  return G_TYPE_INT64;
+}
+
+template < >
+inline ::GType type_to_gtypeid< ::int32_t>() {
+  return G_TYPE_INT;
+}
+
+// \brief Value (and Retrieve) support using std::string as well as const char*
+// by promoting from const char* to the string. promote_from provides a mapping
+// for this promotion (and possibly others in the future).
+
+template <typename T> struct promotes_from {
+  typedef T type;
+};
+template < > struct promotes_from<std::string> {
+  typedef const char* type;
+};
+
+// \brief RawCast converts from a GValue to a value of a canonical type.
+//
+// RawCast is a low level function. Generally, use Cast() instead.
+//
+// \precondition \param x contains a value of type \param T.
+
+template <typename T>
+inline T RawCast(const ::GValue& x) {
+  // Use static_assert() to issue a meaningful compile-time error.
+  // To prevent this from happening for all references to RawCast, use sizeof(T)
+  // to make static_assert depend on type T and therefore prevent binding it
+  // unconditionally until the actual RawCast<T> instantiation happens.
+  static_assert(sizeof(T) == 0, "Using RawCast on unsupported type");
+  return T();
+}
+
+template < >
+inline const char* RawCast<const char*>(const ::GValue& x) {
+  return static_cast<const char*>(::g_value_get_string(&x));
+}
+template < >
+inline double RawCast<double>(const ::GValue& x) {
+  return static_cast<double>(::g_value_get_double(&x));
+}
+template < >
+inline bool RawCast<bool>(const ::GValue& x) {
+  return static_cast<bool>(::g_value_get_boolean(&x));
+}
+template < >
+inline ::uint32_t RawCast< ::uint32_t>(const ::GValue& x) {
+  return static_cast< ::uint32_t>(::g_value_get_uint(&x));
+}
+template < >
+inline ::uint8_t RawCast< ::uint8_t>(const ::GValue& x) {
+  return static_cast< ::uint8_t>(::g_value_get_uchar(&x));
+}
+template < >
+inline ::int64_t RawCast< ::int64_t>(const ::GValue& x) {
+  return static_cast< ::int64_t>(::g_value_get_int64(&x));
+}
+template < >
+inline ::int32_t RawCast< ::int32_t>(const ::GValue& x) {
+  return static_cast< ::int32_t>(::g_value_get_int(&x));
+}
+
+inline void RawSet(GValue* x, const std::string& v) {
+  ::g_value_set_string(x, v.c_str());
+}
+inline void RawSet(GValue* x, const char* v) {
+  ::g_value_set_string(x, v);
+}
+inline void RawSet(GValue* x, double v) {
+  ::g_value_set_double(x, v);
+}
+inline void RawSet(GValue* x, bool v) {
+  ::g_value_set_boolean(x, v);
+}
+inline void RawSet(GValue* x, ::uint32_t v) {
+  ::g_value_set_uint(x, v);
+}
+inline void RawSet(GValue* x, ::uint8_t v) {
+  ::g_value_set_uchar(x, v);
+}
+inline void RawSet(GValue* x, ::int64_t v) {
+  ::g_value_set_int64(x, v);
+}
+inline void RawSet(GValue* x, ::int32_t v) {
+  ::g_value_set_int(x, v);
+}
+
+// \brief Value is a data type for managing GValues.
+//
+// A Value is a polymorphic container holding at most a single value.
+//
+// The Value wrapper ensures proper initialization, copies, and assignment of
+// GValues.
+//
+// \note GValues are equationally incomplete and so can't support proper
+// equality. The semantics of copy are verified with equality of retrieved
+// values.
+
+class Value : public ::GValue {
+ public:
+  Value()
+      : GValue() {
+  }
+  explicit Value(const ::GValue& x)
+      : GValue() {
+    *this = *static_cast<const Value*>(&x);
+  }
+  template <typename T>
+  explicit Value(T x)
+      : GValue() {
+    ::g_value_init(this,
+        type_to_gtypeid<typename promotes_from<T>::type>());
+    RawSet(this, x);
+  }
+  Value(const Value& x)
+      : GValue() {
+    if (x.empty())
+      return;
+    ::g_value_init(this, G_VALUE_TYPE(&x));
+    ::g_value_copy(&x, this);
+  }
+  ~Value() {
+    clear();
+  }
+  Value& operator=(const Value& x) {
+    if (this == &x)
+      return *this;
+    clear();
+    if (x.empty())
+      return *this;
+    ::g_value_init(this, G_VALUE_TYPE(&x));
+    ::g_value_copy(&x, this);
+    return *this;
+  }
+  template <typename T>
+  Value& operator=(const T& x) {
+    clear();
+    ::g_value_init(this,
+                   type_to_gtypeid<typename promotes_from<T>::type>());
+    RawSet(this, x);
+    return *this;
+  }
+
+  // Lower-case names to follow STL container conventions.
+
+  void clear() {
+    if (!empty())
+      ::g_value_unset(this);
+  }
+
+  bool empty() const {
+    return G_VALUE_TYPE(this) == G_TYPE_INVALID;
+  }
+};
+
+template < >
+inline const Value* RawCast<const Value*>(const ::GValue& x) {
+  return static_cast<const Value*>(&x);
+}
+
+// \brief Retrieve gets a value from a GValue.
+//
+// \postcondition If \param x contains a value of type \param T, then the
+//  value is copied to \param result and \true is returned. Otherwise, \param
+//  result is unchanged and \false is returned.
+//
+// \precondition \param result is not \nullptr.
+
+template <typename T>
+bool Retrieve(const ::GValue& x, T* result) {
+  if (!G_VALUE_HOLDS(&x, type_to_gtypeid<typename promotes_from<T>::type>())) {
+    LOG(WARNING) << "GValue retrieve failed. Expected: "
+        << g_type_name(type_to_gtypeid<typename promotes_from<T>::type>())
+        << ", Found: " << g_type_name(G_VALUE_TYPE(&x));
+    return false;
+  }
+
+  *result = RawCast<typename promotes_from<T>::type>(x);
+  return true;
+}
+
+inline bool Retrieve(const ::GValue& x, Value* result) {
+  *result = Value(x);
+  return true;
+}
+
+// \brief ScopedError holds a ::GError* and deletes it on destruction.
+
+struct FreeError {
+  void operator()(::GError* x) const {
+    if (x)
+      ::g_error_free(x);
+  }
+};
+
+typedef std::unique_ptr< ::GError, FreeError> ScopedError;
+
+// \brief ScopedArray holds a ::GArray* and deletes both the container and the
+// segment containing the elements on destruction.
+
+struct FreeArray {
+  void operator()(::GArray* x) const {
+    if (x)
+      ::g_array_free(x, TRUE);
+  }
+};
+
+typedef std::unique_ptr< ::GArray, FreeArray> ScopedArray;
+
+// \brief ScopedPtrArray adapts ::GPtrArray* to conform to the standard
+//  container requirements.
+//
+// \note ScopedPtrArray is only partially implemented and is being fleshed out
+//  as needed.
+//
+// \models Random Access Container, Back Insertion Sequence, ScopedPtrArray is
+//  not copyable and equationally incomplete.
+
+template <typename T>  // T models pointer
+class ScopedPtrArray {
+ public:
+  typedef ::GPtrArray element_type;
+
+  typedef T value_type;
+  typedef const value_type& const_reference;
+  typedef value_type* iterator;
+  typedef const value_type* const_iterator;
+
+  ScopedPtrArray()
+      : object_(0) {
+  }
+
+  explicit ScopedPtrArray(::GPtrArray* x)
+      : object_(x) {
+  }
+
+  ~ScopedPtrArray() {
+    clear();
+  }
+
+  iterator begin() {
+    return iterator(object_ ? object_->pdata : nullptr);
+  }
+  iterator end() {
+    return begin() + size();
+  }
+  const_iterator begin() const {
+    return const_iterator(object_ ? object_->pdata : nullptr);
+  }
+  const_iterator end() const {
+    return begin() + size();
+  }
+
+  // \precondition x is a pointer to an object allocated with g_new().
+
+  void push_back(T x) {
+    if (!object_)
+      object_ = ::g_ptr_array_sized_new(1);
+    ::g_ptr_array_add(object_, ::gpointer(x));
+  }
+
+  T& operator[](std::size_t n) {
+    DCHECK(!(size() < n)) << "ScopedPtrArray index out-of-bound.";
+    return *(begin() + n);
+  }
+
+  std::size_t size() const {
+    return object_ ? object_->len : 0;
+  }
+
+  void clear() {
+    if (object_) {
+      std::for_each(begin(), end(), FreeHelper());
+      ::g_ptr_array_free(object_, true);
+      object_ = nullptr;
+    }
+  }
+
+  void reset(::GPtrArray* p = nullptr) {
+    if (p != object_) {
+      clear();
+      object_ = p;
+    }
+  }
+
+ private:
+  struct FreeHelper {
+    void operator()(T x) const {
+      ::g_free(::gpointer(x));
+    }
+  };
+
+  template <typename U>
+  friend void swap(ScopedPtrArray<U>& x, ScopedPtrArray<U>& y);
+
+  ::GPtrArray* object_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPtrArray);
+};
+
+template <typename U>
+inline void swap(ScopedPtrArray<U>& x, ScopedPtrArray<U>& y) {
+  std::swap(x.object_, y.object_);
+}
+
+// \brief ScopedHashTable manages the lifetime of a ::GHashTable* with an
+// interface compatibitle with a scoped ptr.
+//
+// The ScopedHashTable is also the start of an adaptor to model a standard
+// Container. The standard for an associative container would have an iterator
+// returning a key value pair. However, that isn't possible with
+// ::GHashTable because there is no interface returning a reference to the
+// key value pair, only to retrieve the keys and values and individual elements.
+//
+// So the standard interface of find() wouldn't work. I considered implementing
+// operator[] and count() - operator []. So retrieving a value would look like:
+//
+// if (table.count(key))
+//   success = Retrieve(table[key], &value);
+//
+// But that requires hashing the key twice.
+// For now I implemented a Retrieve member function to follow the pattern
+// developed elsewhere in the code.
+//
+// bool success = Retrieve(key, &x);
+//
+// This is also a template to retrieve the corect type from the stored GValue
+// type.
+//
+// I may revisit this and use scoped_ptr_malloc and a non-member function
+// Retrieve() in the future. The Retrieve pattern is becoming common enough
+// that I want to give some thought as to how to generalize it further.
+
+class ScopedHashTable {
+ public:
+  typedef ::GHashTable element_type;
+
+  ScopedHashTable()
+      : object_(nullptr) {
+  }
+
+  explicit ScopedHashTable(::GHashTable* p)
+      : object_(p) {
+  }
+
+  ~ScopedHashTable() {
+    clear();
+  }
+
+  template <typename T>
+  bool Retrieve(const char* key, T* result) const {
+    DCHECK(object_) << "Retrieve on empty ScopedHashTable.";
+    if (!object_)
+      return false;
+
+    ::gpointer ptr = ::g_hash_table_lookup(object_, key);
+    if (!ptr)
+      return false;
+    return glib::Retrieve(*static_cast< ::GValue*>(ptr), result);
+  }
+
+  void clear() {
+    if (object_) {
+      ::g_hash_table_unref(object_);
+      object_ = nullptr;
+    }
+  }
+
+  GHashTable* get() {
+    return object_;
+  }
+
+  void reset(::GHashTable* p = nullptr) {
+    if (p != object_) {
+      clear();
+      object_ = p;
+    }
+  }
+
+ private:
+  ::GHashTable* object_;
+};
+
+}  // namespace glib
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_GLIB_OBJECT_H_
diff --git a/libbrillo/brillo/glib/object_unittest.cc b/libbrillo/brillo/glib/object_unittest.cc
new file mode 100644
index 0000000..a1ed408
--- /dev/null
+++ b/libbrillo/brillo/glib/object_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 2009 The Chromium OS 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 "brillo/glib/object.h"
+
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <cstring>
+#include <iterator>
+#include <string>
+
+using brillo::glib::ScopedPtrArray;
+using brillo::glib::ScopedError;
+using brillo::glib::Retrieve;
+using brillo::glib::Value;
+using brillo::Resetter;
+
+namespace {  // NOLINT
+
+template <typename T>
+void SetRetrieveTest(const T& x) {
+  Value tmp(x);
+  T result;
+  EXPECT_TRUE(Retrieve(tmp, &result));
+  EXPECT_EQ(result, x);
+}
+
+void ModifyValue(Value* x) {
+  *x = 1.0 / 1231415926.0;   // An unlikely value
+}
+
+template <typename T, typename O>
+void MutableRegularTestValue(const T& x, O modify) {
+  Value tmp(x);
+  Value y = tmp;  // copy-construction
+  T result;
+  EXPECT_TRUE(Retrieve(y, &result));
+  EXPECT_EQ(result, x);
+  modify(&y);
+  LOG(INFO) << "Warning Expected.";
+  EXPECT_TRUE(!(Retrieve(y, &result) && result == x));
+  y = tmp;  // assignment
+  EXPECT_TRUE(Retrieve(y, &result));
+  EXPECT_EQ(result, x);
+  modify(&y);
+  LOG(INFO) << "Warning Expected.";
+  EXPECT_TRUE(!(Retrieve(y, &result) && result == x));
+}
+
+void OutArgument(int** x) {
+  *x = new int(10);  // NOLINT
+}
+
+}  // namespace
+
+TEST(ResetterTest, All) {
+  std::unique_ptr<int> x;
+  OutArgument(&Resetter(&x).lvalue());
+  EXPECT_EQ(*x, 10);
+}
+
+TEST(RetrieveTest, Types) {
+  SetRetrieveTest(std::string("Hello!"));
+  SetRetrieveTest(static_cast<uint32_t>(10));
+  SetRetrieveTest(10.5);
+  SetRetrieveTest(true);
+}
+
+TEST(ValueTest, All) {
+  Value x;  // default construction
+  Value y = x;  // copy with default value
+  x = y;  // assignment with default value
+  Value z(1.5);
+  x = z;  // assignment to default value
+  MutableRegularTestValue(std::string("Hello!"), &ModifyValue);
+}
+
+TEST(ScopedErrorTest, All) {
+  ScopedError a;  // default construction
+  ScopedError b(::g_error_new(::g_quark_from_static_string("error"), -1,
+                              ""));  // constructor
+  ::GError* c = ::g_error_new(::g_quark_from_static_string("error"), -1,
+                              "");
+  ::GError* d = ::g_error_new(::g_quark_from_static_string("error"), -1,
+                              "");
+  a.reset(c);  // reset form 1
+  (void)d;
+}
+
+TEST(ScopedPtrArrayTest, Construction) {
+  const char item[] = "a string";
+  char* a = static_cast<char*>(::g_malloc(sizeof(item)));
+  std::strcpy(a, &item[0]);  // NOLINT
+
+  ::GPtrArray* array = ::g_ptr_array_new();
+  ::g_ptr_array_add(array, ::gpointer(a));
+
+  ScopedPtrArray<const char*> x(array);
+  EXPECT_EQ(x.size(), 1);
+  EXPECT_EQ(x[0], a);  // indexing
+}
+
+TEST(ScopedPtrArrayTest, Reset) {
+  const char item[] = "a string";
+  char* a = static_cast<char*>(::g_malloc(sizeof(item)));
+  std::strcpy(a, &item[0]);  // NOLINT
+
+  ScopedPtrArray<const char*> x;  // default construction
+  x.push_back(a);
+  EXPECT_EQ(x.size(), 1);
+  x.reset();
+  EXPECT_EQ(x.size(), 0);
+
+  char* b = static_cast<char*>(::g_malloc(sizeof(item)));
+  std::strcpy(b, &item[0]);  // NOLINT
+
+  ::GPtrArray* array = ::g_ptr_array_new();
+  ::g_ptr_array_add(array, ::gpointer(b));
+
+  x.reset(array);
+  EXPECT_EQ(x.size(), 1);
+}
+
+TEST(ScopedPtrArrayTest, Iteration) {
+  char* a[] = { static_cast<char*>(::g_malloc(1)),
+      static_cast<char*>(::g_malloc(1)), static_cast<char*>(::g_malloc(1)) };
+
+  ScopedPtrArray<const char*> x;
+  std::copy(&a[0], &a[3], std::back_inserter(x));
+  EXPECT_TRUE(std::equal(x.begin(), x.end(), &a[0]));
+}
+
diff --git a/libbrillo/brillo/http/curl_api.cc b/libbrillo/brillo/http/curl_api.cc
new file mode 100644
index 0000000..1c018bc
--- /dev/null
+++ b/libbrillo/brillo/http/curl_api.cc
@@ -0,0 +1,197 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/curl_api.h>
+
+#include <base/logging.h>
+
+namespace brillo {
+namespace http {
+
+namespace {
+
+static_assert(CURLOPTTYPE_LONG == 0 &&
+              CURLOPTTYPE_OBJECTPOINT == 10000 &&
+              CURLOPTTYPE_FUNCTIONPOINT == 20000 &&
+              CURLOPTTYPE_OFF_T == 30000,
+              "CURL option types are expected to be multiples of 10000");
+
+inline bool VerifyOptionType(CURLoption option, int expected_type) {
+  int option_type = (static_cast<int>(option) / 10000) * 10000;
+  return (option_type == expected_type);
+}
+
+}  // anonymous namespace
+
+CurlApi::CurlApi() {
+  curl_global_init(CURL_GLOBAL_ALL);
+}
+
+CurlApi::~CurlApi() {
+  curl_global_cleanup();
+}
+
+CURL* CurlApi::EasyInit() {
+  return curl_easy_init();
+}
+
+void CurlApi::EasyCleanup(CURL* curl) {
+  curl_easy_cleanup(curl);
+}
+
+CURLcode CurlApi::EasySetOptInt(CURL* curl, CURLoption option, int value) {
+  CHECK(VerifyOptionType(option, CURLOPTTYPE_LONG))
+      << "Only options that expect a LONG data type must be specified here";
+  // CURL actually uses "long" type, so have to make sure we feed it what it
+  // expects.
+  // NOLINTNEXTLINE(runtime/int)
+  return curl_easy_setopt(curl, option, static_cast<long>(value));
+}
+
+CURLcode CurlApi::EasySetOptStr(CURL* curl,
+                                CURLoption option,
+                                const std::string& value) {
+  CHECK(VerifyOptionType(option, CURLOPTTYPE_OBJECTPOINT))
+      << "Only options that expect a STRING data type must be specified here";
+  return curl_easy_setopt(curl, option, value.c_str());
+}
+
+CURLcode CurlApi::EasySetOptPtr(CURL* curl, CURLoption option, void* value) {
+  CHECK(VerifyOptionType(option, CURLOPTTYPE_OBJECTPOINT))
+      << "Only options that expect a pointer data type must be specified here";
+  return curl_easy_setopt(curl, option, value);
+}
+
+CURLcode CurlApi::EasySetOptCallback(CURL* curl,
+                                     CURLoption option,
+                                     intptr_t address) {
+  CHECK(VerifyOptionType(option, CURLOPTTYPE_FUNCTIONPOINT))
+      << "Only options that expect a function pointers must be specified here";
+  return curl_easy_setopt(curl, option, address);
+}
+
+CURLcode CurlApi::EasySetOptOffT(CURL* curl,
+                                 CURLoption option,
+                                 curl_off_t value) {
+  CHECK(VerifyOptionType(option, CURLOPTTYPE_OFF_T))
+      << "Only options that expect a large data size must be specified here";
+  return curl_easy_setopt(curl, option, value);
+}
+
+CURLcode CurlApi::EasyPerform(CURL* curl) {
+  return curl_easy_perform(curl);
+}
+
+CURLcode CurlApi::EasyGetInfoInt(CURL* curl, CURLINFO info, int* value) const {
+  CHECK_EQ(CURLINFO_LONG, info & CURLINFO_TYPEMASK) << "Wrong option type";
+  long data = 0;  // NOLINT(runtime/int) - curl expects a long here.
+  CURLcode code = curl_easy_getinfo(curl, info, &data);
+  if (code == CURLE_OK)
+    *value = static_cast<int>(data);
+  return code;
+}
+
+CURLcode CurlApi::EasyGetInfoDbl(CURL* curl,
+                                 CURLINFO info,
+                                 double* value) const {
+  CHECK_EQ(CURLINFO_DOUBLE, info & CURLINFO_TYPEMASK) << "Wrong option type";
+  return curl_easy_getinfo(curl, info, value);
+}
+
+CURLcode CurlApi::EasyGetInfoStr(CURL* curl,
+                                 CURLINFO info,
+                                 std::string* value) const {
+  CHECK_EQ(CURLINFO_STRING, info & CURLINFO_TYPEMASK) << "Wrong option type";
+  char* data = nullptr;
+  CURLcode code = curl_easy_getinfo(curl, info, &data);
+  if (code == CURLE_OK)
+    *value = data;
+  return code;
+}
+
+CURLcode CurlApi::EasyGetInfoPtr(CURL* curl,
+                                 CURLINFO info,
+                                 void** value) const {
+  // CURL uses "string" type for generic pointer info. Go figure.
+  CHECK_EQ(CURLINFO_STRING, info & CURLINFO_TYPEMASK) << "Wrong option type";
+  return curl_easy_getinfo(curl, info, value);
+}
+
+std::string CurlApi::EasyStrError(CURLcode code) const {
+  return curl_easy_strerror(code);
+}
+
+CURLM* CurlApi::MultiInit() {
+  return curl_multi_init();
+}
+
+CURLMcode CurlApi::MultiCleanup(CURLM* multi_handle) {
+  return curl_multi_cleanup(multi_handle);
+}
+
+CURLMsg* CurlApi::MultiInfoRead(CURLM* multi_handle, int* msgs_in_queue) {
+  return curl_multi_info_read(multi_handle, msgs_in_queue);
+}
+
+CURLMcode CurlApi::MultiAddHandle(CURLM* multi_handle, CURL* curl_handle) {
+  return curl_multi_add_handle(multi_handle, curl_handle);
+}
+
+CURLMcode CurlApi::MultiRemoveHandle(CURLM* multi_handle, CURL* curl_handle) {
+  return curl_multi_remove_handle(multi_handle, curl_handle);
+}
+
+CURLMcode CurlApi::MultiSetSocketCallback(CURLM* multi_handle,
+                                          curl_socket_callback socket_callback,
+                                          void* userp) {
+  CURLMcode code =
+      curl_multi_setopt(multi_handle, CURLMOPT_SOCKETFUNCTION, socket_callback);
+  if (code != CURLM_OK)
+    return code;
+  return curl_multi_setopt(multi_handle, CURLMOPT_SOCKETDATA, userp);
+}
+
+CURLMcode CurlApi::MultiSetTimerCallback(
+    CURLM* multi_handle,
+    curl_multi_timer_callback timer_callback,
+    void* userp) {
+  CURLMcode code =
+      curl_multi_setopt(multi_handle, CURLMOPT_TIMERFUNCTION, timer_callback);
+  if (code != CURLM_OK)
+    return code;
+  return curl_multi_setopt(multi_handle, CURLMOPT_TIMERDATA, userp);
+}
+
+CURLMcode CurlApi::MultiAssign(CURLM* multi_handle,
+                               curl_socket_t sockfd,
+                               void* sockp) {
+  return curl_multi_assign(multi_handle, sockfd, sockp);
+}
+
+CURLMcode CurlApi::MultiSocketAction(CURLM* multi_handle,
+                                     curl_socket_t s,
+                                     int ev_bitmask,
+                                     int* running_handles) {
+  return curl_multi_socket_action(multi_handle, s, ev_bitmask, running_handles);
+}
+
+std::string CurlApi::MultiStrError(CURLMcode code) const {
+  return curl_multi_strerror(code);
+}
+
+CURLMcode CurlApi::MultiPerform(CURLM* multi_handle, int* running_handles) {
+  return curl_multi_perform(multi_handle, running_handles);
+}
+
+CURLMcode CurlApi::MultiWait(CURLM* multi_handle,
+                             curl_waitfd extra_fds[],
+                             unsigned int extra_nfds,
+                             int timeout_ms,
+                             int* numfds) {
+  return curl_multi_wait(multi_handle, extra_fds, extra_nfds, timeout_ms,
+                         numfds);
+}
+
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/curl_api.h b/libbrillo/brillo/http/curl_api.h
new file mode 100644
index 0000000..8e9001d
--- /dev/null
+++ b/libbrillo/brillo/http/curl_api.h
@@ -0,0 +1,232 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_CURL_API_H_
+#define LIBBRILLO_BRILLO_HTTP_CURL_API_H_
+
+#include <curl/curl.h>
+
+#include <string>
+
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+namespace http {
+
+// Abstract wrapper around libcurl C API that allows us to mock it out in tests.
+class CurlInterface {
+ public:
+  CurlInterface() = default;
+  virtual ~CurlInterface() = default;
+
+  // Wrapper around curl_easy_init().
+  virtual CURL* EasyInit() = 0;
+
+  // Wrapper around curl_easy_cleanup().
+  virtual void EasyCleanup(CURL* curl) = 0;
+
+  // Wrappers around curl_easy_setopt().
+  virtual CURLcode EasySetOptInt(CURL* curl, CURLoption option, int value) = 0;
+  virtual CURLcode EasySetOptStr(CURL* curl,
+                                 CURLoption option,
+                                 const std::string& value) = 0;
+  virtual CURLcode EasySetOptPtr(CURL* curl,
+                                 CURLoption option,
+                                 void* value) = 0;
+  virtual CURLcode EasySetOptCallback(CURL* curl,
+                                      CURLoption option,
+                                      intptr_t address) = 0;
+  virtual CURLcode EasySetOptOffT(CURL* curl,
+                                  CURLoption option,
+                                  curl_off_t value) = 0;
+
+  // A type-safe wrapper around function callback options.
+  template<typename R, typename... Args>
+  inline CURLcode EasySetOptCallback(CURL* curl,
+                                     CURLoption option,
+                                     R(*callback)(Args...)) {
+    return EasySetOptCallback(
+        curl, option, reinterpret_cast<intptr_t>(callback));
+  }
+
+  // Wrapper around curl_easy_perform().
+  virtual CURLcode EasyPerform(CURL* curl) = 0;
+
+  // Wrappers around curl_easy_getinfo().
+  virtual CURLcode EasyGetInfoInt(CURL* curl,
+                                  CURLINFO info,
+                                  int* value) const = 0;
+  virtual CURLcode EasyGetInfoDbl(CURL* curl,
+                                  CURLINFO info,
+                                  double* value) const = 0;
+  virtual CURLcode EasyGetInfoStr(CURL* curl,
+                                  CURLINFO info,
+                                  std::string* value) const = 0;
+  virtual CURLcode EasyGetInfoPtr(CURL* curl,
+                                  CURLINFO info,
+                                  void** value) const = 0;
+
+  // Wrapper around curl_easy_strerror().
+  virtual std::string EasyStrError(CURLcode code) const = 0;
+
+  // Wrapper around curl_multi_init().
+  virtual CURLM* MultiInit() = 0;
+
+  // Wrapper around curl_multi_cleanup().
+  virtual CURLMcode MultiCleanup(CURLM* multi_handle) = 0;
+
+  // Wrapper around curl_multi_info_read().
+  virtual CURLMsg* MultiInfoRead(CURLM* multi_handle, int* msgs_in_queue) = 0;
+
+  // Wrapper around curl_multi_add_handle().
+  virtual CURLMcode MultiAddHandle(CURLM* multi_handle, CURL* curl_handle) = 0;
+
+  // Wrapper around curl_multi_remove_handle().
+  virtual CURLMcode MultiRemoveHandle(CURLM* multi_handle,
+                                      CURL* curl_handle) = 0;
+
+  // Wrapper around curl_multi_setopt(CURLMOPT_SOCKETFUNCTION/SOCKETDATA).
+  virtual CURLMcode MultiSetSocketCallback(
+      CURLM* multi_handle,
+      curl_socket_callback socket_callback,
+      void* userp) = 0;
+
+  // Wrapper around curl_multi_setopt(CURLMOPT_TIMERFUNCTION/TIMERDATA).
+  virtual CURLMcode MultiSetTimerCallback(
+      CURLM* multi_handle,
+      curl_multi_timer_callback timer_callback,
+      void* userp) = 0;
+
+  // Wrapper around curl_multi_assign().
+  virtual CURLMcode MultiAssign(CURLM* multi_handle,
+                                curl_socket_t sockfd,
+                                void* sockp) = 0;
+
+  // Wrapper around curl_multi_socket_action().
+  virtual CURLMcode MultiSocketAction(CURLM* multi_handle,
+                                      curl_socket_t s,
+                                      int ev_bitmask,
+                                      int* running_handles) = 0;
+
+  // Wrapper around curl_multi_strerror().
+  virtual std::string MultiStrError(CURLMcode code) const = 0;
+
+  // Wrapper around curl_multi_perform().
+  virtual CURLMcode MultiPerform(CURLM* multi_handle,
+                                 int* running_handles) = 0;
+
+  // Wrapper around curl_multi_wait().
+  virtual CURLMcode MultiWait(CURLM* multi_handle,
+                              curl_waitfd extra_fds[],
+                              unsigned int extra_nfds,
+                              int timeout_ms,
+                              int* numfds) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CurlInterface);
+};
+
+class BRILLO_EXPORT CurlApi : public CurlInterface {
+ public:
+  CurlApi();
+  ~CurlApi() override;
+
+  // Wrapper around curl_easy_init().
+  CURL* EasyInit() override;
+
+  // Wrapper around curl_easy_cleanup().
+  void EasyCleanup(CURL* curl) override;
+
+  // Wrappers around curl_easy_setopt().
+  CURLcode EasySetOptInt(CURL* curl, CURLoption option, int value) override;
+  CURLcode EasySetOptStr(CURL* curl,
+                         CURLoption option,
+                         const std::string& value) override;
+  CURLcode EasySetOptPtr(CURL* curl, CURLoption option, void* value) override;
+  CURLcode EasySetOptCallback(CURL* curl,
+                              CURLoption option,
+                              intptr_t address) override;
+  CURLcode EasySetOptOffT(CURL* curl,
+                          CURLoption option,
+                          curl_off_t value) override;
+
+  // Wrapper around curl_easy_perform().
+  CURLcode EasyPerform(CURL* curl) override;
+
+  // Wrappers around curl_easy_getinfo().
+  CURLcode EasyGetInfoInt(CURL* curl, CURLINFO info, int* value) const override;
+  CURLcode EasyGetInfoDbl(CURL* curl,
+                          CURLINFO info,
+                          double* value) const override;
+  CURLcode EasyGetInfoStr(CURL* curl,
+                          CURLINFO info,
+                          std::string* value) const override;
+  CURLcode EasyGetInfoPtr(CURL* curl,
+                          CURLINFO info,
+                          void** value) const override;
+
+  // Wrapper around curl_easy_strerror().
+  std::string EasyStrError(CURLcode code) const override;
+
+  // Wrapper around curl_multi_init().
+  CURLM* MultiInit() override;
+
+  // Wrapper around curl_multi_cleanup().
+  CURLMcode MultiCleanup(CURLM* multi_handle) override;
+
+  // Wrapper around curl_multi_info_read().
+  CURLMsg* MultiInfoRead(CURLM* multi_handle, int* msgs_in_queue) override;
+
+  // Wrapper around curl_multi_add_handle().
+  CURLMcode MultiAddHandle(CURLM* multi_handle, CURL* curl_handle) override;
+
+  // Wrapper around curl_multi_remove_handle().
+  CURLMcode MultiRemoveHandle(CURLM* multi_handle, CURL* curl_handle) override;
+
+  // Wrapper around curl_multi_setopt(CURLMOPT_SOCKETFUNCTION/SOCKETDATA).
+  CURLMcode MultiSetSocketCallback(
+      CURLM* multi_handle,
+      curl_socket_callback socket_callback,
+      void* userp) override;
+
+  // Wrapper around curl_multi_setopt(CURLMOPT_TIMERFUNCTION/TIMERDATA).
+  CURLMcode MultiSetTimerCallback(
+      CURLM* multi_handle,
+      curl_multi_timer_callback timer_callback,
+      void* userp) override;
+
+  // Wrapper around curl_multi_assign().
+  CURLMcode MultiAssign(CURLM* multi_handle,
+                        curl_socket_t sockfd,
+                        void* sockp) override;
+
+  // Wrapper around curl_multi_socket_action().
+  CURLMcode MultiSocketAction(CURLM* multi_handle,
+                              curl_socket_t s,
+                              int ev_bitmask,
+                              int* running_handles) override;
+
+  // Wrapper around curl_multi_strerror().
+  std::string MultiStrError(CURLMcode code) const override;
+
+  // Wrapper around curl_multi_perform().
+  CURLMcode MultiPerform(CURLM* multi_handle,
+                         int* running_handles) override;
+
+  // Wrapper around curl_multi_wait().
+  CURLMcode MultiWait(CURLM* multi_handle,
+                      curl_waitfd extra_fds[],
+                      unsigned int extra_nfds,
+                      int timeout_ms,
+                      int* numfds) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CurlApi);
+};
+
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_CURL_API_H_
diff --git a/libbrillo/brillo/http/http_connection.h b/libbrillo/brillo/http/http_connection.h
new file mode 100644
index 0000000..9150929
--- /dev/null
+++ b/libbrillo/brillo/http/http_connection.h
@@ -0,0 +1,108 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_HTTP_CONNECTION_H_
+#define LIBBRILLO_BRILLO_HTTP_HTTP_CONNECTION_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/callback_forward.h>
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+#include <brillo/errors/error.h>
+#include <brillo/http/http_transport.h>
+#include <brillo/streams/stream.h>
+
+namespace brillo {
+namespace http {
+
+class Response;
+
+///////////////////////////////////////////////////////////////////////////////
+// Connection class is the base class for HTTP communication session.
+// It abstracts the implementation of underlying transport library (ex libcurl).
+// When the Connection-derived class is constructed, it is pre-set up with
+// basic initialization information necessary to initiate the server request
+// connection (such as the URL, request method, etc - see
+// Transport::CreateConnection() for more details). But most implementations
+// would not probably initiate the physical connection until SendHeaders
+// is called.
+// You normally shouldn't worry about using this class directly.
+// http::Request and http::Response classes use it for communication.
+// Effectively this class is the interface for the request/response objects to
+// the transport-specific instance of the communication channel with the
+// destination server. It is created by Transport as part of initiating
+// the connection to the destination URI and is shared between the request and
+// response object until all the data is sent to the server and the response
+// is received. The class does NOT represent a persistent TCP connection though
+// (e.g. in keep-alive scenarios).
+///////////////////////////////////////////////////////////////////////////////
+class BRILLO_EXPORT Connection
+    : public std::enable_shared_from_this<Connection> {
+ public:
+  explicit Connection(const std::shared_ptr<Transport>& transport)
+      : transport_(transport) {}
+  virtual ~Connection() = default;
+
+  // The following methods are used by http::Request object to initiate the
+  // communication with the server, send the request data and receive the
+  // response.
+
+  // Called by http::Request to initiate the connection with the server.
+  // This normally opens the socket and sends the request headers.
+  virtual bool SendHeaders(const HeaderList& headers,
+                           brillo::ErrorPtr* error) = 0;
+  // If needed, this function can be called to send the request body data.
+  virtual bool SetRequestData(StreamPtr stream, brillo::ErrorPtr* error) = 0;
+  // If needed, this function can be called to customize where the response
+  // data is streamed to.
+  virtual void SetResponseData(StreamPtr stream) = 0;
+  // This function is called when all the data is sent off and it's time
+  // to receive the response data. The method will block until the whole
+  // response message is received, or if an error occur in which case the
+  // function will return false and fill the error details in |error| object.
+  virtual bool FinishRequest(brillo::ErrorPtr* error) = 0;
+  // Send the request asynchronously and invoke the callback with the response
+  // received. Returns the ID of the pending async request.
+  virtual RequestID FinishRequestAsync(const SuccessCallback& success_callback,
+                                       const ErrorCallback& error_callback) = 0;
+
+  // The following methods are used by http::Response object to obtain the
+  // response data. They are used only after the response data has been received
+  // since the http::Response object is not constructed until
+  // Request::GetResponse()/Request::GetResponseAndBlock() methods are called.
+
+  // Returns the HTTP status code (e.g. 200 for success).
+  virtual int GetResponseStatusCode() const = 0;
+  // Returns the status text (e.g. for error 403 it could be "NOT AUTHORIZED").
+  virtual std::string GetResponseStatusText() const = 0;
+  // Returns the HTTP protocol version (e.g. "HTTP/1.1").
+  virtual std::string GetProtocolVersion() const = 0;
+  // Returns the value of particular response header, or empty string if the
+  // headers wasn't received.
+  virtual std::string GetResponseHeader(
+      const std::string& header_name) const = 0;
+  // Returns the response data stream. This function can be called only once
+  // as it transfers ownership of the data stream to the caller. Subsequent
+  // calls will fail with "Stream closed" error.
+  // Returns empty stream on failure and fills in the error information in
+  // |error| object.
+  virtual StreamPtr ExtractDataStream(brillo::ErrorPtr* error) = 0;
+
+ protected:
+  // |transport_| is mainly used to keep the object alive as long as the
+  // connection exists. But some implementations of Connection could use
+  // the Transport-derived class for their own needs as well.
+  std::shared_ptr<Transport> transport_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Connection);
+};
+
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_HTTP_CONNECTION_H_
diff --git a/libbrillo/brillo/http/http_connection_curl.cc b/libbrillo/brillo/http/http_connection_curl.cc
new file mode 100644
index 0000000..3720330
--- /dev/null
+++ b/libbrillo/brillo/http/http_connection_curl.cc
@@ -0,0 +1,268 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/http_connection_curl.h>
+
+#include <base/logging.h>
+#include <brillo/http/http_request.h>
+#include <brillo/http/http_transport_curl.h>
+#include <brillo/streams/memory_stream.h>
+#include <brillo/streams/stream_utils.h>
+#include <brillo/strings/string_utils.h>
+
+namespace brillo {
+namespace http {
+namespace curl {
+
+static int curl_trace(CURL* /* handle */,
+                      curl_infotype type,
+                      char* data,
+                      size_t size,
+                      void* /* userp */) {
+  std::string msg(data, size);
+
+  switch (type) {
+    case CURLINFO_TEXT:
+      VLOG(3) << "== Info: " << msg;
+      break;
+    case CURLINFO_HEADER_OUT:
+      VLOG(3) << "=> Send headers:\n" << msg;
+      break;
+    case CURLINFO_DATA_OUT:
+      VLOG(3) << "=> Send data:\n" << msg;
+      break;
+    case CURLINFO_SSL_DATA_OUT:
+      VLOG(3) << "=> Send SSL data" << msg;
+      break;
+    case CURLINFO_HEADER_IN:
+      VLOG(3) << "<= Recv header: " << msg;
+      break;
+    case CURLINFO_DATA_IN:
+      VLOG(3) << "<= Recv data:\n" << msg;
+      break;
+    case CURLINFO_SSL_DATA_IN:
+      VLOG(3) << "<= Recv SSL data" << msg;
+      break;
+    default:
+      break;
+  }
+  return 0;
+}
+
+Connection::Connection(CURL* curl_handle,
+                       const std::string& method,
+                       const std::shared_ptr<CurlInterface>& curl_interface,
+                       const std::shared_ptr<http::Transport>& transport)
+    : http::Connection(transport),
+      method_(method),
+      curl_handle_(curl_handle),
+      curl_interface_(curl_interface) {
+  // Store the connection pointer inside the CURL handle so we can easily
+  // retrieve it when doing asynchronous I/O.
+  curl_interface_->EasySetOptPtr(curl_handle_, CURLOPT_PRIVATE, this);
+  VLOG(2) << "curl::Connection created: " << method_;
+}
+
+Connection::~Connection() {
+  if (header_list_)
+    curl_slist_free_all(header_list_);
+  curl_interface_->EasyCleanup(curl_handle_);
+  VLOG(2) << "curl::Connection destroyed";
+}
+
+bool Connection::SendHeaders(const HeaderList& headers,
+                             brillo::ErrorPtr* /* error */) {
+  headers_.insert(headers.begin(), headers.end());
+  return true;
+}
+
+bool Connection::SetRequestData(StreamPtr stream,
+                                brillo::ErrorPtr* /* error */) {
+  request_data_stream_ = std::move(stream);
+  return true;
+}
+
+void Connection::SetResponseData(StreamPtr stream) {
+  response_data_stream_ = std::move(stream);
+}
+
+void Connection::PrepareRequest() {
+  if (VLOG_IS_ON(3)) {
+    curl_interface_->EasySetOptCallback(
+        curl_handle_, CURLOPT_DEBUGFUNCTION, &curl_trace);
+    curl_interface_->EasySetOptInt(curl_handle_, CURLOPT_VERBOSE, 1);
+  }
+
+  if (method_ != request_type::kGet) {
+    // Set up HTTP request data.
+    uint64_t data_size = 0;
+    if (request_data_stream_ && request_data_stream_->CanGetSize())
+        data_size = request_data_stream_->GetRemainingSize();
+
+    if (!request_data_stream_ || request_data_stream_->CanGetSize()) {
+      // Data size is known (either no data, or data size is available).
+      if (method_ == request_type::kPut) {
+        curl_interface_->EasySetOptOffT(
+            curl_handle_, CURLOPT_INFILESIZE_LARGE, data_size);
+      } else {
+        curl_interface_->EasySetOptOffT(
+            curl_handle_, CURLOPT_POSTFIELDSIZE_LARGE, data_size);
+      }
+    } else {
+      // Data size is unknown, so use chunked upload.
+      headers_.emplace(http::request_header::kTransferEncoding, "chunked");
+    }
+
+    if (request_data_stream_) {
+      curl_interface_->EasySetOptCallback(
+          curl_handle_, CURLOPT_READFUNCTION, &Connection::read_callback);
+      curl_interface_->EasySetOptPtr(curl_handle_, CURLOPT_READDATA, this);
+    }
+  }
+
+  if (!headers_.empty()) {
+    CHECK(header_list_ == nullptr);
+    for (auto pair : headers_) {
+      std::string header =
+          brillo::string_utils::Join(": ", pair.first, pair.second);
+      VLOG(2) << "Request header: " << header;
+      header_list_ = curl_slist_append(header_list_, header.c_str());
+    }
+    curl_interface_->EasySetOptPtr(
+        curl_handle_, CURLOPT_HTTPHEADER, header_list_);
+  }
+
+  headers_.clear();
+
+  // Set up HTTP response data.
+  if (!response_data_stream_)
+    response_data_stream_ = MemoryStream::Create(nullptr);
+  if (method_ != request_type::kHead) {
+    curl_interface_->EasySetOptCallback(
+        curl_handle_, CURLOPT_WRITEFUNCTION, &Connection::write_callback);
+    curl_interface_->EasySetOptPtr(curl_handle_, CURLOPT_WRITEDATA, this);
+  }
+
+  // HTTP response headers
+  curl_interface_->EasySetOptCallback(
+      curl_handle_, CURLOPT_HEADERFUNCTION, &Connection::header_callback);
+  curl_interface_->EasySetOptPtr(curl_handle_, CURLOPT_HEADERDATA, this);
+}
+
+bool Connection::FinishRequest(brillo::ErrorPtr* error) {
+  PrepareRequest();
+  CURLcode ret = curl_interface_->EasyPerform(curl_handle_);
+  if (ret != CURLE_OK) {
+    Transport::AddEasyCurlError(error, FROM_HERE, ret, curl_interface_.get());
+  } else {
+    // Rewind our data stream to the beginning so that it can be read back.
+    if (response_data_stream_->CanSeek() &&
+        !response_data_stream_->SetPosition(0, error))
+      return false;
+    LOG(INFO) << "Response: " << GetResponseStatusCode() << " ("
+              << GetResponseStatusText() << ")";
+  }
+  return (ret == CURLE_OK);
+}
+
+RequestID Connection::FinishRequestAsync(
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback) {
+  PrepareRequest();
+  return transport_->StartAsyncTransfer(this, success_callback, error_callback);
+}
+
+int Connection::GetResponseStatusCode() const {
+  int status_code = 0;
+  curl_interface_->EasyGetInfoInt(
+      curl_handle_, CURLINFO_RESPONSE_CODE, &status_code);
+  return status_code;
+}
+
+std::string Connection::GetResponseStatusText() const {
+  return status_text_;
+}
+
+std::string Connection::GetProtocolVersion() const {
+  return protocol_version_;
+}
+
+std::string Connection::GetResponseHeader(
+    const std::string& header_name) const {
+  auto p = headers_.find(header_name);
+  return p != headers_.end() ? p->second : std::string();
+}
+
+StreamPtr Connection::ExtractDataStream(brillo::ErrorPtr* error) {
+  if (!response_data_stream_) {
+    stream_utils::ErrorStreamClosed(FROM_HERE, error);
+  }
+  return std::move(response_data_stream_);
+}
+
+size_t Connection::write_callback(char* ptr,
+                                  size_t size,
+                                  size_t num,
+                                  void* data) {
+  Connection* me = reinterpret_cast<Connection*>(data);
+  size_t data_len = size * num;
+  VLOG(1) << "Response data (" << data_len << "): "
+          << std::string{ptr, data_len};
+  // TODO(nathanbullock): Currently we are relying on the stream not blocking,
+  // but if the stream is representing a pipe or some other construct that might
+  // block then this code will behave badly.
+  if (!me->response_data_stream_->WriteAllBlocking(ptr, data_len, nullptr)) {
+    LOG(ERROR) << "Failed to write response data";
+    data_len = 0;
+  }
+  return data_len;
+}
+
+size_t Connection::read_callback(char* ptr,
+                                 size_t size,
+                                 size_t num,
+                                 void* data) {
+  Connection* me = reinterpret_cast<Connection*>(data);
+  size_t data_len = size * num;
+
+  size_t read_size = 0;
+  bool success = me->request_data_stream_->ReadBlocking(ptr, data_len,
+                                                        &read_size, nullptr);
+  VLOG_IF(3, success) << "Sending data: " << std::string{ptr, read_size};
+  return success ? read_size : CURL_READFUNC_ABORT;
+}
+
+size_t Connection::header_callback(char* ptr,
+                                   size_t size,
+                                   size_t num,
+                                   void* data) {
+  using brillo::string_utils::SplitAtFirst;
+  Connection* me = reinterpret_cast<Connection*>(data);
+  size_t hdr_len = size * num;
+  std::string header(ptr, hdr_len);
+  // Remove newlines at the end of header line.
+  while (!header.empty() && (header.back() == '\r' || header.back() == '\n')) {
+    header.pop_back();
+  }
+
+  VLOG(2) << "Response header: " << header;
+
+  if (!me->status_text_set_) {
+    // First header - response code as "HTTP/1.1 200 OK".
+    // Need to extract the OK part
+    auto pair = SplitAtFirst(header, " ");
+    me->protocol_version_ = pair.first;
+    me->status_text_ = SplitAtFirst(pair.second, " ").second;
+    me->status_text_set_ = true;
+  } else {
+    auto pair = SplitAtFirst(header, ":");
+    if (!pair.second.empty())
+      me->headers_.insert(pair);
+  }
+  return hdr_len;
+}
+
+}  // namespace curl
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/http_connection_curl.h b/libbrillo/brillo/http/http_connection_curl.h
new file mode 100644
index 0000000..c34de57
--- /dev/null
+++ b/libbrillo/brillo/http/http_connection_curl.h
@@ -0,0 +1,103 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_HTTP_CONNECTION_CURL_H_
+#define LIBBRILLO_BRILLO_HTTP_HTTP_CONNECTION_CURL_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+#include <brillo/http/http_connection.h>
+#include <brillo/http/http_transport_curl.h>
+#include <curl/curl.h>
+
+namespace brillo {
+namespace http {
+namespace curl {
+
+// This is a libcurl-based implementation of http::Connection.
+class BRILLO_EXPORT Connection : public http::Connection {
+ public:
+  Connection(CURL* curl_handle,
+             const std::string& method,
+             const std::shared_ptr<CurlInterface>& curl_interface,
+             const std::shared_ptr<http::Transport>& transport);
+  ~Connection() override;
+
+  // Overrides from http::Connection.
+  // See http_connection.h for description of these methods.
+  bool SendHeaders(const HeaderList& headers, brillo::ErrorPtr* error) override;
+  bool SetRequestData(StreamPtr stream, brillo::ErrorPtr* error) override;
+  void SetResponseData(StreamPtr stream) override;
+  bool FinishRequest(brillo::ErrorPtr* error) override;
+  RequestID FinishRequestAsync(
+      const SuccessCallback& success_callback,
+      const ErrorCallback& error_callback) override;
+
+  int GetResponseStatusCode() const override;
+  std::string GetResponseStatusText() const override;
+  std::string GetProtocolVersion() const override;
+  std::string GetResponseHeader(const std::string& header_name) const override;
+  StreamPtr ExtractDataStream(brillo::ErrorPtr* error) override;
+
+ protected:
+  // Write data callback. Used by CURL when receiving response data.
+  BRILLO_PRIVATE static size_t write_callback(char* ptr,
+                                              size_t size,
+                                              size_t num,
+                                              void* data);
+  // Read data callback. Used by CURL when sending request body data.
+  BRILLO_PRIVATE static size_t read_callback(char* ptr,
+                                             size_t size,
+                                             size_t num,
+                                             void* data);
+  // Write header data callback. Used by CURL when receiving response headers.
+  BRILLO_PRIVATE static size_t header_callback(char* ptr,
+                                               size_t size,
+                                               size_t num,
+                                               void* data);
+
+  // Helper method to set up the |curl_handle_| with all the parameters
+  // pertaining to the current connection.
+  BRILLO_PRIVATE void PrepareRequest();
+
+  // HTTP request verb, such as "GET", "POST", "PUT", ...
+  std::string method_;
+
+  // Binary data for request body.
+  StreamPtr request_data_stream_;
+
+  // Received response data.
+  StreamPtr response_data_stream_;
+
+  // List of optional request headers provided by the caller.
+  // After request has been sent, contains the received response headers.
+  std::multimap<std::string, std::string> headers_;
+
+  // HTTP protocol version, such as HTTP/1.1
+  std::string protocol_version_;
+  // Response status text, such as "OK" for 200, or "Forbidden" for 403
+  std::string status_text_;
+  // Flag used when parsing response headers to separate the response status
+  // from the rest of response headers.
+  bool status_text_set_{false};
+
+  CURL* curl_handle_{nullptr};
+  curl_slist* header_list_{nullptr};
+
+  std::shared_ptr<CurlInterface> curl_interface_;
+
+ private:
+  friend class http::curl::Transport;
+  DISALLOW_COPY_AND_ASSIGN(Connection);
+};
+
+}  // namespace curl
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_HTTP_CONNECTION_CURL_H_
diff --git a/libbrillo/brillo/http/http_connection_curl_unittest.cc b/libbrillo/brillo/http/http_connection_curl_unittest.cc
new file mode 100644
index 0000000..90a5626
--- /dev/null
+++ b/libbrillo/brillo/http/http_connection_curl_unittest.cc
@@ -0,0 +1,324 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/http_connection_curl.h>
+
+#include <algorithm>
+#include <set>
+
+#include <base/callback.h>
+#include <brillo/http/http_request.h>
+#include <brillo/http/http_transport.h>
+#include <brillo/http/mock_curl_api.h>
+#include <brillo/http/mock_transport.h>
+#include <brillo/streams/memory_stream.h>
+#include <brillo/streams/mock_stream.h>
+#include <brillo/strings/string_utils.h>
+#include <brillo/mime_utils.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::DoAll;
+using testing::Invoke;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::_;
+
+namespace brillo {
+namespace http {
+namespace curl {
+
+namespace {
+
+using ReadWriteCallback =
+    size_t(char* ptr, size_t size, size_t num, void* data);
+
+// A helper class to simulate curl_easy_perform action. It invokes the
+// read callbacks to obtain the request data from the Connection and then
+// calls the header and write callbacks to "send" the response header and body.
+class CurlPerformer {
+ public:
+  // During the tests, use the address of |this| as the CURL* handle.
+  // This allows the static Perform() method to obtain the instance pointer
+  // having only CURL*.
+  CURL* GetCurlHandle() { return reinterpret_cast<CURL*>(this); }
+
+  // Callback to be invoked when mocking out curl_easy_perform() method.
+  static CURLcode Perform(CURL* curl) {
+    CurlPerformer* me = reinterpret_cast<CurlPerformer*>(curl);
+    return me->DoPerform();
+  }
+
+  // CURL callback functions and |connection| pointer needed to invoke the
+  // callbacks from the Connection class.
+  Connection* connection{nullptr};
+  ReadWriteCallback* write_callback{nullptr};
+  ReadWriteCallback* read_callback{nullptr};
+  ReadWriteCallback* header_callback{nullptr};
+
+  // Request body read from the connection.
+  std::string request_body;
+
+  // Response data to be sent back to connection.
+  std::string status_line;
+  HeaderList response_headers;
+  std::string response_body;
+
+ private:
+  // The actual implementation of curl_easy_perform() fake.
+  CURLcode DoPerform() {
+    // Read request body.
+    char buffer[1024];
+    for (;;) {
+      size_t size_read = read_callback(buffer, sizeof(buffer), 1, connection);
+      if (size_read == CURL_READFUNC_ABORT)
+        return CURLE_ABORTED_BY_CALLBACK;
+      if (size_read == CURL_READFUNC_PAUSE)
+        return CURLE_READ_ERROR;  // Shouldn't happen.
+      if (size_read == 0)
+        break;
+      request_body.append(buffer, size_read);
+    }
+
+    // Send the response headers.
+    std::vector<std::string> header_lines;
+    header_lines.push_back(status_line + "\r\n");
+    for (const auto& pair : response_headers) {
+      header_lines.push_back(string_utils::Join(": ", pair.first, pair.second) +
+                             "\r\n");
+    }
+
+    for (const std::string& line : header_lines) {
+      CURLcode code = WriteString(header_callback, line);
+      if (code != CURLE_OK)
+        return code;
+    }
+
+    // Send response body.
+    return WriteString(write_callback, response_body);
+  }
+
+  // Helper method to send a string to a write callback. Keeps calling
+  // the callback until all the data is written.
+  CURLcode WriteString(ReadWriteCallback* callback, const std::string& str) {
+    size_t pos = 0;
+    size_t size_remaining = str.size();
+    while (size_remaining) {
+      size_t size_written = callback(
+          const_cast<char*>(str.data() + pos), size_remaining, 1, connection);
+      if (size_written == CURL_WRITEFUNC_PAUSE)
+        return CURLE_WRITE_ERROR;  // Shouldn't happen.
+      CHECK(size_written <= size_remaining) << "Unexpected size returned";
+      size_remaining -= size_written;
+      pos += size_written;
+    }
+    return CURLE_OK;
+  }
+};
+
+// Custom matcher to validate the parameter of CURLOPT_HTTPHEADER CURL option
+// which contains the request headers as curl_slist* chain.
+MATCHER_P(HeadersMatch, headers, "") {
+  std::multiset<std::string> test_headers;
+  for (const auto& pair : headers)
+    test_headers.insert(string_utils::Join(": ", pair.first, pair.second));
+
+  std::multiset<std::string> src_headers;
+  const curl_slist* head = static_cast<const curl_slist*>(arg);
+  while (head) {
+    src_headers.insert(head->data);
+    head = head->next;
+  }
+
+  std::vector<std::string> difference;
+  std::set_symmetric_difference(src_headers.begin(), src_headers.end(),
+                                test_headers.begin(), test_headers.end(),
+                                std::back_inserter(difference));
+  return difference.empty();
+}
+
+// Custom action to save a CURL callback pointer into a member of CurlPerformer.
+ACTION_TEMPLATE(SaveCallback,
+                HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_2_VALUE_PARAMS(performer, mem_ptr)) {
+  performer->*mem_ptr = reinterpret_cast<ReadWriteCallback*>(std::get<k>(args));
+}
+
+}  // anonymous namespace
+
+class HttpCurlConnectionTest : public testing::Test {
+ public:
+  void SetUp() override {
+    curl_api_ = std::make_shared<MockCurlInterface>();
+    transport_ = std::make_shared<MockTransport>();
+    EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_PRIVATE, _))
+        .WillOnce(Return(CURLE_OK));
+    connection_ = std::make_shared<Connection>(
+        handle_, request_type::kPost, curl_api_, transport_);
+    performer_.connection = connection_.get();
+  }
+
+  void TearDown() override {
+    EXPECT_CALL(*curl_api_, EasyCleanup(handle_)).Times(1);
+    connection_.reset();
+    transport_.reset();
+    curl_api_.reset();
+  }
+
+ protected:
+  std::shared_ptr<MockCurlInterface> curl_api_;
+  std::shared_ptr<MockTransport> transport_;
+  CurlPerformer performer_;
+  CURL* handle_{performer_.GetCurlHandle()};
+  std::shared_ptr<Connection> connection_;
+};
+
+TEST_F(HttpCurlConnectionTest, FinishRequestAsync) {
+  std::string request_data{"Foo Bar Baz"};
+  StreamPtr stream = MemoryStream::OpenRef(request_data, nullptr);
+  EXPECT_TRUE(connection_->SetRequestData(std::move(stream), nullptr));
+  EXPECT_TRUE(connection_->SendHeaders({{"X-Foo", "bar"}}, nullptr));
+
+  if (VLOG_IS_ON(3)) {
+    EXPECT_CALL(*curl_api_,
+                EasySetOptCallback(handle_, CURLOPT_DEBUGFUNCTION, _))
+        .WillOnce(Return(CURLE_OK));
+    EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_VERBOSE, 1))
+        .WillOnce(Return(CURLE_OK));
+  }
+
+  EXPECT_CALL(
+      *curl_api_,
+      EasySetOptOffT(handle_, CURLOPT_POSTFIELDSIZE_LARGE, request_data.size()))
+      .WillOnce(Return(CURLE_OK));
+
+  EXPECT_CALL(*curl_api_, EasySetOptCallback(handle_, CURLOPT_READFUNCTION, _))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_READDATA, _))
+      .WillOnce(Return(CURLE_OK));
+
+  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_HTTPHEADER, _))
+      .WillOnce(Return(CURLE_OK));
+
+  EXPECT_CALL(*curl_api_, EasySetOptCallback(handle_, CURLOPT_WRITEFUNCTION, _))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_WRITEDATA, _))
+      .WillOnce(Return(CURLE_OK));
+
+  EXPECT_CALL(*curl_api_,
+              EasySetOptCallback(handle_, CURLOPT_HEADERFUNCTION, _))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_HEADERDATA, _))
+      .WillOnce(Return(CURLE_OK));
+
+  EXPECT_CALL(*transport_, StartAsyncTransfer(connection_.get(), _, _))
+      .Times(1);
+  connection_->FinishRequestAsync({}, {});
+}
+
+MATCHER_P(MatchStringBuffer, data, "") {
+  return data.compare(static_cast<const char*>(arg)) == 0;
+}
+
+TEST_F(HttpCurlConnectionTest, FinishRequest) {
+  std::string request_data{"Foo Bar Baz"};
+  std::string response_data{"<html><body>OK</body></html>"};
+  StreamPtr stream = MemoryStream::OpenRef(request_data, nullptr);
+  HeaderList headers{
+      {request_header::kAccept, "*/*"},
+      {request_header::kContentType, mime::text::kPlain},
+      {request_header::kContentLength, std::to_string(request_data.size())},
+      {"X-Foo", "bar"},
+  };
+  std::unique_ptr<MockStream> response_stream(new MockStream);
+  EXPECT_CALL(*response_stream,
+              WriteAllBlocking(MatchStringBuffer(response_data),
+                               response_data.size(), _))
+      .WillOnce(Return(true));
+  EXPECT_CALL(*response_stream, CanSeek())
+      .WillOnce(Return(false));
+  connection_->SetResponseData(std::move(response_stream));
+  EXPECT_TRUE(connection_->SetRequestData(std::move(stream), nullptr));
+  EXPECT_TRUE(connection_->SendHeaders(headers, nullptr));
+
+  // Expectations for Connection::FinishRequest() call.
+  if (VLOG_IS_ON(3)) {
+    EXPECT_CALL(*curl_api_,
+                EasySetOptCallback(handle_, CURLOPT_DEBUGFUNCTION, _))
+        .WillOnce(Return(CURLE_OK));
+    EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_VERBOSE, 1))
+        .WillOnce(Return(CURLE_OK));
+  }
+
+  EXPECT_CALL(
+      *curl_api_,
+      EasySetOptOffT(handle_, CURLOPT_POSTFIELDSIZE_LARGE, request_data.size()))
+      .WillOnce(Return(CURLE_OK));
+
+  EXPECT_CALL(*curl_api_, EasySetOptCallback(handle_, CURLOPT_READFUNCTION, _))
+      .WillOnce(
+          DoAll(SaveCallback<2>(&performer_, &CurlPerformer::read_callback),
+                Return(CURLE_OK)));
+  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_READDATA, _))
+      .WillOnce(Return(CURLE_OK));
+
+  EXPECT_CALL(*curl_api_,
+              EasySetOptPtr(handle_, CURLOPT_HTTPHEADER, HeadersMatch(headers)))
+      .WillOnce(Return(CURLE_OK));
+
+  EXPECT_CALL(*curl_api_, EasySetOptCallback(handle_, CURLOPT_WRITEFUNCTION, _))
+      .WillOnce(
+          DoAll(SaveCallback<2>(&performer_, &CurlPerformer::write_callback),
+                Return(CURLE_OK)));
+  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_WRITEDATA, _))
+      .WillOnce(Return(CURLE_OK));
+
+  EXPECT_CALL(*curl_api_,
+              EasySetOptCallback(handle_, CURLOPT_HEADERFUNCTION, _))
+      .WillOnce(
+          DoAll(SaveCallback<2>(&performer_, &CurlPerformer::header_callback),
+                Return(CURLE_OK)));
+  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_HEADERDATA, _))
+      .WillOnce(Return(CURLE_OK));
+
+  EXPECT_CALL(*curl_api_, EasyPerform(handle_))
+      .WillOnce(Invoke(&CurlPerformer::Perform));
+
+  EXPECT_CALL(*curl_api_, EasyGetInfoInt(handle_, CURLINFO_RESPONSE_CODE, _))
+      .WillOnce(DoAll(SetArgPointee<2>(status_code::Ok), Return(CURLE_OK)));
+
+  // Set up the CurlPerformer with the response data expected to be received.
+  HeaderList response_headers{
+      {response_header::kContentLength, std::to_string(response_data.size())},
+      {response_header::kContentType, mime::text::kHtml},
+      {"X-Foo", "baz"},
+  };
+  performer_.status_line = "HTTP/1.1 200 OK";
+  performer_.response_body = response_data;
+  performer_.response_headers = response_headers;
+
+  // Perform the request.
+  EXPECT_TRUE(connection_->FinishRequest(nullptr));
+
+  // Make sure we sent out the request body correctly.
+  EXPECT_EQ(request_data, performer_.request_body);
+
+  // Validate the parsed response data.
+  EXPECT_CALL(*curl_api_, EasyGetInfoInt(handle_, CURLINFO_RESPONSE_CODE, _))
+      .WillOnce(DoAll(SetArgPointee<2>(status_code::Ok), Return(CURLE_OK)));
+  EXPECT_EQ(status_code::Ok, connection_->GetResponseStatusCode());
+  EXPECT_EQ("HTTP/1.1", connection_->GetProtocolVersion());
+  EXPECT_EQ("OK", connection_->GetResponseStatusText());
+  EXPECT_EQ(std::to_string(response_data.size()),
+            connection_->GetResponseHeader(response_header::kContentLength));
+  EXPECT_EQ(mime::text::kHtml,
+            connection_->GetResponseHeader(response_header::kContentType));
+  EXPECT_EQ("baz", connection_->GetResponseHeader("X-Foo"));
+  auto data_stream = connection_->ExtractDataStream(nullptr);
+  ASSERT_NE(nullptr, data_stream.get());
+}
+
+}  // namespace curl
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/http_connection_fake.cc b/libbrillo/brillo/http/http_connection_fake.cc
new file mode 100644
index 0000000..15e5181
--- /dev/null
+++ b/libbrillo/brillo/http/http_connection_fake.cc
@@ -0,0 +1,120 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/http_connection_fake.h>
+
+#include <base/logging.h>
+#include <brillo/bind_lambda.h>
+#include <brillo/http/http_request.h>
+#include <brillo/mime_utils.h>
+#include <brillo/streams/memory_stream.h>
+#include <brillo/strings/string_utils.h>
+
+namespace brillo {
+namespace http {
+namespace fake {
+
+Connection::Connection(const std::string& url,
+                       const std::string& method,
+                       const std::shared_ptr<http::Transport>& transport)
+    : http::Connection(transport), request_(url, method) {
+  VLOG(1) << "fake::Connection created: " << method;
+}
+
+Connection::~Connection() {
+  VLOG(1) << "fake::Connection destroyed";
+}
+
+bool Connection::SendHeaders(const HeaderList& headers,
+                             brillo::ErrorPtr* /* error */) {
+  request_.AddHeaders(headers);
+  return true;
+}
+
+bool Connection::SetRequestData(StreamPtr stream,
+                                brillo::ErrorPtr* /* error */) {
+  request_.SetData(std::move(stream));
+  return true;
+}
+
+bool Connection::FinishRequest(brillo::ErrorPtr*  /* error */) {
+  using brillo::string_utils::ToString;
+  request_.AddHeaders(
+      {{request_header::kContentLength, ToString(request_.GetData().size())}});
+  fake::Transport* transport = static_cast<fake::Transport*>(transport_.get());
+  CHECK(transport) << "Expecting a fake transport";
+  auto handler = transport->GetHandler(request_.GetURL(), request_.GetMethod());
+  if (handler.is_null()) {
+    LOG(ERROR) << "Received unexpected " << request_.GetMethod()
+               << " request at " << request_.GetURL();
+    response_.ReplyText(status_code::NotFound,
+                        "<html><body>Not found</body></html>",
+                        brillo::mime::text::kHtml);
+  } else {
+    handler.Run(request_, &response_);
+  }
+  return true;
+}
+
+RequestID Connection::FinishRequestAsync(
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback) {
+  // Make sure the produced Closure holds a reference to the instance of this
+  // connection.
+  auto connection = std::static_pointer_cast<Connection>(shared_from_this());
+  auto callback = [](std::shared_ptr<Connection> connection,
+                     const SuccessCallback& success_callback,
+                     const ErrorCallback& error_callback) {
+    connection->FinishRequestAsyncHelper(success_callback, error_callback);
+  };
+  transport_->RunCallbackAsync(FROM_HERE,
+                               base::Bind(callback,
+                                          base::Passed(&connection),
+                                          success_callback,
+                                          error_callback));
+  return 1;
+}
+
+void Connection::FinishRequestAsyncHelper(
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback) {
+  brillo::ErrorPtr error;
+  if (!FinishRequest(&error)) {
+    error_callback.Run(1, error.get());
+  } else {
+    std::unique_ptr<Response> response{new Response{shared_from_this()}};
+    success_callback.Run(1, std::move(response));
+  }
+}
+
+int Connection::GetResponseStatusCode() const {
+  return response_.GetStatusCode();
+}
+
+std::string Connection::GetResponseStatusText() const {
+  return response_.GetStatusText();
+}
+
+std::string Connection::GetProtocolVersion() const {
+  return response_.GetProtocolVersion();
+}
+
+std::string Connection::GetResponseHeader(
+    const std::string& header_name) const {
+  return response_.GetHeader(header_name);
+}
+
+StreamPtr Connection::ExtractDataStream(brillo::ErrorPtr* error) {
+  // HEAD requests must not return body.
+  if (request_.GetMethod() != request_type::kHead) {
+    return MemoryStream::OpenRef(response_.GetData(), error);
+  } else {
+    // Return empty data stream for HEAD requests.
+    return MemoryStream::OpenCopyOf(nullptr, 0, error);
+  }
+}
+
+}  // namespace fake
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/http_connection_fake.h b/libbrillo/brillo/http/http_connection_fake.h
new file mode 100644
index 0000000..a6ebeee
--- /dev/null
+++ b/libbrillo/brillo/http/http_connection_fake.h
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_HTTP_CONNECTION_FAKE_H_
+#define LIBBRILLO_BRILLO_HTTP_HTTP_CONNECTION_FAKE_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+#include <brillo/http/http_connection.h>
+#include <brillo/http/http_transport_fake.h>
+
+namespace brillo {
+namespace http {
+namespace fake {
+
+// This is a fake implementation of http::Connection for unit testing.
+class Connection : public http::Connection {
+ public:
+  Connection(const std::string& url,
+             const std::string& method,
+             const std::shared_ptr<http::Transport>& transport);
+  ~Connection() override;
+
+  // Overrides from http::Connection.
+  // See http_connection.h for description of these methods.
+  bool SendHeaders(const HeaderList& headers, brillo::ErrorPtr* error) override;
+  bool SetRequestData(StreamPtr stream, brillo::ErrorPtr* error) override;
+  void SetResponseData(StreamPtr /* stream */) override {}
+  bool FinishRequest(brillo::ErrorPtr* error) override;
+  RequestID FinishRequestAsync(const SuccessCallback& success_callback,
+                               const ErrorCallback& error_callback) override;
+
+  int GetResponseStatusCode() const override;
+  std::string GetResponseStatusText() const override;
+  std::string GetProtocolVersion() const override;
+  std::string GetResponseHeader(const std::string& header_name) const override;
+  StreamPtr ExtractDataStream(brillo::ErrorPtr* error) override;
+
+ private:
+  // A helper method for FinishRequestAsync() implementation.
+  void FinishRequestAsyncHelper(const SuccessCallback& success_callback,
+                                const ErrorCallback& error_callback);
+
+  // Request and response objects passed to the user-provided request handler
+  // callback. The request object contains all the request information.
+  // The response object is the server response that is created by
+  // the handler in response to the request.
+  ServerRequest request_;
+  ServerResponse response_;
+
+  DISALLOW_COPY_AND_ASSIGN(Connection);
+};
+
+}  // namespace fake
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_HTTP_CONNECTION_FAKE_H_
diff --git a/libbrillo/brillo/http/http_form_data.cc b/libbrillo/brillo/http/http_form_data.cc
new file mode 100644
index 0000000..4d8f6f0
--- /dev/null
+++ b/libbrillo/brillo/http/http_form_data.cc
@@ -0,0 +1,221 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/http_form_data.h>
+
+#include <limits>
+
+#include <base/format_macros.h>
+#include <base/rand_util.h>
+#include <base/strings/stringprintf.h>
+
+#include <brillo/errors/error_codes.h>
+#include <brillo/http/http_transport.h>
+#include <brillo/mime_utils.h>
+#include <brillo/streams/file_stream.h>
+#include <brillo/streams/input_stream_set.h>
+#include <brillo/streams/memory_stream.h>
+
+namespace brillo {
+namespace http {
+
+namespace form_header {
+const char kContentDisposition[] = "Content-Disposition";
+const char kContentTransferEncoding[] = "Content-Transfer-Encoding";
+const char kContentType[] = "Content-Type";
+}  // namespace form_header
+
+const char content_disposition::kFile[] = "file";
+const char content_disposition::kFormData[] = "form-data";
+
+FormField::FormField(const std::string& name,
+                     const std::string& content_disposition,
+                     const std::string& content_type,
+                     const std::string& transfer_encoding)
+    : name_{name},
+      content_disposition_{content_disposition},
+      content_type_{content_type},
+      transfer_encoding_{transfer_encoding} {
+}
+
+std::string FormField::GetContentDisposition() const {
+  std::string disposition = content_disposition_;
+  if (!name_.empty())
+    base::StringAppendF(&disposition, "; name=\"%s\"", name_.c_str());
+  return disposition;
+}
+
+std::string FormField::GetContentType() const {
+  return content_type_;
+}
+
+std::string FormField::GetContentHeader() const {
+  HeaderList headers{
+      {form_header::kContentDisposition, GetContentDisposition()}
+  };
+
+  if (!content_type_.empty())
+    headers.emplace_back(form_header::kContentType, GetContentType());
+
+  if (!transfer_encoding_.empty()) {
+    headers.emplace_back(form_header::kContentTransferEncoding,
+                         transfer_encoding_);
+  }
+
+  std::string result;
+  for (const auto& pair : headers) {
+    base::StringAppendF(
+        &result, "%s: %s\r\n", pair.first.c_str(), pair.second.c_str());
+  }
+  result += "\r\n";
+  return result;
+}
+
+TextFormField::TextFormField(const std::string& name,
+                             const std::string& data,
+                             const std::string& content_type,
+                             const std::string& transfer_encoding)
+    : FormField{name,
+                content_disposition::kFormData,
+                content_type,
+                transfer_encoding},
+      data_{data} {
+}
+
+bool TextFormField::ExtractDataStreams(std::vector<StreamPtr>* streams) {
+  streams->push_back(MemoryStream::OpenCopyOf(data_, nullptr));
+  return true;
+}
+
+FileFormField::FileFormField(const std::string& name,
+                             StreamPtr stream,
+                             const std::string& file_name,
+                             const std::string& content_disposition,
+                             const std::string& content_type,
+                             const std::string& transfer_encoding)
+    : FormField{name, content_disposition, content_type, transfer_encoding},
+      stream_{std::move(stream)},
+      file_name_{file_name} {
+}
+
+std::string FileFormField::GetContentDisposition() const {
+  std::string disposition = FormField::GetContentDisposition();
+  base::StringAppendF(&disposition, "; filename=\"%s\"", file_name_.c_str());
+  return disposition;
+}
+
+bool FileFormField::ExtractDataStreams(std::vector<StreamPtr>* streams) {
+  if (!stream_)
+    return false;
+  streams->push_back(std::move(stream_));
+  return true;
+}
+
+MultiPartFormField::MultiPartFormField(const std::string& name,
+                                       const std::string& content_type,
+                                       const std::string& boundary)
+    : FormField{name,
+                content_disposition::kFormData,
+                content_type.empty() ? mime::multipart::kMixed : content_type,
+                {}},
+      boundary_{boundary} {
+  if (boundary_.empty())
+    boundary_ = base::StringPrintf("%016" PRIx64, base::RandUint64());
+}
+
+bool MultiPartFormField::ExtractDataStreams(std::vector<StreamPtr>* streams) {
+  for (auto& part : parts_) {
+    std::string data = GetBoundaryStart() + part->GetContentHeader();
+    streams->push_back(MemoryStream::OpenCopyOf(data, nullptr));
+    if (!part->ExtractDataStreams(streams))
+      return false;
+
+    streams->push_back(MemoryStream::OpenRef("\r\n", nullptr));
+  }
+  if (!parts_.empty()) {
+    std::string data = GetBoundaryEnd();
+    streams->push_back(MemoryStream::OpenCopyOf(data, nullptr));
+  }
+  return true;
+}
+
+std::string MultiPartFormField::GetContentType() const {
+  return base::StringPrintf(
+      "%s; boundary=\"%s\"", content_type_.c_str(), boundary_.c_str());
+}
+
+void MultiPartFormField::AddCustomField(std::unique_ptr<FormField> field) {
+  parts_.push_back(std::move(field));
+}
+
+void MultiPartFormField::AddTextField(const std::string& name,
+                                      const std::string& data) {
+  AddCustomField(std::unique_ptr<FormField>{new TextFormField{name, data}});
+}
+
+bool MultiPartFormField::AddFileField(const std::string& name,
+                                      const base::FilePath& file_path,
+                                      const std::string& content_disposition,
+                                      const std::string& content_type,
+                                      brillo::ErrorPtr* error) {
+  StreamPtr stream = FileStream::Open(file_path, Stream::AccessMode::READ,
+                                      FileStream::Disposition::OPEN_EXISTING,
+                                      error);
+  if (!stream)
+    return false;
+  std::string file_name = file_path.BaseName().value();
+  std::unique_ptr<FormField> file_field{new FileFormField{name,
+                                                          std::move(stream),
+                                                          file_name,
+                                                          content_disposition,
+                                                          content_type,
+                                                          "binary"}};
+  AddCustomField(std::move(file_field));
+  return true;
+}
+
+std::string MultiPartFormField::GetBoundaryStart() const {
+  return base::StringPrintf("--%s\r\n", boundary_.c_str());
+}
+
+std::string MultiPartFormField::GetBoundaryEnd() const {
+  return base::StringPrintf("--%s--", boundary_.c_str());
+}
+
+FormData::FormData() : FormData{std::string{}} {
+}
+
+FormData::FormData(const std::string& boundary)
+    : form_data_{"", mime::multipart::kFormData, boundary} {
+}
+
+void FormData::AddCustomField(std::unique_ptr<FormField> field) {
+  form_data_.AddCustomField(std::move(field));
+}
+
+void FormData::AddTextField(const std::string& name, const std::string& data) {
+  form_data_.AddTextField(name, data);
+}
+
+bool FormData::AddFileField(const std::string& name,
+                            const base::FilePath& file_path,
+                            const std::string& content_type,
+                            brillo::ErrorPtr* error) {
+  return form_data_.AddFileField(
+      name, file_path, content_disposition::kFormData, content_type, error);
+}
+
+std::string FormData::GetContentType() const {
+  return form_data_.GetContentType();
+}
+
+StreamPtr FormData::ExtractDataStream() {
+  std::vector<StreamPtr> source_streams;
+  if (form_data_.ExtractDataStreams(&source_streams))
+    return InputStreamSet::Create(std::move(source_streams), nullptr);
+  return {};
+}
+
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/http_form_data.h b/libbrillo/brillo/http/http_form_data.h
new file mode 100644
index 0000000..e12d3d8
--- /dev/null
+++ b/libbrillo/brillo/http/http_form_data.h
@@ -0,0 +1,233 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_HTTP_FORM_DATA_H_
+#define LIBBRILLO_BRILLO_HTTP_HTTP_FORM_DATA_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/files/file_path.h>
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+#include <brillo/errors/error.h>
+#include <brillo/streams/stream.h>
+
+namespace brillo {
+namespace http {
+
+namespace content_disposition {
+BRILLO_EXPORT extern const char kFormData[];
+BRILLO_EXPORT extern const char kFile[];
+}  // namespace content_disposition
+
+// An abstract base class for all types of form fields used by FormData class.
+// This class represents basic information about a form part in
+// multipart/form-data and multipart/mixed content.
+// For more details on multipart content, see the following RFC:
+//    http://www.ietf.org/rfc/rfc2388
+// For more details on MIME and content headers, see the following RFC:
+//    http://www.ietf.org/rfc/rfc2045
+class BRILLO_EXPORT FormField {
+ public:
+  // The constructor that takes the basic data part information common to
+  // all part types. An example of part's headers could include:
+  //
+  //    Content-Disposition: form-data; name="field1"
+  //    Content-Type: text/plain;charset=windows-1250
+  //    Content-Transfer-Encoding: quoted-printable
+  //
+  // The constructor parameters correspond to the basic part attributes:
+  //  |name| = the part name ("name" parameter of Content-Disposition header;
+  //           "field1" in the example above)
+  //  |content_disposition| = the part disposition ("form-data" in the example)
+  //  |content_type| = the content type ("text/plain;charset=windows-1250")
+  //  |transfer_encoding| = the encoding type for transport ("quoted-printable")
+  //                        See http://www.ietf.org/rfc/rfc2045, section 6.1
+  FormField(const std::string& name,
+            const std::string& content_disposition,
+            const std::string& content_type,
+            const std::string& transfer_encoding);
+  virtual ~FormField() = default;
+
+  // Returns the full Content-Disposition header value. This might include the
+  // disposition type itself as well as the field "name" and/or "filename"
+  // parameters.
+  virtual std::string GetContentDisposition() const;
+
+  // Returns the full content type of field data. MultiPartFormField overloads
+  // this method to append "boundary" parameter to it.
+  virtual std::string GetContentType() const;
+
+  // Returns a string with all of the field headers, delimited by CRLF
+  // characters ("\r\n").
+  std::string GetContentHeader() const;
+
+  // Adds the data stream(s) to the list of streams to read from.
+  // This is a potentially destructive operation and can be guaranteed to
+  // succeed only on the first try. Subsequent calls will fail for certain
+  // types of form fields.
+  virtual bool ExtractDataStreams(std::vector<StreamPtr>* streams) = 0;
+
+ protected:
+  // Form field name. If not empty, it will be appended to Content-Disposition
+  // field header using "name" attribute.
+  std::string name_;
+
+  // Form field disposition. Most of the time this will be "form-data". But for
+  // nested file uploads inside "multipart/mixed" sections, this can be "file".
+  std::string content_disposition_;
+
+  // Content type. If omitted (empty), "plain/text" assumed.
+  std::string content_type_;
+
+  // Transfer encoding for field data. If omitted, "7bit" is assumed. For most
+  // binary contents (e.g. for file content), use "binary".
+  std::string transfer_encoding_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FormField);
+};
+
+// Simple text form field.
+class BRILLO_EXPORT TextFormField : public FormField {
+ public:
+  // Constructor. Parameters:
+  //  name: field name
+  //  data: field text data
+  //  content_type: the data content type. Empty if not specified.
+  //  transfer_encoding: the encoding type of data. If omitted, no encoding
+  //      is specified (and "7bit" is assumed).
+  TextFormField(const std::string& name,
+                const std::string& data,
+                const std::string& content_type = {},
+                const std::string& transfer_encoding = {});
+
+  bool ExtractDataStreams(std::vector<StreamPtr>* streams) override;
+
+ private:
+  std::string data_;  // Buffer/reader for field data.
+
+  DISALLOW_COPY_AND_ASSIGN(TextFormField);
+};
+
+// File upload form field.
+class BRILLO_EXPORT FileFormField : public FormField {
+ public:
+  // Constructor. Parameters:
+  //  name: field name
+  //  stream: open stream with the contents of the file.
+  //  file_name: just the base file name of the file, e.g. "file.txt".
+  //      Used in "filename" parameter of Content-Disposition header.
+  //  content_type: valid content type of the file.
+  //  transfer_encoding: the encoding type of data.
+  //      If omitted, "binary" is used.
+  FileFormField(const std::string& name,
+                StreamPtr stream,
+                const std::string& file_name,
+                const std::string& content_disposition,
+                const std::string& content_type,
+                const std::string& transfer_encoding = {});
+
+  // Override from FormField.
+  // Appends "filename" parameter to Content-Disposition header.
+  std::string GetContentDisposition() const override;
+
+  bool ExtractDataStreams(std::vector<StreamPtr>* streams) override;
+
+ private:
+  StreamPtr stream_;
+  std::string file_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileFormField);
+};
+
+// Multipart form field.
+// This is used directly by FormData class to build the request body for
+// form upload. It can also be used with multiple file uploads for a single
+// file field, when the uploaded files should be sent as "multipart/mixed".
+class BRILLO_EXPORT MultiPartFormField : public FormField {
+ public:
+  // Constructor. Parameters:
+  //  name: field name
+  //  content_type: valid content type. If omitted, "multipart/mixed" is used.
+  //  boundary: multipart boundary separator.
+  //      If omitted/empty, a random string is generated.
+  explicit MultiPartFormField(const std::string& name,
+                     const std::string& content_type = {},
+                     const std::string& boundary = {});
+
+  // Override from FormField.
+  // Appends "boundary" parameter to Content-Type header.
+  std::string GetContentType() const override;
+
+  bool ExtractDataStreams(std::vector<StreamPtr>* streams) override;
+
+  // Adds a form field to the form data. The |field| could be a simple text
+  // field, a file upload field or a multipart form field.
+  void AddCustomField(std::unique_ptr<FormField> field);
+
+  // Adds a simple text form field.
+  void AddTextField(const std::string& name, const std::string& data);
+
+  // Adds a file upload form field using a file path.
+  bool AddFileField(const std::string& name,
+                    const base::FilePath& file_path,
+                    const std::string& content_disposition,
+                    const std::string& content_type,
+                    brillo::ErrorPtr* error);
+
+  // Returns a boundary string used to separate multipart form fields.
+  const std::string& GetBoundary() const { return boundary_; }
+
+ private:
+  // Returns the starting boundary string: "--<boundary>".
+  std::string GetBoundaryStart() const;
+  // Returns the ending boundary string: "--<boundary>--".
+  std::string GetBoundaryEnd() const;
+
+  std::string boundary_;  // Boundary string used as field separator.
+  std::vector<std::unique_ptr<FormField>> parts_;  // Form field list.
+
+  DISALLOW_COPY_AND_ASSIGN(MultiPartFormField);
+};
+
+// A class representing a multipart form data for sending as HTTP POST request.
+class BRILLO_EXPORT FormData final {
+ public:
+  FormData();
+  // Allows to specify a custom |boundary| separator string.
+  explicit FormData(const std::string& boundary);
+
+  // Adds a form field to the form data. The |field| could be a simple text
+  // field, a file upload field or a multipart form field.
+  void AddCustomField(std::unique_ptr<FormField> field);
+
+  // Adds a simple text form field.
+  void AddTextField(const std::string& name, const std::string& data);
+
+  // Adds a file upload form field using a file path.
+  bool AddFileField(const std::string& name,
+                    const base::FilePath& file_path,
+                    const std::string& content_type,
+                    brillo::ErrorPtr* error);
+
+  // Returns the complete content type string to be used in HTTP requests.
+  std::string GetContentType() const;
+
+  // Returns the data stream for the form data. This is a potentially
+  // destructive operation and can be called only once.
+  StreamPtr ExtractDataStream();
+
+ private:
+  MultiPartFormField form_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(FormData);
+};
+
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_HTTP_FORM_DATA_H_
diff --git a/libbrillo/brillo/http/http_form_data_unittest.cc b/libbrillo/brillo/http/http_form_data_unittest.cc
new file mode 100644
index 0000000..842225d
--- /dev/null
+++ b/libbrillo/brillo/http/http_form_data_unittest.cc
@@ -0,0 +1,202 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/http_form_data.h>
+
+#include <set>
+
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <brillo/mime_utils.h>
+#include <brillo/streams/file_stream.h>
+#include <brillo/streams/input_stream_set.h>
+#include <gtest/gtest.h>
+
+namespace brillo {
+namespace http {
+namespace {
+std::string GetFormFieldData(FormField* field) {
+  std::vector<StreamPtr> streams;
+  CHECK(field->ExtractDataStreams(&streams));
+  StreamPtr stream = InputStreamSet::Create(std::move(streams), nullptr);
+
+  std::vector<uint8_t> data(stream->GetSize());
+  EXPECT_TRUE(stream->ReadAllBlocking(data.data(), data.size(), nullptr));
+  return std::string{data.begin(), data.end()};
+}
+}  // anonymous namespace
+
+TEST(HttpFormData, TextFormField) {
+  TextFormField form_field{"field1", "abcdefg", mime::text::kPlain, "7bit"};
+  const char expected_header[] =
+      "Content-Disposition: form-data; name=\"field1\"\r\n"
+      "Content-Type: text/plain\r\n"
+      "Content-Transfer-Encoding: 7bit\r\n"
+      "\r\n";
+  EXPECT_EQ(expected_header, form_field.GetContentHeader());
+  EXPECT_EQ("abcdefg", GetFormFieldData(&form_field));
+}
+
+TEST(HttpFormData, FileFormField) {
+  base::ScopedTempDir dir;
+  ASSERT_TRUE(dir.CreateUniqueTempDir());
+  std::string file_content{"text line1\ntext line2\n"};
+  base::FilePath file_name = dir.path().Append("sample.txt");
+  ASSERT_EQ(file_content.size(),
+            static_cast<size_t>(base::WriteFile(
+                file_name, file_content.data(), file_content.size())));
+
+  StreamPtr stream = FileStream::Open(file_name, Stream::AccessMode::READ,
+                                      FileStream::Disposition::OPEN_EXISTING,
+                                      nullptr);
+  ASSERT_NE(nullptr, stream);
+  FileFormField form_field{"test_file",
+                           std::move(stream),
+                           "sample.txt",
+                           content_disposition::kFormData,
+                           mime::text::kPlain,
+                           ""};
+  const char expected_header[] =
+      "Content-Disposition: form-data; name=\"test_file\";"
+      " filename=\"sample.txt\"\r\n"
+      "Content-Type: text/plain\r\n"
+      "\r\n";
+  EXPECT_EQ(expected_header, form_field.GetContentHeader());
+  EXPECT_EQ(file_content, GetFormFieldData(&form_field));
+}
+
+TEST(HttpFormData, MultiPartFormField) {
+  base::ScopedTempDir dir;
+  ASSERT_TRUE(dir.CreateUniqueTempDir());
+  std::string file1{"text line1\ntext line2\n"};
+  base::FilePath filename1 = dir.path().Append("sample.txt");
+  ASSERT_EQ(file1.size(),
+            static_cast<size_t>(
+                base::WriteFile(filename1, file1.data(), file1.size())));
+  std::string file2{"\x01\x02\x03\x04\x05"};
+  base::FilePath filename2 = dir.path().Append("test.bin");
+  ASSERT_EQ(file2.size(),
+            static_cast<size_t>(
+                base::WriteFile(filename2, file2.data(), file2.size())));
+
+  MultiPartFormField form_field{"foo", mime::multipart::kFormData, "Delimiter"};
+  form_field.AddTextField("name", "John Doe");
+  EXPECT_TRUE(form_field.AddFileField("file1",
+                                      filename1,
+                                      content_disposition::kFormData,
+                                      mime::text::kPlain,
+                                      nullptr));
+  EXPECT_TRUE(form_field.AddFileField("file2",
+                                      filename2,
+                                      content_disposition::kFormData,
+                                      mime::application::kOctet_stream,
+                                      nullptr));
+  const char expected_header[] =
+      "Content-Disposition: form-data; name=\"foo\"\r\n"
+      "Content-Type: multipart/form-data; boundary=\"Delimiter\"\r\n"
+      "\r\n";
+  EXPECT_EQ(expected_header, form_field.GetContentHeader());
+  const char expected_data[] =
+      "--Delimiter\r\n"
+      "Content-Disposition: form-data; name=\"name\"\r\n"
+      "\r\n"
+      "John Doe\r\n"
+      "--Delimiter\r\n"
+      "Content-Disposition: form-data; name=\"file1\";"
+      " filename=\"sample.txt\"\r\n"
+      "Content-Type: text/plain\r\n"
+      "Content-Transfer-Encoding: binary\r\n"
+      "\r\n"
+      "text line1\ntext line2\n\r\n"
+      "--Delimiter\r\n"
+      "Content-Disposition: form-data; name=\"file2\";"
+      " filename=\"test.bin\"\r\n"
+      "Content-Type: application/octet-stream\r\n"
+      "Content-Transfer-Encoding: binary\r\n"
+      "\r\n"
+      "\x01\x02\x03\x04\x05\r\n"
+      "--Delimiter--";
+  EXPECT_EQ(expected_data, GetFormFieldData(&form_field));
+}
+
+TEST(HttpFormData, MultiPartBoundary) {
+  const int count = 10;
+  std::set<std::string> boundaries;
+  for (int i = 0; i < count; i++) {
+    MultiPartFormField field{""};
+    std::string boundary = field.GetBoundary();
+    boundaries.insert(boundary);
+    // Our generated boundary must be 16 character long and contain lowercase
+    // hexadecimal digits only.
+    EXPECT_EQ(16u, boundary.size());
+    EXPECT_EQ(std::string::npos,
+              boundary.find_first_not_of("0123456789abcdef"));
+  }
+  // Now make sure the boundary strings were generated at random, so we should
+  // get |count| unique boundary strings. However since the strings are random,
+  // there is a very slim change of generating the same string twice, so
+  // expect at least 90% of unique strings. 90% is picked arbitrarily here.
+  int expected_min_unique = count * 9 / 10;
+  EXPECT_GE(boundaries.size(), expected_min_unique);
+}
+
+TEST(HttpFormData, FormData) {
+  base::ScopedTempDir dir;
+  ASSERT_TRUE(dir.CreateUniqueTempDir());
+  std::string file1{"text line1\ntext line2\n"};
+  base::FilePath filename1 = dir.path().Append("sample.txt");
+  ASSERT_EQ(file1.size(),
+            static_cast<size_t>(
+                base::WriteFile(filename1, file1.data(), file1.size())));
+  std::string file2{"\x01\x02\x03\x04\x05"};
+  base::FilePath filename2 = dir.path().Append("test.bin");
+  ASSERT_EQ(file2.size(),
+            static_cast<size_t>(
+                base::WriteFile(filename2, file2.data(), file2.size())));
+
+  FormData form_data{"boundary1"};
+  form_data.AddTextField("name", "John Doe");
+  std::unique_ptr<MultiPartFormField> files{
+      new MultiPartFormField{"files", "", "boundary2"}};
+  EXPECT_TRUE(files->AddFileField(
+      "", filename1, content_disposition::kFile, mime::text::kPlain, nullptr));
+  EXPECT_TRUE(files->AddFileField("",
+                                  filename2,
+                                  content_disposition::kFile,
+                                  mime::application::kOctet_stream,
+                                  nullptr));
+  form_data.AddCustomField(std::move(files));
+  EXPECT_EQ("multipart/form-data; boundary=\"boundary1\"",
+            form_data.GetContentType());
+
+  StreamPtr stream = form_data.ExtractDataStream();
+  std::vector<uint8_t> data(stream->GetSize());
+  EXPECT_TRUE(stream->ReadAllBlocking(data.data(), data.size(), nullptr));
+  const char expected_data[] =
+      "--boundary1\r\n"
+      "Content-Disposition: form-data; name=\"name\"\r\n"
+      "\r\n"
+      "John Doe\r\n"
+      "--boundary1\r\n"
+      "Content-Disposition: form-data; name=\"files\"\r\n"
+      "Content-Type: multipart/mixed; boundary=\"boundary2\"\r\n"
+      "\r\n"
+      "--boundary2\r\n"
+      "Content-Disposition: file; filename=\"sample.txt\"\r\n"
+      "Content-Type: text/plain\r\n"
+      "Content-Transfer-Encoding: binary\r\n"
+      "\r\n"
+      "text line1\ntext line2\n\r\n"
+      "--boundary2\r\n"
+      "Content-Disposition: file; filename=\"test.bin\"\r\n"
+      "Content-Type: application/octet-stream\r\n"
+      "Content-Transfer-Encoding: binary\r\n"
+      "\r\n"
+      "\x01\x02\x03\x04\x05\r\n"
+      "--boundary2--\r\n"
+      "--boundary1--";
+  EXPECT_EQ(expected_data, (std::string{data.begin(), data.end()}));
+}
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/http_request.cc b/libbrillo/brillo/http/http_request.cc
new file mode 100644
index 0000000..2784b8e
--- /dev/null
+++ b/libbrillo/brillo/http/http_request.cc
@@ -0,0 +1,357 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/http_request.h>
+
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/logging.h>
+#include <brillo/http/http_form_data.h>
+#include <brillo/map_utils.h>
+#include <brillo/mime_utils.h>
+#include <brillo/streams/memory_stream.h>
+#include <brillo/strings/string_utils.h>
+
+namespace brillo {
+namespace http {
+
+// request_type
+const char request_type::kOptions[]               = "OPTIONS";
+const char request_type::kGet[]                   = "GET";
+const char request_type::kHead[]                  = "HEAD";
+const char request_type::kPost[]                  = "POST";
+const char request_type::kPut[]                   = "PUT";
+const char request_type::kPatch[]                 = "PATCH";
+const char request_type::kDelete[]                = "DELETE";
+const char request_type::kTrace[]                 = "TRACE";
+const char request_type::kConnect[]               = "CONNECT";
+const char request_type::kCopy[]                  = "COPY";
+const char request_type::kMove[]                  = "MOVE";
+
+// request_header
+const char request_header::kAccept[]              = "Accept";
+const char request_header::kAcceptCharset[]       = "Accept-Charset";
+const char request_header::kAcceptEncoding[]      = "Accept-Encoding";
+const char request_header::kAcceptLanguage[]      = "Accept-Language";
+const char request_header::kAllow[]               = "Allow";
+const char request_header::kAuthorization[]       = "Authorization";
+const char request_header::kCacheControl[]        = "Cache-Control";
+const char request_header::kConnection[]          = "Connection";
+const char request_header::kContentEncoding[]     = "Content-Encoding";
+const char request_header::kContentLanguage[]     = "Content-Language";
+const char request_header::kContentLength[]       = "Content-Length";
+const char request_header::kContentLocation[]     = "Content-Location";
+const char request_header::kContentMd5[]          = "Content-MD5";
+const char request_header::kContentRange[]        = "Content-Range";
+const char request_header::kContentType[]         = "Content-Type";
+const char request_header::kCookie[]              = "Cookie";
+const char request_header::kDate[]                = "Date";
+const char request_header::kExpect[]              = "Expect";
+const char request_header::kExpires[]             = "Expires";
+const char request_header::kFrom[]                = "From";
+const char request_header::kHost[]                = "Host";
+const char request_header::kIfMatch[]             = "If-Match";
+const char request_header::kIfModifiedSince[]     = "If-Modified-Since";
+const char request_header::kIfNoneMatch[]         = "If-None-Match";
+const char request_header::kIfRange[]             = "If-Range";
+const char request_header::kIfUnmodifiedSince[]   = "If-Unmodified-Since";
+const char request_header::kLastModified[]        = "Last-Modified";
+const char request_header::kMaxForwards[]         = "Max-Forwards";
+const char request_header::kPragma[]              = "Pragma";
+const char request_header::kProxyAuthorization[]  = "Proxy-Authorization";
+const char request_header::kRange[]               = "Range";
+const char request_header::kReferer[]             = "Referer";
+const char request_header::kTE[]                  = "TE";
+const char request_header::kTrailer[]             = "Trailer";
+const char request_header::kTransferEncoding[]    = "Transfer-Encoding";
+const char request_header::kUpgrade[]             = "Upgrade";
+const char request_header::kUserAgent[]           = "User-Agent";
+const char request_header::kVia[]                 = "Via";
+const char request_header::kWarning[]             = "Warning";
+
+// response_header
+const char response_header::kAcceptRanges[]       = "Accept-Ranges";
+const char response_header::kAge[]                = "Age";
+const char response_header::kAllow[]              = "Allow";
+const char response_header::kCacheControl[]       = "Cache-Control";
+const char response_header::kConnection[]         = "Connection";
+const char response_header::kContentEncoding[]    = "Content-Encoding";
+const char response_header::kContentLanguage[]    = "Content-Language";
+const char response_header::kContentLength[]      = "Content-Length";
+const char response_header::kContentLocation[]    = "Content-Location";
+const char response_header::kContentMd5[]         = "Content-MD5";
+const char response_header::kContentRange[]       = "Content-Range";
+const char response_header::kContentType[]        = "Content-Type";
+const char response_header::kDate[]               = "Date";
+const char response_header::kETag[]               = "ETag";
+const char response_header::kExpires[]            = "Expires";
+const char response_header::kLastModified[]       = "Last-Modified";
+const char response_header::kLocation[]           = "Location";
+const char response_header::kPragma[]             = "Pragma";
+const char response_header::kProxyAuthenticate[]  = "Proxy-Authenticate";
+const char response_header::kRetryAfter[]         = "Retry-After";
+const char response_header::kServer[]             = "Server";
+const char response_header::kSetCookie[]          = "Set-Cookie";
+const char response_header::kTrailer[]            = "Trailer";
+const char response_header::kTransferEncoding[]   = "Transfer-Encoding";
+const char response_header::kUpgrade[]            = "Upgrade";
+const char response_header::kVary[]               = "Vary";
+const char response_header::kVia[]                = "Via";
+const char response_header::kWarning[]            = "Warning";
+const char response_header::kWwwAuthenticate[]    = "WWW-Authenticate";
+
+// ***********************************************************
+// ********************** Request Class **********************
+// ***********************************************************
+Request::Request(const std::string& url,
+                 const std::string& method,
+                 std::shared_ptr<Transport> transport)
+    : transport_(transport), request_url_(url), method_(method) {
+  VLOG(1) << "http::Request created";
+  if (!transport_)
+    transport_ = http::Transport::CreateDefault();
+}
+
+Request::~Request() {
+  VLOG(1) << "http::Request destroyed";
+}
+
+void Request::AddRange(int64_t bytes) {
+  DCHECK(transport_) << "Request already sent";
+  if (bytes < 0) {
+    ranges_.emplace_back(Request::range_value_omitted, -bytes);
+  } else {
+    ranges_.emplace_back(bytes, Request::range_value_omitted);
+  }
+}
+
+void Request::AddRange(uint64_t from_byte, uint64_t to_byte) {
+  DCHECK(transport_) << "Request already sent";
+  ranges_.emplace_back(from_byte, to_byte);
+}
+
+std::unique_ptr<Response> Request::GetResponseAndBlock(
+    brillo::ErrorPtr* error) {
+  if (!SendRequestIfNeeded(error) || !connection_->FinishRequest(error))
+    return std::unique_ptr<Response>();
+  std::unique_ptr<Response> response(new Response(connection_));
+  connection_.reset();
+  transport_.reset();  // Indicate that the response has been received
+  return response;
+}
+
+RequestID Request::GetResponse(const SuccessCallback& success_callback,
+                               const ErrorCallback& error_callback) {
+  ErrorPtr error;
+  if (!SendRequestIfNeeded(&error)) {
+    transport_->RunCallbackAsync(
+        FROM_HERE, base::Bind(error_callback, 0, base::Owned(error.release())));
+    return 0;
+  }
+  RequestID id =
+      connection_->FinishRequestAsync(success_callback, error_callback);
+  connection_.reset();
+  transport_.reset();  // Indicate that the request has been dispatched.
+  return id;
+}
+
+void Request::SetAccept(const std::string& accept_mime_types) {
+  DCHECK(transport_) << "Request already sent";
+  accept_ = accept_mime_types;
+}
+
+const std::string& Request::GetAccept() const {
+  return accept_;
+}
+
+void Request::SetContentType(const std::string& contentType) {
+  DCHECK(transport_) << "Request already sent";
+  content_type_ = contentType;
+}
+
+const std::string& Request::GetContentType() const {
+  return content_type_;
+}
+
+void Request::AddHeader(const std::string& header, const std::string& value) {
+  DCHECK(transport_) << "Request already sent";
+  headers_.emplace(header, value);
+}
+
+void Request::AddHeaders(const HeaderList& headers) {
+  DCHECK(transport_) << "Request already sent";
+  headers_.insert(headers.begin(), headers.end());
+}
+
+bool Request::AddRequestBody(const void* data,
+                             size_t size,
+                             brillo::ErrorPtr* error) {
+  if (!SendRequestIfNeeded(error))
+    return false;
+  StreamPtr stream = MemoryStream::OpenCopyOf(data, size, error);
+  return stream && connection_->SetRequestData(std::move(stream), error);
+}
+
+bool Request::AddRequestBody(StreamPtr stream, brillo::ErrorPtr* error) {
+  return SendRequestIfNeeded(error) &&
+         connection_->SetRequestData(std::move(stream), error);
+}
+
+bool Request::AddRequestBodyAsFormData(std::unique_ptr<FormData> form_data,
+                                       brillo::ErrorPtr* error) {
+  AddHeader(request_header::kContentType, form_data->GetContentType());
+  if (!SendRequestIfNeeded(error))
+    return false;
+  return connection_->SetRequestData(form_data->ExtractDataStream(), error);
+}
+
+bool Request::AddResponseStream(StreamPtr stream, brillo::ErrorPtr* error) {
+  if (!SendRequestIfNeeded(error))
+    return false;
+  connection_->SetResponseData(std::move(stream));
+  return true;
+}
+
+const std::string& Request::GetRequestURL() const {
+  return request_url_;
+}
+
+const std::string& Request::GetRequestMethod() const {
+  return method_;
+}
+
+void Request::SetReferer(const std::string& referer) {
+  DCHECK(transport_) << "Request already sent";
+  referer_ = referer;
+}
+
+const std::string& Request::GetReferer() const {
+  return referer_;
+}
+
+void Request::SetUserAgent(const std::string& user_agent) {
+  DCHECK(transport_) << "Request already sent";
+  user_agent_ = user_agent;
+}
+
+const std::string& Request::GetUserAgent() const {
+  return user_agent_;
+}
+
+bool Request::SendRequestIfNeeded(brillo::ErrorPtr* error) {
+  if (transport_) {
+    if (!connection_) {
+      http::HeaderList headers = brillo::MapToVector(headers_);
+      std::vector<std::string> ranges;
+      if (method_ != request_type::kHead) {
+        ranges.reserve(ranges_.size());
+        for (auto p : ranges_) {
+          if (p.first != range_value_omitted ||
+              p.second != range_value_omitted) {
+            std::string range;
+            if (p.first != range_value_omitted) {
+              range = brillo::string_utils::ToString(p.first);
+            }
+            range += '-';
+            if (p.second != range_value_omitted) {
+              range += brillo::string_utils::ToString(p.second);
+            }
+            ranges.push_back(range);
+          }
+        }
+      }
+      if (!ranges.empty())
+        headers.emplace_back(
+            request_header::kRange,
+            "bytes=" + brillo::string_utils::Join(",", ranges));
+
+      headers.emplace_back(request_header::kAccept, GetAccept());
+      if (method_ != request_type::kGet && method_ != request_type::kHead) {
+        if (!content_type_.empty())
+          headers.emplace_back(request_header::kContentType, content_type_);
+      }
+      connection_ = transport_->CreateConnection(
+          request_url_, method_, headers, user_agent_, referer_, error);
+    }
+
+    if (connection_)
+      return true;
+  } else {
+    brillo::Error::AddTo(error,
+                           FROM_HERE,
+                           http::kErrorDomain,
+                           "response_already_received",
+                           "HTTP response already received");
+  }
+  return false;
+}
+
+// ************************************************************
+// ********************** Response Class **********************
+// ************************************************************
+Response::Response(const std::shared_ptr<Connection>& connection)
+    : connection_{connection} {
+  VLOG(1) << "http::Response created";
+}
+
+Response::~Response() {
+  VLOG(1) << "http::Response destroyed";
+}
+
+bool Response::IsSuccessful() const {
+  int code = GetStatusCode();
+  return code >= status_code::Continue && code < status_code::BadRequest;
+}
+
+int Response::GetStatusCode() const {
+  if (!connection_)
+    return -1;
+
+  return connection_->GetResponseStatusCode();
+}
+
+std::string Response::GetStatusText() const {
+  if (!connection_)
+    return std::string();
+
+  return connection_->GetResponseStatusText();
+}
+
+std::string Response::GetContentType() const {
+  return GetHeader(response_header::kContentType);
+}
+
+StreamPtr Response::ExtractDataStream(ErrorPtr* error) {
+  return connection_->ExtractDataStream(error);
+}
+
+std::vector<uint8_t> Response::ExtractData() {
+  std::vector<uint8_t> data;
+  StreamPtr src_stream = connection_->ExtractDataStream(nullptr);
+  StreamPtr dest_stream = MemoryStream::CreateRef(&data, nullptr);
+  if (src_stream && dest_stream) {
+    char buffer[1024];
+    size_t read = 0;
+    while (src_stream->ReadBlocking(buffer, sizeof(buffer), &read, nullptr) &&
+           read > 0) {
+      CHECK(dest_stream->WriteAllBlocking(buffer, read, nullptr));
+    }
+  }
+  return data;
+}
+
+std::string Response::ExtractDataAsString() {
+  std::vector<uint8_t> data = ExtractData();
+  return std::string{data.begin(), data.end()};
+}
+
+std::string Response::GetHeader(const std::string& header_name) const {
+  if (connection_)
+    return connection_->GetResponseHeader(header_name);
+
+  return std::string();
+}
+
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/http_request.h b/libbrillo/brillo/http/http_request.h
new file mode 100644
index 0000000..42d8048
--- /dev/null
+++ b/libbrillo/brillo/http/http_request.h
@@ -0,0 +1,381 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_HTTP_REQUEST_H_
+#define LIBBRILLO_BRILLO_HTTP_HTTP_REQUEST_H_
+
+#include <limits>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+#include <brillo/errors/error.h>
+#include <brillo/http/http_connection.h>
+#include <brillo/http/http_transport.h>
+
+namespace brillo {
+namespace http {
+
+// HTTP request verbs
+namespace request_type {
+BRILLO_EXPORT extern const char kOptions[];
+BRILLO_EXPORT extern const char kGet[];
+BRILLO_EXPORT extern const char kHead[];
+BRILLO_EXPORT extern const char kPost[];
+BRILLO_EXPORT extern const char kPut[];
+BRILLO_EXPORT extern const char kPatch[];  // Non-standard HTTP/1.1 verb
+BRILLO_EXPORT extern const char kDelete[];
+BRILLO_EXPORT extern const char kTrace[];
+BRILLO_EXPORT extern const char kConnect[];
+BRILLO_EXPORT extern const char kCopy[];   // Non-standard HTTP/1.1 verb
+BRILLO_EXPORT extern const char kMove[];   // Non-standard HTTP/1.1 verb
+}  // namespace request_type
+
+// HTTP request header names
+namespace request_header {
+BRILLO_EXPORT extern const char kAccept[];
+BRILLO_EXPORT extern const char kAcceptCharset[];
+BRILLO_EXPORT extern const char kAcceptEncoding[];
+BRILLO_EXPORT extern const char kAcceptLanguage[];
+BRILLO_EXPORT extern const char kAllow[];
+BRILLO_EXPORT extern const char kAuthorization[];
+BRILLO_EXPORT extern const char kCacheControl[];
+BRILLO_EXPORT extern const char kConnection[];
+BRILLO_EXPORT extern const char kContentEncoding[];
+BRILLO_EXPORT extern const char kContentLanguage[];
+BRILLO_EXPORT extern const char kContentLength[];
+BRILLO_EXPORT extern const char kContentLocation[];
+BRILLO_EXPORT extern const char kContentMd5[];
+BRILLO_EXPORT extern const char kContentRange[];
+BRILLO_EXPORT extern const char kContentType[];
+BRILLO_EXPORT extern const char kCookie[];
+BRILLO_EXPORT extern const char kDate[];
+BRILLO_EXPORT extern const char kExpect[];
+BRILLO_EXPORT extern const char kExpires[];
+BRILLO_EXPORT extern const char kFrom[];
+BRILLO_EXPORT extern const char kHost[];
+BRILLO_EXPORT extern const char kIfMatch[];
+BRILLO_EXPORT extern const char kIfModifiedSince[];
+BRILLO_EXPORT extern const char kIfNoneMatch[];
+BRILLO_EXPORT extern const char kIfRange[];
+BRILLO_EXPORT extern const char kIfUnmodifiedSince[];
+BRILLO_EXPORT extern const char kLastModified[];
+BRILLO_EXPORT extern const char kMaxForwards[];
+BRILLO_EXPORT extern const char kPragma[];
+BRILLO_EXPORT extern const char kProxyAuthorization[];
+BRILLO_EXPORT extern const char kRange[];
+BRILLO_EXPORT extern const char kReferer[];
+BRILLO_EXPORT extern const char kTE[];
+BRILLO_EXPORT extern const char kTrailer[];
+BRILLO_EXPORT extern const char kTransferEncoding[];
+BRILLO_EXPORT extern const char kUpgrade[];
+BRILLO_EXPORT extern const char kUserAgent[];
+BRILLO_EXPORT extern const char kVia[];
+BRILLO_EXPORT extern const char kWarning[];
+}  // namespace request_header
+
+// HTTP response header names
+namespace response_header {
+BRILLO_EXPORT extern const char kAcceptRanges[];
+BRILLO_EXPORT extern const char kAge[];
+BRILLO_EXPORT extern const char kAllow[];
+BRILLO_EXPORT extern const char kCacheControl[];
+BRILLO_EXPORT extern const char kConnection[];
+BRILLO_EXPORT extern const char kContentEncoding[];
+BRILLO_EXPORT extern const char kContentLanguage[];
+BRILLO_EXPORT extern const char kContentLength[];
+BRILLO_EXPORT extern const char kContentLocation[];
+BRILLO_EXPORT extern const char kContentMd5[];
+BRILLO_EXPORT extern const char kContentRange[];
+BRILLO_EXPORT extern const char kContentType[];
+BRILLO_EXPORT extern const char kDate[];
+BRILLO_EXPORT extern const char kETag[];
+BRILLO_EXPORT extern const char kExpires[];
+BRILLO_EXPORT extern const char kLastModified[];
+BRILLO_EXPORT extern const char kLocation[];
+BRILLO_EXPORT extern const char kPragma[];
+BRILLO_EXPORT extern const char kProxyAuthenticate[];
+BRILLO_EXPORT extern const char kRetryAfter[];
+BRILLO_EXPORT extern const char kServer[];
+BRILLO_EXPORT extern const char kSetCookie[];
+BRILLO_EXPORT extern const char kTrailer[];
+BRILLO_EXPORT extern const char kTransferEncoding[];
+BRILLO_EXPORT extern const char kUpgrade[];
+BRILLO_EXPORT extern const char kVary[];
+BRILLO_EXPORT extern const char kVia[];
+BRILLO_EXPORT extern const char kWarning[];
+BRILLO_EXPORT extern const char kWwwAuthenticate[];
+}  // namespace response_header
+
+// HTTP request status (error) codes
+namespace status_code {
+// OK to continue with request
+static const int Continue = 100;
+// Server has switched protocols in upgrade header
+static const int SwitchProtocols = 101;
+
+// Request completed
+static const int Ok = 200;
+// Object created, reason = new URI
+static const int Created = 201;
+// Async completion (TBS)
+static const int Accepted = 202;
+// Partial completion
+static const int Partial = 203;
+// No info to return
+static const int NoContent = 204;
+// Request completed, but clear form
+static const int ResetContent = 205;
+// Partial GET fulfilled
+static const int PartialContent = 206;
+
+// Server couldn't decide what to return
+static const int Ambiguous = 300;
+// Object permanently moved
+static const int Moved = 301;
+// Object temporarily moved
+static const int Redirect = 302;
+// Redirection w/ new access method
+static const int RedirectMethod = 303;
+// If-Modified-Since was not modified
+static const int NotModified = 304;
+// Redirection to proxy, location header specifies proxy to use
+static const int UseProxy = 305;
+// HTTP/1.1: keep same verb
+static const int RedirectKeepVerb = 307;
+
+// Invalid syntax
+static const int BadRequest = 400;
+// Access denied
+static const int Denied = 401;
+// Payment required
+static const int PaymentRequired = 402;
+// Request forbidden
+static const int Forbidden = 403;
+// Object not found
+static const int NotFound = 404;
+// Method is not allowed
+static const int BadMethod = 405;
+// No response acceptable to client found
+static const int NoneAcceptable = 406;
+// Proxy authentication required
+static const int ProxyAuthRequired = 407;
+// Server timed out waiting for request
+static const int RequestTimeout = 408;
+// User should resubmit with more info
+static const int Conflict = 409;
+// The resource is no longer available
+static const int Gone = 410;
+// The server refused to accept request w/o a length
+static const int LengthRequired = 411;
+// Precondition given in request failed
+static const int PrecondionFailed = 412;
+// Request entity was too large
+static const int RequestTooLarge = 413;
+// Request URI too long
+static const int UriTooLong = 414;
+// Unsupported media type
+static const int UnsupportedMedia = 415;
+// Retry after doing the appropriate action.
+static const int RetryWith = 449;
+
+// Internal server error
+static const int InternalServerError = 500;
+// Request not supported
+static const int NotSupported = 501;
+// Error response received from gateway
+static const int BadGateway = 502;
+// Temporarily overloaded
+static const int ServiceUnavailable = 503;
+// Timed out waiting for gateway
+static const int GatewayTimeout = 504;
+// HTTP version not supported
+static const int VersionNotSupported = 505;
+}  // namespace status_code
+
+class Response;  // Just a forward declaration.
+class FormData;
+
+///////////////////////////////////////////////////////////////////////////////
+// Request class is the main object used to set up and initiate an HTTP
+// communication session. It is used to specify the HTTP request method,
+// request URL and many optional parameters (such as HTTP headers, user agent,
+// referer URL and so on.
+//
+// Once everything is setup, GetResponse() method is used to send the request
+// and obtain the server response. The returned Response object can be
+// used to inspect the response code, HTTP headers and/or response body.
+///////////////////////////////////////////////////////////////////////////////
+class BRILLO_EXPORT Request final {
+ public:
+  // The main constructor. |url| specifies the remote host address/path
+  // to send the request to. |method| is the HTTP request verb and
+  // |transport| is the HTTP transport implementation for server communications.
+  Request(const std::string& url,
+          const std::string& method,
+          std::shared_ptr<Transport> transport);
+  ~Request();
+
+  // Gets/Sets "Accept:" header value. The default value is "*/*" if not set.
+  void SetAccept(const std::string& accept_mime_types);
+  const std::string& GetAccept() const;
+
+  // Gets/Sets "Content-Type:" header value
+  void SetContentType(const std::string& content_type);
+  const std::string& GetContentType() const;
+
+  // Adds additional HTTP request header
+  void AddHeader(const std::string& header, const std::string& value);
+  void AddHeaders(const HeaderList& headers);
+
+  // Removes HTTP request header
+  void RemoveHeader(const std::string& header);
+
+  // Adds a request body. This is not to be used with GET method
+  bool AddRequestBody(const void* data, size_t size, brillo::ErrorPtr* error);
+  bool AddRequestBody(StreamPtr stream, brillo::ErrorPtr* error);
+
+  // Adds a request body. This is not to be used with GET method.
+  // This method also sets the correct content-type of the request, including
+  // the multipart data boundary.
+  bool AddRequestBodyAsFormData(std::unique_ptr<FormData> form_data,
+                                brillo::ErrorPtr* error);
+
+  // Adds a stream for the response. Otherwise a MemoryStream will be used.
+  bool AddResponseStream(StreamPtr stream, brillo::ErrorPtr* error);
+
+  // Makes a request for a subrange of data. Specifies a partial range with
+  // either from beginning of the data to the specified offset (if |bytes| is
+  // negative) or from the specified offset to the end of data (if |bytes| is
+  // positive).
+  // All individual ranges will be sent as part of "Range:" HTTP request header.
+  void AddRange(int64_t bytes);
+
+  // Makes a request for a subrange of data. Specifies a full range with
+  // start and end bytes from the beginning of the requested data.
+  // All individual ranges will be sent as part of "Range:" HTTP request header.
+  void AddRange(uint64_t from_byte, uint64_t to_byte);
+
+  // Returns the request URL
+  const std::string& GetRequestURL() const;
+
+  // Returns the request verb.
+  const std::string& GetRequestMethod() const;
+
+  // Gets/Sets a request referer URL (sent as "Referer:" request header).
+  void SetReferer(const std::string& referer);
+  const std::string& GetReferer() const;
+
+  // Gets/Sets a user agent string (sent as "User-Agent:" request header).
+  void SetUserAgent(const std::string& user_agent);
+  const std::string& GetUserAgent() const;
+
+  // Sends the request to the server and blocks until the response is received,
+  // which is returned as the response object.
+  // In case the server couldn't be reached for whatever reason, returns
+  // empty unique_ptr (null). In such a case, the additional error information
+  // can be returned through the optional supplied |error| parameter.
+  std::unique_ptr<Response> GetResponseAndBlock(brillo::ErrorPtr* error);
+
+  // Sends out the request and invokes the |success_callback| when the response
+  // is received. In case of an error, the |error_callback| is invoked.
+  // Returns the ID of the asynchronous request created.
+  RequestID GetResponse(const SuccessCallback& success_callback,
+                        const ErrorCallback& error_callback);
+
+ private:
+  friend class HttpRequestTest;
+
+  // Helper function to create an http::Connection and send off request headers.
+  BRILLO_PRIVATE bool SendRequestIfNeeded(brillo::ErrorPtr* error);
+
+  // Implementation that provides particular HTTP transport.
+  std::shared_ptr<Transport> transport_;
+
+  // An established connection for adding request body. This connection
+  // is maintained by the request object after the headers have been
+  // sent and before the response is requested.
+  std::shared_ptr<Connection> connection_;
+
+  // Full request URL, such as "http://www.host.com/path/to/object"
+  const std::string request_url_;
+  // HTTP request verb, such as "GET", "POST", "PUT", ...
+  const std::string method_;
+
+  // Referrer URL, if any. Sent to the server via "Referer: " header.
+  std::string referer_;
+  // User agent string, if any. Sent to the server via "User-Agent: " header.
+  std::string user_agent_;
+  // Content type of the request body data.
+  // Sent to the server via "Content-Type: " header.
+  std::string content_type_;
+  // List of acceptable response data types.
+  // Sent to the server via "Accept: " header.
+  std::string accept_ = "*/*";
+
+  // List of optional request headers provided by the caller.
+  std::multimap<std::string, std::string> headers_;
+  // List of optional data ranges to request partial content from the server.
+  // Sent to the server as "Range: " header.
+  std::vector<std::pair<uint64_t, uint64_t>> ranges_;
+
+  // range_value_omitted is used in |ranges_| list to indicate omitted value.
+  // E.g. range (10,range_value_omitted) represents bytes from 10 to the end
+  // of the data stream.
+  const uint64_t range_value_omitted = std::numeric_limits<uint64_t>::max();
+
+  DISALLOW_COPY_AND_ASSIGN(Request);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Response class is returned from Request::GetResponse() and is a way
+// to get to response status, error codes, response HTTP headers and response
+// data (body) if available.
+///////////////////////////////////////////////////////////////////////////////
+class BRILLO_EXPORT Response final {
+ public:
+  explicit Response(const std::shared_ptr<Connection>& connection);
+  ~Response();
+
+  // Returns true if server returned a success code (status code below 400).
+  bool IsSuccessful() const;
+
+  // Returns the HTTP status code (e.g. 200 for success)
+  int GetStatusCode() const;
+
+  // Returns the status text (e.g. for error 403 it could be "NOT AUTHORIZED").
+  std::string GetStatusText() const;
+
+  // Returns the content type of the response data.
+  std::string GetContentType() const;
+
+  // Returns response data stream by transferring ownership of the data stream
+  // from Response class to the caller.
+  StreamPtr ExtractDataStream(ErrorPtr* error);
+
+  // Extracts the data from the underlying response data stream as a byte array.
+  std::vector<uint8_t> ExtractData();
+
+  // Extracts the data from the underlying response data stream as a string.
+  std::string ExtractDataAsString();
+
+  // Returns a value of a given response HTTP header.
+  std::string GetHeader(const std::string& header_name) const;
+
+ private:
+  friend class HttpRequestTest;
+
+  std::shared_ptr<Connection> connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(Response);
+};
+
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_HTTP_REQUEST_H_
diff --git a/libbrillo/brillo/http/http_request_unittest.cc b/libbrillo/brillo/http/http_request_unittest.cc
new file mode 100644
index 0000000..edf056b
--- /dev/null
+++ b/libbrillo/brillo/http/http_request_unittest.cc
@@ -0,0 +1,208 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/http_request.h>
+
+#include <string>
+
+#include <base/callback.h>
+#include <brillo/bind_lambda.h>
+#include <brillo/http/mock_connection.h>
+#include <brillo/http/mock_transport.h>
+#include <brillo/mime_utils.h>
+#include <brillo/streams/mock_stream.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::DoAll;
+using testing::Invoke;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Unused;
+using testing::WithArg;
+using testing::_;
+
+namespace brillo {
+namespace http {
+
+MATCHER_P(ContainsStringData, str, "") {
+  if (arg->GetSize() != str.size())
+    return false;
+
+  std::string data;
+  char buf[100];
+  size_t read = 0;
+  while (arg->ReadBlocking(buf, sizeof(buf), &read, nullptr) && read > 0) {
+    data.append(buf, read);
+  }
+  return data == str;
+}
+
+class HttpRequestTest : public testing::Test {
+ public:
+  void SetUp() override {
+    transport_ = std::make_shared<MockTransport>();
+    connection_ = std::make_shared<MockConnection>(transport_);
+  }
+
+  void TearDown() override {
+    // Having shared pointers to mock objects (some of methods in these tests
+    // return shared pointers to connection and transport) could cause the
+    // test expectations to hold on to the mock object without releasing them
+    // at the end of a test, causing Mock's object leak detection to erroneously
+    // detect mock object "leaks". Verify and clear the expectations manually
+    // and explicitly to ensure the shared pointer refcounters are not
+    // preventing the mocks to be destroyed at the end of each test.
+    testing::Mock::VerifyAndClearExpectations(connection_.get());
+    connection_.reset();
+    testing::Mock::VerifyAndClearExpectations(transport_.get());
+    transport_.reset();
+  }
+
+ protected:
+  std::shared_ptr<MockTransport> transport_;
+  std::shared_ptr<MockConnection> connection_;
+};
+
+TEST_F(HttpRequestTest, Defaults) {
+  Request request{"http://www.foo.bar", request_type::kPost, transport_};
+  EXPECT_TRUE(request.GetContentType().empty());
+  EXPECT_TRUE(request.GetReferer().empty());
+  EXPECT_TRUE(request.GetUserAgent().empty());
+  EXPECT_EQ("*/*", request.GetAccept());
+  EXPECT_EQ("http://www.foo.bar", request.GetRequestURL());
+  EXPECT_EQ(request_type::kPost, request.GetRequestMethod());
+
+  Request request2{"http://www.foo.bar/baz", request_type::kGet, transport_};
+  EXPECT_EQ("http://www.foo.bar/baz", request2.GetRequestURL());
+  EXPECT_EQ(request_type::kGet, request2.GetRequestMethod());
+}
+
+TEST_F(HttpRequestTest, ContentType) {
+  Request request{"http://www.foo.bar", request_type::kPost, transport_};
+  request.SetContentType(mime::image::kJpeg);
+  EXPECT_EQ(mime::image::kJpeg, request.GetContentType());
+}
+
+TEST_F(HttpRequestTest, Referer) {
+  Request request{"http://www.foo.bar", request_type::kPost, transport_};
+  request.SetReferer("http://www.foo.bar/baz");
+  EXPECT_EQ("http://www.foo.bar/baz", request.GetReferer());
+}
+
+TEST_F(HttpRequestTest, UserAgent) {
+  Request request{"http://www.foo.bar", request_type::kPost, transport_};
+  request.SetUserAgent("FooBar Browser");
+  EXPECT_EQ("FooBar Browser", request.GetUserAgent());
+}
+
+TEST_F(HttpRequestTest, Accept) {
+  Request request{"http://www.foo.bar", request_type::kPost, transport_};
+  request.SetAccept("text/*, text/html, text/html;level=1, */*");
+  EXPECT_EQ("text/*, text/html, text/html;level=1, */*", request.GetAccept());
+}
+
+TEST_F(HttpRequestTest, GetResponseAndBlock) {
+  Request request{"http://www.foo.bar", request_type::kPost, transport_};
+  request.SetUserAgent("FooBar Browser");
+  request.SetReferer("http://www.foo.bar/baz");
+  request.SetAccept("text/*, text/html, text/html;level=1, */*");
+  request.AddHeader(request_header::kAcceptEncoding, "compress, gzip");
+  request.AddHeaders({
+      {request_header::kAcceptLanguage, "da, en-gb;q=0.8, en;q=0.7"},
+      {request_header::kConnection, "close"},
+  });
+  request.AddRange(-10);
+  request.AddRange(100, 200);
+  request.AddRange(300);
+  std::string req_body{"Foo bar baz"};
+  request.AddHeader(request_header::kContentType, mime::text::kPlain);
+
+  EXPECT_CALL(*transport_, CreateConnection(
+      "http://www.foo.bar",
+      request_type::kPost,
+      HeaderList{
+        {request_header::kAcceptEncoding, "compress, gzip"},
+        {request_header::kAcceptLanguage, "da, en-gb;q=0.8, en;q=0.7"},
+        {request_header::kConnection, "close"},
+        {request_header::kContentType, mime::text::kPlain},
+        {request_header::kRange, "bytes=-10,100-200,300-"},
+        {request_header::kAccept, "text/*, text/html, text/html;level=1, */*"},
+      },
+      "FooBar Browser",
+      "http://www.foo.bar/baz",
+      nullptr)).WillOnce(Return(connection_));
+
+  EXPECT_CALL(*connection_, MockSetRequestData(ContainsStringData(req_body), _))
+      .WillOnce(Return(true));
+
+  EXPECT_TRUE(
+      request.AddRequestBody(req_body.data(), req_body.size(), nullptr));
+
+  EXPECT_CALL(*connection_, FinishRequest(_)).WillOnce(Return(true));
+  auto resp = request.GetResponseAndBlock(nullptr);
+  EXPECT_NE(nullptr, resp.get());
+}
+
+TEST_F(HttpRequestTest, GetResponse) {
+  Request request{"http://foo.bar", request_type::kGet, transport_};
+
+  std::string resp_data{"FooBar response body"};
+  auto read_data =
+      [&resp_data](void* buffer, Unused, size_t* read, Unused) -> bool {
+    memcpy(buffer, resp_data.data(), resp_data.size());
+    *read = resp_data.size();
+    return true;
+  };
+
+  auto success_callback = [](decltype(this) test,
+                             const std::string& resp_data,
+                             RequestID request_id,
+                             std::unique_ptr<Response> resp) {
+    EXPECT_EQ(23, request_id);
+    EXPECT_CALL(*test->connection_, GetResponseStatusCode())
+        .WillOnce(Return(status_code::Partial));
+    EXPECT_EQ(status_code::Partial, resp->GetStatusCode());
+
+    EXPECT_CALL(*test->connection_, GetResponseStatusText())
+        .WillOnce(Return("Partial completion"));
+    EXPECT_EQ("Partial completion", resp->GetStatusText());
+
+    EXPECT_CALL(*test->connection_,
+                GetResponseHeader(response_header::kContentType))
+        .WillOnce(Return(mime::text::kHtml));
+    EXPECT_EQ(mime::text::kHtml, resp->GetContentType());
+
+    EXPECT_EQ(resp_data, resp->ExtractDataAsString());
+  };
+
+  auto finish_request_async =
+      [this, &read_data, &resp_data](const SuccessCallback& success_callback) {
+    std::unique_ptr<MockStream> mock_stream{new MockStream};
+    EXPECT_CALL(*mock_stream, ReadBlocking(_, _, _, _))
+        .WillOnce(Invoke(read_data))
+        .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
+
+    EXPECT_CALL(*connection_, MockExtractDataStream(_))
+      .WillOnce(Return(mock_stream.release()));
+    std::unique_ptr<Response> resp{new Response{connection_}};
+    success_callback.Run(23, std::move(resp));
+  };
+
+  EXPECT_CALL(
+      *transport_,
+      CreateConnection("http://foo.bar", request_type::kGet, _, "", "", _))
+      .WillOnce(Return(connection_));
+
+  EXPECT_CALL(*connection_, FinishRequestAsync(_, _))
+      .WillOnce(DoAll(WithArg<0>(Invoke(finish_request_async)), Return(23)));
+
+  EXPECT_EQ(
+      23,
+      request.GetResponse(
+          base::Bind(success_callback, base::Unretained(this), resp_data), {}));
+}
+
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/http_transport.cc b/libbrillo/brillo/http/http_transport.cc
new file mode 100644
index 0000000..d77eabe
--- /dev/null
+++ b/libbrillo/brillo/http/http_transport.cc
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/http_transport.h>
+
+#include <brillo/http/http_transport_curl.h>
+
+namespace brillo {
+namespace http {
+
+const char kErrorDomain[] = "http_transport";
+
+std::shared_ptr<Transport> Transport::CreateDefault() {
+  return std::make_shared<http::curl::Transport>(std::make_shared<CurlApi>());
+}
+
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/http_transport.h b/libbrillo/brillo/http/http_transport.h
new file mode 100644
index 0000000..63e135c
--- /dev/null
+++ b/libbrillo/brillo/http/http_transport.h
@@ -0,0 +1,95 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_H_
+#define LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <base/callback_forward.h>
+#include <base/location.h>
+#include <base/macros.h>
+#include <base/time/time.h>
+#include <brillo/brillo_export.h>
+#include <brillo/errors/error.h>
+
+namespace brillo {
+namespace http {
+
+BRILLO_EXPORT extern const char kErrorDomain[];
+
+class Request;
+class Response;
+class Connection;
+
+using RequestID = int;
+
+using HeaderList = std::vector<std::pair<std::string, std::string>>;
+using SuccessCallback =
+    base::Callback<void(RequestID, std::unique_ptr<Response>)>;
+using ErrorCallback = base::Callback<void(RequestID, const brillo::Error*)>;
+
+///////////////////////////////////////////////////////////////////////////////
+// Transport is a base class for specific implementation of HTTP communication.
+// This class (and its underlying implementation) is used by http::Request and
+// http::Response classes to provide HTTP functionality to the clients.
+///////////////////////////////////////////////////////////////////////////////
+class BRILLO_EXPORT Transport : public std::enable_shared_from_this<Transport> {
+ public:
+  Transport() = default;
+  virtual ~Transport() = default;
+
+  // Creates a connection object and initializes it with the specified data.
+  // |transport| is a shared pointer to this transport object instance,
+  // used to maintain the object alive as long as the connection exists.
+  // The |url| here is the full URL specified in the request. It is passed
+  // to the underlying transport (e.g. CURL) to establish the connection.
+  virtual std::shared_ptr<Connection> CreateConnection(
+      const std::string& url,
+      const std::string& method,
+      const HeaderList& headers,
+      const std::string& user_agent,
+      const std::string& referer,
+      brillo::ErrorPtr* error) = 0;
+
+  // Runs |callback| on the task runner (message loop) associated with the
+  // transport. For transports that do not contain references to real message
+  // loops (e.g. a fake transport), calls the callback immediately.
+  virtual void RunCallbackAsync(const tracked_objects::Location& from_here,
+                                const base::Closure& callback) = 0;
+
+  // Initiates an asynchronous transfer on the given |connection|.
+  // The actual implementation of an async I/O is transport-specific.
+  // Returns a request ID which can be used to cancel the request.
+  virtual RequestID StartAsyncTransfer(
+      Connection* connection,
+      const SuccessCallback& success_callback,
+      const ErrorCallback& error_callback) = 0;
+
+  // Cancels a pending asynchronous request. This will cancel a pending request
+  // scheduled by the transport while the I/O operations are still in progress.
+  // As soon as all I/O completes for the request/response, or when an error
+  // occurs, the success/error callbacks are invoked and the request is
+  // considered complete and can no longer be canceled.
+  // Returns false if pending request with |request_id| is not found (e.g. it
+  // has already completed/its callbacks are dispatched).
+  virtual bool CancelRequest(RequestID request_id) = 0;
+
+  // Set the default timeout of requests made.
+  virtual void SetDefaultTimeout(base::TimeDelta timeout) = 0;
+
+  // Creates a default http::Transport (currently, using http::curl::Transport).
+  static std::shared_ptr<Transport> CreateDefault();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Transport);
+};
+
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_H_
diff --git a/libbrillo/brillo/http/http_transport_curl.cc b/libbrillo/brillo/http/http_transport_curl.cc
new file mode 100644
index 0000000..f7e3b71
--- /dev/null
+++ b/libbrillo/brillo/http/http_transport_curl.cc
@@ -0,0 +1,513 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/http_transport_curl.h>
+
+#include <limits>
+
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <brillo/http/http_connection_curl.h>
+#include <brillo/http/http_request.h>
+#include <brillo/strings/string_utils.h>
+
+namespace {
+
+const char kCACertificatePath[] =
+#ifdef __ANDROID__
+    "/system/etc/security/cacerts_google";
+#else
+    "/usr/share/brillo-ca-certificates";
+#endif
+
+}  // namespace
+
+namespace brillo {
+namespace http {
+namespace curl {
+
+// This is a class that stores connection data on particular CURL socket
+// and provides file descriptor watcher to monitor read and/or write operations
+// on the socket's file descriptor.
+class Transport::SocketPollData : public base::MessageLoopForIO::Watcher {
+ public:
+  SocketPollData(const std::shared_ptr<CurlInterface>& curl_interface,
+                 CURLM* curl_multi_handle,
+                 Transport* transport,
+                 curl_socket_t socket_fd)
+      : curl_interface_(curl_interface),
+        curl_multi_handle_(curl_multi_handle),
+        transport_(transport),
+        socket_fd_(socket_fd) {}
+
+  // Returns the pointer for the socket-specific file descriptor watcher.
+  base::MessageLoopForIO::FileDescriptorWatcher* GetWatcher() {
+    return &file_descriptor_watcher_;
+  }
+
+ private:
+  // Overrides from base::MessageLoopForIO::Watcher.
+  void OnFileCanReadWithoutBlocking(int fd) override {
+    OnSocketReady(fd, CURL_CSELECT_IN);
+  }
+  void OnFileCanWriteWithoutBlocking(int fd) override {
+    OnSocketReady(fd, CURL_CSELECT_OUT);
+  }
+
+  // Data on the socket is available to be read from or written to.
+  // Notify CURL of the action it needs to take on the socket file descriptor.
+  void OnSocketReady(int fd, int action) {
+    CHECK_EQ(socket_fd_, fd) << "Unexpected socket file descriptor";
+    int still_running_count = 0;
+    CURLMcode code = curl_interface_->MultiSocketAction(
+        curl_multi_handle_, socket_fd_, action, &still_running_count);
+    CHECK_NE(CURLM_CALL_MULTI_PERFORM, code)
+        << "CURL should no longer return CURLM_CALL_MULTI_PERFORM here";
+
+    if (code == CURLM_OK)
+      transport_->ProcessAsyncCurlMessages();
+  }
+
+  // The CURL interface to use.
+  std::shared_ptr<CurlInterface> curl_interface_;
+  // CURL multi-handle associated with the transport.
+  CURLM* curl_multi_handle_;
+  // Transport object itself.
+  Transport* transport_;
+  // The socket file descriptor for the connection.
+  curl_socket_t socket_fd_;
+  // File descriptor watcher to notify us of asynchronous I/O on the FD.
+  base::MessageLoopForIO::FileDescriptorWatcher file_descriptor_watcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(SocketPollData);
+};
+
+// The request data associated with an asynchronous operation on a particular
+// connection.
+struct Transport::AsyncRequestData {
+  // Success/error callbacks to be invoked at the end of the request.
+  SuccessCallback success_callback;
+  ErrorCallback error_callback;
+  // We store a connection here to make sure the object is alive for
+  // as long as asynchronous operation is running.
+  std::shared_ptr<Connection> connection;
+  // The ID of this request.
+  RequestID request_id;
+};
+
+Transport::Transport(const std::shared_ptr<CurlInterface>& curl_interface)
+    : curl_interface_{curl_interface} {
+  VLOG(2) << "curl::Transport created";
+}
+
+Transport::Transport(const std::shared_ptr<CurlInterface>& curl_interface,
+                     const std::string& proxy)
+    : curl_interface_{curl_interface}, proxy_{proxy} {
+  VLOG(2) << "curl::Transport created with proxy " << proxy;
+}
+
+Transport::~Transport() {
+  ShutDownAsyncCurl();
+  VLOG(2) << "curl::Transport destroyed";
+}
+
+std::shared_ptr<http::Connection> Transport::CreateConnection(
+    const std::string& url,
+    const std::string& method,
+    const HeaderList& headers,
+    const std::string& user_agent,
+    const std::string& referer,
+    brillo::ErrorPtr* error) {
+  std::shared_ptr<http::Connection> connection;
+  CURL* curl_handle = curl_interface_->EasyInit();
+  if (!curl_handle) {
+    LOG(ERROR) << "Failed to initialize CURL";
+    brillo::Error::AddTo(error, FROM_HERE, http::kErrorDomain,
+                         "curl_init_failed", "Failed to initialize CURL");
+    return connection;
+  }
+
+  LOG(INFO) << "Sending a " << method << " request to " << url;
+  CURLcode code = curl_interface_->EasySetOptStr(curl_handle, CURLOPT_URL, url);
+
+  if (code == CURLE_OK) {
+    code = curl_interface_->EasySetOptStr(curl_handle, CURLOPT_CAPATH,
+                                          kCACertificatePath);
+  }
+  if (code == CURLE_OK) {
+    code =
+        curl_interface_->EasySetOptInt(curl_handle, CURLOPT_SSL_VERIFYPEER, 1);
+  }
+  if (code == CURLE_OK) {
+    code =
+        curl_interface_->EasySetOptInt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2);
+  }
+  if (code == CURLE_OK && !user_agent.empty()) {
+    code = curl_interface_->EasySetOptStr(
+        curl_handle, CURLOPT_USERAGENT, user_agent);
+  }
+  if (code == CURLE_OK && !referer.empty()) {
+    code =
+        curl_interface_->EasySetOptStr(curl_handle, CURLOPT_REFERER, referer);
+  }
+  if (code == CURLE_OK && !proxy_.empty()) {
+    code = curl_interface_->EasySetOptStr(curl_handle, CURLOPT_PROXY, proxy_);
+  }
+  if (code == CURLE_OK) {
+    int64_t timeout_ms = connection_timeout_.InMillisecondsRoundedUp();
+
+    if (timeout_ms > 0 && timeout_ms <= std::numeric_limits<int>::max()) {
+      code = curl_interface_->EasySetOptInt(
+          curl_handle, CURLOPT_TIMEOUT_MS,
+          static_cast<int>(timeout_ms));
+    }
+  }
+
+  // Setup HTTP request method and optional request body.
+  if (code == CURLE_OK) {
+    if (method == request_type::kGet) {
+      code = curl_interface_->EasySetOptInt(curl_handle, CURLOPT_HTTPGET, 1);
+    } else if (method == request_type::kHead) {
+      code = curl_interface_->EasySetOptInt(curl_handle, CURLOPT_NOBODY, 1);
+    } else if (method == request_type::kPut) {
+      code = curl_interface_->EasySetOptInt(curl_handle, CURLOPT_UPLOAD, 1);
+    } else {
+      // POST and custom request methods
+      code = curl_interface_->EasySetOptInt(curl_handle, CURLOPT_POST, 1);
+      if (code == CURLE_OK) {
+        code = curl_interface_->EasySetOptPtr(
+            curl_handle, CURLOPT_POSTFIELDS, nullptr);
+      }
+      if (code == CURLE_OK && method != request_type::kPost) {
+        code = curl_interface_->EasySetOptStr(
+            curl_handle, CURLOPT_CUSTOMREQUEST, method);
+      }
+    }
+  }
+
+  if (code != CURLE_OK) {
+    AddEasyCurlError(error, FROM_HERE, code, curl_interface_.get());
+    curl_interface_->EasyCleanup(curl_handle);
+    return connection;
+  }
+
+  connection = std::make_shared<http::curl::Connection>(
+      curl_handle, method, curl_interface_, shared_from_this());
+  if (!connection->SendHeaders(headers, error)) {
+    connection.reset();
+  }
+  return connection;
+}
+
+void Transport::RunCallbackAsync(const tracked_objects::Location& from_here,
+                                 const base::Closure& callback) {
+  base::MessageLoopForIO::current()->PostTask(from_here, callback);
+}
+
+RequestID Transport::StartAsyncTransfer(http::Connection* connection,
+                                        const SuccessCallback& success_callback,
+                                        const ErrorCallback& error_callback) {
+  brillo::ErrorPtr error;
+  if (!SetupAsyncCurl(&error)) {
+    RunCallbackAsync(
+        FROM_HERE, base::Bind(error_callback, 0, base::Owned(error.release())));
+    return 0;
+  }
+
+  RequestID request_id = ++last_request_id_;
+
+  auto curl_connection = static_cast<http::curl::Connection*>(connection);
+  std::unique_ptr<AsyncRequestData> request_data{new AsyncRequestData};
+  // Add the request data to |async_requests_| before adding the CURL handle
+  // in case CURL feels like calling the socket callback synchronously which
+  // will need the data to be in |async_requests_| map already.
+  request_data->success_callback = success_callback;
+  request_data->error_callback = error_callback;
+  request_data->connection =
+      std::static_pointer_cast<Connection>(curl_connection->shared_from_this());
+  request_data->request_id = request_id;
+  async_requests_.emplace(curl_connection, std::move(request_data));
+  request_id_map_.emplace(request_id, curl_connection);
+
+  // Add the connection's CURL handle to the multi-handle.
+  CURLMcode code = curl_interface_->MultiAddHandle(
+      curl_multi_handle_, curl_connection->curl_handle_);
+  if (code != CURLM_OK) {
+    brillo::ErrorPtr error;
+    AddMultiCurlError(&error, FROM_HERE, code, curl_interface_.get());
+    RunCallbackAsync(
+        FROM_HERE, base::Bind(error_callback, 0, base::Owned(error.release())));
+    async_requests_.erase(curl_connection);
+    request_id_map_.erase(request_id);
+    return 0;
+  }
+  LOG(INFO) << "Started asynchronous HTTP request with ID " << request_id;
+  return request_id;
+}
+
+bool Transport::CancelRequest(RequestID request_id) {
+  auto p = request_id_map_.find(request_id);
+  if (p == request_id_map_.end()) {
+    // The request must have been completed already...
+    // This is not necessarily an error condition, so fail gracefully.
+    LOG(WARNING) << "HTTP request #" << request_id << " not found";
+    return false;
+  }
+  LOG(INFO) << "Canceling HTTP request #" << request_id;
+  CleanAsyncConnection(p->second);
+  return true;
+}
+
+void Transport::SetDefaultTimeout(base::TimeDelta timeout) {
+  connection_timeout_ = timeout;
+}
+
+void Transport::AddEasyCurlError(brillo::ErrorPtr* error,
+                                 const tracked_objects::Location& location,
+                                 CURLcode code,
+                                 CurlInterface* curl_interface) {
+  brillo::Error::AddTo(error, location, "curl_easy_error",
+                       brillo::string_utils::ToString(code),
+                       curl_interface->EasyStrError(code));
+}
+
+void Transport::AddMultiCurlError(brillo::ErrorPtr* error,
+                                  const tracked_objects::Location& location,
+                                  CURLMcode code,
+                                  CurlInterface* curl_interface) {
+  brillo::Error::AddTo(error, location, "curl_multi_error",
+                       brillo::string_utils::ToString(code),
+                       curl_interface->MultiStrError(code));
+}
+
+bool Transport::SetupAsyncCurl(brillo::ErrorPtr* error) {
+  if (curl_multi_handle_)
+    return true;
+
+  curl_multi_handle_ = curl_interface_->MultiInit();
+  if (!curl_multi_handle_) {
+    LOG(ERROR) << "Failed to initialize CURL";
+    brillo::Error::AddTo(error, FROM_HERE, http::kErrorDomain,
+                         "curl_init_failed", "Failed to initialize CURL");
+    return false;
+  }
+
+  CURLMcode code = curl_interface_->MultiSetSocketCallback(
+      curl_multi_handle_, &Transport::MultiSocketCallback, this);
+  if (code == CURLM_OK) {
+    code = curl_interface_->MultiSetTimerCallback(
+        curl_multi_handle_, &Transport::MultiTimerCallback, this);
+  }
+  if (code != CURLM_OK) {
+    AddMultiCurlError(error, FROM_HERE, code, curl_interface_.get());
+    return false;
+  }
+  return true;
+}
+
+void Transport::ShutDownAsyncCurl() {
+  if (!curl_multi_handle_)
+    return;
+  LOG_IF(WARNING, !poll_data_map_.empty())
+      << "There are pending requests at the time of transport's shutdown";
+  // Make sure we are not leaking any memory here.
+  for (const auto& pair : poll_data_map_)
+    delete pair.second;
+  poll_data_map_.clear();
+  curl_interface_->MultiCleanup(curl_multi_handle_);
+  curl_multi_handle_ = nullptr;
+}
+
+int Transport::MultiSocketCallback(CURL* easy,
+                                   curl_socket_t s,
+                                   int what,
+                                   void* userp,
+                                   void* socketp) {
+  auto transport = static_cast<Transport*>(userp);
+  CHECK(transport) << "Transport must be set for this callback";
+  auto poll_data = static_cast<SocketPollData*>(socketp);
+  if (!poll_data) {
+    // We haven't attached polling data to this socket yet. Let's do this now.
+    poll_data = new SocketPollData{transport->curl_interface_,
+                                   transport->curl_multi_handle_,
+                                   transport,
+                                   s};
+    transport->poll_data_map_.emplace(std::make_pair(easy, s), poll_data);
+    transport->curl_interface_->MultiAssign(
+        transport->curl_multi_handle_, s, poll_data);
+  }
+
+  if (what == CURL_POLL_NONE) {
+    return 0;
+  } else if (what == CURL_POLL_REMOVE) {
+    // Remove the attached data from the socket.
+    transport->curl_interface_->MultiAssign(
+        transport->curl_multi_handle_, s, nullptr);
+    transport->poll_data_map_.erase(std::make_pair(easy, s));
+
+    // Make sure we stop watching the socket file descriptor now, before
+    // we schedule the SocketPollData for deletion.
+    poll_data->GetWatcher()->StopWatchingFileDescriptor();
+    // This method can be called indirectly from SocketPollData::OnSocketReady,
+    // so delay destruction of SocketPollData object till the next loop cycle.
+    base::MessageLoopForIO::current()->DeleteSoon(FROM_HERE, poll_data);
+    return 0;
+  }
+
+  base::MessageLoopForIO::Mode watch_mode = base::MessageLoopForIO::WATCH_READ;
+  switch (what) {
+    case CURL_POLL_IN:
+      watch_mode = base::MessageLoopForIO::WATCH_READ;
+      break;
+    case CURL_POLL_OUT:
+      watch_mode = base::MessageLoopForIO::WATCH_WRITE;
+      break;
+    case CURL_POLL_INOUT:
+      watch_mode = base::MessageLoopForIO::WATCH_READ_WRITE;
+      break;
+    default:
+      LOG(FATAL) << "Unknown CURL socket action: " << what;
+      break;
+  }
+
+  // WatchFileDescriptor() can be called with the same controller object
+  // (watcher) to amend the watch mode, however this has cumulative effect.
+  // For example, if we were watching a file descriptor for READ operations
+  // and now call it to watch for WRITE, it will end up watching for both
+  // READ and WRITE. This is not what we want here, so stop watching the
+  // file descriptor on previous controller before starting with a different
+  // mode.
+  if (!poll_data->GetWatcher()->StopWatchingFileDescriptor())
+    LOG(WARNING) << "Failed to stop watching the previous socket descriptor";
+  CHECK(base::MessageLoopForIO::current()->WatchFileDescriptor(
+      s, true, watch_mode, poll_data->GetWatcher(), poll_data))
+      << "Failed to watch the CURL socket.";
+  return 0;
+}
+
+// CURL actually uses "long" types in callback signatures, so we must comply.
+int Transport::MultiTimerCallback(CURLM* /* multi */,
+                                  long timeout_ms,  // NOLINT(runtime/int)
+                                  void* userp) {
+  auto transport = static_cast<Transport*>(userp);
+  // Cancel any previous timer callbacks.
+  transport->weak_ptr_factory_for_timer_.InvalidateWeakPtrs();
+  if (timeout_ms >= 0) {
+    base::MessageLoopForIO::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&Transport::OnTimer,
+                 transport->weak_ptr_factory_for_timer_.GetWeakPtr()),
+      base::TimeDelta::FromMilliseconds(timeout_ms));
+  }
+  return 0;
+}
+
+void Transport::OnTimer() {
+  if (curl_multi_handle_) {
+    int still_running_count = 0;
+    curl_interface_->MultiSocketAction(
+        curl_multi_handle_, CURL_SOCKET_TIMEOUT, 0, &still_running_count);
+    ProcessAsyncCurlMessages();
+  }
+}
+
+void Transport::ProcessAsyncCurlMessages() {
+  CURLMsg* msg = nullptr;
+  int msgs_left = 0;
+  while ((msg = curl_interface_->MultiInfoRead(curl_multi_handle_,
+                                               &msgs_left))) {
+    if (msg->msg == CURLMSG_DONE) {
+      // Async I/O complete for a connection. Invoke the user callbacks.
+      Connection* connection = nullptr;
+      CHECK_EQ(CURLE_OK,
+               curl_interface_->EasyGetInfoPtr(
+                   msg->easy_handle,
+                   CURLINFO_PRIVATE,
+                   reinterpret_cast<void**>(&connection)));
+      CHECK(connection != nullptr);
+      OnTransferComplete(connection, msg->data.result);
+    }
+  }
+}
+
+void Transport::OnTransferComplete(Connection* connection, CURLcode code) {
+  auto p = async_requests_.find(connection);
+  CHECK(p != async_requests_.end()) << "Unknown connection";
+  AsyncRequestData* request_data = p->second.get();
+  LOG(INFO) << "HTTP request # " << request_data->request_id
+            << " has completed "
+            << (code == CURLE_OK ? "successfully" : "with an error");
+  if (code != CURLE_OK) {
+    brillo::ErrorPtr error;
+    AddEasyCurlError(&error, FROM_HERE, code, curl_interface_.get());
+    RunCallbackAsync(FROM_HERE,
+                     base::Bind(request_data->error_callback,
+                                p->second->request_id,
+                                base::Owned(error.release())));
+  } else {
+    LOG(INFO) << "Response: " << connection->GetResponseStatusCode() << " ("
+              << connection->GetResponseStatusText() << ")";
+    brillo::ErrorPtr error;
+    // Rewind the response data stream to the beginning so the clients can
+    // read the data back.
+    const auto& stream = request_data->connection->response_data_stream_;
+    if (stream && stream->CanSeek() && !stream->SetPosition(0, &error)) {
+      RunCallbackAsync(FROM_HERE,
+                       base::Bind(request_data->error_callback,
+                                  p->second->request_id,
+                                  base::Owned(error.release())));
+    } else {
+      std::unique_ptr<Response> resp{new Response{request_data->connection}};
+      RunCallbackAsync(FROM_HERE,
+                       base::Bind(request_data->success_callback,
+                                  p->second->request_id,
+                                  base::Passed(&resp)));
+    }
+  }
+  // In case of an error on CURL side, we would have dispatched the error
+  // callback and we need to clean up the current connection, however the
+  // error callback has no reference to the connection itself and
+  // |async_requests_| is the only reference to the shared pointer that
+  // maintains the lifetime of |connection| and possibly even this Transport
+  // object instance. As a result, if we call CleanAsyncConnection() directly,
+  // there is a chance that this object might be deleted.
+  // Instead, schedule an asynchronous task to clean up the connection.
+  RunCallbackAsync(FROM_HERE,
+                   base::Bind(&Transport::CleanAsyncConnection,
+                              weak_ptr_factory_.GetWeakPtr(),
+                              connection));
+}
+
+void Transport::CleanAsyncConnection(Connection* connection) {
+  auto p = async_requests_.find(connection);
+  CHECK(p != async_requests_.end()) << "Unknown connection";
+  // Remove the request data from the map first, since this might be the only
+  // reference to the Connection class and even possibly to this Transport.
+  auto request_data = std::move(p->second);
+
+  // Remove associated request ID.
+  request_id_map_.erase(request_data->request_id);
+
+  // Remove the connection's CURL handle from multi-handle.
+  curl_interface_->MultiRemoveHandle(curl_multi_handle_,
+                                     connection->curl_handle_);
+
+  // Remove all the socket data associated with this connection.
+  auto iter = poll_data_map_.begin();
+  while (iter != poll_data_map_.end()) {
+    if (iter->first.first == connection->curl_handle_)
+      iter = poll_data_map_.erase(iter);
+    else
+      ++iter;
+  }
+  // Remove pending asynchronous request data.
+  // This must be last since there is a chance of this object being
+  // destroyed as the result. See the comment in Transport::OnTransferComplete.
+  async_requests_.erase(p);
+}
+
+}  // namespace curl
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/http_transport_curl.h b/libbrillo/brillo/http/http_transport_curl.h
new file mode 100644
index 0000000..0a95c63
--- /dev/null
+++ b/libbrillo/brillo/http/http_transport_curl.h
@@ -0,0 +1,140 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_CURL_H_
+#define LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_CURL_H_
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include <base/memory/weak_ptr.h>
+#include <brillo/brillo_export.h>
+#include <brillo/http/curl_api.h>
+#include <brillo/http/http_transport.h>
+
+namespace brillo {
+namespace http {
+namespace curl {
+
+class Connection;
+
+///////////////////////////////////////////////////////////////////////////////
+// An implementation of http::Transport that uses libcurl for
+// HTTP communications. This class (as http::Transport base)
+// is used by http::Request and http::Response classes to provide HTTP
+// functionality to the clients.
+// See http_transport.h for more details.
+///////////////////////////////////////////////////////////////////////////////
+class BRILLO_EXPORT Transport : public http::Transport {
+ public:
+  // Constructs the transport using the current message loop for async
+  // operations.
+  explicit Transport(const std::shared_ptr<CurlInterface>& curl_interface);
+  // Creates a transport object using a proxy.
+  // |proxy| is of the form [protocol://][user:password@]host[:port].
+  // If not defined, protocol is assumed to be http://.
+  Transport(const std::shared_ptr<CurlInterface>& curl_interface,
+            const std::string& proxy);
+  ~Transport() override;
+
+  // Overrides from http::Transport.
+  std::shared_ptr<http::Connection> CreateConnection(
+      const std::string& url,
+      const std::string& method,
+      const HeaderList& headers,
+      const std::string& user_agent,
+      const std::string& referer,
+      brillo::ErrorPtr* error) override;
+
+  void RunCallbackAsync(const tracked_objects::Location& from_here,
+                        const base::Closure& callback) override;
+
+  RequestID StartAsyncTransfer(http::Connection* connection,
+                               const SuccessCallback& success_callback,
+                               const ErrorCallback& error_callback) override;
+
+  bool CancelRequest(RequestID request_id) override;
+
+  void SetDefaultTimeout(base::TimeDelta timeout) override;
+
+  // Helper methods to convert CURL error codes (CURLcode and CURLMcode)
+  // into brillo::Error object.
+  static void AddEasyCurlError(brillo::ErrorPtr* error,
+                               const tracked_objects::Location& location,
+                               CURLcode code,
+                               CurlInterface* curl_interface);
+
+  static void AddMultiCurlError(brillo::ErrorPtr* error,
+                                const tracked_objects::Location& location,
+                                CURLMcode code,
+                                CurlInterface* curl_interface);
+
+ private:
+  // Forward-declaration of internal implementation structures.
+  struct AsyncRequestData;
+  class SocketPollData;
+
+  // Initializes CURL for async operation.
+  bool SetupAsyncCurl(brillo::ErrorPtr* error);
+
+  // Stops CURL's async operations.
+  void ShutDownAsyncCurl();
+
+  // Handles all pending async messages from CURL.
+  void ProcessAsyncCurlMessages();
+
+  // Processes the transfer completion message (success or failure).
+  void OnTransferComplete(http::curl::Connection* connection,
+                          CURLcode code);
+
+  // Cleans up internal data for a completed/canceled asynchronous operation
+  // on a connection.
+  void CleanAsyncConnection(http::curl::Connection* connection);
+
+  // Called after a timeout delay requested by CURL has elapsed.
+  void OnTimer();
+
+  // Callback for CURL to handle curl_socket_callback() notifications.
+  // The parameters correspond to those of curl_socket_callback().
+  static int MultiSocketCallback(CURL* easy,
+                                 curl_socket_t s,
+                                 int what,
+                                 void* userp,
+                                 void* socketp);
+
+  // Callback for CURL to handle curl_multi_timer_callback() notifications.
+  // The parameters correspond to those of curl_multi_timer_callback().
+  // CURL actually uses "long" types in callback signatures, so we must comply.
+  static int MultiTimerCallback(CURLM* multi,
+                                long timeout_ms,  // NOLINT(runtime/int)
+                                void* userp);
+
+  std::shared_ptr<CurlInterface> curl_interface_;
+  std::string proxy_;
+  // CURL "multi"-handle for processing requests on multiple connections.
+  CURLM* curl_multi_handle_{nullptr};
+  // A map to find a corresponding Connection* using a request ID.
+  std::map<RequestID, Connection*> request_id_map_;
+  // Stores the connection-specific asynchronous data (such as the success
+  // and error callbacks that need to be called at the end of the async
+  // operation).
+  std::map<Connection*, std::unique_ptr<AsyncRequestData>> async_requests_;
+  // Internal data associated with in-progress asynchronous operations.
+  std::map<std::pair<CURL*, curl_socket_t>, SocketPollData*> poll_data_map_;
+  // The last request ID used for asynchronous operations.
+  RequestID last_request_id_{0};
+  // The connection timeout for the requests made.
+  base::TimeDelta connection_timeout_;
+
+  base::WeakPtrFactory<Transport> weak_ptr_factory_for_timer_{this};
+  base::WeakPtrFactory<Transport> weak_ptr_factory_{this};
+  DISALLOW_COPY_AND_ASSIGN(Transport);
+};
+
+}  // namespace curl
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_CURL_H_
diff --git a/libbrillo/brillo/http/http_transport_curl_unittest.cc b/libbrillo/brillo/http/http_transport_curl_unittest.cc
new file mode 100644
index 0000000..702c9d9
--- /dev/null
+++ b/libbrillo/brillo/http/http_transport_curl_unittest.cc
@@ -0,0 +1,312 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/http_transport_curl.h>
+
+#include <base/at_exit.h>
+#include <base/message_loop/message_loop.h>
+#include <base/run_loop.h>
+#include <brillo/bind_lambda.h>
+#include <brillo/http/http_connection_curl.h>
+#include <brillo/http/http_request.h>
+#include <brillo/http/mock_curl_api.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::DoAll;
+using testing::Invoke;
+using testing::Return;
+using testing::SaveArg;
+using testing::SetArgPointee;
+using testing::WithoutArgs;
+using testing::_;
+
+namespace brillo {
+namespace http {
+namespace curl {
+
+class HttpCurlTransportTest : public testing::Test {
+ public:
+  void SetUp() override {
+    curl_api_ = std::make_shared<MockCurlInterface>();
+    transport_ = std::make_shared<Transport>(curl_api_);
+    handle_ = reinterpret_cast<CURL*>(100);  // Mock handle value.
+    EXPECT_CALL(*curl_api_, EasyInit()).WillOnce(Return(handle_));
+    EXPECT_CALL(*curl_api_, EasySetOptStr(handle_, CURLOPT_CAPATH, _))
+        .WillOnce(Return(CURLE_OK));
+    EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_SSL_VERIFYPEER, 1))
+        .WillOnce(Return(CURLE_OK));
+    EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_SSL_VERIFYHOST, 2))
+        .WillOnce(Return(CURLE_OK));
+    EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_PRIVATE, _))
+        .WillRepeatedly(Return(CURLE_OK));
+  }
+
+  void TearDown() override {
+    transport_.reset();
+    curl_api_.reset();
+  }
+
+ protected:
+  std::shared_ptr<MockCurlInterface> curl_api_;
+  std::shared_ptr<Transport> transport_;
+  CURL* handle_{nullptr};
+};
+
+TEST_F(HttpCurlTransportTest, RequestGet) {
+  EXPECT_CALL(*curl_api_,
+              EasySetOptStr(handle_, CURLOPT_URL, "http://foo.bar/get"))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_,
+              EasySetOptStr(handle_, CURLOPT_USERAGENT, "User Agent"))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_,
+              EasySetOptStr(handle_, CURLOPT_REFERER, "http://foo.bar/baz"))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_HTTPGET, 1))
+      .WillOnce(Return(CURLE_OK));
+  auto connection = transport_->CreateConnection("http://foo.bar/get",
+                                                 request_type::kGet,
+                                                 {},
+                                                 "User Agent",
+                                                 "http://foo.bar/baz",
+                                                 nullptr);
+  EXPECT_NE(nullptr, connection.get());
+
+  EXPECT_CALL(*curl_api_, EasyCleanup(handle_)).Times(1);
+  connection.reset();
+}
+
+TEST_F(HttpCurlTransportTest, RequestHead) {
+  EXPECT_CALL(*curl_api_,
+              EasySetOptStr(handle_, CURLOPT_URL, "http://foo.bar/head"))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_NOBODY, 1))
+      .WillOnce(Return(CURLE_OK));
+  auto connection = transport_->CreateConnection(
+      "http://foo.bar/head", request_type::kHead, {}, "", "", nullptr);
+  EXPECT_NE(nullptr, connection.get());
+
+  EXPECT_CALL(*curl_api_, EasyCleanup(handle_)).Times(1);
+  connection.reset();
+}
+
+TEST_F(HttpCurlTransportTest, RequestPut) {
+  EXPECT_CALL(*curl_api_,
+              EasySetOptStr(handle_, CURLOPT_URL, "http://foo.bar/put"))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_UPLOAD, 1))
+      .WillOnce(Return(CURLE_OK));
+  auto connection = transport_->CreateConnection(
+      "http://foo.bar/put", request_type::kPut, {}, "", "", nullptr);
+  EXPECT_NE(nullptr, connection.get());
+
+  EXPECT_CALL(*curl_api_, EasyCleanup(handle_)).Times(1);
+  connection.reset();
+}
+
+TEST_F(HttpCurlTransportTest, RequestPost) {
+  EXPECT_CALL(*curl_api_,
+              EasySetOptStr(handle_, CURLOPT_URL, "http://www.foo.bar/post"))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_POST, 1))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_POSTFIELDS, nullptr))
+      .WillOnce(Return(CURLE_OK));
+  auto connection = transport_->CreateConnection(
+      "http://www.foo.bar/post", request_type::kPost, {}, "", "", nullptr);
+  EXPECT_NE(nullptr, connection.get());
+
+  EXPECT_CALL(*curl_api_, EasyCleanup(handle_)).Times(1);
+  connection.reset();
+}
+
+TEST_F(HttpCurlTransportTest, RequestPatch) {
+  EXPECT_CALL(*curl_api_,
+              EasySetOptStr(handle_, CURLOPT_URL, "http://www.foo.bar/patch"))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_POST, 1))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_POSTFIELDS, nullptr))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(
+      *curl_api_,
+      EasySetOptStr(handle_, CURLOPT_CUSTOMREQUEST, request_type::kPatch))
+      .WillOnce(Return(CURLE_OK));
+  auto connection = transport_->CreateConnection(
+      "http://www.foo.bar/patch", request_type::kPatch, {}, "", "", nullptr);
+  EXPECT_NE(nullptr, connection.get());
+
+  EXPECT_CALL(*curl_api_, EasyCleanup(handle_)).Times(1);
+  connection.reset();
+}
+
+TEST_F(HttpCurlTransportTest, CurlFailure) {
+  EXPECT_CALL(*curl_api_,
+              EasySetOptStr(handle_, CURLOPT_URL, "http://foo.bar/get"))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_HTTPGET, 1))
+      .WillOnce(Return(CURLE_OUT_OF_MEMORY));
+  EXPECT_CALL(*curl_api_, EasyStrError(CURLE_OUT_OF_MEMORY))
+      .WillOnce(Return("Out of Memory"));
+  EXPECT_CALL(*curl_api_, EasyCleanup(handle_)).Times(1);
+  ErrorPtr error;
+  auto connection = transport_->CreateConnection(
+      "http://foo.bar/get", request_type::kGet, {}, "", "", &error);
+
+  EXPECT_EQ(nullptr, connection.get());
+  EXPECT_EQ("curl_easy_error", error->GetDomain());
+  EXPECT_EQ(std::to_string(CURLE_OUT_OF_MEMORY), error->GetCode());
+  EXPECT_EQ("Out of Memory", error->GetMessage());
+}
+
+class HttpCurlTransportAsyncTest : public testing::Test {
+ public:
+  void SetUp() override {
+    curl_api_ = std::make_shared<MockCurlInterface>();
+    transport_ = std::make_shared<Transport>(curl_api_);
+    EXPECT_CALL(*curl_api_, EasyInit()).WillOnce(Return(handle_));
+    EXPECT_CALL(*curl_api_, EasySetOptStr(handle_, CURLOPT_CAPATH, _))
+        .WillOnce(Return(CURLE_OK));
+    EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_SSL_VERIFYPEER, 1))
+        .WillOnce(Return(CURLE_OK));
+    EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_SSL_VERIFYHOST, 2))
+        .WillOnce(Return(CURLE_OK));
+    EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_PRIVATE, _))
+        .WillOnce(Return(CURLE_OK));
+  }
+
+ protected:
+  std::shared_ptr<MockCurlInterface> curl_api_;
+  std::shared_ptr<Transport> transport_;
+  CURL* handle_{reinterpret_cast<CURL*>(123)};          // Mock handle value.
+  CURLM* multi_handle_{reinterpret_cast<CURLM*>(456)};  // Mock handle value.
+  curl_socket_t dummy_socket_{789};
+};
+
+TEST_F(HttpCurlTransportAsyncTest, StartAsyncTransfer) {
+  // This test is a bit tricky because it deals with asynchronous I/O which
+  // relies on a message loop to run all the async tasks.
+  // For this, create a temporary I/O message loop and run it ourselves for the
+  // duration of the test.
+  base::MessageLoopForIO message_loop;
+  base::RunLoop run_loop;
+
+  // Initial expectations for creating a CURL connection.
+  EXPECT_CALL(*curl_api_,
+              EasySetOptStr(handle_, CURLOPT_URL, "http://foo.bar/get"))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_HTTPGET, 1))
+      .WillOnce(Return(CURLE_OK));
+  auto connection = transport_->CreateConnection(
+      "http://foo.bar/get", request_type::kGet, {}, "", "", nullptr);
+  ASSERT_NE(nullptr, connection.get());
+
+  // Success/error callback needed to report the result of an async operation.
+  int success_call_count = 0;
+  auto success_callback = [](int* success_call_count,
+                             base::RunLoop* run_loop,
+                             RequestID /* request_id */,
+                             std::unique_ptr<http::Response> /* resp */) {
+    base::MessageLoop::current()->PostTask(FROM_HERE, run_loop->QuitClosure());
+    (*success_call_count)++;
+  };
+
+  auto error_callback = [](RequestID /* request_id */,
+                           const Error* /* error */) {
+    FAIL() << "This callback shouldn't have been called";
+  };
+
+  EXPECT_CALL(*curl_api_, MultiInit()).WillOnce(Return(multi_handle_));
+  EXPECT_CALL(*curl_api_, EasyGetInfoInt(handle_, CURLINFO_RESPONSE_CODE, _))
+      .WillRepeatedly(DoAll(SetArgPointee<2>(200), Return(CURLE_OK)));
+
+  curl_socket_callback socket_callback = nullptr;
+  EXPECT_CALL(*curl_api_,
+              MultiSetSocketCallback(multi_handle_, _, transport_.get()))
+      .WillOnce(DoAll(SaveArg<1>(&socket_callback), Return(CURLM_OK)));
+
+  curl_multi_timer_callback timer_callback = nullptr;
+  EXPECT_CALL(*curl_api_,
+              MultiSetTimerCallback(multi_handle_, _, transport_.get()))
+      .WillOnce(DoAll(SaveArg<1>(&timer_callback), Return(CURLM_OK)));
+
+  EXPECT_CALL(*curl_api_, MultiAddHandle(multi_handle_, handle_))
+      .WillOnce(Return(CURLM_OK));
+
+  EXPECT_EQ(1,
+            transport_->StartAsyncTransfer(
+                connection.get(),
+                base::Bind(success_callback,
+                           base::Unretained(&success_call_count),
+                           base::Unretained(&run_loop)),
+                base::Bind(error_callback)));
+  EXPECT_EQ(0, success_call_count);
+
+  timer_callback(multi_handle_, 1, transport_.get());
+
+  auto do_socket_action = [&socket_callback, this] {
+    EXPECT_CALL(*curl_api_, MultiAssign(multi_handle_, dummy_socket_, _))
+        .Times(2).WillRepeatedly(Return(CURLM_OK));
+    EXPECT_EQ(0, socket_callback(handle_, dummy_socket_, CURL_POLL_REMOVE,
+                                 transport_.get(), nullptr));
+  };
+
+  EXPECT_CALL(*curl_api_,
+              MultiSocketAction(multi_handle_, CURL_SOCKET_TIMEOUT, 0, _))
+      .WillOnce(DoAll(SetArgPointee<3>(1),
+                      WithoutArgs(Invoke(do_socket_action)),
+                      Return(CURLM_OK)))
+      .WillRepeatedly(DoAll(SetArgPointee<3>(0), Return(CURLM_OK)));
+
+  CURLMsg msg = {};
+  msg.msg = CURLMSG_DONE;
+  msg.easy_handle = handle_;
+  msg.data.result = CURLE_OK;
+
+  EXPECT_CALL(*curl_api_, MultiInfoRead(multi_handle_, _))
+      .WillOnce(DoAll(SetArgPointee<1>(0), Return(&msg)))
+      .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(nullptr)));
+  EXPECT_CALL(*curl_api_, EasyGetInfoPtr(handle_, CURLINFO_PRIVATE, _))
+      .WillRepeatedly(DoAll(SetArgPointee<2>(connection.get()),
+                            Return(CURLE_OK)));
+
+  EXPECT_CALL(*curl_api_, MultiRemoveHandle(multi_handle_, handle_))
+      .WillOnce(Return(CURLM_OK));
+
+  // Just in case something goes wrong and |success_callback| isn't called,
+  // post a time-out quit closure to abort the message loop after 1 second.
+  message_loop.PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromSeconds(1));
+  run_loop.Run();
+  EXPECT_EQ(1, success_call_count);
+
+  EXPECT_CALL(*curl_api_, EasyCleanup(handle_)).Times(1);
+  connection.reset();
+
+  EXPECT_CALL(*curl_api_, MultiCleanup(multi_handle_))
+      .WillOnce(Return(CURLM_OK));
+  transport_.reset();
+}
+
+TEST_F(HttpCurlTransportTest, RequestGetTimeout) {
+  transport_->SetDefaultTimeout(base::TimeDelta::FromMilliseconds(2000));
+  EXPECT_CALL(*curl_api_,
+              EasySetOptStr(handle_, CURLOPT_URL, "http://foo.bar/get"))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_TIMEOUT_MS, 2000))
+      .WillOnce(Return(CURLE_OK));
+  EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_HTTPGET, 1))
+      .WillOnce(Return(CURLE_OK));
+  auto connection = transport_->CreateConnection(
+      "http://foo.bar/get", request_type::kGet, {}, "", "", nullptr);
+  EXPECT_NE(nullptr, connection.get());
+
+  EXPECT_CALL(*curl_api_, EasyCleanup(handle_)).Times(1);
+  connection.reset();
+}
+
+}  // namespace curl
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/http_transport_fake.cc b/libbrillo/brillo/http/http_transport_fake.cc
new file mode 100644
index 0000000..cda885f
--- /dev/null
+++ b/libbrillo/brillo/http/http_transport_fake.cc
@@ -0,0 +1,331 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/http_transport_fake.h>
+
+#include <utility>
+
+#include <base/json/json_reader.h>
+#include <base/json/json_writer.h>
+#include <base/logging.h>
+#include <brillo/bind_lambda.h>
+#include <brillo/http/http_connection_fake.h>
+#include <brillo/http/http_request.h>
+#include <brillo/mime_utils.h>
+#include <brillo/streams/memory_stream.h>
+#include <brillo/strings/string_utils.h>
+#include <brillo/url_utils.h>
+
+namespace brillo {
+
+using http::fake::Transport;
+using http::fake::ServerRequestResponseBase;
+using http::fake::ServerRequest;
+using http::fake::ServerResponse;
+
+Transport::Transport() {
+  VLOG(1) << "fake::Transport created";
+}
+
+Transport::~Transport() {
+  VLOG(1) << "fake::Transport destroyed";
+}
+
+std::shared_ptr<http::Connection> Transport::CreateConnection(
+    const std::string& url,
+    const std::string& method,
+    const HeaderList& headers,
+    const std::string& user_agent,
+    const std::string& referer,
+    brillo::ErrorPtr* error) {
+  std::shared_ptr<http::Connection> connection;
+  if (create_connection_error_) {
+    if (error)
+      *error = std::move(create_connection_error_);
+    return connection;
+  }
+  HeaderList headers_copy = headers;
+  if (!user_agent.empty()) {
+    headers_copy.push_back(
+        std::make_pair(http::request_header::kUserAgent, user_agent));
+  }
+  if (!referer.empty()) {
+    headers_copy.push_back(
+        std::make_pair(http::request_header::kReferer, referer));
+  }
+  connection =
+      std::make_shared<http::fake::Connection>(url, method, shared_from_this());
+  CHECK(connection) << "Unable to create Connection object";
+  if (!connection->SendHeaders(headers_copy, error))
+    connection.reset();
+  request_count_++;
+  return connection;
+}
+
+void Transport::RunCallbackAsync(
+    const tracked_objects::Location& /* from_here */,
+    const base::Closure& callback) {
+  if (!async_) {
+    callback.Run();
+    return;
+  }
+  async_callback_queue_.push(callback);
+}
+
+bool Transport::HandleOneAsyncRequest() {
+  if (async_callback_queue_.empty())
+    return false;
+
+  base::Closure callback = async_callback_queue_.front();
+  async_callback_queue_.pop();
+  callback.Run();
+  return true;
+}
+
+void Transport::HandleAllAsyncRequests() {
+  while (!async_callback_queue_.empty())
+    HandleOneAsyncRequest();
+}
+
+http::RequestID Transport::StartAsyncTransfer(
+    http::Connection* /* connection */,
+    const SuccessCallback& /* success_callback */,
+    const ErrorCallback& /* error_callback */) {
+  // Fake transport doesn't use this method.
+  LOG(FATAL) << "This method should not be called on fake transport";
+  return 0;
+}
+
+bool Transport::CancelRequest(RequestID /* request_id */) {
+  return false;
+}
+
+void Transport::SetDefaultTimeout(base::TimeDelta /* timeout */) {
+}
+
+static inline std::string GetHandlerMapKey(const std::string& url,
+                                           const std::string& method) {
+  return method + ":" + url;
+}
+
+void Transport::AddHandler(const std::string& url,
+                           const std::string& method,
+                           const HandlerCallback& handler) {
+  // Make sure we can override/replace existing handlers.
+  handlers_[GetHandlerMapKey(url, method)] = handler;
+}
+
+void Transport::AddSimpleReplyHandler(const std::string& url,
+                                      const std::string& method,
+                                      int status_code,
+                                      const std::string& reply_text,
+                                      const std::string& mime_type) {
+  auto handler = [](int status_code,
+                    const std::string& reply_text,
+                    const std::string& mime_type,
+                    const ServerRequest& /* request */,
+                    ServerResponse* response) {
+    response->ReplyText(status_code, reply_text, mime_type);
+  };
+  AddHandler(
+      url, method, base::Bind(handler, status_code, reply_text, mime_type));
+}
+
+Transport::HandlerCallback Transport::GetHandler(
+    const std::string& url,
+    const std::string& method) const {
+  // First try the exact combination of URL/Method
+  auto p = handlers_.find(GetHandlerMapKey(url, method));
+  if (p != handlers_.end())
+    return p->second;
+  // If not found, try URL/*
+  p = handlers_.find(GetHandlerMapKey(url, "*"));
+  if (p != handlers_.end())
+    return p->second;
+  // If still not found, try */method
+  p = handlers_.find(GetHandlerMapKey("*", method));
+  if (p != handlers_.end())
+    return p->second;
+  // Finally, try */*
+  p = handlers_.find(GetHandlerMapKey("*", "*"));
+  return (p != handlers_.end()) ? p->second : HandlerCallback();
+}
+
+void ServerRequestResponseBase::SetData(StreamPtr stream) {
+  data_.clear();
+  if (stream) {
+    uint8_t buffer[1024];
+    size_t size = 0;
+    if (stream->CanGetSize())
+      data_.reserve(stream->GetRemainingSize());
+
+    do {
+      CHECK(stream->ReadBlocking(buffer, sizeof(buffer), &size, nullptr));
+      data_.insert(data_.end(), buffer, buffer + size);
+    } while (size > 0);
+  }
+}
+
+std::string ServerRequestResponseBase::GetDataAsString() const {
+  if (data_.empty())
+    return std::string();
+  auto chars = reinterpret_cast<const char*>(data_.data());
+  return std::string(chars, data_.size());
+}
+
+std::unique_ptr<base::DictionaryValue>
+ServerRequestResponseBase::GetDataAsJson() const {
+  std::unique_ptr<base::DictionaryValue> result;
+  if (brillo::mime::RemoveParameters(
+          GetHeader(request_header::kContentType)) ==
+      brillo::mime::application::kJson) {
+    auto value = base::JSONReader::Read(GetDataAsString());
+    result = base::DictionaryValue::From(std::move(value));
+  }
+  return result;
+}
+
+std::string ServerRequestResponseBase::GetDataAsNormalizedJsonString() const {
+  std::string value;
+  // Make sure we serialize the JSON back without any pretty print so
+  // the string comparison works correctly.
+  auto json = GetDataAsJson();
+  if (json)
+    base::JSONWriter::Write(*json, &value);
+  return value;
+}
+
+void ServerRequestResponseBase::AddHeaders(const HeaderList& headers) {
+  for (const auto& pair : headers) {
+    if (pair.second.empty())
+      headers_.erase(pair.first);
+    else
+      headers_.insert(pair);
+  }
+}
+
+std::string ServerRequestResponseBase::GetHeader(
+    const std::string& header_name) const {
+  auto p = headers_.find(header_name);
+  return p != headers_.end() ? p->second : std::string();
+}
+
+ServerRequest::ServerRequest(const std::string& url, const std::string& method)
+    : method_(method) {
+  auto params = brillo::url::GetQueryStringParameters(url);
+  url_ = brillo::url::RemoveQueryString(url, true);
+  form_fields_.insert(params.begin(), params.end());
+}
+
+std::string ServerRequest::GetFormField(const std::string& field_name) const {
+  if (!form_fields_parsed_) {
+    std::string mime_type = brillo::mime::RemoveParameters(
+        GetHeader(request_header::kContentType));
+    if (mime_type == brillo::mime::application::kWwwFormUrlEncoded &&
+        !GetData().empty()) {
+      auto fields = brillo::data_encoding::WebParamsDecode(GetDataAsString());
+      form_fields_.insert(fields.begin(), fields.end());
+    }
+    form_fields_parsed_ = true;
+  }
+  auto p = form_fields_.find(field_name);
+  return p != form_fields_.end() ? p->second : std::string();
+}
+
+void ServerResponse::Reply(int status_code,
+                           const void* data,
+                           size_t data_size,
+                           const std::string& mime_type) {
+  data_.clear();
+  status_code_ = status_code;
+  SetData(MemoryStream::OpenCopyOf(data, data_size, nullptr));
+  AddHeaders({{response_header::kContentLength,
+               brillo::string_utils::ToString(data_size)},
+              {response_header::kContentType, mime_type}});
+}
+
+void ServerResponse::ReplyText(int status_code,
+                               const std::string& text,
+                               const std::string& mime_type) {
+  Reply(status_code, text.data(), text.size(), mime_type);
+}
+
+void ServerResponse::ReplyJson(int status_code, const base::Value* json) {
+  std::string text;
+  base::JSONWriter::WriteWithOptions(
+      *json, base::JSONWriter::OPTIONS_PRETTY_PRINT, &text);
+  std::string mime_type =
+      brillo::mime::AppendParameter(brillo::mime::application::kJson,
+                                      brillo::mime::parameters::kCharset,
+                                      "utf-8");
+  ReplyText(status_code, text, mime_type);
+}
+
+void ServerResponse::ReplyJson(int status_code,
+                               const http::FormFieldList& fields) {
+  base::DictionaryValue json;
+  for (const auto& pair : fields) {
+    json.SetString(pair.first, pair.second);
+  }
+  ReplyJson(status_code, &json);
+}
+
+std::string ServerResponse::GetStatusText() const {
+  static std::vector<std::pair<int, const char*>> status_text_map = {
+      {100, "Continue"},
+      {101, "Switching Protocols"},
+      {102, "Processing"},
+      {200, "OK"},
+      {201, "Created"},
+      {202, "Accepted"},
+      {203, "Non-Authoritative Information"},
+      {204, "No Content"},
+      {205, "Reset Content"},
+      {206, "Partial Content"},
+      {207, "Multi-Status"},
+      {208, "Already Reported"},
+      {226, "IM Used"},
+      {300, "Multiple Choices"},
+      {301, "Moved Permanently"},
+      {302, "Found"},
+      {303, "See Other"},
+      {304, "Not Modified"},
+      {305, "Use Proxy"},
+      {306, "Switch Proxy"},
+      {307, "Temporary Redirect"},
+      {308, "Permanent Redirect"},
+      {400, "Bad Request"},
+      {401, "Unauthorized"},
+      {402, "Payment Required"},
+      {403, "Forbidden"},
+      {404, "Not Found"},
+      {405, "Method Not Allowed"},
+      {406, "Not Acceptable"},
+      {407, "Proxy Authentication Required"},
+      {408, "Request Timeout"},
+      {409, "Conflict"},
+      {410, "Gone"},
+      {411, "Length Required"},
+      {412, "Precondition Failed"},
+      {413, "Request Entity Too Large"},
+      {414, "Request - URI Too Long"},
+      {415, "Unsupported Media Type"},
+      {429, "Too Many Requests"},
+      {431, "Request Header Fields Too Large"},
+      {500, "Internal Server Error"},
+      {501, "Not Implemented"},
+      {502, "Bad Gateway"},
+      {503, "Service Unavailable"},
+      {504, "Gateway Timeout"},
+      {505, "HTTP Version Not Supported"},
+  };
+
+  for (const auto& pair : status_text_map) {
+    if (pair.first == status_code_)
+      return pair.second;
+  }
+  return std::string();
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/http_transport_fake.h b/libbrillo/brillo/http/http_transport_fake.h
new file mode 100644
index 0000000..ac8bc2a
--- /dev/null
+++ b/libbrillo/brillo/http/http_transport_fake.h
@@ -0,0 +1,265 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_FAKE_H_
+#define LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_FAKE_H_
+
+#include <map>
+#include <queue>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <base/callback.h>
+#include <base/values.h>
+#include <brillo/http/http_transport.h>
+#include <brillo/http/http_utils.h>
+
+namespace brillo {
+namespace http {
+namespace fake {
+
+class ServerRequest;
+class ServerResponse;
+class Connection;
+
+///////////////////////////////////////////////////////////////////////////////
+// A fake implementation of http::Transport that simulates HTTP communication
+// with a server.
+///////////////////////////////////////////////////////////////////////////////
+class Transport : public http::Transport {
+ public:
+  Transport();
+  ~Transport() override;
+
+  // Server handler callback signature.
+  using HandlerCallback =
+      base::Callback<void(const ServerRequest&, ServerResponse*)>;
+
+  // This method allows the test code to provide a callback to handle requests
+  // for specific URL/HTTP-verb combination. When a specific |method| request
+  // is made on the given |url|, the |handler| will be invoked and all the
+  // request data will be filled in the |ServerRequest| parameter. Any server
+  // response should be returned through the |ServerResponse| parameter.
+  // Either |method| or |url| (or both) can be specified as "*" to handle
+  // any requests. So, ("http://localhost","*") will handle any request type
+  // on that URL and ("*","GET") will handle any GET requests.
+  // The lookup starts with the most specific data pair to the catch-all (*,*).
+  void AddHandler(const std::string& url,
+                  const std::string& method,
+                  const HandlerCallback& handler);
+  // Simple version of AddHandler. AddSimpleReplyHandler just returns the
+  // specified text response of given MIME type.
+  void AddSimpleReplyHandler(const std::string& url,
+                             const std::string& method,
+                             int status_code,
+                             const std::string& reply_text,
+                             const std::string& mime_type);
+  // Retrieve a handler for specific |url| and request |method|.
+  HandlerCallback GetHandler(const std::string& url,
+                             const std::string& method) const;
+
+  // For tests that want to assert on the number of HTTP requests sent,
+  // these methods can be used to do just that.
+  int GetRequestCount() const { return request_count_; }
+  void ResetRequestCount() { request_count_ = 0; }
+
+  // For tests that wish to simulate critical transport errors, this method
+  // can be used to specify the error to be returned when creating a connection.
+  void SetCreateConnectionError(brillo::ErrorPtr create_connection_error) {
+    create_connection_error_ = std::move(create_connection_error);
+  }
+
+  // For tests that really need async operations with message loop, call this
+  // function with true.
+  void SetAsyncMode(bool async) { async_ = async; }
+
+  // Pops one callback from the top of |async_callback_queue_| and invokes it.
+  // Returns false if the queue is empty.
+  bool HandleOneAsyncRequest();
+
+  // Invokes all the callbacks currently queued in |async_callback_queue_|.
+  void HandleAllAsyncRequests();
+
+  // Overrides from http::Transport.
+  std::shared_ptr<http::Connection> CreateConnection(
+      const std::string& url,
+      const std::string& method,
+      const HeaderList& headers,
+      const std::string& user_agent,
+      const std::string& referer,
+      brillo::ErrorPtr* error) override;
+
+  void RunCallbackAsync(const tracked_objects::Location& from_here,
+                        const base::Closure& callback) override;
+
+  RequestID StartAsyncTransfer(http::Connection* connection,
+                               const SuccessCallback& success_callback,
+                               const ErrorCallback& error_callback) override;
+
+  bool CancelRequest(RequestID request_id) override;
+
+  void SetDefaultTimeout(base::TimeDelta timeout) override;
+
+ private:
+  // A list of user-supplied request handlers.
+  std::map<std::string, HandlerCallback> handlers_;
+  // Counter incremented each time a request is made.
+  int request_count_{0};
+  bool async_{false};
+  // A list of queued callbacks that need to be called at some point.
+  // Call HandleOneAsyncRequest() or HandleAllAsyncRequests() to invoke them.
+  std::queue<base::Closure> async_callback_queue_;
+
+  // Fake error to be returned from CreateConnection method.
+  brillo::ErrorPtr create_connection_error_;
+
+  DISALLOW_COPY_AND_ASSIGN(Transport);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// A base class for ServerRequest and ServerResponse. It provides common
+// functionality to work with request/response HTTP headers and data.
+///////////////////////////////////////////////////////////////////////////////
+class ServerRequestResponseBase {
+ public:
+  ServerRequestResponseBase() = default;
+
+  // Add/retrieve request/response body data.
+  void SetData(StreamPtr stream);
+  const std::vector<uint8_t>& GetData() const { return data_; }
+  std::string GetDataAsString() const;
+  std::unique_ptr<base::DictionaryValue> GetDataAsJson() const;
+  // Parses the data into a JSON object and writes it back to JSON to normalize
+  // its string representation (no pretty print, extra spaces, etc).
+  std::string GetDataAsNormalizedJsonString() const;
+
+  // Add/retrieve request/response HTTP headers.
+  void AddHeaders(const HeaderList& headers);
+  std::string GetHeader(const std::string& header_name) const;
+  const std::multimap<std::string, std::string>& GetHeaders() const {
+    return headers_;
+  }
+
+ protected:
+  // Data buffer.
+  std::vector<uint8_t> data_;
+  // Header map.
+  std::multimap<std::string, std::string> headers_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ServerRequestResponseBase);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// A container class that encapsulates all the HTTP server request information.
+///////////////////////////////////////////////////////////////////////////////
+class ServerRequest : public ServerRequestResponseBase {
+ public:
+  ServerRequest(const std::string& url, const std::string& method);
+
+  // Get the actual request URL. Does not include the query string or fragment.
+  const std::string& GetURL() const { return url_; }
+  // Get the request method.
+  const std::string& GetMethod() const { return method_; }
+  // Get the POST/GET request parameters. These are parsed query string
+  // parameters from the URL. In addition, for POST requests with
+  // application/x-www-form-urlencoded content type, the request body is also
+  // parsed and individual fields can be accessed through this method.
+  std::string GetFormField(const std::string& field_name) const;
+
+ private:
+  // Request URL (without query string or URL fragment).
+  std::string url_;
+  // Request method
+  std::string method_;
+  // List of available request data form fields.
+  mutable std::map<std::string, std::string> form_fields_;
+  // Flag used on first request to GetFormField to parse the body of HTTP POST
+  // request with application/x-www-form-urlencoded content.
+  mutable bool form_fields_parsed_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(ServerRequest);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// A container class that encapsulates all the HTTP server response information.
+// The request handler will use this class to provide a response to the caller.
+// Call the Reply() or the appropriate ReplyNNN() specialization to provide
+// the response data. Additional calls to AddHeaders() can be made to provide
+// custom response headers. The Reply-methods will already provide the
+// following response headers:
+//    Content-Length
+//    Content-Type
+///////////////////////////////////////////////////////////////////////////////
+class ServerResponse : public ServerRequestResponseBase {
+ public:
+  ServerResponse() = default;
+
+  // Generic reply method.
+  void Reply(int status_code,
+             const void* data,
+             size_t data_size,
+             const std::string& mime_type);
+  // Reply with text body.
+  void ReplyText(int status_code,
+                 const std::string& text,
+                 const std::string& mime_type);
+  // Reply with JSON object. The content type will be "application/json".
+  void ReplyJson(int status_code, const base::Value* json);
+  // Special form for JSON response for simple objects that have a flat
+  // list of key-value pairs of string type.
+  void ReplyJson(int status_code, const FormFieldList& fields);
+
+  // Specialized overload to send the binary data as an array of simple
+  // data elements. Only trivial data types (scalars, POD structures, etc)
+  // can be used.
+  template<typename T>
+  void Reply(int status_code,
+             const std::vector<T>& data,
+             const std::string& mime_type) {
+    // Make sure T doesn't have virtual functions, custom constructors, etc.
+    static_assert(std::is_trivial<T>::value, "Only simple data is supported");
+    Reply(status_code, data.data(), data.size() * sizeof(T), mime_type);
+  }
+
+  // Specialized overload to send the binary data.
+  // Only trivial data types (scalars, POD structures, etc) can be used.
+  template<typename T>
+  void Reply(int status_code, const T& data, const std::string& mime_type) {
+    // Make sure T doesn't have virtual functions, custom constructors, etc.
+    static_assert(std::is_trivial<T>::value, "Only simple data is supported");
+    Reply(status_code, &data, sizeof(T), mime_type);
+  }
+
+  // For handlers that want to simulate versions of HTTP protocol other
+  // than HTTP/1.1, call this method with the custom version string,
+  // for example "HTTP/1.0".
+  void SetProtocolVersion(const std::string& protocol_version) {
+    protocol_version_ = protocol_version;
+  }
+
+ protected:
+  // These methods are helpers to implement corresponding functionality
+  // of fake::Connection.
+  friend class Connection;
+  // Helper for fake::Connection::GetResponseStatusCode().
+  int GetStatusCode() const { return status_code_; }
+  // Helper for fake::Connection::GetResponseStatusText().
+  std::string GetStatusText() const;
+  // Helper for fake::Connection::GetProtocolVersion().
+  std::string GetProtocolVersion() const { return protocol_version_; }
+
+ private:
+  int status_code_ = 0;
+  std::string protocol_version_ = "HTTP/1.1";
+
+  DISALLOW_COPY_AND_ASSIGN(ServerResponse);
+};
+
+}  // namespace fake
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_HTTP_TRANSPORT_FAKE_H_
diff --git a/libbrillo/brillo/http/http_utils.cc b/libbrillo/brillo/http/http_utils.cc
new file mode 100644
index 0000000..6132d11
--- /dev/null
+++ b/libbrillo/brillo/http/http_utils.cc
@@ -0,0 +1,437 @@
+// Copyright 2014 The Chromium OS 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 <brillo/http/http_utils.h>
+
+#include <algorithm>
+
+#include <base/bind.h>
+#include <base/json/json_reader.h>
+#include <base/json/json_writer.h>
+#include <base/values.h>
+#include <brillo/data_encoding.h>
+#include <brillo/errors/error_codes.h>
+#include <brillo/mime_utils.h>
+#include <brillo/streams/memory_stream.h>
+
+using brillo::mime::AppendParameter;
+using brillo::mime::RemoveParameters;
+
+namespace brillo {
+namespace http {
+
+std::unique_ptr<Response> GetAndBlock(const std::string& url,
+                                      const HeaderList& headers,
+                                      std::shared_ptr<Transport> transport,
+                                      brillo::ErrorPtr* error) {
+  return SendRequestWithNoDataAndBlock(
+      request_type::kGet, url, headers, transport, error);
+}
+
+RequestID Get(const std::string& url,
+              const HeaderList& headers,
+              std::shared_ptr<Transport> transport,
+              const SuccessCallback& success_callback,
+              const ErrorCallback& error_callback) {
+  return SendRequestWithNoData(request_type::kGet,
+                               url,
+                               headers,
+                               transport,
+                               success_callback,
+                               error_callback);
+}
+
+std::unique_ptr<Response> HeadAndBlock(const std::string& url,
+                                       std::shared_ptr<Transport> transport,
+                                       brillo::ErrorPtr* error) {
+  return SendRequestWithNoDataAndBlock(
+      request_type::kHead, url, {}, transport, error);
+}
+
+RequestID Head(const std::string& url,
+               std::shared_ptr<Transport> transport,
+               const SuccessCallback& success_callback,
+               const ErrorCallback& error_callback) {
+  return SendRequestWithNoData(request_type::kHead,
+                               url,
+                               {},
+                               transport,
+                               success_callback,
+                               error_callback);
+}
+
+std::unique_ptr<Response> PostTextAndBlock(const std::string& url,
+                                           const std::string& data,
+                                           const std::string& mime_type,
+                                           const HeaderList& headers,
+                                           std::shared_ptr<Transport> transport,
+                                           brillo::ErrorPtr* error) {
+  return PostBinaryAndBlock(
+      url, data.data(), data.size(), mime_type, headers, transport, error);
+}
+
+RequestID PostText(const std::string& url,
+                   const std::string& data,
+                   const std::string& mime_type,
+                   const HeaderList& headers,
+                   std::shared_ptr<Transport> transport,
+                   const SuccessCallback& success_callback,
+                   const ErrorCallback& error_callback) {
+  return PostBinary(url,
+                    data.data(),
+                    data.size(),
+                    mime_type,
+                    headers,
+                    transport,
+                    success_callback,
+                    error_callback);
+}
+
+std::unique_ptr<Response> SendRequestAndBlock(
+    const std::string& method,
+    const std::string& url,
+    const void* data,
+    size_t data_size,
+    const std::string& mime_type,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error) {
+  Request request(url, method, transport);
+  request.AddHeaders(headers);
+  if (data_size > 0) {
+    CHECK(!mime_type.empty()) << "MIME type must be specified if request body "
+                                 "message is provided";
+    request.SetContentType(mime_type);
+    if (!request.AddRequestBody(data, data_size, error))
+      return std::unique_ptr<Response>();
+  }
+  return request.GetResponseAndBlock(error);
+}
+
+std::unique_ptr<Response> SendRequestWithNoDataAndBlock(
+    const std::string& method,
+    const std::string& url,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error) {
+  return SendRequestAndBlock(
+      method, url, nullptr, 0, {}, headers, transport, error);
+}
+
+RequestID SendRequest(const std::string& method,
+                      const std::string& url,
+                      StreamPtr stream,
+                      const std::string& mime_type,
+                      const HeaderList& headers,
+                      std::shared_ptr<Transport> transport,
+                      const SuccessCallback& success_callback,
+                      const ErrorCallback& error_callback) {
+  Request request(url, method, transport);
+  request.AddHeaders(headers);
+  if (stream && (!stream->CanGetSize() || stream->GetRemainingSize() > 0)) {
+    CHECK(!mime_type.empty()) << "MIME type must be specified if request body "
+                                 "message is provided";
+    request.SetContentType(mime_type);
+    brillo::ErrorPtr error;
+    if (!request.AddRequestBody(std::move(stream), &error)) {
+      transport->RunCallbackAsync(
+          FROM_HERE, base::Bind(error_callback,
+                                0, base::Owned(error.release())));
+      return 0;
+    }
+  }
+  return request.GetResponse(success_callback, error_callback);
+}
+
+RequestID SendRequest(const std::string& method,
+                      const std::string& url,
+                      const void* data,
+                      size_t data_size,
+                      const std::string& mime_type,
+                      const HeaderList& headers,
+                      std::shared_ptr<Transport> transport,
+                      const SuccessCallback& success_callback,
+                      const ErrorCallback& error_callback) {
+  return SendRequest(method,
+                     url,
+                     MemoryStream::OpenCopyOf(data, data_size, nullptr),
+                     mime_type,
+                     headers,
+                     transport,
+                     success_callback,
+                     error_callback);
+}
+
+RequestID SendRequestWithNoData(const std::string& method,
+                                const std::string& url,
+                                const HeaderList& headers,
+                                std::shared_ptr<Transport> transport,
+                                const SuccessCallback& success_callback,
+                                const ErrorCallback& error_callback) {
+  return SendRequest(method,
+                     url,
+                     {},
+                     {},
+                     headers,
+                     transport,
+                     success_callback,
+                     error_callback);
+}
+
+std::unique_ptr<Response> PostBinaryAndBlock(
+    const std::string& url,
+    const void* data,
+    size_t data_size,
+    const std::string& mime_type,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error) {
+  return SendRequestAndBlock(request_type::kPost,
+                             url,
+                             data,
+                             data_size,
+                             mime_type,
+                             headers,
+                             transport,
+                             error);
+}
+
+RequestID PostBinary(const std::string& url,
+                     StreamPtr stream,
+                     const std::string& mime_type,
+                     const HeaderList& headers,
+                     std::shared_ptr<Transport> transport,
+                     const SuccessCallback& success_callback,
+                     const ErrorCallback& error_callback) {
+  return SendRequest(request_type::kPost,
+                     url,
+                     std::move(stream),
+                     mime_type,
+                     headers,
+                     transport,
+                     success_callback,
+                     error_callback);
+}
+
+RequestID PostBinary(const std::string& url,
+                     const void* data,
+                     size_t data_size,
+                     const std::string& mime_type,
+                     const HeaderList& headers,
+                     std::shared_ptr<Transport> transport,
+                     const SuccessCallback& success_callback,
+                     const ErrorCallback& error_callback) {
+  return SendRequest(request_type::kPost,
+                     url,
+                     data,
+                     data_size,
+                     mime_type,
+                     headers,
+                     transport,
+                     success_callback,
+                     error_callback);
+}
+
+std::unique_ptr<Response> PostFormDataAndBlock(
+    const std::string& url,
+    const FormFieldList& data,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error) {
+  std::string encoded_data = brillo::data_encoding::WebParamsEncode(data);
+  return PostBinaryAndBlock(url,
+                            encoded_data.c_str(),
+                            encoded_data.size(),
+                            brillo::mime::application::kWwwFormUrlEncoded,
+                            headers,
+                            transport,
+                            error);
+}
+
+std::unique_ptr<Response> PostFormDataAndBlock(
+    const std::string& url,
+    std::unique_ptr<FormData> form_data,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error) {
+  Request request(url, request_type::kPost, transport);
+  request.AddHeaders(headers);
+  if (!request.AddRequestBodyAsFormData(std::move(form_data), error))
+    return std::unique_ptr<Response>();
+  return request.GetResponseAndBlock(error);
+}
+
+RequestID PostFormData(const std::string& url,
+                       const FormFieldList& data,
+                       const HeaderList& headers,
+                       std::shared_ptr<Transport> transport,
+                       const SuccessCallback& success_callback,
+                       const ErrorCallback& error_callback) {
+  std::string encoded_data = brillo::data_encoding::WebParamsEncode(data);
+  return PostBinary(url,
+                    encoded_data.c_str(),
+                    encoded_data.size(),
+                    brillo::mime::application::kWwwFormUrlEncoded,
+                    headers,
+                    transport,
+                    success_callback,
+                    error_callback);
+}
+
+RequestID PostFormData(const std::string& url,
+                       std::unique_ptr<FormData> form_data,
+                       const HeaderList& headers,
+                       std::shared_ptr<Transport> transport,
+                       const SuccessCallback& success_callback,
+                       const ErrorCallback& error_callback) {
+  Request request(url, request_type::kPost, transport);
+  request.AddHeaders(headers);
+  brillo::ErrorPtr error;
+  if (!request.AddRequestBodyAsFormData(std::move(form_data), &error)) {
+    transport->RunCallbackAsync(
+        FROM_HERE, base::Bind(error_callback, 0, base::Owned(error.release())));
+    return 0;
+  }
+  return request.GetResponse(success_callback, error_callback);
+}
+
+std::unique_ptr<Response> PostJsonAndBlock(const std::string& url,
+                                           const base::Value* json,
+                                           const HeaderList& headers,
+                                           std::shared_ptr<Transport> transport,
+                                           brillo::ErrorPtr* error) {
+  std::string data;
+  if (json)
+    base::JSONWriter::Write(*json, &data);
+  std::string mime_type = AppendParameter(brillo::mime::application::kJson,
+                                          brillo::mime::parameters::kCharset,
+                                          "utf-8");
+  return PostBinaryAndBlock(
+      url, data.c_str(), data.size(), mime_type, headers, transport, error);
+}
+
+RequestID PostJson(const std::string& url,
+                   std::unique_ptr<base::Value> json,
+                   const HeaderList& headers,
+                   std::shared_ptr<Transport> transport,
+                   const SuccessCallback& success_callback,
+                   const ErrorCallback& error_callback) {
+  std::string data;
+  if (json)
+    base::JSONWriter::Write(*json, &data);
+  std::string mime_type = AppendParameter(brillo::mime::application::kJson,
+                                          brillo::mime::parameters::kCharset,
+                                          "utf-8");
+  return PostBinary(url,
+                    data.c_str(),
+                    data.size(),
+                    mime_type,
+                    headers,
+                    transport,
+                    success_callback,
+                    error_callback);
+}
+
+std::unique_ptr<Response> PatchJsonAndBlock(
+    const std::string& url,
+    const base::Value* json,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error) {
+  std::string data;
+  if (json)
+    base::JSONWriter::Write(*json, &data);
+  std::string mime_type = AppendParameter(brillo::mime::application::kJson,
+                                          brillo::mime::parameters::kCharset,
+                                          "utf-8");
+  return SendRequestAndBlock(request_type::kPatch,
+                             url,
+                             data.c_str(),
+                             data.size(),
+                             mime_type,
+                             headers,
+                             transport,
+                             error);
+}
+
+RequestID PatchJson(const std::string& url,
+                    std::unique_ptr<base::Value> json,
+                    const HeaderList& headers,
+                    std::shared_ptr<Transport> transport,
+                    const SuccessCallback& success_callback,
+                    const ErrorCallback& error_callback) {
+  std::string data;
+  if (json)
+    base::JSONWriter::Write(*json, &data);
+  std::string mime_type =
+      AppendParameter(brillo::mime::application::kJson,
+                      brillo::mime::parameters::kCharset, "utf-8");
+  return SendRequest(request_type::kPatch, url, data.c_str(), data.size(),
+                     mime_type, headers, transport, success_callback,
+                     error_callback);
+}
+
+std::unique_ptr<base::DictionaryValue> ParseJsonResponse(
+    Response* response,
+    int* status_code,
+    brillo::ErrorPtr* error) {
+  std::unique_ptr<base::DictionaryValue> result;
+  if (!response)
+    return result;
+
+  if (status_code)
+    *status_code = response->GetStatusCode();
+
+  // Make sure we have a correct content type. Do not try to parse
+  // binary files, or HTML output. Limit to application/json and text/plain.
+  auto content_type = RemoveParameters(response->GetContentType());
+  if (content_type != brillo::mime::application::kJson &&
+      content_type != brillo::mime::text::kPlain) {
+    brillo::Error::AddTo(error, FROM_HERE, brillo::errors::json::kDomain,
+                         "non_json_content_type",
+                         "Unexpected response content type: " + content_type);
+    return result;
+  }
+
+  std::string json = response->ExtractDataAsString();
+  std::string error_message;
+  auto value = base::JSONReader::ReadAndReturnError(json, base::JSON_PARSE_RFC,
+                                                    nullptr, &error_message);
+  if (!value) {
+    brillo::Error::AddToPrintf(error, FROM_HERE, brillo::errors::json::kDomain,
+                               brillo::errors::json::kParseError,
+                               "Error '%s' occurred parsing JSON string '%s'",
+                               error_message.c_str(), json.c_str());
+    return result;
+  }
+  result = base::DictionaryValue::From(std::move(value));
+  if (!result) {
+    brillo::Error::AddToPrintf(error, FROM_HERE, brillo::errors::json::kDomain,
+                               brillo::errors::json::kObjectExpected,
+                               "Response is not a valid JSON object: '%s'",
+                               json.c_str());
+  }
+  return result;
+}
+
+std::string GetCanonicalHeaderName(const std::string& name) {
+  std::string canonical_name = name;
+  bool word_begin = true;
+  for (char& c : canonical_name) {
+    if (c == '-') {
+      word_begin = true;
+    } else {
+      if (word_begin) {
+        c = toupper(c);
+      } else {
+        c = tolower(c);
+      }
+      word_begin = false;
+    }
+  }
+  return canonical_name;
+}
+
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/http_utils.h b/libbrillo/brillo/http/http_utils.h
new file mode 100644
index 0000000..e09bab8
--- /dev/null
+++ b/libbrillo/brillo/http/http_utils.h
@@ -0,0 +1,319 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_HTTP_UTILS_H_
+#define LIBBRILLO_BRILLO_HTTP_HTTP_UTILS_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <brillo/brillo_export.h>
+#include <brillo/errors/error.h>
+#include <brillo/http/http_form_data.h>
+#include <brillo/http/http_request.h>
+
+namespace base {
+class Value;
+class DictionaryValue;
+}  // namespace base
+
+namespace brillo {
+namespace http {
+
+using FormFieldList = std::vector<std::pair<std::string, std::string>>;
+
+////////////////////////////////////////////////////////////////////////////////
+// The following are simple utility helper functions for common HTTP operations
+// that use http::Request object behind the scenes and set it up accordingly.
+// The values for request method, data MIME type, request header names should
+// not be directly encoded in most cases, but use predefined constants from
+// http_request.h.
+// So, instead of calling:
+//    SendRequestAndBlock("POST",
+//                        "http://url",
+//                        "data", 4,
+//                        "text/plain",
+//                        {{"Authorization", "Bearer TOKEN"}},
+//                        transport, error);
+// You should do use this instead:
+//    SendRequestAndBlock(brillo::http::request_type::kPost,
+//                        "http://url",
+//                        "data", 4,
+//                        brillo::mime::text::kPlain,
+//                        {{brillo::http::request_header::kAuthorization,
+//                          "Bearer TOKEN"}},
+//                        transport, error);
+//
+// For more advanced functionality you need to use Request/Response objects
+// directly.
+////////////////////////////////////////////////////////////////////////////////
+
+// Performs a generic HTTP request with binary data. Success status,
+// returned data and additional information (such as returned HTTP headers)
+// can be obtained from the returned Response object.
+BRILLO_EXPORT std::unique_ptr<Response> SendRequestAndBlock(
+    const std::string& method,
+    const std::string& url,
+    const void* data,
+    size_t data_size,
+    const std::string& mime_type,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error);
+
+// Same as above, but without sending the request body.
+// This is especially useful for requests like "GET" and "HEAD".
+BRILLO_EXPORT std::unique_ptr<Response> SendRequestWithNoDataAndBlock(
+    const std::string& method,
+    const std::string& url,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error);
+
+// Same as above but asynchronous. On success, |success_callback| is called
+// with the response object. On failure, |error_callback| is called with the
+// error details.
+// Returns the ID of the request which can be used to cancel the pending
+// request using Transport::CancelRequest().
+BRILLO_EXPORT RequestID SendRequest(
+    const std::string& method,
+    const std::string& url,
+    StreamPtr stream,
+    const std::string& mime_type,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback);
+
+// Same as above, but takes a memory buffer. The pointer should be valid only
+// until the function returns. The data is copied into an internal buffer to be
+// available for the duration of the asynchronous operation.
+// Returns the ID of the request which can be used to cancel the pending
+// request using Transport::CancelRequest().
+BRILLO_EXPORT RequestID SendRequest(
+    const std::string& method,
+    const std::string& url,
+    const void* data,
+    size_t data_size,
+    const std::string& mime_type,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback);
+
+// Asynchronous version of SendRequestNoData().
+// Returns the ID of the request which can be used to cancel the pending
+// request using Transport::CancelRequest().
+BRILLO_EXPORT RequestID SendRequestWithNoData(
+    const std::string& method,
+    const std::string& url,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback);
+
+// Performs a GET request. Success status, returned data and additional
+// information (such as returned HTTP headers) can be obtained from
+// the returned Response object.
+BRILLO_EXPORT std::unique_ptr<Response> GetAndBlock(
+    const std::string& url,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error);
+
+// Asynchronous version of http::Get().
+// Returns the ID of the request which can be used to cancel the pending
+// request using Transport::CancelRequest().
+BRILLO_EXPORT RequestID Get(
+    const std::string& url,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback);
+
+// Performs a HEAD request. Success status and additional
+// information (such as returned HTTP headers) can be obtained from
+// the returned Response object.
+BRILLO_EXPORT std::unique_ptr<Response> HeadAndBlock(
+    const std::string& url,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error);
+
+// Performs an asynchronous HEAD request.
+// Returns the ID of the request which can be used to cancel the pending
+// request using Transport::CancelRequest().
+BRILLO_EXPORT RequestID Head(
+    const std::string& url,
+    std::shared_ptr<Transport> transport,
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback);
+
+// Performs a POST request with binary data. Success status, returned data
+// and additional information (such as returned HTTP headers) can be obtained
+// from the returned Response object.
+BRILLO_EXPORT std::unique_ptr<Response> PostBinaryAndBlock(
+    const std::string& url,
+    const void* data,
+    size_t data_size,
+    const std::string& mime_type,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error);
+
+// Async version of PostBinary().
+// Returns the ID of the request which can be used to cancel the pending
+// request using Transport::CancelRequest().
+BRILLO_EXPORT RequestID PostBinary(
+    const std::string& url,
+    StreamPtr stream,
+    const std::string& mime_type,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback);
+
+// Same as above, but takes a memory buffer. The pointer should be valid only
+// until the function returns. The data is copied into an internal buffer
+// to be available for the duration of the asynchronous operation.
+// Returns the ID of the request which can be used to cancel the pending
+// request using Transport::CancelRequest().
+BRILLO_EXPORT RequestID PostBinary(
+    const std::string& url,
+    const void* data,
+    size_t data_size,
+    const std::string& mime_type,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback);
+
+// Performs a POST request with text data. Success status, returned data
+// and additional information (such as returned HTTP headers) can be obtained
+// from the returned Response object.
+BRILLO_EXPORT std::unique_ptr<Response> PostTextAndBlock(
+    const std::string& url,
+    const std::string& data,
+    const std::string& mime_type,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error);
+
+// Async version of PostText().
+// Returns the ID of the request which can be used to cancel the pending
+// request using Transport::CancelRequest().
+BRILLO_EXPORT RequestID PostText(
+    const std::string& url,
+    const std::string& data,
+    const std::string& mime_type,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback);
+
+// Performs a POST request with form data. Success status, returned data
+// and additional information (such as returned HTTP headers) can be obtained
+// from the returned Response object. The form data is a list of key/value
+// pairs. The data is posed as "application/x-www-form-urlencoded".
+BRILLO_EXPORT std::unique_ptr<Response> PostFormDataAndBlock(
+    const std::string& url,
+    const FormFieldList& data,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error);
+
+// Async version of PostFormData() above.
+// Returns the ID of the request which can be used to cancel the pending
+// request using Transport::CancelRequest().
+BRILLO_EXPORT RequestID PostFormData(
+    const std::string& url,
+    const FormFieldList& data,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback);
+
+// Performs a POST request with form data, including binary file uploads.
+// Success status, returned data and additional information (such as returned
+// HTTP headers) can be obtained from the returned Response object.
+// The data is posed as "multipart/form-data".
+BRILLO_EXPORT std::unique_ptr<Response> PostFormDataAndBlock(
+    const std::string& url,
+    std::unique_ptr<FormData> form_data,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error);
+
+// Async version of PostFormData() above.
+// Returns the ID of the request which can be used to cancel the pending
+// request using Transport::CancelRequest().
+BRILLO_EXPORT RequestID PostFormData(
+    const std::string& url,
+    std::unique_ptr<FormData> form_data,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback);
+
+// Performs a POST request with JSON data. Success status, returned data
+// and additional information (such as returned HTTP headers) can be obtained
+// from the returned Response object. If a JSON response is expected,
+// use ParseJsonResponse() method on the returned Response object.
+BRILLO_EXPORT std::unique_ptr<Response> PostJsonAndBlock(
+    const std::string& url,
+    const base::Value* json,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error);
+
+// Async version of PostJson().
+// Returns the ID of the request which can be used to cancel the pending
+// request using Transport::CancelRequest().
+BRILLO_EXPORT RequestID PostJson(
+    const std::string& url,
+    std::unique_ptr<base::Value> json,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback);
+
+// Performs a PATCH request with JSON data. Success status, returned data
+// and additional information (such as returned HTTP headers) can be obtained
+// from the returned Response object. If a JSON response is expected,
+// use ParseJsonResponse() method on the returned Response object.
+BRILLO_EXPORT std::unique_ptr<Response> PatchJsonAndBlock(
+    const std::string& url,
+    const base::Value* json,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    brillo::ErrorPtr* error);
+
+// Async version of PatchJson().
+// Returns the ID of the request which can be used to cancel the pending
+// request using Transport::CancelRequest().
+BRILLO_EXPORT RequestID PatchJson(
+    const std::string& url,
+    std::unique_ptr<base::Value> json,
+    const HeaderList& headers,
+    std::shared_ptr<Transport> transport,
+    const SuccessCallback& success_callback,
+    const ErrorCallback& error_callback);
+
+// Given an http::Response object, parse the body data into Json object.
+// Returns null if failed. Optional |error| can be passed in to
+// get the extended error information as to why the parse failed.
+BRILLO_EXPORT std::unique_ptr<base::DictionaryValue> ParseJsonResponse(
+    Response* response,
+    int* status_code,
+    brillo::ErrorPtr* error);
+
+// Converts a request header name to canonical form (lowercase with uppercase
+// first letter and each letter after a hyphen ('-')).
+// "content-TYPE" will be converted to "Content-Type".
+BRILLO_EXPORT std::string GetCanonicalHeaderName(const std::string& name);
+
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_HTTP_UTILS_H_
diff --git a/libbrillo/brillo/http/http_utils_unittest.cc b/libbrillo/brillo/http/http_utils_unittest.cc
new file mode 100644
index 0000000..376ba53
--- /dev/null
+++ b/libbrillo/brillo/http/http_utils_unittest.cc
@@ -0,0 +1,502 @@
+// Copyright 2014 The Chromium OS 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 <numeric>
+#include <string>
+#include <vector>
+
+#include <base/values.h>
+#include <brillo/bind_lambda.h>
+#include <brillo/http/http_transport_fake.h>
+#include <brillo/http/http_utils.h>
+#include <brillo/mime_utils.h>
+#include <brillo/strings/string_utils.h>
+#include <brillo/url_utils.h>
+#include <gtest/gtest.h>
+
+namespace brillo {
+namespace http {
+
+static const char kFakeUrl[] = "http://localhost";
+static const char kEchoUrl[] = "http://localhost/echo";
+static const char kMethodEchoUrl[] = "http://localhost/echo/method";
+
+///////////////////// Generic helper request handlers /////////////////////////
+// Returns the request data back with the same content type.
+static void EchoDataHandler(const fake::ServerRequest& request,
+                            fake::ServerResponse* response) {
+  response->Reply(status_code::Ok,
+                  request.GetData(),
+                  request.GetHeader(request_header::kContentType));
+}
+
+// Returns the request method as a plain text response.
+static void EchoMethodHandler(const fake::ServerRequest& request,
+                              fake::ServerResponse* response) {
+  response->ReplyText(
+      status_code::Ok, request.GetMethod(), brillo::mime::text::kPlain);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+TEST(HttpUtils, SendRequest_BinaryData) {
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(
+      kEchoUrl, request_type::kPost, base::Bind(EchoDataHandler));
+
+  // Test binary data round-tripping.
+  std::vector<uint8_t> custom_data{0xFF, 0x00, 0x80, 0x40, 0xC0, 0x7F};
+  auto response =
+      http::SendRequestAndBlock(request_type::kPost,
+                                kEchoUrl,
+                                custom_data.data(),
+                                custom_data.size(),
+                                brillo::mime::application::kOctet_stream,
+                                {},
+                                transport,
+                                nullptr);
+  EXPECT_TRUE(response->IsSuccessful());
+  EXPECT_EQ(brillo::mime::application::kOctet_stream,
+            response->GetContentType());
+  EXPECT_EQ(custom_data, response->ExtractData());
+}
+
+TEST(HttpUtils, SendRequestAsync_BinaryData) {
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(
+      kEchoUrl, request_type::kPost, base::Bind(EchoDataHandler));
+
+  // Test binary data round-tripping.
+  std::vector<uint8_t> custom_data{0xFF, 0x00, 0x80, 0x40, 0xC0, 0x7F};
+  auto success_callback = [](const std::vector<uint8_t>& custom_data,
+                             RequestID /* id */,
+                             std::unique_ptr<http::Response> response) {
+    EXPECT_TRUE(response->IsSuccessful());
+    EXPECT_EQ(brillo::mime::application::kOctet_stream,
+              response->GetContentType());
+    EXPECT_EQ(custom_data, response->ExtractData());
+  };
+  auto error_callback = [](RequestID /* id */, const Error* /* error */) {
+    FAIL() << "This callback shouldn't have been called";
+  };
+  http::SendRequest(request_type::kPost,
+                    kEchoUrl,
+                    custom_data.data(),
+                    custom_data.size(),
+                    brillo::mime::application::kOctet_stream,
+                    {},
+                    transport,
+                    base::Bind(success_callback, custom_data),
+                    base::Bind(error_callback));
+}
+
+TEST(HttpUtils, SendRequest_Post) {
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
+
+  // Test binary data round-tripping.
+  std::vector<uint8_t> custom_data{0xFF, 0x00, 0x80, 0x40, 0xC0, 0x7F};
+
+  // Check the correct HTTP method used.
+  auto response =
+      http::SendRequestAndBlock(request_type::kPost,
+                                kMethodEchoUrl,
+                                custom_data.data(),
+                                custom_data.size(),
+                                brillo::mime::application::kOctet_stream,
+                                {},
+                                transport,
+                                nullptr);
+  EXPECT_TRUE(response->IsSuccessful());
+  EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
+  EXPECT_EQ(request_type::kPost, response->ExtractDataAsString());
+}
+
+TEST(HttpUtils, SendRequest_Get) {
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
+
+  auto response = http::SendRequestAndBlock(request_type::kGet,
+                                            kMethodEchoUrl,
+                                            nullptr,
+                                            0,
+                                            std::string{},
+                                            {},
+                                            transport,
+                                            nullptr);
+  EXPECT_TRUE(response->IsSuccessful());
+  EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
+  EXPECT_EQ(request_type::kGet, response->ExtractDataAsString());
+}
+
+TEST(HttpUtils, SendRequest_Put) {
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
+
+  auto response = http::SendRequestAndBlock(request_type::kPut,
+                                            kMethodEchoUrl,
+                                            nullptr,
+                                            0,
+                                            std::string{},
+                                            {},
+                                            transport,
+                                            nullptr);
+  EXPECT_TRUE(response->IsSuccessful());
+  EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
+  EXPECT_EQ(request_type::kPut, response->ExtractDataAsString());
+}
+
+TEST(HttpUtils, SendRequest_NotFound) {
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  // Test failed response (URL not found).
+  auto response = http::SendRequestWithNoDataAndBlock(
+      request_type::kGet, "http://blah.com", {}, transport, nullptr);
+  EXPECT_FALSE(response->IsSuccessful());
+  EXPECT_EQ(status_code::NotFound, response->GetStatusCode());
+}
+
+TEST(HttpUtils, SendRequestAsync_NotFound) {
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  // Test failed response (URL not found).
+  auto success_callback =
+      [](RequestID /* request_id */, std::unique_ptr<http::Response> response) {
+    EXPECT_FALSE(response->IsSuccessful());
+    EXPECT_EQ(status_code::NotFound, response->GetStatusCode());
+  };
+  auto error_callback = [](RequestID /* request_id */,
+                           const Error* /* error */) {
+    FAIL() << "This callback shouldn't have been called";
+  };
+  http::SendRequestWithNoData(request_type::kGet,
+                              "http://blah.com",
+                              {},
+                              transport,
+                              base::Bind(success_callback),
+                              base::Bind(error_callback));
+}
+
+TEST(HttpUtils, SendRequest_Headers) {
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+
+  static const char json_echo_url[] = "http://localhost/echo/json";
+  auto JsonEchoHandler =
+      [](const fake::ServerRequest& request, fake::ServerResponse* response) {
+    base::DictionaryValue json;
+    json.SetString("method", request.GetMethod());
+    json.SetString("data", request.GetDataAsString());
+    for (const auto& pair : request.GetHeaders()) {
+      json.SetString("header." + pair.first, pair.second);
+    }
+    response->ReplyJson(status_code::Ok, &json);
+  };
+  transport->AddHandler(json_echo_url, "*", base::Bind(JsonEchoHandler));
+  auto response = http::SendRequestAndBlock(
+      request_type::kPost, json_echo_url, "abcd", 4,
+      brillo::mime::application::kOctet_stream, {
+        {request_header::kCookie, "flavor=vanilla"},
+        {request_header::kIfMatch, "*"},
+      }, transport, nullptr);
+  EXPECT_TRUE(response->IsSuccessful());
+  EXPECT_EQ(brillo::mime::application::kJson,
+            brillo::mime::RemoveParameters(response->GetContentType()));
+  auto json = ParseJsonResponse(response.get(), nullptr, nullptr);
+  std::string value;
+  EXPECT_TRUE(json->GetString("method", &value));
+  EXPECT_EQ(request_type::kPost, value);
+  EXPECT_TRUE(json->GetString("data", &value));
+  EXPECT_EQ("abcd", value);
+  EXPECT_TRUE(json->GetString("header.Cookie", &value));
+  EXPECT_EQ("flavor=vanilla", value);
+  EXPECT_TRUE(json->GetString("header.Content-Type", &value));
+  EXPECT_EQ(brillo::mime::application::kOctet_stream, value);
+  EXPECT_TRUE(json->GetString("header.Content-Length", &value));
+  EXPECT_EQ("4", value);
+  EXPECT_TRUE(json->GetString("header.If-Match", &value));
+  EXPECT_EQ("*", value);
+}
+
+TEST(HttpUtils, Get) {
+  // Sends back the "?test=..." portion of URL.
+  // So if we do GET "http://localhost?test=blah", this handler responds
+  // with "blah" as text/plain.
+  auto GetHandler =
+      [](const fake::ServerRequest& request, fake::ServerResponse* response) {
+    EXPECT_EQ(request_type::kGet, request.GetMethod());
+    EXPECT_EQ("0", request.GetHeader(request_header::kContentLength));
+    EXPECT_EQ("", request.GetHeader(request_header::kContentType));
+    response->ReplyText(status_code::Ok,
+                        request.GetFormField("test"),
+                        brillo::mime::text::kPlain);
+  };
+
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(kFakeUrl, request_type::kGet, base::Bind(GetHandler));
+  transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
+
+  // Make sure Get() actually does the GET request
+  auto response = http::GetAndBlock(kMethodEchoUrl, {}, transport, nullptr);
+  EXPECT_TRUE(response->IsSuccessful());
+  EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
+  EXPECT_EQ(request_type::kGet, response->ExtractDataAsString());
+
+  for (std::string data : {"blah", "some data", ""}) {
+    std::string url = brillo::url::AppendQueryParam(kFakeUrl, "test", data);
+    response = http::GetAndBlock(url, {}, transport, nullptr);
+    EXPECT_EQ(data, response->ExtractDataAsString());
+  }
+}
+
+TEST(HttpUtils, Head) {
+  auto HeadHandler =
+      [](const fake::ServerRequest& request, fake::ServerResponse* response) {
+    EXPECT_EQ(request_type::kHead, request.GetMethod());
+    EXPECT_EQ("0", request.GetHeader(request_header::kContentLength));
+    EXPECT_EQ("", request.GetHeader(request_header::kContentType));
+    response->ReplyText(status_code::Ok, "blah", brillo::mime::text::kPlain);
+  };
+
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(kFakeUrl, request_type::kHead, base::Bind(HeadHandler));
+
+  auto response = http::HeadAndBlock(kFakeUrl, transport, nullptr);
+  EXPECT_TRUE(response->IsSuccessful());
+  EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
+  EXPECT_EQ("", response->ExtractDataAsString());  // Must not have actual body.
+  EXPECT_EQ("4", response->GetHeader(request_header::kContentLength));
+}
+
+TEST(HttpUtils, PostBinary) {
+  auto Handler =
+      [](const fake::ServerRequest& request, fake::ServerResponse* response) {
+    EXPECT_EQ(request_type::kPost, request.GetMethod());
+    EXPECT_EQ("256", request.GetHeader(request_header::kContentLength));
+    EXPECT_EQ(brillo::mime::application::kOctet_stream,
+              request.GetHeader(request_header::kContentType));
+    const auto& data = request.GetData();
+    EXPECT_EQ(256, data.size());
+
+    // Sum up all the bytes.
+    int sum = std::accumulate(data.begin(), data.end(), 0);
+    EXPECT_EQ(32640, sum);  // sum(i, i => [0, 255]) = 32640.
+    response->ReplyText(status_code::Ok, "", brillo::mime::text::kPlain);
+  };
+
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(kFakeUrl, request_type::kPost, base::Bind(Handler));
+
+  /// Fill the data buffer with bytes from 0x00 to 0xFF.
+  std::vector<uint8_t> data(256);
+  std::iota(data.begin(), data.end(), 0);
+
+  auto response = http::PostBinaryAndBlock(kFakeUrl,
+                                           data.data(),
+                                           data.size(),
+                                           mime::application::kOctet_stream,
+                                           {},
+                                           transport,
+                                           nullptr);
+  EXPECT_TRUE(response->IsSuccessful());
+}
+
+TEST(HttpUtils, PostText) {
+  std::string fake_data = "Some data";
+  auto PostHandler = [](const std::string& fake_data,
+                        const fake::ServerRequest& request,
+                        fake::ServerResponse* response) {
+    EXPECT_EQ(request_type::kPost, request.GetMethod());
+    EXPECT_EQ(fake_data.size(),
+              std::stoul(request.GetHeader(request_header::kContentLength)));
+    EXPECT_EQ(brillo::mime::text::kPlain,
+              request.GetHeader(request_header::kContentType));
+    response->ReplyText(status_code::Ok,
+                        request.GetDataAsString(),
+                        brillo::mime::text::kPlain);
+  };
+
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(
+      kFakeUrl, request_type::kPost, base::Bind(PostHandler, fake_data));
+
+  auto response = http::PostTextAndBlock(kFakeUrl,
+                                         fake_data,
+                                         brillo::mime::text::kPlain,
+                                         {},
+                                         transport,
+                                         nullptr);
+  EXPECT_TRUE(response->IsSuccessful());
+  EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
+  EXPECT_EQ(fake_data, response->ExtractDataAsString());
+}
+
+TEST(HttpUtils, PostFormData) {
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(
+      kFakeUrl, request_type::kPost, base::Bind(EchoDataHandler));
+
+  auto response = http::PostFormDataAndBlock(
+      kFakeUrl, {
+          {"key", "value"},
+          {"field", "field value"},
+      }, {}, transport, nullptr);
+  EXPECT_TRUE(response->IsSuccessful());
+  EXPECT_EQ(brillo::mime::application::kWwwFormUrlEncoded,
+            response->GetContentType());
+  EXPECT_EQ("key=value&field=field+value", response->ExtractDataAsString());
+}
+
+TEST(HttpUtils, PostMultipartFormData) {
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(
+      kFakeUrl, request_type::kPost, base::Bind(EchoDataHandler));
+
+  std::unique_ptr<FormData> form_data{new FormData{"boundary123"}};
+  form_data->AddTextField("key1", "value1");
+  form_data->AddTextField("key2", "value2");
+  std::string expected_content_type = form_data->GetContentType();
+  auto response = http::PostFormDataAndBlock(
+      kFakeUrl, std::move(form_data), {}, transport, nullptr);
+  EXPECT_TRUE(response->IsSuccessful());
+  EXPECT_EQ(expected_content_type, response->GetContentType());
+  const char expected_value[] =
+      "--boundary123\r\n"
+      "Content-Disposition: form-data; name=\"key1\"\r\n"
+      "\r\n"
+      "value1\r\n"
+      "--boundary123\r\n"
+      "Content-Disposition: form-data; name=\"key2\"\r\n"
+      "\r\n"
+      "value2\r\n"
+      "--boundary123--";
+  EXPECT_EQ(expected_value, response->ExtractDataAsString());
+}
+
+TEST(HttpUtils, PostPatchJson) {
+  auto JsonHandler =
+      [](const fake::ServerRequest& request, fake::ServerResponse* response) {
+    auto mime_type = brillo::mime::RemoveParameters(
+        request.GetHeader(request_header::kContentType));
+    EXPECT_EQ(brillo::mime::application::kJson, mime_type);
+    response->ReplyJson(
+        status_code::Ok,
+        {
+          {"method", request.GetMethod()}, {"data", request.GetDataAsString()},
+        });
+  };
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(kFakeUrl, "*", base::Bind(JsonHandler));
+
+  base::DictionaryValue json;
+  json.SetString("key1", "val1");
+  json.SetString("key2", "val2");
+  std::string value;
+
+  // Test POST
+  auto response =
+      http::PostJsonAndBlock(kFakeUrl, &json, {}, transport, nullptr);
+  auto resp_json = http::ParseJsonResponse(response.get(), nullptr, nullptr);
+  EXPECT_NE(nullptr, resp_json.get());
+  EXPECT_TRUE(resp_json->GetString("method", &value));
+  EXPECT_EQ(request_type::kPost, value);
+  EXPECT_TRUE(resp_json->GetString("data", &value));
+  EXPECT_EQ("{\"key1\":\"val1\",\"key2\":\"val2\"}", value);
+
+  // Test PATCH
+  response = http::PatchJsonAndBlock(kFakeUrl, &json, {}, transport, nullptr);
+  resp_json = http::ParseJsonResponse(response.get(), nullptr, nullptr);
+  EXPECT_NE(nullptr, resp_json.get());
+  EXPECT_TRUE(resp_json->GetString("method", &value));
+  EXPECT_EQ(request_type::kPatch, value);
+  EXPECT_TRUE(resp_json->GetString("data", &value));
+  EXPECT_EQ("{\"key1\":\"val1\",\"key2\":\"val2\"}", value);
+}
+
+TEST(HttpUtils, ParseJsonResponse) {
+  auto JsonHandler =
+      [](const fake::ServerRequest& request, fake::ServerResponse* response) {
+    int status_code = std::stoi(request.GetFormField("code"));
+    response->ReplyJson(status_code, {{"data", request.GetFormField("value")}});
+  };
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(kFakeUrl, request_type::kPost, base::Bind(JsonHandler));
+
+  // Test valid JSON responses (with success or error codes).
+  for (auto item : {"200;data", "400;wrong", "500;Internal Server error"}) {
+    auto pair = brillo::string_utils::SplitAtFirst(item, ";");
+    auto response = http::PostFormDataAndBlock(
+        kFakeUrl, {
+          {"code", pair.first},
+          {"value", pair.second},
+        }, {}, transport, nullptr);
+    int code = 0;
+    auto json = http::ParseJsonResponse(response.get(), &code, nullptr);
+    EXPECT_NE(nullptr, json.get());
+    std::string value;
+    EXPECT_TRUE(json->GetString("data", &value));
+    EXPECT_EQ(pair.first, brillo::string_utils::ToString(code));
+    EXPECT_EQ(pair.second, value);
+  }
+
+  // Test invalid (non-JSON) response.
+  auto response = http::GetAndBlock("http://bad.url", {}, transport, nullptr);
+  EXPECT_EQ(status_code::NotFound, response->GetStatusCode());
+  EXPECT_EQ(brillo::mime::text::kHtml, response->GetContentType());
+  int code = 0;
+  auto json = http::ParseJsonResponse(response.get(), &code, nullptr);
+  EXPECT_EQ(nullptr, json.get());
+  EXPECT_EQ(status_code::NotFound, code);
+}
+
+TEST(HttpUtils, SendRequest_Failure) {
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
+  ErrorPtr error;
+  Error::AddTo(&error, FROM_HERE, "test_domain", "test_code", "Test message");
+  transport->SetCreateConnectionError(std::move(error));
+  error.reset();  // Just to make sure it is empty...
+  auto response = http::SendRequestWithNoDataAndBlock(
+      request_type::kGet, "http://blah.com", {}, transport, &error);
+  EXPECT_EQ(nullptr, response.get());
+  EXPECT_EQ("test_domain", error->GetDomain());
+  EXPECT_EQ("test_code", error->GetCode());
+  EXPECT_EQ("Test message", error->GetMessage());
+}
+
+TEST(HttpUtils, SendRequestAsync_Failure) {
+  std::shared_ptr<fake::Transport> transport(new fake::Transport);
+  transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
+  ErrorPtr error;
+  Error::AddTo(&error, FROM_HERE, "test_domain", "test_code", "Test message");
+  transport->SetCreateConnectionError(std::move(error));
+  auto success_callback =
+      [](RequestID /* request_id */,
+         std::unique_ptr<http::Response> /* response */) {
+    FAIL() << "This callback shouldn't have been called";
+  };
+  auto error_callback = [](RequestID /* request_id */, const Error* error) {
+    EXPECT_EQ("test_domain", error->GetDomain());
+    EXPECT_EQ("test_code", error->GetCode());
+    EXPECT_EQ("Test message", error->GetMessage());
+  };
+  http::SendRequestWithNoData(request_type::kGet,
+                              "http://blah.com",
+                              {},
+                              transport,
+                              base::Bind(success_callback),
+                              base::Bind(error_callback));
+}
+
+TEST(HttpUtils, GetCanonicalHeaderName) {
+  EXPECT_EQ("Foo", GetCanonicalHeaderName("foo"));
+  EXPECT_EQ("Bar", GetCanonicalHeaderName("BaR"));
+  EXPECT_EQ("Baz", GetCanonicalHeaderName("BAZ"));
+  EXPECT_EQ("Foo-Bar", GetCanonicalHeaderName("foo-bar"));
+  EXPECT_EQ("Foo-Bar-Baz", GetCanonicalHeaderName("foo-Bar-BAZ"));
+  EXPECT_EQ("Foo-Bar-Baz", GetCanonicalHeaderName("FOO-BAR-BAZ"));
+  EXPECT_EQ("Foo-Bar-", GetCanonicalHeaderName("fOO-bAR-"));
+  EXPECT_EQ("-Bar", GetCanonicalHeaderName("-bAR"));
+  EXPECT_EQ("", GetCanonicalHeaderName(""));
+  EXPECT_EQ("A-B-C", GetCanonicalHeaderName("a-B-c"));
+}
+
+}  // namespace http
+}  // namespace brillo
diff --git a/libbrillo/brillo/http/mock_connection.h b/libbrillo/brillo/http/mock_connection.h
new file mode 100644
index 0000000..0796a7e
--- /dev/null
+++ b/libbrillo/brillo/http/mock_connection.h
@@ -0,0 +1,51 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_MOCK_CONNECTION_H_
+#define LIBBRILLO_BRILLO_HTTP_MOCK_CONNECTION_H_
+
+#include <memory>
+#include <string>
+
+#include <base/macros.h>
+#include <brillo/http/http_connection.h>
+#include <gmock/gmock.h>
+
+namespace brillo {
+namespace http {
+
+class MockConnection : public Connection {
+ public:
+  using Connection::Connection;
+
+  MOCK_METHOD2(SendHeaders, bool(const HeaderList&, ErrorPtr*));
+  MOCK_METHOD2(MockSetRequestData, bool(Stream*, ErrorPtr*));
+  MOCK_METHOD1(MockSetResponseData, void(Stream*));
+  MOCK_METHOD1(FinishRequest, bool(ErrorPtr*));
+  MOCK_METHOD2(FinishRequestAsync,
+               RequestID(const SuccessCallback&, const ErrorCallback&));
+  MOCK_CONST_METHOD0(GetResponseStatusCode, int());
+  MOCK_CONST_METHOD0(GetResponseStatusText, std::string());
+  MOCK_CONST_METHOD0(GetProtocolVersion, std::string());
+  MOCK_CONST_METHOD1(GetResponseHeader, std::string(const std::string&));
+  MOCK_CONST_METHOD1(MockExtractDataStream, Stream*(brillo::ErrorPtr*));
+
+ private:
+  bool SetRequestData(StreamPtr stream, brillo::ErrorPtr* error) override {
+    return MockSetRequestData(stream.get(), error);
+  }
+  void SetResponseData(StreamPtr stream) override {
+    MockSetResponseData(stream.get());
+  }
+  StreamPtr ExtractDataStream(brillo::ErrorPtr* error) override {
+    return StreamPtr{MockExtractDataStream(error)};
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(MockConnection);
+};
+
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_MOCK_CONNECTION_H_
diff --git a/libbrillo/brillo/http/mock_curl_api.h b/libbrillo/brillo/http/mock_curl_api.h
new file mode 100644
index 0000000..32b6e0d
--- /dev/null
+++ b/libbrillo/brillo/http/mock_curl_api.h
@@ -0,0 +1,59 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_MOCK_CURL_API_H_
+#define LIBBRILLO_BRILLO_HTTP_MOCK_CURL_API_H_
+
+#include <string>
+
+#include <brillo/http/curl_api.h>
+#include <gmock/gmock.h>
+
+namespace brillo {
+namespace http {
+
+// This is a mock for CURL interfaces which allows to mock out the CURL's
+// low-level C APIs in tests by intercepting the virtual function calls on
+// the abstract CurlInterface.
+class MockCurlInterface : public CurlInterface {
+ public:
+  MockCurlInterface() = default;
+
+  MOCK_METHOD0(EasyInit, CURL*());
+  MOCK_METHOD1(EasyCleanup, void(CURL*));
+  MOCK_METHOD3(EasySetOptInt, CURLcode(CURL*, CURLoption, int));
+  MOCK_METHOD3(EasySetOptStr, CURLcode(CURL*, CURLoption, const std::string&));
+  MOCK_METHOD3(EasySetOptPtr, CURLcode(CURL*, CURLoption, void*));
+  MOCK_METHOD3(EasySetOptCallback, CURLcode(CURL*, CURLoption, intptr_t));
+  MOCK_METHOD3(EasySetOptOffT, CURLcode(CURL*, CURLoption, curl_off_t));
+  MOCK_METHOD1(EasyPerform, CURLcode(CURL*));
+  MOCK_CONST_METHOD3(EasyGetInfoInt, CURLcode(CURL*, CURLINFO, int*));
+  MOCK_CONST_METHOD3(EasyGetInfoDbl, CURLcode(CURL*, CURLINFO, double*));
+  MOCK_CONST_METHOD3(EasyGetInfoStr, CURLcode(CURL*, CURLINFO, std::string*));
+  MOCK_CONST_METHOD3(EasyGetInfoPtr, CURLcode(CURL*, CURLINFO, void**));
+  MOCK_CONST_METHOD1(EasyStrError, std::string(CURLcode));
+  MOCK_METHOD0(MultiInit, CURLM*());
+  MOCK_METHOD1(MultiCleanup, CURLMcode(CURLM*));
+  MOCK_METHOD2(MultiInfoRead, CURLMsg*(CURLM*, int*));
+  MOCK_METHOD2(MultiAddHandle, CURLMcode(CURLM*, CURL*));
+  MOCK_METHOD2(MultiRemoveHandle, CURLMcode(CURLM*, CURL*));
+  MOCK_METHOD3(MultiSetSocketCallback,
+               CURLMcode(CURLM*, curl_socket_callback, void*));
+  MOCK_METHOD3(MultiSetTimerCallback,
+               CURLMcode(CURLM*, curl_multi_timer_callback, void*));
+  MOCK_METHOD3(MultiAssign, CURLMcode(CURLM*, curl_socket_t, void*));
+  MOCK_METHOD4(MultiSocketAction, CURLMcode(CURLM*, curl_socket_t, int, int*));
+  MOCK_CONST_METHOD1(MultiStrError, std::string(CURLMcode));
+  MOCK_METHOD2(MultiPerform, CURLMcode(CURLM*, int*));
+  MOCK_METHOD5(MultiWait,
+               CURLMcode(CURLM*, curl_waitfd[], unsigned int, int, int*));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockCurlInterface);
+};
+
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_MOCK_CURL_API_H_
diff --git a/libbrillo/brillo/http/mock_transport.h b/libbrillo/brillo/http/mock_transport.h
new file mode 100644
index 0000000..9bc6c14
--- /dev/null
+++ b/libbrillo/brillo/http/mock_transport.h
@@ -0,0 +1,44 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_HTTP_MOCK_TRANSPORT_H_
+#define LIBBRILLO_BRILLO_HTTP_MOCK_TRANSPORT_H_
+
+#include <memory>
+#include <string>
+
+#include <base/macros.h>
+#include <brillo/http/http_transport.h>
+#include <gmock/gmock.h>
+
+namespace brillo {
+namespace http {
+
+class MockTransport : public Transport {
+ public:
+  MockTransport() = default;
+
+  MOCK_METHOD6(CreateConnection,
+               std::shared_ptr<Connection>(const std::string&,
+                                           const std::string&,
+                                           const HeaderList&,
+                                           const std::string&,
+                                           const std::string&,
+                                           brillo::ErrorPtr*));
+  MOCK_METHOD2(RunCallbackAsync,
+               void(const tracked_objects::Location&, const base::Closure&));
+  MOCK_METHOD3(StartAsyncTransfer, RequestID(Connection*,
+                                             const SuccessCallback&,
+                                             const ErrorCallback&));
+  MOCK_METHOD1(CancelRequest, bool(RequestID));
+  MOCK_METHOD1(SetDefaultTimeout, void(base::TimeDelta));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockTransport);
+};
+
+}  // namespace http
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_HTTP_MOCK_TRANSPORT_H_
diff --git a/libbrillo/brillo/key_value_store.cc b/libbrillo/brillo/key_value_store.cc
new file mode 100644
index 0000000..7840427
--- /dev/null
+++ b/libbrillo/brillo/key_value_store.cc
@@ -0,0 +1,127 @@
+// Copyright (c) 2010 The Chromium OS 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 "brillo/key_value_store.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/files/file_util.h>
+#include <base/files/important_file_writer.h>
+#include <base/strings/string_split.h>
+#include <base/strings/string_util.h>
+#include <brillo/strings/string_utils.h>
+#include <brillo/map_utils.h>
+
+using std::map;
+using std::string;
+using std::vector;
+
+namespace brillo {
+
+namespace {
+
+// Values used for booleans.
+const char kTrueValue[] = "true";
+const char kFalseValue[] = "false";
+
+// Returns a copy of |key| with leading and trailing whitespace removed.
+string TrimKey(const string& key) {
+  string trimmed_key;
+  base::TrimWhitespaceASCII(key, base::TRIM_ALL, &trimmed_key);
+  CHECK(!trimmed_key.empty());
+  return trimmed_key;
+}
+
+}  // namespace
+
+bool KeyValueStore::Load(const base::FilePath& path) {
+  string file_data;
+  if (!base::ReadFileToString(path, &file_data))
+    return false;
+  return LoadFromString(file_data);
+}
+
+bool KeyValueStore::LoadFromString(const std::string& data) {
+  // Split along '\n', then along '='.
+  vector<string> lines = base::SplitString(data, "\n", base::KEEP_WHITESPACE,
+                                           base::SPLIT_WANT_ALL);
+  for (auto it = lines.begin(); it != lines.end(); ++it) {
+    std::string line;
+    base::TrimWhitespaceASCII(*it, base::TRIM_LEADING, &line);
+    if (line.empty() || line.front() == '#')
+      continue;
+
+    std::string key;
+    std::string value;
+    if (!string_utils::SplitAtFirst(line, "=", &key, &value, false))
+      return false;
+
+    base::TrimWhitespaceASCII(key, base::TRIM_TRAILING, &key);
+    if (key.empty())
+      return false;
+
+    // Append additional lines to the value as long as we see trailing
+    // backslashes.
+    while (!value.empty() && value.back() == '\\') {
+      ++it;
+      if (it == lines.end() || it->empty())
+        return false;
+      value.pop_back();
+      value += *it;
+    }
+
+    store_[key] = value;
+  }
+  return true;
+}
+
+bool KeyValueStore::Save(const base::FilePath& path) const {
+  return base::ImportantFileWriter::WriteFileAtomically(path, SaveToString());
+}
+
+string KeyValueStore::SaveToString() const {
+  string data;
+  for (const auto& key_value : store_)
+    data += key_value.first + "=" + key_value.second + "\n";
+  return data;
+}
+
+bool KeyValueStore::GetString(const string& key, string* value) const {
+  const auto key_value = store_.find(TrimKey(key));
+  if (key_value == store_.end())
+    return false;
+  *value = key_value->second;
+  return true;
+}
+
+void KeyValueStore::SetString(const string& key, const string& value) {
+  store_[TrimKey(key)] = value;
+}
+
+bool KeyValueStore::GetBoolean(const string& key, bool* value) const {
+  string string_value;
+  if (!GetString(key, &string_value))
+    return false;
+
+  if (string_value == kTrueValue) {
+    *value = true;
+    return true;
+  } else if (string_value == kFalseValue) {
+    *value = false;
+    return true;
+  }
+  return false;
+}
+
+void KeyValueStore::SetBoolean(const string& key, bool value) {
+  SetString(key, value ? kTrueValue : kFalseValue);
+}
+
+std::vector<std::string> KeyValueStore::GetKeys() const {
+  return GetMapKeysAsVector(store_);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/key_value_store.h b/libbrillo/brillo/key_value_store.h
new file mode 100644
index 0000000..cc5fa40
--- /dev/null
+++ b/libbrillo/brillo/key_value_store.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// These functions can parse a blob of data that's formatted as a simple
+// key value store. Each key/value pair is stored on its own line and
+// separated by the first '=' on the line.
+
+#ifndef LIBBRILLO_BRILLO_KEY_VALUE_STORE_H_
+#define LIBBRILLO_BRILLO_KEY_VALUE_STORE_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/files/file_path.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+class BRILLO_EXPORT KeyValueStore {
+ public:
+  // Creates an empty KeyValueStore.
+  KeyValueStore() = default;
+  virtual ~KeyValueStore() = default;
+
+  // Loads the key=value pairs from the given |path|. Lines starting with '#'
+  // and empty lines are ignored, and whitespace around keys is trimmed.
+  // Trailing backslashes may be used to extend values across multiple lines.
+  // Adds all the read key=values to the store, overriding those already defined
+  // but persisting the ones that aren't present on the passed file. Returns
+  // whether reading the file succeeded.
+  bool Load(const base::FilePath& path);
+
+  // Loads the key=value pairs parsing the text passed in |data|. See Load() for
+  // details.
+  // Returns whether the parsing succeeded.
+  bool LoadFromString(const std::string& data);
+
+  // Saves the current store to the given |path| file. See SaveToString() for
+  // details on the formate of the created file.
+  // Returns whether the file creation succeeded.
+  bool Save(const base::FilePath& path) const;
+
+  // Returns a string with the contents of the store as key=value lines.
+  // Calling LoadFromString() and then SaveToString() may result in different
+  // result if the original string contained backslash-terminated lines (i.e.
+  // these values will be rewritten on single lines), comments or empty lines.
+  std::string SaveToString() const;
+
+  // Getter for the given key. Returns whether the key was found on the store.
+  bool GetString(const std::string& key, std::string* value) const;
+
+  // Setter for the given key. It overrides the key if already exists.
+  void SetString(const std::string& key, const std::string& value);
+
+  // Boolean getter. Returns whether the key was found on the store and if it
+  // has a valid value ("true" or "false").
+  bool GetBoolean(const std::string& key, bool* value) const;
+
+  // Boolean setter. Sets the value as "true" or "false".
+  void SetBoolean(const std::string& key, bool value);
+
+  // Retrieves the keys for all values currently stored in the map.
+  std::vector<std::string> GetKeys() const;
+
+ private:
+  // The map storing all the key-value pairs.
+  std::map<std::string, std::string> store_;
+
+  DISALLOW_COPY_AND_ASSIGN(KeyValueStore);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_KEY_VALUE_STORE_H_
diff --git a/libbrillo/brillo/key_value_store_unittest.cc b/libbrillo/brillo/key_value_store_unittest.cc
new file mode 100644
index 0000000..cd18e89
--- /dev/null
+++ b/libbrillo/brillo/key_value_store_unittest.cc
@@ -0,0 +1,192 @@
+// Copyright (c) 2010 The Chromium OS 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 <brillo/key_value_store.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <base/logging.h>
+#include <base/strings/string_util.h>
+#include <brillo/map_utils.h>
+#include <gtest/gtest.h>
+
+using base::FilePath;
+using base::ReadFileToString;
+using std::map;
+using std::string;
+using std::vector;
+
+namespace brillo {
+
+class KeyValueStoreTest : public ::testing::Test {
+ protected:
+  // Returns the value from |store_| corresponding to |key|, or an empty string
+  // if the key is not present. Crashes if the store returns an empty value.
+  string GetNonemptyStringValue(const string& key) {
+    string value;
+    if (store_.GetString(key, &value))
+      CHECK(!value.empty());
+    return value;
+  }
+
+  KeyValueStore store_;  // KeyValueStore under test.
+};
+
+TEST_F(KeyValueStoreTest, LoadAndSaveFromFile) {
+  base::ScopedTempDir temp_dir_;
+  CHECK(temp_dir_.CreateUniqueTempDir());
+  base::FilePath temp_file_ = temp_dir_.path().Append("temp.conf");
+  base::FilePath saved_temp_file_ = temp_dir_.path().Append("saved_temp.conf");
+
+  string blob = "A=B\n# Comment\n";
+  ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
+  ASSERT_TRUE(store_.Load(temp_file_));
+
+  string value;
+  EXPECT_TRUE(store_.GetString("A", &value));
+  EXPECT_EQ("B", value);
+
+  ASSERT_TRUE(store_.Save(saved_temp_file_));
+  string read_blob;
+  ASSERT_TRUE(ReadFileToString(FilePath(saved_temp_file_), &read_blob));
+  EXPECT_EQ("A=B\n", read_blob);
+}
+
+TEST_F(KeyValueStoreTest, CommentsAreIgnored) {
+  EXPECT_TRUE(store_.LoadFromString(
+      "# comment\nA=B\n\n\n#another=comment\n  # leading spaces\n"));
+  EXPECT_EQ("A=B\n", store_.SaveToString());
+}
+
+TEST_F(KeyValueStoreTest, EmptyTest) {
+  EXPECT_TRUE(store_.LoadFromString(""));
+  EXPECT_EQ("", store_.SaveToString());
+}
+
+TEST_F(KeyValueStoreTest, LoadAndReloadTest) {
+  EXPECT_TRUE(store_.LoadFromString(
+      "A=B\nC=\nFOO=BAR=BAZ\nBAR=BAX\nMISSING=NEWLINE"));
+
+  map<string, string> expected = {{"A", "B"},
+                                  {"C", ""},
+                                  {"FOO", "BAR=BAZ"},
+                                  {"BAR", "BAX"},
+                                  {"MISSING", "NEWLINE"}};
+
+  // Test expected values.
+  string value;
+  for (const auto& it : expected) {
+    EXPECT_TRUE(store_.GetString(it.first, &value));
+    EXPECT_EQ(it.second, value) << "Testing key: " << it.first;
+  }
+
+  // Save, load and test again.
+  KeyValueStore new_store;
+  ASSERT_TRUE(new_store.LoadFromString(store_.SaveToString()));
+
+  for (const auto& it : expected) {
+    EXPECT_TRUE(new_store.GetString(it.first, &value)) << "key: " << it.first;
+    EXPECT_EQ(it.second, value) << "key: " << it.first;
+  }
+}
+
+TEST_F(KeyValueStoreTest, SimpleBooleanTest) {
+  bool result;
+  EXPECT_FALSE(store_.GetBoolean("A", &result));
+
+  store_.SetBoolean("A", true);
+  EXPECT_TRUE(store_.GetBoolean("A", &result));
+  EXPECT_TRUE(result);
+
+  store_.SetBoolean("A", false);
+  EXPECT_TRUE(store_.GetBoolean("A", &result));
+  EXPECT_FALSE(result);
+}
+
+TEST_F(KeyValueStoreTest, BooleanParsingTest) {
+  string blob = "TRUE=true\nfalse=false\nvar=false\nDONT_SHOUT=TRUE\n";
+  EXPECT_TRUE(store_.LoadFromString(blob));
+
+  map<string, bool> expected = {
+      {"TRUE", true}, {"false", false}, {"var", false}};
+  bool value;
+  EXPECT_FALSE(store_.GetBoolean("DONT_SHOUT", &value));
+  string str_value;
+  EXPECT_TRUE(store_.GetString("DONT_SHOUT", &str_value));
+
+  // Test expected values.
+  for (const auto& it : expected) {
+    EXPECT_TRUE(store_.GetBoolean(it.first, &value)) << "key: " << it.first;
+    EXPECT_EQ(it.second, value) << "key: " << it.first;
+  }
+}
+
+TEST_F(KeyValueStoreTest, TrimWhitespaceAroundKey) {
+  EXPECT_TRUE(store_.LoadFromString("  a=1\nb  =2\n c =3\n"));
+
+  EXPECT_EQ("1", GetNonemptyStringValue("a"));
+  EXPECT_EQ("2", GetNonemptyStringValue("b"));
+  EXPECT_EQ("3", GetNonemptyStringValue("c"));
+
+  // Keys should also be trimmed when setting new values.
+  store_.SetString(" foo ", "4");
+  EXPECT_EQ("4", GetNonemptyStringValue("foo"));
+
+  store_.SetBoolean(" bar ", true);
+  bool value = false;
+  ASSERT_TRUE(store_.GetBoolean("bar", &value));
+  EXPECT_TRUE(value);
+}
+
+TEST_F(KeyValueStoreTest, IgnoreWhitespaceLine) {
+  EXPECT_TRUE(store_.LoadFromString("a=1\n \t \nb=2"));
+
+  EXPECT_EQ("1", GetNonemptyStringValue("a"));
+  EXPECT_EQ("2", GetNonemptyStringValue("b"));
+}
+
+TEST_F(KeyValueStoreTest, RejectEmptyKeys) {
+  EXPECT_FALSE(store_.LoadFromString("=1"));
+  EXPECT_FALSE(store_.LoadFromString(" =2"));
+
+  // Trying to set an empty (after trimming) key should fail an assert.
+  EXPECT_DEATH(store_.SetString(" ", "3"), "");
+  EXPECT_DEATH(store_.SetBoolean(" ", "4"), "");
+}
+
+TEST_F(KeyValueStoreTest, RejectBogusLines) {
+  EXPECT_FALSE(store_.LoadFromString("a=1\nbogus\nb=2"));
+}
+
+TEST_F(KeyValueStoreTest, MultilineValue) {
+  EXPECT_TRUE(store_.LoadFromString("a=foo\nb=bar\\\n  baz \\ \nc=3\n"));
+
+  EXPECT_EQ("foo", GetNonemptyStringValue("a"));
+  EXPECT_EQ("bar  baz \\ ", GetNonemptyStringValue("b"));
+  EXPECT_EQ("3", GetNonemptyStringValue("c"));
+}
+
+TEST_F(KeyValueStoreTest, UnterminatedMultilineValue) {
+  EXPECT_FALSE(store_.LoadFromString("a=foo\\"));
+  EXPECT_FALSE(store_.LoadFromString("a=foo\\\n"));
+  EXPECT_FALSE(store_.LoadFromString("a=foo\\\n\n# blah\n"));
+}
+
+TEST_F(KeyValueStoreTest, GetKeys) {
+  map<string, string> entries = {
+    {"1", "apple"}, {"2", "banana"}, {"3", "cherry"}
+  };
+  for (const auto& it : entries) {
+    store_.SetString(it.first, it.second);
+  }
+
+  vector<string> keys = GetMapKeysAsVector(entries);
+  EXPECT_EQ(keys, store_.GetKeys());
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/location_logging.h b/libbrillo/brillo/location_logging.h
new file mode 100644
index 0000000..8e18c05
--- /dev/null
+++ b/libbrillo/brillo/location_logging.h
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_LOCATION_LOGGING_H_
+#define LIBBRILLO_BRILLO_LOCATION_LOGGING_H_
+
+// These macros help to log Location objects in verbose mode.
+
+#include <base/logging.h>
+
+#define VLOG_LOC_STREAM(from_here, verbose_level)                          \
+  logging::LogMessage((from_here).file_name(), (from_here).line_number(),  \
+                      -(verbose_level)).stream()
+
+#define VLOG_LOC(from_here, verbose_level)                                 \
+  LAZY_STREAM(VLOG_LOC_STREAM(from_here, verbose_level),                   \
+              VLOG_IS_ON(verbose_level))
+
+#define DVLOG_LOC(from_here, verbose_level)                                \
+  LAZY_STREAM(VLOG_LOC_STREAM(from_here, verbose_level),                   \
+              ::logging::DEBUG_MODE && VLOG_IS_ON(verbose_level))
+
+#endif  // LIBBRILLO_BRILLO_LOCATION_LOGGING_H_
diff --git a/libbrillo/brillo/make_unique_ptr.h b/libbrillo/brillo/make_unique_ptr.h
new file mode 100644
index 0000000..89f56e6
--- /dev/null
+++ b/libbrillo/brillo/make_unique_ptr.h
@@ -0,0 +1,25 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_MAKE_UNIQUE_PTR_H_
+#define LIBBRILLO_BRILLO_MAKE_UNIQUE_PTR_H_
+
+#include <memory>
+
+namespace brillo {
+
+// A function to convert T* into unique_ptr<T>
+// Doing e.g. make_unique_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for unique_ptr<FooBarBaz<type>>(new FooBarBaz<type>(arg))
+// Basically the same as Chromium's make_scoped_ptr().
+// Deliberately not named "make_unique" to avoid conflicting with the similar,
+// but more complex and semantically different C++14 function.
+template <typename T>
+std::unique_ptr<T> make_unique_ptr(T* ptr) {
+  return std::unique_ptr<T>(ptr);
+}
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_MAKE_UNIQUE_PTR_H_
diff --git a/libbrillo/brillo/map_utils.h b/libbrillo/brillo/map_utils.h
new file mode 100644
index 0000000..a4568f3
--- /dev/null
+++ b/libbrillo/brillo/map_utils.h
@@ -0,0 +1,71 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_MAP_UTILS_H_
+#define LIBBRILLO_BRILLO_MAP_UTILS_H_
+
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+namespace brillo {
+
+// Given an STL map, returns a set containing all keys from the map.
+template<typename T>
+inline std::set<typename T::key_type> GetMapKeys(const T& map) {
+  std::set<typename T::key_type> keys;
+  for (const auto& pair : map)
+    keys.insert(keys.end(), pair.first);  // Map keys are already sorted.
+  return keys;
+}
+
+// Given an STL map, returns a vector containing all keys from the map.
+// The keys in the vector are sorted.
+template<typename T>
+inline std::vector<typename T::key_type> GetMapKeysAsVector(const T& map) {
+  std::vector<typename T::key_type> keys;
+  keys.reserve(map.size());
+  for (const auto& pair : map)
+    keys.push_back(pair.first);
+  return keys;
+}
+
+// Given an STL map, returns a vector containing all values from the map.
+template<typename T>
+inline std::vector<typename T::mapped_type> GetMapValues(const T& map) {
+  std::vector<typename T::mapped_type> values;
+  values.reserve(map.size());
+  for (const auto& pair : map)
+    values.push_back(pair.second);
+  return values;
+}
+
+// Given an STL map, returns a vector of key-value pairs from the map.
+template<typename T>
+inline std::vector<std::pair<typename T::key_type, typename T::mapped_type>>
+MapToVector(const T& map) {
+  std::vector<std::pair<typename T::key_type, typename T::mapped_type>> vector;
+  vector.reserve(map.size());
+  for (const auto& pair : map)
+    vector.push_back(pair);
+  return vector;
+}
+
+// Given an STL map, returns the value associated with a given key or a default
+// value if the key is not present in the map.
+template<typename T>
+inline typename T::mapped_type GetOrDefault(
+    const T& map,
+    typename T::key_type key,
+    const typename T::mapped_type& def) {
+  typename T::const_iterator it = map.find(key);
+  if (it == map.end())
+    return def;
+  return it->second;
+}
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_MAP_UTILS_H_
diff --git a/libbrillo/brillo/map_utils_unittest.cc b/libbrillo/brillo/map_utils_unittest.cc
new file mode 100644
index 0000000..19bda1d
--- /dev/null
+++ b/libbrillo/brillo/map_utils_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2014 The Chromium OS 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 <brillo/map_utils.h>
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+class MapUtilsTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    map_ = {
+        {"key1", 1}, {"key2", 2}, {"key3", 3}, {"key4", 4}, {"key5", 5},
+    };
+  }
+
+  void TearDown() override { map_.clear(); }
+
+  std::map<std::string, int> map_;
+};
+
+TEST_F(MapUtilsTest, GetMapKeys) {
+  std::set<std::string> keys = GetMapKeys(map_);
+  EXPECT_EQ((std::set<std::string>{"key1", "key2", "key3", "key4", "key5"}),
+            keys);
+}
+
+TEST_F(MapUtilsTest, GetMapKeysAsVector) {
+  std::vector<std::string> keys = GetMapKeysAsVector(map_);
+  EXPECT_EQ((std::vector<std::string>{"key1", "key2", "key3", "key4", "key5"}),
+            keys);
+}
+
+TEST_F(MapUtilsTest, GetMapValues) {
+  std::vector<int> values = GetMapValues(map_);
+  EXPECT_EQ((std::vector<int>{1, 2, 3, 4, 5}), values);
+}
+
+TEST_F(MapUtilsTest, MapToVector) {
+  std::vector<std::pair<std::string, int>> elements = MapToVector(map_);
+  std::vector<std::pair<std::string, int>> expected{
+      {"key1", 1}, {"key2", 2}, {"key3", 3}, {"key4", 4}, {"key5", 5},
+  };
+  EXPECT_EQ(expected, elements);
+}
+
+TEST_F(MapUtilsTest, Empty) {
+  std::map<int, double> empty_map;
+  EXPECT_TRUE(GetMapKeys(empty_map).empty());
+  EXPECT_TRUE(GetMapKeysAsVector(empty_map).empty());
+  EXPECT_TRUE(GetMapValues(empty_map).empty());
+  EXPECT_TRUE(MapToVector(empty_map).empty());
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/message_loops/base_message_loop.cc b/libbrillo/brillo/message_loops/base_message_loop.cc
new file mode 100644
index 0000000..4ea0f08
--- /dev/null
+++ b/libbrillo/brillo/message_loops/base_message_loop.cc
@@ -0,0 +1,436 @@
+// Copyright 2015 The Chromium OS 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 <brillo/message_loops/base_message_loop.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifndef __ANDROID_HOST__
+// Used for MISC_MAJOR. Only required for the target and not always available
+// for the host.
+#include <linux/major.h>
+#endif
+
+#include <vector>
+
+#include <base/bind.h>
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/run_loop.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
+
+#include <brillo/location_logging.h>
+#include <brillo/strings/string_utils.h>
+
+using base::Closure;
+
+namespace {
+
+const char kMiscMinorPath[] = "/proc/misc";
+const char kBinderDriverName[] = "binder";
+
+}  // namespace
+
+namespace brillo {
+
+const int BaseMessageLoop::kInvalidMinor = -1;
+const int BaseMessageLoop::kUninitializedMinor = -2;
+
+BaseMessageLoop::BaseMessageLoop() {
+  CHECK(!base::MessageLoop::current())
+      << "You can't create a base::MessageLoopForIO when another "
+         "base::MessageLoop is already created for this thread.";
+  owned_base_loop_.reset(new base::MessageLoopForIO);
+  base_loop_ = owned_base_loop_.get();
+}
+
+BaseMessageLoop::BaseMessageLoop(base::MessageLoopForIO* base_loop)
+    : base_loop_(base_loop) {}
+
+BaseMessageLoop::~BaseMessageLoop() {
+  for (auto& io_task : io_tasks_) {
+    DVLOG_LOC(io_task.second.location(), 1)
+        << "Removing file descriptor watcher task_id " << io_task.first
+        << " leaked on BaseMessageLoop, scheduled from this location.";
+    io_task.second.StopWatching();
+  }
+
+  // Note all pending canceled delayed tasks when destroying the message loop.
+  size_t lazily_deleted_tasks = 0;
+  for (const auto& delayed_task : delayed_tasks_) {
+    if (delayed_task.second.closure.is_null()) {
+      lazily_deleted_tasks++;
+    } else {
+      DVLOG_LOC(delayed_task.second.location, 1)
+          << "Removing delayed task_id " << delayed_task.first
+          << " leaked on BaseMessageLoop, scheduled from this location.";
+    }
+  }
+  if (lazily_deleted_tasks) {
+    LOG(INFO) << "Leaking " << lazily_deleted_tasks << " canceled tasks.";
+  }
+}
+
+MessageLoop::TaskId BaseMessageLoop::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure &task,
+    base::TimeDelta delay) {
+  TaskId task_id =  NextTaskId();
+  bool base_scheduled = base_loop_->task_runner()->PostDelayedTask(
+      from_here,
+      base::Bind(&BaseMessageLoop::OnRanPostedTask,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 task_id),
+      delay);
+  DVLOG_LOC(from_here, 1) << "Scheduling delayed task_id " << task_id
+                          << " to run in " << delay << ".";
+  if (!base_scheduled)
+    return MessageLoop::kTaskIdNull;
+
+  delayed_tasks_.emplace(task_id,
+                         DelayedTask{from_here, task_id, std::move(task)});
+  return task_id;
+}
+
+MessageLoop::TaskId BaseMessageLoop::WatchFileDescriptor(
+    const tracked_objects::Location& from_here,
+    int fd,
+    WatchMode mode,
+    bool persistent,
+    const Closure &task) {
+  // base::MessageLoopForIO CHECKS that "fd >= 0", so we handle that case here.
+  if (fd < 0)
+    return MessageLoop::kTaskIdNull;
+
+  base::MessageLoopForIO::Mode base_mode = base::MessageLoopForIO::WATCH_READ;
+  switch (mode) {
+    case MessageLoop::kWatchRead:
+      base_mode = base::MessageLoopForIO::WATCH_READ;
+      break;
+    case MessageLoop::kWatchWrite:
+      base_mode = base::MessageLoopForIO::WATCH_WRITE;
+      break;
+    default:
+      return MessageLoop::kTaskIdNull;
+  }
+
+  TaskId task_id =  NextTaskId();
+  auto it_bool = io_tasks_.emplace(
+      std::piecewise_construct,
+      std::forward_as_tuple(task_id),
+      std::forward_as_tuple(
+          from_here, this, task_id, fd, base_mode, persistent, task));
+  // This should always insert a new element.
+  DCHECK(it_bool.second);
+  bool scheduled = it_bool.first->second.StartWatching();
+  DVLOG_LOC(from_here, 1)
+      << "Watching fd " << fd << " for "
+      << (mode == MessageLoop::kWatchRead ? "reading" : "writing")
+      << (persistent ? " persistently" : " just once")
+      << " as task_id " << task_id
+      << (scheduled ? " successfully" : " failed.");
+
+  if (!scheduled) {
+    io_tasks_.erase(task_id);
+    return MessageLoop::kTaskIdNull;
+  }
+
+#ifndef __ANDROID_HOST__
+  // Determine if the passed fd is the binder file descriptor. For that, we need
+  // to check that is a special char device and that the major and minor device
+  // numbers match. The binder file descriptor can't be removed and added back
+  // to an epoll group when there's work available to be done by the file
+  // descriptor due to bugs in the binder driver (b/26524111) when used with
+  // epoll. Therefore, we flag the binder fd and never attempt to remove it.
+  // This may cause the binder file descriptor to be attended with higher
+  // priority and cause starvation of other events.
+  struct stat buf;
+  if (fstat(fd, &buf) == 0 &&
+      S_ISCHR(buf.st_mode) &&
+      major(buf.st_rdev) == MISC_MAJOR &&
+      minor(buf.st_rdev) == GetBinderMinor()) {
+    it_bool.first->second.RunImmediately();
+  }
+#endif
+
+  return task_id;
+}
+
+bool BaseMessageLoop::CancelTask(TaskId task_id) {
+  if (task_id == kTaskIdNull)
+    return false;
+  auto delayed_task_it = delayed_tasks_.find(task_id);
+  if (delayed_task_it == delayed_tasks_.end()) {
+    // This might be an IOTask then.
+    auto io_task_it = io_tasks_.find(task_id);
+    if (io_task_it == io_tasks_.end())
+      return false;
+    return io_task_it->second.CancelTask();
+  }
+  // A DelayedTask was found for this task_id at this point.
+
+  // Check if the callback was already canceled but we have the entry in
+  // delayed_tasks_ since it didn't fire yet in the message loop.
+  if (delayed_task_it->second.closure.is_null())
+    return false;
+
+  DVLOG_LOC(delayed_task_it->second.location, 1)
+      << "Removing task_id " << task_id << " scheduled from this location.";
+  // We reset to closure to a null Closure to release all the resources
+  // used by this closure at this point, but we don't remove the task_id from
+  // delayed_tasks_ since we can't tell base::MessageLoopForIO to not run it.
+  delayed_task_it->second.closure = Closure();
+
+  return true;
+}
+
+bool BaseMessageLoop::RunOnce(bool may_block) {
+  run_once_ = true;
+  base::RunLoop run_loop;  // Uses the base::MessageLoopForIO implicitly.
+  base_run_loop_ = &run_loop;
+  if (!may_block)
+    run_loop.RunUntilIdle();
+  else
+    run_loop.Run();
+  base_run_loop_ = nullptr;
+  // If the flag was reset to false, it means a closure was run.
+  if (!run_once_)
+    return true;
+
+  run_once_ = false;
+  return false;
+}
+
+void BaseMessageLoop::Run() {
+  base::RunLoop run_loop;  // Uses the base::MessageLoopForIO implicitly.
+  base_run_loop_ = &run_loop;
+  run_loop.Run();
+  base_run_loop_ = nullptr;
+}
+
+void BaseMessageLoop::BreakLoop() {
+  if (base_run_loop_ == nullptr) {
+    DVLOG(1) << "Message loop not running, ignoring BreakLoop().";
+    return;  // Message loop not running, nothing to do.
+  }
+  base_run_loop_->Quit();
+}
+
+Closure BaseMessageLoop::QuitClosure() const {
+  if (base_run_loop_ == nullptr)
+    return base::Bind(&base::DoNothing);
+  return base_run_loop_->QuitClosure();
+}
+
+MessageLoop::TaskId BaseMessageLoop::NextTaskId() {
+  TaskId res;
+  do {
+    res = ++last_id_;
+    // We would run out of memory before we run out of task ids.
+  } while (!res ||
+           delayed_tasks_.find(res) != delayed_tasks_.end() ||
+           io_tasks_.find(res) != io_tasks_.end());
+  return res;
+}
+
+void BaseMessageLoop::OnRanPostedTask(MessageLoop::TaskId task_id) {
+  auto task_it = delayed_tasks_.find(task_id);
+  DCHECK(task_it != delayed_tasks_.end());
+  if (!task_it->second.closure.is_null()) {
+    DVLOG_LOC(task_it->second.location, 1)
+        << "Running delayed task_id " << task_id
+        << " scheduled from this location.";
+    // Mark the task as canceled while we are running it so CancelTask returns
+    // false.
+    Closure closure = std::move(task_it->second.closure);
+    task_it->second.closure = Closure();
+    closure.Run();
+
+    // If the |run_once_| flag is set, it is because we are instructed to run
+    // only once callback.
+    if (run_once_) {
+      run_once_ = false;
+      BreakLoop();
+    }
+  }
+  delayed_tasks_.erase(task_it);
+}
+
+void BaseMessageLoop::OnFileReadyPostedTask(MessageLoop::TaskId task_id) {
+  auto task_it = io_tasks_.find(task_id);
+  // Even if this task was canceled while we were waiting in the message loop
+  // for this method to run, the entry in io_tasks_ should still be present, but
+  // won't do anything.
+  DCHECK(task_it != io_tasks_.end());
+  task_it->second.OnFileReadyPostedTask();
+}
+
+int BaseMessageLoop::ParseBinderMinor(
+    const std::string& file_contents) {
+  int result = kInvalidMinor;
+  // Split along '\n', then along the ' '. Note that base::SplitString trims all
+  // white spaces at the beginning and end after splitting.
+  std::vector<std::string> lines =
+      base::SplitString(file_contents, "\n", base::TRIM_WHITESPACE,
+                        base::SPLIT_WANT_ALL);
+  for (const std::string& line : lines) {
+    if (line.empty())
+      continue;
+    std::string number;
+    std::string name;
+    if (!string_utils::SplitAtFirst(line, " ", &number, &name, false))
+      continue;
+
+    if (name == kBinderDriverName && base::StringToInt(number, &result))
+      break;
+  }
+  return result;
+}
+
+unsigned int BaseMessageLoop::GetBinderMinor() {
+  if (binder_minor_ != kUninitializedMinor)
+    return binder_minor_;
+
+  std::string proc_misc;
+  if (!base::ReadFileToString(base::FilePath(kMiscMinorPath), &proc_misc))
+    return binder_minor_;
+  binder_minor_ = ParseBinderMinor(proc_misc);
+  return binder_minor_;
+}
+
+BaseMessageLoop::IOTask::IOTask(const tracked_objects::Location& location,
+                                BaseMessageLoop* loop,
+                                MessageLoop::TaskId task_id,
+                                int fd,
+                                base::MessageLoopForIO::Mode base_mode,
+                                bool persistent,
+                                const Closure& task)
+    : location_(location), loop_(loop), task_id_(task_id),
+      fd_(fd), base_mode_(base_mode), persistent_(persistent), closure_(task) {}
+
+bool BaseMessageLoop::IOTask::StartWatching() {
+  return loop_->base_loop_->WatchFileDescriptor(
+      fd_, persistent_, base_mode_, &fd_watcher_, this);
+}
+
+void BaseMessageLoop::IOTask::StopWatching() {
+  // This is safe to call even if we are not watching for it.
+  fd_watcher_.StopWatchingFileDescriptor();
+}
+
+void BaseMessageLoop::IOTask::OnFileCanReadWithoutBlocking(int /* fd */) {
+  OnFileReady();
+}
+
+void BaseMessageLoop::IOTask::OnFileCanWriteWithoutBlocking(int /* fd */) {
+  OnFileReady();
+}
+
+void BaseMessageLoop::IOTask::OnFileReady() {
+  // For file descriptors marked with the immediate_run flag, we don't call
+  // StopWatching() and wait, instead we dispatch the callback immediately.
+  if (immediate_run_) {
+    posted_task_pending_ = true;
+    OnFileReadyPostedTask();
+    return;
+  }
+
+  // When the file descriptor becomes available we stop watching for it and
+  // schedule a task to run the callback from the main loop. The callback will
+  // run using the same scheduler used to run other delayed tasks, avoiding
+  // starvation of the available posted tasks if there are file descriptors
+  // always available. The new posted task will use the same TaskId as the
+  // current file descriptor watching task an could be canceled in either state,
+  // when waiting for the file descriptor or waiting in the main loop.
+  StopWatching();
+  bool base_scheduled = loop_->base_loop_->task_runner()->PostTask(
+      location_,
+      base::Bind(&BaseMessageLoop::OnFileReadyPostedTask,
+                 loop_->weak_ptr_factory_.GetWeakPtr(),
+                 task_id_));
+  posted_task_pending_ = true;
+  if (base_scheduled) {
+    DVLOG_LOC(location_, 1)
+        << "Dispatching task_id " << task_id_ << " for "
+        << (base_mode_ == base::MessageLoopForIO::WATCH_READ ?
+            "reading" : "writing")
+        << " file descriptor " << fd_ << ", scheduled from this location.";
+  } else {
+    // In the rare case that PostTask() fails, we fall back to run it directly.
+    // This would indicate a bigger problem with the message loop setup.
+    LOG(ERROR) << "Error on base::MessageLoopForIO::PostTask().";
+    OnFileReadyPostedTask();
+  }
+}
+
+void BaseMessageLoop::IOTask::OnFileReadyPostedTask() {
+  // We can't access |this| after running the |closure_| since it could call
+  // CancelTask on its own task_id, so we copy the members we need now.
+  BaseMessageLoop* loop_ptr = loop_;
+  DCHECK(posted_task_pending_ = true);
+  posted_task_pending_ = false;
+
+  // If this task was already canceled, the closure will be null and there is
+  // nothing else to do here. This execution doesn't count a step for RunOnce()
+  // unless we have a callback to run.
+  if (closure_.is_null()) {
+    loop_->io_tasks_.erase(task_id_);
+    return;
+  }
+
+  DVLOG_LOC(location_, 1)
+      << "Running task_id " << task_id_ << " for "
+      << (base_mode_ == base::MessageLoopForIO::WATCH_READ ?
+          "reading" : "writing")
+      << " file descriptor " << fd_ << ", scheduled from this location.";
+
+  if (persistent_) {
+    // In the persistent case we just run the callback. If this callback cancels
+    // the task id, we can't access |this| anymore, so we re-start watching the
+    // file descriptor before running the callback, unless this is a fd where
+    // we didn't stop watching the file descriptor when it became available.
+    if (!immediate_run_)
+      StartWatching();
+    closure_.Run();
+  } else {
+    // This will destroy |this|, the fd_watcher and therefore stop watching this
+    // file descriptor.
+    Closure closure_copy = std::move(closure_);
+    loop_->io_tasks_.erase(task_id_);
+    // Run the closure from the local copy we just made.
+    closure_copy.Run();
+  }
+
+  if (loop_ptr->run_once_) {
+    loop_ptr->run_once_ = false;
+    loop_ptr->BreakLoop();
+  }
+}
+
+bool BaseMessageLoop::IOTask::CancelTask() {
+  if (closure_.is_null())
+    return false;
+
+  DVLOG_LOC(location_, 1)
+      << "Removing task_id " << task_id_ << " scheduled from this location.";
+
+  if (!posted_task_pending_) {
+    // Destroying the FileDescriptorWatcher implicitly stops watching the file
+    // descriptor. This will delete our instance.
+    loop_->io_tasks_.erase(task_id_);
+    return true;
+  }
+  // The IOTask is waiting for the message loop to run its delayed task, so
+  // it is not watching for the file descriptor. We release the closure
+  // resources now but keep the IOTask instance alive while we wait for the
+  // callback to run and delete the IOTask.
+  closure_ = Closure();
+  return true;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/message_loops/base_message_loop.h b/libbrillo/brillo/message_loops/base_message_loop.h
new file mode 100644
index 0000000..f615a1b
--- /dev/null
+++ b/libbrillo/brillo/message_loops/base_message_loop.h
@@ -0,0 +1,198 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_MESSAGE_LOOPS_BASE_MESSAGE_LOOP_H_
+#define LIBBRILLO_BRILLO_MESSAGE_LOOPS_BASE_MESSAGE_LOOP_H_
+
+// BaseMessageLoop is a brillo::MessageLoop implementation based on
+// base::MessageLoopForIO. This allows to mix new code using
+// brillo::MessageLoop and legacy code using base::MessageLoopForIO in the
+// same thread and share a single main loop. This disadvantage of using this
+// class is a less efficient implementation of CancelTask() for delayed tasks
+// since base::MessageLoopForIO doesn't provide a way to remove the event.
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include <base/location.h>
+#include <base/memory/weak_ptr.h>
+#include <base/message_loop/message_loop.h>
+#include <base/time/time.h>
+#include <gtest/gtest_prod.h>
+
+#include <brillo/brillo_export.h>
+#include <brillo/message_loops/message_loop.h>
+
+namespace brillo {
+
+class BRILLO_EXPORT BaseMessageLoop : public MessageLoop {
+ public:
+  // Construct a base::MessageLoopForIO message loop instance and use it as
+  // the default message loop for this thread.
+  BaseMessageLoop();
+
+  // Construct a brillo::BaseMessageLoop using the passed base::MessageLoopForIO
+  // instance.
+  explicit BaseMessageLoop(base::MessageLoopForIO* base_loop);
+  ~BaseMessageLoop() override;
+
+  // MessageLoop overrides.
+  TaskId PostDelayedTask(const tracked_objects::Location& from_here,
+                         const base::Closure& task,
+                         base::TimeDelta delay) override;
+  using MessageLoop::PostDelayedTask;
+  TaskId WatchFileDescriptor(const tracked_objects::Location& from_here,
+                             int fd,
+                             WatchMode mode,
+                             bool persistent,
+                             const base::Closure& task) override;
+  using MessageLoop::WatchFileDescriptor;
+  bool CancelTask(TaskId task_id) override;
+  bool RunOnce(bool may_block) override;
+  void Run() override;
+  void BreakLoop() override;
+
+  // Returns a callback that will quit the current message loop. If the message
+  // loop is not running, an empty (null) callback is returned.
+  base::Closure QuitClosure() const;
+
+ private:
+  FRIEND_TEST(BaseMessageLoopTest, ParseBinderMinor);
+
+  static const int kInvalidMinor;
+  static const int kUninitializedMinor;
+
+  // Parses the contents of the file /proc/misc passed in |file_contents| and
+  // returns the minor device number reported for binder. On error or if not
+  // found, returns kInvalidMinor.
+  static int ParseBinderMinor(const std::string& file_contents);
+
+  // Called by base::MessageLoopForIO when is time to call the callback
+  // scheduled with Post*Task() of id |task_id|, even if it was canceled.
+  void OnRanPostedTask(MessageLoop::TaskId task_id);
+
+  // Called from the message loop when the IOTask should run the scheduled
+  // callback. This is a simple wrapper of IOTask::OnFileReadyPostedTask()
+  // posted from the BaseMessageLoop so it is deleted when the BaseMessageLoop
+  // goes out of scope since we can't cancel the callback otherwise.
+  void OnFileReadyPostedTask(MessageLoop::TaskId task_id);
+
+  // Return a new unused task_id.
+  TaskId NextTaskId();
+
+  // Returns binder minor device number.
+  unsigned int GetBinderMinor();
+
+  struct DelayedTask {
+    tracked_objects::Location location;
+
+    MessageLoop::TaskId task_id;
+    base::Closure closure;
+  };
+
+  class IOTask : public base::MessageLoopForIO::Watcher {
+   public:
+    IOTask(const tracked_objects::Location& location,
+           BaseMessageLoop* loop,
+           MessageLoop::TaskId task_id,
+           int fd,
+           base::MessageLoopForIO::Mode base_mode,
+           bool persistent,
+           const base::Closure& task);
+
+    const tracked_objects::Location& location() const { return location_; }
+
+    // Used to start/stop watching the file descriptor while keeping the
+    // IOTask entry available.
+    bool StartWatching();
+    void StopWatching();
+
+    // Called from the message loop as a PostTask() when the file descriptor is
+    // available, scheduled to run from OnFileReady().
+    void OnFileReadyPostedTask();
+
+    // Cancel the IOTask and returns whether it was actually canceled, with the
+    // same semantics as MessageLoop::CancelTask().
+    bool CancelTask();
+
+    // Sets the closure to be run immediately whenever the file descriptor
+    // becomes ready.
+    void RunImmediately() { immediate_run_= true; }
+
+   private:
+    tracked_objects::Location location_;
+    BaseMessageLoop* loop_;
+
+    // These are the arguments passed in the constructor, basically forwarding
+    // all the arguments passed to WatchFileDescriptor() plus the assigned
+    // TaskId for this task.
+    MessageLoop::TaskId task_id_;
+    int fd_;
+    base::MessageLoopForIO::Mode base_mode_;
+    bool persistent_;
+    base::Closure closure_;
+
+    base::MessageLoopForIO::FileDescriptorWatcher fd_watcher_;
+
+    // Tells whether there is a pending call to OnFileReadPostedTask().
+    bool posted_task_pending_{false};
+
+    // Whether the registered callback should be running immediately when the
+    // file descriptor is ready, as opposed to posting a task to the main loop
+    // to prevent starvation.
+    bool immediate_run_{false};
+
+    // base::MessageLoopForIO::Watcher overrides:
+    void OnFileCanReadWithoutBlocking(int fd) override;
+    void OnFileCanWriteWithoutBlocking(int fd) override;
+
+    // Common implementation for both the read and write case.
+    void OnFileReady();
+
+    DISALLOW_COPY_AND_ASSIGN(IOTask);
+  };
+
+  // The base::MessageLoopForIO instance owned by this class, if any. This
+  // is declared first in this class so it is destroyed last.
+  std::unique_ptr<base::MessageLoopForIO> owned_base_loop_;
+
+  // Tasks blocked on a timeout.
+  std::map<MessageLoop::TaskId, DelayedTask> delayed_tasks_;
+
+  // Tasks blocked on I/O.
+  std::map<MessageLoop::TaskId, IOTask> io_tasks_;
+
+  // Flag to mark that we should run the message loop only one iteration.
+  bool run_once_{false};
+
+  // The last used TaskId. While base::MessageLoopForIO doesn't allow to cancel
+  // delayed tasks, we handle that functionality by not running the callback
+  // if it fires at a later point.
+  MessageLoop::TaskId last_id_{kTaskIdNull};
+
+  // The pointer to the libchrome base::MessageLoopForIO we are wrapping with
+  // this interface. If the instance was created from this object, this will
+  // point to that instance.
+  base::MessageLoopForIO* base_loop_;
+
+  // The RunLoop instance used to run the main loop from Run().
+  base::RunLoop* base_run_loop_{nullptr};
+
+  // The binder minor device number. Binder is a "misc" char device with a
+  // dynamically allocated minor number. When uninitialized, this value will
+  // be negative, otherwise, it will hold the minor part of the binder device
+  // number. This is populated by GetBinderMinor().
+  int binder_minor_{kUninitializedMinor};
+
+  // We use a WeakPtrFactory to schedule tasks with the base::MessageLoopForIO
+  // since we can't cancel the callbacks we have scheduled there once this
+  // instance is destroyed.
+  base::WeakPtrFactory<BaseMessageLoop> weak_ptr_factory_{this};
+  DISALLOW_COPY_AND_ASSIGN(BaseMessageLoop);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_MESSAGE_LOOPS_BASE_MESSAGE_LOOP_H_
diff --git a/libbrillo/brillo/message_loops/base_message_loop_unittest.cc b/libbrillo/brillo/message_loops/base_message_loop_unittest.cc
new file mode 100644
index 0000000..9e052a8
--- /dev/null
+++ b/libbrillo/brillo/message_loops/base_message_loop_unittest.cc
@@ -0,0 +1,24 @@
+// Copyright 2016 The Chromium OS 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 <brillo/message_loops/base_message_loop.h>
+
+#include <gtest/gtest.h>
+
+#include <brillo/message_loops/message_loop.h>
+
+namespace brillo {
+
+class BaseMessageLoopTest : public ::testing::Test {};
+
+TEST(BaseMessageLoopTest, ParseBinderMinor) {
+  EXPECT_EQ(57, BaseMessageLoop::ParseBinderMinor(
+      "227 mcelog\n 58 sw_sync\n 59 ashmem\n 57 binder\n239 uhid\n"));
+  EXPECT_EQ(123, BaseMessageLoop::ParseBinderMinor("123 binder\n"));
+
+  EXPECT_EQ(BaseMessageLoop::kInvalidMinor,
+            BaseMessageLoop::ParseBinderMinor("227 foo\n239 bar\n"));
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/message_loops/fake_message_loop.cc b/libbrillo/brillo/message_loops/fake_message_loop.cc
new file mode 100644
index 0000000..4d0f157
--- /dev/null
+++ b/libbrillo/brillo/message_loops/fake_message_loop.cc
@@ -0,0 +1,141 @@
+// Copyright 2015 The Chromium OS 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 <brillo/message_loops/fake_message_loop.h>
+
+#include <base/logging.h>
+#include <brillo/location_logging.h>
+
+namespace brillo {
+
+FakeMessageLoop::FakeMessageLoop(base::SimpleTestClock* clock)
+  : test_clock_(clock) {
+}
+
+MessageLoop::TaskId FakeMessageLoop::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  // If no SimpleTestClock was provided, we use the last time we fired a
+  // callback. In this way, tasks scheduled from a Closure will have the right
+  // time.
+  if (test_clock_)
+    current_time_ = test_clock_->Now();
+  MessageLoop::TaskId current_id = ++last_id_;
+  // FakeMessageLoop is limited to only 2^64 tasks. That should be enough.
+  CHECK(current_id);
+  tasks_.emplace(current_id, ScheduledTask{from_here, false, task});
+  fire_order_.push(std::make_pair(current_time_ + delay, current_id));
+  VLOG_LOC(from_here, 1) << "Scheduling delayed task_id " << current_id
+                         << " to run at " << current_time_ + delay
+                         << " (in " << delay << ").";
+  return current_id;
+}
+
+MessageLoop::TaskId FakeMessageLoop::WatchFileDescriptor(
+    const tracked_objects::Location& from_here,
+    int fd,
+    WatchMode mode,
+    bool persistent,
+    const base::Closure& task) {
+  MessageLoop::TaskId current_id = ++last_id_;
+  // FakeMessageLoop is limited to only 2^64 tasks. That should be enough.
+  CHECK(current_id);
+  tasks_.emplace(current_id, ScheduledTask{from_here, persistent, task});
+  fds_watched_.emplace(std::make_pair(fd, mode), current_id);
+  return current_id;
+}
+
+bool FakeMessageLoop::CancelTask(TaskId task_id) {
+  if (task_id == MessageLoop::kTaskIdNull)
+    return false;
+  bool ret = tasks_.erase(task_id) > 0;
+  VLOG_IF(1, ret) << "Removing task_id " << task_id;
+  return ret;
+}
+
+bool FakeMessageLoop::RunOnce(bool may_block) {
+  if (test_clock_)
+    current_time_ = test_clock_->Now();
+  // Try to fire ready file descriptors first.
+  for (const auto& fd_mode : fds_ready_) {
+    const auto& fd_watched =  fds_watched_.find(fd_mode);
+    if (fd_watched == fds_watched_.end())
+      continue;
+    // The fd_watched->second task might have been canceled and we never removed
+    // it from the fds_watched_, so we fix that now.
+    const auto& scheduled_task_ref = tasks_.find(fd_watched->second);
+    if (scheduled_task_ref == tasks_.end()) {
+      fds_watched_.erase(fd_watched);
+      continue;
+    }
+    VLOG_LOC(scheduled_task_ref->second.location, 1)
+        << "Running task_id " << fd_watched->second
+        << " for watching file descriptor " << fd_mode.first << " for "
+        << (fd_mode.second == MessageLoop::kWatchRead ? "reading" : "writing")
+        << (scheduled_task_ref->second.persistent ?
+            " persistently" : " just once")
+        << " scheduled from this location.";
+    if (scheduled_task_ref->second.persistent) {
+      scheduled_task_ref->second.callback.Run();
+    } else {
+      base::Closure callback = std::move(scheduled_task_ref->second.callback);
+      tasks_.erase(scheduled_task_ref);
+      fds_watched_.erase(fd_watched);
+      callback.Run();
+    }
+    return true;
+  }
+
+  // Try to fire time-based callbacks afterwards.
+  while (!fire_order_.empty() &&
+         (may_block || fire_order_.top().first <= current_time_)) {
+    const auto task_ref = fire_order_.top();
+    fire_order_.pop();
+    // We need to skip tasks in the priority_queue not in the |tasks_| map.
+    // This is normal if the task was canceled, as there is no efficient way
+    // to remove a task from the priority_queue.
+    const auto scheduled_task_ref = tasks_.find(task_ref.second);
+    if (scheduled_task_ref == tasks_.end())
+      continue;
+    // Advance the clock to the task firing time, if needed.
+    if (current_time_ < task_ref.first) {
+      current_time_ = task_ref.first;
+      if (test_clock_)
+        test_clock_->SetNow(current_time_);
+    }
+    // Move the Closure out of the map before delete it. We need to delete the
+    // entry from the map before we call the callback, since calling CancelTask
+    // for the task you are running now should fail and return false.
+    base::Closure callback = std::move(scheduled_task_ref->second.callback);
+    VLOG_LOC(scheduled_task_ref->second.location, 1)
+        << "Running task_id " << task_ref.second
+        << " at time " << current_time_ << " from this location.";
+    tasks_.erase(scheduled_task_ref);
+
+    callback.Run();
+    return true;
+  }
+  return false;
+}
+
+void FakeMessageLoop::SetFileDescriptorReadiness(int fd,
+                                                 WatchMode mode,
+                                                 bool ready) {
+  if (ready)
+    fds_ready_.emplace(fd, mode);
+  else
+    fds_ready_.erase(std::make_pair(fd, mode));
+}
+
+bool FakeMessageLoop::PendingTasks() {
+  for (const auto& task : tasks_) {
+    VLOG_LOC(task.second.location, 1)
+        << "Pending " << (task.second.persistent ? "persistent " : "")
+        << "task_id " << task.first << " scheduled from here.";
+  }
+  return !tasks_.empty();
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/message_loops/fake_message_loop.h b/libbrillo/brillo/message_loops/fake_message_loop.h
new file mode 100644
index 0000000..c8c1313
--- /dev/null
+++ b/libbrillo/brillo/message_loops/fake_message_loop.h
@@ -0,0 +1,99 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_MESSAGE_LOOPS_FAKE_MESSAGE_LOOP_H_
+#define LIBBRILLO_BRILLO_MESSAGE_LOOPS_FAKE_MESSAGE_LOOP_H_
+
+#include <functional>
+#include <map>
+#include <queue>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include <base/location.h>
+#include <base/test/simple_test_clock.h>
+#include <base/time/time.h>
+
+#include <brillo/brillo_export.h>
+#include <brillo/message_loops/message_loop.h>
+
+namespace brillo {
+
+// The FakeMessageLoop implements a message loop that doesn't block or wait for
+// time based tasks to be ready. The tasks are executed in the order they should
+// be executed in a real message loop implementation, but the time is advanced
+// to the time when the first task should be executed instead of blocking.
+// To keep a consistent notion of time for other classes, FakeMessageLoop
+// optionally updates a SimpleTestClock instance when it needs to advance the
+// clock.
+// This message loop implementation is useful for unittests.
+class BRILLO_EXPORT FakeMessageLoop : public MessageLoop {
+ public:
+  // Create a FakeMessageLoop optionally using a SimpleTestClock to update the
+  // time when Run() or RunOnce(true) are called and should block.
+  explicit FakeMessageLoop(base::SimpleTestClock* clock);
+  ~FakeMessageLoop() override = default;
+
+  TaskId PostDelayedTask(const tracked_objects::Location& from_here,
+                         const base::Closure& task,
+                         base::TimeDelta delay) override;
+  using MessageLoop::PostDelayedTask;
+  TaskId WatchFileDescriptor(const tracked_objects::Location& from_here,
+                             int fd,
+                             WatchMode mode,
+                             bool persistent,
+                             const base::Closure& task) override;
+  using MessageLoop::WatchFileDescriptor;
+  bool CancelTask(TaskId task_id) override;
+  bool RunOnce(bool may_block) override;
+
+  // FakeMessageLoop methods:
+
+  // Pretend, for the purpose of the FakeMessageLoop watching for file
+  // descriptors, that the file descriptor |fd| readiness to perform the
+  // operation described by |mode| is |ready|. Initially, no file descriptor
+  // is ready for any operation.
+  void SetFileDescriptorReadiness(int fd, WatchMode mode, bool ready);
+
+  // Return whether there are peding tasks. Useful to check that no
+  // callbacks were leaked.
+  bool PendingTasks();
+
+ private:
+  struct ScheduledTask {
+    tracked_objects::Location location;
+    bool persistent;
+    base::Closure callback;
+  };
+
+  // The sparse list of scheduled pending callbacks.
+  std::map<MessageLoop::TaskId, ScheduledTask> tasks_;
+
+  // Using std::greater<> for the priority_queue means that the top() of the
+  // queue is the lowest (earliest) time, and for the same time, the smallest
+  // TaskId. This determines the order in which the tasks will be fired.
+  std::priority_queue<
+      std::pair<base::Time, MessageLoop::TaskId>,
+      std::vector<std::pair<base::Time, MessageLoop::TaskId>>,
+      std::greater<std::pair<base::Time, MessageLoop::TaskId>>> fire_order_;
+
+  // The bag of watched (fd, mode) pair associated with the TaskId that's
+  // watching them.
+  std::multimap<std::pair<int, WatchMode>, MessageLoop::TaskId> fds_watched_;
+
+  // The set of (fd, mode) pairs that are faked as ready.
+  std::set<std::pair<int, WatchMode>> fds_ready_;
+
+  base::SimpleTestClock* test_clock_ = nullptr;
+  base::Time current_time_ = base::Time::FromDoubleT(1246996800.);
+
+  MessageLoop::TaskId last_id_ = kTaskIdNull;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeMessageLoop);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_MESSAGE_LOOPS_FAKE_MESSAGE_LOOP_H_
diff --git a/libbrillo/brillo/message_loops/fake_message_loop_unittest.cc b/libbrillo/brillo/message_loops/fake_message_loop_unittest.cc
new file mode 100644
index 0000000..1f94a4b
--- /dev/null
+++ b/libbrillo/brillo/message_loops/fake_message_loop_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright 2015 The Chromium OS 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 <brillo/message_loops/fake_message_loop.h>
+
+#include <memory>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/location.h>
+#include <base/test/simple_test_clock.h>
+#include <gtest/gtest.h>
+
+#include <brillo/bind_lambda.h>
+#include <brillo/message_loops/message_loop.h>
+
+using base::Bind;
+using base::Time;
+using base::TimeDelta;
+using std::vector;
+
+namespace brillo {
+
+using TaskId = MessageLoop::TaskId;
+
+class FakeMessageLoopTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    loop_.reset(new FakeMessageLoop(nullptr));
+    EXPECT_TRUE(loop_.get());
+  }
+  void TearDown() override {
+    EXPECT_FALSE(loop_->PendingTasks());
+  }
+
+  base::SimpleTestClock clock_;
+  std::unique_ptr<FakeMessageLoop> loop_;
+};
+
+TEST_F(FakeMessageLoopTest, CancelTaskInvalidValuesTest) {
+  EXPECT_FALSE(loop_->CancelTask(MessageLoop::kTaskIdNull));
+  EXPECT_FALSE(loop_->CancelTask(1234));
+}
+
+TEST_F(FakeMessageLoopTest, PostDelayedTaskRunsInOrder) {
+  vector<int> order;
+  auto callback = [](std::vector<int>* order, int value) {
+    order->push_back(value);
+  };
+  loop_->PostDelayedTask(Bind(callback, base::Unretained(&order), 1),
+                         TimeDelta::FromSeconds(1));
+  loop_->PostDelayedTask(Bind(callback, base::Unretained(&order), 4),
+                         TimeDelta::FromSeconds(4));
+  loop_->PostDelayedTask(Bind(callback, base::Unretained(&order), 3),
+                         TimeDelta::FromSeconds(3));
+  loop_->PostDelayedTask(Bind(callback, base::Unretained(&order), 2),
+                         TimeDelta::FromSeconds(2));
+  // Run until all the tasks are run.
+  loop_->Run();
+  EXPECT_EQ((vector<int>{1, 2, 3, 4}), order);
+}
+
+TEST_F(FakeMessageLoopTest, PostDelayedTaskAdvancesTheTime) {
+  Time start = Time::FromInternalValue(1000000);
+  clock_.SetNow(start);
+  loop_.reset(new FakeMessageLoop(&clock_));
+  loop_->PostDelayedTask(Bind(&base::DoNothing), TimeDelta::FromSeconds(1));
+  loop_->PostDelayedTask(Bind(&base::DoNothing), TimeDelta::FromSeconds(2));
+  EXPECT_FALSE(loop_->RunOnce(false));
+  // If the callback didn't run, the time shouldn't change.
+  EXPECT_EQ(start, clock_.Now());
+
+  // If we run only one callback, the time should be set to the time that
+  // callack ran.
+  EXPECT_TRUE(loop_->RunOnce(true));
+  EXPECT_EQ(start + TimeDelta::FromSeconds(1), clock_.Now());
+
+  // If the clock is advanced manually, we should be able to run the
+  // callback without blocking, since the firing time is in the past.
+  clock_.SetNow(start + TimeDelta::FromSeconds(3));
+  EXPECT_TRUE(loop_->RunOnce(false));
+  // The time should not change even if the callback is due in the past.
+  EXPECT_EQ(start + TimeDelta::FromSeconds(3), clock_.Now());
+}
+
+TEST_F(FakeMessageLoopTest, WatchFileDescriptorWaits) {
+  int fd = 1234;
+  // We will simulate this situation. At the beginning, we will watch for a
+  // file descriptor that won't trigger for 10s. Then we will pretend it is
+  // ready after 10s and expect its callback to run just once.
+  int called = 0;
+  TaskId task_id = loop_->WatchFileDescriptor(
+      FROM_HERE, fd, MessageLoop::kWatchRead, false,
+      Bind([](int* called) { (*called)++; }, base::Unretained(&called)));
+  EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
+
+  auto callback = [](FakeMessageLoop* loop) { loop->BreakLoop(); };
+  EXPECT_NE(
+      MessageLoop::kTaskIdNull,
+      loop_->PostDelayedTask(Bind(callback, base::Unretained(loop_.get())),
+                             TimeDelta::FromSeconds(10)));
+  EXPECT_NE(
+      MessageLoop::kTaskIdNull,
+      loop_->PostDelayedTask(Bind(callback, base::Unretained(loop_.get())),
+                             TimeDelta::FromSeconds(20)));
+  loop_->Run();
+  EXPECT_EQ(0, called);
+
+  loop_->SetFileDescriptorReadiness(fd, MessageLoop::kWatchRead, true);
+  loop_->Run();
+  EXPECT_EQ(1, called);
+  EXPECT_FALSE(loop_->CancelTask(task_id));
+}
+
+TEST_F(FakeMessageLoopTest, PendingTasksTest) {
+  loop_->PostDelayedTask(Bind(&base::DoNothing), TimeDelta::FromSeconds(1));
+  EXPECT_TRUE(loop_->PendingTasks());
+  loop_->Run();
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/message_loops/glib_message_loop.cc b/libbrillo/brillo/message_loops/glib_message_loop.cc
new file mode 100644
index 0000000..20c271d
--- /dev/null
+++ b/libbrillo/brillo/message_loops/glib_message_loop.cc
@@ -0,0 +1,194 @@
+// Copyright 2015 The Chromium OS 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 <brillo/message_loops/glib_message_loop.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <brillo/location_logging.h>
+
+using base::Closure;
+
+namespace brillo {
+
+GlibMessageLoop::GlibMessageLoop() {
+  loop_ = g_main_loop_new(g_main_context_default(), FALSE);
+}
+
+GlibMessageLoop::~GlibMessageLoop() {
+  // Cancel all pending tasks when destroying the message loop.
+  for (const auto& task : tasks_) {
+    DVLOG_LOC(task.second->location, 1)
+        << "Removing task_id " << task.second->task_id
+        << " leaked on GlibMessageLoop, scheduled from this location.";
+    g_source_remove(task.second->source_id);
+  }
+  g_main_loop_unref(loop_);
+}
+
+MessageLoop::TaskId GlibMessageLoop::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure &task,
+    base::TimeDelta delay) {
+  TaskId task_id =  NextTaskId();
+  // Note: While we store persistent = false in the ScheduledTask object, we
+  // don't check it in OnRanPostedTask() since it is always false for delayed
+  // tasks. This is only used for WatchFileDescriptor below.
+  ScheduledTask* scheduled_task = new ScheduledTask{
+    this, from_here, task_id, 0, false, std::move(task)};
+  DVLOG_LOC(from_here, 1) << "Scheduling delayed task_id " << task_id
+                          << " to run in " << delay << ".";
+  scheduled_task->source_id = g_timeout_add_full(
+      G_PRIORITY_DEFAULT,
+      delay.InMillisecondsRoundedUp(),
+      &GlibMessageLoop::OnRanPostedTask,
+      reinterpret_cast<gpointer>(scheduled_task),
+      DestroyPostedTask);
+  tasks_[task_id] = scheduled_task;
+  return task_id;
+}
+
+MessageLoop::TaskId GlibMessageLoop::WatchFileDescriptor(
+    const tracked_objects::Location& from_here,
+    int fd,
+    WatchMode mode,
+    bool persistent,
+    const Closure &task) {
+  // Quick check to see if the fd is valid.
+  if (fcntl(fd, F_GETFD) == -1 && errno == EBADF)
+      return MessageLoop::kTaskIdNull;
+
+  GIOCondition condition = G_IO_NVAL;
+  switch (mode) {
+    case MessageLoop::kWatchRead:
+      condition = static_cast<GIOCondition>(G_IO_IN | G_IO_HUP | G_IO_NVAL);
+      break;
+    case MessageLoop::kWatchWrite:
+      condition = static_cast<GIOCondition>(G_IO_OUT | G_IO_HUP | G_IO_NVAL);
+      break;
+    default:
+      return MessageLoop::kTaskIdNull;
+  }
+
+  // TODO(deymo): Used g_unix_fd_add_full() instead of g_io_add_watch_full()
+  // when/if we switch to glib 2.36 or newer so we don't need to create a
+  // GIOChannel for this.
+  GIOChannel* io_channel = g_io_channel_unix_new(fd);
+  if (!io_channel)
+    return MessageLoop::kTaskIdNull;
+  GError* error = nullptr;
+  GIOStatus status = g_io_channel_set_encoding(io_channel, nullptr, &error);
+  if (status != G_IO_STATUS_NORMAL) {
+    LOG(ERROR) << "GError(" << error->code << "): "
+               << (error->message ? error->message : "(unknown)");
+    g_error_free(error);
+    // g_io_channel_set_encoding() documentation states that this should be
+    // valid in this context (a new io_channel), but enforce the check in
+    // debug mode.
+    DCHECK(status == G_IO_STATUS_NORMAL);
+    return MessageLoop::kTaskIdNull;
+  }
+
+  TaskId task_id =  NextTaskId();
+  ScheduledTask* scheduled_task = new ScheduledTask{
+    this, from_here, task_id, 0, persistent, std::move(task)};
+  scheduled_task->source_id = g_io_add_watch_full(
+      io_channel,
+      G_PRIORITY_DEFAULT,
+      condition,
+      &GlibMessageLoop::OnWatchedFdReady,
+      reinterpret_cast<gpointer>(scheduled_task),
+      DestroyPostedTask);
+  // g_io_add_watch_full() increases the reference count on the newly created
+  // io_channel, so we can dereference it now and it will be free'd once the
+  // source is removed or now if g_io_add_watch_full() failed.
+  g_io_channel_unref(io_channel);
+
+  DVLOG_LOC(from_here, 1)
+      << "Watching fd " << fd << " for "
+      << (mode == MessageLoop::kWatchRead ? "reading" : "writing")
+      << (persistent ? " persistently" : " just once")
+      << " as task_id " << task_id
+      << (scheduled_task->source_id ? " successfully" : " failed.");
+
+  if (!scheduled_task->source_id) {
+    delete scheduled_task;
+    return MessageLoop::kTaskIdNull;
+  }
+  tasks_[task_id] = scheduled_task;
+  return task_id;
+}
+
+bool GlibMessageLoop::CancelTask(TaskId task_id) {
+  if (task_id == kTaskIdNull)
+    return false;
+  const auto task = tasks_.find(task_id);
+  // It is a programmer error to attempt to remove a non-existent source.
+  if (task == tasks_.end())
+    return false;
+  DVLOG_LOC(task->second->location, 1)
+      << "Removing task_id " << task_id << " scheduled from this location.";
+  guint source_id = task->second->source_id;
+  // We remove here the entry from the tasks_ map, the pointer will be deleted
+  // by the g_source_remove() call.
+  tasks_.erase(task);
+  return g_source_remove(source_id);
+}
+
+bool GlibMessageLoop::RunOnce(bool may_block) {
+  return g_main_context_iteration(nullptr, may_block);
+}
+
+void GlibMessageLoop::Run() {
+  g_main_loop_run(loop_);
+}
+
+void GlibMessageLoop::BreakLoop() {
+  g_main_loop_quit(loop_);
+}
+
+MessageLoop::TaskId GlibMessageLoop::NextTaskId() {
+  TaskId res;
+  do {
+    res = ++last_id_;
+    // We would run out of memory before we run out of task ids.
+  } while (!res || tasks_.find(res) != tasks_.end());
+  return res;
+}
+
+gboolean GlibMessageLoop::OnRanPostedTask(gpointer user_data) {
+  ScheduledTask* scheduled_task = reinterpret_cast<ScheduledTask*>(user_data);
+  DVLOG_LOC(scheduled_task->location, 1)
+      << "Running delayed task_id " << scheduled_task->task_id
+      << " scheduled from this location.";
+  // We only need to remove this task_id from the map. DestroyPostedTask will be
+  // called with this same |user_data| where we can delete the ScheduledTask.
+  scheduled_task->loop->tasks_.erase(scheduled_task->task_id);
+  scheduled_task->closure.Run();
+  return FALSE;  // Removes the source since a callback can only be called once.
+}
+
+gboolean GlibMessageLoop::OnWatchedFdReady(GIOChannel *source,
+                                           GIOCondition condition,
+                                           gpointer user_data) {
+  ScheduledTask* scheduled_task = reinterpret_cast<ScheduledTask*>(user_data);
+  DVLOG_LOC(scheduled_task->location, 1)
+      << "Running task_id " << scheduled_task->task_id
+      << " for watching a file descriptor, scheduled from this location.";
+  if (!scheduled_task->persistent) {
+    // We only need to remove this task_id from the map. DestroyPostedTask will
+    // be called with this same |user_data| where we can delete the
+    // ScheduledTask.
+    scheduled_task->loop->tasks_.erase(scheduled_task->task_id);
+  }
+  scheduled_task->closure.Run();
+  return scheduled_task->persistent;
+}
+
+void GlibMessageLoop::DestroyPostedTask(gpointer user_data) {
+  delete reinterpret_cast<ScheduledTask*>(user_data);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/message_loops/glib_message_loop.h b/libbrillo/brillo/message_loops/glib_message_loop.h
new file mode 100644
index 0000000..50fe2ce
--- /dev/null
+++ b/libbrillo/brillo/message_loops/glib_message_loop.h
@@ -0,0 +1,83 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_MESSAGE_LOOPS_GLIB_MESSAGE_LOOP_H_
+#define LIBBRILLO_BRILLO_MESSAGE_LOOPS_GLIB_MESSAGE_LOOP_H_
+
+#include <map>
+#include <memory>
+
+#include <base/location.h>
+#include <base/time/time.h>
+#include <glib.h>
+
+#include <brillo/brillo_export.h>
+#include <brillo/message_loops/message_loop.h>
+
+namespace brillo {
+
+class BRILLO_EXPORT GlibMessageLoop : public MessageLoop {
+ public:
+  GlibMessageLoop();
+  ~GlibMessageLoop() override;
+
+  // MessageLoop overrides.
+  TaskId PostDelayedTask(const tracked_objects::Location& from_here,
+                         const base::Closure& task,
+                         base::TimeDelta delay) override;
+  using MessageLoop::PostDelayedTask;
+  TaskId WatchFileDescriptor(const tracked_objects::Location& from_here,
+                             int fd,
+                             WatchMode mode,
+                             bool persistent,
+                             const base::Closure& task) override;
+  using MessageLoop::WatchFileDescriptor;
+  bool CancelTask(TaskId task_id) override;
+  bool RunOnce(bool may_block) override;
+  void Run() override;
+  void BreakLoop() override;
+
+ private:
+  // Called by the GLib's main loop when is time to call the callback scheduled
+  // with Post*Task(). The pointer to the callback passed when scheduling it is
+  // passed to this function as a gpointer on |user_data|.
+  static gboolean OnRanPostedTask(gpointer user_data);
+
+  // Called by the GLib's main loop when the watched source |source| is
+  // ready to perform the operation given in |condition| without blocking.
+  static gboolean OnWatchedFdReady(GIOChannel *source,
+                                   GIOCondition condition,
+                                   gpointer user_data);
+
+  // Called by the GLib's main loop when the scheduled callback is removed due
+  // to it being executed or canceled.
+  static void DestroyPostedTask(gpointer user_data);
+
+  // Return a new unused task_id.
+  TaskId NextTaskId();
+
+  GMainLoop* loop_;
+
+  struct ScheduledTask {
+    // A pointer to this GlibMessageLoop so we can remove the Task from the
+    // glib callback.
+    GlibMessageLoop* loop;
+    tracked_objects::Location location;
+
+    MessageLoop::TaskId task_id;
+    guint source_id;
+    bool persistent;
+    base::Closure closure;
+  };
+
+  std::map<MessageLoop::TaskId, ScheduledTask*> tasks_;
+
+  MessageLoop::TaskId last_id_ = kTaskIdNull;
+
+  DISALLOW_COPY_AND_ASSIGN(GlibMessageLoop);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_MESSAGE_LOOPS_GLIB_MESSAGE_LOOP_H_
diff --git a/libbrillo/brillo/message_loops/glib_message_loop_unittest.cc b/libbrillo/brillo/message_loops/glib_message_loop_unittest.cc
new file mode 100644
index 0000000..4b72a11
--- /dev/null
+++ b/libbrillo/brillo/message_loops/glib_message_loop_unittest.cc
@@ -0,0 +1,69 @@
+// Copyright 2015 The Chromium OS 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 <brillo/message_loops/glib_message_loop.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <base/bind.h>
+#include <base/location.h>
+#include <base/posix/eintr_wrapper.h>
+#include <gtest/gtest.h>
+
+#include <brillo/bind_lambda.h>
+#include <brillo/message_loops/message_loop.h>
+#include <brillo/message_loops/message_loop_utils.h>
+
+using base::Bind;
+
+namespace brillo {
+
+using TaskId = MessageLoop::TaskId;
+
+class GlibMessageLoopTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    loop_.reset(new GlibMessageLoop());
+    EXPECT_TRUE(loop_.get());
+  }
+
+  std::unique_ptr<GlibMessageLoop> loop_;
+};
+
+// When you watch a file descriptor for reading, the guaranties are that a
+// blocking call to read() on that file descriptor will not block. This should
+// include the case when the other end of a pipe is closed or the file is empty.
+TEST_F(GlibMessageLoopTest, WatchFileDescriptorTriggersWhenEmpty) {
+  int fd = HANDLE_EINTR(open("/dev/null", O_RDONLY));
+  int called = 0;
+  TaskId task_id = loop_->WatchFileDescriptor(
+      FROM_HERE, fd, MessageLoop::kWatchRead, true,
+      Bind([&called] { called++; }));
+  EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
+  EXPECT_NE(0, MessageLoopRunMaxIterations(loop_.get(), 10));
+  EXPECT_LT(2, called);
+  EXPECT_TRUE(loop_->CancelTask(task_id));
+}
+
+// Test that an invalid file descriptor triggers the callback.
+TEST_F(GlibMessageLoopTest, WatchFileDescriptorTriggersWhenInvalid) {
+  int fd = HANDLE_EINTR(open("/dev/zero", O_RDONLY));
+  int called = 0;
+  TaskId task_id = loop_->WatchFileDescriptor(
+      FROM_HERE, fd, MessageLoop::kWatchRead, true,
+      Bind([&called, fd] {
+        if (!called)
+          IGNORE_EINTR(close(fd));
+        called++;
+      }));
+  EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
+  EXPECT_NE(0, MessageLoopRunMaxIterations(loop_.get(), 10));
+  EXPECT_LT(2, called);
+  EXPECT_TRUE(loop_->CancelTask(task_id));
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/message_loops/message_loop.cc b/libbrillo/brillo/message_loops/message_loop.cc
new file mode 100644
index 0000000..3d64ccb
--- /dev/null
+++ b/libbrillo/brillo/message_loops/message_loop.cc
@@ -0,0 +1,63 @@
+// Copyright 2015 The Chromium OS 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 <brillo/message_loops/message_loop.h>
+
+#include <base/lazy_instance.h>
+#include <base/logging.h>
+#include <base/threading/thread_local.h>
+
+namespace brillo {
+
+namespace {
+
+// A lazily created thread local storage for quick access to a thread's message
+// loop, if one exists.  This should be safe and free of static constructors.
+base::LazyInstance<base::ThreadLocalPointer<MessageLoop> >::Leaky lazy_tls_ptr =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+const MessageLoop::TaskId MessageLoop::kTaskIdNull = 0;
+
+MessageLoop* MessageLoop::current() {
+  DCHECK(lazy_tls_ptr.Pointer()->Get() != nullptr) <<
+      "There isn't a MessageLoop for this thread. You need to initialize it "
+      "first.";
+  return lazy_tls_ptr.Pointer()->Get();
+}
+
+bool MessageLoop::ThreadHasCurrent() {
+  return lazy_tls_ptr.Pointer()->Get() != nullptr;
+}
+
+void MessageLoop::SetAsCurrent() {
+  DCHECK(lazy_tls_ptr.Pointer()->Get() == nullptr) <<
+      "There's already a MessageLoop for this thread.";
+  lazy_tls_ptr.Pointer()->Set(this);
+}
+
+void MessageLoop::ReleaseFromCurrent() {
+  DCHECK(lazy_tls_ptr.Pointer()->Get() == this) <<
+      "This is not the MessageLoop bound to the current thread.";
+  lazy_tls_ptr.Pointer()->Set(nullptr);
+}
+
+MessageLoop::~MessageLoop() {
+  if (lazy_tls_ptr.Pointer()->Get() == this)
+    lazy_tls_ptr.Pointer()->Set(nullptr);
+}
+
+void MessageLoop::Run() {
+  // Default implementation is to call RunOnce() blocking until there aren't
+  // more tasks scheduled.
+  while (!should_exit_ && RunOnce(true)) {}
+  should_exit_ = false;
+}
+
+void MessageLoop::BreakLoop() {
+  should_exit_ = true;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/message_loops/message_loop.h b/libbrillo/brillo/message_loops/message_loop.h
new file mode 100644
index 0000000..c7e3586
--- /dev/null
+++ b/libbrillo/brillo/message_loops/message_loop.h
@@ -0,0 +1,135 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_MESSAGE_LOOPS_MESSAGE_LOOP_H_
+#define LIBBRILLO_BRILLO_MESSAGE_LOOPS_MESSAGE_LOOP_H_
+
+#include <string>
+
+#include <base/callback.h>
+#include <base/location.h>
+#include <base/time/time.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+class BRILLO_EXPORT MessageLoop {
+ public:
+  virtual ~MessageLoop();
+
+  // A unique task identifier used to refer to scheduled callbacks.
+  using TaskId = uint64_t;
+
+  // The kNullEventId is reserved for an invalid task and will never be used
+  // to refer to a real task.
+  static const TaskId kTaskIdNull;
+
+  // Return the MessageLoop for the current thread. It is a fatal error to
+  // request the current MessageLoop if SetAsCurrent() was not called on the
+  // current thread. If you really need to, use ThreadHasCurrent() to check if
+  // there is a current thread.
+  static MessageLoop* current();
+
+  // Return whether there is a MessageLoop in the current thread.
+  static bool ThreadHasCurrent();
+
+  // Set this message loop as the current thread main loop. Only one message
+  // loop can be set at a time. Use ReleaseFromCurrent() to release it.
+  void SetAsCurrent();
+
+  // Release this instance from the current thread. This instance must have
+  // been previously set with SetAsCurrent().
+  void ReleaseFromCurrent();
+
+  // Schedule a Closure |task| to be executed after a |delay|. Returns a task
+  // identifier for the scheduled task that can be used to cancel the task
+  // before it is fired by passing it to CancelTask().
+  // In case of an error scheduling the task, the kTaskIdNull is returned.
+  // Note that once the call is executed or canceled, the TaskId could be reused
+  // at a later point.
+  // This methond can only be called from the same thread running the main loop.
+  virtual TaskId PostDelayedTask(const tracked_objects::Location& from_here,
+                                 const base::Closure& task,
+                                 base::TimeDelta delay) = 0;
+  // Variant without the Location for easier usage.
+  TaskId PostDelayedTask(const base::Closure& task, base::TimeDelta delay) {
+    return PostDelayedTask(tracked_objects::Location(), task, delay);
+  }
+
+  // A convenience method to schedule a call with no delay.
+  // This methond can only be called from the same thread running the main loop.
+  TaskId PostTask(const base::Closure& task) {
+    return PostDelayedTask(task, base::TimeDelta());
+  }
+  TaskId PostTask(const tracked_objects::Location& from_here,
+                  const base::Closure& task) {
+    return PostDelayedTask(from_here, task, base::TimeDelta());
+  }
+
+  // Watch mode flag used to watch for file descriptors.
+  enum WatchMode {
+    kWatchRead,
+    kWatchWrite,
+  };
+
+  // Watch a file descriptor |fd| for it to be ready to perform the operation
+  // passed in |mode| without blocking. When that happens, the |task| closure
+  // will be executed. If |persistent| is true, the file descriptor will
+  // continue to be watched and |task| will continue to be called until the task
+  // is canceled with CancelTask().
+  // Returns the TaskId describing this task. In case of error, returns
+  // kTaskIdNull.
+  virtual TaskId WatchFileDescriptor(const tracked_objects::Location& from_here,
+                                     int fd,
+                                     WatchMode mode,
+                                     bool persistent,
+                                     const base::Closure& task) = 0;
+
+  // Convenience function to call WatchFileDescriptor() without a location.
+  TaskId WatchFileDescriptor(int fd,
+                             WatchMode mode,
+                             bool persistent,
+                             const base::Closure& task) {
+    return WatchFileDescriptor(
+        tracked_objects::Location(), fd, mode, persistent, task);
+  }
+
+  // Cancel a scheduled task. Returns whether the task was canceled. For
+  // example, if the callback was already executed (or is being executed) or was
+  // already canceled this method will fail. Note that the TaskId can be reused
+  // after it was executed or cancelled.
+  virtual bool CancelTask(TaskId task_id) = 0;
+
+  // ---------------------------------------------------------------------------
+  // Methods used to run and stop the message loop.
+
+  // Run one iteration of the message loop, dispatching up to one task. The
+  // |may_block| tells whether this method is allowed to block waiting for a
+  // task to be ready to run. Returns whether it ran a task. Note that even
+  // if |may_block| is true, this method can return false immediately if there
+  // are no more tasks registered.
+  virtual bool RunOnce(bool may_block) = 0;
+
+  // Run the main loop until there are no more registered tasks.
+  virtual void Run();
+
+  // Quit the running main loop immediately. This method will make the current
+  // running Run() method to return right after the current task returns back
+  // to the message loop without processing any other task.
+  virtual void BreakLoop();
+
+ protected:
+  MessageLoop() = default;
+
+ private:
+  // Tells whether Run() should quit the message loop in the default
+  // implementation.
+  bool should_exit_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageLoop);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_MESSAGE_LOOPS_MESSAGE_LOOP_H_
diff --git a/libbrillo/brillo/message_loops/message_loop_unittest.cc b/libbrillo/brillo/message_loops/message_loop_unittest.cc
new file mode 100644
index 0000000..7cc2a30
--- /dev/null
+++ b/libbrillo/brillo/message_loops/message_loop_unittest.cc
@@ -0,0 +1,362 @@
+// Copyright 2015 The Chromium OS 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 <brillo/message_loops/message_loop.h>
+
+// These are the common tests for all the brillo::MessageLoop implementations
+// that should conform to this interface's contracts. For extra
+// implementation-specific tests see the particular implementation unittests in
+// the *_unittest.cc files.
+
+#include <memory>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/location.h>
+#include <base/posix/eintr_wrapper.h>
+#include <gtest/gtest.h>
+
+#include <brillo/bind_lambda.h>
+#include <brillo/unittest_utils.h>
+#include <brillo/message_loops/base_message_loop.h>
+#include <brillo/message_loops/glib_message_loop.h>
+#include <brillo/message_loops/message_loop_utils.h>
+
+using base::Bind;
+using base::TimeDelta;
+
+namespace brillo {
+
+using TaskId = MessageLoop::TaskId;
+
+template <typename T>
+class MessageLoopTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    MessageLoopSetUp();
+    EXPECT_TRUE(this->loop_.get());
+  }
+
+  std::unique_ptr<base::MessageLoopForIO> base_loop_;
+
+  std::unique_ptr<MessageLoop> loop_;
+
+ private:
+  // These MessageLoopSetUp() methods are used to setup each MessageLoop
+  // according to its constructor requirements.
+  void MessageLoopSetUp();
+};
+
+template <>
+void MessageLoopTest<GlibMessageLoop>::MessageLoopSetUp() {
+  loop_.reset(new GlibMessageLoop());
+}
+
+template <>
+void MessageLoopTest<BaseMessageLoop>::MessageLoopSetUp() {
+  base_loop_.reset(new base::MessageLoopForIO());
+  loop_.reset(new BaseMessageLoop(base::MessageLoopForIO::current()));
+}
+
+// This setups gtest to run each one of the following TYPED_TEST test cases on
+// on each implementation.
+typedef ::testing::Types<
+  GlibMessageLoop,
+  BaseMessageLoop> MessageLoopTypes;
+TYPED_TEST_CASE(MessageLoopTest, MessageLoopTypes);
+
+
+TYPED_TEST(MessageLoopTest, CancelTaskInvalidValuesTest) {
+  EXPECT_FALSE(this->loop_->CancelTask(MessageLoop::kTaskIdNull));
+  EXPECT_FALSE(this->loop_->CancelTask(1234));
+}
+
+TYPED_TEST(MessageLoopTest, PostTaskTest) {
+  bool called = false;
+  TaskId task_id = this->loop_->PostTask(FROM_HERE,
+                                         Bind([&called]() { called = true; }));
+  EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
+  MessageLoopRunMaxIterations(this->loop_.get(), 100);
+  EXPECT_TRUE(called);
+}
+
+// Tests that we can cancel tasks right after we schedule them.
+TYPED_TEST(MessageLoopTest, PostTaskCancelledTest) {
+  bool called = false;
+  TaskId task_id = this->loop_->PostTask(FROM_HERE,
+                                         Bind([&called]() { called = true; }));
+  EXPECT_TRUE(this->loop_->CancelTask(task_id));
+  MessageLoopRunMaxIterations(this->loop_.get(), 100);
+  EXPECT_FALSE(called);
+  // Can't remove a task you already removed.
+  EXPECT_FALSE(this->loop_->CancelTask(task_id));
+}
+
+TYPED_TEST(MessageLoopTest, PostDelayedTaskRunsEventuallyTest) {
+  bool called = false;
+  TaskId task_id = this->loop_->PostDelayedTask(
+      FROM_HERE,
+      Bind([&called]() { called = true; }),
+      TimeDelta::FromMilliseconds(50));
+  EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
+  MessageLoopRunUntil(this->loop_.get(),
+                      TimeDelta::FromSeconds(10),
+                      Bind([&called]() { return called; }));
+  // Check that the main loop finished before the 10 seconds timeout, so it
+  // finished due to the callback being called and not due to the timeout.
+  EXPECT_TRUE(called);
+}
+
+// Test that you can call the overloaded version of PostDelayedTask from
+// MessageLoop. This is important because only one of the two methods is
+// virtual, so you need to unhide the other when overriding the virtual one.
+TYPED_TEST(MessageLoopTest, PostDelayedTaskWithoutLocation) {
+  this->loop_->PostDelayedTask(Bind(&base::DoNothing), TimeDelta());
+  EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
+}
+
+TYPED_TEST(MessageLoopTest, WatchForInvalidFD) {
+  bool called = false;
+  EXPECT_EQ(MessageLoop::kTaskIdNull, this->loop_->WatchFileDescriptor(
+      FROM_HERE, -1, MessageLoop::kWatchRead, true,
+      Bind([&called] { called = true; })));
+  EXPECT_EQ(MessageLoop::kTaskIdNull, this->loop_->WatchFileDescriptor(
+      FROM_HERE, -1, MessageLoop::kWatchWrite, true,
+      Bind([&called] { called = true; })));
+  EXPECT_EQ(0, MessageLoopRunMaxIterations(this->loop_.get(), 100));
+  EXPECT_FALSE(called);
+}
+
+TYPED_TEST(MessageLoopTest, CancelWatchedFileDescriptor) {
+  ScopedPipe pipe;
+  bool called = false;
+  TaskId task_id = this->loop_->WatchFileDescriptor(
+      FROM_HERE, pipe.reader, MessageLoop::kWatchRead, true,
+      Bind([&called] { called = true; }));
+  EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
+  // The reader end is blocked because we didn't write anything to the writer
+  // end.
+  EXPECT_EQ(0, MessageLoopRunMaxIterations(this->loop_.get(), 100));
+  EXPECT_FALSE(called);
+  EXPECT_TRUE(this->loop_->CancelTask(task_id));
+}
+
+// When you watch a file descriptor for reading, the guaranties are that a
+// blocking call to read() on that file descriptor will not block. This should
+// include the case when the other end of a pipe is closed or the file is empty.
+TYPED_TEST(MessageLoopTest, WatchFileDescriptorTriggersWhenPipeClosed) {
+  ScopedPipe pipe;
+  bool called = false;
+  EXPECT_EQ(0, HANDLE_EINTR(close(pipe.writer)));
+  pipe.writer = -1;
+  TaskId task_id = this->loop_->WatchFileDescriptor(
+      FROM_HERE, pipe.reader, MessageLoop::kWatchRead, true,
+      Bind([&called] { called = true; }));
+  EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
+  // The reader end is not blocked because we closed the writer end so a read on
+  // the reader end would return 0 bytes read.
+  EXPECT_NE(0, MessageLoopRunMaxIterations(this->loop_.get(), 10));
+  EXPECT_TRUE(called);
+  EXPECT_TRUE(this->loop_->CancelTask(task_id));
+}
+
+// When a WatchFileDescriptor task is scheduled with |persistent| = true, we
+// should keep getting a call whenever the file descriptor is ready.
+TYPED_TEST(MessageLoopTest, WatchFileDescriptorPersistently) {
+  ScopedPipe pipe;
+  EXPECT_EQ(1, HANDLE_EINTR(write(pipe.writer, "a", 1)));
+
+  int called = 0;
+  TaskId task_id = this->loop_->WatchFileDescriptor(
+      FROM_HERE, pipe.reader, MessageLoop::kWatchRead, true,
+      Bind([&called] { called++; }));
+  EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
+  // We let the main loop run for 20 iterations to give it enough iterations to
+  // verify that our callback was called more than one. We only check that our
+  // callback is called more than once.
+  EXPECT_EQ(20, MessageLoopRunMaxIterations(this->loop_.get(), 20));
+  EXPECT_LT(1, called);
+  EXPECT_TRUE(this->loop_->CancelTask(task_id));
+}
+
+TYPED_TEST(MessageLoopTest, WatchFileDescriptorNonPersistent) {
+  ScopedPipe pipe;
+  EXPECT_EQ(1, HANDLE_EINTR(write(pipe.writer, "a", 1)));
+
+  int called = 0;
+  TaskId task_id = this->loop_->WatchFileDescriptor(
+      FROM_HERE, pipe.reader, MessageLoop::kWatchRead, false,
+      Bind([&called] { called++; }));
+  EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
+  // We let the main loop run for 20 iterations but we just expect it to run
+  // at least once. The callback should be called exactly once since we
+  // scheduled it non-persistently. After it ran, we shouldn't be able to cancel
+  // this task.
+  EXPECT_LT(0, MessageLoopRunMaxIterations(this->loop_.get(), 20));
+  EXPECT_EQ(1, called);
+  EXPECT_FALSE(this->loop_->CancelTask(task_id));
+}
+
+TYPED_TEST(MessageLoopTest, WatchFileDescriptorForReadAndWriteSimultaneously) {
+  ScopedSocketPair socks;
+  EXPECT_EQ(1, HANDLE_EINTR(write(socks.right, "a", 1)));
+  // socks.left should be able to read this "a" and should also be able to write
+  // without blocking since the kernel has some buffering for it.
+
+  TaskId read_task_id = this->loop_->WatchFileDescriptor(
+      FROM_HERE, socks.left, MessageLoop::kWatchRead, true,
+      Bind([this, &read_task_id] {
+        EXPECT_TRUE(this->loop_->CancelTask(read_task_id))
+            << "task_id" << read_task_id;
+      }));
+  EXPECT_NE(MessageLoop::kTaskIdNull, read_task_id);
+
+  TaskId write_task_id = this->loop_->WatchFileDescriptor(
+      FROM_HERE, socks.left, MessageLoop::kWatchWrite, true,
+      Bind([this, &write_task_id] {
+        EXPECT_TRUE(this->loop_->CancelTask(write_task_id));
+      }));
+  EXPECT_NE(MessageLoop::kTaskIdNull, write_task_id);
+
+  EXPECT_LT(0, MessageLoopRunMaxIterations(this->loop_.get(), 20));
+
+  EXPECT_FALSE(this->loop_->CancelTask(read_task_id));
+  EXPECT_FALSE(this->loop_->CancelTask(write_task_id));
+}
+
+// Test that we can cancel the task we are running, and should just fail.
+TYPED_TEST(MessageLoopTest, DeleteTaskFromSelf) {
+  bool cancel_result = true;  // We would expect this to be false.
+  MessageLoop* loop_ptr = this->loop_.get();
+  TaskId task_id;
+  task_id = this->loop_->PostTask(
+      FROM_HERE,
+      Bind([&cancel_result, loop_ptr, &task_id]() {
+        cancel_result = loop_ptr->CancelTask(task_id);
+      }));
+  EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
+  EXPECT_FALSE(cancel_result);
+}
+
+// Test that we can cancel a non-persistent file descriptor watching callback,
+// which should fail.
+TYPED_TEST(MessageLoopTest, DeleteNonPersistenIOTaskFromSelf) {
+  ScopedPipe pipe;
+  TaskId task_id = this->loop_->WatchFileDescriptor(
+      FROM_HERE, pipe.writer, MessageLoop::kWatchWrite, false /* persistent */,
+      Bind([this, &task_id] {
+        EXPECT_FALSE(this->loop_->CancelTask(task_id));
+        task_id = MessageLoop::kTaskIdNull;
+      }));
+  EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
+  EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
+  EXPECT_EQ(MessageLoop::kTaskIdNull, task_id);
+}
+
+// Test that we can cancel a persistent file descriptor watching callback from
+// the same callback.
+TYPED_TEST(MessageLoopTest, DeletePersistenIOTaskFromSelf) {
+  ScopedPipe pipe;
+  TaskId task_id = this->loop_->WatchFileDescriptor(
+      FROM_HERE, pipe.writer, MessageLoop::kWatchWrite, true /* persistent */,
+      Bind([this, &task_id] {
+        EXPECT_TRUE(this->loop_->CancelTask(task_id));
+        task_id = MessageLoop::kTaskIdNull;
+      }));
+  EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
+  EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
+  EXPECT_EQ(MessageLoop::kTaskIdNull, task_id);
+}
+
+// Test that we can cancel several persistent file descriptor watching callbacks
+// from a scheduled callback. In the BaseMessageLoop implementation, this code
+// will cause us to cancel an IOTask that has a pending delayed task, but
+// otherwise is a valid test case on all implementations.
+TYPED_TEST(MessageLoopTest, DeleteAllPersistenIOTaskFromSelf) {
+  const int kNumTasks = 5;
+  ScopedPipe pipes[kNumTasks];
+  TaskId task_ids[kNumTasks];
+
+  for (int i = 0; i < kNumTasks; ++i) {
+    task_ids[i] = this->loop_->WatchFileDescriptor(
+        FROM_HERE, pipes[i].writer, MessageLoop::kWatchWrite,
+        true /* persistent */,
+        Bind([this, kNumTasks, &task_ids] {
+          for (int j = 0; j < kNumTasks; ++j) {
+            // Once we cancel all the tasks, none should run, so this code runs
+            // only once from one callback.
+            EXPECT_TRUE(this->loop_->CancelTask(task_ids[j]));
+            task_ids[j] = MessageLoop::kTaskIdNull;
+          }
+        }));
+  }
+  MessageLoopRunMaxIterations(this->loop_.get(), 100);
+  for (int i = 0; i < kNumTasks; ++i) {
+    EXPECT_EQ(MessageLoop::kTaskIdNull, task_ids[i]);
+  }
+}
+
+// Test that if there are several tasks watching for file descriptors to be
+// available or simply waiting in the message loop are fairly scheduled to run.
+// In other words, this test ensures that having a file descriptor always
+// available doesn't prevent other file descriptors watching tasks or delayed
+// tasks to be dispatched, causing starvation.
+TYPED_TEST(MessageLoopTest, AllTasksAreEqual) {
+  int total_calls = 0;
+
+  // First, schedule a repeating timeout callback to run from the main loop.
+  int timeout_called = 0;
+  base::Closure timeout_callback;
+  MessageLoop::TaskId timeout_task;
+  timeout_callback = base::Bind(
+      [this, &timeout_called, &total_calls, &timeout_callback, &timeout_task] {
+        timeout_called++;
+        total_calls++;
+        timeout_task = this->loop_->PostTask(FROM_HERE, Bind(timeout_callback));
+        if (total_calls > 100)
+          this->loop_->BreakLoop();
+      });
+  timeout_task = this->loop_->PostTask(FROM_HERE, timeout_callback);
+
+  // Second, schedule several file descriptor watchers.
+  const int kNumTasks = 3;
+  ScopedPipe pipes[kNumTasks];
+  MessageLoop::TaskId tasks[kNumTasks];
+
+  int reads[kNumTasks] = {};
+  auto fd_callback = [this, &pipes, &reads, &total_calls](int i) {
+    reads[i]++;
+    total_calls++;
+    char c;
+    EXPECT_EQ(1, HANDLE_EINTR(read(pipes[i].reader, &c, 1)));
+    if (total_calls > 100)
+      this->loop_->BreakLoop();
+  };
+
+  for (int i = 0; i < kNumTasks; ++i) {
+    tasks[i] = this->loop_->WatchFileDescriptor(
+        FROM_HERE, pipes[i].reader, MessageLoop::kWatchRead,
+        true /* persistent */,
+        Bind(fd_callback, i));
+    // Make enough bytes available on each file descriptor. This should not
+    // block because we set the size of the file descriptor buffer when
+    // creating it.
+    std::vector<char> blob(1000, 'a');
+    EXPECT_EQ(blob.size(),
+              HANDLE_EINTR(write(pipes[i].writer, blob.data(), blob.size())));
+  }
+  this->loop_->Run();
+  EXPECT_GT(total_calls, 100);
+  // We run the loop up 100 times and expect each callback to run at least 10
+  // times. A good scheduler should balance these callbacks.
+  EXPECT_GE(timeout_called, 10);
+  EXPECT_TRUE(this->loop_->CancelTask(timeout_task));
+  for (int i = 0; i < kNumTasks; ++i) {
+    EXPECT_GE(reads[i], 10) << "Reading from pipes[" << i << "], fd "
+                            << pipes[i].reader;
+    EXPECT_TRUE(this->loop_->CancelTask(tasks[i]));
+  }
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/message_loops/message_loop_utils.cc b/libbrillo/brillo/message_loops/message_loop_utils.cc
new file mode 100644
index 0000000..9ebe865
--- /dev/null
+++ b/libbrillo/brillo/message_loops/message_loop_utils.cc
@@ -0,0 +1,35 @@
+// Copyright 2015 The Chromium OS 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 <brillo/message_loops/message_loop_utils.h>
+
+#include <base/location.h>
+#include <brillo/bind_lambda.h>
+
+namespace brillo {
+
+void MessageLoopRunUntil(
+    MessageLoop* loop,
+    base::TimeDelta timeout,
+    base::Callback<bool()> terminate) {
+  bool timeout_called = false;
+  MessageLoop::TaskId task_id = loop->PostDelayedTask(
+      FROM_HERE,
+      base::Bind([](bool* timeout_called) { *timeout_called = true; },
+                 base::Unretained(&timeout_called)),
+      timeout);
+  while (!timeout_called && (terminate.is_null() || !terminate.Run()))
+    loop->RunOnce(true);
+
+  if (!timeout_called)
+    loop->CancelTask(task_id);
+}
+
+int MessageLoopRunMaxIterations(MessageLoop* loop, int iterations) {
+  int result;
+  for (result = 0; result < iterations && loop->RunOnce(false); result++) {}
+  return result;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/message_loops/message_loop_utils.h b/libbrillo/brillo/message_loops/message_loop_utils.h
new file mode 100644
index 0000000..d49ebdf
--- /dev/null
+++ b/libbrillo/brillo/message_loops/message_loop_utils.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_MESSAGE_LOOPS_MESSAGE_LOOP_UTILS_H_
+#define LIBBRILLO_BRILLO_MESSAGE_LOOPS_MESSAGE_LOOP_UTILS_H_
+
+#include <base/callback.h>
+#include <base/time/time.h>
+
+#include <brillo/brillo_export.h>
+#include <brillo/message_loops/message_loop.h>
+
+namespace brillo {
+
+// Run the MessageLoop until the condition passed in |terminate| returns true
+// or the timeout expires.
+BRILLO_EXPORT void MessageLoopRunUntil(
+    MessageLoop* loop,
+    base::TimeDelta timeout,
+    base::Callback<bool()> terminate);
+
+// Run the MessageLoop |loop| for up to |iterations| times without blocking.
+// Return the number of tasks run.
+BRILLO_EXPORT int MessageLoopRunMaxIterations(MessageLoop* loop,
+                                              int iterations);
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_MESSAGE_LOOPS_MESSAGE_LOOP_UTILS_H_
diff --git a/libbrillo/brillo/message_loops/mock_message_loop.h b/libbrillo/brillo/message_loops/mock_message_loop.h
new file mode 100644
index 0000000..71632f2
--- /dev/null
+++ b/libbrillo/brillo/message_loops/mock_message_loop.h
@@ -0,0 +1,89 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_MESSAGE_LOOPS_MOCK_MESSAGE_LOOP_H_
+#define LIBBRILLO_BRILLO_MESSAGE_LOOPS_MOCK_MESSAGE_LOOP_H_
+
+#include <gmock/gmock.h>
+
+#include <base/location.h>
+#include <base/test/simple_test_clock.h>
+#include <base/time/time.h>
+
+#include <brillo/brillo_export.h>
+#include <brillo/message_loops/fake_message_loop.h>
+#include <brillo/message_loops/message_loop.h>
+
+namespace brillo {
+
+// The MockMessageLoop is a mockable MessageLoop that will by default act as a
+// FakeMessageLoop. It is possible to set expectations with EXPECT_CALL without
+// any action associated and they will call the same methods in the underlying
+// FakeMessageLoop implementation.
+// This message loop implementation is useful to check interaction with the
+// message loop when running unittests.
+class BRILLO_EXPORT MockMessageLoop : public MessageLoop {
+ public:
+  // Create a FakeMessageLoop optionally using a SimpleTestClock to update the
+  // time when Run() or RunOnce(true) are called and should block.
+  explicit MockMessageLoop(base::SimpleTestClock* clock)
+    : fake_loop_(clock) {
+    // Redirect all actions to calling the underlying FakeMessageLoop by
+    // default. For the overloaded methods, we need to disambiguate between the
+    // different options by specifying the type of the method pointer.
+    ON_CALL(*this, PostDelayedTask(::testing::_, ::testing::_, ::testing::_))
+      .WillByDefault(::testing::Invoke(
+          &fake_loop_,
+          static_cast<TaskId(FakeMessageLoop::*)(
+                      const tracked_objects::Location&,
+                      const base::Closure&,
+                      base::TimeDelta)>(
+              &FakeMessageLoop::PostDelayedTask)));
+    ON_CALL(*this, WatchFileDescriptor(
+        ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_))
+      .WillByDefault(::testing::Invoke(
+          &fake_loop_,
+          static_cast<TaskId(FakeMessageLoop::*)(
+                      const tracked_objects::Location&, int, WatchMode, bool,
+                      const base::Closure&)>(
+              &FakeMessageLoop::WatchFileDescriptor)));
+    ON_CALL(*this, CancelTask(::testing::_))
+      .WillByDefault(::testing::Invoke(&fake_loop_,
+                                       &FakeMessageLoop::CancelTask));
+    ON_CALL(*this, RunOnce(::testing::_))
+      .WillByDefault(::testing::Invoke(&fake_loop_,
+                                       &FakeMessageLoop::RunOnce));
+  }
+  ~MockMessageLoop() override = default;
+
+  MOCK_METHOD3(PostDelayedTask,
+               TaskId(const tracked_objects::Location& from_here,
+                      const base::Closure& task,
+                      base::TimeDelta delay));
+  using MessageLoop::PostDelayedTask;
+  MOCK_METHOD5(WatchFileDescriptor,
+               TaskId(const tracked_objects::Location& from_here,
+                      int fd,
+                      WatchMode mode,
+                      bool persistent,
+                      const base::Closure& task));
+  using MessageLoop::WatchFileDescriptor;
+  MOCK_METHOD1(CancelTask, bool(TaskId task_id));
+  MOCK_METHOD1(RunOnce, bool(bool may_block));
+
+  // Returns the actual FakeMessageLoop instance so default actions can be
+  // override with other actions or call
+  FakeMessageLoop* fake_loop() {
+    return &fake_loop_;
+  }
+
+ private:
+  FakeMessageLoop fake_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockMessageLoop);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_MESSAGE_LOOPS_MOCK_MESSAGE_LOOP_H_
diff --git a/libbrillo/brillo/mime_utils.cc b/libbrillo/brillo/mime_utils.cc
new file mode 100644
index 0000000..d98eb43
--- /dev/null
+++ b/libbrillo/brillo/mime_utils.cc
@@ -0,0 +1,163 @@
+// Copyright 2014 The Chromium OS 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 <brillo/mime_utils.h>
+
+#include <algorithm>
+#include <base/strings/string_util.h>
+#include <brillo/strings/string_utils.h>
+
+namespace brillo {
+
+// ***************************************************************************
+// ******************************* MIME types ********************************
+// ***************************************************************************
+const char mime::types::kApplication[]             = "application";
+const char mime::types::kAudio[]                   = "audio";
+const char mime::types::kImage[]                   = "image";
+const char mime::types::kMessage[]                 = "message";
+const char mime::types::kMultipart[]               = "multipart";
+const char mime::types::kText[]                    = "text";
+const char mime::types::kVideo[]                   = "video";
+
+const char mime::parameters::kCharset[]            = "charset";
+
+const char mime::image::kJpeg[]                    = "image/jpeg";
+const char mime::image::kPng[]                     = "image/png";
+const char mime::image::kBmp[]                     = "image/bmp";
+const char mime::image::kTiff[]                    = "image/tiff";
+const char mime::image::kGif[]                     = "image/gif";
+
+const char mime::text::kPlain[]                    = "text/plain";
+const char mime::text::kHtml[]                     = "text/html";
+const char mime::text::kXml[]                      = "text/xml";
+
+const char mime::application::kOctet_stream[]      = "application/octet-stream";
+const char mime::application::kJson[]              = "application/json";
+const char mime::application::kWwwFormUrlEncoded[] =
+    "application/x-www-form-urlencoded";
+const char mime::application::kProtobuf[]          = "application/x-protobuf";
+
+const char mime::multipart::kFormData[]            = "multipart/form-data";
+const char mime::multipart::kMixed[]               = "multipart/mixed";
+
+// ***************************************************************************
+// **************************** Utility Functions ****************************
+// ***************************************************************************
+static std::string EncodeParam(const std::string& param) {
+  // If the string contains one of "tspecials" characters as
+  // specified in RFC 1521, enclose it in quotes.
+  if (param.find_first_of("()<>@,;:\\\"/[]?=") != std::string::npos) {
+    return '"' + param + '"';
+  }
+  return param;
+}
+
+static std::string DecodeParam(const std::string& param) {
+  if (param.size() > 1 && param.front() == '"' && param.back() == '"') {
+    return param.substr(1, param.size() - 2);
+  }
+  return param;
+}
+
+// ***************************************************************************
+// ******************** Main MIME manipulation functions *********************
+// ***************************************************************************
+
+bool mime::Split(const std::string& mime_string,
+                 std::string* type,
+                 std::string* subtype,
+                 mime::Parameters* parameters) {
+  std::vector<std::string> parts =
+      brillo::string_utils::Split(mime_string, ";");
+  if (parts.empty())
+    return false;
+
+  if (!mime::Split(parts.front(), type, subtype))
+    return false;
+
+  if (parameters) {
+    parameters->clear();
+    parameters->reserve(parts.size() - 1);
+    for (size_t i = 1; i < parts.size(); i++) {
+      auto pair = brillo::string_utils::SplitAtFirst(parts[i], "=");
+      pair.second = DecodeParam(pair.second);
+      parameters->push_back(pair);
+    }
+  }
+  return true;
+}
+
+bool mime::Split(const std::string& mime_string,
+                 std::string* type,
+                 std::string* subtype) {
+  std::string mime = mime::RemoveParameters(mime_string);
+  auto types = brillo::string_utils::SplitAtFirst(mime, "/");
+
+  if (type)
+    *type = types.first;
+
+  if (subtype)
+    *subtype = types.second;
+
+  return !types.first.empty() && !types.second.empty();
+}
+
+std::string mime::Combine(const std::string& type,
+                          const std::string& subtype,
+                          const mime::Parameters& parameters) {
+  std::vector<std::string> parts;
+  parts.push_back(brillo::string_utils::Join("/", type, subtype));
+  for (const auto& pair : parameters) {
+    parts.push_back(
+        brillo::string_utils::Join("=", pair.first, EncodeParam(pair.second)));
+  }
+  return brillo::string_utils::Join("; ", parts);
+}
+
+std::string mime::GetType(const std::string& mime_string) {
+  std::string mime = mime::RemoveParameters(mime_string);
+  return brillo::string_utils::SplitAtFirst(mime, "/").first;
+}
+
+std::string mime::GetSubtype(const std::string& mime_string) {
+  std::string mime = mime::RemoveParameters(mime_string);
+  return brillo::string_utils::SplitAtFirst(mime, "/").second;
+}
+
+mime::Parameters mime::GetParameters(const std::string& mime_string) {
+  std::string type;
+  std::string subtype;
+  mime::Parameters parameters;
+
+  if (mime::Split(mime_string, &type, &subtype, &parameters))
+    return parameters;
+
+  return mime::Parameters();
+}
+
+std::string mime::RemoveParameters(const std::string& mime_string) {
+  return brillo::string_utils::SplitAtFirst(mime_string, ";").first;
+}
+
+std::string mime::AppendParameter(const std::string& mime_string,
+                                  const std::string& paramName,
+                                  const std::string& paramValue) {
+  std::string mime(mime_string);
+  mime += "; ";
+  mime += brillo::string_utils::Join("=", paramName, EncodeParam(paramValue));
+  return mime;
+}
+
+std::string mime::GetParameterValue(const std::string& mime_string,
+                                    const std::string& paramName) {
+  mime::Parameters params = mime::GetParameters(mime_string);
+  for (const auto& pair : params) {
+    if (base::EqualsCaseInsensitiveASCII(pair.first.c_str(), paramName.c_str()))
+      return pair.second;
+  }
+  return std::string();
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/mime_utils.h b/libbrillo/brillo/mime_utils.h
new file mode 100644
index 0000000..869b19e
--- /dev/null
+++ b/libbrillo/brillo/mime_utils.h
@@ -0,0 +1,126 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_MIME_UTILS_H_
+#define LIBBRILLO_BRILLO_MIME_UTILS_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <base/compiler_specific.h>
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+namespace mime {
+
+namespace types {
+// Main MIME type categories
+BRILLO_EXPORT extern const char kApplication[];        // application
+BRILLO_EXPORT extern const char kAudio[];              // audio
+BRILLO_EXPORT extern const char kImage[];              // image
+BRILLO_EXPORT extern const char kMessage[];            // message
+BRILLO_EXPORT extern const char kMultipart[];          // multipart
+BRILLO_EXPORT extern const char kText[];               // test
+BRILLO_EXPORT extern const char kVideo[];              // video
+}  // namespace types
+
+namespace parameters {
+// Common MIME parameters
+BRILLO_EXPORT extern const char kCharset[];            // charset=...
+}  // namespace parameters
+
+namespace image {
+// Common image MIME types
+BRILLO_EXPORT extern const char kJpeg[];               // image/jpeg
+BRILLO_EXPORT extern const char kPng[];                // image/png
+BRILLO_EXPORT extern const char kBmp[];                // image/bmp
+BRILLO_EXPORT extern const char kTiff[];               // image/tiff
+BRILLO_EXPORT extern const char kGif[];                // image/gif
+}  // namespace image
+
+namespace text {
+// Common text MIME types
+BRILLO_EXPORT extern const char kPlain[];              // text/plain
+BRILLO_EXPORT extern const char kHtml[];               // text/html
+BRILLO_EXPORT extern const char kXml[];                // text/xml
+}  // namespace text
+
+namespace application {
+// Common application MIME types
+// application/octet-stream
+BRILLO_EXPORT extern const char kOctet_stream[];
+// application/json
+BRILLO_EXPORT extern const char kJson[];
+// application/x-www-form-urlencoded
+BRILLO_EXPORT extern const char kWwwFormUrlEncoded[];
+// application/x-protobuf
+BRILLO_EXPORT extern const char kProtobuf[];
+}  // namespace application
+
+namespace multipart {
+// Common multipart MIME types
+// multipart/form-data
+BRILLO_EXPORT extern const char kFormData[];
+// multipart/mixed
+BRILLO_EXPORT extern const char kMixed[];
+}  // namespace multipart
+
+using Parameters = std::vector<std::pair<std::string, std::string>>;
+
+// Combine a MIME type, subtype and parameters into a MIME string.
+// e.g. Combine("text", "plain", {{"charset", "utf-8"}}) will give:
+//      "text/plain; charset=utf-8"
+BRILLO_EXPORT std::string Combine(
+    const std::string& type,
+    const std::string& subtype,
+    const Parameters& parameters = {}) WARN_UNUSED_RESULT;
+
+// Splits a MIME string into type and subtype.
+// "text/plain;charset=utf-8" => ("text", "plain")
+BRILLO_EXPORT bool Split(const std::string& mime_string,
+                         std::string* type,
+                         std::string* subtype);
+
+// Splits a MIME string into type, subtype, and parameters.
+// "text/plain;charset=utf-8" => ("text", "plain", {{"charset","utf-8"}})
+BRILLO_EXPORT bool Split(const std::string& mime_string,
+                         std::string* type,
+                         std::string* subtype,
+                         Parameters* parameters);
+
+// Returns the MIME type from MIME string.
+// "text/plain;charset=utf-8" => "text"
+BRILLO_EXPORT std::string GetType(const std::string& mime_string);
+
+// Returns the MIME sub-type from MIME string.
+// "text/plain;charset=utf-8" => "plain"
+BRILLO_EXPORT std::string GetSubtype(const std::string& mime_string);
+
+// Returns the MIME parameters from MIME string.
+// "text/plain;charset=utf-8" => {{"charset","utf-8"}}
+BRILLO_EXPORT Parameters GetParameters(const std::string& mime_string);
+
+// Removes parameters from a MIME string
+// "text/plain;charset=utf-8" => "text/plain"
+BRILLO_EXPORT std::string RemoveParameters(
+    const std::string& mime_string) WARN_UNUSED_RESULT;
+
+// Appends a parameter to a MIME string.
+// "text/plain" => "text/plain; charset=utf-8"
+BRILLO_EXPORT std::string AppendParameter(
+    const std::string& mime_string,
+    const std::string& paramName,
+    const std::string& paramValue) WARN_UNUSED_RESULT;
+
+// Returns the value of a parameter on a MIME string (empty string if missing).
+// ("text/plain;charset=utf-8","charset") => "utf-8"
+BRILLO_EXPORT std::string GetParameterValue(const std::string& mime_string,
+                                            const std::string& paramName);
+
+}  // namespace mime
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_MIME_UTILS_H_
diff --git a/libbrillo/brillo/mime_utils_unittest.cc b/libbrillo/brillo/mime_utils_unittest.cc
new file mode 100644
index 0000000..a7595dc
--- /dev/null
+++ b/libbrillo/brillo/mime_utils_unittest.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2014 The Chromium OS 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 <brillo/mime_utils.h>
+
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+TEST(MimeUtils, Combine) {
+  std::string mime_string = mime::Combine(mime::types::kText, "xml");
+  EXPECT_EQ(mime::text::kXml, mime_string);
+  EXPECT_EQ(
+      "application/json; charset=utf-8",
+      mime::Combine(mime::types::kApplication, "json", {{"charset", "utf-8"}}));
+}
+
+TEST(MimeUtils, Split) {
+  std::string s1, s2;
+  EXPECT_TRUE(mime::Split(mime::image::kJpeg, &s1, &s2));
+  EXPECT_EQ(mime::types::kImage, s1);
+  EXPECT_EQ("jpeg", s2);
+
+  mime::Parameters parameters;
+  EXPECT_TRUE(
+      mime::Split("application/json;charset=utf-8", &s1, &s2, &parameters));
+  EXPECT_EQ(mime::types::kApplication, s1);
+  EXPECT_EQ("json", s2);
+  EXPECT_EQ(mime::application::kJson, mime::Combine(s1, s2));
+  EXPECT_EQ(1, parameters.size());
+  EXPECT_EQ(mime::parameters::kCharset, parameters.front().first);
+  EXPECT_EQ("utf-8", parameters.front().second);
+  EXPECT_EQ("application/json; charset=utf-8",
+            mime::Combine(s1, s2, parameters));
+}
+
+TEST(MimeUtils, ExtractParts) {
+  mime::Parameters parameters;
+
+  EXPECT_EQ(mime::types::kText, mime::GetType(mime::text::kPlain));
+  EXPECT_EQ("plain", mime::GetSubtype(mime::text::kPlain));
+
+  parameters = mime::GetParameters("text/plain; charset=iso-8859-1;foo=bar");
+  EXPECT_EQ(2, parameters.size());
+  EXPECT_EQ(mime::parameters::kCharset, parameters[0].first);
+  EXPECT_EQ("iso-8859-1", parameters[0].second);
+  EXPECT_EQ("foo", parameters[1].first);
+  EXPECT_EQ("bar", parameters[1].second);
+}
+
+TEST(MimeUtils, AppendRemoveParams) {
+  std::string mime_string = mime::AppendParameter(
+      mime::text::kXml, mime::parameters::kCharset, "utf-8");
+  EXPECT_EQ("text/xml; charset=utf-8", mime_string);
+  mime_string = mime::AppendParameter(mime_string, "foo", "bar");
+  EXPECT_EQ("text/xml; charset=utf-8; foo=bar", mime_string);
+  EXPECT_EQ("utf-8",
+            mime::GetParameterValue(mime_string, mime::parameters::kCharset));
+  EXPECT_EQ("bar", mime::GetParameterValue(mime_string, "foo"));
+  EXPECT_EQ("", mime::GetParameterValue(mime_string, "baz"));
+  mime_string = mime::RemoveParameters(mime_string);
+  EXPECT_EQ(mime::text::kXml, mime_string);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/minijail/minijail.cc b/libbrillo/brillo/minijail/minijail.cc
new file mode 100644
index 0000000..4d47c05
--- /dev/null
+++ b/libbrillo/brillo/minijail/minijail.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2012 The Chromium OS 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 "brillo/minijail/minijail.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+using std::vector;
+
+namespace brillo {
+
+static base::LazyInstance<Minijail> g_minijail = LAZY_INSTANCE_INITIALIZER;
+
+Minijail::Minijail() {}
+
+Minijail::~Minijail() {}
+
+// static
+Minijail* Minijail::GetInstance() {
+  return g_minijail.Pointer();
+}
+
+struct minijail* Minijail::New() {
+  return minijail_new();
+}
+
+void Minijail::Destroy(struct minijail* jail) {
+  minijail_destroy(jail);
+}
+
+void Minijail::DropRoot(struct minijail* jail, uid_t uid, gid_t gid) {
+  minijail_change_uid(jail, uid);
+  minijail_change_gid(jail, gid);
+}
+
+bool Minijail::DropRoot(struct minijail* jail,
+                        const char* user,
+                        const char* group) {
+  // |user| and |group| are copied so the only reason either of these
+  // calls can fail is ENOMEM.
+  return !minijail_change_user(jail, user) &&
+         !minijail_change_group(jail, group);
+}
+
+void Minijail::EnterNewPidNamespace(struct minijail* jail) {
+  minijail_namespace_pids(jail);
+}
+
+void Minijail::MountTmp(struct minijail* jail) {
+  minijail_mount_tmp(jail);
+}
+
+void Minijail::UseSeccompFilter(struct minijail* jail, const char* path) {
+  minijail_no_new_privs(jail);
+  minijail_use_seccomp_filter(jail);
+  minijail_parse_seccomp_filters(jail, path);
+}
+
+void Minijail::UseCapabilities(struct minijail* jail, uint64_t capmask) {
+  minijail_use_caps(jail, capmask);
+}
+
+void Minijail::ResetSignalMask(struct minijail* jail) {
+  minijail_reset_signal_mask(jail);
+}
+
+void Minijail::Enter(struct minijail* jail) {
+  minijail_enter(jail);
+}
+
+bool Minijail::Run(struct minijail* jail, vector<char*> args, pid_t* pid) {
+  return minijail_run_pid(jail, args[0], args.data(), pid) == 0;
+}
+
+bool Minijail::RunSync(struct minijail* jail, vector<char*> args, int* status) {
+  pid_t pid;
+  if (Run(jail, args, &pid) && waitpid(pid, status, 0) == pid) {
+    return true;
+  }
+
+  return false;
+}
+
+bool Minijail::RunPipe(struct minijail* jail,
+                       vector<char*> args,
+                       pid_t* pid,
+                       int* stdin) {
+#if defined(__ANDROID__)
+  return minijail_run_pid_pipes_no_preload(jail, args[0], args.data(), pid,
+                                           stdin, NULL, NULL) == 0;
+#else
+  return minijail_run_pid_pipes(jail, args[0], args.data(), pid, stdin, NULL,
+                                NULL) == 0;
+#endif  // __ANDROID__
+}
+
+bool Minijail::RunPipes(struct minijail* jail,
+                        vector<char*> args,
+                        pid_t* pid,
+                        int* stdin,
+                        int* stdout,
+                        int* stderr) {
+#if defined(__ANDROID__)
+  return minijail_run_pid_pipes_no_preload(jail, args[0], args.data(), pid,
+                                           stdin, stdout, stderr) == 0;
+#else
+  return minijail_run_pid_pipes(jail, args[0], args.data(), pid, stdin, stdout,
+                                stderr) == 0;
+#endif  // __ANDROID__
+}
+
+bool Minijail::RunAndDestroy(struct minijail* jail,
+                             vector<char*> args,
+                             pid_t* pid) {
+  bool res = Run(jail, args, pid);
+  Destroy(jail);
+  return res;
+}
+
+bool Minijail::RunSyncAndDestroy(struct minijail* jail,
+                                 vector<char*> args,
+                                 int* status) {
+  bool res = RunSync(jail, args, status);
+  Destroy(jail);
+  return res;
+}
+
+bool Minijail::RunPipeAndDestroy(struct minijail* jail,
+                                 vector<char*> args,
+                                 pid_t* pid,
+                                 int* stdin) {
+  bool res = RunPipe(jail, args, pid, stdin);
+  Destroy(jail);
+  return res;
+}
+
+bool Minijail::RunPipesAndDestroy(struct minijail* jail,
+                                  vector<char*> args,
+                                  pid_t* pid,
+                                  int* stdin,
+                                  int* stdout,
+                                  int* stderr) {
+  bool res = RunPipes(jail, args, pid, stdin, stdout, stderr);
+  Destroy(jail);
+  return res;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/minijail/minijail.h b/libbrillo/brillo/minijail/minijail.h
new file mode 100644
index 0000000..4c1431d
--- /dev/null
+++ b/libbrillo/brillo/minijail/minijail.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2012 The Chromium OS 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 LIBBRILLO_BRILLO_MINIJAIL_MINIJAIL_H_
+#define LIBBRILLO_BRILLO_MINIJAIL_MINIJAIL_H_
+
+#include <vector>
+
+extern "C" {
+#include <linux/capability.h>
+#include <sys/types.h>
+}
+
+#include <base/lazy_instance.h>
+
+#include <libminijail.h>
+
+namespace brillo {
+
+// A Minijail abstraction allowing Minijail mocking in tests.
+class Minijail {
+ public:
+  virtual ~Minijail();
+
+  // This is a singleton -- use Minijail::GetInstance()->Foo().
+  static Minijail* GetInstance();
+
+  // minijail_new
+  virtual struct minijail* New();
+  // minijail_destroy
+  virtual void Destroy(struct minijail* jail);
+
+  // minijail_change_uid/minijail_change_gid
+  virtual void DropRoot(struct minijail* jail, uid_t uid, gid_t gid);
+
+  // minijail_change_user/minijail_change_group
+  virtual bool DropRoot(struct minijail* jail,
+                        const char* user,
+                        const char* group);
+
+  // minijail_namespace_pids
+  virtual void EnterNewPidNamespace(struct minijail* jail);
+
+  // minijail_mount_tmp
+  virtual void MountTmp(struct minijail* jail);
+
+  // minijail_use_seccomp_filter/minijail_no_new_privs/
+  // minijail_parse_seccomp_filters
+  virtual void UseSeccompFilter(struct minijail* jail, const char* path);
+
+  // minijail_use_caps
+  virtual void UseCapabilities(struct minijail* jail, uint64_t capmask);
+
+  // minijail_reset_signal_mask
+  virtual void ResetSignalMask(struct minijail* jail);
+
+  // minijail_enter
+  virtual void Enter(struct minijail* jail);
+
+  // minijail_run_pid
+  virtual bool Run(struct minijail* jail, std::vector<char*> args, pid_t* pid);
+
+  // minijail_run_pid and waitpid
+  virtual bool RunSync(struct minijail* jail,
+                       std::vector<char*> args,
+                       int* status);
+
+  // minijail_run_pid_pipes, with |pstdout_fd| and |pstderr_fd| set to NULL.
+  virtual bool RunPipe(struct minijail* jail,
+                       std::vector<char*> args,
+                       pid_t* pid,
+                       int* stdin);
+
+  // minijail_run_pid_pipes
+  virtual bool RunPipes(struct minijail* jail,
+                        std::vector<char*> args,
+                        pid_t* pid,
+                        int* stdin,
+                        int* stdout,
+                        int* stderr);
+
+  // Run() and Destroy()
+  virtual bool RunAndDestroy(struct minijail* jail,
+                             std::vector<char*> args,
+                             pid_t* pid);
+
+  // RunSync() and Destroy()
+  virtual bool RunSyncAndDestroy(struct minijail* jail,
+                                 std::vector<char*> args,
+                                 int* status);
+
+  // RunPipe() and Destroy()
+  virtual bool RunPipeAndDestroy(struct minijail* jail,
+                                 std::vector<char*> args,
+                                 pid_t* pid,
+                                 int* stdin);
+
+  // RunPipes() and Destroy()
+  virtual bool RunPipesAndDestroy(struct minijail* jail,
+                                  std::vector<char*> args,
+                                  pid_t* pid,
+                                  int* stdin,
+                                  int* stdout,
+                                  int* stderr);
+
+ protected:
+  Minijail();
+
+ private:
+  friend struct base::DefaultLazyInstanceTraits<Minijail>;
+
+  DISALLOW_COPY_AND_ASSIGN(Minijail);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_MINIJAIL_MINIJAIL_H_
diff --git a/libbrillo/brillo/minijail/mock_minijail.h b/libbrillo/brillo/minijail/mock_minijail.h
new file mode 100644
index 0000000..a855632
--- /dev/null
+++ b/libbrillo/brillo/minijail/mock_minijail.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 The Chromium OS 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 LIBBRILLO_BRILLO_MINIJAIL_MOCK_MINIJAIL_H_
+#define LIBBRILLO_BRILLO_MINIJAIL_MOCK_MINIJAIL_H_
+
+#include <vector>
+
+#include <base/macros.h>
+#include <gmock/gmock.h>
+
+#include "brillo/minijail/minijail.h"
+
+namespace brillo {
+
+class MockMinijail : public brillo::Minijail {
+ public:
+  MockMinijail() {}
+  virtual ~MockMinijail() {}
+
+  MOCK_METHOD0(New, struct minijail*());
+  MOCK_METHOD1(Destroy, void(struct minijail*));
+
+  MOCK_METHOD3(DropRoot,
+               bool(struct minijail* jail,
+                    const char* user,
+                    const char* group));
+  MOCK_METHOD2(UseSeccompFilter, void(struct minijail* jail, const char* path));
+  MOCK_METHOD2(UseCapabilities, void(struct minijail* jail, uint64_t capmask));
+  MOCK_METHOD1(ResetSignalMask, void(struct minijail* jail));
+  MOCK_METHOD1(Enter, void(struct minijail* jail));
+  MOCK_METHOD3(Run,
+               bool(struct minijail* jail,
+                    std::vector<char*> args,
+                    pid_t* pid));
+  MOCK_METHOD3(RunSync,
+               bool(struct minijail* jail,
+                    std::vector<char*> args,
+                    int* status));
+  MOCK_METHOD3(RunAndDestroy,
+               bool(struct minijail* jail,
+                    std::vector<char*> args,
+                    pid_t* pid));
+  MOCK_METHOD3(RunSyncAndDestroy,
+               bool(struct minijail* jail,
+                    std::vector<char*> args,
+                    int* status));
+  MOCK_METHOD4(RunPipeAndDestroy,
+               bool(struct minijail* jail,
+                    std::vector<char*> args,
+                    pid_t* pid,
+                    int* stdin));
+  MOCK_METHOD6(RunPipesAndDestroy,
+               bool(struct minijail* jail,
+                    std::vector<char*> args,
+                    pid_t* pid,
+                    int* stdin,
+                    int* stdout,
+                    int* stderr));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockMinijail);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_MINIJAIL_MOCK_MINIJAIL_H_
diff --git a/libbrillo/brillo/osrelease_reader.cc b/libbrillo/brillo/osrelease_reader.cc
new file mode 100644
index 0000000..6e4bf90
--- /dev/null
+++ b/libbrillo/brillo/osrelease_reader.cc
@@ -0,0 +1,56 @@
+// Copyright 2014 The Chromium OS 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 <brillo/osrelease_reader.h>
+
+#include <base/files/file_enumerator.h>
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include <brillo/strings/string_utils.h>
+
+namespace brillo {
+
+void OsReleaseReader::Load() {
+  Load(base::FilePath("/"));
+}
+
+bool OsReleaseReader::GetString(const std::string& key,
+                                std::string* value) const {
+  CHECK(initialized_) << "OsReleaseReader.Load() must be called first.";
+  return store_.GetString(key, value);
+}
+
+void OsReleaseReader::LoadTestingOnly(const base::FilePath& root_dir) {
+  Load(root_dir);
+}
+
+void OsReleaseReader::Load(const base::FilePath& root_dir) {
+  base::FilePath osrelease = root_dir.Append("etc").Append("os-release");
+  if (!store_.Load(osrelease)) {
+    // /etc/os-release might not be present (cros deploying a new configuration
+    // or no fields set at all). Just print a debug message and continue.
+    DLOG(INFO) << "Could not load fields from " << osrelease.value();
+  }
+
+  base::FilePath osreleased = root_dir.Append("etc").Append("os-release.d");
+  base::FileEnumerator enumerator(
+      osreleased, false, base::FileEnumerator::FILES);
+
+  for (base::FilePath path = enumerator.Next(); !path.empty();
+       path = enumerator.Next()) {
+    std::string content;
+    if (!base::ReadFileToString(path, &content)) {
+      // The only way to fail is if a file exist in /etc/os-release.d but we
+      // cannot read it.
+      PLOG(FATAL) << "Could not read " << path.value();
+    }
+    // There might be a trailing new line. Strip it to keep only the first line
+    // of the file.
+    content = brillo::string_utils::SplitAtFirst(content, "\n", true).first;
+    store_.SetString(path.BaseName().value(), content);
+  }
+  initialized_ = true;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/osrelease_reader.h b/libbrillo/brillo/osrelease_reader.h
new file mode 100644
index 0000000..f29c14d
--- /dev/null
+++ b/libbrillo/brillo/osrelease_reader.h
@@ -0,0 +1,54 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Wrapper around /etc/os-release and /etc/os-release.d.
+// Standard fields can come from both places depending on how we set them. They
+// should always be accessed through this interface.
+
+#ifndef LIBBRILLO_BRILLO_OSRELEASE_READER_H_
+#define LIBBRILLO_BRILLO_OSRELEASE_READER_H_
+
+#include <string>
+
+#include <brillo/brillo_export.h>
+#include <brillo/key_value_store.h>
+#include <gtest/gtest_prod.h>
+
+namespace brillo {
+
+class BRILLO_EXPORT OsReleaseReader final {
+ public:
+  // Create an empty reader
+  OsReleaseReader() = default;
+
+  // Loads the key=value pairs from either /etc/os-release.d/<KEY> or
+  // /etc/os-release.
+  void Load();
+
+  // Same as the private Load method.
+  // This need to be public so that services can use it in testing mode (for
+  // autotest tests for example).
+  // This should not be used in production so suffix it with TestingOnly to
+  // make it obvious.
+  void LoadTestingOnly(const base::FilePath& root_dir);
+
+  // Getter for the given key. Returns whether the key was found on the store.
+  bool GetString(const std::string& key, std::string* value) const;
+
+ private:
+  // The map storing all the key-value pairs.
+  KeyValueStore store_;
+
+  // os-release can be lazily loaded if need be.
+  bool initialized_;
+
+  // Load the data from a given root_dir.
+  BRILLO_PRIVATE void Load(const base::FilePath& root_dir);
+
+  DISALLOW_COPY_AND_ASSIGN(OsReleaseReader);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_OSRELEASE_READER_H_
diff --git a/libbrillo/brillo/osrelease_reader_unittest.cc b/libbrillo/brillo/osrelease_reader_unittest.cc
new file mode 100644
index 0000000..88185a0
--- /dev/null
+++ b/libbrillo/brillo/osrelease_reader_unittest.cc
@@ -0,0 +1,95 @@
+// Copyright 2014 The Chromium OS 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 <brillo/osrelease_reader.h>
+
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <gtest/gtest.h>
+
+using std::string;
+
+namespace brillo {
+
+class OsReleaseReaderTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    CHECK(temp_dir_.CreateUniqueTempDir());
+    osreleased_ = temp_dir_.path().Append("etc").Append("os-release.d");
+    osrelease_ = temp_dir_.path().Append("etc").Append("os-release");
+    base::CreateDirectory(osreleased_);
+  }
+
+ protected:
+  base::FilePath temp_file_, osrelease_, osreleased_;
+  base::ScopedTempDir temp_dir_;
+  OsReleaseReader store_;  // reader under test.
+};
+
+TEST_F(OsReleaseReaderTest, MissingOsReleaseTest) {
+  store_.LoadTestingOnly(temp_dir_.path());
+}
+
+TEST_F(OsReleaseReaderTest, MissingOsReleaseDTest) {
+  base::DeleteFile(osreleased_, true);
+  store_.LoadTestingOnly(temp_dir_.path());
+}
+
+TEST_F(OsReleaseReaderTest, CompleteTest) {
+  string hello = "hello";
+  string ola = "ola";
+  string bob = "bob";
+  string osreleasecontent = "TEST_KEY=bonjour\nNAME=bob\n";
+
+  base::WriteFile(osreleased_.Append("TEST_KEY"), hello.data(), hello.size());
+  base::WriteFile(osreleased_.Append("GREETINGS"), ola.data(), ola.size());
+  base::WriteFile(osrelease_, osreleasecontent.data(), osreleasecontent.size());
+
+  store_.LoadTestingOnly(temp_dir_.path());
+
+  string test_key_value;
+  ASSERT_TRUE(store_.GetString("TEST_KEY", &test_key_value));
+
+  string greetings_value;
+  ASSERT_TRUE(store_.GetString("GREETINGS", &greetings_value));
+
+  string name_value;
+  ASSERT_TRUE(store_.GetString("NAME", &name_value));
+
+  string nonexistent_value;
+  // Getting the string should fail if the key does not exist.
+  ASSERT_FALSE(store_.GetString("DOES_NOT_EXIST", &nonexistent_value));
+
+  // hello in chosen (from os-release.d) instead of bonjour from os-release.
+  ASSERT_EQ(hello, test_key_value);
+
+  // greetings is set to ola.
+  ASSERT_EQ(ola, greetings_value);
+
+  // Name from os-release is set.
+  ASSERT_EQ(bob, name_value);
+}
+
+TEST_F(OsReleaseReaderTest, NoNewLine) {
+  // New lines should be stripped from os-release.d files.
+  string hello = "hello\n";
+  string bonjour = "bonjour\ngarbage";
+
+  base::WriteFile(osreleased_.Append("HELLO"), hello.data(), hello.size());
+  base::WriteFile(
+      osreleased_.Append("BONJOUR"), bonjour.data(), bonjour.size());
+
+  store_.LoadTestingOnly(temp_dir_.path());
+
+  string hello_value;
+  string bonjour_value;
+
+  ASSERT_TRUE(store_.GetString("HELLO", &hello_value));
+  ASSERT_TRUE(store_.GetString("BONJOUR", &bonjour_value));
+
+  ASSERT_EQ("hello", hello_value);
+  ASSERT_EQ("bonjour", bonjour_value);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/pointer_utils.h b/libbrillo/brillo/pointer_utils.h
new file mode 100644
index 0000000..f688fa8
--- /dev/null
+++ b/libbrillo/brillo/pointer_utils.h
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_POINTER_UTILS_H_
+#define LIBBRILLO_BRILLO_POINTER_UTILS_H_
+
+#include <cstdint>
+#include <sys/types.h>
+
+namespace brillo {
+
+// AdvancePointer() is a helper function to advance void pointer by
+// |byte_offset| bytes. Both const and non-const overloads are provided.
+inline void* AdvancePointer(void* pointer, ssize_t byte_offset) {
+  return reinterpret_cast<uint8_t*>(pointer) + byte_offset;
+}
+inline const void* AdvancePointer(const void* pointer, ssize_t byte_offset) {
+  return reinterpret_cast<const uint8_t*>(pointer) + byte_offset;
+}
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_POINTER_UTILS_H_
diff --git a/libbrillo/brillo/process.cc b/libbrillo/brillo/process.cc
new file mode 100644
index 0000000..7af8fbb
--- /dev/null
+++ b/libbrillo/brillo/process.cc
@@ -0,0 +1,425 @@
+// Copyright (c) 2012 The Chromium OS 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 "brillo/process.h"
+
+#include <fcntl.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <map>
+#include <memory>
+
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include <base/memory/ptr_util.h>
+#include <base/posix/eintr_wrapper.h>
+#include <base/process/process_metrics.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_util.h>
+#include <base/time/time.h>
+
+#ifndef __linux__
+#define setresuid(_u1, _u2, _u3) setreuid(_u1, _u2)
+#define setresgid(_g1, _g2, _g3) setregid(_g1, _g2)
+#endif  // !__linux__
+
+namespace brillo {
+
+bool ReturnTrue() {
+  return true;
+}
+
+Process::Process() {
+}
+
+Process::~Process() {
+}
+
+bool Process::ProcessExists(pid_t pid) {
+  return base::DirectoryExists(
+      base::FilePath(base::StringPrintf("/proc/%d", pid)));
+}
+
+ProcessImpl::ProcessImpl()
+    : pid_(0),
+      uid_(-1),
+      gid_(-1),
+      pre_exec_(base::Bind(&ReturnTrue)),
+      search_path_(false),
+      inherit_parent_signal_mask_(false),
+      close_unused_file_descriptors_(false) {
+}
+
+ProcessImpl::~ProcessImpl() {
+  Reset(0);
+}
+
+void ProcessImpl::AddArg(const std::string& arg) {
+  arguments_.push_back(arg);
+}
+
+void ProcessImpl::RedirectOutput(const std::string& output_file) {
+  output_file_ = output_file;
+}
+
+void ProcessImpl::RedirectUsingPipe(int child_fd, bool is_input) {
+  PipeInfo info;
+  info.is_input_ = is_input;
+  info.is_bound_ = false;
+  pipe_map_[child_fd] = info;
+}
+
+void ProcessImpl::BindFd(int parent_fd, int child_fd) {
+  PipeInfo info;
+  info.is_bound_ = true;
+
+  // info.child_fd_ is the 'child half' of the pipe, which gets dup2()ed into
+  // place over child_fd. Since we already have the child we want to dup2() into
+  // place, we can set info.child_fd_ to parent_fd and leave info.parent_fd_
+  // invalid.
+  info.child_fd_ = parent_fd;
+  info.parent_fd_ = -1;
+  pipe_map_[child_fd] = info;
+}
+
+void ProcessImpl::SetCloseUnusedFileDescriptors(bool close_unused_fds) {
+  close_unused_file_descriptors_ = close_unused_fds;
+}
+
+void ProcessImpl::SetUid(uid_t uid) {
+  uid_ = uid;
+}
+
+void ProcessImpl::SetGid(gid_t gid) {
+  gid_ = gid;
+}
+
+void ProcessImpl::SetCapabilities(uint64_t /*capmask*/) {
+  // No-op, since ProcessImpl does not support sandboxing.
+  return;
+}
+
+void ProcessImpl::ApplySyscallFilter(const std::string& /*path*/) {
+  // No-op, since ProcessImpl does not support sandboxing.
+  return;
+}
+
+void ProcessImpl::EnterNewPidNamespace() {
+  // No-op, since ProcessImpl does not support sandboxing.
+  return;
+}
+
+void ProcessImpl::SetInheritParentSignalMask(bool inherit) {
+  inherit_parent_signal_mask_ = inherit;
+}
+
+void ProcessImpl::SetPreExecCallback(const PreExecCallback& cb) {
+  pre_exec_ = cb;
+}
+
+void ProcessImpl::SetSearchPath(bool search_path) {
+  search_path_ = search_path;
+}
+
+int ProcessImpl::GetPipe(int child_fd) {
+  PipeMap::iterator i = pipe_map_.find(child_fd);
+  if (i == pipe_map_.end())
+    return -1;
+  else
+    return i->second.parent_fd_;
+}
+
+bool ProcessImpl::PopulatePipeMap() {
+  // Verify all target fds are already open.  With this assumption we
+  // can be sure that the pipe fds created below do not overlap with
+  // any of the target fds which simplifies how we dup2 to them.  Note
+  // that multi-threaded code could close i->first between this loop
+  // and the next.
+  for (PipeMap::iterator i = pipe_map_.begin(); i != pipe_map_.end(); ++i) {
+    struct stat stat_buffer;
+    if (fstat(i->first, &stat_buffer) < 0) {
+      int saved_errno = errno;
+      LOG(ERROR) << "Unable to fstat fd " << i->first << ": " << saved_errno;
+      return false;
+    }
+  }
+
+  for (PipeMap::iterator i = pipe_map_.begin(); i != pipe_map_.end(); ++i) {
+    if (i->second.is_bound_) {
+      // already have a parent fd, and the child fd gets dup()ed later.
+      continue;
+    }
+    int pipefds[2];
+    if (pipe(pipefds) < 0) {
+      int saved_errno = errno;
+      LOG(ERROR) << "pipe call failed with: " << saved_errno;
+      return false;
+    }
+    if (i->second.is_input_) {
+      // pipe is an input from the prospective of the child.
+      i->second.parent_fd_ = pipefds[1];
+      i->second.child_fd_ = pipefds[0];
+    } else {
+      i->second.parent_fd_ = pipefds[0];
+      i->second.child_fd_ = pipefds[1];
+    }
+  }
+  return true;
+}
+
+bool ProcessImpl::IsFileDescriptorInPipeMap(int fd) const {
+  for (const auto& pipe : pipe_map_) {
+    if (fd == pipe.second.parent_fd_ ||
+        fd == pipe.second.child_fd_ ||
+        fd == pipe.first) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void ProcessImpl::CloseUnusedFileDescriptors() {
+  size_t max_fds = base::GetMaxFds();
+  for (size_t i = 0; i < max_fds; i++) {
+    const int fd = static_cast<int>(i);
+
+    // Ignore STD file descriptors.
+    if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) {
+      continue;
+    }
+
+    // Ignore file descriptors used by the PipeMap, they will be handled
+    // by this process later on.
+    if (IsFileDescriptorInPipeMap(fd)) {
+      continue;
+    }
+
+    // Since we're just trying to close anything we can find,
+    // ignore any error return values of close().
+    IGNORE_EINTR(close(fd));
+ }
+}
+
+bool ProcessImpl::Start() {
+  // If no arguments are provided, fail.
+  if (arguments_.empty()) {
+    return false;
+  }
+  std::unique_ptr<char* []> argv =
+      base::MakeUnique<char* []>(arguments_.size() + 1);
+
+  for (size_t i = 0; i < arguments_.size(); ++i)
+    argv[i] = const_cast<char*>(arguments_[i].c_str());
+
+  argv[arguments_.size()] = nullptr;
+
+  if (!PopulatePipeMap()) {
+    LOG(ERROR) << "Failing to start because pipe creation failed";
+    return false;
+  }
+
+  pid_t pid = fork();
+  int saved_errno = errno;
+  if (pid < 0) {
+    LOG(ERROR) << "Fork failed: " << saved_errno;
+    Reset(0);
+    return false;
+  }
+
+  if (pid == 0) {
+    // Executing inside the child process.
+    // Close unused file descriptors.
+    if (close_unused_file_descriptors_) {
+      CloseUnusedFileDescriptors();
+    }
+    // Close parent's side of the child pipes. dup2 ours into place and
+    // then close our ends.
+    for (PipeMap::iterator i = pipe_map_.begin(); i != pipe_map_.end(); ++i) {
+      if (i->second.parent_fd_ != -1)
+        IGNORE_EINTR(close(i->second.parent_fd_));
+      // If we want to bind a fd to the same fd in the child, we don't need to
+      // close and dup2 it.
+      if (i->second.child_fd_ == i->first)
+        continue;
+      HANDLE_EINTR(dup2(i->second.child_fd_, i->first));
+    }
+    // Defer the actual close() of the child fd until afterward; this lets the
+    // same child fd be bound to multiple fds using BindFd. Don't close the fd
+    // if it was bound to itself.
+    for (PipeMap::iterator i = pipe_map_.begin(); i != pipe_map_.end(); ++i) {
+      if (i->second.child_fd_ == i->first)
+        continue;
+      IGNORE_EINTR(close(i->second.child_fd_));
+    }
+    if (!output_file_.empty()) {
+      int output_handle = HANDLE_EINTR(open(
+          output_file_.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW,
+          0666));
+      if (output_handle < 0) {
+        PLOG(ERROR) << "Could not create " << output_file_;
+        // Avoid exit() to avoid atexit handlers from parent.
+        _exit(kErrorExitStatus);
+      }
+      HANDLE_EINTR(dup2(output_handle, STDOUT_FILENO));
+      HANDLE_EINTR(dup2(output_handle, STDERR_FILENO));
+      // Only close output_handle if it does not happen to be one of
+      // the two standard file descriptors we are trying to redirect.
+      if (output_handle != STDOUT_FILENO && output_handle != STDERR_FILENO) {
+        IGNORE_EINTR(close(output_handle));
+      }
+    }
+    if (gid_ != static_cast<gid_t>(-1) && setresgid(gid_, gid_, gid_) < 0) {
+      int saved_errno = errno;
+      LOG(ERROR) << "Unable to set GID to " << gid_ << ": " << saved_errno;
+      _exit(kErrorExitStatus);
+    }
+    if (uid_ != static_cast<uid_t>(-1) && setresuid(uid_, uid_, uid_) < 0) {
+      int saved_errno = errno;
+      LOG(ERROR) << "Unable to set UID to " << uid_ << ": " << saved_errno;
+      _exit(kErrorExitStatus);
+    }
+    if (!pre_exec_.Run()) {
+      LOG(ERROR) << "Pre-exec callback failed";
+      _exit(kErrorExitStatus);
+    }
+    // Reset signal mask for the child process if not inheriting signal mask
+    // from the parent process.
+    if (!inherit_parent_signal_mask_) {
+      sigset_t signal_mask;
+      CHECK_EQ(0, sigemptyset(&signal_mask));
+      CHECK_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, nullptr));
+    }
+    if (search_path_) {
+      execvp(argv[0], &argv[0]);
+    } else {
+      execv(argv[0], &argv[0]);
+    }
+    PLOG(ERROR) << "Exec of " << argv[0] << " failed:";
+    _exit(kErrorExitStatus);
+  } else {
+    // Still executing inside the parent process with known child pid.
+    arguments_.clear();
+    UpdatePid(pid);
+    // Close our copy of child side pipes only if we created those pipes.
+    for (const auto& i : pipe_map_) {
+      if (!i.second.is_bound_) {
+        IGNORE_EINTR(close(i.second.child_fd_));
+      }
+    }
+  }
+  return true;
+}
+
+int ProcessImpl::Wait() {
+  int status = 0;
+  if (pid_ == 0) {
+    LOG(ERROR) << "Process not running";
+    return -1;
+  }
+  if (HANDLE_EINTR(waitpid(pid_, &status, 0)) < 0) {
+    int saved_errno = errno;
+    LOG(ERROR) << "Problem waiting for pid " << pid_ << ": " << saved_errno;
+    return -1;
+  }
+  pid_t old_pid = pid_;
+  // Update the pid to 0 - do not Reset as we do not want to try to
+  // kill the process that has just exited.
+  UpdatePid(0);
+  if (!WIFEXITED(status)) {
+    DCHECK(WIFSIGNALED(status)) << old_pid
+                                << " neither exited, nor died on a signal?";
+    LOG(ERROR) << "Process " << old_pid
+               << " did not exit normally: " << WTERMSIG(status);
+    return -1;
+  }
+  return WEXITSTATUS(status);
+}
+
+int ProcessImpl::Run() {
+  if (!Start()) {
+    return -1;
+  }
+  return Wait();
+}
+
+pid_t ProcessImpl::pid() {
+  return pid_;
+}
+
+bool ProcessImpl::Kill(int signal, int timeout) {
+  if (pid_ == 0) {
+    // Passing pid == 0 to kill is committing suicide.  Check specifically.
+    LOG(ERROR) << "Process not running";
+    return false;
+  }
+  if (kill(pid_, signal) < 0) {
+    PLOG(ERROR) << "Unable to send signal to " << pid_;
+    return false;
+  }
+  base::TimeTicks start_signal = base::TimeTicks::Now();
+  do {
+    int status = 0;
+    pid_t w = waitpid(pid_, &status, WNOHANG);
+    if (w < 0) {
+      if (errno == ECHILD)
+        return true;
+      PLOG(ERROR) << "Waitpid returned " << w;
+      return false;
+    }
+    if (w > 0) {
+      Reset(0);
+      return true;
+    }
+    usleep(100);
+  } while ((base::TimeTicks::Now() - start_signal).InSecondsF() <= timeout);
+  LOG(INFO) << "process " << pid_ << " did not exit from signal " << signal
+            << " in " << timeout << " seconds";
+  return false;
+}
+
+void ProcessImpl::UpdatePid(pid_t new_pid) {
+  pid_ = new_pid;
+}
+
+void ProcessImpl::Reset(pid_t new_pid) {
+  arguments_.clear();
+  // Close our side of all pipes to this child giving the child to
+  // handle sigpipes and shutdown nicely, though likely it won't
+  // have time.
+  for (PipeMap::iterator i = pipe_map_.begin(); i != pipe_map_.end(); ++i)
+    IGNORE_EINTR(close(i->second.parent_fd_));
+  pipe_map_.clear();
+  if (pid_)
+    Kill(SIGKILL, 0);
+  UpdatePid(new_pid);
+}
+
+bool ProcessImpl::ResetPidByFile(const std::string& pid_file) {
+  std::string contents;
+  if (!base::ReadFileToString(base::FilePath(pid_file), &contents)) {
+    LOG(ERROR) << "Could not read pid file" << pid_file;
+    return false;
+  }
+  base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
+  int64_t pid_int64 = 0;
+  if (!base::StringToInt64(contents, &pid_int64)) {
+    LOG(ERROR) << "Unexpected pid file contents";
+    return false;
+  }
+  Reset(pid_int64);
+  return true;
+}
+
+pid_t ProcessImpl::Release() {
+  pid_t old_pid = pid_;
+  pid_ = 0;
+  return old_pid;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/process.h b/libbrillo/brillo/process.h
new file mode 100644
index 0000000..9760ab3
--- /dev/null
+++ b/libbrillo/brillo/process.h
@@ -0,0 +1,236 @@
+// Copyright (c) 2012 The Chromium OS 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 LIBBRILLO_BRILLO_PROCESS_H_
+#define LIBBRILLO_BRILLO_PROCESS_H_
+
+#include <sys/types.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+#include <brillo/brillo_export.h>
+#include <gtest/gtest_prod.h>
+
+namespace brillo {
+// Manages a process.  Can create the process, attach to an existing
+// process by pid or pid file, and kill the process.  Upon destruction
+// any managed process is killed with SIGKILL.  Use Release() to
+// release the process from management.  A given system process may
+// only be managed by one Process at a time.
+class BRILLO_EXPORT Process {
+ public:
+  Process();
+  virtual ~Process();
+
+  // Adds |arg| to the executable command-line to be run.  The
+  // executable name itself is the first argument.
+  virtual void AddArg(const std::string& arg) = 0;
+
+  // Adds |option| and |value| as an option with a string value to the
+  // command line to be run.
+  inline void AddStringOption(const std::string& option,
+                              const std::string& value) {
+    AddArg(option);
+    AddArg(value);
+  }
+
+  // Adds |option| and |value| as an option which takes an integer
+  // value to the command line to be run.
+  inline void AddIntOption(const std::string& option, int value) {
+    AddArg(option);
+    AddArg(base::StringPrintf("%d", value));
+  }
+
+  // Redirects stderr and stdout to |output_file|.
+  virtual void RedirectOutput(const std::string& output_file) = 0;
+
+  // Indicates we want to redirect |child_fd| in the child process's
+  // file table to a pipe.  |child_fd| will be available for reading
+  // from child process's perspective iff |is_input|.
+  virtual void RedirectUsingPipe(int child_fd, bool is_input) = 0;
+
+  // Binds the given file descriptor in the parent to the given file
+  // descriptor in the child.
+  virtual void BindFd(int parent_fd, int child_fd) = 0;
+
+  // Set a flag |close_unused_fds| to indicate if the child process
+  // should close all unused file descriptors inherited from the
+  // parent process.  This will not close the file descriptors for
+  // the standard streams (stdin, stdout, and stderr).
+  virtual void SetCloseUnusedFileDescriptors(bool close_unused_fds) = 0;
+
+  // Set the real/effective/saved user ID of the child process.
+  virtual void SetUid(uid_t uid) = 0;
+
+  // Set the real/effective/saved group ID of the child process.
+  virtual void SetGid(gid_t gid) = 0;
+
+  // Set the capabilities assigned to the child process.
+  // NOTE: |capmask| is indeed a mask and should be passed in as the result of
+  // the CAP_TO_MASK(capability) macro, e.g.
+  //     my_process.SetCapabilities(CAP_TO_MASK(CAP_SETUID) |
+  //                                CAP_TO_MASK(CAP_SETGID));
+  // NOTE: supporting this sandboxing feature is optional (provide no-op
+  // implementation if your Process implementation does not support this).
+  virtual void SetCapabilities(uint64_t capmask) = 0;
+
+  // Apply a syscall filter to the process using the policy file at |path|.
+  // NOTE: supporting this sandboxing feature is optional (provide no-op
+  // implementation if your Process implementation does not support this).
+  virtual void ApplySyscallFilter(const std::string& path) = 0;
+
+  // Enter new PID namespace when this process is run.
+  // NOTE: supporting this sandboxing feature is optional (provide no-op
+  // implementation if your Process implementation does not support this).
+  virtual void EnterNewPidNamespace() = 0;
+
+  // Set a flag |inherit| to indicate if the child process intend to
+  // inherit signal mask from the parent process. When |inherit| is
+  // set to true, the child process will inherit signal mask from the
+  // parent process. This could cause unintended side effect, where all
+  // the signals to the child process might be blocked if they are set
+  // in the parent's signal mask.
+  virtual void SetInheritParentSignalMask(bool inherit) = 0;
+
+  typedef base::Callback<bool(void)> PreExecCallback;
+
+  // Set the pre-exec callback. This is called after all setup is complete but
+  // before we exec() the process. The callback may return false to cause Start
+  // to return false without starting the process.
+  virtual void SetPreExecCallback(const PreExecCallback& cb) = 0;
+
+  // Sets whether starting the process should search the system path or not.
+  // By default the system path will not be searched.
+  virtual void SetSearchPath(bool search_path) = 0;
+
+  // Gets the pipe file descriptor mapped to the process's |child_fd|.
+  virtual int GetPipe(int child_fd) = 0;
+
+  // Starts this process, returning true if successful.
+  virtual bool Start() = 0;
+
+  // Waits for this process to finish.  Returns the process's exit
+  // status if it exited normally, or otherwise returns -1.  Note
+  // that kErrorExitStatus may be returned if an error occurred
+  // after forking and before execing the child process.
+  virtual int Wait() = 0;
+
+  // Start and wait for this process to finish.  Returns same value as
+  // Wait().
+  virtual int Run() = 0;
+
+  // Returns the pid of this process or else returns 0 if there is no
+  // corresponding process (either because it has not yet been started
+  // or has since exited).
+  virtual pid_t pid() = 0;
+
+  // Sends |signal| to process and wait |timeout| seconds until it
+  // dies.  If process is not a child, returns immediately with a
+  // value based on whether kill was successful.  If the process is a
+  // child and |timeout| is non-zero, returns true if the process is
+  // able to be reaped within the given |timeout| in seconds.
+  virtual bool Kill(int signal, int timeout) = 0;
+
+  // Resets this Process object to refer to the process with |pid|.
+  // If |pid| is zero, this object no longer refers to a process.
+  virtual void Reset(pid_t new_pid) = 0;
+
+  // Same as Reset but reads the pid from |pid_file|.  Returns false
+  // only when the file cannot be read/parsed.
+  virtual bool ResetPidByFile(const std::string& pid_file) = 0;
+
+  // Releases the process so that on destruction, the process is not killed.
+  virtual pid_t Release() = 0;
+
+  // Returns if |pid| is a currently running process.
+  static bool ProcessExists(pid_t pid);
+
+  // When returned from Wait or Run, indicates an error may have occurred
+  // creating the process.
+  enum { kErrorExitStatus = 127 };
+};
+
+class BRILLO_EXPORT ProcessImpl : public Process {
+ public:
+  ProcessImpl();
+  virtual ~ProcessImpl();
+
+  virtual void AddArg(const std::string& arg);
+  virtual void RedirectOutput(const std::string& output_file);
+  virtual void RedirectUsingPipe(int child_fd, bool is_input);
+  virtual void BindFd(int parent_fd, int child_fd);
+  virtual void SetCloseUnusedFileDescriptors(bool close_unused_fds);
+  virtual void SetUid(uid_t uid);
+  virtual void SetGid(gid_t gid);
+  virtual void SetCapabilities(uint64_t capmask);
+  virtual void ApplySyscallFilter(const std::string& path);
+  virtual void EnterNewPidNamespace();
+  virtual void SetInheritParentSignalMask(bool inherit);
+  virtual void SetPreExecCallback(const PreExecCallback& cb);
+  virtual void SetSearchPath(bool search_path);
+  virtual int GetPipe(int child_fd);
+  virtual bool Start();
+  virtual int Wait();
+  virtual int Run();
+  virtual pid_t pid();
+  virtual bool Kill(int signal, int timeout);
+  virtual void Reset(pid_t pid);
+  virtual bool ResetPidByFile(const std::string& pid_file);
+  virtual pid_t Release();
+
+ protected:
+  struct PipeInfo {
+    PipeInfo() : parent_fd_(-1), child_fd_(-1), is_input_(false) {}
+    // Parent (our) side of the pipe to the child process.
+    int parent_fd_;
+    // Child's side of the pipe to the parent.
+    int child_fd_;
+    // Is this an input or output pipe from child's perspective.
+    bool is_input_;
+    // Is this a bound (pre-existing) file descriptor?
+    bool is_bound_;
+  };
+  typedef std::map<int, PipeInfo> PipeMap;
+
+  void UpdatePid(pid_t new_pid);
+  bool PopulatePipeMap();
+
+ private:
+  FRIEND_TEST(ProcessTest, ResetPidByFile);
+
+  bool IsFileDescriptorInPipeMap(int fd) const;
+  void CloseUnusedFileDescriptors();
+
+  // Pid of currently managed process or 0 if no currently managed
+  // process.  pid must not be modified except by calling
+  // UpdatePid(new_pid).
+  pid_t pid_;
+  std::string output_file_;
+  std::vector<std::string> arguments_;
+  // Map of child target file descriptors (first) to information about
+  // pipes created (second).
+  PipeMap pipe_map_;
+  uid_t uid_;
+  gid_t gid_;
+  PreExecCallback pre_exec_;
+  bool search_path_;
+  // Flag indicating to inherit signal mask from the parent process. It
+  // is set to false by default, which means by default the child process
+  // will not inherit signal mask from the parent process.
+  bool inherit_parent_signal_mask_;
+  // Flag indicating to close unused file descriptors inherited from the
+  // parent process when starting the child process, which avoids leaking
+  // unnecessary file descriptors to the child process.
+  bool close_unused_file_descriptors_;
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_PROCESS_H_
diff --git a/libbrillo/brillo/process_information.cc b/libbrillo/brillo/process_information.cc
new file mode 100644
index 0000000..6b03c40
--- /dev/null
+++ b/libbrillo/brillo/process_information.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Chromium OS 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 "brillo/process_information.h"
+
+namespace brillo {
+
+ProcessInformation::ProcessInformation() : cmd_line_(), process_id_(-1) {
+}
+ProcessInformation::~ProcessInformation() {
+}
+
+std::string ProcessInformation::GetCommandLine() {
+  std::string result;
+  for (std::vector<std::string>::iterator cmd_itr = cmd_line_.begin();
+       cmd_itr != cmd_line_.end();
+       cmd_itr++) {
+    if (result.length()) {
+      result.append(" ");
+    }
+    result.append((*cmd_itr));
+  }
+  return result;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/process_information.h b/libbrillo/brillo/process_information.h
new file mode 100644
index 0000000..3f0a2c9
--- /dev/null
+++ b/libbrillo/brillo/process_information.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2012 The Chromium OS 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 LIBBRILLO_BRILLO_PROCESS_INFORMATION_H_
+#define LIBBRILLO_BRILLO_PROCESS_INFORMATION_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+// Information for a single running process. Stores its command line, set of
+// open files, process id and working directory.
+class BRILLO_EXPORT ProcessInformation {
+ public:
+  ProcessInformation();
+  virtual ~ProcessInformation();
+
+  std::string GetCommandLine();
+
+  // Set the command line array.  This method DOES swap out the contents of
+  // |value|.  The caller should expect an empty vector on return.
+  void set_cmd_line(std::vector<std::string>* value) {
+    cmd_line_.clear();
+    cmd_line_.swap(*value);
+  }
+
+  const std::vector<std::string>& get_cmd_line() { return cmd_line_; }
+
+  // Set the command line array.  This method DOES swap out the contents of
+  // |value|.  The caller should expect an empty set on return.
+  void set_open_files(std::set<std::string>* value) {
+    open_files_.clear();
+    open_files_.swap(*value);
+  }
+
+  const std::set<std::string>& get_open_files() { return open_files_; }
+
+  // Set the command line array.  This method DOES swap out the contents of
+  // |value|.  The caller should expect an empty string on return.
+  void set_cwd(std::string* value) {
+    cwd_.clear();
+    cwd_.swap(*value);
+  }
+
+  const std::string& get_cwd() { return cwd_; }
+
+  void set_process_id(int value) { process_id_ = value; }
+
+  int get_process_id() { return process_id_; }
+
+ private:
+  std::vector<std::string> cmd_line_;
+  std::set<std::string> open_files_;
+  std::string cwd_;
+  int process_id_;
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_PROCESS_INFORMATION_H_
diff --git a/libbrillo/brillo/process_mock.h b/libbrillo/brillo/process_mock.h
new file mode 100644
index 0000000..f73d242
--- /dev/null
+++ b/libbrillo/brillo/process_mock.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2012 The Chromium OS 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 LIBBRILLO_BRILLO_PROCESS_MOCK_H_
+#define LIBBRILLO_BRILLO_PROCESS_MOCK_H_
+
+#include <string>
+
+#include <gmock/gmock.h>
+
+#include "brillo/process.h"
+
+namespace brillo {
+
+class ProcessMock : public Process {
+ public:
+  ProcessMock() {}
+  virtual ~ProcessMock() {}
+
+  MOCK_METHOD1(AddArg, void(const std::string& arg));
+  MOCK_METHOD1(RedirectOutput, void(const std::string& output_file));
+  MOCK_METHOD2(RedirectUsingPipe, void(int child_fd, bool is_input));
+  MOCK_METHOD2(BindFd, void(int parent_fd, int child_fd));
+  MOCK_METHOD1(SetUid, void(uid_t));
+  MOCK_METHOD1(SetGid, void(gid_t));
+  MOCK_METHOD1(SetCapabilities, void(uint64_t capmask));
+  MOCK_METHOD1(ApplySyscallFilter, void(const std::string& path));
+  MOCK_METHOD0(EnterNewPidNamespace, void());
+  MOCK_METHOD1(SetInheritParentSignalMask, void(bool));
+  MOCK_METHOD1(SetPreExecCallback, void(const PreExecCallback&));
+  MOCK_METHOD1(SetSearchPath, void(bool));
+  MOCK_METHOD1(GetPipe, int(int child_fd));
+  MOCK_METHOD0(Start, bool());
+  MOCK_METHOD0(Wait, int());
+  MOCK_METHOD0(Run, int());
+  MOCK_METHOD0(pid, pid_t());
+  MOCK_METHOD2(Kill, bool(int signal, int timeout));
+  MOCK_METHOD1(Reset, void(pid_t));
+  MOCK_METHOD1(ResetPidByFile, bool(const std::string& pid_file));
+  MOCK_METHOD0(Release, pid_t());
+  MOCK_METHOD1(SetCloseUnusedFileDescriptors, void(bool close_unused_fds));
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_PROCESS_MOCK_H_
diff --git a/libbrillo/brillo/process_reaper.cc b/libbrillo/brillo/process_reaper.cc
new file mode 100644
index 0000000..c4cb1cf
--- /dev/null
+++ b/libbrillo/brillo/process_reaper.cc
@@ -0,0 +1,91 @@
+// Copyright 2015 The Chromium OS 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 "brillo/process_reaper.h"
+
+#include <sys/signalfd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <base/bind.h>
+#include <base/posix/eintr_wrapper.h>
+#include <brillo/asynchronous_signal_handler.h>
+#include <brillo/daemons/daemon.h>
+#include <brillo/location_logging.h>
+
+namespace brillo {
+
+ProcessReaper::~ProcessReaper() {
+  Unregister();
+}
+
+void ProcessReaper::Register(
+    AsynchronousSignalHandlerInterface* async_signal_handler) {
+  CHECK(!async_signal_handler_);
+  async_signal_handler_ = async_signal_handler;
+  async_signal_handler->RegisterHandler(
+      SIGCHLD,
+      base::Bind(&ProcessReaper::HandleSIGCHLD, base::Unretained(this)));
+}
+
+void ProcessReaper::Unregister() {
+  if (!async_signal_handler_)
+    return;
+  async_signal_handler_->UnregisterHandler(SIGCHLD);
+  async_signal_handler_ = nullptr;
+}
+
+bool ProcessReaper::WatchForChild(const tracked_objects::Location& from_here,
+                                  pid_t pid,
+                                  const ChildCallback& callback) {
+  if (watched_processes_.find(pid) != watched_processes_.end())
+    return false;
+  watched_processes_.emplace(pid, WatchedProcess{from_here, callback});
+  return true;
+}
+
+bool ProcessReaper::ForgetChild(pid_t pid) {
+  return watched_processes_.erase(pid) != 0;
+}
+
+bool ProcessReaper::HandleSIGCHLD(
+    const struct signalfd_siginfo& /* sigfd_info */) {
+  // One SIGCHLD may correspond to multiple terminated children, so ignore
+  // sigfd_info and reap any available children.
+  while (true) {
+    siginfo_t info;
+    info.si_pid = 0;
+    int rc = HANDLE_EINTR(waitid(P_ALL, 0, &info, WNOHANG | WEXITED));
+
+    if (rc == -1) {
+      if (errno != ECHILD) {
+        PLOG(ERROR) << "waitid failed";
+      }
+      break;
+    }
+
+    if (info.si_pid == 0) {
+      break;
+    }
+
+    auto proc = watched_processes_.find(info.si_pid);
+    if (proc == watched_processes_.end()) {
+      LOG(INFO) << "Untracked process " << info.si_pid
+                << " terminated with status " << info.si_status
+                << " (code = " << info.si_code << ")";
+    } else {
+      DVLOG_LOC(proc->second.location, 1)
+          << "Process " << info.si_pid << " terminated with status "
+          << info.si_status << " (code = " << info.si_code << ")";
+      ChildCallback callback = std::move(proc->second.callback);
+      watched_processes_.erase(proc);
+      callback.Run(info);
+    }
+  }
+
+  // Return false to indicate that our handler should not be uninstalled.
+  return false;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/process_reaper.h b/libbrillo/brillo/process_reaper.h
new file mode 100644
index 0000000..937c88c
--- /dev/null
+++ b/libbrillo/brillo/process_reaper.h
@@ -0,0 +1,74 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_PROCESS_REAPER_H_
+#define LIBBRILLO_BRILLO_PROCESS_REAPER_H_
+
+#include <sys/wait.h>
+
+#include <map>
+
+#include <base/callback.h>
+#include <base/location.h>
+#include <base/macros.h>
+#include <brillo/asynchronous_signal_handler.h>
+#include <brillo/daemons/daemon.h>
+
+namespace brillo {
+
+class BRILLO_EXPORT ProcessReaper final {
+ public:
+  // The callback called when a child exits.
+  using ChildCallback = base::Callback<void(const siginfo_t&)>;
+
+  ProcessReaper() = default;
+  ~ProcessReaper();
+
+  // Register the ProcessReaper using either the provided
+  // brillo::AsynchronousSignalHandlerInterface. You can call Unregister() to
+  // remove this ProcessReapper or it will be called during shutdown.
+  // You can only register this ProcessReaper with one signal handler at a time.
+  void Register(AsynchronousSignalHandlerInterface* async_signal_handler);
+
+  // Unregisters the ProcessReaper from the
+  // brillo::AsynchronousSignalHandlerInterface passed in Register(). It
+  // doesn't do anything if not registered.
+  void Unregister();
+
+  // Watch for the child process |pid| to finish and call |callback| when the
+  // selected process exits or the process terminates for other reason. The
+  // |callback| receives the exit status and exit code of the terminated process
+  // as a siginfo_t. See wait(2) for details about siginfo_t.
+  bool WatchForChild(const tracked_objects::Location& from_here,
+                     pid_t pid,
+                     const ChildCallback& callback);
+
+  // Stop watching child process |pid|.  This is useful in situations
+  // where the child process may have been reaped outside of the signal
+  // handler, or the caller is no longer interested in being notified about
+  // this child process anymore.  Returns true if a child was removed from
+  // the watchlist.
+  bool ForgetChild(pid_t pid);
+
+ private:
+  // SIGCHLD handler for the AsynchronousSignalHandler. Always returns false
+  // (meaning that the signal handler should not be unregistered).
+  bool HandleSIGCHLD(const signalfd_siginfo& sigfd_info);
+
+  struct WatchedProcess {
+    tracked_objects::Location location;
+    ChildCallback callback;
+  };
+  std::map<pid_t, WatchedProcess> watched_processes_;
+
+  // The |async_signal_handler_| is owned by the caller and is |nullptr| when
+  // not registered.
+  AsynchronousSignalHandlerInterface* async_signal_handler_{nullptr};
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessReaper);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_PROCESS_REAPER_H_
diff --git a/libbrillo/brillo/process_reaper_unittest.cc b/libbrillo/brillo/process_reaper_unittest.cc
new file mode 100644
index 0000000..0ca6e34
--- /dev/null
+++ b/libbrillo/brillo/process_reaper_unittest.cc
@@ -0,0 +1,150 @@
+// Copyright 2015 The Chromium OS 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 <brillo/process_reaper.h>
+
+#include <signal.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <base/bind.h>
+#include <base/location.h>
+#include <base/message_loop/message_loop.h>
+#include <brillo/asynchronous_signal_handler.h>
+#include <brillo/bind_lambda.h>
+#include <brillo/message_loops/base_message_loop.h>
+#include <gtest/gtest.h>
+
+namespace {
+
+pid_t ForkChildAndExit(int exit_code) {
+  pid_t pid = fork();
+  PCHECK(pid != -1);
+  if (pid == 0) {
+    _exit(exit_code);
+  }
+  return pid;
+}
+
+pid_t ForkChildAndKill(int sig) {
+  pid_t pid = fork();
+  PCHECK(pid != -1);
+  if (pid == 0) {
+    if (raise(sig) != 0) {
+      PLOG(ERROR) << "raise(" << sig << ")";
+    }
+    _exit(0);  // Not reached. This value will cause the test to fail.
+  }
+  return pid;
+}
+
+}  // namespace
+
+namespace brillo {
+
+class ProcessReaperTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    brillo_loop_.SetAsCurrent();
+    async_signal_handler_.Init();
+    process_reaper_.Register(&async_signal_handler_);
+  }
+
+ protected:
+  base::MessageLoopForIO base_loop_;
+  brillo::BaseMessageLoop brillo_loop_{&base_loop_};
+  brillo::AsynchronousSignalHandler async_signal_handler_;
+
+  // ProcessReaper under test.
+  ProcessReaper process_reaper_;
+};
+
+TEST_F(ProcessReaperTest, UnregisterWhenNotRegistered) {
+  ProcessReaper another_process_reaper_;
+  another_process_reaper_.Unregister();
+}
+
+TEST_F(ProcessReaperTest, UnregisterAndReregister) {
+  process_reaper_.Unregister();
+  process_reaper_.Register(&async_signal_handler_);
+  // This checks that we can unregister the ProcessReaper and then destroy it.
+  process_reaper_.Unregister();
+}
+
+TEST_F(ProcessReaperTest, ReapExitedChild) {
+  pid_t pid = ForkChildAndExit(123);
+  EXPECT_TRUE(process_reaper_.WatchForChild(FROM_HERE, pid, base::Bind(
+      [](decltype(this) test, const siginfo_t& info) {
+        EXPECT_EQ(CLD_EXITED, info.si_code);
+        EXPECT_EQ(123, info.si_status);
+        test->brillo_loop_.BreakLoop();
+      }, base::Unretained(this))));
+  brillo_loop_.Run();
+}
+
+// Test that simultaneous child processes fire their respective callbacks when
+// exiting.
+TEST_F(ProcessReaperTest, ReapedChildsMatchCallbacks) {
+  int running_childs = 10;
+  for (int i = 0; i < running_childs; ++i) {
+    // Different processes will have different exit values.
+    int exit_value = 1 + i;
+    pid_t pid = ForkChildAndExit(exit_value);
+    EXPECT_TRUE(process_reaper_.WatchForChild(
+        FROM_HERE,
+        pid,
+        base::Bind(
+            [](decltype(this) test,
+               int exit_value,
+               int* running_childs,
+               const siginfo_t& info) {
+              EXPECT_EQ(CLD_EXITED, info.si_code);
+              EXPECT_EQ(exit_value, info.si_status);
+              (*running_childs)--;
+              if (*running_childs == 0)
+                test->brillo_loop_.BreakLoop();
+            },
+            base::Unretained(this),
+            exit_value,
+            base::Unretained(&running_childs))));
+  }
+  // This sleep is optional. It helps to have more processes exit before we
+  // start watching for them in the message loop.
+  usleep(10 * 1000);
+  brillo_loop_.Run();
+  EXPECT_EQ(0, running_childs);
+}
+
+TEST_F(ProcessReaperTest, ReapKilledChild) {
+  pid_t pid = ForkChildAndKill(SIGKILL);
+  EXPECT_TRUE(process_reaper_.WatchForChild(FROM_HERE, pid, base::Bind(
+      [](decltype(this) test, const siginfo_t& info) {
+        EXPECT_EQ(CLD_KILLED, info.si_code);
+        EXPECT_EQ(SIGKILL, info.si_status);
+        test->brillo_loop_.BreakLoop();
+      }, base::Unretained(this))));
+  brillo_loop_.Run();
+}
+
+TEST_F(ProcessReaperTest, ReapKilledAndForgottenChild) {
+  pid_t pid = ForkChildAndExit(0);
+  EXPECT_TRUE(process_reaper_.WatchForChild(FROM_HERE, pid, base::Bind(
+      [](decltype(this) test, const siginfo_t& /* info */) {
+        ADD_FAILURE() << "Child process was still tracked.";
+        test->brillo_loop_.BreakLoop();
+      }, base::Unretained(this))));
+  EXPECT_TRUE(process_reaper_.ForgetChild(pid));
+
+  // A second call should return failure.
+  EXPECT_FALSE(process_reaper_.ForgetChild(pid));
+
+  // Run the loop with a timeout, as the BreakLoop() above is not expected.
+  brillo_loop_.PostDelayedTask(FROM_HERE,
+                               base::Bind(&MessageLoop::BreakLoop,
+                                          base::Unretained(&brillo_loop_)),
+                               base::TimeDelta::FromMilliseconds(100));
+  brillo_loop_.Run();
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/process_unittest.cc b/libbrillo/brillo/process_unittest.cc
new file mode 100644
index 0000000..d2c92e6
--- /dev/null
+++ b/libbrillo/brillo/process_unittest.cc
@@ -0,0 +1,384 @@
+// Copyright (c) 2012 The Chromium OS 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 "brillo/process.h"
+
+#include <unistd.h>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <gtest/gtest.h>
+
+#include "brillo/process_mock.h"
+#include "brillo/unittest_utils.h"
+#include "brillo/test_helpers.h"
+
+using base::FilePath;
+
+// This test assumes the following standard binaries are installed.
+#if defined(__ANDROID__)
+# define SYSTEM_PREFIX "/system"
+static const char kBinStat[] = SYSTEM_PREFIX "/bin/stat";
+#else
+# define SYSTEM_PREFIX ""
+static const char kBinStat[] = "/usr/bin/stat";
+#endif
+
+static const char kBinSh[] = SYSTEM_PREFIX "/bin/sh";
+static const char kBinCat[] = SYSTEM_PREFIX "/bin/cat";
+static const char kBinCp[] = SYSTEM_PREFIX "/bin/cp";
+static const char kBinEcho[] = SYSTEM_PREFIX "/bin/echo";
+static const char kBinFalse[] = SYSTEM_PREFIX "/bin/false";
+static const char kBinSleep[] = SYSTEM_PREFIX "/bin/sleep";
+static const char kBinTrue[] = SYSTEM_PREFIX "/bin/true";
+
+namespace brillo {
+
+// Test that the mock has all the functions of the interface by
+// instantiating it.  This variable is not used elsewhere.
+struct CompileMocks {
+  ProcessMock process_mock;
+};
+
+TEST(SimpleProcess, Basic) {
+  // Log must be cleared before running this test, just as ProcessTest::SetUp.
+  ClearLog();
+  ProcessImpl process;
+  process.AddArg(kBinEcho);
+  EXPECT_EQ(0, process.Run());
+  EXPECT_EQ("", GetLog());
+}
+
+TEST(SimpleProcess, NoSearchPath) {
+  ProcessImpl process;
+  process.AddArg("echo");
+  EXPECT_EQ(127, process.Run());
+}
+
+TEST(SimpleProcess, SearchPath) {
+  ProcessImpl process;
+  process.AddArg("echo");
+  process.SetSearchPath(true);
+  EXPECT_EQ(EXIT_SUCCESS, process.Run());
+}
+
+TEST(SimpleProcess, BindFd) {
+  int fds[2];
+  char buf[16];
+  static const char* kMsg = "hello, world!";
+  ProcessImpl process;
+  EXPECT_EQ(0, pipe(fds));
+  process.AddArg(kBinEcho);
+  process.AddArg(kMsg);
+  process.BindFd(fds[1], 1);
+  process.Run();
+  memset(buf, 0, sizeof(buf));
+  EXPECT_EQ(read(fds[0], buf, sizeof(buf) - 1), strlen(kMsg) + 1);
+  EXPECT_EQ(std::string(kMsg) + "\n", std::string(buf));
+}
+
+// The test framework uses the device's dash shell as "sh", which doesn't
+// support redirecting stdout to arbitrary large file descriptor numbers
+// directly, nor has /proc mounted to open /proc/self/fd/NN. This test would
+// fail if pipe.writer is big enough.
+// TODO(deymo): Write a helper program that writes "hello_world" to the passed
+// file descriptor and re-enabled this test.
+TEST(DISABLED_SimpleProcess, BindFdToSameFd) {
+  static const char* kMsg = "hello_world";
+  ScopedPipe pipe;
+  ProcessImpl process;
+  process.AddArg(kBinSh);
+  process.AddArg("-c");
+  process.AddArg(base::StringPrintf("echo %s >&%d", kMsg, pipe.writer));
+  process.BindFd(pipe.writer, pipe.writer);
+  process.Run();
+  close(pipe.writer);
+  pipe.writer = -1;
+
+  char buf[16];
+  memset(buf, 0, sizeof(buf));
+  EXPECT_EQ(read(pipe.reader, buf, sizeof(buf) - 1), strlen(kMsg) + 1);
+  EXPECT_EQ(std::string(kMsg) + "\n", std::string(buf));
+}
+
+class ProcessTest : public ::testing::Test {
+ public:
+  void SetUp() {
+    CHECK(temp_dir_.CreateUniqueTempDir());
+    output_file_ = temp_dir_.path().Append("fork_out").value();
+    process_.RedirectOutput(output_file_);
+    ClearLog();
+  }
+
+  static void SetUpTestCase() {
+    base::CommandLine::Init(0, nullptr);
+    ::brillo::InitLog(brillo::kLogToStderr);
+    ::brillo::LogToString(true);
+  }
+
+ protected:
+  void CheckStderrCaptured();
+  FilePath GetFdPath(int fd);
+
+  ProcessImpl process_;
+  std::vector<const char*> args_;
+  std::string output_file_;
+  base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(ProcessTest, Basic) {
+  process_.AddArg(kBinEcho);
+  process_.AddArg("hello world");
+  EXPECT_EQ(0, process_.Run());
+  ExpectFileEquals("hello world\n", output_file_.c_str());
+  EXPECT_EQ("", GetLog());
+}
+
+TEST_F(ProcessTest, AddStringOption) {
+  process_.AddArg(kBinEcho);
+  process_.AddStringOption("--hello", "world");
+  EXPECT_EQ(0, process_.Run());
+  ExpectFileEquals("--hello world\n", output_file_.c_str());
+}
+
+TEST_F(ProcessTest, AddIntValue) {
+  process_.AddArg(kBinEcho);
+  process_.AddIntOption("--answer", 42);
+  EXPECT_EQ(0, process_.Run());
+  ExpectFileEquals("--answer 42\n", output_file_.c_str());
+}
+
+TEST_F(ProcessTest, NonZeroReturnValue) {
+  process_.AddArg(kBinFalse);
+  EXPECT_EQ(1, process_.Run());
+  ExpectFileEquals("", output_file_.c_str());
+  EXPECT_EQ("", GetLog());
+}
+
+TEST_F(ProcessTest, BadOutputFile) {
+  process_.AddArg(kBinEcho);
+  process_.RedirectOutput("/bad/path");
+  EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run());
+}
+
+TEST_F(ProcessTest, BadExecutable) {
+  process_.AddArg("false");
+  EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run());
+}
+
+void ProcessTest::CheckStderrCaptured() {
+  std::string contents;
+  process_.AddArg(kBinSh);
+  process_.AddArg("-c");
+  process_.AddArg("echo errormessage 1>&2 && exit 1");
+  EXPECT_EQ(1, process_.Run());
+  EXPECT_TRUE(base::ReadFileToString(FilePath(output_file_), &contents));
+  EXPECT_NE(std::string::npos, contents.find("errormessage"));
+  EXPECT_EQ("", GetLog());
+}
+
+TEST_F(ProcessTest, StderrCaptured) {
+  CheckStderrCaptured();
+}
+
+TEST_F(ProcessTest, StderrCapturedWhenPreviouslyClosed) {
+  int saved_stderr = dup(STDERR_FILENO);
+  close(STDERR_FILENO);
+  CheckStderrCaptured();
+  dup2(saved_stderr, STDERR_FILENO);
+}
+
+FilePath ProcessTest::GetFdPath(int fd) {
+  return FilePath(base::StringPrintf("/proc/self/fd/%d", fd));
+}
+
+TEST_F(ProcessTest, RedirectStderrUsingPipe) {
+  std::string contents;
+  process_.RedirectOutput("");
+  process_.AddArg(kBinSh);
+  process_.AddArg("-c");
+  process_.AddArg("echo errormessage >&2 && exit 1");
+  process_.RedirectUsingPipe(STDERR_FILENO, false);
+  EXPECT_EQ(-1, process_.GetPipe(STDERR_FILENO));
+  EXPECT_EQ(1, process_.Run());
+  int pipe_fd = process_.GetPipe(STDERR_FILENO);
+  EXPECT_GE(pipe_fd, 0);
+  EXPECT_EQ(-1, process_.GetPipe(STDOUT_FILENO));
+  EXPECT_EQ(-1, process_.GetPipe(STDIN_FILENO));
+  EXPECT_TRUE(base::ReadFileToString(GetFdPath(pipe_fd), &contents));
+  EXPECT_NE(std::string::npos, contents.find("errormessage"));
+  EXPECT_EQ("", GetLog());
+}
+
+TEST_F(ProcessTest, RedirectStderrUsingPipeWhenPreviouslyClosed) {
+  int saved_stderr = dup(STDERR_FILENO);
+  close(STDERR_FILENO);
+  process_.RedirectOutput("");
+  process_.AddArg(kBinCp);
+  process_.RedirectUsingPipe(STDERR_FILENO, false);
+  EXPECT_FALSE(process_.Start());
+  EXPECT_TRUE(FindLog("Unable to fstat fd 2:"));
+  dup2(saved_stderr, STDERR_FILENO);
+}
+
+TEST_F(ProcessTest, RedirectStdoutUsingPipe) {
+  std::string contents;
+  process_.RedirectOutput("");
+  process_.AddArg(kBinEcho);
+  process_.AddArg("hello world\n");
+  process_.RedirectUsingPipe(STDOUT_FILENO, false);
+  EXPECT_EQ(-1, process_.GetPipe(STDOUT_FILENO));
+  EXPECT_EQ(0, process_.Run());
+  int pipe_fd = process_.GetPipe(STDOUT_FILENO);
+  EXPECT_GE(pipe_fd, 0);
+  EXPECT_EQ(-1, process_.GetPipe(STDERR_FILENO));
+  EXPECT_EQ(-1, process_.GetPipe(STDIN_FILENO));
+  EXPECT_TRUE(base::ReadFileToString(GetFdPath(pipe_fd), &contents));
+  EXPECT_NE(std::string::npos, contents.find("hello world\n"));
+  EXPECT_EQ("", GetLog());
+}
+
+TEST_F(ProcessTest, RedirectStdinUsingPipe) {
+  std::string contents;
+  const char kMessage[] = "made it!\n";
+  process_.AddArg(kBinCat);
+  process_.RedirectUsingPipe(STDIN_FILENO, true);
+  process_.RedirectOutput(output_file_);
+  EXPECT_TRUE(process_.Start());
+  int write_fd = process_.GetPipe(STDIN_FILENO);
+  EXPECT_EQ(-1, process_.GetPipe(STDERR_FILENO));
+  EXPECT_TRUE(base::WriteFile(GetFdPath(write_fd), kMessage, strlen(kMessage)));
+  close(write_fd);
+  EXPECT_EQ(0, process_.Wait());
+  ExpectFileEquals(kMessage, output_file_.c_str());
+}
+
+TEST_F(ProcessTest, WithSameUid) {
+  gid_t uid = geteuid();
+  process_.AddArg(kBinEcho);
+  process_.SetUid(uid);
+  EXPECT_EQ(0, process_.Run());
+}
+
+TEST_F(ProcessTest, WithSameGid) {
+  gid_t gid = getegid();
+  process_.AddArg(kBinEcho);
+  process_.SetGid(gid);
+  EXPECT_EQ(0, process_.Run());
+}
+
+TEST_F(ProcessTest, WithIllegalUid) {
+  ASSERT_NE(0, geteuid());
+  process_.AddArg(kBinEcho);
+  process_.SetUid(0);
+  EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run());
+  std::string contents;
+  EXPECT_TRUE(base::ReadFileToString(FilePath(output_file_), &contents));
+  EXPECT_NE(std::string::npos, contents.find("Unable to set UID to 0: 1\n"));
+}
+
+TEST_F(ProcessTest, WithIllegalGid) {
+  ASSERT_NE(0, getegid());
+  process_.AddArg(kBinEcho);
+  process_.SetGid(0);
+  EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run());
+  std::string contents;
+  EXPECT_TRUE(base::ReadFileToString(FilePath(output_file_), &contents));
+  EXPECT_NE(std::string::npos, contents.find("Unable to set GID to 0: 1\n"));
+}
+
+TEST_F(ProcessTest, NoParams) {
+  EXPECT_EQ(-1, process_.Run());
+}
+
+#if !defined(__BIONIC__)  // Bionic intercepts the segfault on Android.
+TEST_F(ProcessTest, SegFaultHandling) {
+  process_.AddArg(kBinSh);
+  process_.AddArg("-c");
+  process_.AddArg("kill -SEGV $$");
+  EXPECT_EQ(-1, process_.Run());
+  EXPECT_TRUE(FindLog("did not exit normally: 11"));
+}
+#endif
+
+TEST_F(ProcessTest, KillHandling) {
+  process_.AddArg(kBinSh);
+  process_.AddArg("-c");
+  process_.AddArg("kill -KILL $$");
+  EXPECT_EQ(-1, process_.Run());
+  EXPECT_TRUE(FindLog("did not exit normally: 9"));
+}
+
+
+TEST_F(ProcessTest, KillNoPid) {
+  process_.Kill(SIGTERM, 0);
+  EXPECT_TRUE(FindLog("Process not running"));
+}
+
+TEST_F(ProcessTest, ProcessExists) {
+  EXPECT_FALSE(Process::ProcessExists(0));
+  EXPECT_TRUE(Process::ProcessExists(1));
+  EXPECT_TRUE(Process::ProcessExists(getpid()));
+}
+
+TEST_F(ProcessTest, ResetPidByFile) {
+  FilePath pid_path = temp_dir_.path().Append("pid");
+  EXPECT_FALSE(process_.ResetPidByFile(pid_path.value()));
+  EXPECT_TRUE(base::WriteFile(pid_path, "456\n", 4));
+  EXPECT_TRUE(process_.ResetPidByFile(pid_path.value()));
+  EXPECT_EQ(456, process_.pid());
+  // The purpose of this unit test is to check if Process::ResetPidByFile() can
+  // properly read a pid from a file. We don't really want to kill the process
+  // with pid 456, so update the pid to 0 to prevent the Process destructor from
+  // killing any innocent process.
+  process_.UpdatePid(0);
+}
+
+TEST_F(ProcessTest, KillSleeper) {
+  process_.AddArg(kBinSleep);
+  process_.AddArg("10000");
+  ASSERT_TRUE(process_.Start());
+  pid_t pid = process_.pid();
+  ASSERT_GT(pid, 1);
+  EXPECT_TRUE(process_.Kill(SIGTERM, 1));
+  EXPECT_EQ(0, process_.pid());
+}
+
+TEST_F(ProcessTest, Reset) {
+  process_.AddArg(kBinFalse);
+  process_.Reset(0);
+  process_.AddArg(kBinEcho);
+  EXPECT_EQ(0, process_.Run());
+}
+
+bool ReturnFalse() { return false; }
+
+TEST_F(ProcessTest, PreExecCallback) {
+  process_.AddArg(kBinTrue);
+  process_.SetPreExecCallback(base::Bind(&ReturnFalse));
+  ASSERT_NE(0, process_.Run());
+}
+
+TEST_F(ProcessTest, LeakUnusedFileDescriptors) {
+  ScopedPipe pipe;
+  process_.AddArg(kBinStat);
+  process_.AddArg(GetFdPath(pipe.reader).value());
+  process_.AddArg(GetFdPath(pipe.writer).value());
+  process_.SetCloseUnusedFileDescriptors(false);
+  EXPECT_EQ(0, process_.Run());
+}
+
+TEST_F(ProcessTest, CloseUnusedFileDescriptors) {
+  ScopedPipe pipe;
+  process_.AddArg(kBinStat);
+  process_.AddArg(GetFdPath(pipe.reader).value());
+  process_.AddArg(GetFdPath(pipe.writer).value());
+  process_.SetCloseUnusedFileDescriptors(true);
+  // Stat should fail when running on these file descriptor because the files
+  // should not be there.
+  EXPECT_EQ(1, process_.Run());
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/secure_blob.cc b/libbrillo/brillo/secure_blob.cc
new file mode 100644
index 0000000..9e6d570
--- /dev/null
+++ b/libbrillo/brillo/secure_blob.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium OS 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 <cstring>  // memcpy
+
+#include <base/stl_util.h>
+
+#include "brillo/secure_blob.h"
+
+namespace brillo {
+
+SecureBlob::SecureBlob(const std::string& data)
+    : SecureBlob(data.begin(), data.end()) {}
+
+SecureBlob::~SecureBlob() {
+  clear();
+}
+
+void SecureBlob::resize(size_type count) {
+  if (count < size()) {
+    SecureMemset(data() + count, 0, capacity() - count);
+  }
+  Blob::resize(count);
+}
+
+void SecureBlob::resize(size_type count, const value_type& value) {
+  if (count < size()) {
+    SecureMemset(data() + count, 0, capacity() - count);
+  }
+  Blob::resize(count, value);
+}
+
+void SecureBlob::clear() {
+  SecureMemset(data(), 0, capacity());
+  Blob::clear();
+}
+
+std::string SecureBlob::to_string() const {
+  return std::string(data(), data() + size());
+}
+
+SecureBlob SecureBlob::Combine(const SecureBlob& blob1,
+                               const SecureBlob& blob2) {
+  SecureBlob result;
+  result.reserve(blob1.size() + blob2.size());
+  result.insert(result.end(), blob1.begin(), blob1.end());
+  result.insert(result.end(), blob2.begin(), blob2.end());
+  return result;
+}
+
+void* SecureMemset(void* v, int c, size_t n) {
+  volatile uint8_t* p = reinterpret_cast<volatile uint8_t*>(v);
+  while (n--)
+    *p++ = c;
+  return v;
+}
+
+int SecureMemcmp(const void* s1, const void* s2, size_t n) {
+  const uint8_t* us1 = reinterpret_cast<const uint8_t*>(s1);
+  const uint8_t* us2 = reinterpret_cast<const uint8_t*>(s2);
+  int result = 0;
+
+  if (0 == n)
+    return 1;
+
+  /* Code snippet without data-dependent branch due to
+   * Nate Lawson (nate@root.org) of Root Labs. */
+  while (n--)
+    result |= *us1++ ^ *us2++;
+
+  return result != 0;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/secure_blob.h b/libbrillo/brillo/secure_blob.h
new file mode 100644
index 0000000..b6111c7
--- /dev/null
+++ b/libbrillo/brillo/secure_blob.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium OS 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 LIBBRILLO_BRILLO_SECURE_BLOB_H_
+#define LIBBRILLO_BRILLO_SECURE_BLOB_H_
+
+#include <string>
+#include <vector>
+
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+using Blob = std::vector<uint8_t>;
+
+// SecureBlob erases the contents on destruction.  It does not guarantee erasure
+// on resize, assign, etc.
+class BRILLO_EXPORT SecureBlob : public Blob {
+ public:
+  SecureBlob() = default;
+  using Blob::vector;  // Inherit standard constructors from vector.
+  explicit SecureBlob(const std::string& data);
+  ~SecureBlob();
+
+  void resize(size_type count);
+  void resize(size_type count, const value_type& value);
+  void clear();
+
+  std::string to_string() const;
+  char* char_data() { return reinterpret_cast<char*>(data()); }
+  const char* char_data() const {
+    return reinterpret_cast<const char*>(data());
+  }
+  static SecureBlob Combine(const SecureBlob& blob1, const SecureBlob& blob2);
+};
+
+// Secure memset(). This function is guaranteed to fill in the whole buffer
+// and is not subject to compiler optimization as allowed by Sub-clause 5.1.2.3
+// of C Standard [ISO/IEC 9899:2011] which states:
+// In the abstract machine, all expressions are evaluated as specified by the
+// semantics. An actual implementation need not evaluate part of an expression
+// if it can deduce that its value is not used and that no needed side effects
+// are produced (including any caused by calling a function or accessing
+// a volatile object).
+// While memset() can be optimized out in certain situations (since most
+// compilers implement this function as intrinsic and know of its side effects),
+// this function will not be optimized out.
+BRILLO_EXPORT void* SecureMemset(void* v, int c, size_t n);
+
+// Compare [n] bytes starting at [s1] with [s2] and return 0 if they match,
+// 1 if they don't. Time taken to perform the comparison is only dependent on
+// [n] and not on the relationship of the match between [s1] and [s2].
+BRILLO_EXPORT int SecureMemcmp(const void* s1, const void* s2, size_t n);
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_SECURE_BLOB_H_
diff --git a/libbrillo/brillo/secure_blob_unittest.cc b/libbrillo/brillo/secure_blob_unittest.cc
new file mode 100644
index 0000000..d4fd555
--- /dev/null
+++ b/libbrillo/brillo/secure_blob_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Unit tests for SecureBlob.
+
+#include "brillo/secure_blob.h"
+
+#include <algorithm>
+#include <iterator>
+#include <numeric>
+
+#include <base/logging.h>
+#include <gtest/gtest.h>
+
+namespace brillo {
+using std::string;
+
+class SecureBlobTest : public ::testing::Test {
+ public:
+  SecureBlobTest() {}
+  virtual ~SecureBlobTest() {}
+
+  static bool FindBlobInBlob(const brillo::Blob& haystack,
+                             const brillo::Blob& needle) {
+    auto pos = std::search(
+        haystack.begin(), haystack.end(), needle.begin(), needle.end());
+    return (pos != haystack.end());
+  }
+
+  static int FindBlobIndexInBlob(const brillo::Blob& haystack,
+                                 const brillo::Blob& needle) {
+    auto pos = std::search(
+        haystack.begin(), haystack.end(), needle.begin(), needle.end());
+    if (pos == haystack.end()) {
+      return -1;
+    }
+    return std::distance(haystack.begin(), pos);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SecureBlobTest);
+};
+
+TEST_F(SecureBlobTest, AllocationSizeTest) {
+  // Check that allocating a SecureBlob of a specified size works
+  SecureBlob blob(32);
+
+  EXPECT_EQ(32, blob.size());
+}
+
+TEST_F(SecureBlobTest, AllocationCopyTest) {
+  // Check that allocating a SecureBlob with an iterator works
+  unsigned char from_data[32];
+  std::iota(std::begin(from_data), std::end(from_data), 0);
+
+  SecureBlob blob(std::begin(from_data), std::end(from_data));
+
+  EXPECT_EQ(sizeof(from_data), blob.size());
+
+  for (unsigned int i = 0; i < sizeof(from_data); i++) {
+    EXPECT_EQ(from_data[i], blob[i]);
+  }
+}
+
+TEST_F(SecureBlobTest, IteratorConstructorTest) {
+  // Check that allocating a SecureBlob with an iterator works
+  brillo::Blob from_blob(32);
+  for (unsigned int i = 0; i < from_blob.size(); i++) {
+    from_blob[i] = i;
+  }
+
+  SecureBlob blob(from_blob.begin(), from_blob.end());
+
+  EXPECT_EQ(from_blob.size(), blob.size());
+  EXPECT_TRUE(SecureBlobTest::FindBlobInBlob(from_blob, blob));
+}
+
+TEST_F(SecureBlobTest, ResizeTest) {
+  // Check that resizing a SecureBlob wipes the excess memory.  The test assumes
+  // that resize() down by one will not re-allocate the memory, so the last byte
+  // will still be part of the SecureBlob's allocation
+  size_t length = 1024;
+  SecureBlob blob(length);
+  void* original_data = blob.data();
+  for (size_t i = 0; i < length; i++) {
+    blob[i] = i;
+  }
+
+  blob.resize(length - 1);
+
+  EXPECT_EQ(original_data, blob.data());
+  EXPECT_EQ(length - 1, blob.size());
+  EXPECT_EQ(0, blob.data()[length - 1]);
+}
+
+TEST_F(SecureBlobTest, CombineTest) {
+  SecureBlob blob1(32);
+  SecureBlob blob2(32);
+  std::iota(blob1.begin(), blob1.end(), 0);
+  std::iota(blob2.begin(), blob2.end(), 32);
+  SecureBlob combined_blob = SecureBlob::Combine(blob1, blob2);
+  EXPECT_EQ(combined_blob.size(), (blob1.size() + blob2.size()));
+  EXPECT_TRUE(SecureBlobTest::FindBlobInBlob(combined_blob, blob1));
+  EXPECT_TRUE(SecureBlobTest::FindBlobInBlob(combined_blob, blob2));
+  int blob1_index = SecureBlobTest::FindBlobIndexInBlob(combined_blob, blob1);
+  int blob2_index = SecureBlobTest::FindBlobIndexInBlob(combined_blob, blob2);
+  EXPECT_EQ(blob1_index, 0);
+  EXPECT_EQ(blob2_index, 32);
+}
+
+TEST_F(SecureBlobTest, BlobToStringTest) {
+  std::string test_string("Test String");
+  SecureBlob blob = SecureBlob(test_string.begin(), test_string.end());
+  EXPECT_EQ(blob.size(), test_string.length());
+  std::string result_string = blob.to_string();
+  EXPECT_EQ(test_string.compare(result_string), 0);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/fake_stream.cc b/libbrillo/brillo/streams/fake_stream.cc
new file mode 100644
index 0000000..0428935
--- /dev/null
+++ b/libbrillo/brillo/streams/fake_stream.cc
@@ -0,0 +1,404 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/fake_stream.h>
+
+#include <algorithm>
+
+#include <base/bind.h>
+#include <brillo/message_loops/message_loop.h>
+#include <brillo/streams/stream_utils.h>
+
+namespace brillo {
+
+namespace {
+
+// Gets a delta between the two times, makes sure that the delta is positive.
+base::TimeDelta CalculateDelay(const base::Time& now,
+                               const base::Time& delay_until) {
+  const base::TimeDelta zero_delay;
+  if (delay_until.is_null() || now >= delay_until) {
+    return zero_delay;
+  }
+
+  base::TimeDelta delay = delay_until - now;
+  if (delay < zero_delay)
+    delay = zero_delay;
+  return delay;
+}
+
+// Given the current clock time, and expected delays for read and write
+// operations calculates the smaller wait delay of the two and sets the
+// resulting operation to |*mode| and the delay to wait for into |*delay|.
+void GetMinDelayAndMode(const base::Time& now,
+                        bool read, const base::Time& delay_read_until,
+                        bool write, const base::Time& delay_write_until,
+                        Stream::AccessMode* mode, base::TimeDelta* delay) {
+  base::TimeDelta read_delay = base::TimeDelta::Max();
+  base::TimeDelta write_delay = base::TimeDelta::Max();
+
+  if (read)
+    read_delay = CalculateDelay(now, delay_read_until);
+  if (write)
+    write_delay = CalculateDelay(now, delay_write_until);
+
+  if (read_delay > write_delay) {
+    read = false;
+  } else if (read_delay < write_delay) {
+    write = false;
+  }
+  *mode = stream_utils::MakeAccessMode(read, write);
+  *delay = std::min(read_delay, write_delay);
+}
+
+}  // anonymous namespace
+
+FakeStream::FakeStream(Stream::AccessMode mode,
+                       base::Clock* clock)
+    : mode_{mode}, clock_{clock} {}
+
+void FakeStream::AddReadPacketData(base::TimeDelta delay,
+                                   const void* data,
+                                   size_t size) {
+  auto* byte_ptr = static_cast<const uint8_t*>(data);
+  AddReadPacketData(delay, brillo::Blob{byte_ptr, byte_ptr + size});
+}
+
+void FakeStream::AddReadPacketData(base::TimeDelta delay, brillo::Blob data) {
+  InputDataPacket packet;
+  packet.data = std::move(data);
+  packet.delay_before = delay;
+  incoming_queue_.push(std::move(packet));
+}
+
+void FakeStream::AddReadPacketString(base::TimeDelta delay,
+                                     const std::string& data) {
+  AddReadPacketData(delay, brillo::Blob{data.begin(), data.end()});
+}
+
+void FakeStream::QueueReadError(base::TimeDelta delay) {
+  QueueReadErrorWithMessage(delay, std::string{});
+}
+
+void FakeStream::QueueReadErrorWithMessage(base::TimeDelta delay,
+                                           const std::string& message) {
+  InputDataPacket packet;
+  packet.data.assign(message.begin(), message.end());
+  packet.delay_before = delay;
+  packet.read_error = true;
+  incoming_queue_.push(std::move(packet));
+}
+
+void FakeStream::ClearReadQueue() {
+  std::queue<InputDataPacket>().swap(incoming_queue_);
+  delay_input_until_ = base::Time{};
+  input_buffer_.clear();
+  input_ptr_ = 0;
+  report_read_error_ = 0;
+}
+
+void FakeStream::ExpectWritePacketSize(base::TimeDelta delay,
+                                       size_t data_size) {
+  OutputDataPacket packet;
+  packet.expected_size = data_size;
+  packet.delay_before = delay;
+  outgoing_queue_.push(std::move(packet));
+}
+
+void FakeStream::ExpectWritePacketData(base::TimeDelta delay,
+                                       const void* data,
+                                       size_t size) {
+  auto* byte_ptr = static_cast<const uint8_t*>(data);
+  ExpectWritePacketData(delay, brillo::Blob{byte_ptr, byte_ptr + size});
+}
+
+void FakeStream::ExpectWritePacketData(base::TimeDelta delay,
+                                       brillo::Blob data) {
+  OutputDataPacket packet;
+  packet.expected_size = data.size();
+  packet.data = std::move(data);
+  packet.delay_before = delay;
+  outgoing_queue_.push(std::move(packet));
+}
+
+void FakeStream::ExpectWritePacketString(base::TimeDelta delay,
+                                         const std::string& data) {
+  ExpectWritePacketData(delay, brillo::Blob{data.begin(), data.end()});
+}
+
+void FakeStream::QueueWriteError(base::TimeDelta delay) {
+  QueueWriteErrorWithMessage(delay, std::string{});
+}
+
+void FakeStream::QueueWriteErrorWithMessage(base::TimeDelta delay,
+                                            const std::string& message) {
+  OutputDataPacket packet;
+  packet.expected_size = 0;
+  packet.data.assign(message.begin(), message.end());
+  packet.delay_before = delay;
+  packet.write_error = true;
+  outgoing_queue_.push(std::move(packet));
+}
+
+void FakeStream::ClearWriteQueue() {
+  std::queue<OutputDataPacket>().swap(outgoing_queue_);
+  delay_output_until_ = base::Time{};
+  output_buffer_.clear();
+  expected_output_data_.clear();
+  max_output_buffer_size_ = 0;
+  all_output_data_.clear();
+  report_write_error_ = 0;
+}
+
+const brillo::Blob& FakeStream::GetFlushedOutputData() const {
+  return all_output_data_;
+}
+
+std::string FakeStream::GetFlushedOutputDataAsString() const {
+  return std::string{all_output_data_.begin(), all_output_data_.end()};
+}
+
+bool FakeStream::CanRead() const {
+  return stream_utils::IsReadAccessMode(mode_);
+}
+
+bool FakeStream::CanWrite() const {
+  return stream_utils::IsWriteAccessMode(mode_);
+}
+
+bool FakeStream::SetSizeBlocking(uint64_t /* size */, ErrorPtr* error) {
+  return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+}
+
+bool FakeStream::Seek(int64_t /* offset */,
+                      Whence /* whence */,
+                      uint64_t* /* new_position */,
+                      ErrorPtr* error) {
+  return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+}
+
+bool FakeStream::IsReadBufferEmpty() const {
+  return input_ptr_ >= input_buffer_.size();
+}
+
+bool FakeStream::PopReadPacket() {
+  if (incoming_queue_.empty())
+    return false;
+  const InputDataPacket& packet = incoming_queue_.front();
+  input_ptr_ = 0;
+  input_buffer_ = std::move(packet.data);
+  delay_input_until_ = clock_->Now() + packet.delay_before;
+  incoming_queue_.pop();
+  report_read_error_ = packet.read_error;
+  return true;
+}
+
+bool FakeStream::ReadNonBlocking(void* buffer,
+                                 size_t size_to_read,
+                                 size_t* size_read,
+                                 bool* end_of_stream,
+                                 ErrorPtr* error) {
+  if (!CanRead())
+    return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  for (;;) {
+    if (!delay_input_until_.is_null() && clock_->Now() < delay_input_until_) {
+      *size_read = 0;
+      if (end_of_stream)
+        *end_of_stream = false;
+      break;
+    }
+
+    if (report_read_error_) {
+      report_read_error_ = false;
+      std::string message{input_buffer_.begin(), input_buffer_.end()};
+      if (message.empty())
+        message = "Simulating read error for tests";
+      input_buffer_.clear();
+      Error::AddTo(error, FROM_HERE, "fake_stream", "read_error", message);
+      return false;
+    }
+
+    if (!IsReadBufferEmpty()) {
+      size_to_read = std::min(size_to_read, input_buffer_.size() - input_ptr_);
+      std::memcpy(buffer, input_buffer_.data() + input_ptr_, size_to_read);
+      input_ptr_ += size_to_read;
+      *size_read = size_to_read;
+      if (end_of_stream)
+        *end_of_stream = false;
+      break;
+    }
+
+    if (!PopReadPacket()) {
+      *size_read = 0;
+      if (end_of_stream)
+        *end_of_stream = true;
+      break;
+    }
+  }
+  return true;
+}
+
+bool FakeStream::IsWriteBufferFull() const {
+  return output_buffer_.size() >= max_output_buffer_size_;
+}
+
+bool FakeStream::PopWritePacket() {
+  if (outgoing_queue_.empty())
+    return false;
+  const OutputDataPacket& packet = outgoing_queue_.front();
+  expected_output_data_ = std::move(packet.data);
+  delay_output_until_ = clock_->Now() + packet.delay_before;
+  max_output_buffer_size_ = packet.expected_size;
+  report_write_error_ = packet.write_error;
+  outgoing_queue_.pop();
+  return true;
+}
+
+bool FakeStream::WriteNonBlocking(const void* buffer,
+                                  size_t size_to_write,
+                                  size_t* size_written,
+                                  ErrorPtr* error) {
+  if (!CanWrite())
+    return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  for (;;) {
+    if (!delay_output_until_.is_null() && clock_->Now() < delay_output_until_) {
+      *size_written = 0;
+      return true;
+    }
+
+    if (report_write_error_) {
+      report_write_error_ = false;
+      std::string message{expected_output_data_.begin(),
+                          expected_output_data_.end()};
+      if (message.empty())
+        message = "Simulating write error for tests";
+      output_buffer_.clear();
+      max_output_buffer_size_ = 0;
+      expected_output_data_.clear();
+      Error::AddTo(error, FROM_HERE, "fake_stream", "write_error", message);
+      return false;
+    }
+
+    if (!IsWriteBufferFull()) {
+      bool success = true;
+      size_to_write = std::min(size_to_write,
+                               max_output_buffer_size_ - output_buffer_.size());
+      auto byte_ptr = static_cast<const uint8_t*>(buffer);
+      output_buffer_.insert(output_buffer_.end(),
+                            byte_ptr, byte_ptr + size_to_write);
+      if (output_buffer_.size()  == max_output_buffer_size_) {
+        if (!expected_output_data_.empty() &&
+            expected_output_data_ != output_buffer_) {
+          // We expected different data to be written, report an error.
+          Error::AddTo(error, FROM_HERE, "fake_stream", "data_mismatch",
+                       "Unexpected data written");
+          success = false;
+        }
+
+        all_output_data_.insert(all_output_data_.end(),
+                                output_buffer_.begin(), output_buffer_.end());
+
+        output_buffer_.clear();
+        max_output_buffer_size_ = 0;
+        expected_output_data_.clear();
+      }
+      *size_written = size_to_write;
+      return success;
+    }
+
+    if (!PopWritePacket()) {
+      // No more data expected.
+      Error::AddTo(error, FROM_HERE, "fake_stream", "full",
+                   "No more output data expected");
+      return false;
+    }
+  }
+}
+
+bool FakeStream::FlushBlocking(ErrorPtr* error) {
+  if (!CanWrite())
+    return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  bool success = true;
+  if (!output_buffer_.empty()) {
+    if (!expected_output_data_.empty() &&
+        expected_output_data_ != output_buffer_) {
+      // We expected different data to be written, report an error.
+      Error::AddTo(error, FROM_HERE, "fake_stream", "data_mismatch",
+                   "Unexpected data written");
+      success = false;
+    }
+    all_output_data_.insert(all_output_data_.end(),
+                            output_buffer_.begin(), output_buffer_.end());
+
+    output_buffer_.clear();
+    max_output_buffer_size_ = 0;
+    expected_output_data_.clear();
+  }
+  return success;
+}
+
+bool FakeStream::CloseBlocking(ErrorPtr* /* error */) {
+  is_open_ = false;
+  return true;
+}
+
+bool FakeStream::WaitForData(AccessMode mode,
+                             const base::Callback<void(AccessMode)>& callback,
+                             ErrorPtr* error) {
+  bool read_requested = stream_utils::IsReadAccessMode(mode);
+  bool write_requested = stream_utils::IsWriteAccessMode(mode);
+
+  if ((read_requested && !CanRead()) || (write_requested && !CanWrite()))
+    return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+
+  if (read_requested && IsReadBufferEmpty())
+    PopReadPacket();
+  if (write_requested && IsWriteBufferFull())
+    PopWritePacket();
+
+  base::TimeDelta delay;
+  GetMinDelayAndMode(clock_->Now(), read_requested, delay_input_until_,
+                     write_requested, delay_output_until_, &mode, &delay);
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE, base::Bind(callback, mode), delay);
+  return true;
+}
+
+bool FakeStream::WaitForDataBlocking(AccessMode in_mode,
+                                     base::TimeDelta timeout,
+                                     AccessMode* out_mode,
+                                     ErrorPtr* error) {
+  const base::TimeDelta zero_delay;
+  bool read_requested = stream_utils::IsReadAccessMode(in_mode);
+  bool write_requested = stream_utils::IsWriteAccessMode(in_mode);
+
+  if ((read_requested && !CanRead()) || (write_requested && !CanWrite()))
+    return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+
+  base::TimeDelta delay;
+  GetMinDelayAndMode(clock_->Now(), read_requested, delay_input_until_,
+                     write_requested, delay_output_until_, out_mode, &delay);
+
+  if (timeout < delay)
+    return stream_utils::ErrorOperationTimeout(FROM_HERE, error);
+
+  LOG(INFO) << "TEST: Would have blocked for " << delay.InMilliseconds()
+            << " ms.";
+
+  return true;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/fake_stream.h b/libbrillo/brillo/streams/fake_stream.h
new file mode 100644
index 0000000..fb9b522
--- /dev/null
+++ b/libbrillo/brillo/streams/fake_stream.h
@@ -0,0 +1,171 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_STREAMS_FAKE_STREAM_H_
+#define LIBBRILLO_BRILLO_STREAMS_FAKE_STREAM_H_
+
+#include <queue>
+#include <string>
+
+#include <base/callback_forward.h>
+#include <base/macros.h>
+#include <base/time/clock.h>
+#include <base/time/time.h>
+#include <brillo/secure_blob.h>
+#include <brillo/streams/stream.h>
+
+namespace brillo {
+
+// Fake stream implementation for testing.
+// This class allows to provide data for the stream in tests that can be later
+// read through the Stream interface. Also, data written into the stream can be
+// later inspected and verified.
+//
+// NOTE: This class provides a fake implementation for streams with separate
+// input and output channels. That is, read and write operations do not affect
+// each other. Also, the stream implementation is sequential only (no seeking).
+// Good examples of a use case for fake stream are:
+//  - read-only sequential streams (file, memory, pipe, ...)
+//  - write-only sequential streams (same as above)
+//  - independent channel read-write streams (sockets, ...)
+//
+// For more complex read/write stream test scenarios using a real MemoryStream
+// or temporary FileStream is probably a better choice.
+class FakeStream : public Stream {
+ public:
+  // Construct a new instance of the fake stream.
+  //   mode        - expected read/write mode supported by the stream.
+  //   clock       - the clock to use to get the current time.
+  FakeStream(Stream::AccessMode mode,
+             base::Clock* clock);
+
+  // Add data packets to the read queue of the stream.
+  // Optional |delay| indicates that the data packet should be delayed.
+  void AddReadPacketData(base::TimeDelta delay, const void* data, size_t size);
+  void AddReadPacketData(base::TimeDelta delay, brillo::Blob data);
+  void AddReadPacketString(base::TimeDelta delay, const std::string& data);
+
+  // Schedule a read error by adding a special error packet to the queue.
+  void QueueReadError(base::TimeDelta delay);
+  void QueueReadErrorWithMessage(base::TimeDelta delay,
+                                 const std::string& message);
+
+  // Resets read queue and clears any input data buffers.
+  void ClearReadQueue();
+
+  // Add expectations for output data packets to be written by the stream.
+  // Optional |delay| indicates that the initial write operation for the data in
+  // the packet should be delayed.
+  // ExpectWritePacketSize just limits the size of output packet while
+  // ExpectWritePacketData also validates that the data matches that of |data|.
+  void ExpectWritePacketSize(base::TimeDelta delay, size_t data_size);
+  void ExpectWritePacketData(base::TimeDelta delay,
+                             const void* data,
+                             size_t size);
+  void ExpectWritePacketData(base::TimeDelta delay, brillo::Blob data);
+  void ExpectWritePacketString(base::TimeDelta delay, const std::string& data);
+
+  // Schedule a write error by adding a special error packet to the queue.
+  void QueueWriteError(base::TimeDelta delay);
+  void QueueWriteErrorWithMessage(base::TimeDelta delay,
+                                  const std::string& message);
+
+  // Resets write queue and clears any output data buffers.
+  void ClearWriteQueue();
+
+  // Returns the output data accumulated so far by all complete write packets,
+  // or explicitly flushed.
+  const brillo::Blob& GetFlushedOutputData() const;
+  std::string GetFlushedOutputDataAsString() const;
+
+  // Overrides from brillo::Stream.
+  bool IsOpen() const override { return is_open_; }
+  bool CanRead() const override;
+  bool CanWrite() const override;
+  bool CanSeek() const override { return false; }
+  bool CanGetSize() const override { return false; }
+  uint64_t GetSize() const override { return 0; }
+  bool SetSizeBlocking(uint64_t size, ErrorPtr* error) override;
+  uint64_t GetRemainingSize() const override { return 0; }
+  uint64_t GetPosition() const override { return 0; }
+  bool Seek(int64_t offset,
+            Whence whence,
+            uint64_t* new_position,
+            ErrorPtr* error) override;
+
+  bool ReadNonBlocking(void* buffer,
+                       size_t size_to_read,
+                       size_t* size_read,
+                       bool* end_of_stream,
+                       ErrorPtr* error) override;
+  bool WriteNonBlocking(const void* buffer,
+                        size_t size_to_write,
+                        size_t* size_written,
+                        ErrorPtr* error) override;
+  bool FlushBlocking(ErrorPtr* error) override;
+  bool CloseBlocking(ErrorPtr* error) override;
+  bool WaitForData(AccessMode mode,
+                   const base::Callback<void(AccessMode)>& callback,
+                   ErrorPtr* error) override;
+  bool WaitForDataBlocking(AccessMode in_mode,
+                           base::TimeDelta timeout,
+                           AccessMode* out_mode,
+                           ErrorPtr* error) override;
+
+ private:
+  // Input data packet to be placed on the read queue.
+  struct InputDataPacket {
+    brillo::Blob data;  // Data to be read.
+    base::TimeDelta delay_before;  // Possible delay for the first read.
+    bool read_error{false};  // Set to true if this packet generates an error.
+  };
+
+  // Output data packet to be placed on the write queue.
+  struct OutputDataPacket {
+    size_t expected_size{0};  // Output packet size
+    brillo::Blob data;  // Possible data to verify the output with.
+    base::TimeDelta delay_before;  // Possible delay for the first write.
+    bool write_error{false};  // Set to true if this packet generates an error.
+  };
+
+  // Check if there is any pending read data in the input buffer.
+  bool IsReadBufferEmpty() const;
+  // Pops the next read packet from the queue and sets its data into the
+  // internal input buffer.
+  bool PopReadPacket();
+
+  // Check if the output buffer is full.
+  bool IsWriteBufferFull() const;
+
+  // Moves the current full output buffer into |all_output_data_|, clears the
+  // buffer, and pops the information about the next expected output packet
+  // from the write queue.
+  bool PopWritePacket();
+
+  bool is_open_{true};
+  Stream::AccessMode mode_;
+  base::Clock* clock_;
+
+  // Internal data for read operations.
+  std::queue<InputDataPacket> incoming_queue_;
+  base::Time delay_input_until_;
+  brillo::Blob input_buffer_;
+  size_t input_ptr_{0};
+  bool report_read_error_{false};
+
+  // Internal data for write operations.
+  std::queue<OutputDataPacket> outgoing_queue_;
+  base::Time delay_output_until_;
+  brillo::Blob output_buffer_;
+  brillo::Blob expected_output_data_;
+  size_t max_output_buffer_size_{0};
+  bool report_write_error_{false};
+  brillo::Blob all_output_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeStream);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_STREAMS_FAKE_STREAM_H_
diff --git a/libbrillo/brillo/streams/fake_stream_unittest.cc b/libbrillo/brillo/streams/fake_stream_unittest.cc
new file mode 100644
index 0000000..df8b223
--- /dev/null
+++ b/libbrillo/brillo/streams/fake_stream_unittest.cc
@@ -0,0 +1,535 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/fake_stream.h>
+
+#include <vector>
+
+#include <base/callback.h>
+#include <base/test/simple_test_clock.h>
+#include <brillo/bind_lambda.h>
+#include <brillo/message_loops/mock_message_loop.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::AnyNumber;
+using testing::InSequence;
+using testing::_;
+
+namespace brillo {
+
+class FakeStreamTest : public testing::Test {
+ public:
+  void SetUp() override {
+    mock_loop_.SetAsCurrent();
+    // Ignore calls to RunOnce().
+    EXPECT_CALL(mock_loop_, RunOnce(true)).Times(AnyNumber());
+  }
+
+  void CreateStream(Stream::AccessMode mode) {
+    stream_.reset(new FakeStream{mode, &clock_});
+  }
+
+  // Performs non-blocking read on the stream and returns the read data
+  // as a string in |out_buffer|. Returns true if the read was successful or
+  // false when an error occurs. |*eos| is set to true when end of stream is
+  // reached.
+  bool ReadString(size_t size_to_read, std::string* out_buffer, bool* eos) {
+    std::vector<char> data;
+    data.resize(size_to_read);
+    size_t size_read = 0;
+    bool ok = stream_->ReadNonBlocking(data.data(), data.size(), &size_read,
+                                       eos, nullptr);
+    if (ok) {
+      out_buffer->assign(data.data(), data.data() + size_read);
+    } else {
+      out_buffer->clear();
+    }
+    return ok;
+  }
+
+  // Writes a string to a stream. Returns the number of bytes written or -1
+  // in case an error occurred.
+  int WriteString(const std::string& data) {
+    size_t written = 0;
+    if (!stream_->WriteNonBlocking(data.data(), data.size(), &written, nullptr))
+      return -1;
+    return static_cast<int>(written);
+  }
+
+ protected:
+  base::SimpleTestClock clock_;
+  MockMessageLoop mock_loop_{&clock_};
+  std::unique_ptr<FakeStream> stream_;
+  const base::TimeDelta zero_delay;
+};
+
+TEST_F(FakeStreamTest, InitReadOnly) {
+  CreateStream(Stream::AccessMode::READ);
+  EXPECT_TRUE(stream_->IsOpen());
+  EXPECT_TRUE(stream_->CanRead());
+  EXPECT_FALSE(stream_->CanWrite());
+  EXPECT_FALSE(stream_->CanSeek());
+  EXPECT_FALSE(stream_->CanGetSize());
+  EXPECT_EQ(0, stream_->GetSize());
+  EXPECT_EQ(0, stream_->GetRemainingSize());
+  EXPECT_EQ(0, stream_->GetPosition());
+}
+
+TEST_F(FakeStreamTest, InitWriteOnly) {
+  CreateStream(Stream::AccessMode::WRITE);
+  EXPECT_TRUE(stream_->IsOpen());
+  EXPECT_FALSE(stream_->CanRead());
+  EXPECT_TRUE(stream_->CanWrite());
+  EXPECT_FALSE(stream_->CanSeek());
+  EXPECT_FALSE(stream_->CanGetSize());
+  EXPECT_EQ(0, stream_->GetSize());
+  EXPECT_EQ(0, stream_->GetRemainingSize());
+  EXPECT_EQ(0, stream_->GetPosition());
+}
+
+TEST_F(FakeStreamTest, InitReadWrite) {
+  CreateStream(Stream::AccessMode::READ_WRITE);
+  EXPECT_TRUE(stream_->IsOpen());
+  EXPECT_TRUE(stream_->CanRead());
+  EXPECT_TRUE(stream_->CanWrite());
+  EXPECT_FALSE(stream_->CanSeek());
+  EXPECT_FALSE(stream_->CanGetSize());
+  EXPECT_EQ(0, stream_->GetSize());
+  EXPECT_EQ(0, stream_->GetRemainingSize());
+  EXPECT_EQ(0, stream_->GetPosition());
+}
+
+TEST_F(FakeStreamTest, ReadEmpty) {
+  CreateStream(Stream::AccessMode::READ);
+  std::string data;
+  bool eos = false;
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_TRUE(eos);
+  EXPECT_TRUE(data.empty());
+}
+
+TEST_F(FakeStreamTest, ReadFullPacket) {
+  CreateStream(Stream::AccessMode::READ);
+  stream_->AddReadPacketString({}, "foo");
+  std::string data;
+  bool eos = false;
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_EQ("foo", data);
+
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_TRUE(eos);
+  EXPECT_TRUE(data.empty());
+}
+
+TEST_F(FakeStreamTest, ReadPartialPacket) {
+  CreateStream(Stream::AccessMode::READ);
+  stream_->AddReadPacketString({}, "foobar");
+  std::string data;
+  bool eos = false;
+  EXPECT_TRUE(ReadString(3, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_EQ("foo", data);
+
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_EQ("bar", data);
+
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_TRUE(eos);
+  EXPECT_TRUE(data.empty());
+}
+
+TEST_F(FakeStreamTest, ReadMultiplePackets) {
+  CreateStream(Stream::AccessMode::READ);
+  stream_->AddReadPacketString({}, "foobar");
+  stream_->AddReadPacketString({}, "baz");
+  stream_->AddReadPacketString({}, "quux");
+  std::string data;
+  bool eos = false;
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_EQ("foobar", data);
+
+  EXPECT_TRUE(ReadString(2, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_EQ("ba", data);
+
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_EQ("z", data);
+
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_EQ("quux", data);
+
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_TRUE(eos);
+  EXPECT_TRUE(data.empty());
+
+  stream_->AddReadPacketString({}, "foo-bar");
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_EQ("foo-bar", data);
+}
+
+TEST_F(FakeStreamTest, ReadPacketsWithDelay) {
+  CreateStream(Stream::AccessMode::READ);
+  stream_->AddReadPacketString({}, "foobar");
+  stream_->AddReadPacketString(base::TimeDelta::FromSeconds(1), "baz");
+  std::string data;
+  bool eos = false;
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_EQ("foobar", data);
+
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_TRUE(data.empty());
+
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_TRUE(data.empty());
+
+  clock_.Advance(base::TimeDelta::FromSeconds(1));
+
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_EQ("baz", data);
+}
+
+TEST_F(FakeStreamTest, ReadPacketsWithError) {
+  CreateStream(Stream::AccessMode::READ);
+  stream_->AddReadPacketString({}, "foobar");
+  stream_->QueueReadErrorWithMessage(base::TimeDelta::FromSeconds(1),
+                                     "Dummy error");
+  stream_->AddReadPacketString({}, "baz");
+
+  std::string data;
+  bool eos = false;
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_EQ("foobar", data);
+
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_TRUE(data.empty());
+
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_TRUE(data.empty());
+
+  clock_.Advance(base::TimeDelta::FromSeconds(1));
+
+  EXPECT_FALSE(ReadString(100, &data, &eos));
+
+  EXPECT_TRUE(ReadString(100, &data, &eos));
+  EXPECT_FALSE(eos);
+  EXPECT_EQ("baz", data);
+}
+
+TEST_F(FakeStreamTest, WaitForDataRead) {
+  CreateStream(Stream::AccessMode::READ);
+
+  EXPECT_CALL(mock_loop_, PostDelayedTask(_, _, zero_delay)).Times(2);
+
+  int call_count = 0;
+  auto callback = [](int* call_count, Stream::AccessMode mode) {
+    (*call_count)++;
+    EXPECT_EQ(Stream::AccessMode::READ, mode);
+  };
+
+  EXPECT_TRUE(
+      stream_->WaitForData(Stream::AccessMode::READ,
+                           base::Bind(callback, base::Unretained(&call_count)),
+                           nullptr));
+  mock_loop_.Run();
+  EXPECT_EQ(1, call_count);
+
+  stream_->AddReadPacketString({}, "foobar");
+  EXPECT_TRUE(
+      stream_->WaitForData(Stream::AccessMode::READ,
+                           base::Bind(callback, base::Unretained(&call_count)),
+                           nullptr));
+  mock_loop_.Run();
+  EXPECT_EQ(2, call_count);
+
+  stream_->ClearReadQueue();
+
+  auto one_sec_delay = base::TimeDelta::FromSeconds(1);
+  stream_->AddReadPacketString(one_sec_delay, "baz");
+  EXPECT_CALL(mock_loop_, PostDelayedTask(_, _, one_sec_delay)).Times(1);
+  EXPECT_TRUE(
+      stream_->WaitForData(Stream::AccessMode::READ,
+                           base::Bind(callback, base::Unretained(&call_count)),
+                           nullptr));
+  mock_loop_.Run();
+  EXPECT_EQ(3, call_count);
+}
+
+TEST_F(FakeStreamTest, ReadAsync) {
+  CreateStream(Stream::AccessMode::READ);
+  std::string input_data = "foobar-baz";
+  size_t split_pos = input_data.find('-');
+
+  auto one_sec_delay = base::TimeDelta::FromSeconds(1);
+  stream_->AddReadPacketString({}, input_data.substr(0, split_pos));
+  stream_->AddReadPacketString(one_sec_delay, input_data.substr(split_pos));
+
+  {
+    InSequence seq;
+    EXPECT_CALL(mock_loop_, PostDelayedTask(_, _, zero_delay)).Times(1);
+    EXPECT_CALL(mock_loop_, PostDelayedTask(_, _, one_sec_delay)).Times(1);
+  }
+
+  std::vector<char> buffer;
+  buffer.resize(input_data.size());
+
+  int success_count = 0;
+  int error_count = 0;
+  auto on_success = [](int* success_count) { (*success_count)++; };
+  auto on_failure = [](int* error_count, const Error* /* error */) {
+    (*error_count)++;
+  };
+
+  EXPECT_TRUE(stream_->ReadAllAsync(
+      buffer.data(),
+      buffer.size(),
+      base::Bind(on_success, base::Unretained(&success_count)),
+      base::Bind(on_failure, base::Unretained(&error_count)),
+      nullptr));
+  mock_loop_.Run();
+  EXPECT_EQ(1, success_count);
+  EXPECT_EQ(0, error_count);
+  EXPECT_EQ(input_data, (std::string{buffer.begin(), buffer.end()}));
+}
+
+TEST_F(FakeStreamTest, WriteEmpty) {
+  CreateStream(Stream::AccessMode::WRITE);
+  EXPECT_EQ(-1, WriteString("foo"));
+}
+
+TEST_F(FakeStreamTest, WritePartial) {
+  CreateStream(Stream::AccessMode::WRITE);
+  stream_->ExpectWritePacketSize({}, 6);
+  EXPECT_EQ(3, WriteString("foo"));
+  EXPECT_EQ(3, WriteString("bar"));
+  EXPECT_EQ(-1, WriteString("baz"));
+
+  EXPECT_EQ("foobar", stream_->GetFlushedOutputDataAsString());
+}
+
+TEST_F(FakeStreamTest, WriteFullPackets) {
+  CreateStream(Stream::AccessMode::WRITE);
+
+  stream_->ExpectWritePacketSize({}, 3);
+  EXPECT_EQ(3, WriteString("foo"));
+  EXPECT_EQ(-1, WriteString("bar"));
+
+  stream_->ExpectWritePacketSize({}, 3);
+  EXPECT_EQ(3, WriteString("bar"));
+
+  stream_->ExpectWritePacketSize({}, 3);
+  EXPECT_EQ(3, WriteString("quux"));
+
+  EXPECT_EQ("foobarquu", stream_->GetFlushedOutputDataAsString());
+}
+
+TEST_F(FakeStreamTest, WriteAndVerifyData) {
+  CreateStream(Stream::AccessMode::WRITE);
+
+  stream_->ExpectWritePacketString({}, "foo");
+  stream_->ExpectWritePacketString({}, "bar");
+  EXPECT_EQ(3, WriteString("foobar"));
+  EXPECT_EQ(3, WriteString("bar"));
+
+  stream_->ExpectWritePacketString({}, "foo");
+  stream_->ExpectWritePacketString({}, "baz");
+  EXPECT_EQ(3, WriteString("foobar"));
+  EXPECT_EQ(-1, WriteString("bar"));
+
+  stream_->ExpectWritePacketString({}, "foobar");
+  EXPECT_EQ(3, WriteString("foo"));
+  EXPECT_EQ(2, WriteString("ba"));
+  EXPECT_EQ(-1, WriteString("z"));
+}
+
+TEST_F(FakeStreamTest, WriteWithDelay) {
+  CreateStream(Stream::AccessMode::WRITE);
+
+  const auto delay = base::TimeDelta::FromMilliseconds(500);
+
+  stream_->ExpectWritePacketSize({}, 3);
+  stream_->ExpectWritePacketSize(delay, 3);
+  EXPECT_EQ(3, WriteString("foobar"));
+
+  EXPECT_EQ(0, WriteString("bar"));
+  EXPECT_EQ(0, WriteString("bar"));
+  clock_.Advance(delay);
+  EXPECT_EQ(3, WriteString("bar"));
+
+  EXPECT_EQ("foobar", stream_->GetFlushedOutputDataAsString());
+}
+
+TEST_F(FakeStreamTest, WriteWithError) {
+  CreateStream(Stream::AccessMode::WRITE);
+
+  const auto delay = base::TimeDelta::FromMilliseconds(500);
+
+  stream_->ExpectWritePacketSize({}, 3);
+  stream_->QueueWriteError({});
+  stream_->ExpectWritePacketSize({}, 3);
+  stream_->QueueWriteErrorWithMessage(delay, "Dummy message");
+  stream_->ExpectWritePacketString({}, "foobar");
+
+  const std::string data = "foobarbaz";
+  EXPECT_EQ(3, WriteString(data));
+  EXPECT_EQ(-1, WriteString(data));  // Simulated error #1.
+  EXPECT_EQ(3, WriteString(data));
+  EXPECT_EQ(0, WriteString(data));  // Waiting for data...
+  clock_.Advance(delay);
+  EXPECT_EQ(-1, WriteString(data));  // Simulated error #2.
+  EXPECT_EQ(6, WriteString(data));
+  EXPECT_EQ(-1, WriteString(data));  // No more data expected.
+}
+
+TEST_F(FakeStreamTest, WaitForDataWrite) {
+  CreateStream(Stream::AccessMode::WRITE);
+
+  EXPECT_CALL(mock_loop_, PostDelayedTask(_, _, zero_delay)).Times(2);
+
+  int call_count = 0;
+  auto callback = [](int* call_count, Stream::AccessMode mode) {
+    (*call_count)++;
+    EXPECT_EQ(Stream::AccessMode::WRITE, mode);
+  };
+
+  EXPECT_TRUE(
+      stream_->WaitForData(Stream::AccessMode::WRITE,
+                           base::Bind(callback, base::Unretained(&call_count)),
+                           nullptr));
+  mock_loop_.Run();
+  EXPECT_EQ(1, call_count);
+
+  stream_->ExpectWritePacketString({}, "foobar");
+  EXPECT_TRUE(
+      stream_->WaitForData(Stream::AccessMode::WRITE,
+                           base::Bind(callback, base::Unretained(&call_count)),
+                           nullptr));
+  mock_loop_.Run();
+  EXPECT_EQ(2, call_count);
+
+  stream_->ClearWriteQueue();
+
+  auto one_sec_delay = base::TimeDelta::FromSeconds(1);
+  stream_->ExpectWritePacketString(one_sec_delay, "baz");
+  EXPECT_CALL(mock_loop_, PostDelayedTask(_, _, one_sec_delay)).Times(1);
+  EXPECT_TRUE(
+      stream_->WaitForData(Stream::AccessMode::WRITE,
+                           base::Bind(callback, base::Unretained(&call_count)),
+                           nullptr));
+  mock_loop_.Run();
+  EXPECT_EQ(3, call_count);
+}
+
+TEST_F(FakeStreamTest, WriteAsync) {
+  CreateStream(Stream::AccessMode::WRITE);
+  std::string output_data = "foobar-baz";
+  size_t split_pos = output_data.find('-');
+
+  auto one_sec_delay = base::TimeDelta::FromSeconds(1);
+  stream_->ExpectWritePacketString({}, output_data.substr(0, split_pos));
+  stream_->ExpectWritePacketString(one_sec_delay,
+                                   output_data.substr(split_pos));
+
+  {
+    InSequence seq;
+    EXPECT_CALL(mock_loop_, PostDelayedTask(_, _, zero_delay)).Times(1);
+    EXPECT_CALL(mock_loop_, PostDelayedTask(_, _, one_sec_delay)).Times(1);
+  }
+
+  int success_count = 0;
+  int error_count = 0;
+  auto on_success = [](int* success_count) { (*success_count)++; };
+  auto on_failure = [](int* error_count, const Error* /* error */) {
+    (*error_count)++;
+  };
+
+  EXPECT_TRUE(stream_->WriteAllAsync(
+      output_data.data(),
+      output_data.size(),
+      base::Bind(on_success, base::Unretained(&success_count)),
+      base::Bind(on_failure, base::Unretained(&error_count)),
+      nullptr));
+  mock_loop_.Run();
+  EXPECT_EQ(1, success_count);
+  EXPECT_EQ(0, error_count);
+  EXPECT_EQ(output_data, stream_->GetFlushedOutputDataAsString());
+}
+
+TEST_F(FakeStreamTest, WaitForDataReadWrite) {
+  CreateStream(Stream::AccessMode::READ_WRITE);
+  auto one_sec_delay = base::TimeDelta::FromSeconds(1);
+  auto two_sec_delay = base::TimeDelta::FromSeconds(2);
+
+  int call_count = 0;
+  auto callback = [](int* call_count,
+                     Stream::AccessMode mode,
+                     Stream::AccessMode expected_mode) {
+    (*call_count)++;
+    EXPECT_EQ(static_cast<int>(expected_mode), static_cast<int>(mode));
+  };
+
+  stream_->AddReadPacketString(one_sec_delay, "foo");
+  stream_->ExpectWritePacketString(two_sec_delay, "bar");
+
+  EXPECT_CALL(mock_loop_, PostDelayedTask(_, _, one_sec_delay)).Times(1);
+  EXPECT_TRUE(stream_->WaitForData(Stream::AccessMode::READ_WRITE,
+                                   base::Bind(callback,
+                                              base::Unretained(&call_count),
+                                              Stream::AccessMode::READ),
+                                   nullptr));
+  mock_loop_.Run();
+  EXPECT_EQ(1, call_count);
+
+  // The above step has adjusted the clock by 1 second already.
+  stream_->ClearReadQueue();
+  stream_->AddReadPacketString(two_sec_delay, "foo");
+  EXPECT_CALL(mock_loop_, PostDelayedTask(_, _, one_sec_delay)).Times(1);
+  EXPECT_TRUE(stream_->WaitForData(Stream::AccessMode::READ_WRITE,
+                                   base::Bind(callback,
+                                              base::Unretained(&call_count),
+                                              Stream::AccessMode::WRITE),
+                                   nullptr));
+  mock_loop_.Run();
+  EXPECT_EQ(2, call_count);
+
+  clock_.Advance(one_sec_delay);
+
+  EXPECT_CALL(mock_loop_, PostDelayedTask(_, _, zero_delay)).Times(1);
+  EXPECT_TRUE(stream_->WaitForData(Stream::AccessMode::READ_WRITE,
+                                   base::Bind(callback,
+                                              base::Unretained(&call_count),
+                                              Stream::AccessMode::READ_WRITE),
+                                   nullptr));
+  mock_loop_.Run();
+  EXPECT_EQ(3, call_count);
+
+  stream_->ClearReadQueue();
+  stream_->ClearWriteQueue();
+  stream_->AddReadPacketString(one_sec_delay, "foo");
+  stream_->ExpectWritePacketString(one_sec_delay, "bar");
+
+  EXPECT_CALL(mock_loop_, PostDelayedTask(_, _, one_sec_delay)).Times(1);
+  EXPECT_TRUE(stream_->WaitForData(Stream::AccessMode::READ_WRITE,
+                                   base::Bind(callback,
+                                              base::Unretained(&call_count),
+                                              Stream::AccessMode::READ_WRITE),
+                                   nullptr));
+  mock_loop_.Run();
+  EXPECT_EQ(4, call_count);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/file_stream.cc b/libbrillo/brillo/streams/file_stream.cc
new file mode 100644
index 0000000..7b28a5a
--- /dev/null
+++ b/libbrillo/brillo/streams/file_stream.cc
@@ -0,0 +1,548 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/file_stream.h>
+
+#include <algorithm>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <base/bind.h>
+#include <base/files/file_util.h>
+#include <base/posix/eintr_wrapper.h>
+#include <brillo/errors/error_codes.h>
+#include <brillo/message_loops/message_loop.h>
+#include <brillo/streams/stream_errors.h>
+#include <brillo/streams/stream_utils.h>
+
+namespace brillo {
+
+// FileDescriptor is a helper class that serves two purposes:
+// 1. It wraps low-level system APIs (as FileDescriptorInterface) to allow
+//    mocking calls to them in tests.
+// 2. It provides file descriptor watching services using FileDescriptorWatcher
+//    and MessageLoopForIO::Watcher interface.
+// The real FileStream uses this class to perform actual file I/O on the
+// contained file descriptor.
+class FileDescriptor : public FileStream::FileDescriptorInterface {
+ public:
+  FileDescriptor(int fd, bool own) : fd_{fd}, own_{own} {}
+  ~FileDescriptor() override {
+    if (IsOpen()) {
+      Close();
+    }
+  }
+
+  // Overrides for FileStream::FileDescriptorInterface methods.
+  bool IsOpen() const override { return fd_ >= 0; }
+
+  ssize_t Read(void* buf, size_t nbyte) override {
+    return HANDLE_EINTR(read(fd_, buf, nbyte));
+  }
+
+  ssize_t Write(const void* buf, size_t nbyte) override {
+    return HANDLE_EINTR(write(fd_, buf, nbyte));
+  }
+
+  off64_t Seek(off64_t offset, int whence) override {
+    return lseek64(fd_, offset, whence);
+  }
+
+  mode_t GetFileMode() const override {
+    struct stat file_stat;
+    if (fstat(fd_, &file_stat) < 0)
+      return 0;
+    return file_stat.st_mode;
+  }
+
+  uint64_t GetSize() const override {
+    struct stat file_stat;
+    if (fstat(fd_, &file_stat) < 0)
+      return 0;
+    return file_stat.st_size;
+  }
+
+  int Truncate(off64_t length) const override {
+    return HANDLE_EINTR(ftruncate(fd_, length));
+  }
+
+  int Close() override {
+    int fd = -1;
+    // The stream may or may not own the file descriptor stored in |fd_|.
+    // Despite that, we will need to set |fd_| to -1 when Close() finished.
+    // So, here we set it to -1 first and if we own the old descriptor, close
+    // it before exiting.
+    std::swap(fd, fd_);
+    CancelPendingAsyncOperations();
+    return own_ ? IGNORE_EINTR(close(fd)) : 0;
+  }
+
+  bool WaitForData(Stream::AccessMode mode,
+                   const DataCallback& data_callback,
+                   ErrorPtr* error) override {
+    if (stream_utils::IsReadAccessMode(mode)) {
+      CHECK(read_data_callback_.is_null());
+      MessageLoop::current()->CancelTask(read_watcher_);
+      read_watcher_ = MessageLoop::current()->WatchFileDescriptor(
+          FROM_HERE,
+          fd_,
+          MessageLoop::WatchMode::kWatchRead,
+          false,  // persistent
+          base::Bind(&FileDescriptor::OnFileCanReadWithoutBlocking,
+                     base::Unretained(this)));
+      if (read_watcher_ == MessageLoop::kTaskIdNull) {
+        Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
+                     errors::stream::kInvalidParameter,
+                     "File descriptor doesn't support watching for reading.");
+        return false;
+      }
+      read_data_callback_ = data_callback;
+    }
+    if (stream_utils::IsWriteAccessMode(mode)) {
+      CHECK(write_data_callback_.is_null());
+      MessageLoop::current()->CancelTask(write_watcher_);
+      write_watcher_ = MessageLoop::current()->WatchFileDescriptor(
+          FROM_HERE,
+          fd_,
+          MessageLoop::WatchMode::kWatchWrite,
+          false,  // persistent
+          base::Bind(&FileDescriptor::OnFileCanWriteWithoutBlocking,
+                     base::Unretained(this)));
+      if (write_watcher_ == MessageLoop::kTaskIdNull) {
+        Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
+                     errors::stream::kInvalidParameter,
+                     "File descriptor doesn't support watching for writing.");
+        return false;
+      }
+      write_data_callback_ = data_callback;
+    }
+    return true;
+  }
+
+  int WaitForDataBlocking(Stream::AccessMode in_mode,
+                          base::TimeDelta timeout,
+                          Stream::AccessMode* out_mode) override {
+    fd_set read_fds;
+    fd_set write_fds;
+    fd_set error_fds;
+
+    FD_ZERO(&read_fds);
+    FD_ZERO(&write_fds);
+    FD_ZERO(&error_fds);
+
+    if (stream_utils::IsReadAccessMode(in_mode))
+      FD_SET(fd_, &read_fds);
+
+    if (stream_utils::IsWriteAccessMode(in_mode))
+      FD_SET(fd_, &write_fds);
+
+    FD_SET(fd_, &error_fds);
+    timeval timeout_val = {};
+    if (!timeout.is_max()) {
+      const timespec ts = timeout.ToTimeSpec();
+      TIMESPEC_TO_TIMEVAL(&timeout_val, &ts);
+    }
+    int res = HANDLE_EINTR(select(fd_ + 1, &read_fds, &write_fds, &error_fds,
+                                  timeout.is_max() ? nullptr : &timeout_val));
+    if (res > 0 && out_mode) {
+      *out_mode = stream_utils::MakeAccessMode(FD_ISSET(fd_, &read_fds),
+                                               FD_ISSET(fd_, &write_fds));
+    }
+    return res;
+  }
+
+  void CancelPendingAsyncOperations() override {
+    read_data_callback_.Reset();
+    if (read_watcher_ != MessageLoop::kTaskIdNull) {
+      MessageLoop::current()->CancelTask(read_watcher_);
+      read_watcher_ = MessageLoop::kTaskIdNull;
+    }
+
+    write_data_callback_.Reset();
+    if (write_watcher_ != MessageLoop::kTaskIdNull) {
+      MessageLoop::current()->CancelTask(write_watcher_);
+      write_watcher_ = MessageLoop::kTaskIdNull;
+    }
+  }
+
+  // Called from the brillo::MessageLoop when the file descriptor is available
+  // for reading.
+  void OnFileCanReadWithoutBlocking() {
+    CHECK(!read_data_callback_.is_null());
+    DataCallback cb = read_data_callback_;
+    read_data_callback_.Reset();
+    cb.Run(Stream::AccessMode::READ);
+  }
+
+  void OnFileCanWriteWithoutBlocking() {
+    CHECK(!write_data_callback_.is_null());
+    DataCallback cb = write_data_callback_;
+    write_data_callback_.Reset();
+    cb.Run(Stream::AccessMode::WRITE);
+  }
+
+ private:
+  // The actual file descriptor we are working with. Will contain -1 if the
+  // file stream has been closed.
+  int fd_;
+
+  // |own_| is set to true if the file stream owns the file descriptor |fd_| and
+  // must close it when the stream is closed. This will be false for file
+  // descriptors that shouldn't be closed (e.g. stdin, stdout, stderr).
+  bool own_;
+
+  // Stream callbacks to be called when read and/or write operations can be
+  // performed on the file descriptor without blocking.
+  DataCallback read_data_callback_;
+  DataCallback write_data_callback_;
+
+  // MessageLoop tasks monitoring read/write operations on the file descriptor.
+  MessageLoop::TaskId read_watcher_{MessageLoop::kTaskIdNull};
+  MessageLoop::TaskId write_watcher_{MessageLoop::kTaskIdNull};
+
+  DISALLOW_COPY_AND_ASSIGN(FileDescriptor);
+};
+
+StreamPtr FileStream::Open(const base::FilePath& path,
+                           AccessMode mode,
+                           Disposition disposition,
+                           ErrorPtr* error) {
+  StreamPtr stream;
+  int open_flags = O_CLOEXEC;
+  switch (mode) {
+    case AccessMode::READ:
+      open_flags |= O_RDONLY;
+      break;
+    case AccessMode::WRITE:
+      open_flags |= O_WRONLY;
+      break;
+    case AccessMode::READ_WRITE:
+      open_flags |= O_RDWR;
+      break;
+  }
+
+  switch (disposition) {
+    case Disposition::OPEN_EXISTING:
+      // Nothing else to do.
+      break;
+    case Disposition::CREATE_ALWAYS:
+      open_flags |= O_CREAT | O_TRUNC;
+      break;
+    case Disposition::CREATE_NEW_ONLY:
+      open_flags |= O_CREAT | O_EXCL;
+      break;
+    case Disposition::TRUNCATE_EXISTING:
+      open_flags |= O_TRUNC;
+      break;
+  }
+
+  mode_t creation_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+  int fd = HANDLE_EINTR(open(path.value().c_str(), open_flags, creation_mode));
+  if (fd < 0) {
+    brillo::errors::system::AddSystemError(error, FROM_HERE, errno);
+    return stream;
+  }
+  if (HANDLE_EINTR(fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)) < 0) {
+    brillo::errors::system::AddSystemError(error, FROM_HERE, errno);
+    IGNORE_EINTR(close(fd));
+    return stream;
+  }
+
+  std::unique_ptr<FileDescriptorInterface> fd_interface{
+      new FileDescriptor{fd, true}};
+
+  stream.reset(new FileStream{std::move(fd_interface), mode});
+  return stream;
+}
+
+StreamPtr FileStream::CreateTemporary(ErrorPtr* error) {
+  StreamPtr stream;
+  base::FilePath path;
+  // The "proper" solution would be here to add O_TMPFILE flag to |open_flags|
+  // below and pass just the temp directory path to open(), so the actual file
+  // name isn't even needed. However this is supported only as of Linux kernel
+  // 3.11 and not all our configurations have that. So, for now just create
+  // a temp file first and then open it.
+  if (!base::CreateTemporaryFile(&path)) {
+    brillo::errors::system::AddSystemError(error, FROM_HERE, errno);
+    return stream;
+  }
+  int open_flags = O_CLOEXEC | O_RDWR | O_CREAT | O_TRUNC;
+  mode_t creation_mode = S_IRUSR | S_IWUSR;
+  int fd = HANDLE_EINTR(open(path.value().c_str(), open_flags, creation_mode));
+  if (fd < 0) {
+    brillo::errors::system::AddSystemError(error, FROM_HERE, errno);
+    return stream;
+  }
+  unlink(path.value().c_str());
+
+  stream = FromFileDescriptor(fd, true, error);
+  if (!stream)
+    IGNORE_EINTR(close(fd));
+  return stream;
+}
+
+StreamPtr FileStream::FromFileDescriptor(int file_descriptor,
+                                         bool own_descriptor,
+                                         ErrorPtr* error) {
+  StreamPtr stream;
+  if (file_descriptor < 0 || file_descriptor >= FD_SETSIZE) {
+    Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
+                 errors::stream::kInvalidParameter,
+                 "Invalid file descriptor value");
+    return stream;
+  }
+
+  int fd_flags = HANDLE_EINTR(fcntl(file_descriptor, F_GETFL));
+  if (fd_flags < 0) {
+    brillo::errors::system::AddSystemError(error, FROM_HERE, errno);
+    return stream;
+  }
+  int file_access_mode = (fd_flags & O_ACCMODE);
+  AccessMode access_mode = AccessMode::READ_WRITE;
+  if (file_access_mode == O_RDONLY)
+    access_mode = AccessMode::READ;
+  else if (file_access_mode == O_WRONLY)
+    access_mode = AccessMode::WRITE;
+
+  // Make sure the file descriptor is set to perform non-blocking operations
+  // if not enabled already.
+  if ((fd_flags & O_NONBLOCK) == 0) {
+    fd_flags |= O_NONBLOCK;
+    if (HANDLE_EINTR(fcntl(file_descriptor, F_SETFL, fd_flags)) < 0) {
+      brillo::errors::system::AddSystemError(error, FROM_HERE, errno);
+      return stream;
+    }
+  }
+
+  std::unique_ptr<FileDescriptorInterface> fd_interface{
+      new FileDescriptor{file_descriptor, own_descriptor}};
+
+  stream.reset(new FileStream{std::move(fd_interface), access_mode});
+  return stream;
+}
+
+FileStream::FileStream(std::unique_ptr<FileDescriptorInterface> fd_interface,
+                       AccessMode mode)
+    : fd_interface_(std::move(fd_interface)),
+      access_mode_(mode) {
+  switch (fd_interface_->GetFileMode() & S_IFMT) {
+    case S_IFCHR:  // Character device
+    case S_IFSOCK:  // Socket
+    case S_IFIFO:  // FIFO/pipe
+      // We know that these devices are not seekable and stream size is unknown.
+      seekable_ = false;
+      can_get_size_ = false;
+      break;
+
+    case S_IFBLK:  // Block device
+    case S_IFDIR:  // Directory
+    case S_IFREG:  // Normal file
+    case S_IFLNK:  // Symbolic link
+    default:
+      // The above devices support seek. Also, if not sure/in doubt, err on the
+      // side of "allowable".
+      seekable_ = true;
+      can_get_size_ = true;
+      break;
+  }
+}
+
+bool FileStream::IsOpen() const {
+  return fd_interface_->IsOpen();
+}
+
+bool FileStream::CanRead() const {
+  return IsOpen() && stream_utils::IsReadAccessMode(access_mode_);
+}
+
+bool FileStream::CanWrite() const {
+  return IsOpen() && stream_utils::IsWriteAccessMode(access_mode_);
+}
+
+bool FileStream::CanSeek() const {
+  return IsOpen() && seekable_;
+}
+
+bool FileStream::CanGetSize() const {
+  return IsOpen() && can_get_size_;
+}
+
+uint64_t FileStream::GetSize() const {
+  return IsOpen() ? fd_interface_->GetSize() : 0;
+}
+
+bool FileStream::SetSizeBlocking(uint64_t size, ErrorPtr* error) {
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  if (!stream_utils::CheckInt64Overflow(FROM_HERE, size, 0, error))
+    return false;
+
+  if (fd_interface_->Truncate(size) >= 0)
+    return true;
+
+  errors::system::AddSystemError(error, FROM_HERE, errno);
+  return false;
+}
+
+uint64_t FileStream::GetRemainingSize() const {
+  if (!CanGetSize())
+    return 0;
+  uint64_t pos = GetPosition();
+  uint64_t size = GetSize();
+  return (pos < size) ? (size - pos) : 0;
+}
+
+uint64_t FileStream::GetPosition() const {
+  if (!CanSeek())
+    return 0;
+
+  off64_t pos = fd_interface_->Seek(0, SEEK_CUR);
+  const off64_t min_pos = 0;
+  return std::max(min_pos, pos);
+}
+
+bool FileStream::Seek(int64_t offset,
+                      Whence whence,
+                      uint64_t* new_position,
+                      ErrorPtr* error) {
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  int raw_whence = 0;
+  switch (whence) {
+    case Whence::FROM_BEGIN:
+      raw_whence = SEEK_SET;
+      break;
+    case Whence::FROM_CURRENT:
+      raw_whence = SEEK_CUR;
+      break;
+    case Whence::FROM_END:
+      raw_whence = SEEK_END;
+      break;
+    default:
+      Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
+                   errors::stream::kInvalidParameter, "Invalid whence");
+      return false;
+  }
+  off64_t pos = fd_interface_->Seek(offset, raw_whence);
+  if (pos < 0) {
+    errors::system::AddSystemError(error, FROM_HERE, errno);
+    return false;
+  }
+
+  if (new_position)
+    *new_position = static_cast<uint64_t>(pos);
+  return true;
+}
+
+bool FileStream::ReadNonBlocking(void* buffer,
+                                 size_t size_to_read,
+                                 size_t* size_read,
+                                 bool* end_of_stream,
+                                 ErrorPtr* error) {
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  ssize_t read = fd_interface_->Read(buffer, size_to_read);
+  if (read < 0) {
+    // If read() fails, check if this is due to no data being currently
+    // available and we do non-blocking I/O.
+    if (errno == EWOULDBLOCK || errno == EAGAIN) {
+      if (end_of_stream)
+        *end_of_stream = false;
+      *size_read = 0;
+      return true;
+    }
+    // Otherwise a real problem occurred.
+    errors::system::AddSystemError(error, FROM_HERE, errno);
+    return false;
+  }
+  if (end_of_stream)
+    *end_of_stream = (read == 0 && size_to_read != 0);
+  *size_read = read;
+  return true;
+}
+
+bool FileStream::WriteNonBlocking(const void* buffer,
+                                  size_t size_to_write,
+                                  size_t* size_written,
+                                  ErrorPtr* error) {
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  ssize_t written = fd_interface_->Write(buffer, size_to_write);
+  if (written < 0) {
+    // If write() fails, check if this is due to the fact that no data
+    // can be presently written and we do non-blocking I/O.
+    if (errno == EWOULDBLOCK || errno == EAGAIN) {
+      *size_written = 0;
+      return true;
+    }
+    // Otherwise a real problem occurred.
+    errors::system::AddSystemError(error, FROM_HERE, errno);
+    return false;
+  }
+  *size_written = written;
+  return true;
+}
+
+bool FileStream::FlushBlocking(ErrorPtr* error) {
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  // File descriptors don't have an internal buffer to flush.
+  return true;
+}
+
+bool FileStream::CloseBlocking(ErrorPtr* error) {
+  if (!IsOpen())
+    return true;
+
+  if (fd_interface_->Close() < 0) {
+    errors::system::AddSystemError(error, FROM_HERE, errno);
+    return false;
+  }
+
+  return true;
+}
+
+bool FileStream::WaitForData(
+    AccessMode mode,
+    const base::Callback<void(AccessMode)>& callback,
+    ErrorPtr* error) {
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  return fd_interface_->WaitForData(mode, callback, error);
+}
+
+bool FileStream::WaitForDataBlocking(AccessMode in_mode,
+                                     base::TimeDelta timeout,
+                                     AccessMode* out_mode,
+                                     ErrorPtr* error) {
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  int ret = fd_interface_->WaitForDataBlocking(in_mode, timeout, out_mode);
+  if (ret < 0) {
+    errors::system::AddSystemError(error, FROM_HERE, errno);
+    return false;
+  }
+  if (ret == 0)
+    return stream_utils::ErrorOperationTimeout(FROM_HERE, error);
+
+  return true;
+}
+
+void FileStream::CancelPendingAsyncOperations() {
+  if (IsOpen()) {
+    fd_interface_->CancelPendingAsyncOperations();
+  }
+  Stream::CancelPendingAsyncOperations();
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/file_stream.h b/libbrillo/brillo/streams/file_stream.h
new file mode 100644
index 0000000..1cf39b5
--- /dev/null
+++ b/libbrillo/brillo/streams/file_stream.h
@@ -0,0 +1,175 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_STREAMS_FILE_STREAM_H_
+#define LIBBRILLO_BRILLO_STREAMS_FILE_STREAM_H_
+
+#include <base/files/file_path.h>
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+#include <brillo/streams/stream.h>
+
+namespace brillo {
+
+// FileStream class provides the implementation of brillo::Stream for files
+// and file-descriptor-based streams, such as pipes and sockets.
+// The FileStream class cannot be instantiated by clients directly. However
+// they should use the static factory methods such as:
+//  - FileStream::Open(): to open a file by name.
+//  - FileStream::CreateTemporary(): to create a temporary file stream.
+//  - FileStream::FromFileDescriptor(): to create a stream using an existing
+//    file descriptor.
+class BRILLO_EXPORT FileStream : public Stream {
+ public:
+  // See comments for FileStream::Open() for detailed description of this enum.
+  enum class Disposition {
+    OPEN_EXISTING,  // Open existing file only. Fail if doesn't exist.
+    CREATE_ALWAYS,  // Create empty file, possibly overwriting existing file.
+    CREATE_NEW_ONLY,  // Create new file if doesn't exist already.
+    TRUNCATE_EXISTING,  // Open/truncate existing file. Fail if doesn't exist.
+  };
+
+  // Simple interface to wrap native library calls so that they can be mocked
+  // out for testing.
+  struct FileDescriptorInterface {
+    using DataCallback = base::Callback<void(Stream::AccessMode)>;
+
+    virtual ~FileDescriptorInterface() = default;
+
+    virtual bool IsOpen() const = 0;
+    virtual ssize_t Read(void* buf, size_t nbyte) = 0;
+    virtual ssize_t Write(const void* buf, size_t nbyte) = 0;
+    virtual off64_t Seek(off64_t offset, int whence) = 0;
+    virtual mode_t GetFileMode() const = 0;
+    virtual uint64_t GetSize() const = 0;
+    virtual int Truncate(off64_t length) const = 0;
+    virtual int Close() = 0;
+    virtual bool WaitForData(AccessMode mode,
+                             const DataCallback& data_callback,
+                             ErrorPtr* error) = 0;
+    virtual int WaitForDataBlocking(AccessMode in_mode,
+                                    base::TimeDelta timeout,
+                                    AccessMode* out_mode) = 0;
+    virtual void CancelPendingAsyncOperations() = 0;
+  };
+
+  // == Construction ==========================================================
+
+  // Opens a file at specified |path| for reading, writing or both as indicated
+  // by |mode|. The |disposition| specifies how the file must be opened/created:
+  //  - OPEN_EXISTING   - opens the existing file and keeps its content intact.
+  //                      The seek pointer is at the beginning of the file.
+  //  - CREATE_ALWAYS   - creates the file always. If it exists, the file is
+  //                      truncated.
+  //  - CREATE_NEW_ONLY - creates a new file only if it doesn't exist. Fails
+  //                      otherwise. This can be useful for creating lock files.
+  //  - TRUNCATE_EXISTING - opens existing file and truncates it to zero length.
+  //                       Fails if the file doesn't already exist.
+  // If successful, the open file stream is returned. Otherwise returns the
+  // stream pointer containing nullptr and fills in the details of the error
+  // in |error| object, if provided.
+  static StreamPtr Open(const base::FilePath& path,
+                        AccessMode mode,
+                        Disposition disposition,
+                        ErrorPtr* error);
+
+  // Creates a temporary unnamed file and returns a stream to it. The file will
+  // be deleted when the stream is destroyed.
+  static StreamPtr CreateTemporary(ErrorPtr* error);
+
+  // Creates a file stream based on existing file descriptor. The file
+  // descriptor will be set into non-blocking mode and will be owned by the
+  // resulting stream (and closed when the stream is destroyed).
+  // If the function fails, returns a null stream pointer and sets the error
+  // details to |error| object. Also note that it is the caller's responsibility
+  // to close the file descriptor if this function fails, since the stream
+  // hasn't been created yet and didn't take ownership of the file descriptor.
+  // |own_descriptor| indicates whether the stream must close the underlying
+  // file descriptor when its CloseBlocking() method is called. This should be
+  // set to false for file descriptors that shouldn't be closed (e.g. stdin).
+  static StreamPtr FromFileDescriptor(int file_descriptor,
+                                      bool own_descriptor,
+                                      ErrorPtr* error);
+
+  // == Stream capabilities ===================================================
+  bool IsOpen() const override;
+  bool CanRead() const override;
+  bool CanWrite() const override;
+  bool CanSeek() const override;
+  bool CanGetSize() const override;
+
+  // == Stream size operations ================================================
+  uint64_t GetSize() const override;
+  bool SetSizeBlocking(uint64_t size, ErrorPtr* error) override;
+  uint64_t GetRemainingSize() const override;
+
+  // == Seek operations =======================================================
+  uint64_t GetPosition() const override;
+  bool Seek(int64_t offset,
+            Whence whence,
+            uint64_t* new_position,
+            ErrorPtr* error) override;
+
+  // == Read operations =======================================================
+  bool ReadNonBlocking(void* buffer,
+                       size_t size_to_read,
+                       size_t* size_read,
+                       bool* end_of_stream,
+                       ErrorPtr* error) override;
+
+  // == Write operations ======================================================
+  bool WriteNonBlocking(const void* buffer,
+                        size_t size_to_write,
+                        size_t* size_written,
+                        ErrorPtr* error) override;
+
+  // == Finalizing/closing streams  ===========================================
+  bool FlushBlocking(ErrorPtr* error) override;
+  bool CloseBlocking(ErrorPtr* error) override;
+
+  // == Data availability monitoring ==========================================
+
+  // Override for Stream::WaitForData to start watching the associated file
+  // descriptor for non-blocking read/write operations.
+  bool WaitForData(AccessMode mode,
+                   const base::Callback<void(AccessMode)>& callback,
+                   ErrorPtr* error) override;
+
+  // Runs select() on the file descriptor to wait until we can do non-blocking
+  // I/O on it.
+  bool WaitForDataBlocking(AccessMode in_mode,
+                           base::TimeDelta timeout,
+                           AccessMode* out_mode,
+                           ErrorPtr* error) override;
+
+  // Cancels pending asynchronous read/write operations.
+  void CancelPendingAsyncOperations() override;
+
+ private:
+  friend class FileStreamTest;
+
+  // Internal constructor used by the factory methods Open(), CreateTemporary(),
+  // and FromFileDescriptor().
+  FileStream(std::unique_ptr<FileDescriptorInterface> fd_interface,
+             AccessMode mode);
+
+  // Wrapper for the file descriptor. Used in testing to mock out the real
+  // file system APIs.
+  std::unique_ptr<FileDescriptorInterface> fd_interface_;
+
+  // The access mode this stream is open with.
+  AccessMode access_mode_{AccessMode::READ_WRITE};
+
+  // Set to false for streams that are guaranteed non-seekable.
+  bool seekable_{true};
+
+  // Set to false for streams that have unknown size.
+  bool can_get_size_{false};
+
+  DISALLOW_COPY_AND_ASSIGN(FileStream);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_STREAMS_FILE_STREAM_H_
diff --git a/libbrillo/brillo/streams/file_stream_unittest.cc b/libbrillo/brillo/streams/file_stream_unittest.cc
new file mode 100644
index 0000000..4554ede
--- /dev/null
+++ b/libbrillo/brillo/streams/file_stream_unittest.cc
@@ -0,0 +1,1148 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/file_stream.h>
+
+#include <limits>
+#include <numeric>
+#include <string>
+#include <sys/stat.h>
+#include <vector>
+
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <base/message_loop/message_loop.h>
+#include <base/rand_util.h>
+#include <base/run_loop.h>
+#include <brillo/bind_lambda.h>
+#include <brillo/errors/error_codes.h>
+#include <brillo/message_loops/base_message_loop.h>
+#include <brillo/message_loops/message_loop_utils.h>
+#include <brillo/streams/stream_errors.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::InSequence;
+using testing::Return;
+using testing::ReturnArg;
+using testing::SaveArg;
+using testing::SetErrnoAndReturn;
+using testing::_;
+
+namespace brillo {
+
+namespace {
+
+// gmock action that would return a blocking situation from a read() or write().
+ACTION(ReturnWouldBlock) {
+  errno = EWOULDBLOCK;
+  return -1;
+}
+
+// Helper function to read one byte from the stream.
+inline int ReadByte(Stream* stream) {
+  uint8_t byte = 0;
+  return stream->ReadAllBlocking(&byte, sizeof(byte), nullptr) ? byte : -1;
+}
+
+// Helper function to write one byte from the stream.
+inline bool WriteByte(Stream* stream, uint8_t byte) {
+  return stream->WriteAllBlocking(&byte, sizeof(byte), nullptr);
+}
+
+// Helper function to test file stream workflow on newly created file.
+void TestCreateFile(Stream* stream) {
+  ASSERT_TRUE(stream->IsOpen());
+
+  // Set up a sample data buffer.
+  std::vector<uint8_t> in_buffer(256);
+  std::iota(in_buffer.begin(), in_buffer.end(), 0);
+
+  // Initial assumptions about empty file stream.
+  EXPECT_TRUE(stream->CanRead());
+  EXPECT_TRUE(stream->CanWrite());
+  EXPECT_TRUE(stream->CanSeek());
+  EXPECT_TRUE(stream->CanGetSize());
+  EXPECT_EQ(0, stream->GetPosition());
+  EXPECT_EQ(0, stream->GetSize());
+
+  // Write sample data.
+  EXPECT_TRUE(stream->WriteAllBlocking(in_buffer.data(), in_buffer.size(),
+                                       nullptr));
+  EXPECT_EQ(in_buffer.size(), stream->GetPosition());
+  EXPECT_EQ(in_buffer.size(), stream->GetSize());
+
+  // Rewind the stream to the beginning.
+  uint64_t pos = 0;
+  EXPECT_TRUE(stream->Seek(0, Stream::Whence::FROM_BEGIN, &pos, nullptr));
+  EXPECT_EQ(0, pos);
+  EXPECT_EQ(0, stream->GetPosition());
+  EXPECT_EQ(in_buffer.size(), stream->GetSize());
+
+  // Read the file contents back.
+  std::vector<uint8_t> out_buffer(256);
+  EXPECT_TRUE(stream->ReadAllBlocking(out_buffer.data(), out_buffer.size(),
+                                      nullptr));
+  EXPECT_EQ(out_buffer.size(), stream->GetPosition());
+  EXPECT_EQ(out_buffer.size(), stream->GetSize());
+
+  // Make sure the data read matches those written.
+  EXPECT_EQ(in_buffer, out_buffer);
+
+  // Random read/write
+  EXPECT_TRUE(stream->Seek(10, Stream::Whence::FROM_BEGIN, &pos, nullptr));
+  EXPECT_EQ(10, pos);
+
+  // Since our data buffer contained values from 0 to 255, the byte at position
+  // 10 will contain the value of 10.
+  EXPECT_EQ(10, ReadByte(stream));
+  EXPECT_EQ(11, ReadByte(stream));
+  EXPECT_EQ(12, ReadByte(stream));
+  EXPECT_TRUE(stream->Seek(7, Stream::Whence::FROM_CURRENT, nullptr, nullptr));
+  EXPECT_EQ(20, ReadByte(stream));
+
+  EXPECT_EQ(21, stream->GetPosition());
+  EXPECT_TRUE(stream->Seek(-2, Stream::Whence::FROM_CURRENT, &pos, nullptr));
+  EXPECT_EQ(19, pos);
+  EXPECT_TRUE(WriteByte(stream, 100));
+  EXPECT_EQ(20, ReadByte(stream));
+  EXPECT_TRUE(stream->Seek(-2, Stream::Whence::FROM_CURRENT, nullptr, nullptr));
+  EXPECT_EQ(100, ReadByte(stream));
+  EXPECT_EQ(20, ReadByte(stream));
+  EXPECT_TRUE(stream->Seek(-1, Stream::Whence::FROM_END, &pos, nullptr));
+  EXPECT_EQ(255, pos);
+  EXPECT_EQ(255, ReadByte(stream));
+  EXPECT_EQ(-1, ReadByte(stream));
+}
+
+}  // anonymous namespace
+
+// A mock file descriptor wrapper to test low-level file API used by FileStream.
+class MockFileDescriptor : public FileStream::FileDescriptorInterface {
+ public:
+  MOCK_CONST_METHOD0(IsOpen, bool());
+  MOCK_METHOD2(Read, ssize_t(void*, size_t));
+  MOCK_METHOD2(Write, ssize_t(const void*, size_t));
+  MOCK_METHOD2(Seek, off64_t(off64_t, int));
+  MOCK_CONST_METHOD0(GetFileMode, mode_t());
+  MOCK_CONST_METHOD0(GetSize, uint64_t());
+  MOCK_CONST_METHOD1(Truncate, int(off64_t));
+  MOCK_METHOD0(Flush, int());
+  MOCK_METHOD0(Close, int());
+  MOCK_METHOD3(WaitForData,
+               bool(Stream::AccessMode, const DataCallback&, ErrorPtr*));
+  MOCK_METHOD3(WaitForDataBlocking,
+               int(Stream::AccessMode, base::TimeDelta, Stream::AccessMode*));
+  MOCK_METHOD0(CancelPendingAsyncOperations, void());
+};
+
+class FileStreamTest : public testing::Test {
+ public:
+  void SetUp() override {
+    CreateStream(S_IFREG, Stream::AccessMode::READ_WRITE);
+  }
+
+  MockFileDescriptor& fd_mock() {
+    return *static_cast<MockFileDescriptor*>(stream_->fd_interface_.get());
+  }
+
+  void CreateStream(mode_t file_mode, Stream::AccessMode access_mode) {
+    std::unique_ptr<MockFileDescriptor> fd{new MockFileDescriptor{}};
+    EXPECT_CALL(*fd, GetFileMode()).WillOnce(Return(file_mode));
+    stream_.reset(new FileStream(std::move(fd), access_mode));
+    EXPECT_CALL(fd_mock(), IsOpen()).WillRepeatedly(Return(true));
+  }
+
+  void ExpectStreamClosed(const ErrorPtr& error) const {
+    EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+    EXPECT_EQ(errors::stream::kStreamClosed, error->GetCode());
+    EXPECT_EQ("Stream is closed", error->GetMessage());
+  }
+
+  void ExpectStreamOffsetTooLarge(const ErrorPtr& error) const {
+    EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+    EXPECT_EQ(errors::stream::kInvalidParameter, error->GetCode());
+    EXPECT_EQ("The stream offset value is out of range", error->GetMessage());
+  }
+
+  inline static char* IntToPtr(int addr) {
+    return reinterpret_cast<char*>(addr);
+  }
+
+  inline static const char* IntToConstPtr(int addr) {
+    return reinterpret_cast<const char*>(addr);
+  }
+
+  bool CallWaitForData(Stream::AccessMode mode, ErrorPtr* error) {
+    return stream_->WaitForData(mode, {}, error);
+  }
+
+  std::unique_ptr<FileStream> stream_;
+
+  const uint64_t kMaxSize = std::numeric_limits<int64_t>::max();
+  const uint64_t kTooLargeSize = std::numeric_limits<uint64_t>::max();
+
+  // Dummy buffer pointer values to make sure that input pointer values
+  // are delegated to the file interface without a change.
+  char* const test_read_buffer_ = IntToPtr(12345);
+  const char* const test_write_buffer_ = IntToConstPtr(67890);
+};
+
+TEST_F(FileStreamTest, IsOpen) {
+  EXPECT_TRUE(stream_->IsOpen());
+  EXPECT_CALL(fd_mock(), IsOpen()).WillOnce(Return(false));
+  EXPECT_FALSE(stream_->IsOpen());
+}
+
+TEST_F(FileStreamTest, CanRead) {
+  CreateStream(S_IFREG, Stream::AccessMode::READ_WRITE);
+  EXPECT_TRUE(stream_->CanRead());
+  EXPECT_CALL(fd_mock(), IsOpen()).WillRepeatedly(Return(false));
+  EXPECT_FALSE(stream_->CanRead());
+  CreateStream(S_IFREG, Stream::AccessMode::READ);
+  EXPECT_TRUE(stream_->CanRead());
+  CreateStream(S_IFREG, Stream::AccessMode::WRITE);
+  EXPECT_FALSE(stream_->CanRead());
+}
+
+TEST_F(FileStreamTest, CanWrite) {
+  CreateStream(S_IFREG, Stream::AccessMode::READ_WRITE);
+  EXPECT_TRUE(stream_->CanWrite());
+  EXPECT_CALL(fd_mock(), IsOpen()).WillRepeatedly(Return(false));
+  EXPECT_FALSE(stream_->CanWrite());
+  CreateStream(S_IFREG, Stream::AccessMode::READ);
+  EXPECT_FALSE(stream_->CanWrite());
+  CreateStream(S_IFREG, Stream::AccessMode::WRITE);
+  EXPECT_TRUE(stream_->CanWrite());
+}
+
+TEST_F(FileStreamTest, CanSeek) {
+  CreateStream(S_IFBLK, Stream::AccessMode::READ_WRITE);
+  EXPECT_TRUE(stream_->CanSeek());
+  CreateStream(S_IFDIR, Stream::AccessMode::READ_WRITE);
+  EXPECT_TRUE(stream_->CanSeek());
+  CreateStream(S_IFREG, Stream::AccessMode::READ_WRITE);
+  EXPECT_TRUE(stream_->CanSeek());
+  CreateStream(S_IFLNK, Stream::AccessMode::READ_WRITE);
+  EXPECT_TRUE(stream_->CanSeek());
+  CreateStream(S_IFCHR, Stream::AccessMode::READ_WRITE);
+  EXPECT_FALSE(stream_->CanSeek());
+  CreateStream(S_IFSOCK, Stream::AccessMode::READ_WRITE);
+  EXPECT_FALSE(stream_->CanSeek());
+  CreateStream(S_IFIFO, Stream::AccessMode::READ_WRITE);
+  EXPECT_FALSE(stream_->CanSeek());
+
+  CreateStream(S_IFREG, Stream::AccessMode::READ);
+  EXPECT_TRUE(stream_->CanSeek());
+  CreateStream(S_IFREG, Stream::AccessMode::WRITE);
+  EXPECT_TRUE(stream_->CanSeek());
+}
+
+TEST_F(FileStreamTest, CanGetSize) {
+  CreateStream(S_IFBLK, Stream::AccessMode::READ_WRITE);
+  EXPECT_TRUE(stream_->CanGetSize());
+  CreateStream(S_IFDIR, Stream::AccessMode::READ_WRITE);
+  EXPECT_TRUE(stream_->CanGetSize());
+  CreateStream(S_IFREG, Stream::AccessMode::READ_WRITE);
+  EXPECT_TRUE(stream_->CanGetSize());
+  CreateStream(S_IFLNK, Stream::AccessMode::READ_WRITE);
+  EXPECT_TRUE(stream_->CanGetSize());
+  CreateStream(S_IFCHR, Stream::AccessMode::READ_WRITE);
+  EXPECT_FALSE(stream_->CanGetSize());
+  CreateStream(S_IFSOCK, Stream::AccessMode::READ_WRITE);
+  EXPECT_FALSE(stream_->CanGetSize());
+  CreateStream(S_IFIFO, Stream::AccessMode::READ_WRITE);
+  EXPECT_FALSE(stream_->CanGetSize());
+
+  CreateStream(S_IFREG, Stream::AccessMode::READ);
+  EXPECT_TRUE(stream_->CanGetSize());
+  CreateStream(S_IFREG, Stream::AccessMode::WRITE);
+  EXPECT_TRUE(stream_->CanGetSize());
+}
+
+TEST_F(FileStreamTest, GetSize) {
+  EXPECT_CALL(fd_mock(), GetSize()).WillRepeatedly(Return(12345));
+  EXPECT_EQ(12345u, stream_->GetSize());
+  EXPECT_CALL(fd_mock(), IsOpen()).WillOnce(Return(false));
+  EXPECT_EQ(0u, stream_->GetSize());
+}
+
+TEST_F(FileStreamTest, SetSizeBlocking) {
+  EXPECT_CALL(fd_mock(), Truncate(0)).WillOnce(Return(0));
+  EXPECT_TRUE(stream_->SetSizeBlocking(0, nullptr));
+
+  EXPECT_CALL(fd_mock(), Truncate(123)).WillOnce(Return(0));
+  EXPECT_TRUE(stream_->SetSizeBlocking(123, nullptr));
+
+  EXPECT_CALL(fd_mock(), Truncate(kMaxSize)).WillOnce(Return(0));
+  EXPECT_TRUE(stream_->SetSizeBlocking(kMaxSize, nullptr));
+}
+
+TEST_F(FileStreamTest, SetSizeBlocking_Fail) {
+  brillo::ErrorPtr error;
+
+  EXPECT_CALL(fd_mock(), Truncate(1235)).WillOnce(SetErrnoAndReturn(EIO, -1));
+  EXPECT_FALSE(stream_->SetSizeBlocking(1235, &error));
+  EXPECT_EQ(errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("EIO", error->GetCode());
+
+  error.reset();
+  EXPECT_FALSE(stream_->SetSizeBlocking(kTooLargeSize, &error));
+  ExpectStreamOffsetTooLarge(error);
+
+  error.reset();
+  EXPECT_CALL(fd_mock(), IsOpen()).WillOnce(Return(false));
+  EXPECT_FALSE(stream_->SetSizeBlocking(1235, &error));
+  ExpectStreamClosed(error);
+}
+
+TEST_F(FileStreamTest, GetRemainingSize) {
+  EXPECT_CALL(fd_mock(), Seek(0, SEEK_CUR)).WillOnce(Return(234));
+  EXPECT_CALL(fd_mock(), GetSize()).WillOnce(Return(1234));
+  EXPECT_EQ(1000u, stream_->GetRemainingSize());
+
+  EXPECT_CALL(fd_mock(), Seek(0, SEEK_CUR)).WillOnce(Return(1234));
+  EXPECT_CALL(fd_mock(), GetSize()).WillOnce(Return(1000));
+  EXPECT_EQ(0u, stream_->GetRemainingSize());
+}
+
+TEST_F(FileStreamTest, Seek_Set) {
+  uint64_t pos = 0;
+
+  EXPECT_CALL(fd_mock(), Seek(0, SEEK_SET)).WillOnce(Return(0));
+  EXPECT_TRUE(stream_->Seek(0, Stream::Whence::FROM_BEGIN, &pos, nullptr));
+  EXPECT_EQ(0u, pos);
+
+  EXPECT_CALL(fd_mock(), Seek(123456, SEEK_SET)).WillOnce(Return(123456));
+  EXPECT_TRUE(stream_->Seek(123456, Stream::Whence::FROM_BEGIN, &pos, nullptr));
+  EXPECT_EQ(123456u, pos);
+
+  EXPECT_CALL(fd_mock(), Seek(kMaxSize, SEEK_SET))
+      .WillRepeatedly(Return(kMaxSize));
+  EXPECT_TRUE(stream_->Seek(kMaxSize, Stream::Whence::FROM_BEGIN, &pos,
+              nullptr));
+  EXPECT_EQ(kMaxSize, pos);
+  EXPECT_TRUE(stream_->Seek(kMaxSize, Stream::Whence::FROM_BEGIN, nullptr,
+              nullptr));
+}
+
+TEST_F(FileStreamTest, Seek_Cur) {
+  uint64_t pos = 0;
+
+  EXPECT_CALL(fd_mock(), Seek(0, SEEK_CUR)).WillOnce(Return(100));
+  EXPECT_TRUE(stream_->Seek(0, Stream::Whence::FROM_CURRENT, &pos, nullptr));
+  EXPECT_EQ(100u, pos);
+
+  EXPECT_CALL(fd_mock(), Seek(234, SEEK_CUR)).WillOnce(Return(1234));
+  EXPECT_TRUE(stream_->Seek(234, Stream::Whence::FROM_CURRENT, &pos, nullptr));
+  EXPECT_EQ(1234u, pos);
+
+  EXPECT_CALL(fd_mock(), Seek(-100, SEEK_CUR)).WillOnce(Return(900));
+  EXPECT_TRUE(stream_->Seek(-100, Stream::Whence::FROM_CURRENT, &pos, nullptr));
+  EXPECT_EQ(900u, pos);
+}
+
+TEST_F(FileStreamTest, Seek_End) {
+  uint64_t pos = 0;
+
+  EXPECT_CALL(fd_mock(), Seek(0, SEEK_END)).WillOnce(Return(1000));
+  EXPECT_TRUE(stream_->Seek(0, Stream::Whence::FROM_END, &pos, nullptr));
+  EXPECT_EQ(1000u, pos);
+
+  EXPECT_CALL(fd_mock(), Seek(234, SEEK_END)).WillOnce(Return(10234));
+  EXPECT_TRUE(stream_->Seek(234, Stream::Whence::FROM_END, &pos, nullptr));
+  EXPECT_EQ(10234u, pos);
+
+  EXPECT_CALL(fd_mock(), Seek(-100, SEEK_END)).WillOnce(Return(9900));
+  EXPECT_TRUE(stream_->Seek(-100, Stream::Whence::FROM_END, &pos, nullptr));
+  EXPECT_EQ(9900u, pos);
+}
+
+TEST_F(FileStreamTest, Seek_Fail) {
+  brillo::ErrorPtr error;
+  EXPECT_CALL(fd_mock(), Seek(0, SEEK_SET))
+      .WillOnce(SetErrnoAndReturn(EPIPE, -1));
+  EXPECT_FALSE(stream_->Seek(0, Stream::Whence::FROM_BEGIN, nullptr, &error));
+  EXPECT_EQ(errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("EPIPE", error->GetCode());
+}
+
+TEST_F(FileStreamTest, ReadAsync) {
+  size_t read_size = 0;
+  bool failed = false;
+  auto success_callback = [](size_t* read_size, size_t size) {
+    *read_size = size;
+  };
+  auto error_callback = [](bool* failed, const Error* /* error */) {
+    *failed = true;
+  };
+  FileStream::FileDescriptorInterface::DataCallback data_callback;
+
+  EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 100))
+      .WillOnce(ReturnWouldBlock());
+  EXPECT_CALL(fd_mock(), WaitForData(Stream::AccessMode::READ, _, _))
+      .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
+  EXPECT_TRUE(stream_->ReadAsync(
+      test_read_buffer_,
+      100,
+      base::Bind(success_callback, base::Unretained(&read_size)),
+      base::Bind(error_callback, base::Unretained(&failed)),
+      nullptr));
+  EXPECT_EQ(0u, read_size);
+  EXPECT_FALSE(failed);
+
+  EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 100)).WillOnce(Return(83));
+  data_callback.Run(Stream::AccessMode::READ);
+  EXPECT_EQ(83u, read_size);
+  EXPECT_FALSE(failed);
+}
+
+TEST_F(FileStreamTest, ReadNonBlocking) {
+  size_t size = 0;
+  bool eos = false;
+  EXPECT_CALL(fd_mock(), Read(test_read_buffer_, _))
+      .WillRepeatedly(ReturnArg<1>());
+  EXPECT_TRUE(stream_->ReadNonBlocking(test_read_buffer_, 100, &size, &eos,
+                                       nullptr));
+  EXPECT_EQ(100u, size);
+  EXPECT_FALSE(eos);
+
+  EXPECT_TRUE(stream_->ReadNonBlocking(test_read_buffer_, 0, &size, &eos,
+                                       nullptr));
+  EXPECT_EQ(0u, size);
+  EXPECT_FALSE(eos);
+
+  EXPECT_CALL(fd_mock(), Read(test_read_buffer_, _)).WillOnce(Return(0));
+  EXPECT_TRUE(stream_->ReadNonBlocking(test_read_buffer_, 100, &size, &eos,
+                                       nullptr));
+  EXPECT_EQ(0u, size);
+  EXPECT_TRUE(eos);
+
+  EXPECT_CALL(fd_mock(), Read(test_read_buffer_, _))
+      .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+  EXPECT_TRUE(stream_->ReadNonBlocking(test_read_buffer_, 100, &size, &eos,
+                                       nullptr));
+  EXPECT_EQ(0u, size);
+  EXPECT_FALSE(eos);
+}
+
+TEST_F(FileStreamTest, ReadNonBlocking_Fail) {
+  size_t size = 0;
+  brillo::ErrorPtr error;
+  EXPECT_CALL(fd_mock(), Read(test_read_buffer_, _))
+      .WillOnce(SetErrnoAndReturn(EACCES, -1));
+  EXPECT_FALSE(stream_->ReadNonBlocking(test_read_buffer_, 100, &size, nullptr,
+                                        &error));
+  EXPECT_EQ(errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("EACCES", error->GetCode());
+}
+
+TEST_F(FileStreamTest, ReadBlocking) {
+  size_t size = 0;
+  EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 100)).WillOnce(Return(20));
+  EXPECT_TRUE(stream_->ReadBlocking(test_read_buffer_, 100, &size, nullptr));
+  EXPECT_EQ(20u, size);
+
+  {
+    InSequence seq;
+    EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 80))
+        .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+    EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _, _))
+        .WillOnce(Return(1));
+    EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 80)).WillOnce(Return(45));
+  }
+  EXPECT_TRUE(stream_->ReadBlocking(test_read_buffer_, 80, &size, nullptr));
+  EXPECT_EQ(45u, size);
+
+  EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 50)).WillOnce(Return(0));
+  EXPECT_TRUE(stream_->ReadBlocking(test_read_buffer_, 50, &size, nullptr));
+  EXPECT_EQ(0u, size);
+}
+
+TEST_F(FileStreamTest, ReadBlocking_Fail) {
+  {
+    InSequence seq;
+    EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 80))
+        .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+    EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _, _))
+        .WillOnce(SetErrnoAndReturn(EBADF, -1));
+  }
+  brillo::ErrorPtr error;
+  size_t size = 0;
+  EXPECT_FALSE(stream_->ReadBlocking(test_read_buffer_, 80, &size, &error));
+  EXPECT_EQ(errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("EBADF", error->GetCode());
+}
+
+TEST_F(FileStreamTest, ReadAllBlocking) {
+  {
+    InSequence seq;
+    EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 100)).WillOnce(Return(20));
+    EXPECT_CALL(fd_mock(), Read(test_read_buffer_ + 20, 80))
+        .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+    EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _, _))
+        .WillOnce(Return(1));
+    EXPECT_CALL(fd_mock(), Read(test_read_buffer_ + 20, 80))
+        .WillOnce(Return(45));
+    EXPECT_CALL(fd_mock(), Read(test_read_buffer_ + 65, 35))
+        .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+    EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _, _))
+        .WillOnce(Return(1));
+    EXPECT_CALL(fd_mock(), Read(test_read_buffer_ + 65, 35))
+        .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+    EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::READ, _, _))
+        .WillOnce(Return(1));
+    EXPECT_CALL(fd_mock(), Read(test_read_buffer_ + 65, 35))
+        .WillOnce(Return(35));
+  }
+  EXPECT_TRUE(stream_->ReadAllBlocking(test_read_buffer_, 100, nullptr));
+}
+
+TEST_F(FileStreamTest, ReadAllBlocking_Fail) {
+  {
+    InSequence seq;
+    EXPECT_CALL(fd_mock(), Read(test_read_buffer_, 100)).WillOnce(Return(20));
+    EXPECT_CALL(fd_mock(), Read(test_read_buffer_ + 20, 80))
+        .WillOnce(Return(0));
+  }
+  brillo::ErrorPtr error;
+  EXPECT_FALSE(stream_->ReadAllBlocking(test_read_buffer_, 100, &error));
+  EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+  EXPECT_EQ(errors::stream::kPartialData, error->GetCode());
+  EXPECT_EQ("Reading past the end of stream", error->GetMessage());
+}
+
+TEST_F(FileStreamTest, WriteAsync) {
+  size_t write_size = 0;
+  bool failed = false;
+  auto success_callback = [](size_t* write_size, size_t size) {
+    *write_size = size;
+  };
+  auto error_callback = [](bool* failed, const Error* /* error */) {
+    *failed = true;
+  };
+  FileStream::FileDescriptorInterface::DataCallback data_callback;
+
+  EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 100))
+      .WillOnce(ReturnWouldBlock());
+  EXPECT_CALL(fd_mock(), WaitForData(Stream::AccessMode::WRITE, _, _))
+      .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
+  EXPECT_TRUE(stream_->WriteAsync(
+      test_write_buffer_,
+      100,
+      base::Bind(success_callback, base::Unretained(&write_size)),
+      base::Bind(error_callback, base::Unretained(&failed)),
+      nullptr));
+  EXPECT_EQ(0u, write_size);
+  EXPECT_FALSE(failed);
+
+  EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 100)).WillOnce(Return(87));
+  data_callback.Run(Stream::AccessMode::WRITE);
+  EXPECT_EQ(87u, write_size);
+  EXPECT_FALSE(failed);
+}
+
+TEST_F(FileStreamTest, WriteNonBlocking) {
+  size_t size = 0;
+  EXPECT_CALL(fd_mock(), Write(test_write_buffer_, _))
+      .WillRepeatedly(ReturnArg<1>());
+  EXPECT_TRUE(stream_->WriteNonBlocking(test_write_buffer_, 100, &size,
+                                        nullptr));
+  EXPECT_EQ(100u, size);
+
+  EXPECT_TRUE(stream_->WriteNonBlocking(test_write_buffer_, 0, &size, nullptr));
+  EXPECT_EQ(0u, size);
+
+  EXPECT_CALL(fd_mock(), Write(test_write_buffer_, _)).WillOnce(Return(0));
+  EXPECT_TRUE(stream_->WriteNonBlocking(test_write_buffer_, 100, &size,
+                                        nullptr));
+  EXPECT_EQ(0u, size);
+
+  EXPECT_CALL(fd_mock(), Write(test_write_buffer_, _))
+      .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+  EXPECT_TRUE(stream_->WriteNonBlocking(test_write_buffer_, 100, &size,
+                                        nullptr));
+  EXPECT_EQ(0u, size);
+}
+
+TEST_F(FileStreamTest, WriteNonBlocking_Fail) {
+  size_t size = 0;
+  brillo::ErrorPtr error;
+  EXPECT_CALL(fd_mock(), Write(test_write_buffer_, _))
+      .WillOnce(SetErrnoAndReturn(EACCES, -1));
+  EXPECT_FALSE(stream_->WriteNonBlocking(test_write_buffer_, 100, &size,
+                                         &error));
+  EXPECT_EQ(errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("EACCES", error->GetCode());
+}
+
+TEST_F(FileStreamTest, WriteBlocking) {
+  size_t size = 0;
+  EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 100)).WillOnce(Return(20));
+  EXPECT_TRUE(stream_->WriteBlocking(test_write_buffer_, 100, &size, nullptr));
+  EXPECT_EQ(20u, size);
+
+  {
+    InSequence seq;
+    EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 80))
+        .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+    EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+        .WillOnce(Return(1));
+    EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 80)).WillOnce(Return(45));
+  }
+  EXPECT_TRUE(stream_->WriteBlocking(test_write_buffer_, 80, &size, nullptr));
+  EXPECT_EQ(45u, size);
+
+  {
+    InSequence seq;
+    EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 50)).WillOnce(Return(0));
+    EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+        .WillOnce(Return(1));
+    EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 50)).WillOnce(Return(1));
+  }
+  EXPECT_TRUE(stream_->WriteBlocking(test_write_buffer_, 50, &size, nullptr));
+  EXPECT_EQ(1u, size);
+}
+
+TEST_F(FileStreamTest, WriteBlocking_Fail) {
+  {
+    InSequence seq;
+    EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 80))
+        .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+    EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+        .WillOnce(SetErrnoAndReturn(EBADF, -1));
+  }
+  brillo::ErrorPtr error;
+  size_t size = 0;
+  EXPECT_FALSE(stream_->WriteBlocking(test_write_buffer_, 80, &size, &error));
+  EXPECT_EQ(errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("EBADF", error->GetCode());
+}
+
+TEST_F(FileStreamTest, WriteAllBlocking) {
+  {
+    InSequence seq;
+    EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 100)).WillOnce(Return(20));
+    EXPECT_CALL(fd_mock(), Write(test_write_buffer_ + 20, 80))
+        .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+    EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+        .WillOnce(Return(1));
+    EXPECT_CALL(fd_mock(), Write(test_write_buffer_ + 20, 80))
+        .WillOnce(Return(45));
+    EXPECT_CALL(fd_mock(), Write(test_write_buffer_ + 65, 35))
+        .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+    EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+        .WillOnce(Return(1));
+    EXPECT_CALL(fd_mock(), Write(test_write_buffer_ + 65, 35))
+        .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+    EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+        .WillOnce(Return(1));
+    EXPECT_CALL(fd_mock(), Write(test_write_buffer_ + 65, 35))
+        .WillOnce(Return(35));
+  }
+  EXPECT_TRUE(stream_->WriteAllBlocking(test_write_buffer_, 100, nullptr));
+}
+
+TEST_F(FileStreamTest, WriteAllBlocking_Fail) {
+  {
+    InSequence seq;
+    EXPECT_CALL(fd_mock(), Write(test_write_buffer_, 80))
+        .WillOnce(SetErrnoAndReturn(EAGAIN, -1));
+    EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+        .WillOnce(SetErrnoAndReturn(EBADF, -1));
+  }
+  brillo::ErrorPtr error;
+  EXPECT_FALSE(stream_->WriteAllBlocking(test_write_buffer_, 80, &error));
+  EXPECT_EQ(errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("EBADF", error->GetCode());
+}
+
+TEST_F(FileStreamTest, WaitForDataBlocking_Timeout) {
+  EXPECT_CALL(fd_mock(), WaitForDataBlocking(Stream::AccessMode::WRITE, _, _))
+      .WillOnce(Return(0));
+  brillo::ErrorPtr error;
+  EXPECT_FALSE(stream_->WaitForDataBlocking(Stream::AccessMode::WRITE, {},
+                                            nullptr, &error));
+  EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+  EXPECT_EQ(errors::stream::kTimeout, error->GetCode());
+}
+
+TEST_F(FileStreamTest, FlushBlocking) {
+  EXPECT_TRUE(stream_->FlushBlocking(nullptr));
+}
+
+TEST_F(FileStreamTest, CloseBlocking) {
+  EXPECT_CALL(fd_mock(), Close()).WillOnce(Return(0));
+  EXPECT_TRUE(stream_->CloseBlocking(nullptr));
+
+  EXPECT_CALL(fd_mock(), IsOpen()).WillOnce(Return(false));
+  EXPECT_TRUE(stream_->CloseBlocking(nullptr));
+}
+
+TEST_F(FileStreamTest, CloseBlocking_Fail) {
+  brillo::ErrorPtr error;
+  EXPECT_CALL(fd_mock(), Close()).WillOnce(SetErrnoAndReturn(EFBIG, -1));
+  EXPECT_FALSE(stream_->CloseBlocking(&error));
+  EXPECT_EQ(errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("EFBIG", error->GetCode());
+}
+
+TEST_F(FileStreamTest, WaitForData) {
+  EXPECT_CALL(fd_mock(), WaitForData(Stream::AccessMode::READ, _, _))
+      .WillOnce(Return(true));
+  EXPECT_TRUE(CallWaitForData(Stream::AccessMode::READ, nullptr));
+
+  EXPECT_CALL(fd_mock(), WaitForData(Stream::AccessMode::WRITE, _, _))
+      .WillOnce(Return(true));
+  EXPECT_TRUE(CallWaitForData(Stream::AccessMode::WRITE, nullptr));
+
+  EXPECT_CALL(fd_mock(), WaitForData(Stream::AccessMode::READ_WRITE, _, _))
+      .WillOnce(Return(true));
+  EXPECT_TRUE(CallWaitForData(Stream::AccessMode::READ_WRITE, nullptr));
+
+  EXPECT_CALL(fd_mock(), WaitForData(Stream::AccessMode::READ_WRITE, _, _))
+      .WillOnce(Return(false));
+  EXPECT_FALSE(CallWaitForData(Stream::AccessMode::READ_WRITE, nullptr));
+}
+
+TEST_F(FileStreamTest, CreateTemporary) {
+  StreamPtr stream = FileStream::CreateTemporary(nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  TestCreateFile(stream.get());
+}
+
+TEST_F(FileStreamTest, OpenRead) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.path().Append(base::FilePath{"test.dat"});
+  std::vector<char> buffer(1024 * 1024);
+  base::RandBytes(buffer.data(), buffer.size());
+  int file_size = buffer.size();  // Stupid base::WriteFile taking "int" size.
+  ASSERT_EQ(file_size, base::WriteFile(path, buffer.data(), file_size));
+
+  StreamPtr stream = FileStream::Open(path,
+                                      Stream::AccessMode::READ,
+                                      FileStream::Disposition::OPEN_EXISTING,
+                                      nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  ASSERT_TRUE(stream->IsOpen());
+  EXPECT_TRUE(stream->CanRead());
+  EXPECT_FALSE(stream->CanWrite());
+  EXPECT_TRUE(stream->CanSeek());
+  EXPECT_TRUE(stream->CanGetSize());
+  EXPECT_EQ(0u, stream->GetPosition());
+  EXPECT_EQ(buffer.size(), stream->GetSize());
+
+  std::vector<char> buffer2(buffer.size());
+  EXPECT_TRUE(stream->ReadAllBlocking(buffer2.data(), buffer2.size(), nullptr));
+  EXPECT_EQ(buffer2, buffer);
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+}
+
+TEST_F(FileStreamTest, OpenWrite) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.path().Append(base::FilePath{"test.dat"});
+  std::vector<char> buffer(1024 * 1024);
+  base::RandBytes(buffer.data(), buffer.size());
+
+  StreamPtr stream = FileStream::Open(path,
+                                      Stream::AccessMode::WRITE,
+                                      FileStream::Disposition::CREATE_ALWAYS,
+                                      nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  ASSERT_TRUE(stream->IsOpen());
+  EXPECT_FALSE(stream->CanRead());
+  EXPECT_TRUE(stream->CanWrite());
+  EXPECT_TRUE(stream->CanSeek());
+  EXPECT_TRUE(stream->CanGetSize());
+  EXPECT_EQ(0u, stream->GetPosition());
+  EXPECT_EQ(0u, stream->GetSize());
+
+  EXPECT_TRUE(stream->WriteAllBlocking(buffer.data(), buffer.size(), nullptr));
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+
+  std::vector<char> buffer2(buffer.size());
+  int file_size = buffer2.size();  // Stupid base::ReadFile taking "int" size.
+  ASSERT_EQ(file_size, base::ReadFile(path, buffer2.data(), file_size));
+  EXPECT_EQ(buffer2, buffer);
+}
+
+TEST_F(FileStreamTest, Open_OpenExisting) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.path().Append(base::FilePath{"test.dat"});
+  std::string data{"Lorem ipsum dolor sit amet ..."};
+  int data_size = data.size();  // I hate ints for data size...
+  ASSERT_EQ(data_size, base::WriteFile(path, data.data(), data_size));
+
+  StreamPtr stream = FileStream::Open(path,
+                                      Stream::AccessMode::READ_WRITE,
+                                      FileStream::Disposition::OPEN_EXISTING,
+                                      nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  EXPECT_TRUE(stream->CanRead());
+  EXPECT_TRUE(stream->CanWrite());
+  EXPECT_TRUE(stream->CanSeek());
+  EXPECT_TRUE(stream->CanGetSize());
+  EXPECT_EQ(0u, stream->GetPosition());
+  EXPECT_EQ(data.size(), stream->GetSize());
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+}
+
+TEST_F(FileStreamTest, Open_OpenExisting_Fail) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.path().Append(base::FilePath{"test.dat"});
+
+  ErrorPtr error;
+  StreamPtr stream = FileStream::Open(path,
+                                      Stream::AccessMode::READ_WRITE,
+                                      FileStream::Disposition::OPEN_EXISTING,
+                                      &error);
+  ASSERT_EQ(nullptr, stream.get());
+  EXPECT_EQ(errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("ENOENT", error->GetCode());
+}
+
+TEST_F(FileStreamTest, Open_CreateAlways_New) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.path().Append(base::FilePath{"test.dat"});
+
+  StreamPtr stream = FileStream::Open(path,
+                                      Stream::AccessMode::READ_WRITE,
+                                      FileStream::Disposition::CREATE_ALWAYS,
+                                      nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  EXPECT_TRUE(stream->CanRead());
+  EXPECT_TRUE(stream->CanWrite());
+  EXPECT_TRUE(stream->CanSeek());
+  EXPECT_TRUE(stream->CanGetSize());
+  EXPECT_EQ(0u, stream->GetPosition());
+  EXPECT_EQ(0u, stream->GetSize());
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+}
+
+TEST_F(FileStreamTest, Open_CreateAlways_Existing) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.path().Append(base::FilePath{"test.dat"});
+  std::string data{"Lorem ipsum dolor sit amet ..."};
+  int data_size = data.size();  // I hate ints for data size...
+  ASSERT_EQ(data_size, base::WriteFile(path, data.data(), data_size));
+
+  StreamPtr stream = FileStream::Open(path,
+                                      Stream::AccessMode::READ_WRITE,
+                                      FileStream::Disposition::CREATE_ALWAYS,
+                                      nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  EXPECT_TRUE(stream->CanRead());
+  EXPECT_TRUE(stream->CanWrite());
+  EXPECT_TRUE(stream->CanSeek());
+  EXPECT_TRUE(stream->CanGetSize());
+  EXPECT_EQ(0u, stream->GetPosition());
+  EXPECT_EQ(0u, stream->GetSize());
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+}
+
+TEST_F(FileStreamTest, Open_CreateNewOnly_New) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.path().Append(base::FilePath{"test.dat"});
+
+  StreamPtr stream = FileStream::Open(path,
+                                      Stream::AccessMode::READ_WRITE,
+                                      FileStream::Disposition::CREATE_NEW_ONLY,
+                                      nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  EXPECT_TRUE(stream->CanRead());
+  EXPECT_TRUE(stream->CanWrite());
+  EXPECT_TRUE(stream->CanSeek());
+  EXPECT_TRUE(stream->CanGetSize());
+  EXPECT_EQ(0u, stream->GetPosition());
+  EXPECT_EQ(0u, stream->GetSize());
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+}
+
+TEST_F(FileStreamTest, Open_CreateNewOnly_Existing) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.path().Append(base::FilePath{"test.dat"});
+  std::string data{"Lorem ipsum dolor sit amet ..."};
+  int data_size = data.size();  // I hate ints for data size...
+  ASSERT_EQ(data_size, base::WriteFile(path, data.data(), data_size));
+
+  ErrorPtr error;
+  StreamPtr stream = FileStream::Open(path,
+                                      Stream::AccessMode::READ_WRITE,
+                                      FileStream::Disposition::CREATE_NEW_ONLY,
+                                      &error);
+  ASSERT_EQ(nullptr, stream.get());
+  EXPECT_EQ(errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("EEXIST", error->GetCode());
+}
+
+TEST_F(FileStreamTest, Open_TruncateExisting_New) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.path().Append(base::FilePath{"test.dat"});
+
+  ErrorPtr error;
+  StreamPtr stream = FileStream::Open(
+      path,
+      Stream::AccessMode::READ_WRITE,
+      FileStream::Disposition::TRUNCATE_EXISTING,
+      &error);
+  ASSERT_EQ(nullptr, stream.get());
+  EXPECT_EQ(errors::system::kDomain, error->GetDomain());
+  EXPECT_EQ("ENOENT", error->GetCode());
+}
+
+TEST_F(FileStreamTest, Open_TruncateExisting_Existing) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath path = temp_dir.path().Append(base::FilePath{"test.dat"});
+  std::string data{"Lorem ipsum dolor sit amet ..."};
+  int data_size = data.size();  // I hate ints for data size...
+  ASSERT_EQ(data_size, base::WriteFile(path, data.data(), data_size));
+
+  StreamPtr stream = FileStream::Open(
+      path,
+      Stream::AccessMode::READ_WRITE,
+      FileStream::Disposition::TRUNCATE_EXISTING,
+      nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  EXPECT_TRUE(stream->CanRead());
+  EXPECT_TRUE(stream->CanWrite());
+  EXPECT_TRUE(stream->CanSeek());
+  EXPECT_TRUE(stream->CanGetSize());
+  EXPECT_EQ(0u, stream->GetPosition());
+  EXPECT_EQ(0u, stream->GetSize());
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+}
+
+TEST_F(FileStreamTest, FromFileDescriptor_StdIn) {
+  StreamPtr stream =
+      FileStream::FromFileDescriptor(STDIN_FILENO, false, nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  EXPECT_TRUE(stream->IsOpen());
+  EXPECT_TRUE(stream->CanRead());
+  EXPECT_FALSE(stream->CanSeek());
+  EXPECT_FALSE(stream->CanGetSize());
+}
+
+TEST_F(FileStreamTest, FromFileDescriptor_StdOut) {
+  StreamPtr stream =
+      FileStream::FromFileDescriptor(STDOUT_FILENO, false, nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  EXPECT_TRUE(stream->IsOpen());
+  EXPECT_TRUE(stream->CanWrite());
+  EXPECT_FALSE(stream->CanSeek());
+  EXPECT_FALSE(stream->CanGetSize());
+}
+
+TEST_F(FileStreamTest, FromFileDescriptor_StdErr) {
+  StreamPtr stream =
+      FileStream::FromFileDescriptor(STDERR_FILENO, false, nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  EXPECT_TRUE(stream->IsOpen());
+  EXPECT_TRUE(stream->CanWrite());
+  EXPECT_FALSE(stream->CanSeek());
+  EXPECT_FALSE(stream->CanGetSize());
+}
+
+TEST_F(FileStreamTest, FromFileDescriptor_ReadNonBlocking) {
+  int fds[2] = {-1, -1};
+  ASSERT_EQ(0, pipe(fds));
+
+  StreamPtr stream = FileStream::FromFileDescriptor(fds[0], true, nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  EXPECT_TRUE(stream->IsOpen());
+  EXPECT_TRUE(stream->CanRead());
+  EXPECT_FALSE(stream->CanWrite());
+  EXPECT_FALSE(stream->CanSeek());
+  EXPECT_FALSE(stream->CanGetSize());
+
+  char buf[10];
+  size_t read = 0;
+  bool eos = true;
+  EXPECT_TRUE(stream->ReadNonBlocking(buf, sizeof(buf), &read, &eos, nullptr));
+  EXPECT_EQ(0, read);
+  EXPECT_FALSE(eos);
+
+  std::string data{"foo_bar"};
+  EXPECT_TRUE(base::WriteFileDescriptor(fds[1], data.data(), data.size()));
+  EXPECT_TRUE(stream->ReadNonBlocking(buf, sizeof(buf), &read, &eos, nullptr));
+  EXPECT_EQ(data.size(), read);
+  EXPECT_FALSE(eos);
+  EXPECT_EQ(data, (std::string{buf, read}));
+
+  EXPECT_TRUE(stream->ReadNonBlocking(buf, sizeof(buf), &read, &eos, nullptr));
+  EXPECT_EQ(0, read);
+  EXPECT_FALSE(eos);
+
+  close(fds[1]);
+
+  EXPECT_TRUE(stream->ReadNonBlocking(buf, sizeof(buf), &read, &eos, nullptr));
+  EXPECT_EQ(0, read);
+  EXPECT_TRUE(eos);
+
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+}
+
+TEST_F(FileStreamTest, FromFileDescriptor_WriteNonBlocking) {
+  int fds[2] = {-1, -1};
+  ASSERT_EQ(0, pipe(fds));
+
+  StreamPtr stream = FileStream::FromFileDescriptor(fds[1], true, nullptr);
+  ASSERT_NE(nullptr, stream.get());
+  EXPECT_TRUE(stream->IsOpen());
+  EXPECT_FALSE(stream->CanRead());
+  EXPECT_TRUE(stream->CanWrite());
+  EXPECT_FALSE(stream->CanSeek());
+  EXPECT_FALSE(stream->CanGetSize());
+
+  // Pipe buffer is generally 64K, so 128K should be more than enough.
+  std::vector<char> buffer(128 * 1024);
+  base::RandBytes(buffer.data(), buffer.size());
+  size_t written = 0;
+  size_t total_size = 0;
+
+  // Fill the output buffer of the pipe until we can no longer write any data
+  // to it.
+  do {
+    ASSERT_TRUE(stream->WriteNonBlocking(buffer.data(), buffer.size(), &written,
+                                         nullptr));
+    total_size += written;
+  } while (written == buffer.size());
+
+  EXPECT_TRUE(stream->WriteNonBlocking(buffer.data(), buffer.size(), &written,
+                                       nullptr));
+  EXPECT_EQ(0, written);
+
+  std::vector<char> out_buffer(total_size);
+  EXPECT_TRUE(base::ReadFromFD(fds[0], out_buffer.data(), out_buffer.size()));
+
+  EXPECT_TRUE(stream->WriteNonBlocking(buffer.data(), buffer.size(), &written,
+                                       nullptr));
+  EXPECT_GT(written, 0);
+  out_buffer.resize(written);
+  EXPECT_TRUE(base::ReadFromFD(fds[0], out_buffer.data(), out_buffer.size()));
+  EXPECT_TRUE(std::equal(out_buffer.begin(), out_buffer.end(), buffer.begin()));
+
+  close(fds[0]);
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+}
+
+TEST_F(FileStreamTest, FromFileDescriptor_ReadAsync) {
+  int fds[2] = {-1, -1};
+  bool succeeded = false;
+  bool failed = false;
+  char buffer[100];
+  base::MessageLoopForIO base_loop;
+  BaseMessageLoop brillo_loop{&base_loop};
+  brillo_loop.SetAsCurrent();
+
+  auto success_callback = [](bool* succeeded, char* buffer, size_t size) {
+    std::string data{buffer, buffer + size};
+    ASSERT_EQ("abracadabra", data);
+    *succeeded = true;
+  };
+
+  auto error_callback = [](bool* failed, const Error* /* error */) {
+    *failed = true;
+  };
+
+  auto write_data_callback = [](int write_fd) {
+    std::string data{"abracadabra"};
+    EXPECT_TRUE(base::WriteFileDescriptor(write_fd, data.data(), data.size()));
+  };
+
+  ASSERT_EQ(0, pipe(fds));
+
+  StreamPtr stream = FileStream::FromFileDescriptor(fds[0], true, nullptr);
+
+  // Write to the pipe with a bit of delay.
+  brillo_loop.PostDelayedTask(
+      FROM_HERE,
+      base::Bind(write_data_callback, fds[1]),
+      base::TimeDelta::FromMilliseconds(10));
+
+  EXPECT_TRUE(
+      stream->ReadAsync(buffer,
+                        100,
+                        base::Bind(success_callback,
+                                   base::Unretained(&succeeded),
+                                   base::Unretained(buffer)),
+                        base::Bind(error_callback, base::Unretained(&failed)),
+                        nullptr));
+
+  auto end_condition = [](bool* failed, bool* succeeded) {
+    return *failed || *succeeded;
+  };
+  MessageLoopRunUntil(&brillo_loop,
+                      base::TimeDelta::FromSeconds(1),
+                      base::Bind(end_condition,
+                                 base::Unretained(&failed),
+                                 base::Unretained(&succeeded)));
+
+  EXPECT_TRUE(succeeded);
+  EXPECT_FALSE(failed);
+
+  close(fds[1]);
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+}
+
+TEST_F(FileStreamTest, FromFileDescriptor_WriteAsync) {
+  int fds[2] = {-1, -1};
+  bool succeeded = false;
+  bool failed = false;
+  const std::string data{"abracadabra"};
+  base::MessageLoopForIO base_loop;
+  BaseMessageLoop brillo_loop{&base_loop};
+  brillo_loop.SetAsCurrent();
+
+  ASSERT_EQ(0, pipe(fds));
+
+  auto success_callback = [](bool* succeeded,
+                             const std::string& data,
+                             int read_fd,
+                             size_t /* size */) {
+    char buffer[100];
+    EXPECT_TRUE(base::ReadFromFD(read_fd, buffer, data.size()));
+    EXPECT_EQ(data, (std::string{buffer, buffer + data.size()}));
+    *succeeded = true;
+  };
+
+  auto error_callback = [](bool* failed, const Error* /* error */) {
+    *failed = true;
+  };
+
+  StreamPtr stream = FileStream::FromFileDescriptor(fds[1], true, nullptr);
+
+  EXPECT_TRUE(stream->WriteAsync(
+      data.data(),
+      data.size(),
+      base::Bind(success_callback, base::Unretained(&succeeded), data, fds[0]),
+      base::Bind(error_callback, base::Unretained(&failed)),
+      nullptr));
+
+  auto end_condition = [](bool* failed, bool* succeeded) {
+    return *failed || *succeeded;
+  };
+  MessageLoopRunUntil(&brillo_loop,
+                      base::TimeDelta::FromSeconds(1),
+                      base::Bind(end_condition,
+                                 base::Unretained(&failed),
+                                 base::Unretained(&succeeded)));
+
+  EXPECT_TRUE(succeeded);
+  EXPECT_FALSE(failed);
+
+  close(fds[0]);
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/input_stream_set.cc b/libbrillo/brillo/streams/input_stream_set.cc
new file mode 100644
index 0000000..986efac
--- /dev/null
+++ b/libbrillo/brillo/streams/input_stream_set.cc
@@ -0,0 +1,205 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/input_stream_set.h>
+
+#include <base/bind.h>
+#include <brillo/message_loops/message_loop.h>
+#include <brillo/streams/stream_errors.h>
+#include <brillo/streams/stream_utils.h>
+
+namespace brillo {
+
+InputStreamSet::InputStreamSet(
+    std::vector<Stream*> source_streams,
+    std::vector<StreamPtr> owned_source_streams,
+    uint64_t initial_stream_size)
+    : source_streams_{std::move(source_streams)},
+      owned_source_streams_{std::move(owned_source_streams)},
+      initial_stream_size_{initial_stream_size} {}
+
+StreamPtr InputStreamSet::Create(std::vector<Stream*> source_streams,
+                                 std::vector<StreamPtr> owned_source_streams,
+                                 ErrorPtr* error) {
+  StreamPtr stream;
+
+  if (source_streams.empty()) {
+    Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
+                 errors::stream::kInvalidParameter,
+                 "Source stream list is empty");
+    return stream;
+  }
+
+  // Make sure we have only readable streams.
+  for (Stream* src_stream : source_streams) {
+    if (!src_stream->CanRead()) {
+      Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
+                   errors::stream::kInvalidParameter,
+                   "The stream list must contain only readable streams");
+      return stream;
+    }
+  }
+
+  // We are using remaining size here because the multiplexed stream is not
+  // seekable and the bytes already read are essentially "lost" as far as this
+  // stream is concerned.
+  uint64_t initial_stream_size = 0;
+  for (const Stream* stream : source_streams)
+    initial_stream_size += stream->GetRemainingSize();
+
+  stream.reset(new InputStreamSet{std::move(source_streams),
+                                  std::move(owned_source_streams),
+                                  initial_stream_size});
+  return stream;
+}
+
+StreamPtr InputStreamSet::Create(std::vector<Stream*> source_streams,
+                                 ErrorPtr* error) {
+  return Create(std::move(source_streams), {}, error);
+}
+
+StreamPtr InputStreamSet::Create(std::vector<StreamPtr> owned_source_streams,
+                                 ErrorPtr* error) {
+  std::vector<Stream*> source_streams;
+  source_streams.reserve(owned_source_streams.size());
+  for (const StreamPtr& stream : owned_source_streams)
+    source_streams.push_back(stream.get());
+  return Create(std::move(source_streams), std::move(owned_source_streams),
+                error);
+}
+
+bool InputStreamSet::IsOpen() const {
+  return !closed_;
+}
+
+bool InputStreamSet::CanGetSize() const {
+  bool can_get_size = IsOpen();
+  for (const Stream* stream : source_streams_) {
+    if (!stream->CanGetSize()) {
+      can_get_size = false;
+      break;
+    }
+  }
+  return can_get_size;
+}
+
+uint64_t InputStreamSet::GetSize() const {
+  return initial_stream_size_;
+}
+
+bool InputStreamSet::SetSizeBlocking(uint64_t /* size */, ErrorPtr* error) {
+  return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+}
+
+uint64_t InputStreamSet::GetRemainingSize() const {
+  uint64_t size = 0;
+  for (const Stream* stream : source_streams_)
+    size += stream->GetRemainingSize();
+  return size;
+}
+
+bool InputStreamSet::Seek(int64_t /* offset */,
+                          Whence /* whence */,
+                          uint64_t* /* new_position */,
+                          ErrorPtr* error) {
+  return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+}
+
+bool InputStreamSet::ReadNonBlocking(void* buffer,
+                                     size_t size_to_read,
+                                     size_t* size_read,
+                                     bool* end_of_stream,
+                                     ErrorPtr* error) {
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  while (!source_streams_.empty()) {
+    Stream* stream = source_streams_.front();
+    bool eos = false;
+    if (!stream->ReadNonBlocking(buffer, size_to_read, size_read, &eos, error))
+      return false;
+
+    if (*size_read > 0 || !eos) {
+      if (end_of_stream)
+        *end_of_stream = false;
+      return true;
+    }
+
+    source_streams_.erase(source_streams_.begin());
+  }
+  *size_read = 0;
+  if (end_of_stream)
+    *end_of_stream = true;
+  return true;
+}
+
+bool InputStreamSet::WriteNonBlocking(const void* /* buffer */,
+                                      size_t /* size_to_write */,
+                                      size_t* /* size_written */,
+                                      ErrorPtr* error) {
+  return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+}
+
+bool InputStreamSet::CloseBlocking(ErrorPtr* error) {
+  bool success = true;
+  // We want to close only the owned streams.
+  for (StreamPtr& stream_ptr : owned_source_streams_) {
+    if (!stream_ptr->CloseBlocking(error))
+      success = false;  // Keep going for other streams...
+  }
+  owned_source_streams_.clear();
+  source_streams_.clear();
+  initial_stream_size_ = 0;
+  closed_ = true;
+  return success;
+}
+
+bool InputStreamSet::WaitForData(
+    AccessMode mode,
+    const base::Callback<void(AccessMode)>& callback,
+    ErrorPtr* error) {
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  if (stream_utils::IsWriteAccessMode(mode))
+    return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+
+  if (!source_streams_.empty()) {
+    Stream* stream = source_streams_.front();
+    return stream->WaitForData(mode, callback, error);
+  }
+
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, mode));
+  return true;
+}
+
+bool InputStreamSet::WaitForDataBlocking(AccessMode in_mode,
+                                         base::TimeDelta timeout,
+                                         AccessMode* out_mode,
+                                         ErrorPtr* error) {
+  if (!IsOpen())
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+
+  if (stream_utils::IsWriteAccessMode(in_mode))
+    return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+
+  if (!source_streams_.empty()) {
+    Stream* stream = source_streams_.front();
+    return stream->WaitForDataBlocking(in_mode, timeout, out_mode, error);
+  }
+
+  if (out_mode)
+    *out_mode = in_mode;
+  return true;
+}
+
+void InputStreamSet::CancelPendingAsyncOperations() {
+  if (IsOpen() && !source_streams_.empty()) {
+    Stream* stream = source_streams_.front();
+    stream->CancelPendingAsyncOperations();
+  }
+  Stream::CancelPendingAsyncOperations();
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/input_stream_set.h b/libbrillo/brillo/streams/input_stream_set.h
new file mode 100644
index 0000000..9111ff9
--- /dev/null
+++ b/libbrillo/brillo/streams/input_stream_set.h
@@ -0,0 +1,132 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_STREAMS_INPUT_STREAM_SET_H_
+#define LIBBRILLO_BRILLO_STREAMS_INPUT_STREAM_SET_H_
+
+#include <vector>
+
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+#include <brillo/streams/stream.h>
+
+namespace brillo {
+
+// Multiplexer stream allows to bundle a bunch of secondary streams in one
+// logical stream and simulate a read operation across data concatenated from
+// all those source streams.
+//
+// When created on a set of source streams like stream1, stream2, stream3, etc.,
+// reading from the multiplexer stream will read all the data from stream1 until
+// end-of-stream is reached, then keep reading from stream2, stream3 and so on.
+//
+// InputStreamSet has an option of owning the underlying source streams
+// or just referencing them. Owned streams are passed to InputStreamSet
+// with exclusive ownership transfer (using StreamPtr) and those streams will
+// be closed/destroyed when InputStreamSet is closed/destroyed.
+// Referenced source streams' life time is maintained elsewhere and they must
+// be valid for the duration of InputStreamSet's life. Closing the
+// muliplexer stream does not close the referenced streams.
+class BRILLO_EXPORT InputStreamSet : public Stream {
+ public:
+  // == Construction ==========================================================
+
+  // Generic method that constructs a multiplexer stream on a list of source
+  // streams. |source_streams| is the list of all source stream references
+  // in the order they need to be read from. |owned_source_streams| is a list
+  // of source stream instances that the multiplexer stream will own.
+  // Note that the streams from |owned_source_streams| should still be
+  // referenced in |source_streams| if you need their data to be read from.
+  // |owned_source_streams| could be empty (in which case none of the source
+  // streams are not owned), or contain fewer items than in |source_streams|.
+  static StreamPtr Create(std::vector<Stream*> source_streams,
+                          std::vector<StreamPtr> owned_source_streams,
+                          ErrorPtr* error);
+
+  // Simple helper method to create a multiplexer stream with a list of
+  // referenced streams. None of the streams will be owned.
+  // Effectively calls Create(source_streams, {}, error);
+  static StreamPtr Create(std::vector<Stream*> source_streams, ErrorPtr* error);
+
+  // Simple helper method to create a multiplexer stream with a list of
+  // referenced streams. None of the streams will be owned.
+  // Effectively calls Create(source_streams, owned_source_streams, error)
+  // with |source_streams| containing pointers to the streams from
+  // |owned_source_streams| list.
+  static StreamPtr Create(std::vector<StreamPtr> owned_source_streams,
+                          ErrorPtr* error);
+
+  // == Stream capabilities ===================================================
+  bool IsOpen() const override;
+  bool CanRead() const override { return true; }
+  bool CanWrite() const override { return false; }
+  bool CanSeek() const override { return false; }
+  bool CanGetSize() const override;
+
+  // == Stream size operations ================================================
+  uint64_t GetSize() const override;
+  bool SetSizeBlocking(uint64_t size, ErrorPtr* error) override;
+  uint64_t GetRemainingSize() const override;
+
+  // == Seek operations =======================================================
+  uint64_t GetPosition() const override { return 0; }
+  bool Seek(int64_t offset,
+            Whence whence,
+            uint64_t* new_position,
+            ErrorPtr* error) override;
+
+  // == Read operations =======================================================
+  bool ReadNonBlocking(void* buffer,
+                       size_t size_to_read,
+                       size_t* size_read,
+                       bool* end_of_stream,
+                       ErrorPtr* error) override;
+
+  // == Write operations ======================================================
+  bool WriteNonBlocking(const void* buffer,
+                        size_t size_to_write,
+                        size_t* size_written,
+                        ErrorPtr* error) override;
+
+  // == Finalizing/closing streams  ===========================================
+  bool FlushBlocking(ErrorPtr* /* error */) override { return true; }
+  bool CloseBlocking(ErrorPtr* error) override;
+
+  // == Data availability monitoring ==========================================
+  bool WaitForData(AccessMode mode,
+                   const base::Callback<void(AccessMode)>& callback,
+                   ErrorPtr* error) override;
+
+  bool WaitForDataBlocking(AccessMode in_mode,
+                           base::TimeDelta timeout,
+                           AccessMode* out_mode,
+                           ErrorPtr* error) override;
+
+  void CancelPendingAsyncOperations() override;
+
+ private:
+  friend class InputStreamSetTest;
+
+  // Internal constructor used by the Create() factory methods.
+  InputStreamSet(std::vector<Stream*> source_streams,
+                 std::vector<StreamPtr> owned_source_streams,
+                 uint64_t initial_stream_size);
+
+  // List of streams to read data from.
+  std::vector<Stream*> source_streams_;
+
+  // List of source streams this stream owns. Owned source streams will be
+  // closed when InputStreamSet::CloseBlocking() is called and will be
+  // destroyed when this stream is destroyed.
+  std::vector<StreamPtr> owned_source_streams_;
+
+  uint64_t initial_stream_size_{0};
+  bool closed_{false};
+
+  DISALLOW_COPY_AND_ASSIGN(InputStreamSet);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_STREAMS_INPUT_STREAM_SET_H_
diff --git a/libbrillo/brillo/streams/input_stream_set_unittest.cc b/libbrillo/brillo/streams/input_stream_set_unittest.cc
new file mode 100644
index 0000000..3268d96
--- /dev/null
+++ b/libbrillo/brillo/streams/input_stream_set_unittest.cc
@@ -0,0 +1,170 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/input_stream_set.h>
+
+#include <brillo/errors/error_codes.h>
+#include <brillo/streams/mock_stream.h>
+#include <brillo/streams/stream_errors.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::An;
+using testing::DoAll;
+using testing::InSequence;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::StrictMock;
+using testing::_;
+
+namespace brillo {
+
+class InputStreamSetTest : public testing::Test {
+ public:
+  void SetUp() override {
+    itf1_.reset(new StrictMock<MockStream>{});
+    itf2_.reset(new StrictMock<MockStream>{});
+    stream_.reset(new InputStreamSet({itf1_.get(), itf2_.get()}, {}, 100));
+  }
+
+  void TearDown() override {
+    stream_.reset();
+    itf2_.reset();
+    itf1_.reset();
+  }
+
+  std::unique_ptr<StrictMock<MockStream>> itf1_;
+  std::unique_ptr<StrictMock<MockStream>> itf2_;
+  std::unique_ptr<InputStreamSet> stream_;
+
+  inline static void* IntToPtr(int addr) {
+    return reinterpret_cast<void*>(addr);
+  }
+};
+
+TEST_F(InputStreamSetTest, InitialFalseAssumptions) {
+  // Methods that should just succeed/fail without calling underlying streams.
+  EXPECT_TRUE(stream_->CanRead());
+  EXPECT_FALSE(stream_->CanWrite());
+  EXPECT_FALSE(stream_->CanSeek());
+  EXPECT_EQ(100, stream_->GetSize());
+  EXPECT_FALSE(stream_->SetSizeBlocking(0, nullptr));
+  EXPECT_FALSE(stream_->GetPosition());
+  EXPECT_FALSE(stream_->Seek(0, Stream::Whence::FROM_BEGIN, nullptr, nullptr));
+  char buffer[100];
+  size_t size = 0;
+  EXPECT_FALSE(stream_->WriteAsync(buffer, sizeof(buffer), {}, {}, nullptr));
+  EXPECT_FALSE(stream_->WriteAllAsync(buffer, sizeof(buffer), {}, {}, nullptr));
+  EXPECT_FALSE(stream_->WriteNonBlocking(buffer, sizeof(buffer), &size,
+                                         nullptr));
+  EXPECT_FALSE(stream_->WriteBlocking(buffer, sizeof(buffer), &size, nullptr));
+  EXPECT_FALSE(stream_->WriteAllBlocking(buffer, sizeof(buffer), nullptr));
+  EXPECT_TRUE(stream_->FlushBlocking(nullptr));
+  EXPECT_TRUE(stream_->CloseBlocking(nullptr));
+}
+
+TEST_F(InputStreamSetTest, InitialTrueAssumptions) {
+  // Methods that redirect calls to underlying streams.
+  EXPECT_CALL(*itf1_, CanGetSize()).WillOnce(Return(true));
+  EXPECT_CALL(*itf2_, CanGetSize()).WillOnce(Return(true));
+  EXPECT_TRUE(stream_->CanGetSize());
+
+  // Reading from the first stream fails, so the second one shouldn't be used.
+  EXPECT_CALL(*itf1_, ReadNonBlocking(_, _, _, _, _))
+      .WillOnce(Return(false));
+  EXPECT_CALL(*itf2_, ReadNonBlocking(_, _, _, _, _)).Times(0);
+  char buffer[100];
+  size_t size = 0;
+  EXPECT_FALSE(stream_->ReadBlocking(buffer, sizeof(buffer), &size, nullptr));
+}
+
+TEST_F(InputStreamSetTest, CanGetSize) {
+  EXPECT_CALL(*itf1_, CanGetSize()).WillOnce(Return(true));
+  EXPECT_CALL(*itf2_, CanGetSize()).WillOnce(Return(true));
+  EXPECT_TRUE(stream_->CanGetSize());
+
+  EXPECT_CALL(*itf1_, CanGetSize()).WillOnce(Return(false));
+  EXPECT_FALSE(stream_->CanGetSize());
+
+  EXPECT_CALL(*itf1_, CanGetSize()).WillOnce(Return(true));
+  EXPECT_CALL(*itf2_, CanGetSize()).WillOnce(Return(false));
+  EXPECT_FALSE(stream_->CanGetSize());
+}
+
+TEST_F(InputStreamSetTest, GetRemainingSize) {
+  EXPECT_CALL(*itf1_, GetRemainingSize()).WillOnce(Return(10));
+  EXPECT_CALL(*itf2_, GetRemainingSize()).WillOnce(Return(32));
+  EXPECT_EQ(42, stream_->GetRemainingSize());
+}
+
+TEST_F(InputStreamSetTest, ReadNonBlocking) {
+  size_t read = 0;
+  bool eos = false;
+
+  InSequence s;
+  EXPECT_CALL(*itf1_, ReadNonBlocking(IntToPtr(1000), 100, _, _, _))
+    .WillOnce(DoAll(SetArgPointee<2>(10),
+                    SetArgPointee<3>(false),
+                    Return(true)));
+  EXPECT_TRUE(stream_->ReadNonBlocking(IntToPtr(1000), 100, &read, &eos,
+                                       nullptr));
+  EXPECT_EQ(10, read);
+  EXPECT_FALSE(eos);
+
+  EXPECT_CALL(*itf1_, ReadNonBlocking(IntToPtr(1000), 100, _, _, _))
+    .WillOnce(DoAll(SetArgPointee<2>(0), SetArgPointee<3>(true), Return(true)));
+  EXPECT_CALL(*itf2_, ReadNonBlocking(IntToPtr(1000), 100 , _, _, _))
+    .WillOnce(DoAll(SetArgPointee<2>(100),
+                    SetArgPointee<3>(false),
+                    Return(true)));
+  EXPECT_TRUE(stream_->ReadNonBlocking(IntToPtr(1000), 100, &read, &eos,
+                                       nullptr));
+  EXPECT_EQ(100, read);
+  EXPECT_FALSE(eos);
+
+  EXPECT_CALL(*itf2_, ReadNonBlocking(IntToPtr(1000), 100, _, _, _))
+    .WillOnce(DoAll(SetArgPointee<2>(0), SetArgPointee<3>(true), Return(true)));
+  EXPECT_TRUE(stream_->ReadNonBlocking(IntToPtr(1000), 100, &read, &eos,
+                                       nullptr));
+  EXPECT_EQ(0, read);
+  EXPECT_TRUE(eos);
+}
+
+TEST_F(InputStreamSetTest, ReadBlocking) {
+  size_t read = 0;
+
+  InSequence s;
+  EXPECT_CALL(*itf1_, ReadNonBlocking(IntToPtr(1000), 100, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(10),
+                      SetArgPointee<3>(false),
+                      Return(true)));
+  EXPECT_TRUE(stream_->ReadBlocking(IntToPtr(1000), 100, &read, nullptr));
+  EXPECT_EQ(10, read);
+
+  EXPECT_CALL(*itf1_, ReadNonBlocking(IntToPtr(1000), 100, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(0),
+                      SetArgPointee<3>(true),
+                      Return(true)));
+  EXPECT_CALL(*itf2_, ReadNonBlocking(IntToPtr(1000), 100, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(0),
+                      SetArgPointee<3>(false),
+                      Return(true)));
+  EXPECT_CALL(*itf2_, WaitForDataBlocking(Stream::AccessMode::READ, _, _, _))
+      .WillOnce(Return(true));
+  EXPECT_CALL(*itf2_, ReadNonBlocking(IntToPtr(1000), 100, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(100),
+                      SetArgPointee<3>(false),
+                      Return(true)));
+  EXPECT_TRUE(stream_->ReadBlocking(IntToPtr(1000), 100, &read, nullptr));
+  EXPECT_EQ(100, read);
+
+  EXPECT_CALL(*itf2_, ReadNonBlocking(IntToPtr(1000), 100, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(0),
+                      SetArgPointee<3>(true),
+                      Return(true)));
+  EXPECT_TRUE(stream_->ReadBlocking(IntToPtr(1000), 100, &read, nullptr));
+  EXPECT_EQ(0, read);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/memory_containers.cc b/libbrillo/brillo/streams/memory_containers.cc
new file mode 100644
index 0000000..c1b842e
--- /dev/null
+++ b/libbrillo/brillo/streams/memory_containers.cc
@@ -0,0 +1,132 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/memory_containers.h>
+
+#include <base/callback.h>
+#include <brillo/streams/stream_errors.h>
+
+namespace brillo {
+namespace data_container {
+
+namespace {
+
+bool ErrorStreamReadOnly(const tracked_objects::Location& location,
+                         ErrorPtr* error) {
+  Error::AddTo(error,
+               location,
+               errors::stream::kDomain,
+               errors::stream::kOperationNotSupported,
+               "Stream is read-only");
+  return false;
+}
+
+}  // anonymous namespace
+
+void ContiguousBufferBase::CopyMemoryBlock(void* dest,
+                                           const void* src,
+                                           size_t size) const {
+  memcpy(dest, src, size);
+}
+
+bool ContiguousBufferBase::Read(void* buffer,
+                                size_t size_to_read,
+                                size_t offset,
+                                size_t* size_read,
+                                ErrorPtr* error) {
+  size_t buf_size = GetSize();
+  if (offset < buf_size) {
+    size_t remaining = buf_size - offset;
+    if (size_to_read >= remaining) {
+      size_to_read = remaining;
+    }
+    const void* src_buffer = GetReadOnlyBuffer(offset, error);
+    if (!src_buffer)
+      return false;
+
+    CopyMemoryBlock(buffer, src_buffer, size_to_read);
+  } else {
+    size_to_read = 0;
+  }
+  if (size_read)
+    *size_read = size_to_read;
+  return true;
+}
+
+bool ContiguousBufferBase::Write(const void* buffer,
+                                 size_t size_to_write,
+                                 size_t offset,
+                                 size_t* size_written,
+                                 ErrorPtr* error) {
+  if (size_to_write) {
+    size_t new_size = offset + size_to_write;
+    if (GetSize() < new_size && !Resize(new_size, error))
+      return false;
+    void* ptr = GetBuffer(offset, error);
+    if (!ptr)
+      return false;
+    CopyMemoryBlock(ptr, buffer, size_to_write);
+    if (size_written)
+      *size_written = size_to_write;
+  }
+  return true;
+}
+
+bool ContiguousReadOnlyBufferBase::Write(const void* /* buffer */,
+                                         size_t /* size_to_write */,
+                                         size_t /* offset */,
+                                         size_t* /* size_written */,
+                                         ErrorPtr* error) {
+  return ErrorStreamReadOnly(FROM_HERE, error);
+}
+
+bool ContiguousReadOnlyBufferBase::Resize(size_t /* new_size */,
+                                          ErrorPtr* error) {
+  return ErrorStreamReadOnly(FROM_HERE, error);
+}
+
+void* ContiguousReadOnlyBufferBase::GetBuffer(size_t /* offset */,
+                                              ErrorPtr* error) {
+  ErrorStreamReadOnly(FROM_HERE, error);
+  return nullptr;
+}
+
+ByteBuffer::ByteBuffer(size_t reserve_size)
+    : VectorPtr(new std::vector<uint8_t>()) {
+  vector_ptr_->reserve(reserve_size);
+}
+
+ByteBuffer::~ByteBuffer() {
+  delete vector_ptr_;
+}
+
+StringPtr::StringPtr(std::string* string) : string_ptr_(string) {}
+
+bool StringPtr::Resize(size_t new_size, ErrorPtr* /* error */) {
+  string_ptr_->resize(new_size);
+  return true;
+}
+
+const void* StringPtr::GetReadOnlyBuffer(size_t offset,
+                                         ErrorPtr* /* error */) const {
+  return string_ptr_->data() + offset;
+}
+
+void* StringPtr::GetBuffer(size_t offset, ErrorPtr* /* error */) {
+  return &(*string_ptr_)[offset];
+}
+
+ReadOnlyStringRef::ReadOnlyStringRef(const std::string& string)
+    : string_ref_(string) {}
+
+const void* ReadOnlyStringRef::GetReadOnlyBuffer(size_t offset,
+                                                 ErrorPtr* /* error */) const {
+  return string_ref_.data() + offset;
+}
+
+ReadOnlyStringCopy::ReadOnlyStringCopy(std::string string)
+    : ReadOnlyStringRef(string_copy_), string_copy_(std::move(string)) {}
+
+}  // namespace data_container
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/memory_containers.h b/libbrillo/brillo/streams/memory_containers.h
new file mode 100644
index 0000000..d3cb205
--- /dev/null
+++ b/libbrillo/brillo/streams/memory_containers.h
@@ -0,0 +1,288 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_STREAMS_MEMORY_CONTAINERS_H_
+#define LIBBRILLO_BRILLO_STREAMS_MEMORY_CONTAINERS_H_
+
+#include <string>
+#include <vector>
+
+#include <brillo/brillo_export.h>
+#include <brillo/errors/error.h>
+#include <brillo/streams/stream.h>
+
+namespace brillo {
+namespace data_container {
+
+// MemoryStream class relies on helper classes defined below to support data
+// storage in various types of containers.
+// A particular implementation of container type (e.g. based on raw memory
+// buffers, std::vector, std::string or others) need to implement the container
+// interface provided by data_container::DataContainerInterface.
+// Low-level functionality such as reading data from and writing data to the
+// container, getting and changing the buffer size, and so on, must be provided.
+// Not all methods must be provided. For example, for read-only containers, only
+// read operations can be provided.
+class BRILLO_EXPORT DataContainerInterface {
+ public:
+  DataContainerInterface() = default;
+  virtual ~DataContainerInterface() = default;
+
+  // Read the data from the container into |buffer|. Up to |size_to_read| bytes
+  // must be read at a time. The container can return fewer bytes. The actual
+  // size of data read is provided in |size_read|.
+  // If the read operation fails, the function must return false and provide
+  // additional information about the error in |error| object.
+  virtual bool Read(void* buffer,
+                    size_t size_to_read,
+                    size_t offset,
+                    size_t* size_read,
+                    ErrorPtr* error) = 0;
+
+  // Writes |size_to_write| bytes of data from |buffer| into the container.
+  // The container may accept fewer bytes of data. The actual size of data
+  // written is provided in |size_written|.
+  // If the read operation fails, the function must return false and provide
+  // additional information about the error in |error| object.
+  virtual bool Write(const void* buffer,
+                     size_t size_to_write,
+                     size_t offset,
+                     size_t* size_written,
+                     ErrorPtr* error) = 0;
+  // Resizes the container to the new size specified in |new_size|.
+  virtual bool Resize(size_t new_size, ErrorPtr* error) = 0;
+  // Returns the current size of the container.
+  virtual size_t GetSize() const = 0;
+  // Returns true if the container is read-only.
+  virtual bool IsReadOnly() const = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DataContainerInterface);
+};
+
+// ContiguousBufferBase is a helper base class for memory containers that
+// employ contiguous memory for all of their data. This class provides the
+// default implementation for Read() and Write() functions and requires the
+// implementations to provide GetBuffer() and/or ReadOnlyBuffer() functions.
+class BRILLO_EXPORT ContiguousBufferBase : public DataContainerInterface {
+ public:
+  ContiguousBufferBase() = default;
+  // Implementation of DataContainerInterface::Read().
+  bool Read(void* buffer,
+            size_t size_to_read,
+            size_t offset,
+            size_t* size_read,
+            ErrorPtr* error) override;
+  // Implementation of DataContainerInterface::Write().
+  bool Write(const void* buffer,
+             size_t size_to_write,
+             size_t offset,
+             size_t* size_written,
+             ErrorPtr* error) override;
+
+  // Overload to provide the pointer to the read-only data for the container at
+  // the specified |offset|. In case of an error, this function must return
+  // nullptr and provide error details in |error| object if provided.
+  virtual const void* GetReadOnlyBuffer(size_t offset,
+                                        ErrorPtr* error) const = 0;
+  // Overload to provide the pointer to the read/write data for the container at
+  // the specified |offset|. In case of an error, this function must return
+  // nullptr and provide error details in |error| object if provided.
+  virtual void* GetBuffer(size_t offset, ErrorPtr* error) = 0;
+
+ protected:
+  // Wrapper around memcpy which can be mocked out in tests.
+  virtual void CopyMemoryBlock(void* dest, const void* src, size_t size) const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ContiguousBufferBase);
+};
+
+// ContiguousReadOnlyBufferBase is a specialization of ContiguousBufferBase for
+// read-only containers.
+class BRILLO_EXPORT ContiguousReadOnlyBufferBase : public ContiguousBufferBase {
+ public:
+  ContiguousReadOnlyBufferBase() = default;
+  // Fails with an error "operation_not_supported" (Stream is read-only) error.
+  bool Write(const void* buffer,
+             size_t size_to_write,
+             size_t offset,
+             size_t* size_written,
+             ErrorPtr* error) override;
+  // Fails with an error "operation_not_supported" (Stream is read-only) error.
+  bool Resize(size_t new_size, ErrorPtr* error) override;
+  // Fails with an error "operation_not_supported" (Stream is read-only) error.
+  bool IsReadOnly() const override { return true; }
+  // Fails with an error "operation_not_supported" (Stream is read-only) error.
+  void* GetBuffer(size_t offset, ErrorPtr* error) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ContiguousReadOnlyBufferBase);
+};
+
+// ReadOnlyBuffer implements a read-only container based on raw memory block.
+class BRILLO_EXPORT ReadOnlyBuffer : public ContiguousReadOnlyBufferBase {
+ public:
+  // Constructs the container based at the pointer to memory |buffer| and its
+  // |size|. The pointer to the memory must be valid throughout life-time of
+  // the stream using this container.
+  ReadOnlyBuffer(const void* buffer, size_t size)
+      : buffer_(buffer), size_(size) {}
+
+  // Returns the pointer to data at |offset|.
+  const void* GetReadOnlyBuffer(size_t offset,
+                                ErrorPtr* /* error */) const override {
+    return reinterpret_cast<const uint8_t*>(buffer_) + offset;
+  }
+  // Returns the size of the container.
+  size_t GetSize() const override { return size_; }
+
+ private:
+  // Raw memory pointer to the data block and its size.
+  const void* buffer_;
+  size_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReadOnlyBuffer);
+};
+
+// VectorPtr<T> is a read/write container based on a vector<T> pointer.
+// This is a template class to allow usage of both vector<char> and
+// vector<uint8_t> without duplicating the implementation.
+template<typename T>
+class VectorPtr : public ContiguousBufferBase {
+ public:
+  static_assert(sizeof(T) == 1, "Only char/byte is supported");
+  explicit VectorPtr(std::vector<T>* vector) : vector_ptr_(vector) {}
+
+  bool Resize(size_t new_size, ErrorPtr* /* error */) override {
+    vector_ptr_->resize(new_size);
+    return true;
+  }
+  size_t GetSize() const override { return vector_ptr_->size(); }
+  bool IsReadOnly() const override { return false; }
+  const void* GetReadOnlyBuffer(size_t offset,
+                                ErrorPtr* /* error */) const override {
+    return reinterpret_cast<const uint8_t*>(vector_ptr_->data()) + offset;
+  }
+  void* GetBuffer(size_t offset, ErrorPtr* /* error */) override {
+    return reinterpret_cast<uint8_t*>(vector_ptr_->data()) + offset;
+  }
+
+ protected:
+  std::vector<T>* vector_ptr_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(VectorPtr);
+};
+
+// ReadOnlyVectorRef<T> is a read-only container based on a vector<T> reference.
+// This is a template class to allow usage of both vector<char> and
+// vector<uint8_t> without duplicating the implementation.
+template<typename T>
+class ReadOnlyVectorRef : public ContiguousReadOnlyBufferBase {
+ public:
+  static_assert(sizeof(T) == 1, "Only char/byte is supported");
+  explicit ReadOnlyVectorRef(const std::vector<T>& vector)
+      : vector_ref_(vector) {}
+
+  const void* GetReadOnlyBuffer(size_t offset,
+                                ErrorPtr* /* error */) const override {
+    return reinterpret_cast<const uint8_t*>(vector_ref_.data()) + offset;
+  }
+  size_t GetSize() const override { return vector_ref_.size(); }
+
+ protected:
+  const std::vector<T>& vector_ref_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ReadOnlyVectorRef);
+};
+
+// ReadOnlyVectorCopy<T> is a read-only container based on a copy of vector<T>.
+// This container actually owns the data stored in the vector.
+// This is a template class to allow usage of both vector<char> and
+// vector<uint8_t> without duplicating the implementation.
+template<typename T>
+class ReadOnlyVectorCopy : public ContiguousReadOnlyBufferBase {
+ public:
+  static_assert(sizeof(T) == 1, "Only char/byte is supported");
+  explicit ReadOnlyVectorCopy(std::vector<T> vector)
+      : vector_copy_(std::move(vector)) {}
+
+  ReadOnlyVectorCopy(const T* buffer, size_t size)
+      : vector_copy_(buffer, buffer + size) {}
+
+  const void* GetReadOnlyBuffer(size_t offset,
+                                ErrorPtr* /* error */) const override {
+    return reinterpret_cast<const uint8_t*>(vector_copy_.data()) + offset;
+  }
+  size_t GetSize() const override { return vector_copy_.size(); }
+
+ protected:
+  std::vector<T> vector_copy_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ReadOnlyVectorCopy);
+};
+
+// ByteBuffer is a read/write container that manages the data and underlying
+// storage.
+class BRILLO_EXPORT ByteBuffer : public VectorPtr<uint8_t> {
+ public:
+  explicit ByteBuffer(size_t reserve_size);
+  ~ByteBuffer() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ByteBuffer);
+};
+
+// StringPtr is a read/write container based on external std::string storage.
+class BRILLO_EXPORT StringPtr : public ContiguousBufferBase {
+ public:
+  explicit StringPtr(std::string* string);
+
+  bool Resize(size_t new_size, ErrorPtr* error) override;
+  size_t GetSize() const override { return string_ptr_->size(); }
+  bool IsReadOnly() const override { return false; }
+  const void* GetReadOnlyBuffer(size_t offset, ErrorPtr* error) const override;
+  void* GetBuffer(size_t offset, ErrorPtr* error) override;
+
+ protected:
+  std::string* string_ptr_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StringPtr);
+};
+
+// ReadOnlyStringRef is a read-only container based on external std::string.
+class BRILLO_EXPORT ReadOnlyStringRef : public ContiguousReadOnlyBufferBase {
+ public:
+  explicit ReadOnlyStringRef(const std::string& string);
+  const void* GetReadOnlyBuffer(size_t offset, ErrorPtr* error) const override;
+  size_t GetSize() const override { return string_ref_.size(); }
+
+ protected:
+  const std::string& string_ref_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ReadOnlyStringRef);
+};
+
+// ReadOnlyStringCopy is a read-only container based on a copy of a std::string.
+// This container actually owns the data stored in the string.
+class BRILLO_EXPORT ReadOnlyStringCopy : public ReadOnlyStringRef {
+ public:
+  explicit ReadOnlyStringCopy(std::string string);
+
+ protected:
+  std::string string_copy_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ReadOnlyStringCopy);
+};
+
+}  // namespace data_container
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_STREAMS_MEMORY_CONTAINERS_H_
diff --git a/libbrillo/brillo/streams/memory_containers_unittest.cc b/libbrillo/brillo/streams/memory_containers_unittest.cc
new file mode 100644
index 0000000..2f0bf38
--- /dev/null
+++ b/libbrillo/brillo/streams/memory_containers_unittest.cc
@@ -0,0 +1,214 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/memory_containers.h>
+
+#include <limits>
+#include <memory>
+
+#include <brillo/streams/mock_stream.h>
+#include <brillo/streams/stream_errors.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::DoAll;
+using testing::Invoke;
+using testing::InSequence;
+using testing::Return;
+using testing::WithArgs;
+using testing::_;
+
+namespace brillo {
+
+namespace {
+class MockContiguousBuffer : public data_container::ContiguousBufferBase {
+ public:
+  MockContiguousBuffer() = default;
+
+  MOCK_METHOD2(Resize, bool(size_t, ErrorPtr*));
+  MOCK_CONST_METHOD0(GetSize, size_t());
+  MOCK_CONST_METHOD0(IsReadOnly, bool());
+
+  MOCK_CONST_METHOD2(GetReadOnlyBuffer, const void*(size_t, ErrorPtr*));
+  MOCK_METHOD2(GetBuffer, void*(size_t, ErrorPtr*));
+
+  MOCK_CONST_METHOD3(CopyMemoryBlock, void(void*, const void*, size_t));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockContiguousBuffer);
+};
+}  // anonymous namespace
+
+class MemoryContainerTest : public testing::Test {
+ public:
+  inline static void* IntToPtr(int addr) {
+    return reinterpret_cast<void*>(addr);
+  }
+
+  inline static const void* IntToConstPtr(int addr) {
+    return reinterpret_cast<const void*>(addr);
+  }
+
+  // Dummy buffer pointer values used as external data source/destination for
+  // read/write operations.
+  void* const test_read_buffer_ = IntToPtr(12345);
+  const void* const test_write_buffer_ = IntToConstPtr(67890);
+
+  // Dummy buffer pointer values used for internal buffer owned by the
+  // memory buffer container class.
+  const void* const const_buffer_ = IntToConstPtr(123);
+  void* const buffer_ = IntToPtr(456);
+
+  MockContiguousBuffer container_;
+};
+
+TEST_F(MemoryContainerTest, Read_WithinBuffer) {
+  {
+    InSequence s;
+    EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
+    EXPECT_CALL(container_, GetReadOnlyBuffer(10, _))
+      .WillOnce(Return(const_buffer_));
+    EXPECT_CALL(container_,
+                CopyMemoryBlock(test_read_buffer_, const_buffer_, 50)).Times(1);
+  }
+  size_t read = 0;
+  ErrorPtr error;
+  EXPECT_TRUE(container_.Read(test_read_buffer_, 50, 10, &read, &error));
+  EXPECT_EQ(50, read);
+  EXPECT_EQ(nullptr, error.get());
+}
+
+TEST_F(MemoryContainerTest, Read_PastEndOfBuffer) {
+  {
+    InSequence s;
+    EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
+    EXPECT_CALL(container_, GetReadOnlyBuffer(80, _))
+      .WillOnce(Return(const_buffer_));
+    EXPECT_CALL(container_,
+                CopyMemoryBlock(test_read_buffer_, const_buffer_, 20)).Times(1);
+  }
+  size_t read = 0;
+  EXPECT_TRUE(container_.Read(test_read_buffer_, 50, 80, &read, nullptr));
+  EXPECT_EQ(20, read);
+}
+
+TEST_F(MemoryContainerTest, Read_OutsideBuffer) {
+  EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
+  size_t read = 0;
+  EXPECT_TRUE(container_.Read(test_read_buffer_, 50, 100, &read, nullptr));
+  EXPECT_EQ(0, read);
+}
+
+TEST_F(MemoryContainerTest, Read_Error) {
+  auto OnReadError = [](ErrorPtr* error) {
+    Error::AddTo(error, FROM_HERE, "domain", "read_error", "read error");
+  };
+
+  {
+    InSequence s;
+    EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
+    EXPECT_CALL(container_, GetReadOnlyBuffer(0, _))
+      .WillOnce(DoAll(WithArgs<1>(Invoke(OnReadError)), Return(nullptr)));
+  }
+  size_t read = 0;
+  ErrorPtr error;
+  EXPECT_FALSE(container_.Read(test_read_buffer_, 10, 0, &read, &error));
+  EXPECT_EQ(0, read);
+  EXPECT_NE(nullptr, error.get());
+  EXPECT_EQ("domain", error->GetDomain());
+  EXPECT_EQ("read_error", error->GetCode());
+  EXPECT_EQ("read error", error->GetMessage());
+}
+
+TEST_F(MemoryContainerTest, Write_WithinBuffer) {
+  {
+    InSequence s;
+    EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
+    EXPECT_CALL(container_, GetBuffer(10, _))
+      .WillOnce(Return(buffer_));
+    EXPECT_CALL(container_,
+                CopyMemoryBlock(buffer_, test_write_buffer_, 50)).Times(1);
+  }
+  size_t written = 0;
+  ErrorPtr error;
+  EXPECT_TRUE(container_.Write(test_write_buffer_, 50, 10, &written, &error));
+  EXPECT_EQ(50, written);
+  EXPECT_EQ(nullptr, error.get());
+}
+
+TEST_F(MemoryContainerTest, Write_PastEndOfBuffer) {
+  {
+    InSequence s;
+    EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
+    EXPECT_CALL(container_, Resize(130, _)).WillOnce(Return(true));
+    EXPECT_CALL(container_, GetBuffer(80, _))
+      .WillOnce(Return(buffer_));
+    EXPECT_CALL(container_,
+                CopyMemoryBlock(buffer_, test_write_buffer_, 50)).Times(1);
+  }
+  size_t written = 0;
+  EXPECT_TRUE(container_.Write(test_write_buffer_, 50, 80, &written, nullptr));
+  EXPECT_EQ(50, written);
+}
+
+TEST_F(MemoryContainerTest, Write_OutsideBuffer) {
+  {
+    InSequence s;
+    EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
+    EXPECT_CALL(container_, Resize(160, _)).WillOnce(Return(true));
+    EXPECT_CALL(container_, GetBuffer(110, _))
+      .WillOnce(Return(buffer_));
+    EXPECT_CALL(container_,
+                CopyMemoryBlock(buffer_, test_write_buffer_, 50)).Times(1);
+  }
+  size_t written = 0;
+  EXPECT_TRUE(container_.Write(test_write_buffer_, 50, 110, &written, nullptr));
+  EXPECT_EQ(50, written);
+}
+
+TEST_F(MemoryContainerTest, Write_Error_Resize) {
+  auto OnWriteError = [](ErrorPtr* error) {
+    Error::AddTo(error, FROM_HERE, "domain", "write_error", "resize error");
+  };
+
+  {
+    InSequence s;
+    EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
+    EXPECT_CALL(container_, Resize(160, _))
+      .WillOnce(DoAll(WithArgs<1>(Invoke(OnWriteError)), Return(false)));
+  }
+  size_t written = 0;
+  ErrorPtr error;
+  EXPECT_FALSE(container_.Write(test_write_buffer_, 50, 110, &written, &error));
+  EXPECT_EQ(0, written);
+  EXPECT_NE(nullptr, error.get());
+  EXPECT_EQ("domain", error->GetDomain());
+  EXPECT_EQ("write_error", error->GetCode());
+  EXPECT_EQ("resize error", error->GetMessage());
+}
+
+TEST_F(MemoryContainerTest, Write_Error) {
+  auto OnWriteError = [](ErrorPtr* error) {
+    Error::AddTo(error, FROM_HERE, "domain", "write_error", "write error");
+  };
+
+  {
+    InSequence s;
+    EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
+    EXPECT_CALL(container_, Resize(160, _)).WillOnce(Return(true));
+    EXPECT_CALL(container_, GetBuffer(110, _))
+      .WillOnce(DoAll(WithArgs<1>(Invoke(OnWriteError)), Return(nullptr)));
+  }
+  size_t written = 0;
+  ErrorPtr error;
+  EXPECT_FALSE(container_.Write(test_write_buffer_, 50, 110, &written, &error));
+  EXPECT_EQ(0, written);
+  EXPECT_NE(nullptr, error.get());
+  EXPECT_EQ("domain", error->GetDomain());
+  EXPECT_EQ("write_error", error->GetCode());
+  EXPECT_EQ("write error", error->GetMessage());
+}
+
+}  // namespace brillo
+
diff --git a/libbrillo/brillo/streams/memory_stream.cc b/libbrillo/brillo/streams/memory_stream.cc
new file mode 100644
index 0000000..54f127a
--- /dev/null
+++ b/libbrillo/brillo/streams/memory_stream.cc
@@ -0,0 +1,201 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/memory_stream.h>
+
+#include <limits>
+
+#include <base/bind.h>
+#include <brillo/message_loops/message_loop.h>
+#include <brillo/streams/stream_errors.h>
+#include <brillo/streams/stream_utils.h>
+
+namespace brillo {
+
+MemoryStream::MemoryStream(
+    std::unique_ptr<data_container::DataContainerInterface> container,
+    size_t stream_position)
+    : container_{std::move(container)}, stream_position_{stream_position} {}
+
+StreamPtr MemoryStream::OpenRef(const void* buffer,
+                                size_t size,
+                                ErrorPtr* error) {
+  std::unique_ptr<data_container::ReadOnlyBuffer> container{
+      new data_container::ReadOnlyBuffer{buffer, size}};
+  return CreateEx(std::move(container), 0, error);
+}
+
+StreamPtr MemoryStream::OpenCopyOf(const void* buffer,
+                                   size_t size,
+                                   ErrorPtr* error) {
+  std::unique_ptr<data_container::ReadOnlyVectorCopy<uint8_t>> container{
+      new data_container::ReadOnlyVectorCopy<uint8_t>{
+          reinterpret_cast<const uint8_t*>(buffer), size}};
+  return CreateEx(std::move(container), 0, error);
+}
+
+StreamPtr MemoryStream::OpenRef(const std::string& buffer, ErrorPtr* error) {
+  std::unique_ptr<data_container::ReadOnlyStringRef> container{
+      new data_container::ReadOnlyStringRef{buffer}};
+  return CreateEx(std::move(container), 0, error);
+}
+
+StreamPtr MemoryStream::OpenCopyOf(std::string buffer, ErrorPtr* error) {
+  std::unique_ptr<data_container::ReadOnlyStringCopy> container{
+      new data_container::ReadOnlyStringCopy{std::move(buffer)}};
+  return CreateEx(std::move(container), 0, error);
+}
+
+StreamPtr MemoryStream::OpenRef(const char* buffer, ErrorPtr* error) {
+  return OpenRef(buffer, std::strlen(buffer), error);
+}
+
+StreamPtr MemoryStream::OpenCopyOf(const char* buffer, ErrorPtr* error) {
+  return OpenCopyOf(buffer, std::strlen(buffer), error);
+}
+
+StreamPtr MemoryStream::Create(size_t reserve_size, ErrorPtr* error) {
+  std::unique_ptr<data_container::ByteBuffer> container{
+      new data_container::ByteBuffer{reserve_size}};
+  return CreateEx(std::move(container), 0, error);
+}
+
+StreamPtr MemoryStream::CreateRef(std::string* buffer, ErrorPtr* error) {
+  std::unique_ptr<data_container::StringPtr> container{
+      new data_container::StringPtr{buffer}};
+  return CreateEx(std::move(container), 0, error);
+}
+
+StreamPtr MemoryStream::CreateRefForAppend(std::string* buffer,
+                                           ErrorPtr* error) {
+  std::unique_ptr<data_container::StringPtr> container{
+      new data_container::StringPtr{buffer}};
+  return CreateEx(std::move(container), buffer->size(), error);
+}
+
+StreamPtr MemoryStream::CreateEx(
+    std::unique_ptr<data_container::DataContainerInterface> container,
+    size_t stream_position,
+    ErrorPtr* error) {
+  ignore_result(error);  // Unused.
+  return StreamPtr{new MemoryStream(std::move(container), stream_position)};
+}
+
+bool MemoryStream::IsOpen() const { return container_ != nullptr; }
+bool MemoryStream::CanRead() const { return IsOpen(); }
+
+bool MemoryStream::CanWrite() const {
+  return IsOpen() && !container_->IsReadOnly();
+}
+
+bool MemoryStream::CanSeek() const { return IsOpen(); }
+bool MemoryStream::CanGetSize() const { return IsOpen(); }
+
+uint64_t MemoryStream::GetSize() const {
+  return IsOpen() ? container_->GetSize() : 0;
+}
+
+bool MemoryStream::SetSizeBlocking(uint64_t size, ErrorPtr* error) {
+  if (!CheckContainer(error))
+    return false;
+  return container_->Resize(size, error);
+}
+
+uint64_t MemoryStream::GetRemainingSize() const {
+  uint64_t pos = GetPosition();
+  uint64_t size = GetSize();
+  return (pos < size) ? size - pos : 0;
+}
+
+uint64_t MemoryStream::GetPosition() const {
+  return IsOpen() ? stream_position_ : 0;
+}
+
+bool MemoryStream::Seek(int64_t offset,
+                        Whence whence,
+                        uint64_t* new_position,
+                        ErrorPtr* error) {
+  uint64_t pos = 0;
+  if (!CheckContainer(error) ||
+      !stream_utils::CalculateStreamPosition(FROM_HERE, offset, whence,
+                                             stream_position_, GetSize(), &pos,
+                                             error)) {
+    return false;
+  }
+  if (pos > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) {
+    // This can only be the case on 32 bit systems.
+    brillo::Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
+                         errors::stream::kInvalidParameter,
+                         "Stream pointer position is outside allowed limits");
+    return false;
+  }
+
+  stream_position_ = static_cast<size_t>(pos);
+  if (new_position)
+    *new_position = stream_position_;
+  return true;
+}
+
+bool MemoryStream::ReadNonBlocking(void* buffer,
+                                   size_t size_to_read,
+                                   size_t* size_read,
+                                   bool* end_of_stream,
+                                   ErrorPtr* error) {
+  if (!CheckContainer(error))
+    return false;
+  size_t read = 0;
+  if (!container_->Read(buffer, size_to_read, stream_position_, &read, error))
+    return false;
+  stream_position_ += read;
+  *size_read = read;
+  if (end_of_stream)
+    *end_of_stream = (read == 0) && (size_to_read != 0);
+  return true;
+}
+
+bool MemoryStream::WriteNonBlocking(const void* buffer,
+                                    size_t size_to_write,
+                                    size_t* size_written,
+                                    ErrorPtr* error) {
+  if (!CheckContainer(error))
+    return false;
+  if (!container_->Write(buffer, size_to_write, stream_position_, size_written,
+                         error)) {
+    return false;
+  }
+  stream_position_ += *size_written;
+  return true;
+}
+
+bool MemoryStream::FlushBlocking(ErrorPtr* error) {
+  return CheckContainer(error);
+}
+
+bool MemoryStream::CloseBlocking(ErrorPtr* error) {
+  ignore_result(error);  // Unused.
+  container_.reset();
+  return true;
+}
+
+bool MemoryStream::CheckContainer(ErrorPtr* error) const {
+  return container_ || stream_utils::ErrorStreamClosed(FROM_HERE, error);
+}
+
+bool MemoryStream::WaitForData(AccessMode mode,
+                               const base::Callback<void(AccessMode)>& callback,
+                               ErrorPtr* /* error */) {
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, mode));
+  return true;
+}
+
+bool MemoryStream::WaitForDataBlocking(AccessMode in_mode,
+                                       base::TimeDelta /* timeout */,
+                                       AccessMode* out_mode,
+                                       ErrorPtr* /* error */) {
+  if (out_mode)
+    *out_mode = in_mode;
+  return true;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/memory_stream.h b/libbrillo/brillo/streams/memory_stream.h
new file mode 100644
index 0000000..b4927a8
--- /dev/null
+++ b/libbrillo/brillo/streams/memory_stream.h
@@ -0,0 +1,212 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_STREAMS_MEMORY_STREAM_H_
+#define LIBBRILLO_BRILLO_STREAMS_MEMORY_STREAM_H_
+
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+#include <base/memory/weak_ptr.h>
+#include <brillo/brillo_export.h>
+#include <brillo/streams/memory_containers.h>
+#include <brillo/streams/stream.h>
+
+namespace brillo {
+
+// MemoryStream is a brillo::Stream implementation for memory buffer. A number
+// of memory containers are supported, such as raw memory pointers, data stored
+// in std::vector and std::string.
+// MemoryStream offers support for constant read-only memory buffers as well as
+// for writable buffers that can grow when needed.
+// A memory stream is created by using the OpenNNN and CreateNNN factory methods
+// to construct a read-only and writable streams respectively.
+// The following factory methods overloads are provided:
+//  - OpenRef    - overloads for constructing the stream on a constant read-only
+//                 memory buffer that is not owned by the stream. The buffer
+//                 pointer/reference must remain valid throughout the lifetime
+//                 of the constructed stream object. The benefit of this is that
+//                 no data copying is performed and the underlying container can
+//                 be manipulated outside of the stream.
+//  - OpenCopyOf - overloads to construct a stream that copies the data from the
+//                 memory buffer and maintains the copied data until the stream
+//                 is closed or destroyed. This makes it possible to construct
+//                 a read-only streams on transient data or for cases where
+//                 it is not possible or necessary to maintain the lifetime of
+//                 the underlying memory buffer.
+//  - Create     - creates a new internal memory buffer that can be written to
+//                 or read from using the stream I/O interface.
+//  - CreateRef  - constructs a read/write stream on a reference of data
+//                 container such as std::vector or std::string which must
+//                 remain valid throughout the lifetime of the memory stream.
+//                 The data already stored in the container is maintained,
+//                 however the stream pointer is set to the beginning of the
+//                 data when the stream is created.
+//  - CreateRefForAppend - similar to CreateRef except that it automatically
+//                 positions the stream seek pointer at the end of the data,
+//                 which makes it possible to append more data to the existing
+//                 container.
+class BRILLO_EXPORT MemoryStream : public Stream {
+ public:
+  // == Construction ==========================================================
+
+  // Constructs a read-only stream on a generic memory buffer. The data
+  // pointed to by |buffer| will be copied and owned by the stream object.
+  static StreamPtr OpenCopyOf(const void* buffer, size_t size, ErrorPtr* error);
+  static StreamPtr OpenCopyOf(std::string buffer, ErrorPtr* error);
+  static StreamPtr OpenCopyOf(const char* buffer, ErrorPtr* error);
+  // Only vectors of char and uint8_t are supported.
+  template<typename T>
+  inline static StreamPtr OpenCopyOf(std::vector<T> buffer, ErrorPtr* error) {
+    std::unique_ptr<data_container::ReadOnlyVectorCopy<T>> container{
+        new data_container::ReadOnlyVectorCopy<T>{std::move(buffer)}};
+    return CreateEx(std::move(container), 0, error);
+  }
+
+  // Constructs a read-only stream on a generic memory buffer which is owned
+  // by the caller.
+  // ***WARNING***: The |buffer| pointer must be valid for as long as the stream
+  // object is alive. The stream does not do any additional lifetime management
+  // for the data pointed to by |buffer| and destroying that buffer before
+  // the stream is closed will lead to unexpected behavior.
+  static StreamPtr OpenRef(const void* buffer, size_t size, ErrorPtr* error);
+  static StreamPtr OpenRef(const std::string& buffer, ErrorPtr* error);
+  static StreamPtr OpenRef(const char* buffer, ErrorPtr* error);
+  // Only vectors of char and uint8_t are supported.
+  template<typename T>
+  inline static StreamPtr OpenRef(const std::vector<T>& buffer,
+                                  ErrorPtr* error) {
+    std::unique_ptr<data_container::ReadOnlyVectorRef<T>> container{
+        new data_container::ReadOnlyVectorRef<T>{buffer}};
+    return CreateEx(std::move(container), 0, error);
+  }
+
+  ///------------------------------------------------------------------------
+  // Creates new stream for reading/writing. This method creates an internal
+  // memory buffer and maintains it until the stream is closed. |reserve_size|
+  // parameter is a hint of the buffer size to pre-allocate. This does not
+  // affect the memory buffer reported size. The buffer can grow past that
+  // amount if needed.
+  static StreamPtr Create(size_t reserve_size, ErrorPtr* error);
+
+  inline static StreamPtr Create(ErrorPtr* error) { return Create(0, error); }
+
+  // Creates new stream for reading/writing stored in a string. The string
+  // |buffer| must remain valid during the lifetime of the stream.
+  // The stream pointer will be at the beginning of the string and the string's
+  // content is preserved.
+  static StreamPtr CreateRef(std::string* buffer, ErrorPtr* error);
+
+  // Creates new stream for reading/writing stored in a vector. The vector
+  // |buffer| must remain valid during the lifetime of the stream.
+  // The stream pointer will be at the beginning of the data and the vector's
+  // content is preserved.
+  // Only vectors of char and uint8_t are supported.
+  template<typename T>
+  static StreamPtr CreateRef(std::vector<T>* buffer, ErrorPtr* error) {
+    std::unique_ptr<data_container::VectorPtr<T>> container{
+        new data_container::VectorPtr<T>{buffer}};
+    return CreateEx(std::move(container), 0, error);
+  }
+
+  // Creates new stream for reading/writing stored in a string. The string
+  // |buffer| must remain valid during the lifetime of the stream.
+  // The stream pointer will be at the end of the string and the string's
+  // content is preserved.
+  static StreamPtr CreateRefForAppend(std::string* buffer, ErrorPtr* error);
+
+  // Creates new stream for reading/writing stored in a vector. The vector
+  // |buffer| must remain valid during the lifetime of the stream.
+  // The stream pointer will be at the end of the data and the vector's
+  // content is preserved.
+  // Only vectors of char and uint8_t are supported.
+  template<typename T>
+  static StreamPtr CreateRefForAppend(std::vector<T>* buffer, ErrorPtr* error) {
+    std::unique_ptr<data_container::VectorPtr<T>> container{
+        new data_container::VectorPtr<T>{buffer}};
+    return CreateEx(std::move(container), buffer->size() * sizeof(T), error);
+  }
+
+  ///------------------------------------------------------------------------
+  // Generic stream creation on a data container. Takes an arbitrary |container|
+  // and constructs a stream using it. The container determines the traits of
+  // the stream (e.g. whether it is read-only, what operations are supported
+  // and so on). |stream_position| is the current stream pointer position at
+  // creation time.
+  static StreamPtr CreateEx(
+      std::unique_ptr<data_container::DataContainerInterface> container,
+      size_t stream_position,
+      ErrorPtr* error);
+
+  // == Stream capabilities ===================================================
+  bool IsOpen() const override;
+  bool CanRead() const override;
+  bool CanWrite() const override;
+  bool CanSeek() const override;
+  bool CanGetSize() const override;
+
+  // == Stream size operations ================================================
+  uint64_t GetSize() const override;
+  bool SetSizeBlocking(uint64_t size, ErrorPtr* error) override;
+  uint64_t GetRemainingSize() const override;
+
+  // == Seek operations =======================================================
+  uint64_t GetPosition() const override;
+  bool Seek(int64_t offset,
+            Whence whence,
+            uint64_t* new_position,
+            ErrorPtr* error) override;
+
+  // == Read operations =======================================================
+  bool ReadNonBlocking(void* buffer,
+                       size_t size_to_read,
+                       size_t* size_read,
+                       bool* end_of_stream,
+                       ErrorPtr* error) override;
+
+  // == Write operations ======================================================
+  bool WriteNonBlocking(const void* buffer,
+                        size_t size_to_write,
+                        size_t* size_written,
+                        ErrorPtr* error) override;
+
+  // == Finalizing/closing streams  ===========================================
+  bool FlushBlocking(ErrorPtr* error) override;
+  bool CloseBlocking(ErrorPtr* error) override;
+
+  // == Data availability monitoring ==========================================
+  bool WaitForData(AccessMode mode,
+                   const base::Callback<void(AccessMode)>& callback,
+                   ErrorPtr* error) override;
+
+  bool WaitForDataBlocking(AccessMode in_mode,
+                           base::TimeDelta timeout,
+                           AccessMode* out_mode,
+                           ErrorPtr* error) override;
+
+ private:
+  friend class MemoryStreamTest;
+
+  // Private constructor used by MemoryStream::OpenNNNN() and
+  // MemoryStream::CreateNNNN() factory methods.
+  MemoryStream(
+      std::unique_ptr<data_container::DataContainerInterface> container,
+      size_t stream_position);
+
+  // Checks if the stream has a valid container.
+  bool CheckContainer(ErrorPtr* error) const;
+
+  // Data container the stream is using to write and/or read data.
+  std::unique_ptr<data_container::DataContainerInterface> container_;
+
+  // The current stream pointer position.
+  size_t stream_position_{0};
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryStream);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_STREAMS_MEMORY_STREAM_H_
diff --git a/libbrillo/brillo/streams/memory_stream_unittest.cc b/libbrillo/brillo/streams/memory_stream_unittest.cc
new file mode 100644
index 0000000..75278f7
--- /dev/null
+++ b/libbrillo/brillo/streams/memory_stream_unittest.cc
@@ -0,0 +1,382 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/memory_stream.h>
+
+#include <algorithm>
+#include <limits>
+#include <numeric>
+#include <string>
+#include <vector>
+
+#include <brillo/streams/stream_errors.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::DoAll;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::_;
+
+namespace brillo {
+
+namespace {
+
+int ReadByte(Stream* stream, brillo::ErrorPtr* error) {
+  uint8_t byte = 0;
+  return stream->ReadAllBlocking(&byte, sizeof(byte), error) ? byte : -1;
+}
+
+class MockMemoryContainer : public data_container::DataContainerInterface {
+ public:
+  MockMemoryContainer() = default;
+
+  MOCK_METHOD5(Read, bool(void*, size_t, size_t, size_t*, ErrorPtr*));
+  MOCK_METHOD5(Write, bool(const void*, size_t, size_t, size_t*, ErrorPtr*));
+  MOCK_METHOD2(Resize, bool(size_t, ErrorPtr*));
+  MOCK_CONST_METHOD0(GetSize, size_t());
+  MOCK_CONST_METHOD0(IsReadOnly, bool());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockMemoryContainer);
+};
+
+}  // anonymous namespace
+
+class MemoryStreamTest : public testing::Test {
+ public:
+  void SetUp() override {
+    std::unique_ptr<MockMemoryContainer> container{new MockMemoryContainer{}};
+    stream_.reset(new MemoryStream{std::move(container), 0});
+  }
+
+  MockMemoryContainer& container_mock() {
+    return *static_cast<MockMemoryContainer*>(stream_->container_.get());
+  }
+
+  inline static void* IntToPtr(int addr) {
+    return reinterpret_cast<void*>(addr);
+  }
+
+  inline static const void* IntToConstPtr(int addr) {
+    return reinterpret_cast<const void*>(addr);
+  }
+
+  std::unique_ptr<MemoryStream> stream_;
+  // Dummy buffer pointer values to make sure that input pointer values
+  // are delegated to the stream interface without a change.
+  void* const test_read_buffer_ = IntToPtr(12345);
+  const void* const test_write_buffer_ = IntToConstPtr(67890);
+  // We limit the size of memory streams to be the maximum size of either of
+  // size_t (on 32 bit platforms) or the size of signed 64 bit integer.
+  const size_t kSizeMax =
+      std::min<uint64_t>(std::numeric_limits<size_t>::max(),
+                         std::numeric_limits<int64_t>::max());
+};
+
+TEST_F(MemoryStreamTest, CanRead) {
+  EXPECT_TRUE(stream_->CanRead());
+}
+
+TEST_F(MemoryStreamTest, CanWrite) {
+  EXPECT_CALL(container_mock(), IsReadOnly())
+    .WillOnce(Return(true))
+    .WillOnce(Return(false));
+
+  EXPECT_FALSE(stream_->CanWrite());
+  EXPECT_TRUE(stream_->CanWrite());
+}
+
+TEST_F(MemoryStreamTest, CanSeek) {
+  EXPECT_TRUE(stream_->CanSeek());
+}
+
+TEST_F(MemoryStreamTest, GetSize) {
+  EXPECT_CALL(container_mock(), GetSize())
+    .WillOnce(Return(0))
+    .WillOnce(Return(1234))
+    .WillOnce(Return(kSizeMax));
+
+  EXPECT_EQ(0, stream_->GetSize());
+  EXPECT_EQ(1234, stream_->GetSize());
+  EXPECT_EQ(kSizeMax, stream_->GetSize());
+}
+
+TEST_F(MemoryStreamTest, SetSizeBlocking) {
+  EXPECT_CALL(container_mock(), Resize(0, _)).WillOnce(Return(true));
+
+  ErrorPtr error;
+  EXPECT_TRUE(stream_->SetSizeBlocking(0, &error));
+  EXPECT_EQ(nullptr, error.get());
+
+  EXPECT_CALL(container_mock(), Resize(kSizeMax, nullptr))
+    .WillOnce(Return(true));
+
+  EXPECT_TRUE(stream_->SetSizeBlocking(kSizeMax, nullptr));
+}
+
+TEST_F(MemoryStreamTest, SeekAndGetPosition) {
+  EXPECT_EQ(0, stream_->GetPosition());
+
+  EXPECT_CALL(container_mock(), GetSize()).WillRepeatedly(Return(200));
+
+  ErrorPtr error;
+  uint64_t new_pos = 0;
+  EXPECT_TRUE(stream_->Seek(2, Stream::Whence::FROM_BEGIN, &new_pos, &error));
+  EXPECT_EQ(nullptr, error.get());
+  EXPECT_EQ(2, new_pos);
+  EXPECT_EQ(2, stream_->GetPosition());
+  EXPECT_TRUE(stream_->Seek(2, Stream::Whence::FROM_CURRENT, &new_pos, &error));
+  EXPECT_EQ(nullptr, error.get());
+  EXPECT_EQ(4, new_pos);
+  EXPECT_EQ(4, stream_->GetPosition());
+
+  EXPECT_TRUE(stream_->Seek(-2, Stream::Whence::FROM_END, nullptr, nullptr));
+  EXPECT_EQ(198, stream_->GetPosition());
+
+  EXPECT_CALL(container_mock(), GetSize()).WillOnce(Return(kSizeMax));
+  EXPECT_TRUE(stream_->Seek(0, Stream::Whence::FROM_END, nullptr, nullptr));
+  EXPECT_EQ(kSizeMax, stream_->GetPosition());
+}
+
+TEST_F(MemoryStreamTest, ReadNonBlocking) {
+  size_t read = 0;
+  bool eos = false;
+
+  EXPECT_CALL(container_mock(), Read(test_read_buffer_, 10, 0, _, nullptr))
+    .WillOnce(DoAll(SetArgPointee<3>(5), Return(true)));
+
+  EXPECT_TRUE(stream_->ReadNonBlocking(test_read_buffer_, 10, &read, &eos,
+                                       nullptr));
+  EXPECT_EQ(5, read);
+  EXPECT_EQ(5, stream_->GetPosition());
+  EXPECT_FALSE(eos);
+
+  EXPECT_CALL(container_mock(), Read(test_read_buffer_, 100, 5, _, nullptr))
+    .WillOnce(DoAll(SetArgPointee<3>(100), Return(true)));
+
+  EXPECT_TRUE(stream_->ReadNonBlocking(test_read_buffer_, 100, &read, &eos,
+                                       nullptr));
+  EXPECT_EQ(100, read);
+  EXPECT_EQ(105, stream_->GetPosition());
+  EXPECT_FALSE(eos);
+
+  EXPECT_CALL(container_mock(), Read(test_read_buffer_, 10, 105, _, nullptr))
+    .WillOnce(DoAll(SetArgPointee<3>(0), Return(true)));
+
+  EXPECT_TRUE(stream_->ReadNonBlocking(test_read_buffer_, 10, &read, &eos,
+                                       nullptr));
+  EXPECT_EQ(0, read);
+  EXPECT_EQ(105, stream_->GetPosition());
+  EXPECT_TRUE(eos);
+}
+
+TEST_F(MemoryStreamTest, WriteNonBlocking) {
+  size_t written = 0;
+
+  EXPECT_CALL(container_mock(), Write(test_write_buffer_, 10, 0, _, nullptr))
+    .WillOnce(DoAll(SetArgPointee<3>(5), Return(true)));
+
+  EXPECT_TRUE(stream_->WriteNonBlocking(test_write_buffer_, 10, &written,
+                                        nullptr));
+  EXPECT_EQ(5, written);
+  EXPECT_EQ(5, stream_->GetPosition());
+
+  EXPECT_CALL(container_mock(), Write(test_write_buffer_, 100, 5, _, nullptr))
+    .WillOnce(DoAll(SetArgPointee<3>(100), Return(true)));
+
+  EXPECT_TRUE(stream_->WriteNonBlocking(test_write_buffer_, 100, &written,
+                                        nullptr));
+  EXPECT_EQ(100, written);
+  EXPECT_EQ(105, stream_->GetPosition());
+
+  EXPECT_CALL(container_mock(), Write(test_write_buffer_, 10, 105, _, nullptr))
+    .WillOnce(DoAll(SetArgPointee<3>(10), Return(true)));
+
+  EXPECT_TRUE(stream_->WriteNonBlocking(test_write_buffer_, 10, &written,
+                                        nullptr));
+  EXPECT_EQ(115, stream_->GetPosition());
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Factory method tests.
+TEST(MemoryStream, OpenBinary) {
+  char buffer[] = {1, 2, 3};
+  StreamPtr stream = MemoryStream::OpenRef(buffer, sizeof(buffer), nullptr);
+  buffer[0] = 5;
+  EXPECT_EQ(3, stream->GetSize());
+  EXPECT_EQ(5, ReadByte(stream.get(), nullptr));
+  EXPECT_EQ(2, ReadByte(stream.get(), nullptr));
+  EXPECT_EQ(3, ReadByte(stream.get(), nullptr));
+  brillo::ErrorPtr error;
+  EXPECT_EQ(-1, ReadByte(stream.get(), &error));
+  EXPECT_EQ(errors::stream::kPartialData, error->GetCode());
+  EXPECT_EQ("Reading past the end of stream", error->GetMessage());
+}
+
+TEST(MemoryStream, OpenBinaryCopy) {
+  char buffer[] = {1, 2, 3};
+  StreamPtr stream = MemoryStream::OpenCopyOf(buffer, sizeof(buffer), nullptr);
+  buffer[0] = 5;
+  EXPECT_EQ(3, stream->GetSize());
+  EXPECT_EQ(1, ReadByte(stream.get(), nullptr));
+  EXPECT_EQ(2, ReadByte(stream.get(), nullptr));
+  EXPECT_EQ(3, ReadByte(stream.get(), nullptr));
+  brillo::ErrorPtr error;
+  EXPECT_EQ(-1, ReadByte(stream.get(), &error));
+  EXPECT_EQ(errors::stream::kPartialData, error->GetCode());
+  EXPECT_EQ("Reading past the end of stream", error->GetMessage());
+}
+
+TEST(MemoryStream, OpenString) {
+  std::string str("abcd");
+  StreamPtr stream = MemoryStream::OpenRef(str, nullptr);
+  str[0] = 'A';
+  EXPECT_EQ(4, stream->GetSize());
+  EXPECT_EQ('A', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('b', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('c', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('d', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ(-1, ReadByte(stream.get(), nullptr));
+}
+
+TEST(MemoryStream, OpenStringCopy) {
+  std::string str("abcd");
+  StreamPtr stream = MemoryStream::OpenCopyOf(str, nullptr);
+  str[0] = 'A';
+  EXPECT_EQ(4, stream->GetSize());
+  EXPECT_EQ('a', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('b', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('c', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('d', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ(-1, ReadByte(stream.get(), nullptr));
+}
+
+TEST(MemoryStream, OpenCharBuf) {
+  char str[] = "abcd";
+  StreamPtr stream = MemoryStream::OpenRef(str, nullptr);
+  str[0] = 'A';
+  EXPECT_EQ(4, stream->GetSize());
+  EXPECT_EQ('A', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('b', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('c', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('d', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ(-1, ReadByte(stream.get(), nullptr));
+}
+
+TEST(MemoryStream, OpenCharBufCopy) {
+  char str[] = "abcd";
+  StreamPtr stream = MemoryStream::OpenCopyOf(str, nullptr);
+  str[0] = 'A';
+  EXPECT_EQ(4, stream->GetSize());
+  EXPECT_EQ('a', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('b', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('c', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('d', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ(-1, ReadByte(stream.get(), nullptr));
+}
+
+TEST(MemoryStream, OpenVector) {
+  std::vector<char> data = {'a', 'b', 'c', 'd'};
+  StreamPtr stream = MemoryStream::OpenRef(data, nullptr);
+  data[0] = 'A';
+  EXPECT_EQ(4, stream->GetSize());
+  EXPECT_EQ(0, stream->GetPosition());
+  EXPECT_EQ(4, stream->GetRemainingSize());
+  EXPECT_EQ('A', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('b', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('c', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('d', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ(4, stream->GetPosition());
+  EXPECT_EQ(4, stream->GetSize());
+  EXPECT_EQ(0, stream->GetRemainingSize());
+}
+
+TEST(MemoryStream, OpenVectorCopy) {
+  std::vector<uint8_t> data = {'a', 'b', 'c', 'd'};
+  StreamPtr stream = MemoryStream::OpenCopyOf(data, nullptr);
+  data[0] = 'A';
+  EXPECT_EQ(4, stream->GetSize());
+  EXPECT_EQ(0, stream->GetPosition());
+  EXPECT_EQ(4, stream->GetRemainingSize());
+  EXPECT_EQ('a', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('b', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('c', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ('d', ReadByte(stream.get(), nullptr));
+  EXPECT_EQ(4, stream->GetPosition());
+  EXPECT_EQ(4, stream->GetSize());
+  EXPECT_EQ(0, stream->GetRemainingSize());
+}
+
+TEST(MemoryStream, CreateVector) {
+  std::vector<uint8_t> buffer;
+  StreamPtr stream = MemoryStream::CreateRef(&buffer, nullptr);
+  EXPECT_TRUE(buffer.empty());
+  EXPECT_EQ(0, stream->GetPosition());
+  EXPECT_EQ(0, stream->GetSize());
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+
+  buffer.resize(5);
+  std::iota(buffer.begin(), buffer.end(), 0);
+  stream = MemoryStream::CreateRef(&buffer, nullptr);
+  EXPECT_FALSE(buffer.empty());
+  EXPECT_EQ(0, stream->GetPosition());
+  EXPECT_EQ(5, stream->GetSize());
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+
+  stream = MemoryStream::CreateRefForAppend(&buffer, nullptr);
+  EXPECT_FALSE(buffer.empty());
+  EXPECT_EQ(5, stream->GetPosition());
+  EXPECT_EQ(5, stream->GetSize());
+  EXPECT_TRUE(stream->WriteAllBlocking("abcde", 5, nullptr));
+  EXPECT_FALSE(buffer.empty());
+  EXPECT_EQ(10, stream->GetPosition());
+  EXPECT_EQ(10, stream->GetSize());
+  EXPECT_TRUE(stream->SetPosition(0, nullptr));
+  EXPECT_EQ(0, stream->GetPosition());
+  EXPECT_EQ(10, stream->GetSize());
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+
+  EXPECT_EQ(10, buffer.size());
+  EXPECT_EQ((std::vector<uint8_t>{0, 1, 2, 3, 4, 'a', 'b', 'c', 'd', 'e'}),
+            buffer);
+
+  stream = MemoryStream::OpenRef(buffer, nullptr);
+  EXPECT_FALSE(buffer.empty());
+  EXPECT_EQ(0, stream->GetPosition());
+  EXPECT_EQ(10, stream->GetSize());
+}
+
+TEST(MemoryStream, CreateString) {
+  std::string buffer;
+  StreamPtr stream = MemoryStream::CreateRef(&buffer, nullptr);
+  EXPECT_TRUE(buffer.empty());
+  EXPECT_EQ(0, stream->GetPosition());
+  EXPECT_EQ(0, stream->GetSize());
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+
+  buffer = "abc";
+  stream = MemoryStream::CreateRef(&buffer, nullptr);
+  EXPECT_FALSE(buffer.empty());
+  EXPECT_EQ(0, stream->GetPosition());
+  EXPECT_EQ(3, stream->GetSize());
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+
+  stream = MemoryStream::CreateRefForAppend(&buffer, nullptr);
+  EXPECT_FALSE(buffer.empty());
+  EXPECT_EQ(3, stream->GetPosition());
+  EXPECT_EQ(3, stream->GetSize());
+  EXPECT_TRUE(stream->WriteAllBlocking("d_1234", 6, nullptr));
+  EXPECT_FALSE(buffer.empty());
+  EXPECT_EQ(9, stream->GetPosition());
+  EXPECT_EQ(9, stream->GetSize());
+  EXPECT_TRUE(stream->SetPosition(0, nullptr));
+  EXPECT_EQ(0, stream->GetPosition());
+  EXPECT_EQ(9, stream->GetSize());
+  EXPECT_TRUE(stream->CloseBlocking(nullptr));
+  EXPECT_EQ(9, buffer.size());
+  EXPECT_EQ("abcd_1234", buffer);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/mock_stream.h b/libbrillo/brillo/streams/mock_stream.h
new file mode 100644
index 0000000..934912a
--- /dev/null
+++ b/libbrillo/brillo/streams/mock_stream.h
@@ -0,0 +1,75 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_STREAMS_MOCK_STREAM_H_
+#define LIBBRILLO_BRILLO_STREAMS_MOCK_STREAM_H_
+
+#include <gmock/gmock.h>
+
+#include <brillo/streams/stream.h>
+
+namespace brillo {
+
+// Mock Stream implementation for testing.
+class MockStream : public Stream {
+ public:
+  MockStream() = default;
+
+  MOCK_CONST_METHOD0(IsOpen, bool());
+  MOCK_CONST_METHOD0(CanRead, bool());
+  MOCK_CONST_METHOD0(CanWrite, bool());
+  MOCK_CONST_METHOD0(CanSeek, bool());
+  MOCK_CONST_METHOD0(CanGetSize, bool());
+
+  MOCK_CONST_METHOD0(GetSize, uint64_t());
+  MOCK_METHOD2(SetSizeBlocking, bool(uint64_t, ErrorPtr*));
+  MOCK_CONST_METHOD0(GetRemainingSize, uint64_t());
+
+  MOCK_CONST_METHOD0(GetPosition, uint64_t());
+  MOCK_METHOD4(Seek, bool(int64_t, Whence, uint64_t*, ErrorPtr*));
+
+  MOCK_METHOD5(ReadAsync, bool(void*,
+                               size_t,
+                               const base::Callback<void(size_t)>&,
+                               const ErrorCallback&,
+                               ErrorPtr*));
+  MOCK_METHOD5(ReadAllAsync, bool(void*,
+                                  size_t,
+                                  const base::Closure&,
+                                  const ErrorCallback&,
+                                  ErrorPtr*));
+  MOCK_METHOD5(ReadNonBlocking, bool(void*, size_t, size_t*, bool*, ErrorPtr*));
+  MOCK_METHOD4(ReadBlocking, bool(void*, size_t, size_t*, ErrorPtr*));
+  MOCK_METHOD3(ReadAllBlocking, bool(void*, size_t, ErrorPtr*));
+
+  MOCK_METHOD5(WriteAsync, bool(const void*,
+                                size_t,
+                                const base::Callback<void(size_t)>&,
+                                const ErrorCallback&,
+                                ErrorPtr*));
+  MOCK_METHOD5(WriteAllAsync, bool(const void*,
+                                   size_t,
+                                   const base::Closure&,
+                                   const ErrorCallback&,
+                                   ErrorPtr*));
+  MOCK_METHOD4(WriteNonBlocking, bool(const void*, size_t, size_t*, ErrorPtr*));
+  MOCK_METHOD4(WriteBlocking, bool(const void*, size_t, size_t*, ErrorPtr*));
+  MOCK_METHOD3(WriteAllBlocking, bool(const void*, size_t, ErrorPtr*));
+
+  MOCK_METHOD1(FlushBlocking, bool(ErrorPtr*));
+  MOCK_METHOD1(CloseBlocking, bool(ErrorPtr*));
+
+  MOCK_METHOD3(WaitForData, bool(AccessMode,
+                                 const base::Callback<void(AccessMode)>&,
+                                 ErrorPtr*));
+  MOCK_METHOD4(WaitForDataBlocking,
+               bool(AccessMode, base::TimeDelta, AccessMode*, ErrorPtr*));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockStream);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_STREAMS_MOCK_STREAM_H_
diff --git a/libbrillo/brillo/streams/openssl_stream_bio.cc b/libbrillo/brillo/streams/openssl_stream_bio.cc
new file mode 100644
index 0000000..a63d9c0
--- /dev/null
+++ b/libbrillo/brillo/streams/openssl_stream_bio.cc
@@ -0,0 +1,101 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/openssl_stream_bio.h>
+
+#include <openssl/bio.h>
+
+#include <base/numerics/safe_conversions.h>
+#include <brillo/streams/stream.h>
+
+namespace brillo {
+
+namespace {
+
+// Internal functions for implementing OpenSSL BIO on brillo::Stream.
+int stream_write(BIO* bio, const char* buf, int size) {
+  brillo::Stream* stream = static_cast<brillo::Stream*>(bio->ptr);
+  size_t written = 0;
+  BIO_clear_retry_flags(bio);
+  if (!stream->WriteNonBlocking(buf, size, &written, nullptr))
+    return -1;
+
+  if (written == 0) {
+    // Socket's output buffer is full, try again later.
+    BIO_set_retry_write(bio);
+    return -1;
+  }
+  return base::checked_cast<int>(written);
+}
+
+int stream_read(BIO* bio, char* buf, int size) {
+  brillo::Stream* stream = static_cast<brillo::Stream*>(bio->ptr);
+  size_t read = 0;
+  BIO_clear_retry_flags(bio);
+  bool eos = false;
+  if (!stream->ReadNonBlocking(buf, size, &read, &eos, nullptr))
+    return -1;
+
+  if (read == 0 && !eos) {
+    // If no data is available on the socket and it is still not closed,
+    // ask OpenSSL to try again later.
+    BIO_set_retry_read(bio);
+    return -1;
+  }
+  return base::checked_cast<int>(read);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+long stream_ctrl(BIO* bio, int cmd, long /* num */, void* /* ptr */) {
+  if (cmd == BIO_CTRL_FLUSH) {
+    brillo::Stream* stream = static_cast<brillo::Stream*>(bio->ptr);
+    return stream->FlushBlocking(nullptr) ? 1 : 0;
+  }
+  return 0;
+}
+
+int stream_new(BIO* bio) {
+  bio->shutdown = 0;  // By default do not close underlying stream on shutdown.
+  bio->init = 0;
+  bio->num = -1;  // not used.
+  return 1;
+}
+
+int stream_free(BIO* bio) {
+  if (!bio)
+    return 0;
+
+  if (bio->init) {
+    bio->ptr = nullptr;
+    bio->init = 0;
+  }
+  return 1;
+}
+
+// BIO_METHOD structure describing the BIO built on top of brillo::Stream.
+BIO_METHOD stream_method = {
+    0x7F | BIO_TYPE_SOURCE_SINK,  // type: 0x7F is an arbitrary unused type ID.
+    "stream",      // name
+    stream_write,  // write function
+    stream_read,   // read function
+    nullptr,       // puts function, not implemented
+    nullptr,       // gets function, not implemented
+    stream_ctrl,   // control function
+    stream_new,    // creation
+    stream_free,   // free
+    nullptr,       // callback function, not used
+};
+
+}  // anonymous namespace
+
+BIO* BIO_new_stream(brillo::Stream* stream) {
+  BIO* bio = BIO_new(&stream_method);
+  if (bio) {
+    bio->ptr = stream;
+    bio->init = 1;
+  }
+  return bio;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/openssl_stream_bio.h b/libbrillo/brillo/streams/openssl_stream_bio.h
new file mode 100644
index 0000000..549c99c
--- /dev/null
+++ b/libbrillo/brillo/streams/openssl_stream_bio.h
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_STREAMS_OPENSSL_STREAM_BIO_H_
+#define LIBBRILLO_BRILLO_STREAMS_OPENSSL_STREAM_BIO_H_
+
+#include <brillo/brillo_export.h>
+
+// Forward-declare BIO as an alias to OpenSSL's internal bio_st structure.
+using BIO = struct bio_st;
+
+namespace brillo {
+
+class Stream;
+
+// Creates a new BIO that uses the brillo::Stream as the back-end storage.
+// The created BIO does *NOT* own the |stream| and the stream must out-live
+// the BIO.
+// At the moment, only BIO_read and BIO_write operations are supported as well
+// as BIO_flush. More functionality could be added to this when/if needed.
+// The returned BIO performs *NON-BLOCKING* IO on the underlying stream.
+BRILLO_EXPORT BIO* BIO_new_stream(brillo::Stream* stream);
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_STREAMS_OPENSSL_STREAM_BIO_H_
diff --git a/libbrillo/brillo/streams/openssl_stream_bio_unittests.cc b/libbrillo/brillo/streams/openssl_stream_bio_unittests.cc
new file mode 100644
index 0000000..a80710d
--- /dev/null
+++ b/libbrillo/brillo/streams/openssl_stream_bio_unittests.cc
@@ -0,0 +1,125 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/openssl_stream_bio.h>
+
+#include <memory>
+#include <openssl/bio.h>
+
+#include <brillo/streams/mock_stream.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::DoAll;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::StrictMock;
+using testing::_;
+
+namespace brillo {
+
+class StreamBIOTest : public testing::Test {
+ public:
+  void SetUp() override {
+    stream_.reset(new StrictMock<MockStream>{});
+    bio_ = BIO_new_stream(stream_.get());
+  }
+
+  void TearDown() override {
+    BIO_free(bio_);
+    bio_ = nullptr;
+    stream_.reset();
+  }
+
+  std::unique_ptr<StrictMock<MockStream>> stream_;
+  BIO* bio_{nullptr};
+};
+
+TEST_F(StreamBIOTest, ReadFull) {
+  char buffer[10];
+  EXPECT_CALL(*stream_, ReadNonBlocking(buffer, 10, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(10),
+                      SetArgPointee<3>(false),
+                      Return(true)));
+  EXPECT_EQ(10, BIO_read(bio_, buffer, sizeof(buffer)));
+}
+
+TEST_F(StreamBIOTest, ReadPartial) {
+  char buffer[10];
+  EXPECT_CALL(*stream_, ReadNonBlocking(buffer, 10, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(3),
+                      SetArgPointee<3>(false),
+                      Return(true)));
+  EXPECT_EQ(3, BIO_read(bio_, buffer, sizeof(buffer)));
+}
+
+TEST_F(StreamBIOTest, ReadWouldBlock) {
+  char buffer[10];
+  EXPECT_CALL(*stream_, ReadNonBlocking(buffer, 10, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(0),
+                      SetArgPointee<3>(false),
+                      Return(true)));
+  EXPECT_EQ(-1, BIO_read(bio_, buffer, sizeof(buffer)));
+  EXPECT_TRUE(BIO_should_retry(bio_));
+}
+
+TEST_F(StreamBIOTest, ReadEndOfStream) {
+  char buffer[10];
+  EXPECT_CALL(*stream_, ReadNonBlocking(buffer, 10, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(0),
+                      SetArgPointee<3>(true),
+                      Return(true)));
+  EXPECT_EQ(0, BIO_read(bio_, buffer, sizeof(buffer)));
+  EXPECT_FALSE(BIO_should_retry(bio_));
+}
+
+TEST_F(StreamBIOTest, ReadError) {
+  char buffer[10];
+  EXPECT_CALL(*stream_, ReadNonBlocking(buffer, 10, _, _, _))
+      .WillOnce(Return(false));
+  EXPECT_EQ(-1, BIO_read(bio_, buffer, sizeof(buffer)));
+  EXPECT_FALSE(BIO_should_retry(bio_));
+}
+
+TEST_F(StreamBIOTest, WriteFull) {
+  char buffer[10] = {};
+  EXPECT_CALL(*stream_, WriteNonBlocking(buffer, 10, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(10), Return(true)));
+  EXPECT_EQ(10, BIO_write(bio_, buffer, sizeof(buffer)));
+}
+
+TEST_F(StreamBIOTest, WritePartial) {
+  char buffer[10] = {};
+  EXPECT_CALL(*stream_, WriteNonBlocking(buffer, 10, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(3), Return(true)));
+  EXPECT_EQ(3, BIO_write(bio_, buffer, sizeof(buffer)));
+}
+
+TEST_F(StreamBIOTest, WriteWouldBlock) {
+  char buffer[10] = {};
+  EXPECT_CALL(*stream_, WriteNonBlocking(buffer, 10, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
+  EXPECT_EQ(-1, BIO_write(bio_, buffer, sizeof(buffer)));
+  EXPECT_TRUE(BIO_should_retry(bio_));
+}
+
+TEST_F(StreamBIOTest, WriteError) {
+  char buffer[10] = {};
+  EXPECT_CALL(*stream_, WriteNonBlocking(buffer, 10, _, _))
+      .WillOnce(Return(false));
+  EXPECT_EQ(-1, BIO_write(bio_, buffer, sizeof(buffer)));
+  EXPECT_FALSE(BIO_should_retry(bio_));
+}
+
+TEST_F(StreamBIOTest, FlushSuccess) {
+  EXPECT_CALL(*stream_, FlushBlocking(_)).WillOnce(Return(true));
+  EXPECT_EQ(1, BIO_flush(bio_));
+}
+
+TEST_F(StreamBIOTest, FlushError) {
+  EXPECT_CALL(*stream_, FlushBlocking(_)).WillOnce(Return(false));
+  EXPECT_EQ(0, BIO_flush(bio_));
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/stream.cc b/libbrillo/brillo/streams/stream.cc
new file mode 100644
index 0000000..6a40c00
--- /dev/null
+++ b/libbrillo/brillo/streams/stream.cc
@@ -0,0 +1,392 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/stream.h>
+
+#include <algorithm>
+
+#include <base/bind.h>
+#include <brillo/message_loops/message_loop.h>
+#include <brillo/pointer_utils.h>
+#include <brillo/streams/stream_errors.h>
+#include <brillo/streams/stream_utils.h>
+
+namespace brillo {
+
+bool Stream::TruncateBlocking(ErrorPtr* error) {
+  return SetSizeBlocking(GetPosition(), error);
+}
+
+bool Stream::SetPosition(uint64_t position, ErrorPtr* error) {
+  if (!stream_utils::CheckInt64Overflow(FROM_HERE, position, 0, error))
+    return false;
+  return Seek(position, Whence::FROM_BEGIN, nullptr, error);
+}
+
+bool Stream::ReadAsync(void* buffer,
+                       size_t size_to_read,
+                       const base::Callback<void(size_t)>& success_callback,
+                       const ErrorCallback& error_callback,
+                       ErrorPtr* error) {
+  if (is_async_read_pending_) {
+    Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
+                 errors::stream::kOperationNotSupported,
+                 "Another asynchronous operation is still pending");
+    return false;
+  }
+
+  auto callback = base::Bind(&Stream::IgnoreEOSCallback, success_callback);
+  // If we can read some data right away non-blocking we should still run the
+  // callback from the main loop, so we pass true here for force_async_callback.
+  return ReadAsyncImpl(buffer, size_to_read, callback, error_callback, error,
+                       true);
+}
+
+bool Stream::ReadAllAsync(void* buffer,
+                          size_t size_to_read,
+                          const base::Closure& success_callback,
+                          const ErrorCallback& error_callback,
+                          ErrorPtr* error) {
+  if (is_async_read_pending_) {
+    Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
+                 errors::stream::kOperationNotSupported,
+                 "Another asynchronous operation is still pending");
+    return false;
+  }
+
+  auto callback = base::Bind(&Stream::ReadAllAsyncCallback,
+                             weak_ptr_factory_.GetWeakPtr(), buffer,
+                             size_to_read, success_callback, error_callback);
+  return ReadAsyncImpl(buffer, size_to_read, callback, error_callback, error,
+                       true);
+}
+
+bool Stream::ReadBlocking(void* buffer,
+                          size_t size_to_read,
+                          size_t* size_read,
+                          ErrorPtr* error) {
+  for (;;) {
+    bool eos = false;
+    if (!ReadNonBlocking(buffer, size_to_read, size_read, &eos, error))
+      return false;
+
+    if (*size_read > 0 || eos)
+      break;
+
+    if (!WaitForDataBlocking(AccessMode::READ, base::TimeDelta::Max(), nullptr,
+                             error)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool Stream::ReadAllBlocking(void* buffer,
+                             size_t size_to_read,
+                             ErrorPtr* error) {
+  while (size_to_read > 0) {
+    size_t size_read = 0;
+    if (!ReadBlocking(buffer, size_to_read, &size_read, error))
+      return false;
+
+    if (size_read == 0)
+      return stream_utils::ErrorReadPastEndOfStream(FROM_HERE, error);
+
+    size_to_read -= size_read;
+    buffer = AdvancePointer(buffer, size_read);
+  }
+  return true;
+}
+
+bool Stream::WriteAsync(const void* buffer,
+                        size_t size_to_write,
+                        const base::Callback<void(size_t)>& success_callback,
+                        const ErrorCallback& error_callback,
+                        ErrorPtr* error) {
+  if (is_async_write_pending_) {
+    Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
+                 errors::stream::kOperationNotSupported,
+                 "Another asynchronous operation is still pending");
+    return false;
+  }
+  // If we can read some data right away non-blocking we should still run the
+  // callback from the main loop, so we pass true here for force_async_callback.
+  return WriteAsyncImpl(buffer, size_to_write, success_callback, error_callback,
+                        error, true);
+}
+
+bool Stream::WriteAllAsync(const void* buffer,
+                           size_t size_to_write,
+                           const base::Closure& success_callback,
+                           const ErrorCallback& error_callback,
+                           ErrorPtr* error) {
+  if (is_async_write_pending_) {
+    Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
+                 errors::stream::kOperationNotSupported,
+                 "Another asynchronous operation is still pending");
+    return false;
+  }
+
+  auto callback = base::Bind(&Stream::WriteAllAsyncCallback,
+                             weak_ptr_factory_.GetWeakPtr(), buffer,
+                             size_to_write, success_callback, error_callback);
+  return WriteAsyncImpl(buffer, size_to_write, callback, error_callback, error,
+                        true);
+}
+
+bool Stream::WriteBlocking(const void* buffer,
+                           size_t size_to_write,
+                           size_t* size_written,
+                           ErrorPtr* error) {
+  for (;;) {
+    if (!WriteNonBlocking(buffer, size_to_write, size_written, error))
+      return false;
+
+    if (*size_written > 0 || size_to_write == 0)
+      break;
+
+    if (!WaitForDataBlocking(AccessMode::WRITE, base::TimeDelta::Max(), nullptr,
+                             error)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool Stream::WriteAllBlocking(const void* buffer,
+                              size_t size_to_write,
+                              ErrorPtr* error) {
+  while (size_to_write > 0) {
+    size_t size_written = 0;
+    if (!WriteBlocking(buffer, size_to_write, &size_written, error))
+      return false;
+
+    if (size_written == 0) {
+      Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
+                   errors::stream::kPartialData,
+                   "Failed to write all the data");
+      return false;
+    }
+    size_to_write -= size_written;
+    buffer = AdvancePointer(buffer, size_written);
+  }
+  return true;
+}
+
+bool Stream::FlushAsync(const base::Closure& success_callback,
+                        const ErrorCallback& error_callback,
+                        ErrorPtr* /* error */) {
+  auto callback = base::Bind(&Stream::FlushAsyncCallback,
+                             weak_ptr_factory_.GetWeakPtr(),
+                             success_callback, error_callback);
+  MessageLoop::current()->PostTask(FROM_HERE, callback);
+  return true;
+}
+
+void Stream::IgnoreEOSCallback(
+    const base::Callback<void(size_t)>& success_callback,
+    size_t bytes,
+    bool /* eos */) {
+  success_callback.Run(bytes);
+}
+
+bool Stream::ReadAsyncImpl(
+    void* buffer,
+    size_t size_to_read,
+    const base::Callback<void(size_t, bool)>& success_callback,
+    const ErrorCallback& error_callback,
+    ErrorPtr* error,
+    bool force_async_callback) {
+  CHECK(!is_async_read_pending_);
+  // We set this value to true early in the function so calling others will
+  // prevent us from calling WaitForData() to make calls to
+  // ReadAsync() fail while we run WaitForData().
+  is_async_read_pending_ = true;
+
+  size_t read = 0;
+  bool eos = false;
+  if (!ReadNonBlocking(buffer, size_to_read, &read, &eos, error))
+    return false;
+
+  if (read > 0 || eos) {
+    if (force_async_callback) {
+      MessageLoop::current()->PostTask(
+          FROM_HERE,
+          base::Bind(&Stream::OnReadAsyncDone, weak_ptr_factory_.GetWeakPtr(),
+                     success_callback, read, eos));
+    } else {
+      is_async_read_pending_ = false;
+      success_callback.Run(read, eos);
+    }
+    return true;
+  }
+
+  is_async_read_pending_ = WaitForData(
+      AccessMode::READ,
+      base::Bind(&Stream::OnReadAvailable, weak_ptr_factory_.GetWeakPtr(),
+                 buffer, size_to_read, success_callback, error_callback),
+      error);
+  return is_async_read_pending_;
+}
+
+void Stream::OnReadAsyncDone(
+    const base::Callback<void(size_t, bool)>& success_callback,
+    size_t bytes_read,
+    bool eos) {
+  is_async_read_pending_ = false;
+  success_callback.Run(bytes_read, eos);
+}
+
+void Stream::OnReadAvailable(
+    void* buffer,
+    size_t size_to_read,
+    const base::Callback<void(size_t, bool)>& success_callback,
+    const ErrorCallback& error_callback,
+    AccessMode mode) {
+  CHECK(stream_utils::IsReadAccessMode(mode));
+  CHECK(is_async_read_pending_);
+  is_async_read_pending_ = false;
+  ErrorPtr error;
+  // Just reschedule the read operation but don't need to run the callback from
+  // the main loop since we are already running on a callback.
+  if (!ReadAsyncImpl(buffer, size_to_read, success_callback, error_callback,
+                     &error, false)) {
+    error_callback.Run(error.get());
+  }
+}
+
+bool Stream::WriteAsyncImpl(
+    const void* buffer,
+    size_t size_to_write,
+    const base::Callback<void(size_t)>& success_callback,
+    const ErrorCallback& error_callback,
+    ErrorPtr* error,
+    bool force_async_callback) {
+  CHECK(!is_async_write_pending_);
+  // We set this value to true early in the function so calling others will
+  // prevent us from calling WaitForData() to make calls to
+  // ReadAsync() fail while we run WaitForData().
+  is_async_write_pending_ = true;
+
+  size_t written = 0;
+  if (!WriteNonBlocking(buffer, size_to_write, &written, error))
+    return false;
+
+  if (written > 0) {
+    if (force_async_callback) {
+      MessageLoop::current()->PostTask(
+          FROM_HERE,
+          base::Bind(&Stream::OnWriteAsyncDone, weak_ptr_factory_.GetWeakPtr(),
+                     success_callback, written));
+    } else {
+      is_async_write_pending_ = false;
+      success_callback.Run(written);
+    }
+    return true;
+  }
+  is_async_write_pending_ = WaitForData(
+      AccessMode::WRITE,
+      base::Bind(&Stream::OnWriteAvailable, weak_ptr_factory_.GetWeakPtr(),
+                 buffer, size_to_write, success_callback, error_callback),
+      error);
+  return is_async_write_pending_;
+}
+
+void Stream::OnWriteAsyncDone(
+    const base::Callback<void(size_t)>& success_callback,
+    size_t size_written) {
+  is_async_write_pending_ = false;
+  success_callback.Run(size_written);
+}
+
+void Stream::OnWriteAvailable(
+    const void* buffer,
+    size_t size,
+    const base::Callback<void(size_t)>& success_callback,
+    const ErrorCallback& error_callback,
+    AccessMode mode) {
+  CHECK(stream_utils::IsWriteAccessMode(mode));
+  CHECK(is_async_write_pending_);
+  is_async_write_pending_ = false;
+  ErrorPtr error;
+  // Just reschedule the read operation but don't need to run the callback from
+  // the main loop since we are already running on a callback.
+  if (!WriteAsyncImpl(buffer, size, success_callback, error_callback, &error,
+                      false)) {
+    error_callback.Run(error.get());
+  }
+}
+
+void Stream::ReadAllAsyncCallback(void* buffer,
+                                  size_t size_to_read,
+                                  const base::Closure& success_callback,
+                                  const ErrorCallback& error_callback,
+                                  size_t size_read,
+                                  bool eos) {
+  ErrorPtr error;
+  size_to_read -= size_read;
+  if (size_to_read != 0 && eos) {
+    stream_utils::ErrorReadPastEndOfStream(FROM_HERE, &error);
+    error_callback.Run(error.get());
+    return;
+  }
+
+  if (size_to_read) {
+    buffer = AdvancePointer(buffer, size_read);
+    auto callback = base::Bind(&Stream::ReadAllAsyncCallback,
+                               weak_ptr_factory_.GetWeakPtr(), buffer,
+                               size_to_read, success_callback, error_callback);
+    if (!ReadAsyncImpl(buffer, size_to_read, callback, error_callback, &error,
+                       false)) {
+      error_callback.Run(error.get());
+    }
+  } else {
+    success_callback.Run();
+  }
+}
+
+void Stream::WriteAllAsyncCallback(const void* buffer,
+                                   size_t size_to_write,
+                                   const base::Closure& success_callback,
+                                   const ErrorCallback& error_callback,
+                                   size_t size_written) {
+  ErrorPtr error;
+  if (size_to_write != 0 && size_written == 0) {
+    Error::AddTo(&error, FROM_HERE, errors::stream::kDomain,
+                 errors::stream::kPartialData, "Failed to write all the data");
+    error_callback.Run(error.get());
+    return;
+  }
+  size_to_write -= size_written;
+  if (size_to_write) {
+    buffer = AdvancePointer(buffer, size_written);
+    auto callback = base::Bind(&Stream::WriteAllAsyncCallback,
+                               weak_ptr_factory_.GetWeakPtr(), buffer,
+                               size_to_write, success_callback, error_callback);
+    if (!WriteAsyncImpl(buffer, size_to_write, callback, error_callback, &error,
+                        false)) {
+      error_callback.Run(error.get());
+    }
+  } else {
+    success_callback.Run();
+  }
+}
+
+void Stream::FlushAsyncCallback(const base::Closure& success_callback,
+                                const ErrorCallback& error_callback) {
+  ErrorPtr error;
+  if (FlushBlocking(&error)) {
+    success_callback.Run();
+  } else {
+    error_callback.Run(error.get());
+  }
+}
+
+void Stream::CancelPendingAsyncOperations() {
+  weak_ptr_factory_.InvalidateWeakPtrs();
+  is_async_read_pending_ = false;
+  is_async_write_pending_ = false;
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/stream.h b/libbrillo/brillo/streams/stream.h
new file mode 100644
index 0000000..d7c58db
--- /dev/null
+++ b/libbrillo/brillo/streams/stream.h
@@ -0,0 +1,506 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_STREAMS_STREAM_H_
+#define LIBBRILLO_BRILLO_STREAMS_STREAM_H_
+
+#include <cstdint>
+#include <memory>
+
+#include <base/callback.h>
+#include <base/macros.h>
+#include <base/memory/weak_ptr.h>
+#include <base/time/time.h>
+#include <brillo/brillo_export.h>
+#include <brillo/errors/error.h>
+
+namespace brillo {
+
+// Stream is a base class that specific stream storage implementations must
+// derive from to provide I/O facilities.
+// The stream class provides general streaming I/O primitives to read, write and
+// seek within a stream. It has methods for asynchronous (callback-based) as
+// well as synchronous (both blocking and non-blocking) operations.
+// The Stream class is abstract and cannot be created by itself.
+// In order to construct a stream, you must use one of the derived classes'
+// factory methods which return a stream smart pointer (StreamPtr):
+//
+//    StreamPtr input_stream = FileStream::Open(path, AccessMode::READ);
+//    StreamPtr output_stream = MemoryStream::Create();
+//    uint8_t buf[1000];
+//    size_t read = 0;
+//    while (input_stream->ReadBlocking(buf, sizeof(buf), &read, nullptr)) {
+//      if (read == 0) break;
+//      output_stream->WriteAllBlocking(buf, read, nullptr);
+//    }
+//
+// NOTE ABOUT ASYNCHRONOUS OPERATIONS: Asynchronous I/O relies on a MessageLoop
+// instance to be present on the current thread. Using Stream::ReadAsync(),
+// Stream::WriteAsync() and similar will call MessageLoop::current() to access
+// the current message loop and abort if there isn't one for the current thread.
+// Also, only one outstanding asynchronous operation of particular kind (reading
+// or writing) at a time is supported. Trying to call ReadAsync() while another
+// asynchronous read operation is pending will fail with an error
+// ("operation_not_supported").
+//
+// NOTE ABOUT READING FROM/WRITING TO STREAMS: In many cases underlying streams
+// use buffered I/O. Using all read/write methods other than ReadAllAsync(),
+// ReadAllBlocking(), WriteAllAsync(), WriteAllBlocking() will return
+// immediately if there is any data available in the underlying buffer. That is,
+// trying to read 1000 bytes while the internal buffer contains only 100 will
+// return immediately with just those 100 bytes and no blocking or other I/O
+// traffic will be incurred. This guarantee is important for efficient and
+// correct implementation of duplex communication over pipes and sockets.
+//
+// NOTE TO IMPLEMENTERS: When creating new stream types, you must derive
+// from this class and provide the implementation for its pure virtual methods.
+// For operations that do not apply to your stream, make sure the corresponding
+// methods return "false" and set the error to "operation_not_supported".
+// You should use stream_utils::ErrorOperationNotSupported() for this. Also
+// Make sure the stream capabilities functions like CanRead(), etc return
+// correct values:
+//
+//    bool MyReadOnlyStream::CanRead() const { return true; }
+//    bool MyReadOnlyStream::CanWrite() const { return false; }
+//    bool MyReadOnlyStream::WriteBlocking(const void* buffer,
+//                                         size_t size_to_write,
+//                                         size_t* size_written,
+//                                         ErrorPtr* error) {
+//      return stream_utils::ErrorOperationNotSupported(error);
+//    }
+//
+// The class should also provide a static factory methods to create/open
+// a new stream:
+//
+//    static StreamPtr MyReadOnlyStream::Open(..., ErrorPtr* error) {
+//      auto my_stream = std::make_unique<MyReadOnlyStream>(...);
+//      if (!my_stream->Initialize(..., error))
+//        my_stream.reset();
+//      }
+//      return my_stream;
+//    }
+//
+class BRILLO_EXPORT Stream {
+ public:
+  // When seeking in streams, whence specifies the origin of the seek operation.
+  enum class Whence { FROM_BEGIN, FROM_CURRENT, FROM_END };
+  // Stream access mode for open operations (used in derived classes).
+  enum class AccessMode { READ, WRITE, READ_WRITE };
+
+  // Standard error callback for asynchronous operations.
+  using ErrorCallback = base::Callback<void(const Error*)>;
+
+  virtual ~Stream() = default;
+
+  // == Stream capabilities ===================================================
+
+  // Returns true while stream is open. Closing the last reference to the stream
+  // will make this method return false.
+  virtual bool IsOpen() const = 0;
+
+  // Called to determine if read operations are supported on the stream (stream
+  // is readable). This method does not check if there is actually any data to
+  // read, only the fact that the stream is open in read mode and can be read
+  // from in general.
+  // If CanRead() returns false, it is guaranteed that the stream can't be
+  // read from. However, if it returns true, there is no guarantee that the
+  // subsequent read operation will actually succeed (for example, the stream
+  // position could be at the end of the data stream, or the access mode of
+  // the stream is unknown beforehand).
+  virtual bool CanRead() const = 0;
+
+  // Called to determine if write operations are supported on the stream (stream
+  // is writable).
+  // If CanWrite() returns false, it is guaranteed that the stream can't be
+  // written to. However, if it returns true, the subsequent write operation
+  // is not guaranteed to succeed (e.g. the output media could be out of free
+  // space or a transport error could occur).
+  virtual bool CanWrite() const = 0;
+
+  // Called to determine if random access I/O operations are supported on
+  // the stream. Sequential streams should return false.
+  // If CanSeek() returns false, it is guaranteed that the stream can't use
+  // Seek(). However, if it returns true, it might be possible to seek, but this
+  // is not guaranteed since the actual underlying stream capabilities might
+  // not be known.
+  // Note that non-seekable streams might still maintain the current stream
+  // position and GetPosition method might still be used even if CanSeek()
+  // returns false. However SetPosition() will almost always fail in such
+  // a case.
+  virtual bool CanSeek() const = 0;
+
+  // Called to determine if the size of the stream is known. Size of some
+  // sequential streams (e.g. based on pipes) is unknown beforehand, so this
+  // method can be used to check how reliable a call to GetSize() is.
+  virtual bool CanGetSize() const = 0;
+
+  // == Stream size operations ================================================
+
+  // Returns the size of stream data.
+  // If the stream size is unavailable/unknown, it returns 0.
+  virtual uint64_t GetSize() const = 0;
+
+  // Resizes the stream storage to |size|. Stream must be writable and support
+  // this operation.
+  virtual bool SetSizeBlocking(uint64_t size, ErrorPtr* error) = 0;
+
+  // Truncates the stream at the current stream pointer.
+  // Calls SetSizeBlocking(GetPosition(), ...).
+  bool TruncateBlocking(ErrorPtr* error);
+
+  // Returns the amount of data remaining in the stream. If the size of the
+  // stream is unknown, or if the stream pointer is at or past the end of the
+  // stream, the function returns 0.
+  virtual uint64_t GetRemainingSize() const = 0;
+
+  // == Seek operations =======================================================
+
+  // Gets the position of the stream I/O pointer from the beginning of the
+  // stream. If the stream position is unavailable/unknown, it returns 0.
+  virtual uint64_t GetPosition() const = 0;
+
+  // Moves the stream pointer to the specified position, relative to the
+  // beginning of the stream. This calls Seek(position, Whence::FROM_BEGIN),
+  // however it also provides proper |position| validation to ensure that
+  // it doesn't overflow the range of signed int64_t used by Seek.
+  bool SetPosition(uint64_t position, ErrorPtr* error);
+
+  // Moves the stream pointer by |offset| bytes relative to |whence|.
+  // When successful, returns true and sets the new pointer position from the
+  // beginning of the stream to |new_position|. If |new_position| is nullptr,
+  // new stream position is not returned.
+  // On error, returns false and specifies additional details in |error| if it
+  // is not nullptr.
+  virtual bool Seek(int64_t offset,
+                    Whence whence,
+                    uint64_t* new_position,
+                    ErrorPtr* error) = 0;
+
+  // == Read operations =======================================================
+
+  // -- Asynchronous ----------------------------------------------------------
+
+  // Reads up to |size_to_read| bytes from the stream asynchronously. It is not
+  // guaranteed that all requested data will be read. It is not an error for
+  // this function to read fewer bytes than requested. If the function reads
+  // zero bytes, it means that the end of stream is reached.
+  // Upon successful read, the |success_callback| will be invoked with the
+  // actual number of bytes read.
+  // If an error occurs during the asynchronous operation, the |error_callback|
+  // is invoked with the error details. The error object pointer passed in as a
+  // parameter to the |error_callback| is valid only for the duration of that
+  // callback.
+  // If this function successfully schedules an asynchronous operation, it
+  // returns true. If it fails immediately, it will return false and set the
+  // error details to |error| object and will not call the success or error
+  // callbacks.
+  // The |buffer| must be at least |size_to_read| in size and must remain
+  // valid for the duration of the asynchronous operation (until either
+  // |success_callback| or |error_callback| is called).
+  // Only one asynchronous operation at a time is allowed on the stream (read
+  // and/or write)
+  // Uses ReadNonBlocking() and MonitorDataAvailable().
+  virtual bool ReadAsync(void* buffer,
+                         size_t size_to_read,
+                         const base::Callback<void(size_t)>& success_callback,
+                         const ErrorCallback& error_callback,
+                         ErrorPtr* error);
+
+  // Similar to ReadAsync() operation above but reads exactly |size_to_read|
+  // bytes from the stream into the |buffer|. Attempt to read past the end of
+  // the stream is considered an error in this case and will trigger the
+  // |error_callback|. The rest of restrictions and conditions of ReadAsync()
+  // method applies to ReadAllAsync() as well.
+  // Uses ReadNonBlocking() and MonitorDataAvailable().
+  virtual bool ReadAllAsync(void* buffer,
+                            size_t size_to_read,
+                            const base::Closure& success_callback,
+                            const ErrorCallback& error_callback,
+                            ErrorPtr* error);
+
+  // -- Synchronous non-blocking ----------------------------------------------
+
+  // Reads up to |size_to_read| bytes from the stream without blocking.
+  // The |buffer| must be at least |size_to_read| in size. It is not an error
+  // for this function to return without reading all (or any) the data.
+  // The actual amount of data read (which could be 0 bytes) is returned in
+  // |size_read|.
+  // On error, the function returns false and specifies additional error details
+  // in |error|.
+  // If end of stream is reached or if no data is currently available to be read
+  // without blocking, |size_read| will contain 0 and the function will still
+  // return true (success). In case of end-of-stream scenario, |end_of_stream|
+  // will also be set to true to indicate that no more data is available.
+  virtual bool ReadNonBlocking(void* buffer,
+                               size_t size_to_read,
+                               size_t* size_read,
+                               bool* end_of_stream,
+                               ErrorPtr* error) = 0;
+
+  // -- Synchronous blocking --------------------------------------------------
+
+  // Reads up to |size_to_read| bytes from the stream. This function will block
+  // until at least one byte is read or the end of stream is reached or until
+  // the stream is closed.
+  // The |buffer| must be at least |size_to_read| in size. It is not an error
+  // for this function to return without reading all the data. The actual amount
+  // of data read (which could be 0 bytes) is returned in |size_read|.
+  // On error, the function returns false and specifies additional error details
+  // in |error|. In this case, the state of the stream pointer is undefined,
+  // since some bytes might have been read successfully (and the pointer moved)
+  // before the error has occurred and |size_read| is not updated.
+  // If end of stream is reached, |size_read| will contain 0 and the function
+  // will still return true (success).
+  virtual bool ReadBlocking(void* buffer,
+                            size_t size_to_read,
+                            size_t* size_read,
+                            ErrorPtr* error);
+
+  // Reads exactly |size_to_read| bytes to |buffer|. Returns false on error
+  // (reading fewer than requested bytes is treated as an error as well).
+  // Calls ReadAllBlocking() repeatedly until all the data is read.
+  virtual bool ReadAllBlocking(void* buffer,
+                               size_t size_to_read,
+                               ErrorPtr* error);
+
+  // == Write operations ======================================================
+
+  // -- Asynchronous ----------------------------------------------------------
+
+  // Writes up to |size_to_write| bytes from |buffer| to the stream
+  // asynchronously. It is not guaranteed that all requested data will be
+  // written. It is not an error for this function to write fewer bytes than
+  // requested.
+  // Upon successful write, the |success_callback| will be invoked with the
+  // actual number of bytes written.
+  // If an error occurs during the asynchronous operation, the |error_callback|
+  // is invoked with the error details. The error object pointer is valid only
+  // for the duration of the error callback.
+  // If this function successfully schedules an asynchronous operation, it
+  // returns true. If it fails immediately, it will return false and set the
+  // error details to |error| object and will not call the success or error
+  // callbacks.
+  // The |buffer| must be at least |size_to_write| in size and must remain
+  // valid for the duration of the asynchronous operation (until either
+  // |success_callback| or |error_callback| is called).
+  // Only one asynchronous operation at a time is allowed on the stream (read
+  // and/or write).
+  // Uses WriteNonBlocking() and MonitorDataAvailable().
+  virtual bool WriteAsync(const void* buffer,
+                          size_t size_to_write,
+                          const base::Callback<void(size_t)>& success_callback,
+                          const ErrorCallback& error_callback,
+                          ErrorPtr* error);
+
+  // Similar to WriteAsync() operation above but writes exactly |size_to_write|
+  // bytes from |buffet| to the stream. When all the data is written
+  // successfully, the |success_callback| is invoked.
+  // The rest of restrictions and conditions of WriteAsync() method applies to
+  // WriteAllAsync() as well.
+  // Uses WriteNonBlocking() and MonitorDataAvailable().
+  virtual bool WriteAllAsync(const void* buffer,
+                             size_t size_to_write,
+                             const base::Closure& success_callback,
+                             const ErrorCallback& error_callback,
+                             ErrorPtr* error);
+
+  // -- Synchronous non-blocking ----------------------------------------------
+
+  // Writes up to |size_to_write| bytes to the stream. The |buffer| must be at
+  // least |size_to_write| in size. It is not an error for this function to
+  // return without writing all the data requested (or any data at all).
+  // The actual amount of data written is returned in |size_written|.
+  // On error, the function returns false and specifies additional error details
+  // in |error|.
+  virtual bool WriteNonBlocking(const void* buffer,
+                                size_t size_to_write,
+                                size_t* size_written,
+                                ErrorPtr* error) = 0;
+
+  // -- Synchronous blocking --------------------------------------------------
+
+  // Writes up to |size_to_write| bytes to the stream. The |buffer| must be at
+  // least |size_to_write| in size. It is not an error for this function to
+  // return without writing all the data requested. The actual amount of data
+  // written is returned in |size_written|.
+  // On error, the function returns false and specifies additional error details
+  // in |error|.
+  virtual bool WriteBlocking(const void* buffer,
+                             size_t size_to_write,
+                             size_t* size_written,
+                             ErrorPtr* error);
+
+  // Writes exactly |size_to_write| bytes to |buffer|. Returns false on error
+  // (writing fewer than requested bytes is treated as an error as well).
+  // Calls WriteBlocking() repeatedly until all the data is written.
+  virtual bool WriteAllBlocking(const void* buffer,
+                                size_t size_to_write,
+                                ErrorPtr* error);
+
+  // == Finalizing/closing streams  ===========================================
+
+  // Flushes all the user-space data from cache output buffers to storage
+  // medium. For read-only streams this is a no-op, however it is still valid
+  // to call this method on read-only streams.
+  // If an error occurs, the function returns false and specifies additional
+  // error details in |error|.
+  virtual bool FlushBlocking(ErrorPtr* error) = 0;
+
+  // Flushes all the user-space data from the cache output buffer
+  // asynchronously. When all the data is successfully flushed, the
+  // |success_callback| is invoked. If an error occurs while flushing, partial
+  // data might be flushed and |error_callback| is invoked. If there's an error
+  // scheduling the flush operation, it returns false and neither callback will
+  // be called.
+  virtual bool FlushAsync(const base::Closure& success_callback,
+                          const ErrorCallback& error_callback,
+                          ErrorPtr* error);
+
+  // Closes the underlying stream. The stream is also automatically closed
+  // when the stream object is destroyed, but since closing a stream is
+  // an operation that may fail, in situations when it is important to detect
+  // the failure to close the stream, CloseBlocking() should be used explicitly
+  // before destroying the stream object.
+  virtual bool CloseBlocking(ErrorPtr* error) = 0;
+
+  // == Data availability monitoring ==========================================
+
+  // Overloaded by derived classes to provide stream monitoring for read/write
+  // data availability for the stream. Calls |callback| when data can be read
+  // and/or written without blocking.
+  // |mode| specifies the type of operation to monitor for (read, write, both).
+  virtual bool WaitForData(AccessMode mode,
+                           const base::Callback<void(AccessMode)>& callback,
+                           ErrorPtr* error) = 0;
+
+  // Helper function for implementing blocking I/O. Blocks until the
+  // non-blocking operation specified by |in_mode| can be performed.
+  // If |out_mode| is not nullptr, it receives the actual operation that can be
+  // performed. For example, watching a stream for READ_WRITE while only
+  // READ can be performed, |out_mode| would contain READ even though |in_mode|
+  // was set to READ_WRITE.
+  // |timeout| is the maximum amount of time to wait. Set it to TimeDelta::Max()
+  // to wait indefinitely.
+  virtual bool WaitForDataBlocking(AccessMode in_mode,
+                                   base::TimeDelta timeout,
+                                   AccessMode* out_mode,
+                                   ErrorPtr* error) = 0;
+
+  // Cancels pending asynchronous read/write operations.
+  virtual void CancelPendingAsyncOperations();
+
+ protected:
+  Stream() = default;
+
+ private:
+  // Simple wrapper to call the externally exposed |success_callback| that only
+  // receives a size_t.
+  BRILLO_PRIVATE static void IgnoreEOSCallback(
+      const base::Callback<void(size_t)>& success_callback,
+      size_t read,
+      bool eos);
+
+  // The internal implementation of ReadAsync() and ReadAllAsync().
+  // Calls ReadNonBlocking and if there's no data available waits for it calling
+  // WaitForData(). The extra |force_async_callback| tell whether the success
+  // callback should be called from the main loop instead of directly from this
+  // method. This method only calls WaitForData() if ReadNonBlocking() returns a
+  // situation in which it would block (bytes_read = 0 and eos = false),
+  // preventing us from calling WaitForData() on streams that don't support such
+  // feature.
+  BRILLO_PRIVATE bool ReadAsyncImpl(
+      void* buffer,
+      size_t size_to_read,
+      const base::Callback<void(size_t, bool)>& success_callback,
+      const ErrorCallback& error_callback,
+      ErrorPtr* error,
+      bool force_async_callback);
+
+  // Called from the main loop when the ReadAsyncImpl finished right away
+  // without waiting for data. We use this callback to call the
+  // |sucess_callback| but invalidate the callback if the Stream is destroyed
+  // while this call is waiting in the main loop.
+  BRILLO_PRIVATE void OnReadAsyncDone(
+      const base::Callback<void(size_t, bool)>& success_callback,
+      size_t bytes_read,
+      bool eos);
+
+  // Called from WaitForData() when read operations can be performed
+  // without blocking (the type of operation is provided in |mode|).
+  BRILLO_PRIVATE void OnReadAvailable(
+      void* buffer,
+      size_t size_to_read,
+      const base::Callback<void(size_t, bool)>& success_callback,
+      const ErrorCallback& error_callback,
+      AccessMode mode);
+
+  // The internal implementation of WriteAsync() and WriteAllAsync().
+  // Calls WriteNonBlocking and if the write would block for it to not block
+  // calling WaitForData(). The extra |force_async_callback| tell whether the
+  // success callback should be called from the main loop instead of directly
+  // from this method. This method only calls WaitForData() if
+  // WriteNonBlocking() returns a situation in which it would block
+  // (size_written = 0 and eos = false), preventing us from calling
+  // WaitForData() on streams that don't support such feature.
+  BRILLO_PRIVATE bool WriteAsyncImpl(
+      const void* buffer,
+      size_t size_to_write,
+      const base::Callback<void(size_t)>& success_callback,
+      const ErrorCallback& error_callback,
+      ErrorPtr* error,
+      bool force_async_callback);
+
+  // Called from the main loop when the WriteAsyncImpl finished right away
+  // without waiting for data. We use this callback to call the
+  // |sucess_callback| but invalidate the callback if the Stream is destroyed
+  // while this call is waiting in the main loop.
+  BRILLO_PRIVATE void OnWriteAsyncDone(
+      const base::Callback<void(size_t)>& success_callback,
+      size_t size_written);
+
+  // Called from WaitForData() when write operations can be performed
+  // without blocking (the type of operation is provided in |mode|).
+  BRILLO_PRIVATE void OnWriteAvailable(
+      const void* buffer,
+      size_t size,
+      const base::Callback<void(size_t)>& success_callback,
+      const ErrorCallback& error_callback,
+      AccessMode mode);
+
+  // Helper callbacks to implement ReadAllAsync/WriteAllAsync.
+  BRILLO_PRIVATE void ReadAllAsyncCallback(
+      void* buffer,
+      size_t size_to_read,
+      const base::Closure& success_callback,
+      const ErrorCallback& error_callback,
+      size_t size_read,
+      bool eos);
+  BRILLO_PRIVATE void WriteAllAsyncCallback(
+      const void* buffer,
+      size_t size_to_write,
+      const base::Closure& success_callback,
+      const ErrorCallback& error_callback,
+      size_t size_written);
+
+  // Helper callbacks to implement FlushAsync().
+  BRILLO_PRIVATE void FlushAsyncCallback(
+      const base::Closure& success_callback,
+      const ErrorCallback& error_callback);
+
+  // Data members for asynchronous read operations.
+  bool is_async_read_pending_{false};
+
+  // Data members for asynchronous write operations.
+  bool is_async_write_pending_{false};
+
+  base::WeakPtrFactory<Stream> weak_ptr_factory_{this};
+  DISALLOW_COPY_AND_ASSIGN(Stream);
+};
+
+// A smart pointer to the stream used to pass the stream object around.
+using StreamPtr = std::unique_ptr<Stream>;
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_STREAMS_STREAM_H_
diff --git a/libbrillo/brillo/streams/stream_errors.cc b/libbrillo/brillo/streams/stream_errors.cc
new file mode 100644
index 0000000..e7c3dcd
--- /dev/null
+++ b/libbrillo/brillo/streams/stream_errors.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/stream_errors.h>
+
+namespace brillo {
+namespace errors {
+namespace stream {
+
+const char kDomain[] = "stream.io";
+
+const char kStreamClosed[] = "stream_closed";
+const char kOperationNotSupported[] = "operation_not_supported";
+const char kPartialData[] = "partial_data";
+const char kInvalidParameter[] = "invalid_parameter";
+const char kTimeout[] = "time_out";
+
+}  // namespace stream
+}  // namespace errors
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/stream_errors.h b/libbrillo/brillo/streams/stream_errors.h
new file mode 100644
index 0000000..1eacc5e
--- /dev/null
+++ b/libbrillo/brillo/streams/stream_errors.h
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_STREAMS_STREAM_ERRORS_H_
+#define LIBBRILLO_BRILLO_STREAMS_STREAM_ERRORS_H_
+
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+namespace errors {
+namespace stream {
+
+// Error domain for generic stream-based errors.
+BRILLO_EXPORT extern const char kDomain[];
+
+BRILLO_EXPORT extern const char kStreamClosed[];
+BRILLO_EXPORT extern const char kOperationNotSupported[];
+BRILLO_EXPORT extern const char kPartialData[];
+BRILLO_EXPORT extern const char kInvalidParameter[];
+BRILLO_EXPORT extern const char kTimeout[];
+
+}  // namespace stream
+}  // namespace errors
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_STREAMS_STREAM_ERRORS_H_
diff --git a/libbrillo/brillo/streams/stream_unittest.cc b/libbrillo/brillo/streams/stream_unittest.cc
new file mode 100644
index 0000000..625b569
--- /dev/null
+++ b/libbrillo/brillo/streams/stream_unittest.cc
@@ -0,0 +1,523 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/stream.h>
+
+#include <limits>
+
+#include <base/callback.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <brillo/bind_lambda.h>
+#include <brillo/message_loops/fake_message_loop.h>
+#include <brillo/streams/stream_errors.h>
+
+using testing::DoAll;
+using testing::InSequence;
+using testing::Return;
+using testing::SaveArg;
+using testing::SetArgPointee;
+using testing::_;
+
+namespace brillo {
+
+using AccessMode = Stream::AccessMode;
+using Whence = Stream::Whence;
+
+// To verify "non-trivial" methods implemented in Stream, mock out the
+// "trivial" methods to make sure the ones we are interested in testing
+// actually end up calling the expected methods with right parameters.
+class MockStreamImpl : public Stream {
+ public:
+  MockStreamImpl() = default;
+
+  MOCK_CONST_METHOD0(IsOpen, bool());
+  MOCK_CONST_METHOD0(CanRead, bool());
+  MOCK_CONST_METHOD0(CanWrite, bool());
+  MOCK_CONST_METHOD0(CanSeek, bool());
+  MOCK_CONST_METHOD0(CanGetSize, bool());
+
+  MOCK_CONST_METHOD0(GetSize, uint64_t());
+  MOCK_METHOD2(SetSizeBlocking, bool(uint64_t, ErrorPtr*));
+  MOCK_CONST_METHOD0(GetRemainingSize, uint64_t());
+
+  MOCK_CONST_METHOD0(GetPosition, uint64_t());
+  MOCK_METHOD4(Seek, bool(int64_t, Whence, uint64_t*, ErrorPtr*));
+
+  // Omitted: ReadAsync
+  // Omitted: ReadAllAsync
+  MOCK_METHOD5(ReadNonBlocking, bool(void*, size_t, size_t*, bool*, ErrorPtr*));
+  // Omitted: ReadBlocking
+  // Omitted: ReadAllBlocking
+
+  // Omitted: WriteAsync
+  // Omitted: WriteAllAsync
+  MOCK_METHOD4(WriteNonBlocking, bool(const void*, size_t, size_t*, ErrorPtr*));
+  // Omitted: WriteBlocking
+  // Omitted: WriteAllBlocking
+
+  MOCK_METHOD1(FlushBlocking, bool(ErrorPtr*));
+  MOCK_METHOD1(CloseBlocking, bool(ErrorPtr*));
+
+  MOCK_METHOD3(WaitForData, bool(AccessMode,
+                                 const base::Callback<void(AccessMode)>&,
+                                 ErrorPtr*));
+  MOCK_METHOD4(WaitForDataBlocking,
+               bool(AccessMode, base::TimeDelta, AccessMode*, ErrorPtr*));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockStreamImpl);
+};
+
+TEST(Stream, TruncateBlocking) {
+  MockStreamImpl stream_mock;
+  EXPECT_CALL(stream_mock, GetPosition()).WillOnce(Return(123));
+  EXPECT_CALL(stream_mock, SetSizeBlocking(123, _)).WillOnce(Return(true));
+  EXPECT_TRUE(stream_mock.TruncateBlocking(nullptr));
+}
+
+TEST(Stream, SetPosition) {
+  MockStreamImpl stream_mock;
+  EXPECT_CALL(stream_mock, Seek(12345, Whence::FROM_BEGIN, _, _))
+      .WillOnce(Return(true));
+  EXPECT_TRUE(stream_mock.SetPosition(12345, nullptr));
+
+  // Test too large an offset (that doesn't fit in signed 64 bit value).
+  ErrorPtr error;
+  uint64_t max_offset = std::numeric_limits<int64_t>::max();
+  EXPECT_CALL(stream_mock, Seek(max_offset, _, _, _))
+      .WillOnce(Return(true));
+  EXPECT_TRUE(stream_mock.SetPosition(max_offset, nullptr));
+
+  EXPECT_FALSE(stream_mock.SetPosition(max_offset + 1, &error));
+  EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+  EXPECT_EQ(errors::stream::kInvalidParameter, error->GetCode());
+}
+
+TEST(Stream, ReadAsync) {
+  size_t read_size = 0;
+  bool succeeded = false;
+  bool failed = false;
+  auto success_callback = [](size_t* read_size, bool* succeeded,size_t size) {
+    *read_size = size;
+    *succeeded = true;
+  };
+  auto error_callback = [](bool* failed, const Error* /* error */) {
+    *failed = true;
+  };
+
+  MockStreamImpl stream_mock;
+  base::Callback<void(AccessMode)> data_callback;
+  char buf[10];
+
+  // This sets up an initial non blocking read that would block, so ReadAsync()
+  // should wait for more data.
+  EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
+      .WillOnce(
+          DoAll(SetArgPointee<2>(0), SetArgPointee<3>(false), Return(true)));
+  EXPECT_CALL(stream_mock, WaitForData(AccessMode::READ, _, _))
+      .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
+  EXPECT_TRUE(stream_mock.ReadAsync(
+      buf,
+      sizeof(buf),
+      base::Bind(success_callback,
+                 base::Unretained(&read_size),
+                 base::Unretained(&succeeded)),
+      base::Bind(error_callback, base::Unretained(&failed)),
+      nullptr));
+  EXPECT_EQ(0u, read_size);
+  EXPECT_FALSE(succeeded);
+  EXPECT_FALSE(failed);
+
+  // Since the previous call is waiting for the data to be available, we can't
+  // schedule another read.
+  ErrorPtr error;
+  EXPECT_FALSE(stream_mock.ReadAsync(
+      buf,
+      sizeof(buf),
+      base::Bind(success_callback,
+                 base::Unretained(&read_size),
+                 base::Unretained(&succeeded)),
+      base::Bind(error_callback, base::Unretained(&failed)),
+      &error));
+  EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+  EXPECT_EQ(errors::stream::kOperationNotSupported, error->GetCode());
+  EXPECT_EQ("Another asynchronous operation is still pending",
+            error->GetMessage());
+
+  // Making the data available via data_callback should not schedule the
+  // success callback from the main loop and run it directly instead.
+  EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(7),
+                      SetArgPointee<3>(false),
+                      Return(true)));
+  data_callback.Run(AccessMode::READ);
+  EXPECT_EQ(7u, read_size);
+  EXPECT_FALSE(failed);
+}
+
+TEST(Stream, ReadAsync_DontWaitForData) {
+  bool succeeded = false;
+  bool failed = false;
+  auto success_callback = [](bool* succeeded, size_t /* size */) {
+    *succeeded = true;
+  };
+  auto error_callback = [](bool* failed, const Error* /* error */) {
+    *failed = true;
+  };
+
+  MockStreamImpl stream_mock;
+  char buf[10];
+  FakeMessageLoop fake_loop_{nullptr};
+  fake_loop_.SetAsCurrent();
+
+  EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
+      .WillOnce(
+          DoAll(SetArgPointee<2>(5), SetArgPointee<3>(false), Return(true)));
+  EXPECT_CALL(stream_mock, WaitForData(_, _, _)).Times(0);
+  EXPECT_TRUE(stream_mock.ReadAsync(
+      buf,
+      sizeof(buf),
+      base::Bind(success_callback, base::Unretained(&succeeded)),
+      base::Bind(error_callback, base::Unretained(&failed)),
+      nullptr));
+  // Even if ReadNonBlocking() returned some data without waiting, the
+  // |success_callback| should not run yet.
+  EXPECT_TRUE(fake_loop_.PendingTasks());
+  EXPECT_FALSE(succeeded);
+  EXPECT_FALSE(failed);
+
+  // Since the previous callback is still waiting in the main loop, we can't
+  // schedule another read yet.
+  ErrorPtr error;
+  EXPECT_FALSE(stream_mock.ReadAsync(
+      buf,
+      sizeof(buf),
+      base::Bind(success_callback, base::Unretained(&succeeded)),
+      base::Bind(error_callback, base::Unretained(&failed)),
+      &error));
+  EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+  EXPECT_EQ(errors::stream::kOperationNotSupported, error->GetCode());
+  EXPECT_EQ("Another asynchronous operation is still pending",
+            error->GetMessage());
+
+  fake_loop_.Run();
+  EXPECT_TRUE(succeeded);
+  EXPECT_FALSE(failed);
+}
+
+TEST(Stream, ReadAllAsync) {
+  bool succeeded = false;
+  bool failed = false;
+  auto success_callback = [](bool* succeeded) { *succeeded = true; };
+  auto error_callback = [](bool* failed, const Error* /* error */) {
+    *failed = true;
+  };
+
+  MockStreamImpl stream_mock;
+  base::Callback<void(AccessMode)> data_callback;
+  char buf[10];
+
+  // This sets up an initial non blocking read that would block, so
+  // ReadAllAsync() should wait for more data.
+  EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
+      .WillOnce(
+          DoAll(SetArgPointee<2>(0), SetArgPointee<3>(false), Return(true)));
+  EXPECT_CALL(stream_mock, WaitForData(AccessMode::READ, _, _))
+      .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
+  EXPECT_TRUE(stream_mock.ReadAllAsync(
+      buf,
+      sizeof(buf),
+      base::Bind(success_callback, base::Unretained(&succeeded)),
+      base::Bind(error_callback, base::Unretained(&failed)),
+      nullptr));
+  EXPECT_FALSE(succeeded);
+  EXPECT_FALSE(failed);
+  testing::Mock::VerifyAndClearExpectations(&stream_mock);
+
+  // ReadAllAsync() will try to read non blocking until the read would block
+  // before it waits for the data to be available again.
+  EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(7),
+                      SetArgPointee<3>(false),
+                      Return(true)));
+  EXPECT_CALL(stream_mock, ReadNonBlocking(buf + 7, 3, _, _, _))
+      .WillOnce(
+          DoAll(SetArgPointee<2>(0), SetArgPointee<3>(false), Return(true)));
+  EXPECT_CALL(stream_mock, WaitForData(AccessMode::READ, _, _))
+      .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
+  data_callback.Run(AccessMode::READ);
+  EXPECT_FALSE(succeeded);
+  EXPECT_FALSE(failed);
+  testing::Mock::VerifyAndClearExpectations(&stream_mock);
+
+  EXPECT_CALL(stream_mock, ReadNonBlocking(buf + 7, 3, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(3),
+                      SetArgPointee<3>(true),
+                      Return(true)));
+  data_callback.Run(AccessMode::READ);
+  EXPECT_TRUE(succeeded);
+  EXPECT_FALSE(failed);
+}
+
+TEST(Stream, ReadAllAsync_EOS) {
+  bool succeeded = false;
+  bool failed = false;
+  auto success_callback = [](bool* succeeded) { *succeeded = true; };
+  auto error_callback = [](bool* failed, const Error* error) {
+    ASSERT_EQ(errors::stream::kDomain, error->GetDomain());
+    ASSERT_EQ(errors::stream::kPartialData, error->GetCode());
+    *failed = true;
+  };
+
+  MockStreamImpl stream_mock;
+  base::Callback<void(AccessMode)> data_callback;
+  char buf[10];
+
+  EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
+      .WillOnce(
+          DoAll(SetArgPointee<2>(0), SetArgPointee<3>(false), Return(true)));
+  EXPECT_CALL(stream_mock, WaitForData(AccessMode::READ, _, _))
+      .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
+  EXPECT_TRUE(stream_mock.ReadAllAsync(
+      buf,
+      sizeof(buf),
+      base::Bind(success_callback, base::Unretained(&succeeded)),
+      base::Bind(error_callback, base::Unretained(&failed)),
+      nullptr));
+
+  // ReadAsyncAll() should finish and fail once ReadNonBlocking() returns an
+  // end-of-stream condition.
+  EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(7),
+                      SetArgPointee<3>(true),
+                      Return(true)));
+  data_callback.Run(AccessMode::READ);
+  EXPECT_FALSE(succeeded);
+  EXPECT_TRUE(failed);
+}
+
+TEST(Stream, ReadBlocking) {
+  MockStreamImpl stream_mock;
+  char buf[1024];
+  size_t read = 0;
+
+  EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(24),
+                      SetArgPointee<3>(false),
+                      Return(true)));
+  EXPECT_TRUE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
+  EXPECT_EQ(24, read);
+
+  EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(0),
+                      SetArgPointee<3>(true),
+                      Return(true)));
+  EXPECT_TRUE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
+  EXPECT_EQ(0, read);
+
+  {
+    InSequence seq;
+    EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
+        .WillOnce(DoAll(SetArgPointee<2>(0),
+                        SetArgPointee<3>(false),
+                        Return(true)));
+    EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _, _))
+        .WillOnce(Return(true));
+    EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
+        .WillOnce(DoAll(SetArgPointee<2>(0),
+                        SetArgPointee<3>(false),
+                        Return(true)));
+    EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _, _))
+        .WillOnce(Return(true));
+    EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
+        .WillOnce(DoAll(SetArgPointee<2>(124),
+                        SetArgPointee<3>(false),
+                        Return(true)));
+  }
+  EXPECT_TRUE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
+  EXPECT_EQ(124, read);
+
+  {
+    InSequence seq;
+    EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
+        .WillOnce(DoAll(SetArgPointee<2>(0),
+                        SetArgPointee<3>(false),
+                        Return(true)));
+    EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _, _))
+        .WillOnce(Return(false));
+  }
+  EXPECT_FALSE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
+}
+
+TEST(Stream, ReadAllBlocking) {
+  class MockReadBlocking : public MockStreamImpl {
+   public:
+    MOCK_METHOD4(ReadBlocking, bool(void*, size_t, size_t*, ErrorPtr*));
+  } stream_mock;
+
+  char buf[1024];
+
+  EXPECT_CALL(stream_mock, ReadBlocking(buf, 1024, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(24), Return(true)));
+  EXPECT_CALL(stream_mock, ReadBlocking(buf + 24, 1000, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(1000), Return(true)));
+  EXPECT_TRUE(stream_mock.ReadAllBlocking(buf, sizeof(buf), nullptr));
+
+  ErrorPtr error;
+  EXPECT_CALL(stream_mock, ReadBlocking(buf, 1024, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(24), Return(true)));
+  EXPECT_CALL(stream_mock, ReadBlocking(buf + 24, 1000, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
+  EXPECT_FALSE(stream_mock.ReadAllBlocking(buf, sizeof(buf), &error));
+  EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+  EXPECT_EQ(errors::stream::kPartialData, error->GetCode());
+}
+
+TEST(Stream, WriteAsync) {
+  size_t write_size = 0;
+  bool failed = false;
+  auto success_callback = [](size_t* write_size, size_t size) {
+    *write_size = size;
+  };
+  auto error_callback = [](bool* failed, const Error* /* error */) {
+    *failed = true;
+  };
+
+  MockStreamImpl stream_mock;
+  InSequence s;
+  base::Callback<void(AccessMode)> data_callback;
+  char buf[10] = {};
+
+  // WriteNonBlocking returns a blocking situation (size_written = 0) so the
+  // WaitForData() is run.
+  EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 10, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
+  EXPECT_CALL(stream_mock, WaitForData(AccessMode::WRITE, _, _))
+      .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
+  EXPECT_TRUE(stream_mock.WriteAsync(
+      buf,
+      sizeof(buf),
+      base::Bind(success_callback, base::Unretained(&write_size)),
+      base::Bind(error_callback, base::Unretained(&failed)),
+      nullptr));
+  EXPECT_EQ(0u, write_size);
+  EXPECT_FALSE(failed);
+
+  ErrorPtr error;
+  EXPECT_FALSE(stream_mock.WriteAsync(
+      buf,
+      sizeof(buf),
+      base::Bind(success_callback, base::Unretained(&write_size)),
+      base::Bind(error_callback, base::Unretained(&failed)),
+      &error));
+  EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+  EXPECT_EQ(errors::stream::kOperationNotSupported, error->GetCode());
+  EXPECT_EQ("Another asynchronous operation is still pending",
+            error->GetMessage());
+
+  EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 10, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(7), Return(true)));
+  data_callback.Run(AccessMode::WRITE);
+  EXPECT_EQ(7u, write_size);
+  EXPECT_FALSE(failed);
+}
+
+TEST(Stream, WriteAllAsync) {
+  bool succeeded = false;
+  bool failed = false;
+  auto success_callback = [](bool* succeeded) { *succeeded = true; };
+  auto error_callback = [](bool* failed, const Error* /* error */) {
+    *failed = true;
+  };
+
+  MockStreamImpl stream_mock;
+  base::Callback<void(AccessMode)> data_callback;
+  char buf[10] = {};
+
+  EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 10, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
+  EXPECT_CALL(stream_mock, WaitForData(AccessMode::WRITE, _, _))
+      .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
+  EXPECT_TRUE(stream_mock.WriteAllAsync(
+      buf,
+      sizeof(buf),
+      base::Bind(success_callback, base::Unretained(&succeeded)),
+      base::Bind(error_callback, base::Unretained(&failed)),
+      nullptr));
+  testing::Mock::VerifyAndClearExpectations(&stream_mock);
+  EXPECT_FALSE(succeeded);
+  EXPECT_FALSE(failed);
+
+  EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 10, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(7), Return(true)));
+  EXPECT_CALL(stream_mock, WriteNonBlocking(buf + 7, 3, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
+  EXPECT_CALL(stream_mock, WaitForData(AccessMode::WRITE, _, _))
+      .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
+  data_callback.Run(AccessMode::WRITE);
+  testing::Mock::VerifyAndClearExpectations(&stream_mock);
+  EXPECT_FALSE(succeeded);
+  EXPECT_FALSE(failed);
+
+  EXPECT_CALL(stream_mock, WriteNonBlocking(buf + 7, 3, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(3), Return(true)));
+  data_callback.Run(AccessMode::WRITE);
+  EXPECT_TRUE(succeeded);
+  EXPECT_FALSE(failed);
+}
+
+TEST(Stream, WriteBlocking) {
+  MockStreamImpl stream_mock;
+  char buf[1024];
+  size_t written = 0;
+
+  EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(24), Return(true)));
+  EXPECT_TRUE(stream_mock.WriteBlocking(buf, sizeof(buf), &written, nullptr));
+  EXPECT_EQ(24, written);
+
+  {
+    InSequence seq;
+    EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
+          .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
+    EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _, _))
+        .WillOnce(Return(true));
+    EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
+          .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
+    EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _, _))
+        .WillOnce(Return(true));
+    EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
+          .WillOnce(DoAll(SetArgPointee<2>(124), Return(true)));
+  }
+  EXPECT_TRUE(stream_mock.WriteBlocking(buf, sizeof(buf), &written, nullptr));
+  EXPECT_EQ(124, written);
+
+  {
+    InSequence seq;
+    EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
+          .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
+    EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _, _))
+        .WillOnce(Return(false));
+  }
+  EXPECT_FALSE(stream_mock.WriteBlocking(buf, sizeof(buf), &written, nullptr));
+}
+
+TEST(Stream, WriteAllBlocking) {
+  class MockWritelocking : public MockStreamImpl {
+   public:
+    MOCK_METHOD4(WriteBlocking, bool(const void*, size_t, size_t*, ErrorPtr*));
+  } stream_mock;
+
+  char buf[1024];
+
+  EXPECT_CALL(stream_mock, WriteBlocking(buf, 1024, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(24), Return(true)));
+  EXPECT_CALL(stream_mock, WriteBlocking(buf + 24, 1000, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(1000), Return(true)));
+  EXPECT_TRUE(stream_mock.WriteAllBlocking(buf, sizeof(buf), nullptr));
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/stream_utils.cc b/libbrillo/brillo/streams/stream_utils.cc
new file mode 100644
index 0000000..5f3be24
--- /dev/null
+++ b/libbrillo/brillo/streams/stream_utils.cc
@@ -0,0 +1,216 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/stream_utils.h>
+
+#include <limits>
+
+#include <base/bind.h>
+#include <brillo/message_loops/message_loop.h>
+#include <brillo/streams/stream_errors.h>
+
+namespace brillo {
+namespace stream_utils {
+
+namespace {
+
+// Status of asynchronous CopyData operation.
+struct CopyDataState {
+  brillo::StreamPtr in_stream;
+  brillo::StreamPtr out_stream;
+  std::vector<uint8_t> buffer;
+  uint64_t remaining_to_copy;
+  uint64_t size_copied;
+  CopyDataSuccessCallback success_callback;
+  CopyDataErrorCallback error_callback;
+};
+
+// Async CopyData I/O error callback.
+void OnCopyDataError(const std::shared_ptr<CopyDataState>& state,
+                     const brillo::Error* error) {
+  state->error_callback.Run(std::move(state->in_stream),
+                            std::move(state->out_stream), error);
+}
+
+// Forward declaration.
+void PerformRead(const std::shared_ptr<CopyDataState>& state);
+
+// Callback from read operation for CopyData. Writes the read data to the output
+// stream and invokes PerformRead when done to restart the copy cycle.
+void PerformWrite(const std::shared_ptr<CopyDataState>& state, size_t size) {
+  if (size == 0) {
+    state->success_callback.Run(std::move(state->in_stream),
+                                std::move(state->out_stream),
+                                state->size_copied);
+    return;
+  }
+  state->size_copied += size;
+  CHECK_GE(state->remaining_to_copy, size);
+  state->remaining_to_copy -= size;
+
+  brillo::ErrorPtr error;
+  bool success = state->out_stream->WriteAllAsync(
+      state->buffer.data(), size, base::Bind(&PerformRead, state),
+      base::Bind(&OnCopyDataError, state), &error);
+
+  if (!success)
+    OnCopyDataError(state, error.get());
+}
+
+// Performs the read part of asynchronous CopyData operation. Reads the data
+// from input stream and invokes PerformWrite when done to write the data to
+// the output stream.
+void PerformRead(const std::shared_ptr<CopyDataState>& state) {
+  brillo::ErrorPtr error;
+  const uint64_t buffer_size = state->buffer.size();
+  // |buffer_size| is guaranteed to fit in size_t, so |size_to_read| value will
+  // also not overflow size_t, so the static_cast below is safe.
+  size_t size_to_read =
+      static_cast<size_t>(std::min(buffer_size, state->remaining_to_copy));
+  if (size_to_read == 0)
+    return PerformWrite(state, 0);  // Nothing more to read. Finish operation.
+  bool success = state->in_stream->ReadAsync(
+      state->buffer.data(), size_to_read, base::Bind(PerformWrite, state),
+      base::Bind(OnCopyDataError, state), &error);
+
+  if (!success)
+    OnCopyDataError(state, error.get());
+}
+
+}  // anonymous namespace
+
+bool ErrorStreamClosed(const tracked_objects::Location& location,
+                       ErrorPtr* error) {
+  Error::AddTo(error,
+               location,
+               errors::stream::kDomain,
+               errors::stream::kStreamClosed,
+               "Stream is closed");
+  return false;
+}
+
+bool ErrorOperationNotSupported(const tracked_objects::Location& location,
+                                ErrorPtr* error) {
+  Error::AddTo(error,
+               location,
+               errors::stream::kDomain,
+               errors::stream::kOperationNotSupported,
+               "Stream operation not supported");
+  return false;
+}
+
+bool ErrorReadPastEndOfStream(const tracked_objects::Location& location,
+                              ErrorPtr* error) {
+  Error::AddTo(error,
+               location,
+               errors::stream::kDomain,
+               errors::stream::kPartialData,
+               "Reading past the end of stream");
+  return false;
+}
+
+bool ErrorOperationTimeout(const tracked_objects::Location& location,
+                           ErrorPtr* error) {
+  Error::AddTo(error,
+               location,
+               errors::stream::kDomain,
+               errors::stream::kTimeout,
+               "Operation timed out");
+  return false;
+}
+
+bool CheckInt64Overflow(const tracked_objects::Location& location,
+                        uint64_t position,
+                        int64_t offset,
+                        ErrorPtr* error) {
+  if (offset < 0) {
+    // Subtracting the offset. Make sure we do not underflow.
+    uint64_t unsigned_offset = static_cast<uint64_t>(-offset);
+    if (position >= unsigned_offset)
+      return true;
+  } else {
+    // Adding the offset. Make sure we do not overflow unsigned 64 bits first.
+    if (position <= std::numeric_limits<uint64_t>::max() - offset) {
+      // We definitely will not overflow the unsigned 64 bit integer.
+      // Now check that we end up within the limits of signed 64 bit integer.
+      uint64_t new_position = position + offset;
+      uint64_t max = std::numeric_limits<int64_t>::max();
+      if (new_position <= max)
+        return true;
+    }
+  }
+  Error::AddTo(error,
+               location,
+               errors::stream::kDomain,
+               errors::stream::kInvalidParameter,
+               "The stream offset value is out of range");
+  return false;
+}
+
+bool CalculateStreamPosition(const tracked_objects::Location& location,
+                             int64_t offset,
+                             Stream::Whence whence,
+                             uint64_t current_position,
+                             uint64_t stream_size,
+                             uint64_t* new_position,
+                             ErrorPtr* error) {
+  uint64_t pos = 0;
+  switch (whence) {
+    case Stream::Whence::FROM_BEGIN:
+      pos = 0;
+      break;
+
+    case Stream::Whence::FROM_CURRENT:
+      pos = current_position;
+      break;
+
+    case Stream::Whence::FROM_END:
+      pos = stream_size;
+      break;
+
+    default:
+      Error::AddTo(error,
+                   location,
+                   errors::stream::kDomain,
+                   errors::stream::kInvalidParameter,
+                   "Invalid stream position whence");
+      return false;
+  }
+
+  if (!CheckInt64Overflow(location, pos, offset, error))
+    return false;
+
+  *new_position = static_cast<uint64_t>(pos + offset);
+  return true;
+}
+
+void CopyData(StreamPtr in_stream,
+              StreamPtr out_stream,
+              const CopyDataSuccessCallback& success_callback,
+              const CopyDataErrorCallback& error_callback) {
+  CopyData(std::move(in_stream), std::move(out_stream),
+           std::numeric_limits<uint64_t>::max(), 4096, success_callback,
+           error_callback);
+}
+
+void CopyData(StreamPtr in_stream,
+              StreamPtr out_stream,
+              uint64_t max_size_to_copy,
+              size_t buffer_size,
+              const CopyDataSuccessCallback& success_callback,
+              const CopyDataErrorCallback& error_callback) {
+  auto state = std::make_shared<CopyDataState>();
+  state->in_stream = std::move(in_stream);
+  state->out_stream = std::move(out_stream);
+  state->buffer.resize(buffer_size);
+  state->remaining_to_copy = max_size_to_copy;
+  state->size_copied = 0;
+  state->success_callback = success_callback;
+  state->error_callback = error_callback;
+  brillo::MessageLoop::current()->PostTask(FROM_HERE,
+                                             base::Bind(&PerformRead, state));
+}
+
+}  // namespace stream_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/stream_utils.h b/libbrillo/brillo/streams/stream_utils.h
new file mode 100644
index 0000000..981a6d5
--- /dev/null
+++ b/libbrillo/brillo/streams/stream_utils.h
@@ -0,0 +1,114 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_STREAMS_STREAM_UTILS_H_
+#define LIBBRILLO_BRILLO_STREAMS_STREAM_UTILS_H_
+
+#include <base/location.h>
+#include <brillo/brillo_export.h>
+#include <brillo/streams/stream.h>
+
+namespace brillo {
+namespace stream_utils {
+
+// Generates "Stream closed" error and returns false.
+BRILLO_EXPORT bool ErrorStreamClosed(
+    const tracked_objects::Location& location, ErrorPtr* error);
+
+// Generates "Not supported" error and returns false.
+BRILLO_EXPORT bool ErrorOperationNotSupported(
+    const tracked_objects::Location& location, ErrorPtr* error);
+
+// Generates "Read past end of stream" error and returns false.
+BRILLO_EXPORT bool ErrorReadPastEndOfStream(
+    const tracked_objects::Location& location, ErrorPtr* error);
+
+// Generates "Operation time out" error and returns false.
+BRILLO_EXPORT bool ErrorOperationTimeout(
+    const tracked_objects::Location& location, ErrorPtr* error);
+
+// Checks if |position| + |offset| fit within the constraint of positive
+// signed int64_t type. We use uint64_t for absolute stream pointer positions,
+// however many implementations, including file-descriptor-based I/O do not
+// support the full extent of unsigned 64 bit numbers. So we restrict the file
+// positions to what can fit in the signed 64 bit value (that is, we support
+// "only" up to 9 exabytes, instead of the possible 18).
+// The |location| parameter will be used to report the origin of the error
+// if one is generated/triggered.
+BRILLO_EXPORT bool CheckInt64Overflow(
+    const tracked_objects::Location& location,
+    uint64_t position,
+    int64_t offset,
+    ErrorPtr* error);
+
+// Helper function to calculate the stream position based on the current
+// stream position and offset. Returns true and the new calculated stream
+// position in |new_position| if successful. In case of invalid stream
+// position (negative values or out of range of signed 64 bit values), returns
+// false and "invalid_parameter" |error|.
+// The |location| parameter will be used to report the origin of the error
+// if one is generated/triggered.
+BRILLO_EXPORT bool CalculateStreamPosition(
+    const tracked_objects::Location& location,
+    int64_t offset,
+    Stream::Whence whence,
+    uint64_t current_position,
+    uint64_t stream_size,
+    uint64_t* new_position,
+    ErrorPtr* error);
+
+// Checks if |mode| allows read access.
+inline bool IsReadAccessMode(Stream::AccessMode mode) {
+  return mode == Stream::AccessMode::READ ||
+         mode == Stream::AccessMode::READ_WRITE;
+}
+
+// Checks if |mode| allows write access.
+inline bool IsWriteAccessMode(Stream::AccessMode mode) {
+  return mode == Stream::AccessMode::WRITE ||
+         mode == Stream::AccessMode::READ_WRITE;
+}
+
+// Make the access mode based on read/write rights requested.
+inline Stream::AccessMode MakeAccessMode(bool read, bool write) {
+  CHECK(read || write);  // Either read or write (or both) must be specified.
+  if (read && write)
+    return Stream::AccessMode::READ_WRITE;
+  return write ? Stream::AccessMode::WRITE : Stream::AccessMode::READ;
+}
+
+using CopyDataSuccessCallback =
+    base::Callback<void(StreamPtr, StreamPtr, uint64_t)>;
+using CopyDataErrorCallback =
+    base::Callback<void(StreamPtr, StreamPtr, const brillo::Error*)>;
+
+// Asynchronously copies data from input stream to output stream until all the
+// data from the input stream is read. The function takes ownership of both
+// streams for the duration of the operation and then gives them back when
+// either the |success_callback| or |error_callback| is called.
+// |success_callback| also provides the number of bytes actually copied.
+// This variant of CopyData uses internal buffer of 4 KiB for the operation.
+BRILLO_EXPORT void CopyData(StreamPtr in_stream,
+                            StreamPtr out_stream,
+                            const CopyDataSuccessCallback& success_callback,
+                            const CopyDataErrorCallback& error_callback);
+
+// Asynchronously copies data from input stream to output stream until the
+// maximum amount of data specified in |max_size_to_copy| is copied or the end
+// of the input stream is encountered. The function takes ownership of both
+// streams for the duration of the operation and then gives them back when
+// either the |success_callback| or |error_callback| is called.
+// |success_callback| also provides the number of bytes actually copied.
+// |buffer_size| specifies the size of the read buffer to use for the operation.
+BRILLO_EXPORT void CopyData(StreamPtr in_stream,
+                            StreamPtr out_stream,
+                            uint64_t max_size_to_copy,
+                            size_t buffer_size,
+                            const CopyDataSuccessCallback& success_callback,
+                            const CopyDataErrorCallback& error_callback);
+
+}  // namespace stream_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_STREAMS_STREAM_UTILS_H_
diff --git a/libbrillo/brillo/streams/stream_utils_unittest.cc b/libbrillo/brillo/streams/stream_utils_unittest.cc
new file mode 100644
index 0000000..f27d233
--- /dev/null
+++ b/libbrillo/brillo/streams/stream_utils_unittest.cc
@@ -0,0 +1,300 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/stream_utils.h>
+
+#include <limits>
+
+#include <base/bind.h>
+#include <brillo/message_loops/fake_message_loop.h>
+#include <brillo/message_loops/message_loop.h>
+#include <brillo/streams/mock_stream.h>
+#include <brillo/streams/stream_errors.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::DoAll;
+using testing::InSequence;
+using testing::Return;
+using testing::StrictMock;
+using testing::_;
+
+ACTION_TEMPLATE(InvokeAsyncCallback,
+                HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_1_VALUE_PARAMS(size)) {
+  brillo::MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(std::get<k>(args), size));
+  return true;
+}
+
+ACTION_TEMPLATE(InvokeAsyncCallback,
+                HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_0_VALUE_PARAMS()) {
+  brillo::MessageLoop::current()->PostTask(FROM_HERE, std::get<k>(args));
+  return true;
+}
+
+ACTION_TEMPLATE(InvokeAsyncErrorCallback,
+                HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_1_VALUE_PARAMS(code)) {
+  brillo::ErrorPtr error;
+  brillo::Error::AddTo(&error, FROM_HERE, "test", code, "message");
+  brillo::MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(std::get<k>(args), base::Owned(error.release())));
+  return true;
+}
+
+namespace brillo {
+
+TEST(StreamUtils, ErrorStreamClosed) {
+  ErrorPtr error;
+  EXPECT_FALSE(stream_utils::ErrorStreamClosed(FROM_HERE, &error));
+  EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+  EXPECT_EQ(errors::stream::kStreamClosed, error->GetCode());
+  EXPECT_EQ("Stream is closed", error->GetMessage());
+}
+
+TEST(StreamUtils, ErrorOperationNotSupported) {
+  ErrorPtr error;
+  EXPECT_FALSE(stream_utils::ErrorOperationNotSupported(FROM_HERE, &error));
+  EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+  EXPECT_EQ(errors::stream::kOperationNotSupported, error->GetCode());
+  EXPECT_EQ("Stream operation not supported", error->GetMessage());
+}
+
+TEST(StreamUtils, ErrorReadPastEndOfStream) {
+  ErrorPtr error;
+  EXPECT_FALSE(stream_utils::ErrorReadPastEndOfStream(FROM_HERE, &error));
+  EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+  EXPECT_EQ(errors::stream::kPartialData, error->GetCode());
+  EXPECT_EQ("Reading past the end of stream", error->GetMessage());
+}
+
+TEST(StreamUtils, CheckInt64Overflow) {
+  const int64_t max_int64 = std::numeric_limits<int64_t>::max();
+  const uint64_t max_uint64 = std::numeric_limits<uint64_t>::max();
+  EXPECT_TRUE(stream_utils::CheckInt64Overflow(FROM_HERE, 0, 0, nullptr));
+  EXPECT_TRUE(stream_utils::CheckInt64Overflow(
+      FROM_HERE, 0, max_int64, nullptr));
+  EXPECT_TRUE(stream_utils::CheckInt64Overflow(
+      FROM_HERE, max_int64, 0, nullptr));
+  EXPECT_TRUE(stream_utils::CheckInt64Overflow(FROM_HERE, 100, -90, nullptr));
+  EXPECT_TRUE(stream_utils::CheckInt64Overflow(
+      FROM_HERE, 1000, -1000, nullptr));
+
+  ErrorPtr error;
+  EXPECT_FALSE(stream_utils::CheckInt64Overflow(FROM_HERE, 100, -101, &error));
+  EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
+  EXPECT_EQ(errors::stream::kInvalidParameter, error->GetCode());
+  EXPECT_EQ("The stream offset value is out of range", error->GetMessage());
+
+  EXPECT_FALSE(stream_utils::CheckInt64Overflow(
+      FROM_HERE, max_int64, 1, nullptr));
+  EXPECT_FALSE(stream_utils::CheckInt64Overflow(
+      FROM_HERE, max_uint64, 0, nullptr));
+  EXPECT_FALSE(stream_utils::CheckInt64Overflow(
+      FROM_HERE, max_uint64, max_int64, nullptr));
+}
+
+TEST(StreamUtils, CalculateStreamPosition) {
+  using Whence = Stream::Whence;
+  const uint64_t current_pos = 1234;
+  const uint64_t end_pos = 2000;
+  uint64_t pos = 0;
+
+  EXPECT_TRUE(stream_utils::CalculateStreamPosition(
+      FROM_HERE, 0, Whence::FROM_BEGIN, current_pos, end_pos, &pos, nullptr));
+  EXPECT_EQ(0u, pos);
+
+  EXPECT_TRUE(stream_utils::CalculateStreamPosition(
+      FROM_HERE, 0, Whence::FROM_CURRENT, current_pos, end_pos, &pos, nullptr));
+  EXPECT_EQ(current_pos, pos);
+
+  EXPECT_TRUE(stream_utils::CalculateStreamPosition(
+      FROM_HERE, 0, Whence::FROM_END, current_pos, end_pos, &pos, nullptr));
+  EXPECT_EQ(end_pos, pos);
+
+  EXPECT_TRUE(stream_utils::CalculateStreamPosition(
+      FROM_HERE, 10, Whence::FROM_BEGIN, current_pos, end_pos, &pos, nullptr));
+  EXPECT_EQ(10u, pos);
+
+  EXPECT_TRUE(stream_utils::CalculateStreamPosition(
+      FROM_HERE, 10, Whence::FROM_CURRENT, current_pos, end_pos, &pos,
+      nullptr));
+  EXPECT_EQ(current_pos + 10, pos);
+
+  EXPECT_TRUE(stream_utils::CalculateStreamPosition(
+      FROM_HERE, 10, Whence::FROM_END, current_pos, end_pos, &pos, nullptr));
+  EXPECT_EQ(end_pos + 10, pos);
+
+  EXPECT_TRUE(stream_utils::CalculateStreamPosition(
+      FROM_HERE, -10, Whence::FROM_CURRENT, current_pos, end_pos, &pos,
+      nullptr));
+  EXPECT_EQ(current_pos - 10, pos);
+
+  EXPECT_TRUE(stream_utils::CalculateStreamPosition(
+      FROM_HERE, -10, Whence::FROM_END, current_pos, end_pos, &pos, nullptr));
+  EXPECT_EQ(end_pos - 10, pos);
+
+  ErrorPtr error;
+  EXPECT_FALSE(stream_utils::CalculateStreamPosition(
+      FROM_HERE, -1, Whence::FROM_BEGIN, current_pos, end_pos, &pos, &error));
+  EXPECT_EQ(errors::stream::kInvalidParameter, error->GetCode());
+  EXPECT_EQ("The stream offset value is out of range", error->GetMessage());
+
+  EXPECT_FALSE(stream_utils::CalculateStreamPosition(
+      FROM_HERE, -1001, Whence::FROM_CURRENT, 1000, end_pos, &pos, nullptr));
+
+  const uint64_t max_int64 = std::numeric_limits<int64_t>::max();
+  EXPECT_FALSE(stream_utils::CalculateStreamPosition(
+      FROM_HERE, 1, Whence::FROM_CURRENT, max_int64, end_pos, &pos, nullptr));
+}
+
+class CopyStreamDataTest : public testing::Test {
+ public:
+  void SetUp() override {
+    fake_loop_.SetAsCurrent();
+    in_stream_.reset(new StrictMock<MockStream>{});
+    out_stream_.reset(new StrictMock<MockStream>{});
+  }
+
+  FakeMessageLoop fake_loop_{nullptr};
+  std::unique_ptr<StrictMock<MockStream>> in_stream_;
+  std::unique_ptr<StrictMock<MockStream>> out_stream_;
+  bool succeeded_{false};
+  bool failed_{false};
+
+  void OnSuccess(uint64_t expected,
+                 StreamPtr /* in_stream */,
+                 StreamPtr /* out_stream */,
+                 uint64_t copied) {
+    EXPECT_EQ(expected, copied);
+    succeeded_ = true;
+  }
+
+  void OnError(const std::string& expected_error,
+               StreamPtr /* in_stream */,
+               StreamPtr /* out_stream */,
+               const Error* error) {
+    EXPECT_EQ(expected_error, error->GetCode());
+    failed_ = true;
+  }
+
+  void ExpectSuccess() {
+    EXPECT_TRUE(succeeded_);
+    EXPECT_FALSE(failed_);
+  }
+
+  void ExpectFailure() {
+    EXPECT_FALSE(succeeded_);
+    EXPECT_TRUE(failed_);
+  }
+};
+
+TEST_F(CopyStreamDataTest, CopyAllAtOnce) {
+  {
+    InSequence seq;
+    EXPECT_CALL(*in_stream_, ReadAsync(_, 100, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>(100));
+    EXPECT_CALL(*out_stream_, WriteAllAsync(_, 100, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>());
+  }
+  stream_utils::CopyData(
+      std::move(in_stream_), std::move(out_stream_), 100, 4096,
+      base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 100),
+      base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), ""));
+  fake_loop_.Run();
+  ExpectSuccess();
+}
+
+TEST_F(CopyStreamDataTest, CopyInBlocks) {
+  {
+    InSequence seq;
+    EXPECT_CALL(*in_stream_, ReadAsync(_, 100, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>(60));
+    EXPECT_CALL(*out_stream_, WriteAllAsync(_, 60, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>());
+    EXPECT_CALL(*in_stream_, ReadAsync(_, 40, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>(40));
+    EXPECT_CALL(*out_stream_, WriteAllAsync(_, 40, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>());
+  }
+  stream_utils::CopyData(
+      std::move(in_stream_), std::move(out_stream_), 100, 4096,
+      base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 100),
+      base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), ""));
+  fake_loop_.Run();
+  ExpectSuccess();
+}
+
+TEST_F(CopyStreamDataTest, CopyTillEndOfStream) {
+  {
+    InSequence seq;
+    EXPECT_CALL(*in_stream_, ReadAsync(_, 100, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>(60));
+    EXPECT_CALL(*out_stream_, WriteAllAsync(_, 60, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>());
+    EXPECT_CALL(*in_stream_, ReadAsync(_, 40, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>(0));
+  }
+  stream_utils::CopyData(
+      std::move(in_stream_), std::move(out_stream_), 100, 4096,
+      base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 60),
+      base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), ""));
+  fake_loop_.Run();
+  ExpectSuccess();
+}
+
+TEST_F(CopyStreamDataTest, CopyInSmallBlocks) {
+  {
+    InSequence seq;
+    EXPECT_CALL(*in_stream_, ReadAsync(_, 60, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>(60));
+    EXPECT_CALL(*out_stream_, WriteAllAsync(_, 60, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>());
+    EXPECT_CALL(*in_stream_, ReadAsync(_, 40, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>(40));
+    EXPECT_CALL(*out_stream_, WriteAllAsync(_, 40, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>());
+  }
+  stream_utils::CopyData(
+      std::move(in_stream_), std::move(out_stream_), 100, 60,
+      base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 100),
+      base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), ""));
+  fake_loop_.Run();
+  ExpectSuccess();
+}
+
+TEST_F(CopyStreamDataTest, ErrorRead) {
+  {
+    InSequence seq;
+    EXPECT_CALL(*in_stream_, ReadAsync(_, 60, _, _, _))
+        .WillOnce(InvokeAsyncErrorCallback<3>("read"));
+  }
+  stream_utils::CopyData(
+      std::move(in_stream_), std::move(out_stream_), 100, 60,
+      base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 0),
+      base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), "read"));
+  fake_loop_.Run();
+  ExpectFailure();
+}
+
+TEST_F(CopyStreamDataTest, ErrorWrite) {
+  {
+    InSequence seq;
+    EXPECT_CALL(*in_stream_, ReadAsync(_, 60, _, _, _))
+        .WillOnce(InvokeAsyncCallback<2>(60));
+    EXPECT_CALL(*out_stream_, WriteAllAsync(_, 60, _, _, _))
+        .WillOnce(InvokeAsyncErrorCallback<3>("write"));
+  }
+  stream_utils::CopyData(
+      std::move(in_stream_), std::move(out_stream_), 100, 60,
+      base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 0),
+      base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this),
+                 "write"));
+  fake_loop_.Run();
+  ExpectFailure();
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/tls_stream.cc b/libbrillo/brillo/streams/tls_stream.cc
new file mode 100644
index 0000000..ac116a4
--- /dev/null
+++ b/libbrillo/brillo/streams/tls_stream.cc
@@ -0,0 +1,545 @@
+// Copyright 2015 The Chromium OS 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 <brillo/streams/tls_stream.h>
+
+#include <algorithm>
+#include <limits>
+#include <string>
+#include <vector>
+
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
+#include <base/bind.h>
+#include <base/memory/weak_ptr.h>
+#include <brillo/message_loops/message_loop.h>
+#include <brillo/secure_blob.h>
+#include <brillo/streams/openssl_stream_bio.h>
+#include <brillo/streams/stream_utils.h>
+#include <brillo/strings/string_utils.h>
+
+namespace {
+
+// SSL info callback which is called by OpenSSL when we enable logging level of
+// at least 3. This logs the information about the internal TLS handshake.
+void TlsInfoCallback(const SSL* /* ssl */, int where, int ret) {
+  std::string reason;
+  std::vector<std::string> info;
+  if (where & SSL_CB_LOOP)
+    info.push_back("loop");
+  if (where & SSL_CB_EXIT)
+    info.push_back("exit");
+  if (where & SSL_CB_READ)
+    info.push_back("read");
+  if (where & SSL_CB_WRITE)
+    info.push_back("write");
+  if (where & SSL_CB_ALERT) {
+    info.push_back("alert");
+    reason = ", reason: ";
+    reason += SSL_alert_type_string_long(ret);
+    reason += "/";
+    reason += SSL_alert_desc_string_long(ret);
+  }
+  if (where & SSL_CB_HANDSHAKE_START)
+    info.push_back("handshake_start");
+  if (where & SSL_CB_HANDSHAKE_DONE)
+    info.push_back("handshake_done");
+
+  VLOG(3) << "TLS progress info: " << brillo::string_utils::Join(",", info)
+          << ", with status: " << ret << reason;
+}
+
+// Static variable to store the index of TlsStream private data in SSL context
+// used to store custom data for OnCertVerifyResults().
+int ssl_ctx_private_data_index = -1;
+
+// Default trusted certificate store location.
+const char kCACertificatePath[] =
+#ifdef __ANDROID__
+    "/system/etc/security/cacerts_google";
+#else
+    "/usr/share/chromeos-ca-certificates";
+#endif
+
+}  // anonymous namespace
+
+namespace brillo {
+
+// Helper implementation of TLS stream used to hide most of OpenSSL inner
+// workings from the users of brillo::TlsStream.
+class TlsStream::TlsStreamImpl {
+ public:
+  TlsStreamImpl();
+  ~TlsStreamImpl();
+
+  bool Init(StreamPtr socket,
+            const std::string& host,
+            const base::Closure& success_callback,
+            const Stream::ErrorCallback& error_callback,
+            ErrorPtr* error);
+
+  bool ReadNonBlocking(void* buffer,
+                       size_t size_to_read,
+                       size_t* size_read,
+                       bool* end_of_stream,
+                       ErrorPtr* error);
+
+  bool WriteNonBlocking(const void* buffer,
+                        size_t size_to_write,
+                        size_t* size_written,
+                        ErrorPtr* error);
+
+  bool Flush(ErrorPtr* error);
+  bool Close(ErrorPtr* error);
+  bool WaitForData(AccessMode mode,
+                   const base::Callback<void(AccessMode)>& callback,
+                   ErrorPtr* error);
+  bool WaitForDataBlocking(AccessMode in_mode,
+                           base::TimeDelta timeout,
+                           AccessMode* out_mode,
+                           ErrorPtr* error);
+  void CancelPendingAsyncOperations();
+
+ private:
+  bool ReportError(ErrorPtr* error,
+                   const tracked_objects::Location& location,
+                   const std::string& message);
+  void DoHandshake(const base::Closure& success_callback,
+                   const Stream::ErrorCallback& error_callback);
+  void RetryHandshake(const base::Closure& success_callback,
+                      const Stream::ErrorCallback& error_callback,
+                      Stream::AccessMode mode);
+
+  int OnCertVerifyResults(int ok, X509_STORE_CTX* ctx);
+  static int OnCertVerifyResultsStatic(int ok, X509_STORE_CTX* ctx);
+
+  StreamPtr socket_;
+  std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)> ctx_{nullptr, SSL_CTX_free};
+  std::unique_ptr<SSL, decltype(&SSL_free)> ssl_{nullptr, SSL_free};
+  BIO* stream_bio_{nullptr};
+  bool need_more_read_{false};
+  bool need_more_write_{false};
+
+  base::WeakPtrFactory<TlsStreamImpl> weak_ptr_factory_{this};
+  DISALLOW_COPY_AND_ASSIGN(TlsStreamImpl);
+};
+
+TlsStream::TlsStreamImpl::TlsStreamImpl() {
+  SSL_load_error_strings();
+  SSL_library_init();
+  if (ssl_ctx_private_data_index < 0) {
+    ssl_ctx_private_data_index =
+        SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
+  }
+}
+
+TlsStream::TlsStreamImpl::~TlsStreamImpl() {
+  ssl_.reset();
+  ctx_.reset();
+}
+
+bool TlsStream::TlsStreamImpl::ReadNonBlocking(void* buffer,
+                                               size_t size_to_read,
+                                               size_t* size_read,
+                                               bool* end_of_stream,
+                                               ErrorPtr* error) {
+  const size_t max_int = std::numeric_limits<int>::max();
+  int size_int = static_cast<int>(std::min(size_to_read, max_int));
+  int ret = SSL_read(ssl_.get(), buffer, size_int);
+  if (ret > 0) {
+    *size_read = static_cast<size_t>(ret);
+    if (end_of_stream)
+      *end_of_stream = false;
+    return true;
+  }
+
+  int err = SSL_get_error(ssl_.get(), ret);
+  if (err == SSL_ERROR_ZERO_RETURN) {
+    *size_read = 0;
+    if (end_of_stream)
+      *end_of_stream = true;
+    return true;
+  }
+
+  if (err == SSL_ERROR_WANT_READ) {
+    need_more_read_ = true;
+  } else if (err == SSL_ERROR_WANT_WRITE) {
+    // Writes might be required for SSL_read() because of possible TLS
+    // re-negotiations which can happen at any time.
+    need_more_write_ = true;
+  } else {
+    return ReportError(error, FROM_HERE, "Error reading from TLS socket");
+  }
+  *size_read = 0;
+  if (end_of_stream)
+    *end_of_stream = false;
+  return true;
+}
+
+bool TlsStream::TlsStreamImpl::WriteNonBlocking(const void* buffer,
+                                                size_t size_to_write,
+                                                size_t* size_written,
+                                                ErrorPtr* error) {
+  const size_t max_int = std::numeric_limits<int>::max();
+  int size_int = static_cast<int>(std::min(size_to_write, max_int));
+  int ret = SSL_write(ssl_.get(), buffer, size_int);
+  if (ret > 0) {
+    *size_written = static_cast<size_t>(ret);
+    return true;
+  }
+
+  int err = SSL_get_error(ssl_.get(), ret);
+  if (err == SSL_ERROR_WANT_READ) {
+    // Reads might be required for SSL_write() because of possible TLS
+    // re-negotiations which can happen at any time.
+    need_more_read_ = true;
+  } else if (err == SSL_ERROR_WANT_WRITE) {
+    need_more_write_ = true;
+  } else {
+    return ReportError(error, FROM_HERE, "Error writing to TLS socket");
+  }
+  *size_written = 0;
+  return true;
+}
+
+bool TlsStream::TlsStreamImpl::Flush(ErrorPtr* error) {
+  return socket_->FlushBlocking(error);
+}
+
+bool TlsStream::TlsStreamImpl::Close(ErrorPtr* error) {
+  // 2 seconds should be plenty here.
+  const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(2);
+  // The retry count of 4 below is just arbitrary, to ensure we don't get stuck
+  // here forever. We should rarely need to repeat SSL_shutdown anyway.
+  for (int retry_count = 0; retry_count < 4; retry_count++) {
+    int ret = SSL_shutdown(ssl_.get());
+    // We really don't care for bi-directional shutdown here.
+    // Just make sure we only send the "close notify" alert to the remote peer.
+    if (ret >= 0)
+      break;
+
+    int err = SSL_get_error(ssl_.get(), ret);
+    if (err == SSL_ERROR_WANT_READ) {
+      if (!socket_->WaitForDataBlocking(AccessMode::READ, kTimeout, nullptr,
+                                        error)) {
+        break;
+      }
+    } else if (err == SSL_ERROR_WANT_WRITE) {
+      if (!socket_->WaitForDataBlocking(AccessMode::WRITE, kTimeout, nullptr,
+                                        error)) {
+        break;
+      }
+    } else {
+      LOG(ERROR) << "SSL_shutdown returned error #" << err;
+      ReportError(error, FROM_HERE, "Failed to shut down TLS socket");
+      break;
+    }
+  }
+  return socket_->CloseBlocking(error);
+}
+
+bool TlsStream::TlsStreamImpl::WaitForData(
+    AccessMode mode,
+    const base::Callback<void(AccessMode)>& callback,
+    ErrorPtr* error) {
+  bool is_read = stream_utils::IsReadAccessMode(mode);
+  bool is_write = stream_utils::IsWriteAccessMode(mode);
+  is_read |= need_more_read_;
+  is_write |= need_more_write_;
+  need_more_read_ = false;
+  need_more_write_ = false;
+  if (is_read && SSL_pending(ssl_.get()) > 0) {
+    callback.Run(AccessMode::READ);
+    return true;
+  }
+  mode = stream_utils::MakeAccessMode(is_read, is_write);
+  return socket_->WaitForData(mode, callback, error);
+}
+
+bool TlsStream::TlsStreamImpl::WaitForDataBlocking(AccessMode in_mode,
+                                                   base::TimeDelta timeout,
+                                                   AccessMode* out_mode,
+                                                   ErrorPtr* error) {
+  bool is_read = stream_utils::IsReadAccessMode(in_mode);
+  bool is_write = stream_utils::IsWriteAccessMode(in_mode);
+  is_read |= need_more_read_;
+  is_write |= need_more_write_;
+  need_more_read_ = need_more_write_ = false;
+  if (is_read && SSL_pending(ssl_.get()) > 0) {
+    if (out_mode)
+      *out_mode = AccessMode::READ;
+    return true;
+  }
+  in_mode = stream_utils::MakeAccessMode(is_read, is_write);
+  return socket_->WaitForDataBlocking(in_mode, timeout, out_mode, error);
+}
+
+void TlsStream::TlsStreamImpl::CancelPendingAsyncOperations() {
+  socket_->CancelPendingAsyncOperations();
+  weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
+bool TlsStream::TlsStreamImpl::ReportError(
+    ErrorPtr* error,
+    const tracked_objects::Location& location,
+    const std::string& message) {
+  const char* file = nullptr;
+  int line = 0;
+  const char* data = 0;
+  int flags = 0;
+  while (auto errnum = ERR_get_error_line_data(&file, &line, &data, &flags)) {
+    char buf[256];
+    ERR_error_string_n(errnum, buf, sizeof(buf));
+    tracked_objects::Location ssl_location{"Unknown", file, line, nullptr};
+    std::string ssl_message = buf;
+    if (flags & ERR_TXT_STRING) {
+      ssl_message += ": ";
+      ssl_message += data;
+    }
+    Error::AddTo(error, ssl_location, "openssl", std::to_string(errnum),
+                 ssl_message);
+  }
+  Error::AddTo(error, location, "tls_stream", "failed", message);
+  return false;
+}
+
+int TlsStream::TlsStreamImpl::OnCertVerifyResults(int ok, X509_STORE_CTX* ctx) {
+  // OpenSSL already performs a comprehensive check of the certificate chain
+  // (using X509_verify_cert() function) and calls back with the result of its
+  // verification.
+  // |ok| is set to 1 if the verification passed and 0 if an error was detected.
+  // Here we can perform some additional checks if we need to, or simply log
+  // the issues found.
+
+  // For now, just log an error if it occurred.
+  if (!ok) {
+    LOG(ERROR) << "Server certificate validation failed: "
+               << X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx));
+  }
+  return ok;
+}
+
+int TlsStream::TlsStreamImpl::OnCertVerifyResultsStatic(int ok,
+                                                        X509_STORE_CTX* ctx) {
+  // Obtain the pointer to the instance of TlsStream::TlsStreamImpl from the
+  // SSL CTX object referenced by |ctx|.
+  SSL* ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(
+      ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
+  SSL_CTX* ssl_ctx = ssl ? SSL_get_SSL_CTX(ssl) : nullptr;
+  TlsStream::TlsStreamImpl* self = nullptr;
+  if (ssl_ctx) {
+    self = static_cast<TlsStream::TlsStreamImpl*>(SSL_CTX_get_ex_data(
+        ssl_ctx, ssl_ctx_private_data_index));
+  }
+  return self ? self->OnCertVerifyResults(ok, ctx) : ok;
+}
+
+bool TlsStream::TlsStreamImpl::Init(StreamPtr socket,
+                                    const std::string& host,
+                                    const base::Closure& success_callback,
+                                    const Stream::ErrorCallback& error_callback,
+                                    ErrorPtr* error) {
+  ctx_.reset(SSL_CTX_new(TLSv1_2_client_method()));
+  if (!ctx_)
+    return ReportError(error, FROM_HERE, "Cannot create SSL_CTX");
+
+  // Top cipher suites supported by both Google GFEs and OpenSSL (in server
+  // preferred order).
+  int res = SSL_CTX_set_cipher_list(ctx_.get(),
+                                    "ECDHE-ECDSA-AES128-GCM-SHA256:"
+                                    "ECDHE-ECDSA-AES256-GCM-SHA384:"
+                                    "ECDHE-RSA-AES128-GCM-SHA256:"
+                                    "ECDHE-RSA-AES256-GCM-SHA384");
+  if (res != 1)
+    return ReportError(error, FROM_HERE, "Cannot set the cipher list");
+
+  res = SSL_CTX_load_verify_locations(ctx_.get(), nullptr, kCACertificatePath);
+  if (res != 1) {
+    return ReportError(error, FROM_HERE,
+                       "Failed to specify trusted certificate location");
+  }
+
+  // Store a pointer to "this" into SSL_CTX instance.
+  SSL_CTX_set_ex_data(ctx_.get(), ssl_ctx_private_data_index, this);
+
+  // Ask OpenSSL to validate the server host from the certificate to match
+  // the expected host name we are given:
+  X509_VERIFY_PARAM* param = SSL_CTX_get0_param(ctx_.get());
+  X509_VERIFY_PARAM_set1_host(param, host.c_str(), host.size());
+
+  SSL_CTX_set_verify(ctx_.get(), SSL_VERIFY_PEER,
+                     &TlsStreamImpl::OnCertVerifyResultsStatic);
+
+  socket_ = std::move(socket);
+  ssl_.reset(SSL_new(ctx_.get()));
+
+  // Enable TLS progress callback if VLOG level is >=3.
+  if (VLOG_IS_ON(3))
+    SSL_set_info_callback(ssl_.get(), TlsInfoCallback);
+
+  stream_bio_ = BIO_new_stream(socket_.get());
+  SSL_set_bio(ssl_.get(), stream_bio_, stream_bio_);
+  SSL_set_connect_state(ssl_.get());
+
+  // We might have no message loop (e.g. we are in unit tests).
+  if (MessageLoop::ThreadHasCurrent()) {
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&TlsStreamImpl::DoHandshake,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   success_callback,
+                   error_callback));
+  } else {
+    DoHandshake(success_callback, error_callback);
+  }
+  return true;
+}
+
+void TlsStream::TlsStreamImpl::RetryHandshake(
+    const base::Closure& success_callback,
+    const Stream::ErrorCallback& error_callback,
+    Stream::AccessMode /* mode */) {
+  VLOG(1) << "Retrying TLS handshake";
+  DoHandshake(success_callback, error_callback);
+}
+
+void TlsStream::TlsStreamImpl::DoHandshake(
+    const base::Closure& success_callback,
+    const Stream::ErrorCallback& error_callback) {
+  VLOG(1) << "Begin TLS handshake";
+  int res = SSL_do_handshake(ssl_.get());
+  if (res == 1) {
+    VLOG(1) << "Handshake successful";
+    success_callback.Run();
+    return;
+  }
+  ErrorPtr error;
+  int err = SSL_get_error(ssl_.get(), res);
+  if (err == SSL_ERROR_WANT_READ) {
+    VLOG(1) << "Waiting for read data...";
+    bool ok = socket_->WaitForData(
+        Stream::AccessMode::READ,
+        base::Bind(&TlsStreamImpl::RetryHandshake,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   success_callback, error_callback),
+        &error);
+    if (ok)
+      return;
+  } else if (err == SSL_ERROR_WANT_WRITE) {
+    VLOG(1) << "Waiting for write data...";
+    bool ok = socket_->WaitForData(
+        Stream::AccessMode::WRITE,
+        base::Bind(&TlsStreamImpl::RetryHandshake,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   success_callback, error_callback),
+        &error);
+    if (ok)
+      return;
+  } else {
+    ReportError(&error, FROM_HERE, "TLS handshake failed.");
+  }
+  error_callback.Run(error.get());
+}
+
+/////////////////////////////////////////////////////////////////////////////
+TlsStream::TlsStream(std::unique_ptr<TlsStreamImpl> impl)
+    : impl_{std::move(impl)} {}
+
+TlsStream::~TlsStream() {
+  if (impl_) {
+    impl_->Close(nullptr);
+  }
+}
+
+void TlsStream::Connect(StreamPtr socket,
+                        const std::string& host,
+                        const base::Callback<void(StreamPtr)>& success_callback,
+                        const Stream::ErrorCallback& error_callback) {
+  std::unique_ptr<TlsStreamImpl> impl{new TlsStreamImpl};
+  std::unique_ptr<TlsStream> stream{new TlsStream{std::move(impl)}};
+
+  TlsStreamImpl* pimpl = stream->impl_.get();
+  ErrorPtr error;
+  bool success = pimpl->Init(std::move(socket), host,
+                             base::Bind(success_callback,
+                                        base::Passed(std::move(stream))),
+                             error_callback, &error);
+
+  if (!success)
+    error_callback.Run(error.get());
+}
+
+bool TlsStream::IsOpen() const {
+  return impl_ ? true : false;
+}
+
+bool TlsStream::SetSizeBlocking(uint64_t /* size */, ErrorPtr* error) {
+  return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+}
+
+bool TlsStream::Seek(int64_t /* offset */,
+                     Whence /* whence */,
+                     uint64_t* /* new_position*/,
+                     ErrorPtr* error) {
+  return stream_utils::ErrorOperationNotSupported(FROM_HERE, error);
+}
+
+bool TlsStream::ReadNonBlocking(void* buffer,
+                                size_t size_to_read,
+                                size_t* size_read,
+                                bool* end_of_stream,
+                                ErrorPtr* error) {
+  if (!impl_)
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+  return impl_->ReadNonBlocking(buffer, size_to_read, size_read, end_of_stream,
+                                error);
+}
+
+bool TlsStream::WriteNonBlocking(const void* buffer,
+                                 size_t size_to_write,
+                                 size_t* size_written,
+                                 ErrorPtr* error) {
+  if (!impl_)
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+  return impl_->WriteNonBlocking(buffer, size_to_write, size_written, error);
+}
+
+bool TlsStream::FlushBlocking(ErrorPtr* error) {
+  if (!impl_)
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+  return impl_->Flush(error);
+}
+
+bool TlsStream::CloseBlocking(ErrorPtr* error) {
+  if (impl_ && !impl_->Close(error))
+    return false;
+  impl_.reset();
+  return true;
+}
+
+bool TlsStream::WaitForData(AccessMode mode,
+                            const base::Callback<void(AccessMode)>& callback,
+                            ErrorPtr* error) {
+  if (!impl_)
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+  return impl_->WaitForData(mode, callback, error);
+}
+
+bool TlsStream::WaitForDataBlocking(AccessMode in_mode,
+                                    base::TimeDelta timeout,
+                                    AccessMode* out_mode,
+                                    ErrorPtr* error) {
+  if (!impl_)
+    return stream_utils::ErrorStreamClosed(FROM_HERE, error);
+  return impl_->WaitForDataBlocking(in_mode, timeout, out_mode, error);
+}
+
+void TlsStream::CancelPendingAsyncOperations() {
+  if (impl_)
+    impl_->CancelPendingAsyncOperations();
+  Stream::CancelPendingAsyncOperations();
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/streams/tls_stream.h b/libbrillo/brillo/streams/tls_stream.h
new file mode 100644
index 0000000..1431eec
--- /dev/null
+++ b/libbrillo/brillo/streams/tls_stream.h
@@ -0,0 +1,84 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_STREAMS_TLS_STREAM_H_
+#define LIBBRILLO_BRILLO_STREAMS_TLS_STREAM_H_
+
+#include <memory>
+#include <string>
+
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+#include <brillo/errors/error.h>
+#include <brillo/streams/stream.h>
+
+namespace brillo {
+
+// This class provides client-side TLS stream that performs handshake with the
+// server and established a secure communication channel which can be used
+// by performing read/write operations on this stream. Both synchronous and
+// asynchronous I/O is supported.
+// The underlying socket stream must already be created and connected to the
+// destination server and passed in TlsStream::Connect() method as |socket|.
+class BRILLO_EXPORT TlsStream : public Stream {
+ public:
+  ~TlsStream() override;
+
+  // Perform a TLS handshake and establish secure connection over |socket|.
+  // Calls |callback| when successful and passes the instance of TlsStream
+  // as an argument. In case of an error, |error_callback| is called.
+  // |host| must specify the expected remote host (server) name.
+  static void Connect(
+      StreamPtr socket,
+      const std::string& host,
+      const base::Callback<void(StreamPtr)>& success_callback,
+      const Stream::ErrorCallback& error_callback);
+
+  // Overrides from Stream:
+  bool IsOpen() const override;
+  bool CanRead() const override { return true; }
+  bool CanWrite() const override { return true; }
+  bool CanSeek() const override { return false; }
+  bool CanGetSize() const override { return false; }
+  uint64_t GetSize() const override { return 0; }
+  bool SetSizeBlocking(uint64_t size, ErrorPtr* error) override;
+  uint64_t GetRemainingSize() const override { return 0; }
+  uint64_t GetPosition() const override { return 0; }
+  bool Seek(int64_t offset,
+            Whence whence,
+            uint64_t* new_position,
+            ErrorPtr* error) override;
+  bool ReadNonBlocking(void* buffer,
+                       size_t size_to_read,
+                       size_t* size_read,
+                       bool* end_of_stream,
+                       ErrorPtr* error) override;
+  bool WriteNonBlocking(const void* buffer,
+                        size_t size_to_write,
+                        size_t* size_written,
+                        ErrorPtr* error) override;
+  bool FlushBlocking(ErrorPtr* error) override;
+  bool CloseBlocking(ErrorPtr* error) override;
+  bool WaitForData(AccessMode mode,
+                   const base::Callback<void(AccessMode)>& callback,
+                   ErrorPtr* error) override;
+  bool WaitForDataBlocking(AccessMode in_mode,
+                           base::TimeDelta timeout,
+                           AccessMode* out_mode,
+                           ErrorPtr* error) override;
+  void CancelPendingAsyncOperations() override;
+
+ private:
+  class TlsStreamImpl;
+
+  // Private constructor called from TlsStream::Connect() factory method.
+  explicit TlsStream(std::unique_ptr<TlsStreamImpl> impl);
+
+  std::unique_ptr<TlsStreamImpl> impl_;
+  DISALLOW_COPY_AND_ASSIGN(TlsStream);
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_STREAMS_TLS_STREAM_H_
diff --git a/libbrillo/brillo/strings/string_utils.cc b/libbrillo/brillo/strings/string_utils.cc
new file mode 100644
index 0000000..8279a0e
--- /dev/null
+++ b/libbrillo/brillo/strings/string_utils.cc
@@ -0,0 +1,89 @@
+// Copyright 2014 The Chromium OS 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 <brillo/strings/string_utils.h>
+
+#include <algorithm>
+#include <string.h>
+#include <utility>
+
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+
+namespace brillo {
+namespace string_utils {
+
+std::vector<std::string> Split(const std::string& str,
+                               const std::string& delimiter,
+                               bool trim_whitespaces,
+                               bool purge_empty_strings) {
+  std::vector<std::string> tokens;
+  if (str.empty())
+    return tokens;
+
+  for (std::string::size_type i = 0;;) {
+    const std::string::size_type pos =
+        delimiter.empty() ? (i + 1) : str.find(delimiter, i);
+    std::string tmp_str{str.substr(i, pos - i)};
+    if (trim_whitespaces)
+      base::TrimWhitespaceASCII(tmp_str, base::TRIM_ALL, &tmp_str);
+    if (!tmp_str.empty() || !purge_empty_strings)
+      tokens.emplace_back(std::move(tmp_str));
+    if (pos >= str.size())
+      break;
+    i = pos + delimiter.size();
+  }
+  return tokens;
+}
+
+bool SplitAtFirst(const std::string& str,
+                  const std::string& delimiter,
+                  std::string* left_part,
+                  std::string* right_part,
+                  bool trim_whitespaces) {
+  bool delimiter_found = false;
+  std::string::size_type pos = str.find(delimiter);
+  if (pos != std::string::npos) {
+    *left_part = str.substr(0, pos);
+    *right_part = str.substr(pos + delimiter.size());
+    delimiter_found = true;
+  } else {
+    *left_part = str;
+    right_part->clear();
+  }
+
+  if (trim_whitespaces) {
+    base::TrimWhitespaceASCII(*left_part, base::TRIM_ALL, left_part);
+    base::TrimWhitespaceASCII(*right_part, base::TRIM_ALL, right_part);
+  }
+
+  return delimiter_found;
+}
+
+std::pair<std::string, std::string> SplitAtFirst(const std::string& str,
+                                                 const std::string& delimiter,
+                                                 bool trim_whitespaces) {
+  std::pair<std::string, std::string> pair;
+  SplitAtFirst(str, delimiter, &pair.first, &pair.second, trim_whitespaces);
+  return pair;
+}
+
+std::string ToString(double value) {
+  return base::StringPrintf("%g", value);
+}
+
+std::string ToString(bool value) {
+  return value ? "true" : "false";
+}
+
+std::string GetBytesAsString(const std::vector<uint8_t>& buffer) {
+  return std::string(buffer.begin(), buffer.end());
+}
+
+std::vector<uint8_t> GetStringAsBytes(const std::string& str) {
+  return std::vector<uint8_t>(str.begin(), str.end());
+}
+
+}  // namespace string_utils
+}  // namespace brillo
diff --git a/libbrillo/brillo/strings/string_utils.h b/libbrillo/brillo/strings/string_utils.h
new file mode 100644
index 0000000..6f1a934
--- /dev/null
+++ b/libbrillo/brillo/strings/string_utils.h
@@ -0,0 +1,131 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_STRINGS_STRING_UTILS_H_
+#define LIBBRILLO_BRILLO_STRINGS_STRING_UTILS_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+namespace string_utils {
+
+// Treats the string as a delimited list of substrings and returns the array
+// of original elements of the list.
+// |trim_whitespaces| causes each element to have all whitespaces trimmed off.
+// |purge_empty_strings| specifies whether empty elements from the original
+// string should be omitted.
+BRILLO_EXPORT std::vector<std::string> Split(const std::string& str,
+                                             const std::string& delimiter,
+                                             bool trim_whitespaces,
+                                             bool purge_empty_strings);
+// Splits the string, trims all whitespaces, omits empty string parts.
+inline std::vector<std::string> Split(const std::string& str,
+                                      const std::string& delimiter) {
+  return Split(str, delimiter, true, true);
+}
+// Splits the string, omits empty string parts.
+inline std::vector<std::string> Split(const std::string& str,
+                                      const std::string& delimiter,
+                                      bool trim_whitespaces) {
+  return Split(str, delimiter, trim_whitespaces, true);
+}
+
+// Splits the string into two pieces at the first position of the specified
+// delimiter.
+BRILLO_EXPORT std::pair<std::string, std::string> SplitAtFirst(
+    const std::string& str,
+    const std::string& delimiter,
+    bool trim_whitespaces);
+// Splits the string into two pieces at the first position of the specified
+// delimiter. Both parts have all whitespaces trimmed off.
+inline std::pair<std::string, std::string> SplitAtFirst(
+    const std::string& str,
+    const std::string& delimiter) {
+  return SplitAtFirst(str, delimiter, true);
+}
+
+// The following overload returns false if the delimiter was not found in the
+// source string. In this case, |left_part| will be set to |str| and
+// |right_part| will be empty.
+BRILLO_EXPORT bool SplitAtFirst(const std::string& str,
+                                const std::string& delimiter,
+                                std::string* left_part,
+                                std::string* right_part,
+                                bool trim_whitespaces);
+// Always trims the white spaces in the split parts.
+inline bool SplitAtFirst(const std::string& str,
+                         const std::string& delimiter,
+                         std::string* left_part,
+                         std::string* right_part) {
+  return SplitAtFirst(str, delimiter, left_part, right_part, true);
+}
+
+// Joins strings into a single string separated by |delimiter|.
+template <class InputIterator>
+std::string JoinRange(const std::string& delimiter,
+                      InputIterator first,
+                      InputIterator last) {
+  std::string result;
+  if (first == last)
+    return result;
+  result = *first;
+  for (++first; first != last; ++first) {
+    result += delimiter;
+    result += *first;
+  }
+  return result;
+}
+
+template <class Container>
+std::string Join(const std::string& delimiter, const Container& strings) {
+  using std::begin;
+  using std::end;
+  return JoinRange(delimiter, begin(strings), end(strings));
+}
+
+inline std::string Join(const std::string& delimiter,
+                        std::initializer_list<std::string> strings) {
+  return JoinRange(delimiter, strings.begin(), strings.end());
+}
+
+inline std::string Join(const std::string& delimiter,
+                        const std::string& str1,
+                        const std::string& str2) {
+  return str1 + delimiter + str2;
+}
+
+// string_utils::ToString() is a helper function to convert any scalar type
+// to a string. In most cases, it redirects the call to std::to_string with
+// two exceptions: for std::string itself and for double and bool.
+template <typename T>
+inline std::string ToString(T value) {
+  return std::to_string(value);
+}
+// Having the following overload is handy for templates where the type
+// of template parameter isn't known and could be a string itself.
+inline std::string ToString(std::string value) {
+  return value;
+}
+// We overload this for double because std::to_string(double) uses %f to
+// format the value and I would like to use a shorter %g format instead.
+BRILLO_EXPORT std::string ToString(double value);
+// And the bool to be converted as true/false instead of 1/0.
+BRILLO_EXPORT std::string ToString(bool value);
+
+// Converts a byte-array into a string. This method doesn't perform any
+// data re-encoding. It just takes every byte from the buffer and appends it
+// to the string as a character.
+BRILLO_EXPORT std::string GetBytesAsString(const std::vector<uint8_t>& buf);
+
+// Converts a string into a byte-array. Opposite of GetBytesAsString().
+BRILLO_EXPORT std::vector<uint8_t> GetStringAsBytes(const std::string& str);
+
+}  // namespace string_utils
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_STRINGS_STRING_UTILS_H_
diff --git a/libbrillo/brillo/strings/string_utils_unittest.cc b/libbrillo/brillo/strings/string_utils_unittest.cc
new file mode 100644
index 0000000..c554e74
--- /dev/null
+++ b/libbrillo/brillo/strings/string_utils_unittest.cc
@@ -0,0 +1,163 @@
+// Copyright (c) 2014 The Chromium OS 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 <brillo/strings/string_utils.h>
+
+#include <list>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+TEST(StringUtils, Split) {
+  std::vector<std::string> parts;
+
+  parts = string_utils::Split("", ",", false, false);
+  EXPECT_EQ(0, parts.size());
+
+  parts = string_utils::Split("abc", ",", false, false);
+  EXPECT_EQ(1, parts.size());
+  EXPECT_EQ("abc", parts[0]);
+
+  parts = string_utils::Split(",a,bc , d,  ,e, ", ",", true, true);
+  EXPECT_EQ(4, parts.size());
+  EXPECT_EQ("a", parts[0]);
+  EXPECT_EQ("bc", parts[1]);
+  EXPECT_EQ("d", parts[2]);
+  EXPECT_EQ("e", parts[3]);
+
+  parts = string_utils::Split(",a,bc , d,  ,e, ", ",", false, true);
+  EXPECT_EQ(6, parts.size());
+  EXPECT_EQ("a", parts[0]);
+  EXPECT_EQ("bc ", parts[1]);
+  EXPECT_EQ(" d", parts[2]);
+  EXPECT_EQ("  ", parts[3]);
+  EXPECT_EQ("e", parts[4]);
+  EXPECT_EQ(" ", parts[5]);
+
+  parts = string_utils::Split(",a,bc , d,  ,e, ", ",", true, false);
+  EXPECT_EQ(7, parts.size());
+  EXPECT_EQ("", parts[0]);
+  EXPECT_EQ("a", parts[1]);
+  EXPECT_EQ("bc", parts[2]);
+  EXPECT_EQ("d", parts[3]);
+  EXPECT_EQ("", parts[4]);
+  EXPECT_EQ("e", parts[5]);
+  EXPECT_EQ("", parts[6]);
+
+  parts = string_utils::Split(",a,bc , d,  ,e, ", ",", false, false);
+  EXPECT_EQ(7, parts.size());
+  EXPECT_EQ("", parts[0]);
+  EXPECT_EQ("a", parts[1]);
+  EXPECT_EQ("bc ", parts[2]);
+  EXPECT_EQ(" d", parts[3]);
+  EXPECT_EQ("  ", parts[4]);
+  EXPECT_EQ("e", parts[5]);
+  EXPECT_EQ(" ", parts[6]);
+
+  parts = string_utils::Split("abc:=xyz", ":=", false, false);
+  EXPECT_EQ(2, parts.size());
+  EXPECT_EQ("abc", parts[0]);
+  EXPECT_EQ("xyz", parts[1]);
+
+  parts = string_utils::Split("abc", "", false, false);
+  EXPECT_EQ(3, parts.size());
+  EXPECT_EQ("a", parts[0]);
+  EXPECT_EQ("b", parts[1]);
+  EXPECT_EQ("c", parts[2]);
+}
+
+TEST(StringUtils, SplitAtFirst) {
+  std::pair<std::string, std::string> pair;
+
+  pair = string_utils::SplitAtFirst(" 123 : 4 : 56 : 789 ", ":", true);
+  EXPECT_EQ("123", pair.first);
+  EXPECT_EQ("4 : 56 : 789", pair.second);
+
+  pair = string_utils::SplitAtFirst(" 123 : 4 : 56 : 789 ", ":", false);
+  EXPECT_EQ(" 123 ", pair.first);
+  EXPECT_EQ(" 4 : 56 : 789 ", pair.second);
+
+  pair = string_utils::SplitAtFirst("", "=");
+  EXPECT_EQ("", pair.first);
+  EXPECT_EQ("", pair.second);
+
+  pair = string_utils::SplitAtFirst("=", "=");
+  EXPECT_EQ("", pair.first);
+  EXPECT_EQ("", pair.second);
+
+  pair = string_utils::SplitAtFirst("a=", "=");
+  EXPECT_EQ("a", pair.first);
+  EXPECT_EQ("", pair.second);
+
+  pair = string_utils::SplitAtFirst("abc=", "=");
+  EXPECT_EQ("abc", pair.first);
+  EXPECT_EQ("", pair.second);
+
+  pair = string_utils::SplitAtFirst("=a", "=");
+  EXPECT_EQ("", pair.first);
+  EXPECT_EQ("a", pair.second);
+
+  pair = string_utils::SplitAtFirst("=abc=", "=");
+  EXPECT_EQ("", pair.first);
+  EXPECT_EQ("abc=", pair.second);
+
+  pair = string_utils::SplitAtFirst("abc", "=");
+  EXPECT_EQ("abc", pair.first);
+  EXPECT_EQ("", pair.second);
+
+  pair = string_utils::SplitAtFirst("abc:=xyz", ":=");
+  EXPECT_EQ("abc", pair.first);
+  EXPECT_EQ("xyz", pair.second);
+
+  pair = string_utils::SplitAtFirst("abc", "");
+  EXPECT_EQ("", pair.first);
+  EXPECT_EQ("abc", pair.second);
+}
+
+TEST(StringUtils, Join_String) {
+  EXPECT_EQ("", string_utils::Join(",", {}));
+  EXPECT_EQ("abc", string_utils::Join(",", {"abc"}));
+  EXPECT_EQ("abc,,xyz", string_utils::Join(",", {"abc", "", "xyz"}));
+  EXPECT_EQ("abc,defg", string_utils::Join(",", {"abc", "defg"}));
+  EXPECT_EQ("1 : 2 : 3", string_utils::Join(" : ", {"1", "2", "3"}));
+  EXPECT_EQ("1:2", string_utils::Join(":", std::set<std::string>{"1", "2"}));
+  EXPECT_EQ("1:2", string_utils::Join(":", std::vector<std::string>{"1", "2"}));
+  EXPECT_EQ("1:2", string_utils::Join(":", std::list<std::string>{"1", "2"}));
+  EXPECT_EQ("123", string_utils::Join("", {"1", "2", "3"}));
+}
+
+TEST(StringUtils, Join_Pair) {
+  EXPECT_EQ("ab,cd", string_utils::Join(",", "ab", "cd"));
+  EXPECT_EQ("key = value", string_utils::Join(" = ", "key", "value"));
+}
+
+TEST(StringUtils, GetBytesAsString) {
+  EXPECT_EQ("abc", string_utils::GetBytesAsString({'a', 'b', 'c'}));
+  EXPECT_TRUE(string_utils::GetBytesAsString({}).empty());
+  auto str = string_utils::GetBytesAsString({0xFF, 0x00, 0x01, 0x7F, 0x80});
+  ASSERT_EQ(5, str.size());
+  EXPECT_EQ('\xFF', str[0]);
+  EXPECT_EQ('\x00', str[1]);
+  EXPECT_EQ('\x01', str[2]);
+  EXPECT_EQ('\x7F', str[3]);
+  EXPECT_EQ('\x80', str[4]);
+}
+
+TEST(StringUtils, GetStringAsBytes) {
+  EXPECT_EQ((std::vector<uint8_t>{'a', 'b', 'c'}),
+            string_utils::GetStringAsBytes("abc"));
+  EXPECT_TRUE(string_utils::GetStringAsBytes("").empty());
+  auto buf = string_utils::GetStringAsBytes(std::string{"\x80\0\1\xFF", 4});
+  ASSERT_EQ(4, buf.size());
+  EXPECT_EQ(128, buf[0]);
+  EXPECT_EQ(0, buf[1]);
+  EXPECT_EQ(1, buf[2]);
+  EXPECT_EQ(255, buf[3]);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/syslog_logging.cc b/libbrillo/brillo/syslog_logging.cc
new file mode 100644
index 0000000..40b064a
--- /dev/null
+++ b/libbrillo/brillo/syslog_logging.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2012 The Chromium OS 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 "brillo/syslog_logging.h"
+
+#include <syslog.h>
+
+#include <string>
+
+// syslog.h and base/logging.h both try to #define LOG_INFO and LOG_WARNING.
+// We need to #undef at least these two before including base/logging.h.  The
+// others are included to be consistent.
+namespace {
+const int kSyslogDebug    = LOG_DEBUG;
+const int kSyslogInfo     = LOG_INFO;
+const int kSyslogWarning  = LOG_WARNING;
+const int kSyslogError    = LOG_ERR;
+const int kSyslogCritical = LOG_CRIT;
+
+#undef LOG_INFO
+#undef LOG_WARNING
+#undef LOG_ERR
+#undef LOG_CRIT
+}  // namespace
+
+#include <base/logging.h>
+
+static std::string s_ident;
+static std::string s_accumulated;
+static bool s_accumulate;
+static bool s_log_to_syslog;
+static bool s_log_to_stderr;
+static bool s_log_header;
+
+static bool HandleMessage(int severity,
+                          const char* /* file */,
+                          int /* line */,
+                          size_t message_start,
+                          const std::string& message) {
+  switch (severity) {
+    case logging::LOG_INFO:
+      severity = kSyslogInfo;
+      break;
+
+    case logging::LOG_WARNING:
+      severity = kSyslogWarning;
+      break;
+
+    case logging::LOG_ERROR:
+      severity = kSyslogError;
+      break;
+
+    case logging::LOG_FATAL:
+      severity = kSyslogCritical;
+      break;
+
+    default:
+      severity = kSyslogDebug;
+      break;
+  }
+
+  const char* str;
+  if (s_log_header) {
+    str = message.c_str();
+  } else {
+    str = message.c_str() + message_start;
+  }
+
+  if (s_log_to_syslog)
+    syslog(severity, "%s", str);
+  if (s_accumulate)
+    s_accumulated.append(str);
+  return !s_log_to_stderr && severity != kSyslogCritical;
+}
+
+namespace brillo {
+void SetLogFlags(int log_flags) {
+  s_log_to_syslog = (log_flags & kLogToSyslog) != 0;
+  s_log_to_stderr = (log_flags & kLogToStderr) != 0;
+  s_log_header = (log_flags & kLogHeader) != 0;
+}
+int GetLogFlags() {
+  int flags = 0;
+  flags |= (s_log_to_syslog) ? kLogToSyslog : 0;
+  flags |= (s_log_to_stderr) ? kLogToStderr : 0;
+  flags |= (s_log_header) ? kLogHeader : 0;
+  return flags;
+}
+void InitLog(int init_flags) {
+  logging::LoggingSettings settings;
+  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+  logging::InitLogging(settings);
+
+  const bool kOptionPID = false;
+  const bool kOptionTID = false;
+  const bool kOptionTimestamp = false;
+  const bool kOptionTickcount = false;
+  logging::SetLogItems(
+      kOptionPID, kOptionTID, kOptionTimestamp, kOptionTickcount);
+  logging::SetLogMessageHandler(HandleMessage);
+  SetLogFlags(init_flags);
+}
+void OpenLog(const char* ident, bool log_pid) {
+  s_ident = ident;
+  openlog(s_ident.c_str(), log_pid ? LOG_PID : 0, LOG_USER);
+}
+void LogToString(bool enabled) {
+  s_accumulate = enabled;
+}
+std::string GetLog() {
+  return s_accumulated;
+}
+void ClearLog() {
+  s_accumulated.clear();
+}
+bool FindLog(const char* string) {
+  return s_accumulated.find(string) != std::string::npos;
+}
+}  // namespace brillo
diff --git a/libbrillo/brillo/syslog_logging.h b/libbrillo/brillo/syslog_logging.h
new file mode 100644
index 0000000..b054259
--- /dev/null
+++ b/libbrillo/brillo/syslog_logging.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 The Chromium OS 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 LIBBRILLO_BRILLO_SYSLOG_LOGGING_H_
+#define LIBBRILLO_BRILLO_SYSLOG_LOGGING_H_
+
+#include <string>
+
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+enum InitFlags {
+  kLogToSyslog = 1,
+  kLogToStderr = 2,
+  kLogHeader = 4,
+};
+
+// Initialize logging subsystem.  |init_flags| is a bitfield, with bits defined
+// in InitFlags above.
+BRILLO_EXPORT void InitLog(int init_flags);
+// Gets the current logging flags.
+BRILLO_EXPORT int GetLogFlags();
+// Sets the current logging flags.
+BRILLO_EXPORT void SetLogFlags(int log_flags);
+// Convenience function for configuring syslog via openlog.  Users
+// could call openlog directly except for naming collisions between
+// base/logging.h and syslog.h.  Similarly users cannot pass the
+// normal parameters so we pick a representative set.  |log_pid|
+// causes pid to be logged with |ident|.
+BRILLO_EXPORT void OpenLog(const char* ident, bool log_pid);
+// Start accumulating the logs to a string.  This is inefficient, so
+// do not set to true if large numbers of log messages are coming.
+// Accumulated logs are only ever cleared when the clear function ings
+// called.
+BRILLO_EXPORT void LogToString(bool enabled);
+// Get the accumulated logs as a string.
+BRILLO_EXPORT std::string GetLog();
+// Clear the accumulated logs.
+BRILLO_EXPORT void ClearLog();
+// Returns true if the accumulated log contains the given string.  Useful
+// for testing.
+BRILLO_EXPORT bool FindLog(const char* string);
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_SYSLOG_LOGGING_H_
diff --git a/libbrillo/brillo/syslog_logging_unittest.cc b/libbrillo/brillo/syslog_logging_unittest.cc
new file mode 100644
index 0000000..e852e50
--- /dev/null
+++ b/libbrillo/brillo/syslog_logging_unittest.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium OS 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 <base/logging.h>
+#include <brillo/syslog_logging.h>
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+class SyslogLoggingDeathTest : public ::testing::Test {
+ public:
+  SyslogLoggingDeathTest() {}
+  virtual ~SyslogLoggingDeathTest() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SyslogLoggingDeathTest);
+};
+
+TEST_F(SyslogLoggingDeathTest, FatalLoggingIsFatal) {
+  int old_flags = GetLogFlags();
+  SetLogFlags(kLogToStderr);
+  EXPECT_DEATH({ LOG(FATAL) << "First Fatality!"; }, "First Fatality!");
+  // No flags == don't log to syslog, stderr, or accumulated string.
+  SetLogFlags(0);
+  // Still a fatal log message
+  EXPECT_DEATH({ LOG(FATAL) << "Second Fatality!"; }, "Second Fatality!");
+  SetLogFlags(old_flags);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/test_helpers.h b/libbrillo/brillo/test_helpers.h
new file mode 100644
index 0000000..815eede
--- /dev/null
+++ b/libbrillo/brillo/test_helpers.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 The Chromium OS 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 LIBBRILLO_BRILLO_TEST_HELPERS_H_
+#define LIBBRILLO_BRILLO_TEST_HELPERS_H_
+
+#include "gtest/gtest.h"
+
+#include <string>
+
+#include <base/command_line.h>
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/logging.h>
+
+#include "brillo/syslog_logging.h"
+
+inline void ExpectFileEquals(const char* golden, const char* file_path) {
+  std::string contents;
+  EXPECT_TRUE(base::ReadFileToString(base::FilePath(file_path), &contents));
+  EXPECT_EQ(golden, contents);
+}
+
+inline void SetUpTests(int* argc, char** argv, bool log_to_stderr) {
+  base::CommandLine::Init(*argc, argv);
+  ::brillo::InitLog(log_to_stderr ? brillo::kLogToStderr : 0);
+  ::brillo::LogToString(true);
+  ::testing::InitGoogleTest(argc, argv);
+}
+
+#endif  // LIBBRILLO_BRILLO_TEST_HELPERS_H_
diff --git a/libbrillo/brillo/type_name_undecorate.cc b/libbrillo/brillo/type_name_undecorate.cc
new file mode 100644
index 0000000..b588170
--- /dev/null
+++ b/libbrillo/brillo/type_name_undecorate.cc
@@ -0,0 +1,68 @@
+// Copyright 2014 The Chromium OS 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 <brillo/type_name_undecorate.h>
+
+#include <cstring>
+
+#ifdef __GNUG__
+#include <cstdlib>
+#include <cxxabi.h>
+#include <memory>
+#endif  // __GNUG__
+
+namespace brillo {
+
+std::string UndecorateTypeName(const char* type_name) {
+#ifdef __GNUG__
+  // Under g++ use abi::__cxa_demangle() to undecorate the type name.
+  int status = 0;
+
+  std::unique_ptr<char, decltype(&std::free)> res{
+      abi::__cxa_demangle(type_name, nullptr, nullptr, &status),
+      std::free
+  };
+
+  return (status == 0) ? res.get() : type_name;
+#else
+  // If not compiled with g++, do nothing...
+  // E.g. MSVC's type_info::name() already contains undecorated name.
+  return type_name;
+#endif
+}
+
+std::string GetUndecoratedTypeNameForTag(const char* type_tag) {
+#if defined(USE_RTTI_FOR_TYPE_TAGS) && \
+    (defined(__cpp_rtti) || defined(__GXX_RTTI))
+  return UndecorateTypeName(type_tag);
+#else
+  // The signature of type tag for, say, 'int' would be the following:
+  //    const char *brillo::GetTypeTag() [T = int]
+  // So we just need to extract the type name between '[T = ' and ']'.
+  const char* token = " = ";
+  const char* pos = std::strstr(type_tag, token);
+  if (!pos)
+    return type_tag;
+  std::string name = pos + std::strlen(token);
+  if (!name.empty() && name.back() == ']')
+    name.pop_back();
+  return name;
+#endif
+}
+
+// Implementations of the explicitly instantiated GetTypeTag<T>() for common
+// types.
+template const char* GetTypeTag<int8_t>();
+template const char* GetTypeTag<uint8_t>();
+template const char* GetTypeTag<int16_t>();
+template const char* GetTypeTag<uint16_t>();
+template const char* GetTypeTag<int32_t>();
+template const char* GetTypeTag<uint32_t>();
+template const char* GetTypeTag<int64_t>();
+template const char* GetTypeTag<uint64_t>();
+template const char* GetTypeTag<bool>();
+template const char* GetTypeTag<double>();
+template const char* GetTypeTag<std::string>();
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/type_name_undecorate.h b/libbrillo/brillo/type_name_undecorate.h
new file mode 100644
index 0000000..c750e58
--- /dev/null
+++ b/libbrillo/brillo/type_name_undecorate.h
@@ -0,0 +1,69 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_TYPE_NAME_UNDECORATE_H_
+#define LIBBRILLO_BRILLO_TYPE_NAME_UNDECORATE_H_
+
+#include <string>
+#include <typeinfo>
+
+#include <brillo/brillo_export.h>
+
+#if !defined(USE_RTTI_FOR_TYPE_TAGS) && !defined(__clang__)
+// When type information is used with RTTI disabled, we rely on
+// __PRETTY_FUNCTION__ macro for type tags. Unfortunately gcc and clang produce
+// different signatures for types that have optional template parameters, such
+// as std::vector and std::map. The problem arises when inter-operating between
+// libraries that are compiled with different compilers.
+// Since most of Brillo is compiled with clang, we choose clang here exclusively
+// and prevent this code from compiling with GCC to avoid hidden runtime errors.
+#error TypeInfo/Any with RTTI disabled is supported on clang compiler only.
+#endif
+
+namespace brillo {
+
+template<typename T>
+const char* GetTypeTag() {
+#if defined(USE_RTTI_FOR_TYPE_TAGS) && \
+    (defined(__cpp_rtti) || defined(__GXX_RTTI))
+  return typeid(T).name();
+#else
+  // __PRETTY_FUNCTION__ would include the type T signature and therefore each
+  // instance of brillo::internal_details::GetTypeTag<T>() will have a different
+  // tag string.
+  return __PRETTY_FUNCTION__;
+#endif
+}
+
+// Explicitly instantiate GetTypeTag<T>() for common types to minimize static
+// data segment pollution.
+extern template BRILLO_EXPORT const char* GetTypeTag<int8_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<uint8_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<int16_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<uint16_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<int32_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<uint32_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<int64_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<uint64_t>();
+extern template BRILLO_EXPORT const char* GetTypeTag<bool>();
+extern template BRILLO_EXPORT const char* GetTypeTag<double>();
+extern template BRILLO_EXPORT const char* GetTypeTag<std::string>();
+
+// Use brillo::UndecorateTypeName() to obtain human-readable type from
+// the decorated/mangled type name returned by std::type_info::name().
+BRILLO_EXPORT std::string UndecorateTypeName(const char* type_name);
+
+// Returns undecorated type name for the given type tag. This will extract the
+// actual type name from the type tag string.
+BRILLO_EXPORT std::string GetUndecoratedTypeNameForTag(const char* type_tag);
+
+// A template helper function that returns the undecorated type name for type T.
+template<typename T>
+inline std::string GetUndecoratedTypeName() {
+  return GetUndecoratedTypeNameForTag(GetTypeTag<T>());
+}
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_TYPE_NAME_UNDECORATE_H_
diff --git a/libbrillo/brillo/type_name_undecorate_unittest.cc b/libbrillo/brillo/type_name_undecorate_unittest.cc
new file mode 100644
index 0000000..604c0fb
--- /dev/null
+++ b/libbrillo/brillo/type_name_undecorate_unittest.cc
@@ -0,0 +1,67 @@
+// Copyright 2014 The Chromium OS 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 <brillo/type_name_undecorate.h>
+
+#include <brillo/variant_dictionary.h>
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+// Tests using tags from the __PRETTY_FUNCTION__ don't work when using RTTI
+// to get the type name.
+#ifndef USE_RTTI_FOR_TYPE_TAGS
+TEST(TypeTags, GetTypeTag) {
+  EXPECT_STREQ("const char *brillo::GetTypeTag() [T = int]", GetTypeTag<int>());
+  EXPECT_STREQ("const char *brillo::GetTypeTag() [T = std::__1::map<std::__1::"
+               "basic_string<char, std::__1::char_traits<char>, "
+               "std::__1::allocator<char> >, brillo::Any, std::__1::less<"
+               "std::__1::basic_string<char, std::__1::char_traits<char>, "
+               "std::__1::allocator<char> > >, std::__1::allocator<std::__1::"
+               "pair<const std::__1::basic_string<char, std::__1::char_traits"
+               "<char>, std::__1::allocator<char> >, brillo::Any> > >]",
+               GetTypeTag<VariantDictionary>());
+  EXPECT_STREQ("const char *brillo::GetTypeTag() [T = int []]",
+               GetTypeTag<int[]>());
+}
+#endif  // USE_RTTI_FOR_TYPE_TAGS
+
+TEST(TypeDecoration, UndecorateTypeName) {
+  EXPECT_EQ("int", UndecorateTypeName("i"));
+  EXPECT_EQ("char const* brillo::GetTypeTag<unsigned long long>()",
+            UndecorateTypeName("_ZN6brillo10GetTypeTagIyEEPKcv"));
+  EXPECT_EQ("std::__1::to_string(int)",
+            UndecorateTypeName("_ZNSt3__19to_stringEi"));
+}
+
+#ifndef USE_RTTI_FOR_TYPE_TAGS
+TEST(TypeDecoration, GetUndecoratedTypeNameForTag) {
+  EXPECT_EQ("int",
+            GetUndecoratedTypeNameForTag(
+                "const char *brillo::GetTypeTag() [T = int]"));
+  EXPECT_EQ("int []",
+            GetUndecoratedTypeNameForTag(
+                "const char *brillo::GetTypeTag() [T = int []]"));
+  EXPECT_EQ("foo::bar<int []>()",
+            GetUndecoratedTypeNameForTag(
+                "const char *brillo::GetTypeTag() [T = foo::bar<int []>()]"));
+}
+
+TEST(TypeDecoration, GetUndecoratedTypeName) {
+  EXPECT_EQ("int", GetUndecoratedTypeName<int>());
+  EXPECT_EQ("int *", GetUndecoratedTypeName<int*>());
+  EXPECT_EQ("const int *", GetUndecoratedTypeName<const int*>());
+  EXPECT_EQ("int []", GetUndecoratedTypeName<int[]>());
+  EXPECT_EQ("bool", GetUndecoratedTypeName<bool>());
+  EXPECT_EQ("char", GetUndecoratedTypeName<char>());
+  EXPECT_EQ("float", GetUndecoratedTypeName<float>());
+  EXPECT_EQ("double", GetUndecoratedTypeName<double>());
+  EXPECT_EQ("long", GetUndecoratedTypeName<long>());
+  EXPECT_EQ("std::__1::map<int, double, std::__1::less<int>, "
+            "std::__1::allocator<std::__1::pair<const int, double> > >",
+            (GetUndecoratedTypeName<std::map<int, double>>()));
+}
+#endif  // USE_RTTI_FOR_TYPE_TAGS
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/unittest_utils.cc b/libbrillo/brillo/unittest_utils.cc
new file mode 100644
index 0000000..7cace5d
--- /dev/null
+++ b/libbrillo/brillo/unittest_utils.cc
@@ -0,0 +1,53 @@
+// Copyright 2014 The Chromium OS 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 <brillo/unittest_utils.h>
+
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <base/logging.h>
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+const int ScopedPipe::kPipeSize = 4096;
+
+ScopedPipe::ScopedPipe() {
+  int fds[2];
+  if (pipe(fds) != 0) {
+    PLOG(FATAL) << "Creating a pipe()";
+  }
+  reader = fds[0];
+  writer = fds[1];
+  EXPECT_EQ(kPipeSize, fcntl(writer, F_SETPIPE_SZ, kPipeSize));
+}
+
+ScopedPipe::~ScopedPipe() {
+  if (reader != -1)
+    close(reader);
+  if (writer != -1)
+    close(writer);
+}
+
+
+ScopedSocketPair::ScopedSocketPair() {
+  int fds[2];
+  if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) != 0) {
+    PLOG(FATAL) << "Creating a socketpair()";
+  }
+  left = fds[0];
+  right = fds[1];
+}
+
+ScopedSocketPair::~ScopedSocketPair() {
+  if (left != -1)
+    close(left);
+  if (right != -1)
+    close(right);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/unittest_utils.h b/libbrillo/brillo/unittest_utils.h
new file mode 100644
index 0000000..a7f92db
--- /dev/null
+++ b/libbrillo/brillo/unittest_utils.h
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Internal implementation of brillo::Any class.
+
+#ifndef LIBBRILLO_BRILLO_UNITTEST_UTILS_H_
+#define LIBBRILLO_BRILLO_UNITTEST_UTILS_H_
+
+namespace brillo {
+
+// Helper class to create and close a unidirectional pipe. The file descriptors
+// will be closed on destruction, unless set to -1.
+class ScopedPipe {
+ public:
+  // The internal pipe size.
+  static const int kPipeSize;
+
+  ScopedPipe();
+  ~ScopedPipe();
+
+  // The reader and writer end of the pipe.
+  int reader{-1};
+  int writer{-1};
+};
+
+// Helper class to create and close a bi-directional pair of sockets. The
+// sockets will be closed on destruction, unless set to -1.
+class ScopedSocketPair {
+ public:
+  ScopedSocketPair();
+  ~ScopedSocketPair();
+
+  // The left and right sockets are bi-directional connected and
+  // indistinguishable file descriptor. We named them left/right for easier
+  // reading.
+  int left{-1};
+  int right{-1};
+};
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_UNITTEST_UTILS_H_
diff --git a/libbrillo/brillo/url_utils.cc b/libbrillo/brillo/url_utils.cc
new file mode 100644
index 0000000..eba7db8
--- /dev/null
+++ b/libbrillo/brillo/url_utils.cc
@@ -0,0 +1,166 @@
+// Copyright 2014 The Chromium OS 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 <brillo/url_utils.h>
+
+#include <algorithm>
+
+namespace {
+// Given a URL string, determine where the query string starts and ends.
+// URLs have schema, domain and path (along with possible user name, password
+// and port number which are of no interest for us here) which could optionally
+// have a query string that is separated from the path by '?'. Finally, the URL
+// could also have a '#'-separated URL fragment which is usually used by the
+// browser as a bookmark element. So, for example:
+//    http://server.com/path/to/object?k=v&foo=bar#fragment
+// Here:
+//    http://server.com/path/to/object - is the URL of the object,
+//    ?k=v&foo=bar                     - URL query string
+//    #fragment                        - URL fragment string
+// If |exclude_fragment| is true, the function returns the start character and
+// the length of the query string alone. If it is false, the query string length
+// will include both the query string and the fragment.
+bool GetQueryStringPos(const std::string& url,
+                       bool exclude_fragment,
+                       size_t* query_pos,
+                       size_t* query_len) {
+  size_t query_start = url.find_first_of("?#");
+  if (query_start == std::string::npos) {
+    *query_pos = url.size();
+    if (query_len)
+      *query_len = 0;
+    return false;
+  }
+
+  *query_pos = query_start;
+  if (query_len) {
+    size_t query_end = url.size();
+
+    if (exclude_fragment) {
+      if (url[query_start] == '?') {
+        size_t pos_fragment = url.find('#', query_start);
+        if (pos_fragment != std::string::npos)
+          query_end = pos_fragment;
+      } else {
+        query_end = query_start;
+      }
+    }
+    *query_len = query_end - query_start;
+  }
+  return true;
+}
+}  // anonymous namespace
+
+namespace brillo {
+
+std::string url::TrimOffQueryString(std::string* url) {
+  size_t query_pos;
+  if (!GetQueryStringPos(*url, false, &query_pos, nullptr))
+    return std::string();
+  std::string query_string = url->substr(query_pos);
+  url->resize(query_pos);
+  return query_string;
+}
+
+std::string url::Combine(const std::string& url, const std::string& subpath) {
+  return CombineMultiple(url, {subpath});
+}
+
+std::string url::CombineMultiple(const std::string& url,
+                                 const std::vector<std::string>& parts) {
+  std::string result = url;
+  if (!parts.empty()) {
+    std::string query_string = TrimOffQueryString(&result);
+    for (const auto& part : parts) {
+      if (!part.empty()) {
+        if (!result.empty() && result.back() != '/')
+          result += '/';
+        size_t non_slash_pos = part.find_first_not_of('/');
+        if (non_slash_pos != std::string::npos)
+          result += part.substr(non_slash_pos);
+      }
+    }
+    result += query_string;
+  }
+  return result;
+}
+
+std::string url::GetQueryString(const std::string& url, bool remove_fragment) {
+  std::string query_string;
+  size_t query_pos, query_len;
+  if (GetQueryStringPos(url, remove_fragment, &query_pos, &query_len)) {
+    query_string = url.substr(query_pos, query_len);
+  }
+  return query_string;
+}
+
+data_encoding::WebParamList url::GetQueryStringParameters(
+    const std::string& url) {
+  // Extract the query string and remove the leading '?'.
+  std::string query_string = GetQueryString(url, true);
+  if (!query_string.empty() && query_string.front() == '?')
+    query_string.erase(query_string.begin());
+  return data_encoding::WebParamsDecode(query_string);
+}
+
+std::string url::GetQueryStringValue(const std::string& url,
+                                     const std::string& name) {
+  return GetQueryStringValue(GetQueryStringParameters(url), name);
+}
+
+std::string url::GetQueryStringValue(const data_encoding::WebParamList& params,
+                                     const std::string& name) {
+  for (const auto& pair : params) {
+    if (name.compare(pair.first) == 0)
+      return pair.second;
+  }
+  return std::string();
+}
+
+std::string url::RemoveQueryString(const std::string& url,
+                                   bool remove_fragment_too) {
+  size_t query_pos, query_len;
+  if (!GetQueryStringPos(url, !remove_fragment_too, &query_pos, &query_len))
+    return url;
+  std::string result = url.substr(0, query_pos);
+  size_t fragment_pos = query_pos + query_len;
+  if (fragment_pos < url.size()) {
+    result += url.substr(fragment_pos);
+  }
+  return result;
+}
+
+std::string url::AppendQueryParam(const std::string& url,
+                                  const std::string& name,
+                                  const std::string& value) {
+  return AppendQueryParams(url, {{name, value}});
+}
+
+std::string url::AppendQueryParams(const std::string& url,
+                                   const data_encoding::WebParamList& params) {
+  if (params.empty())
+    return url;
+  size_t query_pos, query_len;
+  GetQueryStringPos(url, true, &query_pos, &query_len);
+  size_t fragment_pos = query_pos + query_len;
+  std::string result = url.substr(0, fragment_pos);
+  if (query_len == 0) {
+    result += '?';
+  } else if (query_len > 1) {
+    result += '&';
+  }
+  result += data_encoding::WebParamsEncode(params);
+  if (fragment_pos < url.size()) {
+    result += url.substr(fragment_pos);
+  }
+  return result;
+}
+
+bool url::HasQueryString(const std::string& url) {
+  size_t query_pos, query_len;
+  GetQueryStringPos(url, true, &query_pos, &query_len);
+  return (query_len > 0);
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/url_utils.h b/libbrillo/brillo/url_utils.h
new file mode 100644
index 0000000..fd66dd6
--- /dev/null
+++ b/libbrillo/brillo/url_utils.h
@@ -0,0 +1,85 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_URL_UTILS_H_
+#define LIBBRILLO_BRILLO_URL_UTILS_H_
+
+#include <string>
+#include <vector>
+
+#include <base/compiler_specific.h>
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+#include <brillo/data_encoding.h>
+
+namespace brillo {
+
+namespace url {
+
+// Appends a subpath to url and delimiting then with '/' if the path doesn't
+// end with it already. Also handles URLs with query parameters/fragment.
+BRILLO_EXPORT std::string Combine(
+    const std::string& url,
+    const std::string& subpath) WARN_UNUSED_RESULT;
+BRILLO_EXPORT std::string CombineMultiple(
+    const std::string& url,
+    const std::vector<std::string>& parts) WARN_UNUSED_RESULT;
+
+// Removes the query string/fragment from |url| and returns the query string.
+// This method actually modifies |url|. So, if you call it on this:
+//    http://www.test.org/?foo=bar
+// it will modify |url| to "http://www.test.org/" and return "?foo=bar"
+BRILLO_EXPORT std::string TrimOffQueryString(std::string* url);
+
+// Returns the query string, if available.
+// For example, for the following URL:
+//    http://server.com/path/to/object?k=v&foo=bar#fragment
+// Here:
+//    http://server.com/path/to/object - is the URL of the object,
+//    ?k=v&foo=bar                     - URL query string
+//    #fragment                        - URL fragment string
+// If |remove_fragment| is true, the function returns the query string without
+// the fragment. Otherwise the fragment is included as part of the result.
+BRILLO_EXPORT std::string GetQueryString(const std::string& url,
+                                         bool remove_fragment);
+
+// Parses the query string into a set of key-value pairs.
+BRILLO_EXPORT data_encoding::WebParamList GetQueryStringParameters(
+    const std::string& url);
+
+// Returns a value of the specified query parameter, or empty string if missing.
+BRILLO_EXPORT std::string GetQueryStringValue(
+    const std::string& url,
+    const std::string& name);
+BRILLO_EXPORT std::string GetQueryStringValue(
+    const data_encoding::WebParamList& params,
+    const std::string& name);
+
+// Removes the query string and/or a fragment part from URL.
+// If |remove_fragment| is specified, the fragment is also removed.
+// For example:
+//    http://server.com/path/to/object?k=v&foo=bar#fragment
+// true  -> http://server.com/path/to/object
+// false -> http://server.com/path/to/object#fragment
+BRILLO_EXPORT std::string RemoveQueryString(
+    const std::string& url,
+    bool remove_fragment) WARN_UNUSED_RESULT;
+
+// Appends a single query parameter to the URL.
+BRILLO_EXPORT std::string AppendQueryParam(
+    const std::string& url,
+    const std::string& name,
+    const std::string& value) WARN_UNUSED_RESULT;
+// Appends a list of query parameters to the URL.
+BRILLO_EXPORT std::string AppendQueryParams(
+    const std::string& url,
+    const data_encoding::WebParamList& params) WARN_UNUSED_RESULT;
+
+// Checks if the URL has query parameters.
+BRILLO_EXPORT bool HasQueryString(const std::string& url);
+
+}  // namespace url
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_URL_UTILS_H_
diff --git a/libbrillo/brillo/url_utils_unittest.cc b/libbrillo/brillo/url_utils_unittest.cc
new file mode 100644
index 0000000..a2603cb
--- /dev/null
+++ b/libbrillo/brillo/url_utils_unittest.cc
@@ -0,0 +1,146 @@
+// Copyright (c) 2014 The Chromium OS 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 <brillo/url_utils.h>
+
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+TEST(UrlUtils, Combine) {
+  EXPECT_EQ("http://sample.org/path",
+            url::Combine("http://sample.org", "path"));
+  EXPECT_EQ("http://sample.org/path",
+            url::Combine("http://sample.org/", "path"));
+  EXPECT_EQ("path1/path2", url::Combine("", "path1/path2"));
+  EXPECT_EQ("path1/path2", url::Combine("path1", "path2"));
+  EXPECT_EQ("http://sample.org", url::Combine("http://sample.org", ""));
+  EXPECT_EQ("http://sample.org/path",
+            url::Combine("http://sample.org/", "/path"));
+  EXPECT_EQ("http://sample.org/path",
+            url::Combine("http://sample.org", "//////path"));
+  EXPECT_EQ("http://sample.org/", url::Combine("http://sample.org", "///"));
+  EXPECT_EQ("http://sample.org/obj/path1/path2",
+            url::Combine("http://sample.org/obj", "path1/path2"));
+  EXPECT_EQ("http://sample.org/obj/path1/path2#tag",
+            url::Combine("http://sample.org/obj#tag", "path1/path2"));
+  EXPECT_EQ("http://sample.org/obj/path1/path2?k1=v1&k2=v2",
+            url::Combine("http://sample.org/obj?k1=v1&k2=v2", "path1/path2"));
+  EXPECT_EQ("http://sample.org/obj/path1/path2?k1=v1#k2=v2",
+            url::Combine("http://sample.org/obj/?k1=v1#k2=v2", "path1/path2"));
+  EXPECT_EQ("http://sample.org/obj/path1/path2#tag?",
+            url::Combine("http://sample.org/obj#tag?", "path1/path2"));
+  EXPECT_EQ("path1/path2", url::CombineMultiple("", {"path1", "path2"}));
+  EXPECT_EQ("http://sample.org/obj/part1/part2",
+            url::CombineMultiple("http://sample.org",
+                                 {"obj", "", "/part1/", "part2"}));
+}
+
+TEST(UrlUtils, GetQueryString) {
+  EXPECT_EQ("", url::GetQueryString("http://sample.org", false));
+  EXPECT_EQ("", url::GetQueryString("http://sample.org", true));
+  EXPECT_EQ("", url::GetQueryString("", false));
+  EXPECT_EQ("", url::GetQueryString("", true));
+
+  EXPECT_EQ("?q=v&b=2#tag?2",
+            url::GetQueryString("http://s.com/?q=v&b=2#tag?2", false));
+  EXPECT_EQ("?q=v&b=2",
+            url::GetQueryString("http://s.com/?q=v&b=2#tag?2", true));
+
+  EXPECT_EQ("#tag?a=2", url::GetQueryString("http://s.com/#tag?a=2", false));
+  EXPECT_EQ("", url::GetQueryString("http://s.com/#tag?a=2", true));
+
+  EXPECT_EQ("?a=2&b=2", url::GetQueryString("?a=2&b=2", false));
+  EXPECT_EQ("?a=2&b=2", url::GetQueryString("?a=2&b=2", true));
+
+  EXPECT_EQ("#s#?d#?f?#s?#d", url::GetQueryString("#s#?d#?f?#s?#d", false));
+  EXPECT_EQ("", url::GetQueryString("#s#?d#?f?#s?#d", true));
+}
+
+TEST(UrlUtils, GetQueryStringParameters) {
+  auto params = url::GetQueryStringParameters(
+      "http://sample.org/path?k=v&&%3Dkey%3D=val%26&r#blah");
+
+  EXPECT_EQ(3, params.size());
+  EXPECT_EQ("k", params[0].first);
+  EXPECT_EQ("v", params[0].second);
+  EXPECT_EQ("=key=", params[1].first);
+  EXPECT_EQ("val&", params[1].second);
+  EXPECT_EQ("r", params[2].first);
+  EXPECT_EQ("", params[2].second);
+}
+
+TEST(UrlUtils, GetQueryStringValue) {
+  std::string url = "http://url?key1=val1&&key2=val2";
+  EXPECT_EQ("val1", url::GetQueryStringValue(url, "key1"));
+  EXPECT_EQ("val2", url::GetQueryStringValue(url, "key2"));
+  EXPECT_EQ("", url::GetQueryStringValue(url, "key3"));
+
+  auto params = url::GetQueryStringParameters(url);
+  EXPECT_EQ("val1", url::GetQueryStringValue(params, "key1"));
+  EXPECT_EQ("val2", url::GetQueryStringValue(params, "key2"));
+  EXPECT_EQ("", url::GetQueryStringValue(params, "key3"));
+}
+
+TEST(UrlUtils, TrimOffQueryString) {
+  std::string url = "http://url?key1=val1&key2=val2#fragment";
+  std::string query = url::TrimOffQueryString(&url);
+  EXPECT_EQ("http://url", url);
+  EXPECT_EQ("?key1=val1&key2=val2#fragment", query);
+
+  url = "http://url#fragment";
+  query = url::TrimOffQueryString(&url);
+  EXPECT_EQ("http://url", url);
+  EXPECT_EQ("#fragment", query);
+
+  url = "http://url";
+  query = url::TrimOffQueryString(&url);
+  EXPECT_EQ("http://url", url);
+  EXPECT_EQ("", query);
+}
+
+TEST(UrlUtils, RemoveQueryString) {
+  std::string url = "http://url?key1=val1&key2=val2#fragment";
+  EXPECT_EQ("http://url", url::RemoveQueryString(url, true));
+  EXPECT_EQ("http://url#fragment", url::RemoveQueryString(url, false));
+}
+
+TEST(UrlUtils, AppendQueryParam) {
+  std::string url = "http://server.com/path";
+  url = url::AppendQueryParam(url, "param", "value");
+  EXPECT_EQ("http://server.com/path?param=value", url);
+  url = url::AppendQueryParam(url, "param2", "v");
+  EXPECT_EQ("http://server.com/path?param=value&param2=v", url);
+
+  url = "http://server.com/path#fragment";
+  url = url::AppendQueryParam(url, "param", "value");
+  EXPECT_EQ("http://server.com/path?param=value#fragment", url);
+  url = url::AppendQueryParam(url, "param2", "v");
+  EXPECT_EQ("http://server.com/path?param=value&param2=v#fragment", url);
+
+  url = url::AppendQueryParam("http://server.com/path?", "param", "value");
+  EXPECT_EQ("http://server.com/path?param=value", url);
+}
+
+TEST(UrlUtils, AppendQueryParams) {
+  std::string url = "http://server.com/path";
+  url = url::AppendQueryParams(url, {});
+  EXPECT_EQ("http://server.com/path", url);
+  url = url::AppendQueryParams(url, {{"param", "value"}, {"q", "="}});
+  EXPECT_EQ("http://server.com/path?param=value&q=%3D", url);
+  url += "#fr?";
+  url = url::AppendQueryParams(url, {{"p", "1"}, {"s&", "\n"}});
+  EXPECT_EQ("http://server.com/path?param=value&q=%3D&p=1&s%26=%0A#fr?", url);
+}
+
+TEST(UrlUtils, HasQueryString) {
+  EXPECT_FALSE(url::HasQueryString("http://server.com/path"));
+  EXPECT_FALSE(url::HasQueryString("http://server.com/path#blah?v=1"));
+  EXPECT_TRUE(url::HasQueryString("http://server.com/path?v=1#blah"));
+  EXPECT_TRUE(url::HasQueryString("http://server.com/path?v=1"));
+  EXPECT_FALSE(url::HasQueryString(""));
+  EXPECT_TRUE(url::HasQueryString("?ss"));
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/userdb_utils.cc b/libbrillo/brillo/userdb_utils.cc
new file mode 100644
index 0000000..55c964c
--- /dev/null
+++ b/libbrillo/brillo/userdb_utils.cc
@@ -0,0 +1,56 @@
+// Copyright 2015 The Chromium OS 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 "brillo/userdb_utils.h"
+
+#include <grp.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include <base/logging.h>
+
+namespace brillo {
+namespace userdb {
+
+bool GetUserInfo(const std::string& user, uid_t* uid, gid_t* gid) {
+  ssize_t buf_len = sysconf(_SC_GETPW_R_SIZE_MAX);
+  if (buf_len < 0)
+    buf_len = 16384;  // 16K should be enough?...
+  passwd pwd_buf;
+  passwd* pwd = nullptr;
+  std::vector<char> buf(buf_len);
+  if (getpwnam_r(user.c_str(), &pwd_buf, buf.data(), buf_len, &pwd) || !pwd) {
+    PLOG(ERROR) << "Unable to find user " << user;
+    return false;
+  }
+
+  if (uid)
+    *uid = pwd->pw_uid;
+  if (gid)
+    *gid = pwd->pw_gid;
+  return true;
+}
+
+bool GetGroupInfo(const std::string& group, gid_t* gid) {
+  ssize_t buf_len = sysconf(_SC_GETGR_R_SIZE_MAX);
+  if (buf_len < 0)
+    buf_len = 16384;  // 16K should be enough?...
+  struct group grp_buf;
+  struct group* grp = nullptr;
+  std::vector<char> buf(buf_len);
+  if (getgrnam_r(group.c_str(), &grp_buf, buf.data(), buf_len, &grp) || !grp) {
+    PLOG(ERROR) << "Unable to find group " << group;
+    return false;
+  }
+
+  if (gid)
+    *gid = grp->gr_gid;
+  return true;
+}
+
+}  // namespace userdb
+}  // namespace brillo
diff --git a/libbrillo/brillo/userdb_utils.h b/libbrillo/brillo/userdb_utils.h
new file mode 100644
index 0000000..8d6dc20
--- /dev/null
+++ b/libbrillo/brillo/userdb_utils.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_USERDB_UTILS_H_
+#define LIBBRILLO_BRILLO_USERDB_UTILS_H_
+
+#include <sys/types.h>
+
+#include <string>
+
+#include <base/compiler_specific.h>
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+namespace userdb {
+
+// Looks up the UID and GID corresponding to |user|. Returns true on success.
+// Passing nullptr for |uid| or |gid| causes them to be ignored.
+BRILLO_EXPORT bool GetUserInfo(
+    const std::string& user, uid_t* uid, gid_t* gid) WARN_UNUSED_RESULT;
+
+// Looks up the GID corresponding to |group|. Returns true on success.
+// Passing nullptr for |gid| causes it to be ignored.
+BRILLO_EXPORT bool GetGroupInfo(
+    const std::string& group, gid_t* gid) WARN_UNUSED_RESULT;
+
+}  // namespace userdb
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_USERDB_UTILS_H_
diff --git a/libbrillo/brillo/value_conversion.cc b/libbrillo/brillo/value_conversion.cc
new file mode 100644
index 0000000..aa5135b
--- /dev/null
+++ b/libbrillo/brillo/value_conversion.cc
@@ -0,0 +1,60 @@
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <brillo/value_conversion.h>
+
+#include <string>
+#include <vector>
+
+namespace brillo {
+
+bool FromValue(const base::Value& in_value,
+               std::unique_ptr<base::ListValue>* out_value) {
+  const base::ListValue* list = nullptr;
+  if (!in_value.GetAsList(&list))
+    return false;
+  out_value->reset(list->DeepCopy());
+  return true;
+}
+
+bool FromValue(const base::Value& in_value,
+               std::unique_ptr<base::DictionaryValue>* out_value) {
+  const base::DictionaryValue* dict = nullptr;
+  if (!in_value.GetAsDictionary(&dict))
+    return false;
+  out_value->reset(dict->DeepCopy());
+  return true;
+}
+
+std::unique_ptr<base::Value> ToValue(int value) {
+  return std::unique_ptr<base::Value>{new base::FundamentalValue{value}};
+}
+
+std::unique_ptr<base::Value> ToValue(bool value) {
+  return std::unique_ptr<base::Value>{new base::FundamentalValue{value}};
+}
+
+std::unique_ptr<base::Value> ToValue(double value) {
+  return std::unique_ptr<base::Value>{new base::FundamentalValue{value}};
+}
+
+std::unique_ptr<base::Value> ToValue(const char* value) {
+  return std::unique_ptr<base::Value>{new base::StringValue{value}};
+}
+
+std::unique_ptr<base::Value> ToValue(const std::string& value) {
+  return std::unique_ptr<base::Value>{new base::StringValue{value}};
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/value_conversion.h b/libbrillo/brillo/value_conversion.h
new file mode 100644
index 0000000..d681f76
--- /dev/null
+++ b/libbrillo/brillo/value_conversion.h
@@ -0,0 +1,137 @@
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef BRILLO_VALUE_CONVERSION_H_
+#define BRILLO_VALUE_CONVERSION_H_
+
+// This file provides a set of helper functions to convert between base::Value
+// and native types. Apart from handling standard types such as 'int' and
+// 'std::string' it also provides conversion to/from std::vector<T> (which
+// converts to Base::listValue) and std::map<std::string, T> (convertible to
+// base::DictionaryValue).
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/values.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+inline bool FromValue(const base::Value& in_value, bool* out_value) {
+  return in_value.GetAsBoolean(out_value);
+}
+
+inline bool FromValue(const base::Value& in_value, int* out_value) {
+  return in_value.GetAsInteger(out_value);
+}
+
+inline bool FromValue(const base::Value& in_value, double* out_value) {
+  return in_value.GetAsDouble(out_value);
+}
+
+inline bool FromValue(const base::Value& in_value, std::string* out_value) {
+  return in_value.GetAsString(out_value);
+}
+
+inline bool FromValue(const base::Value& in_value,
+                      const base::ListValue** out_value) {
+  return in_value.GetAsList(out_value);
+}
+
+inline bool FromValue(const base::Value& in_value,
+                      const base::DictionaryValue** out_value) {
+  return in_value.GetAsDictionary(out_value);
+}
+
+BRILLO_EXPORT bool FromValue(const base::Value& in_value,
+                             std::unique_ptr<base::ListValue>* out_value);
+BRILLO_EXPORT bool FromValue(const base::Value& in_value,
+                             std::unique_ptr<base::DictionaryValue>* out_value);
+
+template <typename T, typename Pred, typename Alloc>
+bool FromValue(const base::Value& in_value,
+              std::map<std::string, T, Pred, Alloc>* out_value);
+
+template <typename T, typename Alloc>
+bool FromValue(const base::Value& in_value, std::vector<T, Alloc>* out_value) {
+  const base::ListValue* list = nullptr;
+  if (!in_value.GetAsList(&list))
+    return false;
+  out_value->clear();
+  out_value->reserve(list->GetSize());
+  for (const auto& item : *list) {
+    T value{};
+    if (!FromValue(*item, &value))
+      return false;
+    out_value->push_back(std::move(value));
+  }
+  return true;
+}
+
+template <typename T, typename Pred, typename Alloc>
+bool FromValue(const base::Value& in_value,
+              std::map<std::string, T, Pred, Alloc>* out_value) {
+  const base::DictionaryValue* dict = nullptr;
+  if (!in_value.GetAsDictionary(&dict))
+    return false;
+  out_value->clear();
+  for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
+    if (!FromValue(it.value(), &(*out_value)[it.key()]))
+      return false;
+  }
+  return true;
+}
+
+template <typename T>
+T FromValue(const base::Value& value) {
+  T out_value{};
+  CHECK(FromValue(value, &out_value));
+  return out_value;
+}
+
+BRILLO_EXPORT std::unique_ptr<base::Value> ToValue(int value);
+BRILLO_EXPORT std::unique_ptr<base::Value> ToValue(bool value);
+BRILLO_EXPORT std::unique_ptr<base::Value> ToValue(double value);
+BRILLO_EXPORT std::unique_ptr<base::Value> ToValue(const std::string& value);
+// Implicit conversion of char* to 'bool' has precedence over the user-defined
+// std::string conversion. Override this behavior explicitly.
+BRILLO_EXPORT std::unique_ptr<base::Value> ToValue(const char* value);
+
+template <typename T, typename Pred, typename Alloc>
+std::unique_ptr<base::Value> ToValue(
+    const std::map<std::string, T, Pred, Alloc>& dictionary);
+
+template <typename T, typename Alloc>
+std::unique_ptr<base::Value> ToValue(const std::vector<T, Alloc>& list) {
+  std::unique_ptr<base::ListValue> result{new base::ListValue};
+  for (const auto& value : list)
+    result->Append(ToValue(value));
+  return std::move(result);
+}
+
+template <typename T, typename Pred, typename Alloc>
+std::unique_ptr<base::Value> ToValue(
+    const std::map<std::string, T, Pred, Alloc>& dictionary) {
+  std::unique_ptr<base::DictionaryValue> result{new base::DictionaryValue};
+  for (const auto& pair : dictionary)
+    result->Set(pair.first, ToValue(pair.second));
+  return std::move(result);
+}
+
+}  // namespace brillo
+
+#endif  // BRILLO_VALUE_CONVERSION_H_
diff --git a/libbrillo/brillo/value_conversion_unittest.cc b/libbrillo/brillo/value_conversion_unittest.cc
new file mode 100644
index 0000000..aa1be2a
--- /dev/null
+++ b/libbrillo/brillo/value_conversion_unittest.cc
@@ -0,0 +1,265 @@
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <brillo/value_conversion.h>
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/json/json_reader.h>
+#include <base/json/json_writer.h>
+#include <gtest/gtest.h>
+
+namespace brillo {
+
+namespace {
+
+std::unique_ptr<base::Value> ParseValue(std::string json) {
+  std::replace(json.begin(), json.end(), '\'', '"');
+  std::string message;
+  auto value = base::JSONReader::ReadAndReturnError(json, base::JSON_PARSE_RFC,
+                                                    nullptr, &message);
+  CHECK(value) << "Failed to load JSON: " << message << ", " << json;
+  return value;
+}
+
+inline bool IsEqualValue(const base::Value& val1, const base::Value& val2) {
+  return val1.Equals(&val2);
+}
+
+#define EXPECT_JSON_EQ(expected, actual) \
+  EXPECT_PRED2(IsEqualValue, *ParseValue(expected), actual)
+
+}  // namespace
+
+TEST(ValueConversionTest, FromValueInt) {
+  int actual;
+  EXPECT_TRUE(FromValue(*ParseValue("123"), &actual));
+  EXPECT_EQ(123, actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("-123"), &actual));
+  EXPECT_EQ(-123, actual);
+
+  EXPECT_FALSE(FromValue(*ParseValue("true"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueBool) {
+  bool actual;
+  EXPECT_TRUE(FromValue(*ParseValue("false"), &actual));
+  EXPECT_FALSE(actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("true"), &actual));
+  EXPECT_TRUE(actual);
+
+  EXPECT_FALSE(FromValue(*ParseValue("0"), &actual));
+  EXPECT_FALSE(FromValue(*ParseValue("1"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueDouble) {
+  double actual;
+  EXPECT_TRUE(FromValue(*ParseValue("12.5"), &actual));
+  EXPECT_DOUBLE_EQ(12.5, actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("-0.1"), &actual));
+  EXPECT_DOUBLE_EQ(-0.1, actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("17"), &actual));
+  EXPECT_DOUBLE_EQ(17.0, actual);
+
+  EXPECT_FALSE(FromValue(*ParseValue("'1.0'"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueString) {
+  std::string actual;
+  EXPECT_TRUE(FromValue(*ParseValue("'foo'"), &actual));
+  EXPECT_EQ("foo", actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("'bar'"), &actual));
+  EXPECT_EQ("bar", actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("''"), &actual));
+  EXPECT_TRUE(actual.empty());
+
+  EXPECT_FALSE(FromValue(*ParseValue("1"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueListValue) {
+  const base::ListValue* list = nullptr;
+  auto in_value = ParseValue("[1, 2, 'foo']");
+  EXPECT_TRUE(FromValue(*in_value, &list));
+  EXPECT_JSON_EQ("[1, 2, 'foo']", *list);
+}
+
+TEST(ValueConversionTest, FromValueDictValue) {
+  const base::DictionaryValue* dict = nullptr;
+  auto in_value = ParseValue("{'foo':'bar','baz': 1}");
+  EXPECT_TRUE(FromValue(*in_value, &dict));
+  EXPECT_JSON_EQ("{'foo':'bar','baz': 1}", *dict);
+}
+
+TEST(ValueConversionTest, FromValueListValueUniquePtr) {
+  std::unique_ptr<base::ListValue> list;
+  EXPECT_TRUE(FromValue(*ParseValue("[1, 2, 'bar']"), &list));
+  EXPECT_JSON_EQ("[1, 2, 'bar']", *list);
+}
+
+TEST(ValueConversionTest, FromValueDictValueUniquePtr) {
+  std::unique_ptr<base::DictionaryValue> dict;
+  EXPECT_TRUE(FromValue(*ParseValue("{'foo':'bar','baz': 1}"), &dict));
+  EXPECT_JSON_EQ("{'foo':'bar','baz': 1}", *dict);
+}
+
+TEST(ValueConversionTest, FromValueVectorOfInt) {
+  std::vector<int> actual;
+  EXPECT_TRUE(FromValue(*ParseValue("[1, 2, 3, 4]"), &actual));
+  EXPECT_EQ((std::vector<int>{1, 2, 3, 4}), actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("[]"), &actual));
+  EXPECT_TRUE(actual.empty());
+
+  EXPECT_FALSE(FromValue(*ParseValue("[1, 2, 3, '4']"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueVectorOfBool) {
+  std::vector<bool> actual;
+  EXPECT_TRUE(FromValue(*ParseValue("[true, true, false]"), &actual));
+  EXPECT_EQ((std::vector<bool>{true, true, false}), actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("[]"), &actual));
+  EXPECT_TRUE(actual.empty());
+
+  EXPECT_FALSE(FromValue(*ParseValue("[true, 0]"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueVectorOfDouble) {
+  std::vector<double> actual;
+  EXPECT_TRUE(FromValue(*ParseValue("[1, 2.0, 6.5, -11.2]"), &actual));
+  EXPECT_EQ((std::vector<double>{1.0, 2.0, 6.5, -11.2}), actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("[]"), &actual));
+  EXPECT_TRUE(actual.empty());
+
+  EXPECT_FALSE(FromValue(*ParseValue("['s']"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueVectorOfString) {
+  std::vector<std::string> actual;
+  EXPECT_TRUE(FromValue(*ParseValue("['', 'foo', 'bar']"), &actual));
+  EXPECT_EQ((std::vector<std::string>{"", "foo", "bar"}), actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("[]"), &actual));
+  EXPECT_TRUE(actual.empty());
+
+  EXPECT_FALSE(FromValue(*ParseValue("[100]"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueVectorOfVectors) {
+  std::vector<std::vector<int>> actual;
+  EXPECT_TRUE(FromValue(*ParseValue("[[1,2], [], [3]]"), &actual));
+  EXPECT_EQ((std::vector<std::vector<int>>{{1,2}, {}, {3}}), actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("[]"), &actual));
+  EXPECT_TRUE(actual.empty());
+
+  EXPECT_FALSE(FromValue(*ParseValue("[100]"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueMap) {
+  std::map<std::string, int> actual;
+  EXPECT_TRUE(FromValue(*ParseValue("{'foo':1, 'bar':2, 'baz':3}"), &actual));
+  EXPECT_EQ((std::map<std::string, int>{{"foo", 1}, {"bar", 2}, {"baz", 3}}),
+            actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("{}"), &actual));
+  EXPECT_TRUE(actual.empty());
+
+  EXPECT_FALSE(FromValue(*ParseValue("{'foo':1, 'bar':'2'}"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueMapOfVectors) {
+  std::map<std::string, std::vector<int>> actual;
+  EXPECT_TRUE(FromValue(*ParseValue("{'foo':[1,2], 'bar':[]}"), &actual));
+  std::map<std::string, std::vector<int>> expected{
+      {"foo", {1, 2}}, {"bar", {}}};
+  EXPECT_EQ(expected, actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("{}"), &actual));
+  EXPECT_TRUE(actual.empty());
+
+  EXPECT_FALSE(FromValue(*ParseValue("{'foo':[1], 'bar':[2,'3']}"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueVectorOfMaps) {
+  std::vector<std::map<std::string, int>> actual;
+  EXPECT_TRUE(FromValue(*ParseValue("[{'foo':1,'bar':2},{'baz':3}]"), &actual));
+  std::vector<std::map<std::string, int>> expected{
+      {{"foo", 1}, {"bar", 2}}, {{"baz", 3}}};
+  EXPECT_EQ(expected, actual);
+
+  EXPECT_TRUE(FromValue(*ParseValue("[]"), &actual));
+  EXPECT_TRUE(actual.empty());
+
+  EXPECT_FALSE(FromValue(*ParseValue("[{'foo':1}, 'bar']"), &actual));
+}
+
+TEST(ValueConversionTest, FromValueVectorOfLists) {
+  std::vector<std::unique_ptr<base::ListValue>> actual;
+  EXPECT_TRUE(FromValue(*ParseValue("[['foo',1],['bar',2],[true]]"), &actual));
+  ASSERT_EQ(3, actual.size());
+  EXPECT_JSON_EQ("['foo', 1]", *actual[0]);
+  EXPECT_JSON_EQ("['bar', 2]", *actual[1]);
+  EXPECT_JSON_EQ("[true]", *actual[2]);
+}
+
+TEST(ValueConversionTest, FromValueVectorOfDicts) {
+  std::vector<std::unique_ptr<base::DictionaryValue>> actual;
+  EXPECT_TRUE(FromValue(*ParseValue("[{'foo': 1}, {'bar': 2}]"), &actual));
+  ASSERT_EQ(2, actual.size());
+  EXPECT_JSON_EQ("{'foo': 1}", *actual[0]);
+  EXPECT_JSON_EQ("{'bar': 2}", *actual[1]);
+}
+
+TEST(ValueConversionTest, ToValueScalar) {
+  EXPECT_JSON_EQ("1234", *ToValue(1234));
+  EXPECT_JSON_EQ("true", *ToValue(true));
+  EXPECT_JSON_EQ("false", *ToValue(false));
+  EXPECT_JSON_EQ("12.5", *ToValue(12.5));
+  EXPECT_JSON_EQ("'foobar'", *ToValue("foobar"));
+}
+
+TEST(ValueConversionTest, ToValueVector) {
+  EXPECT_JSON_EQ("[1, 2, 3]", *ToValue(std::vector<int>{1, 2, 3}));
+  EXPECT_JSON_EQ("[]", *ToValue(std::vector<int>{}));
+  EXPECT_JSON_EQ("[true, false]", *ToValue(std::vector<bool>{true, false}));
+  EXPECT_JSON_EQ("['foo', 'bar']",
+                 *ToValue(std::vector<std::string>{"foo", "bar"}));
+  EXPECT_JSON_EQ("[[1,2],[3]]",
+                 *ToValue(std::vector<std::vector<int>>{{1, 2}, {3}}));
+}
+
+TEST(ValueConversionTest, ToValueMap) {
+  EXPECT_JSON_EQ("{'foo': 1, 'bar': 2}",
+                 *ToValue(std::map<std::string, int>{{"foo", 1}, {"bar", 2}}));
+  EXPECT_JSON_EQ("{}", *ToValue(std::map<std::string, int>{}));
+  EXPECT_JSON_EQ("{'foo': true}",
+                 *ToValue(std::map<std::string, bool>{{"foo", true}}));
+  EXPECT_JSON_EQ("{'foo': 1.1, 'bar': 2.2}",
+                 *ToValue(std::map<std::string, double>{{"foo", 1.1},
+                                                        {"bar", 2.2}}));
+}
+
+}  // namespace brillo
diff --git a/libbrillo/brillo/variant_dictionary.h b/libbrillo/brillo/variant_dictionary.h
new file mode 100644
index 0000000..0b71e9c
--- /dev/null
+++ b/libbrillo/brillo/variant_dictionary.h
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_BRILLO_VARIANT_DICTIONARY_H_
+#define LIBBRILLO_BRILLO_VARIANT_DICTIONARY_H_
+
+#include <map>
+#include <string>
+
+#include <brillo/any.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+using VariantDictionary = std::map<std::string, brillo::Any>;
+
+// GetVariantValueOrDefault tries to retrieve the named key from the dictionary
+// and convert it to the type T.  If the value does not exist, or the type
+// conversion fails, the default value of type T is returned.
+template<typename T>
+const T GetVariantValueOrDefault(const VariantDictionary& dictionary,
+                                 const std::string& key) {
+  VariantDictionary::const_iterator it = dictionary.find(key);
+  if (it == dictionary.end()) {
+    return T();
+  }
+  return it->second.TryGet<T>();
+}
+
+}  // namespace brillo
+
+#endif  // LIBBRILLO_BRILLO_VARIANT_DICTIONARY_H_
diff --git a/libbrillo/brillo/variant_dictionary_unittest.cc b/libbrillo/brillo/variant_dictionary_unittest.cc
new file mode 100644
index 0000000..73ead2c
--- /dev/null
+++ b/libbrillo/brillo/variant_dictionary_unittest.cc
@@ -0,0 +1,26 @@
+// Copyright 2015 The Chromium OS 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 <string>
+
+#include <brillo/any.h>
+#include <brillo/variant_dictionary.h>
+#include <gtest/gtest.h>
+
+using brillo::VariantDictionary;
+using brillo::GetVariantValueOrDefault;
+
+TEST(VariantDictionary, GetVariantValueOrDefault) {
+  VariantDictionary dictionary;
+  dictionary.emplace("a", 1);
+  dictionary.emplace("b", "string");
+
+  // Test values that are present in the VariantDictionary.
+  EXPECT_EQ(1, GetVariantValueOrDefault<int>(dictionary, "a"));
+  EXPECT_EQ("string", GetVariantValueOrDefault<const char*>(dictionary, "b"));
+
+  // Test that missing keys result in defaults.
+  EXPECT_EQ("", GetVariantValueOrDefault<std::string>(dictionary, "missing"));
+  EXPECT_EQ(0, GetVariantValueOrDefault<int>(dictionary, "missing"));
+}
diff --git a/libbrillo/gen_coverage_html.sh b/libbrillo/gen_coverage_html.sh
new file mode 100755
index 0000000..9faf1a9
--- /dev/null
+++ b/libbrillo/gen_coverage_html.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -ex
+
+scons debug=1 -c
+scons debug=1
+lcov -d . --zerocounters
+./unittests
+lcov --base-directory . --directory . --capture --output-file app.info
+
+# some versions of genhtml support the --no-function-coverage argument,
+# which we want. The problem w/ function coverage is that every template
+# instantiation of a method counts as a different method, so if we
+# instantiate a method twice, once for testing and once for prod, the method
+# is tested, but it shows only 50% function coverage b/c it thinks we didn't
+# test the prod version.
+
+genhtml --no-function-coverage -o html ./app.info || genhtml -o html ./app.info
diff --git a/libbrillo/libbrillo-395517.gypi b/libbrillo/libbrillo-395517.gypi
new file mode 100644
index 0000000..a846c70
--- /dev/null
+++ b/libbrillo/libbrillo-395517.gypi
@@ -0,0 +1,8 @@
+{
+  'variables': {
+    'libbase_ver': 395517,
+  },
+  'includes': [
+    '../libbrillo/libbrillo.gypi',
+  ],
+}
diff --git a/libbrillo/libbrillo-glib.pc.in b/libbrillo/libbrillo-glib.pc.in
new file mode 100644
index 0000000..cfd9fc8
--- /dev/null
+++ b/libbrillo/libbrillo-glib.pc.in
@@ -0,0 +1,8 @@
+bslot=@BSLOT@
+
+Name: libbrillo-glib
+Description: brillo glib wrapper library
+Version: ${bslot}
+Requires.private: @PRIVATE_PC@
+Libs: -lbrillo-glib-${bslot}
+
diff --git a/libbrillo/libbrillo-test.pc.in b/libbrillo/libbrillo-test.pc.in
new file mode 100644
index 0000000..4fece7c
--- /dev/null
+++ b/libbrillo/libbrillo-test.pc.in
@@ -0,0 +1,8 @@
+bslot=@BSLOT@
+
+Name: libbrillo-test
+Description: brillo test library
+Version: ${bslot}
+# Because libbrillo-test is static, we have to depend directly on everything.
+Requires: @PRIVATE_PC@
+Libs: -lbrillo-test-${bslot}
diff --git a/libbrillo/libbrillo.gyp b/libbrillo/libbrillo.gyp
new file mode 100644
index 0000000..487e99d
--- /dev/null
+++ b/libbrillo/libbrillo.gyp
@@ -0,0 +1,6 @@
+{
+  'includes': [
+    'libbrillo-395517.gypi',
+    'libpolicy.gypi',
+  ]
+}
diff --git a/libbrillo/libbrillo.gypi b/libbrillo/libbrillo.gypi
new file mode 100644
index 0000000..0a641ba
--- /dev/null
+++ b/libbrillo/libbrillo.gypi
@@ -0,0 +1,382 @@
+{
+  'target_defaults': {
+    'variables': {
+      'deps': [
+        'libchrome-<(libbase_ver)'
+      ],
+      'USE_dbus%': '1',
+    },
+    'include_dirs': [
+      '../libbrillo',
+    ],
+    'defines': [
+      'USE_DBUS=<(USE_dbus)',
+      'USE_RTTI_FOR_TYPE_TAGS',
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'libbrillo-<(libbase_ver)',
+      'type': 'none',
+      'dependencies': [
+        'libbrillo-core-<(libbase_ver)',
+        'libbrillo-cryptohome-<(libbase_ver)',
+        'libbrillo-http-<(libbase_ver)',
+        'libbrillo-minijail-<(libbase_ver)',
+        'libbrillo-streams-<(libbase_ver)',
+        'libpolicy-<(libbase_ver)',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '../libbrillo',
+        ],
+      },
+      'includes': ['../common-mk/deps.gypi'],
+    },
+    {
+      'target_name': 'libbrillo-core-<(libbase_ver)',
+      'type': 'shared_library',
+      'variables': {
+        'exported_deps': [
+          'dbus-1',
+        ],
+        'deps': ['<@(exported_deps)'],
+      },
+      'all_dependent_settings': {
+        'variables': {
+          'deps': [
+            '<@(exported_deps)',
+          ],
+        },
+      },
+      'libraries': ['-lmodp_b64'],
+      #TODO(deymo): Split DBus code from libbrillo-core the same way is split in
+      # the Android.mk, based on the <(USE_dbus) variable.
+      'sources': [
+        'brillo/any.cc',
+        'brillo/asynchronous_signal_handler.cc',
+        'brillo/backoff_entry.cc',
+        'brillo/daemons/dbus_daemon.cc',
+        'brillo/daemons/daemon.cc',
+        'brillo/data_encoding.cc',
+        'brillo/dbus/async_event_sequencer.cc',
+        'brillo/dbus/data_serialization.cc',
+        'brillo/dbus/dbus_connection.cc',
+        'brillo/dbus/dbus_method_invoker.cc',
+        'brillo/dbus/dbus_method_response.cc',
+        'brillo/dbus/dbus_object.cc',
+        'brillo/dbus/dbus_service_watcher.cc',
+        'brillo/dbus/dbus_signal.cc',
+        'brillo/dbus/exported_object_manager.cc',
+        'brillo/dbus/exported_property_set.cc',
+        'brillo/dbus/utils.cc',
+        'brillo/errors/error.cc',
+        'brillo/errors/error_codes.cc',
+        'brillo/file_utils.cc',
+        'brillo/flag_helper.cc',
+        'brillo/key_value_store.cc',
+        'brillo/message_loops/base_message_loop.cc',
+        'brillo/message_loops/message_loop.cc',
+        'brillo/message_loops/message_loop_utils.cc',
+        'brillo/mime_utils.cc',
+        'brillo/osrelease_reader.cc',
+        'brillo/process.cc',
+        'brillo/process_reaper.cc',
+        'brillo/process_information.cc',
+        'brillo/secure_blob.cc',
+        'brillo/strings/string_utils.cc',
+        'brillo/syslog_logging.cc',
+        'brillo/type_name_undecorate.cc',
+        'brillo/url_utils.cc',
+        'brillo/userdb_utils.cc',
+        'brillo/value_conversion.cc',
+      ],
+    },
+    {
+      'target_name': 'libbrillo-http-<(libbase_ver)',
+      'type': 'shared_library',
+      'dependencies': [
+        'libbrillo-core-<(libbase_ver)',
+        'libbrillo-streams-<(libbase_ver)',
+      ],
+      'variables': {
+        'exported_deps': [
+          'libcurl',
+        ],
+        'deps': ['<@(exported_deps)'],
+      },
+      'all_dependent_settings': {
+        'variables': {
+          'deps': [
+            '<@(exported_deps)',
+          ],
+        },
+      },
+      'sources': [
+        'brillo/http/curl_api.cc',
+        'brillo/http/http_connection_curl.cc',
+        'brillo/http/http_form_data.cc',
+        'brillo/http/http_request.cc',
+        'brillo/http/http_transport.cc',
+        'brillo/http/http_transport_curl.cc',
+        'brillo/http/http_utils.cc',
+      ],
+    },
+    {
+      'target_name': 'libbrillo-streams-<(libbase_ver)',
+      'type': 'shared_library',
+      'dependencies': [
+        'libbrillo-core-<(libbase_ver)',
+      ],
+      'variables': {
+        'exported_deps': [
+          'openssl',
+        ],
+        'deps': ['<@(exported_deps)'],
+      },
+      'all_dependent_settings': {
+        'variables': {
+          'deps': [
+            '<@(exported_deps)',
+          ],
+        },
+      },
+      'sources': [
+        'brillo/streams/file_stream.cc',
+        'brillo/streams/input_stream_set.cc',
+        'brillo/streams/memory_containers.cc',
+        'brillo/streams/memory_stream.cc',
+        'brillo/streams/openssl_stream_bio.cc',
+        'brillo/streams/stream.cc',
+        'brillo/streams/stream_errors.cc',
+        'brillo/streams/stream_utils.cc',
+        'brillo/streams/tls_stream.cc',
+      ],
+    },
+    {
+      'target_name': 'libbrillo-test-<(libbase_ver)',
+      'type': 'static_library',
+      'standalone_static_library': 1,
+      'dependencies': [
+        'libbrillo-http-<(libbase_ver)',
+      ],
+      'sources': [
+        'brillo/http/http_connection_fake.cc',
+        'brillo/http/http_transport_fake.cc',
+        'brillo/message_loops/fake_message_loop.cc',
+        'brillo/streams/fake_stream.cc',
+        'brillo/unittest_utils.cc',
+      ],
+      'includes': ['../common-mk/deps.gypi'],
+    },
+    {
+      'target_name': 'libbrillo-cryptohome-<(libbase_ver)',
+      'type': 'shared_library',
+      'variables': {
+        'exported_deps': [
+          'openssl',
+        ],
+        'deps': ['<@(exported_deps)'],
+      },
+      'all_dependent_settings': {
+        'variables': {
+          'deps': [
+            '<@(exported_deps)',
+          ],
+        },
+      },
+      'sources': [
+        'brillo/cryptohome.cc',
+      ],
+    },
+    {
+      'target_name': 'libbrillo-minijail-<(libbase_ver)',
+      'type': 'shared_library',
+      'variables': {
+        'exported_deps': [
+          'libminijail',
+        ],
+        'deps': ['<@(exported_deps)'],
+      },
+      'all_dependent_settings': {
+        'variables': {
+          'deps': [
+            '<@(exported_deps)',
+          ],
+        },
+      },
+      'cflags': [
+        '-fvisibility=default',
+      ],
+      'sources': [
+        'brillo/minijail/minijail.cc',
+      ],
+    },
+    {
+      'target_name': 'libpolicy-<(libbase_ver)',
+      'type': 'shared_library',
+      'dependencies': [
+        'libpolicy-includes',
+        '../common-mk/external_dependencies.gyp:policy-protos',
+      ],
+      'variables': {
+        'exported_deps': [
+          'openssl',
+          'protobuf-lite',
+        ],
+        'deps': ['<@(exported_deps)'],
+      },
+      'all_dependent_settings': {
+        'variables': {
+          'deps': [
+            '<@(exported_deps)',
+          ],
+        },
+      },
+      'ldflags': [
+        '-Wl,--version-script,<(platform2_root)/libbrillo/libpolicy.ver',
+      ],
+      'sources': [
+        'policy/device_policy.cc',
+        'policy/device_policy_impl.cc',
+        'policy/libpolicy.cc',
+      ],
+    },
+    {
+      'target_name': 'libbrillo-glib-<(libbase_ver)',
+      'type': 'shared_library',
+      'dependencies': [
+          'libbrillo-<(libbase_ver)',
+      ],
+      'variables': {
+        'exported_deps': [
+          'dbus-1',
+          'dbus-glib-1',
+          'glib-2.0',
+          'gobject-2.0',
+        ],
+        'deps': ['<@(exported_deps)'],
+      },
+      'cflags': [
+        # glib uses the deprecated "register" attribute in some header files.
+        '-Wno-deprecated-register',
+      ],
+      'all_dependent_settings': {
+        'variables': {
+          'deps': [
+            '<@(exported_deps)',
+          ],
+        },
+      },
+      'sources': [
+        'brillo/glib/abstract_dbus_service.cc',
+        'brillo/glib/dbus.cc',
+        'brillo/message_loops/glib_message_loop.cc',
+      ],
+      'includes': ['../common-mk/deps.gypi'],
+    },
+  ],
+  'conditions': [
+    ['USE_test == 1', {
+      'targets': [
+        {
+          'target_name': 'libbrillo-<(libbase_ver)_unittests',
+          'type': 'executable',
+          'dependencies': [
+            'libbrillo-<(libbase_ver)',
+            'libbrillo-test-<(libbase_ver)',
+            'libbrillo-glib-<(libbase_ver)',
+          ],
+          'variables': {
+            'deps': [
+              'libchrome-test-<(libbase_ver)',
+            ],
+            'proto_in_dir': 'brillo/dbus',
+            'proto_out_dir': 'include/brillo/dbus',
+          },
+          'includes': [
+            '../common-mk/common_test.gypi',
+            '../common-mk/protoc.gypi',
+          ],
+          'cflags': [
+            '-Wno-format-zero-length',
+          ],
+          'conditions': [
+            ['debug == 1', {
+              'cflags': [
+                '-fprofile-arcs',
+                '-ftest-coverage',
+                '-fno-inline',
+              ],
+              'libraries': [
+                '-lgcov',
+              ],
+            }],
+          ],
+          'sources': [
+            'brillo/any_unittest.cc',
+            'brillo/any_internal_impl_unittest.cc',
+            'brillo/asynchronous_signal_handler_unittest.cc',
+            'brillo/backoff_entry_unittest.cc',
+            'brillo/data_encoding_unittest.cc',
+            'brillo/dbus/async_event_sequencer_unittest.cc',
+            'brillo/dbus/data_serialization_unittest.cc',
+            'brillo/dbus/dbus_method_invoker_unittest.cc',
+            'brillo/dbus/dbus_object_unittest.cc',
+            'brillo/dbus/dbus_param_reader_unittest.cc',
+            'brillo/dbus/dbus_param_writer_unittest.cc',
+            'brillo/dbus/dbus_signal_handler_unittest.cc',
+            'brillo/dbus/exported_object_manager_unittest.cc',
+            'brillo/dbus/exported_property_set_unittest.cc',
+            'brillo/errors/error_codes_unittest.cc',
+            'brillo/errors/error_unittest.cc',
+            'brillo/file_utils_unittest.cc',
+            'brillo/flag_helper_unittest.cc',
+            'brillo/glib/object_unittest.cc',
+            'brillo/http/http_connection_curl_unittest.cc',
+            'brillo/http/http_form_data_unittest.cc',
+            'brillo/http/http_request_unittest.cc',
+            'brillo/http/http_transport_curl_unittest.cc',
+            'brillo/http/http_utils_unittest.cc',
+            'brillo/key_value_store_unittest.cc',
+            'brillo/map_utils_unittest.cc',
+            'brillo/message_loops/base_message_loop_unittest.cc',
+            'brillo/message_loops/fake_message_loop_unittest.cc',
+            'brillo/message_loops/glib_message_loop_unittest.cc',
+            'brillo/message_loops/message_loop_unittest.cc',
+            'brillo/mime_utils_unittest.cc',
+            'brillo/osrelease_reader_unittest.cc',
+            'brillo/process_reaper_unittest.cc',
+            'brillo/process_unittest.cc',
+            'brillo/secure_blob_unittest.cc',
+            'brillo/streams/fake_stream_unittest.cc',
+            'brillo/streams/file_stream_unittest.cc',
+            'brillo/streams/input_stream_set_unittest.cc',
+            'brillo/streams/memory_containers_unittest.cc',
+            'brillo/streams/memory_stream_unittest.cc',
+            'brillo/streams/openssl_stream_bio_unittests.cc',
+            'brillo/streams/stream_unittest.cc',
+            'brillo/streams/stream_utils_unittest.cc',
+            'brillo/strings/string_utils_unittest.cc',
+            'brillo/type_name_undecorate_unittest.cc',
+            'brillo/unittest_utils.cc',
+            'brillo/url_utils_unittest.cc',
+            'brillo/variant_dictionary_unittest.cc',
+            'brillo/value_conversion_unittest.cc',
+            'testrunner.cc',
+            '<(proto_in_dir)/test.proto',
+          ]
+        },
+        {
+          'target_name': 'libpolicy-<(libbase_ver)_unittests',
+          'type': 'executable',
+          'dependencies': ['libpolicy-<(libbase_ver)'],
+          'includes': ['../common-mk/common_test.gypi'],
+          'sources': [
+            'policy/tests/libpolicy_unittest.cc',
+          ]
+        },
+      ],
+    }],
+  ],
+}
diff --git a/libbrillo/libbrillo.pc.in b/libbrillo/libbrillo.pc.in
new file mode 100644
index 0000000..a3a9e07
--- /dev/null
+++ b/libbrillo/libbrillo.pc.in
@@ -0,0 +1,8 @@
+bslot=@BSLOT@
+
+Name: libbrillo
+Description: brillo base library
+Version: ${bslot}
+Requires.private: @PRIVATE_PC@
+Cflags: -DUSE_RTTI_FOR_TYPE_TAGS
+Libs: -lbrillo-${bslot}
diff --git a/libbrillo/libpolicy.gypi b/libbrillo/libpolicy.gypi
new file mode 100644
index 0000000..25b251d
--- /dev/null
+++ b/libbrillo/libpolicy.gypi
@@ -0,0 +1,20 @@
+{
+  'targets': [
+    {
+      'target_name': 'libpolicy-includes',
+      'type': 'none',
+      'copies': [
+        {
+          'destination': '<(SHARED_INTERMEDIATE_DIR)/include/policy',
+          'files': [
+            'policy/device_policy.h',
+            'policy/device_policy_impl.h',
+            'policy/libpolicy.h',
+            'policy/mock_libpolicy.h',
+            'policy/mock_device_policy.h',
+          ],
+        },
+      ],
+    },
+  ],
+}
diff --git a/libbrillo/libpolicy.ver b/libbrillo/libpolicy.ver
new file mode 100644
index 0000000..4acb71c
--- /dev/null
+++ b/libbrillo/libpolicy.ver
@@ -0,0 +1,19 @@
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  global:
+    extern "C++" {
+      enterprise_management::*;
+      typeinfo*for*enterprise_management::*;
+      vtable*for*enterprise_management*;
+
+      policy::*;
+      typeinfo*for*policy::*;
+      vtable*for*policy*;
+      _VTV*::__vtable_map;
+    };
+
+  local: *;
+};
diff --git a/libbrillo/platform2_preinstall.sh b/libbrillo/platform2_preinstall.sh
new file mode 100755
index 0000000..448a31a
--- /dev/null
+++ b/libbrillo/platform2_preinstall.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+OUT=$1
+shift
+for v; do
+  # Extract all the libbrillo sublibs from 'dependencies' section of
+  # 'libbrillo-<(libbase_ver)' target in libbrillo.gypi and convert them
+  # into an array of "-lbrillo-<sublib>-<v>" flags.
+  sublibs=($(sed -n "
+     /'target_name': 'libbrillo-<(libbase_ver)'/,/target_name/ {
+       /dependencies/,/],/ {
+         /libbrillo/ {
+           s:[',]::g
+           s:<(libbase_ver):${v}:g
+           s:libbrillo:-lbrillo:
+           p
+         }
+       }
+     }" libbrillo.gypi))
+
+  echo "GROUP ( AS_NEEDED ( ${sublibs[@]} ) )" > "${OUT}"/lib/libbrillo-${v}.so
+
+  deps=$(<"${OUT}"/gen/libbrillo-${v}-deps.txt)
+  pc="${OUT}"/lib/libbrillo-${v}.pc
+
+  sed \
+    -e "s/@BSLOT@/${v}/g" \
+    -e "s/@PRIVATE_PC@/${deps}/g" \
+    "libbrillo.pc.in" > "${pc}"
+
+  deps_test=$(<"${OUT}"/gen/libbrillo-test-${v}-deps.txt)
+  deps_test+=" libbrillo-${v}"
+  sed \
+    -e "s/@BSLOT@/${v}/g" \
+    -e "s/@PRIVATE_PC@/${deps_test}/g" \
+    "libbrillo-test.pc.in" > "${OUT}/lib/libbrillo-test-${v}.pc"
+
+
+  deps_glib=$(<"${OUT}"/gen/libbrillo-glib-${v}-deps.txt)
+  pc_glib="${OUT}"/lib/libbrillo-glib-${v}.pc
+
+  sed \
+    -e "s/@BSLOT@/${v}/g" \
+    -e "s/@PRIVATE_PC@/${deps_glib}/g" \
+    "libbrillo-glib.pc.in" > "${pc_glib}"
+done
diff --git a/libbrillo/policy/WATCHLISTS b/libbrillo/policy/WATCHLISTS
new file mode 100644
index 0000000..c806539
--- /dev/null
+++ b/libbrillo/policy/WATCHLISTS
@@ -0,0 +1,14 @@
+# See http://dev.chromium.org/developers/contributing-code/watchlists for
+# a description of this file's format.
+# Please keep these keys in alphabetical order.
+
+{
+  'WATCHLIST_DEFINITIONS': {
+    'all': {
+      'filepath': '.',
+    },
+  },
+  'WATCHLISTS': {
+    'all': ['pastarmovj@chromium.org']
+  },
+}
diff --git a/libbrillo/policy/device_policy.cc b/libbrillo/policy/device_policy.cc
new file mode 100644
index 0000000..e9445e7
--- /dev/null
+++ b/libbrillo/policy/device_policy.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2011 The Chromium OS 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 "policy/device_policy.h"
+
+namespace policy {
+
+DevicePolicy::DevicePolicy() {
+}
+
+DevicePolicy::~DevicePolicy() {
+}
+
+}  // namespace policy
+
diff --git a/libbrillo/policy/device_policy.h b/libbrillo/policy/device_policy.h
new file mode 100644
index 0000000..840e7e5
--- /dev/null
+++ b/libbrillo/policy/device_policy.h
@@ -0,0 +1,166 @@
+// Copyright (c) 2012 The Chromium OS 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 LIBBRILLO_POLICY_DEVICE_POLICY_H_
+#define LIBBRILLO_POLICY_DEVICE_POLICY_H_
+
+#include <stdint.h>
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+#pragma GCC visibility push(default)
+
+namespace policy {
+
+// This class holds device settings that are to be enforced across all users.
+// It is also responsible for loading the policy blob from disk and verifying
+// the signature against the owner's key.
+//
+// This class defines the interface for querying device policy on ChromeOS.
+// The implementation is hidden in DevicePolicyImpl to prevent protobuf
+// definition from leaking into the libraries using this interface.
+class DevicePolicy {
+ public:
+  // Identifiers of a USB device or device family.
+  struct UsbDeviceId {
+    // USB Vendor Identifier (aka idVendor).
+    uint16_t vendor_id;
+
+    // USB Product Identifier (aka idProduct).
+    uint16_t product_id;
+  };
+
+  DevicePolicy();
+  virtual ~DevicePolicy();
+
+  // Load the signed policy off of disk into |policy_|.
+  // Returns true unless there is a policy on disk and loading it fails.
+  virtual bool LoadPolicy() = 0;
+
+  // Writes the value of the DevicePolicyRefreshRate policy in |rate|. Returns
+  // true on success.
+  virtual bool GetPolicyRefreshRate(int* rate) const = 0;
+
+  // Writes the value of the UserWhitelist policy in |user_whitelist|. Returns
+  // true on success.
+  virtual bool GetUserWhitelist(
+      std::vector<std::string>* user_whitelist) const = 0;
+
+  // Writes the value of the GuestModeEnabled policy in |guest_mode_enabled|.
+  // Returns true on success.
+  virtual bool GetGuestModeEnabled(bool* guest_mode_enabled) const = 0;
+
+  // Writes the value of the CameraEnabled policy in |camera_enabled|. Returns
+  // true on success.
+  virtual bool GetCameraEnabled(bool* camera_enabled) const = 0;
+
+  // Writes the value of the ShowUserNamesOnSignIn policy in |show_user_names|.
+  // Returns true on success.
+  virtual bool GetShowUserNames(bool* show_user_names) const = 0;
+
+  // Writes the value of the DataRoamingEnabled policy in |data_roaming_enabled|
+  // Returns true on success.
+  virtual bool GetDataRoamingEnabled(bool* data_roaming_enabled) const = 0;
+
+  // Writes the value of the AllowNewUsers policy in |allow_new_users|. Returns
+  // true on success.
+  virtual bool GetAllowNewUsers(bool* allow_new_users) const = 0;
+
+  // Writes the value of MetricEnabled policy in |metrics_enabled|. Returns true
+  // on success.
+  virtual bool GetMetricsEnabled(bool* metrics_enabled) const = 0;
+
+  // Writes the value of ReportVersionInfo policy in |report_version_info|.
+  // Returns true on success.
+  virtual bool GetReportVersionInfo(bool* report_version_info) const = 0;
+
+  // Writes the value of ReportActivityTimes policy in |report_activity_times|.
+  // Returns true on success.
+  virtual bool GetReportActivityTimes(bool* report_activity_times) const = 0;
+
+  // Writes the value of ReportBootMode policy in |report_boot_mode|. Returns
+  // true on success.
+  virtual bool GetReportBootMode(bool* report_boot_mode) const = 0;
+
+  // Writes the value of the EphemeralUsersEnabled policy in
+  // |ephemeral_users_enabled|. Returns true on success.
+  virtual bool GetEphemeralUsersEnabled(
+      bool* ephemeral_users_enabled) const =  0;
+
+  // Writes the value of the release channel policy in |release_channel|.
+  // Returns true on success.
+  virtual bool GetReleaseChannel(std::string* release_channel) const = 0;
+
+  // Writes the value of the release_channel_delegated policy in
+  // |release_channel_delegated|. Returns true on success.
+  virtual bool GetReleaseChannelDelegated(
+      bool* release_channel_delegated) const = 0;
+
+  // Writes the value of the update_disabled policy in |update_disabled|.
+  // Returns true on success.
+  virtual bool GetUpdateDisabled(bool* update_disabled) const = 0;
+
+  // Writes the value of the target_version_prefix policy in
+  // |target_version_prefix|. Returns true on success.
+  virtual bool GetTargetVersionPrefix(
+      std::string* target_version_prefix) const = 0;
+
+  // Writes the value of the scatter_factor_in_seconds policy in
+  // |scatter_factor_in_seconds|. Returns true on success.
+  virtual bool GetScatterFactorInSeconds(
+      int64_t* scatter_factor_in_seconds) const = 0;
+
+  // Writes the connection types on which updates are allowed to
+  // |connection_types|. The identifiers returned are intended to be consistent
+  // with what the connection manager users: ethernet, wifi, wimax, bluetooth,
+  // cellular.
+  virtual bool GetAllowedConnectionTypesForUpdate(
+      std::set<std::string>* connection_types) const = 0;
+
+  // Writes the value of the OpenNetworkConfiguration policy in
+  // |open_network_configuration|. Returns true on success.
+  virtual bool GetOpenNetworkConfiguration(
+      std::string* open_network_configuration) const = 0;
+
+  // Writes the name of the device owner in |owner|. For enterprise enrolled
+  // devices, this will be an empty string.
+  // Returns true on success.
+  virtual bool GetOwner(std::string* owner) const = 0;
+
+  // Write the value of http_downloads_enabled policy in
+  // |http_downloads_enabled|. Returns true on success.
+  virtual bool GetHttpDownloadsEnabled(bool* http_downloads_enabled) const = 0;
+
+  // Writes the value of au_p2p_enabled policy in
+  // |au_p2p_enabled|. Returns true on success.
+  virtual bool GetAuP2PEnabled(bool* au_p2p_enabled) const = 0;
+
+  // Writes the value of allow_kiosk_app_control_chrome_version policy in
+  // |allow_kiosk_app_control_chrome_version|. Returns true on success.
+  virtual bool GetAllowKioskAppControlChromeVersion(
+      bool* allow_kiosk_app_control_chrome_version) const = 0;
+
+  // Writes the value of the UsbDetachableWhitelist policy in |usb_whitelist|.
+  // Returns true on success.
+  virtual bool GetUsbDetachableWhitelist(
+      std::vector<UsbDeviceId>* usb_whitelist) const = 0;
+
+ private:
+  // Verifies that the policy files are owned by root and exist.
+  virtual bool VerifyPolicyFiles() = 0;
+
+  // Verifies that the policy signature is correct.
+  virtual bool VerifyPolicySignature() = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(DevicePolicy);
+};
+}  // namespace policy
+
+#pragma GCC visibility pop
+
+#endif  // LIBBRILLO_POLICY_DEVICE_POLICY_H_
diff --git a/libbrillo/policy/device_policy_impl.cc b/libbrillo/policy/device_policy_impl.cc
new file mode 100644
index 0000000..784cace
--- /dev/null
+++ b/libbrillo/policy/device_policy_impl.cc
@@ -0,0 +1,465 @@
+// Copyright (c) 2012 The Chromium OS 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 "policy/device_policy_impl.h"
+
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include <base/macros.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <set>
+#include <string>
+
+#include "bindings/chrome_device_policy.pb.h"
+#include "bindings/device_management_backend.pb.h"
+
+namespace policy {
+
+namespace {
+const char kPolicyPath[] = "/var/lib/whitelist/policy";
+const char kPublicKeyPath[] = "/var/lib/whitelist/owner.key";
+
+// Reads the public key used to sign the policy from |key_file| and stores it
+// in |public_key|. Returns true on success.
+bool ReadPublicKeyFromFile(const base::FilePath& key_file,
+                           std::string* public_key) {
+  if (!base::PathExists(key_file))
+    return false;
+  public_key->clear();
+  if (!base::ReadFileToString(key_file, public_key) || public_key->empty()) {
+    LOG(ERROR) << "Could not read public key off disk";
+    return false;
+  }
+  return true;
+}
+
+// Verifies that the |signed_data| has correct |signature| with |public_key|.
+bool VerifySignature(const std::string& signed_data,
+                     const std::string& signature,
+                     const std::string& public_key) {
+  EVP_MD_CTX ctx;
+  EVP_MD_CTX_init(&ctx);
+
+  const EVP_MD* digest = EVP_sha1();
+
+  char* key = const_cast<char*>(public_key.data());
+  BIO* bio = BIO_new_mem_buf(key, public_key.length());
+  if (!bio) {
+    EVP_MD_CTX_cleanup(&ctx);
+    return false;
+  }
+
+  EVP_PKEY* public_key_ssl = d2i_PUBKEY_bio(bio, nullptr);
+  if (!public_key_ssl) {
+    BIO_free_all(bio);
+    EVP_MD_CTX_cleanup(&ctx);
+    return false;
+  }
+
+  const unsigned char* sig =
+      reinterpret_cast<const unsigned char*>(signature.data());
+  int rv = EVP_VerifyInit_ex(&ctx, digest, nullptr);
+  if (rv == 1) {
+    EVP_VerifyUpdate(&ctx, signed_data.data(), signed_data.length());
+    rv = EVP_VerifyFinal(&ctx,
+                         sig, signature.length(),
+                         public_key_ssl);
+  }
+
+  EVP_PKEY_free(public_key_ssl);
+  BIO_free_all(bio);
+  EVP_MD_CTX_cleanup(&ctx);
+
+  return rv == 1;
+}
+
+// Decodes the connection type enum from the device settings protobuf to string
+// representations. The strings must match the connection manager definitions.
+std::string DecodeConnectionType(int type) {
+  static const char* const kConnectionTypes[] = {
+    "ethernet",
+    "wifi",
+    "wimax",
+    "bluetooth",
+    "cellular",
+  };
+
+  if (type < 0 || type >= static_cast<int>(arraysize(kConnectionTypes)))
+    return std::string();
+
+  return kConnectionTypes[type];
+}
+
+}  // namespace
+
+DevicePolicyImpl::DevicePolicyImpl()
+    : policy_path_(kPolicyPath),
+      keyfile_path_(kPublicKeyPath) {
+}
+
+DevicePolicyImpl::~DevicePolicyImpl() {
+}
+
+bool DevicePolicyImpl::LoadPolicy() {
+  if (!VerifyPolicyFiles()) {
+    return false;
+  }
+
+  std::string polstr;
+  if (!base::ReadFileToString(policy_path_, &polstr) || polstr.empty()) {
+    LOG(ERROR) << "Could not read policy off disk";
+    return false;
+  }
+  if (!policy_.ParseFromString(polstr) || !policy_.has_policy_data()) {
+    LOG(ERROR) << "Policy on disk could not be parsed!";
+    return false;
+  }
+  policy_data_.ParseFromString(policy_.policy_data());
+  if (!policy_data_.has_policy_value()) {
+    LOG(ERROR) << "Policy on disk could not be parsed!";
+    return false;
+  }
+
+  // Make sure the signature is still valid.
+  if (!VerifyPolicySignature()) {
+    LOG(ERROR) << "Policy signature verification failed!";
+    return false;
+  }
+
+  device_policy_.ParseFromString(policy_data_.policy_value());
+  return true;
+}
+
+bool DevicePolicyImpl::GetPolicyRefreshRate(int* rate) const {
+  if (!device_policy_.has_device_policy_refresh_rate())
+    return false;
+  *rate = static_cast<int>(
+      device_policy_.device_policy_refresh_rate().device_policy_refresh_rate());
+  return true;
+}
+
+bool DevicePolicyImpl::GetUserWhitelist(
+    std::vector<std::string>* user_whitelist) const {
+  if (!device_policy_.has_user_whitelist())
+    return false;
+  const enterprise_management::UserWhitelistProto& proto =
+      device_policy_.user_whitelist();
+  user_whitelist->clear();
+  for (int i = 0; i < proto.user_whitelist_size(); i++)
+    user_whitelist->push_back(proto.user_whitelist(i));
+  return true;
+}
+
+bool DevicePolicyImpl::GetGuestModeEnabled(bool* guest_mode_enabled) const {
+  if (!device_policy_.has_guest_mode_enabled())
+    return false;
+  *guest_mode_enabled =
+      device_policy_.guest_mode_enabled().guest_mode_enabled();
+  return true;
+}
+
+bool DevicePolicyImpl::GetCameraEnabled(bool* camera_enabled) const {
+  if (!device_policy_.has_camera_enabled())
+    return false;
+  *camera_enabled = device_policy_.camera_enabled().camera_enabled();
+  return true;
+}
+
+bool DevicePolicyImpl::GetShowUserNames(bool* show_user_names) const {
+  if (!device_policy_.has_show_user_names())
+    return false;
+  *show_user_names = device_policy_.show_user_names().show_user_names();
+  return true;
+}
+
+bool DevicePolicyImpl::GetDataRoamingEnabled(bool* data_roaming_enabled) const {
+  if (!device_policy_.has_data_roaming_enabled())
+    return false;
+  *data_roaming_enabled =
+      device_policy_.data_roaming_enabled().data_roaming_enabled();
+  return true;
+}
+
+bool DevicePolicyImpl::GetAllowNewUsers(bool* allow_new_users) const {
+  if (!device_policy_.has_allow_new_users())
+    return false;
+  *allow_new_users = device_policy_.allow_new_users().allow_new_users();
+  return true;
+}
+
+bool DevicePolicyImpl::GetMetricsEnabled(bool* metrics_enabled) const {
+  if (!device_policy_.has_metrics_enabled())
+    return false;
+  *metrics_enabled = device_policy_.metrics_enabled().metrics_enabled();
+  return true;
+}
+
+bool DevicePolicyImpl::GetReportVersionInfo(bool* report_version_info) const {
+  if (!device_policy_.has_device_reporting())
+    return false;
+
+  const enterprise_management::DeviceReportingProto& proto =
+      device_policy_.device_reporting();
+  if (!proto.has_report_version_info())
+    return false;
+
+  *report_version_info = proto.report_version_info();
+  return true;
+}
+
+bool DevicePolicyImpl::GetReportActivityTimes(
+    bool* report_activity_times) const {
+  if (!device_policy_.has_device_reporting())
+    return false;
+
+  const enterprise_management::DeviceReportingProto& proto =
+      device_policy_.device_reporting();
+  if (!proto.has_report_activity_times())
+    return false;
+
+  *report_activity_times = proto.report_activity_times();
+  return true;
+}
+
+bool DevicePolicyImpl::GetReportBootMode(bool* report_boot_mode) const {
+  if (!device_policy_.has_device_reporting())
+    return false;
+
+  const enterprise_management::DeviceReportingProto& proto =
+      device_policy_.device_reporting();
+  if (!proto.has_report_boot_mode())
+    return false;
+
+  *report_boot_mode = proto.report_boot_mode();
+  return true;
+}
+
+bool DevicePolicyImpl::GetEphemeralUsersEnabled(
+    bool* ephemeral_users_enabled) const {
+  if (!device_policy_.has_ephemeral_users_enabled())
+    return false;
+  *ephemeral_users_enabled =
+      device_policy_.ephemeral_users_enabled().ephemeral_users_enabled();
+  return true;
+}
+
+bool DevicePolicyImpl::GetReleaseChannel(
+    std::string* release_channel) const {
+  if (!device_policy_.has_release_channel())
+    return false;
+
+  const enterprise_management::ReleaseChannelProto& proto =
+      device_policy_.release_channel();
+  if (!proto.has_release_channel())
+    return false;
+
+  *release_channel = proto.release_channel();
+  return true;
+}
+
+bool DevicePolicyImpl::GetReleaseChannelDelegated(
+    bool* release_channel_delegated) const {
+  if (!device_policy_.has_release_channel())
+    return false;
+
+  const enterprise_management::ReleaseChannelProto& proto =
+      device_policy_.release_channel();
+  if (!proto.has_release_channel_delegated())
+    return false;
+
+  *release_channel_delegated = proto.release_channel_delegated();
+  return true;
+}
+
+bool DevicePolicyImpl::GetUpdateDisabled(
+    bool* update_disabled) const {
+  if (!device_policy_.has_auto_update_settings())
+    return false;
+
+  const enterprise_management::AutoUpdateSettingsProto& proto =
+      device_policy_.auto_update_settings();
+  if (!proto.has_update_disabled())
+    return false;
+
+  *update_disabled = proto.update_disabled();
+  return true;
+}
+
+bool DevicePolicyImpl::GetTargetVersionPrefix(
+    std::string* target_version_prefix) const {
+  if (!device_policy_.has_auto_update_settings())
+    return false;
+
+  const enterprise_management::AutoUpdateSettingsProto& proto =
+      device_policy_.auto_update_settings();
+  if (!proto.has_target_version_prefix())
+    return false;
+
+  *target_version_prefix = proto.target_version_prefix();
+  return true;
+}
+
+bool DevicePolicyImpl::GetScatterFactorInSeconds(
+    int64_t* scatter_factor_in_seconds) const {
+  if (!device_policy_.has_auto_update_settings())
+    return false;
+
+  const enterprise_management::AutoUpdateSettingsProto& proto =
+      device_policy_.auto_update_settings();
+  if (!proto.has_scatter_factor_in_seconds())
+    return false;
+
+  *scatter_factor_in_seconds = proto.scatter_factor_in_seconds();
+  return true;
+}
+
+bool DevicePolicyImpl::GetAllowedConnectionTypesForUpdate(
+      std::set<std::string>* connection_types) const {
+  if (!device_policy_.has_auto_update_settings())
+    return false;
+
+  const enterprise_management::AutoUpdateSettingsProto& proto =
+      device_policy_.auto_update_settings();
+  if (proto.allowed_connection_types_size() <= 0)
+    return false;
+
+  for (int i = 0; i < proto.allowed_connection_types_size(); i++) {
+    std::string type = DecodeConnectionType(proto.allowed_connection_types(i));
+    if (!type.empty())
+      connection_types->insert(type);
+  }
+  return true;
+}
+
+bool DevicePolicyImpl::GetOpenNetworkConfiguration(
+    std::string* open_network_configuration) const {
+  if (!device_policy_.has_open_network_configuration())
+    return false;
+
+  const enterprise_management::DeviceOpenNetworkConfigurationProto& proto =
+      device_policy_.open_network_configuration();
+  if (!proto.has_open_network_configuration())
+    return false;
+
+  *open_network_configuration = proto.open_network_configuration();
+  return true;
+}
+
+bool DevicePolicyImpl::GetOwner(std::string* owner) const {
+  // The device is enterprise enrolled iff a request token exists.
+  if (policy_data_.has_request_token()) {
+    *owner = "";
+    return true;
+  }
+  if (!policy_data_.has_username())
+    return false;
+  *owner = policy_data_.username();
+  return true;
+}
+
+bool DevicePolicyImpl::GetHttpDownloadsEnabled(
+    bool* http_downloads_enabled) const {
+  if (!device_policy_.has_auto_update_settings())
+    return false;
+
+  const enterprise_management::AutoUpdateSettingsProto& proto =
+      device_policy_.auto_update_settings();
+
+  if (!proto.has_http_downloads_enabled())
+    return false;
+
+  *http_downloads_enabled = proto.http_downloads_enabled();
+  return true;
+}
+
+bool DevicePolicyImpl::GetAuP2PEnabled(bool* au_p2p_enabled) const {
+  if (!device_policy_.has_auto_update_settings())
+    return false;
+
+  const enterprise_management::AutoUpdateSettingsProto& proto =
+      device_policy_.auto_update_settings();
+
+  if (!proto.has_p2p_enabled())
+    return false;
+
+  *au_p2p_enabled = proto.p2p_enabled();
+  return true;
+}
+
+bool DevicePolicyImpl::GetAllowKioskAppControlChromeVersion(
+      bool* allow_kiosk_app_control_chrome_version) const {
+  if (!device_policy_.has_allow_kiosk_app_control_chrome_version())
+    return false;
+
+  const enterprise_management::AllowKioskAppControlChromeVersionProto& proto =
+      device_policy_.allow_kiosk_app_control_chrome_version();
+
+  if (!proto.has_allow_kiosk_app_control_chrome_version())
+    return false;
+
+  *allow_kiosk_app_control_chrome_version =
+      proto.allow_kiosk_app_control_chrome_version();
+  return true;
+}
+
+bool DevicePolicyImpl::GetUsbDetachableWhitelist(
+    std::vector<UsbDeviceId>* usb_whitelist) const {
+  if (!device_policy_.has_usb_detachable_whitelist())
+    return false;
+  const enterprise_management::UsbDetachableWhitelistProto& proto =
+      device_policy_.usb_detachable_whitelist();
+  usb_whitelist->clear();
+  for (int i = 0; i < proto.id_size(); i++) {
+    const ::enterprise_management::UsbDeviceIdProto& id = proto.id(i);
+    UsbDeviceId dev_id;
+    dev_id.vendor_id = id.has_vendor_id() ? id.vendor_id() : 0;
+    dev_id.product_id = id.has_product_id() ? id.product_id() : 0;
+    usb_whitelist->push_back(dev_id);
+  }
+  return true;
+}
+
+bool DevicePolicyImpl::VerifyPolicyFiles() {
+  // Both the policy and its signature have to exist.
+  if (!base::PathExists(policy_path_) || !base::PathExists(keyfile_path_)) {
+    return false;
+  }
+
+  // Check if the policy and signature file is owned by root.
+  struct stat file_stat;
+  stat(policy_path_.value().c_str(), &file_stat);
+  if (file_stat.st_uid != 0) {
+    LOG(ERROR) << "Policy file is not owned by root!";
+    return false;
+  }
+  stat(keyfile_path_.value().c_str(), &file_stat);
+  if (file_stat.st_uid != 0) {
+    LOG(ERROR) << "Policy signature file is not owned by root!";
+    return false;
+  }
+  return true;
+}
+
+bool DevicePolicyImpl::VerifyPolicySignature() {
+  if (policy_.has_policy_data_signature()) {
+    std::string policy_data = policy_.policy_data();
+    std::string policy_data_signature = policy_.policy_data_signature();
+    std::string public_key;
+    if (!ReadPublicKeyFromFile(base::FilePath(keyfile_path_), &public_key)) {
+      LOG(ERROR) << "Could not read owner key off disk";
+      return false;
+    }
+    if (!VerifySignature(policy_data, policy_data_signature, public_key)) {
+      LOG(ERROR) << "Signature does not match the data or can not be verified!";
+      return false;
+    }
+    return true;
+  }
+  LOG(ERROR) << "The policy blob is not signed!";
+  return false;
+}
+
+}  // namespace policy
diff --git a/libbrillo/policy/device_policy_impl.h b/libbrillo/policy/device_policy_impl.h
new file mode 100644
index 0000000..db22475
--- /dev/null
+++ b/libbrillo/policy/device_policy_impl.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 The Chromium OS 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 LIBBRILLO_POLICY_DEVICE_POLICY_IMPL_H_
+#define LIBBRILLO_POLICY_DEVICE_POLICY_IMPL_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include <base/files/file_path.h>
+#include <base/macros.h>
+
+#include "bindings/chrome_device_policy.pb.h"
+#include "bindings/device_management_backend.pb.h"
+#include "policy/device_policy.h"
+
+#pragma GCC visibility push(default)
+
+namespace policy {
+
+// This class holds device settings that are to be enforced across all users.
+//
+// Before serving it to the users this class verifies that the policy is valid
+// against its signature and the owner's key and also that the policy files
+// are owned by root.
+class DevicePolicyImpl : public DevicePolicy {
+ public:
+  DevicePolicyImpl();
+  virtual ~DevicePolicyImpl();
+
+  virtual bool LoadPolicy();
+  virtual bool GetPolicyRefreshRate(int* rate) const;
+  virtual bool GetUserWhitelist(std::vector<std::string>* user_whitelist) const;
+  virtual bool GetGuestModeEnabled(bool* guest_mode_enabled) const;
+  virtual bool GetCameraEnabled(bool* camera_enabled) const;
+  virtual bool GetShowUserNames(bool* show_user_names) const;
+  virtual bool GetDataRoamingEnabled(bool* data_roaming_enabled) const;
+  virtual bool GetAllowNewUsers(bool* allow_new_users) const;
+  virtual bool GetMetricsEnabled(bool* metrics_enabled) const;
+  virtual bool GetReportVersionInfo(bool* report_version_info) const;
+  virtual bool GetReportActivityTimes(bool* report_activity_times) const;
+  virtual bool GetReportBootMode(bool* report_boot_mode) const;
+  virtual bool GetEphemeralUsersEnabled(bool* ephemeral_users_enabled) const;
+  virtual bool GetReleaseChannel(std::string* release_channel) const;
+  virtual bool GetReleaseChannelDelegated(
+      bool* release_channel_delegated) const;
+  virtual bool GetUpdateDisabled(bool* update_disabled) const;
+  virtual bool GetTargetVersionPrefix(
+      std::string* target_version_prefix) const;
+  virtual bool GetScatterFactorInSeconds(
+      int64_t* scatter_factor_in_seconds) const;
+  virtual bool GetAllowedConnectionTypesForUpdate(
+      std::set<std::string>* connection_types) const;
+  virtual bool GetOpenNetworkConfiguration(
+      std::string* open_network_configuration) const;
+  virtual bool GetOwner(std::string* owner) const;
+  virtual bool GetHttpDownloadsEnabled(bool* http_downloads_enabled) const;
+  virtual bool GetAuP2PEnabled(bool* au_p2p_enabled) const;
+  virtual bool GetAllowKioskAppControlChromeVersion(
+      bool* allow_kiosk_app_control_chrome_version) const;
+  virtual bool GetUsbDetachableWhitelist(
+      std::vector<UsbDeviceId>* usb_whitelist) const;
+
+ protected:
+  // Verifies that the policy files are owned by root and exist.
+  virtual bool VerifyPolicyFiles();
+
+  base::FilePath policy_path_;
+  base::FilePath keyfile_path_;
+
+ private:
+  // Verifies that the policy signature is correct.
+  virtual bool VerifyPolicySignature();
+
+  enterprise_management::PolicyFetchResponse policy_;
+  enterprise_management::PolicyData policy_data_;
+  enterprise_management::ChromeDeviceSettingsProto device_policy_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevicePolicyImpl);
+};
+}  // namespace policy
+
+#pragma GCC visibility pop
+
+#endif  // LIBBRILLO_POLICY_DEVICE_POLICY_IMPL_H_
diff --git a/libbrillo/policy/libpolicy.cc b/libbrillo/policy/libpolicy.cc
new file mode 100644
index 0000000..c075c84
--- /dev/null
+++ b/libbrillo/policy/libpolicy.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 The Chromium OS 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 "policy/libpolicy.h"
+
+#include <base/logging.h>
+
+#include "policy/device_policy.h"
+#ifndef __ANDROID__
+#include "policy/device_policy_impl.h"
+#endif
+
+namespace policy {
+
+PolicyProvider::PolicyProvider()
+    : device_policy_(nullptr),
+      device_policy_is_loaded_(false) {
+#ifndef __ANDROID__
+  device_policy_.reset(new DevicePolicyImpl());
+#endif
+}
+
+PolicyProvider::PolicyProvider(DevicePolicy* device_policy)
+    : device_policy_(device_policy),
+      device_policy_is_loaded_(true) {
+}
+
+PolicyProvider::~PolicyProvider() {
+}
+
+bool PolicyProvider::Reload() {
+  if (!device_policy_)
+    return false;
+  device_policy_is_loaded_ = device_policy_->LoadPolicy();
+  if (!device_policy_is_loaded_) {
+    LOG(WARNING) << "Could not load the device policy file.";
+  }
+  return device_policy_is_loaded_;
+}
+
+bool PolicyProvider::device_policy_is_loaded() const {
+  return device_policy_is_loaded_;
+}
+
+const DevicePolicy& PolicyProvider::GetDevicePolicy() const {
+  if (!device_policy_is_loaded_)
+    DCHECK("Trying to get policy data but policy was not loaded!");
+
+  return *device_policy_;
+}
+
+}  // namespace policy
diff --git a/libbrillo/policy/libpolicy.h b/libbrillo/policy/libpolicy.h
new file mode 100644
index 0000000..eeca189
--- /dev/null
+++ b/libbrillo/policy/libpolicy.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium OS 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 LIBBRILLO_POLICY_LIBPOLICY_H_
+#define LIBBRILLO_POLICY_LIBPOLICY_H_
+
+#include <memory>
+#include <string>
+
+#include <base/macros.h>
+
+#pragma GCC visibility push(default)
+
+namespace policy {
+
+class DevicePolicy;
+
+// This class holds device settings that are to be enforced across all users.
+//
+// If there is a policy on disk at creation time, we will load it at verify
+// its signature.
+class PolicyProvider {
+ public:
+  PolicyProvider();
+  virtual ~PolicyProvider();
+
+  // Constructor for tests only!
+  explicit PolicyProvider(DevicePolicy* device_policy);
+
+  // This function will ensure the freshness of the contents that the getters
+  // are delivering. Normally contents are cached to prevent unnecessary load.
+  virtual bool Reload();
+
+  virtual bool device_policy_is_loaded() const;
+
+  // Returns a value from the device policy cache.
+  virtual const DevicePolicy& GetDevicePolicy() const;
+
+ private:
+  std::unique_ptr<DevicePolicy> device_policy_;
+  bool device_policy_is_loaded_;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyProvider);
+};
+}  // namespace policy
+
+#pragma GCC visibility pop
+
+#endif  // LIBBRILLO_POLICY_LIBPOLICY_H_
diff --git a/libbrillo/policy/mock_device_policy.h b/libbrillo/policy/mock_device_policy.h
new file mode 100644
index 0000000..cabba91
--- /dev/null
+++ b/libbrillo/policy/mock_device_policy.h
@@ -0,0 +1,107 @@
+// Copyright (c) 2012 The Chromium OS 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 LIBBRILLO_POLICY_MOCK_DEVICE_POLICY_H_
+#define LIBBRILLO_POLICY_MOCK_DEVICE_POLICY_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include <gmock/gmock.h>
+
+#include "policy/device_policy.h"
+
+#pragma GCC visibility push(default)
+
+namespace policy {
+
+// This is a generic mock class for the DevicePolicy that can be used by other
+// subsystems for tests. It allows to mock out the reading of a real policy
+// file and to simulate different policy values.
+// The test that needs policies would then do something like this :
+// // Prepare the action that would return a predefined policy value:
+// ACTION_P(SetMetricsPolicy, enabled) {
+//   *arg0 = enabled;
+//   return true;
+// }
+// ...
+// // Initialize the Mock class
+// policy::MockDevicePolicy* device_policy = new policy::MockDevicePolicy();
+// // We should expect calls to LoadPolicy almost always and return true.
+// EXPECT_CALL(*device_policy_, LoadPolicy())
+//     .Times(AnyNumber())
+//     .WillRepeatedly(Return(true));
+// // This example needs to simulate the Metrics Enabled policy being set.
+// EXPECT_CALL(*device_policy_, GetMetricsEnabled(_))
+//     .Times(AnyNumber())
+//     .WillRepeatedly(SetMetricsPolicy(true));
+// policy::PolicyProvider provider(device_policy);
+// ...
+// // In a test that needs other value of that policy we can do that:
+// EXPECT_CALL(*device_policy_, GetMetricsEnabled(_))
+//     .WillOnce(SetMetricsPolicy(false));
+//
+// See metrics_library_test.cc for example.
+class MockDevicePolicy : public DevicePolicy {
+ public:
+  MockDevicePolicy() {
+    ON_CALL(*this, LoadPolicy()).WillByDefault(testing::Return(true));
+  }
+  ~MockDevicePolicy() override = default;
+
+  MOCK_METHOD0(LoadPolicy, bool(void));
+
+  MOCK_CONST_METHOD1(GetPolicyRefreshRate,
+                     bool(int*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetUserWhitelist, bool(std::vector<std::string>*));
+  MOCK_CONST_METHOD1(GetGuestModeEnabled,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetCameraEnabled,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetShowUserNames,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetDataRoamingEnabled,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetAllowNewUsers,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetMetricsEnabled,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetReportVersionInfo,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetReportActivityTimes,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetReportBootMode,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetEphemeralUsersEnabled,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetReleaseChannel, bool(std::string*));
+  MOCK_CONST_METHOD1(GetReleaseChannelDelegated,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetUpdateDisabled,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetTargetVersionPrefix, bool(std::string*));
+  MOCK_CONST_METHOD1(GetScatterFactorInSeconds,
+                     bool(int64_t*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetAllowedConnectionTypesForUpdate,
+                     bool(std::set<std::string>*));
+  MOCK_CONST_METHOD1(GetOpenNetworkConfiguration, bool(std::string*));
+  MOCK_CONST_METHOD1(GetOwner, bool(std::string*));
+  MOCK_CONST_METHOD1(GetHttpDownloadsEnabled,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetAuP2PEnabled,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetAllowKioskAppControlChromeVersion,
+                     bool(bool*));  // NOLINT(readability/function)
+  MOCK_CONST_METHOD1(GetUsbDetachableWhitelist,
+                     bool(std::vector<DevicePolicy::UsbDeviceId>*));
+
+  MOCK_METHOD0(VerifyPolicyFiles, bool(void));
+  MOCK_METHOD0(VerifyPolicySignature, bool(void));
+};
+}  // namespace policy
+
+#pragma GCC visibility pop
+
+#endif  // LIBBRILLO_POLICY_MOCK_DEVICE_POLICY_H_
diff --git a/libbrillo/policy/mock_libpolicy.h b/libbrillo/policy/mock_libpolicy.h
new file mode 100644
index 0000000..acb9b8b
--- /dev/null
+++ b/libbrillo/policy/mock_libpolicy.h
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium OS 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 LIBBRILLO_POLICY_MOCK_LIBPOLICY_H_
+#define LIBBRILLO_POLICY_MOCK_LIBPOLICY_H_
+
+#include <gmock/gmock.h>
+#include <set>
+
+#include "policy/libpolicy.h"
+
+#pragma GCC visibility push(default)
+
+namespace policy {
+
+// This is a generic mock of the PolicyProvider class.
+class MockPolicyProvider : public PolicyProvider {
+ public:
+  MockPolicyProvider() = default;
+  ~MockPolicyProvider() override = default;
+
+  MOCK_METHOD0(Reload, bool(void));
+  MOCK_CONST_METHOD0(device_policy_is_loaded, bool(void));
+  MOCK_CONST_METHOD0(GetDevicePolicy, const DevicePolicy&(void));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockPolicyProvider);
+};
+
+}  // namespace policy
+
+#pragma GCC visibility pop
+
+#endif  // LIBBRILLO_POLICY_MOCK_LIBPOLICY_H_
diff --git a/libbrillo/policy/tests/libpolicy_unittest.cc b/libbrillo/policy/tests/libpolicy_unittest.cc
new file mode 100644
index 0000000..2946ee7
--- /dev/null
+++ b/libbrillo/policy/tests/libpolicy_unittest.cc
@@ -0,0 +1,233 @@
+// Copyright (c) 2012 The Chromium OS 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 "policy/libpolicy.h"
+
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
+#include <base/files/file_path.h>
+#include <base/logging.h>
+#include <gtest/gtest.h>
+
+#include "policy/device_policy_impl.h"
+
+namespace policy {
+
+static const char kPolicyFileAllSet[] =
+    "policy/tests/whitelist/policy_all";
+static const char kPolicyFileNoneSet[] =
+    "policy/tests/whitelist/policy_none";
+static const char kKeyFile[] = "policy/tests/whitelist/owner.key";
+
+// This class mocks only the minimally needed functionionality to run tests
+// that would otherwise fail because of hard restrictions like root file
+// ownership. Otherwise, it preserves all the functionallity of the original
+// class.
+class MockDevicePolicyImpl : public DevicePolicyImpl {
+ public:
+  MockDevicePolicyImpl(const base::FilePath& policy_path,
+                       const base::FilePath& keyfile_path,
+                       bool verify_files)
+      : verify_files_(verify_files) {
+    policy_path_ = policy_path;
+    keyfile_path_ = keyfile_path;
+  }
+
+ private:
+  // We don't care if files are owned by root for most tests.
+  virtual bool VerifyPolicyFiles() {
+    return !verify_files_ || DevicePolicyImpl::VerifyPolicyFiles();
+  }
+
+  bool verify_files_;
+};
+
+// Test that a policy file can be verified and parsed correctly. The file
+// contains all possible fields, so reading should succeed for all.
+TEST(PolicyTest, DevicePolicyAllSetTest) {
+  base::FilePath policy_file(kPolicyFileAllSet);
+  base::FilePath key_file(kKeyFile);
+  MockDevicePolicyImpl* device_policy =
+      new MockDevicePolicyImpl(policy_file, key_file, false);
+  PolicyProvider provider(device_policy);
+  provider.Reload();
+
+  // Ensure we successfully loaded the device policy file.
+  ASSERT_TRUE(provider.device_policy_is_loaded());
+
+  const DevicePolicy& policy = provider.GetDevicePolicy();
+
+  // Check that we can read out all fields of the sample protobuf.
+  int int_value = -1;
+  ASSERT_TRUE(policy.GetPolicyRefreshRate(&int_value));
+  ASSERT_EQ(100, int_value);
+
+  std::vector<std::string> list_value;
+  ASSERT_TRUE(policy.GetUserWhitelist(&list_value));
+  ASSERT_EQ(3, list_value.size());
+  ASSERT_EQ("me@here.com", list_value[0]);
+  ASSERT_EQ("you@there.com", list_value[1]);
+  ASSERT_EQ("*@monsters.com", list_value[2]);
+
+  bool bool_value = true;
+  ASSERT_TRUE(policy.GetGuestModeEnabled(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetCameraEnabled(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetShowUserNames(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetDataRoamingEnabled(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetAllowNewUsers(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetMetricsEnabled(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetReportVersionInfo(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetReportActivityTimes(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetReportBootMode(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetEphemeralUsersEnabled(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  std::string string_value;
+  ASSERT_TRUE(policy.GetReleaseChannel(&string_value));
+  ASSERT_EQ("stable-channel", string_value);
+
+  bool_value = false;
+  ASSERT_TRUE(policy.GetReleaseChannelDelegated(&bool_value));
+  ASSERT_TRUE(bool_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetUpdateDisabled(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  int64_t int64_value = -1LL;
+  ASSERT_TRUE(policy.GetScatterFactorInSeconds(&int64_value));
+  ASSERT_EQ(17LL, int64_value);
+
+  ASSERT_TRUE(policy.GetTargetVersionPrefix(&string_value));
+  ASSERT_EQ("42.0.", string_value);
+
+  std::set<std::string> types;
+  ASSERT_TRUE(policy.GetAllowedConnectionTypesForUpdate(&types));
+  ASSERT_TRUE(types.end() != types.find("ethernet"));
+  ASSERT_TRUE(types.end() != types.find("wifi"));
+  ASSERT_EQ(2, types.size());
+
+  ASSERT_TRUE(policy.GetOpenNetworkConfiguration(&string_value));
+  ASSERT_EQ("{}", string_value);
+
+  ASSERT_TRUE(policy.GetOwner(&string_value));
+  ASSERT_EQ("", string_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetHttpDownloadsEnabled(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetAuP2PEnabled(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  bool_value = true;
+  ASSERT_TRUE(policy.GetAllowKioskAppControlChromeVersion(&bool_value));
+  ASSERT_FALSE(bool_value);
+
+  std::vector<DevicePolicy::UsbDeviceId> list_device;
+  ASSERT_TRUE(policy.GetUsbDetachableWhitelist(&list_device));
+  ASSERT_EQ(2, list_device.size());
+  ASSERT_EQ(0x413c, list_device[0].vendor_id);
+  ASSERT_EQ(0x2105, list_device[0].product_id);
+  ASSERT_EQ(0x0403, list_device[1].vendor_id);
+  ASSERT_EQ(0x6001, list_device[1].product_id);
+
+  // Reloading the protobuf should succeed.
+  ASSERT_TRUE(provider.Reload());
+}
+
+// Test that a policy file can be verified and parsed correctly. The file
+// contains none of the possible fields, so reading should fail for all.
+TEST(PolicyTest, DevicePolicyNoneSetTest) {
+  base::FilePath policy_file(kPolicyFileNoneSet);
+  base::FilePath key_file(kKeyFile);
+  MockDevicePolicyImpl* device_policy =
+      new MockDevicePolicyImpl(policy_file, key_file, false);
+  PolicyProvider provider(device_policy);
+  provider.Reload();
+
+  // Ensure we successfully loaded the device policy file.
+  ASSERT_TRUE(provider.device_policy_is_loaded());
+
+  const DevicePolicy& policy = provider.GetDevicePolicy();
+
+  // Check that we cannot read any fields out of the sample protobuf.
+  int int_value;
+  int64_t int64_value;
+  std::vector<std::string> list_value;
+  bool bool_value;
+  std::string string_value;
+  std::vector<DevicePolicy::UsbDeviceId> list_device;
+
+  ASSERT_FALSE(policy.GetPolicyRefreshRate(&int_value));
+  ASSERT_FALSE(policy.GetUserWhitelist(&list_value));
+  ASSERT_FALSE(policy.GetGuestModeEnabled(&bool_value));
+  ASSERT_FALSE(policy.GetCameraEnabled(&bool_value));
+  ASSERT_FALSE(policy.GetShowUserNames(&bool_value));
+  ASSERT_FALSE(policy.GetDataRoamingEnabled(&bool_value));
+  ASSERT_FALSE(policy.GetAllowNewUsers(&bool_value));
+  ASSERT_FALSE(policy.GetMetricsEnabled(&bool_value));
+  ASSERT_FALSE(policy.GetReportVersionInfo(&bool_value));
+  ASSERT_FALSE(policy.GetReportActivityTimes(&bool_value));
+  ASSERT_FALSE(policy.GetReportBootMode(&bool_value));
+  ASSERT_FALSE(policy.GetEphemeralUsersEnabled(&bool_value));
+  ASSERT_FALSE(policy.GetReleaseChannel(&string_value));
+  ASSERT_FALSE(policy.GetUpdateDisabled(&bool_value));
+  ASSERT_FALSE(policy.GetTargetVersionPrefix(&string_value));
+  ASSERT_FALSE(policy.GetScatterFactorInSeconds(&int64_value));
+  ASSERT_FALSE(policy.GetOpenNetworkConfiguration(&string_value));
+  ASSERT_FALSE(policy.GetHttpDownloadsEnabled(&bool_value));
+  ASSERT_FALSE(policy.GetAuP2PEnabled(&bool_value));
+  ASSERT_FALSE(policy.GetAllowKioskAppControlChromeVersion(&bool_value));
+  ASSERT_FALSE(policy.GetUsbDetachableWhitelist(&list_device));
+}
+
+// Verify that the library will correctly recognize and signal missing files.
+TEST(PolicyTest, DevicePolicyFailure) {
+  LOG(INFO) << "Errors expected.";
+  // Try loading non-existing protobuf should fail.
+  base::FilePath non_existing("this_file_is_doof");
+  MockDevicePolicyImpl* device_policy =
+      new MockDevicePolicyImpl(non_existing, non_existing, true);
+  PolicyProvider provider(device_policy);
+  // Even after reload the policy should still be not loaded.
+  ASSERT_FALSE(provider.Reload());
+  ASSERT_FALSE(provider.device_policy_is_loaded());
+}
+
+}  // namespace policy
+
+int main(int argc, char* argv[]) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/libbrillo/policy/tests/whitelist/README b/libbrillo/policy/tests/whitelist/README
new file mode 100644
index 0000000..34d63d0
--- /dev/null
+++ b/libbrillo/policy/tests/whitelist/README
@@ -0,0 +1,4 @@
+The files in this directory are sample Device Policy File. To modify them please
+refer to the following instructions:
+
+  http://www.chromium.org/developers/how-tos/enterprise/protobuf-encoded-policy-blobs
diff --git a/libbrillo/policy/tests/whitelist/owner.key b/libbrillo/policy/tests/whitelist/owner.key
new file mode 100644
index 0000000..352c42c
--- /dev/null
+++ b/libbrillo/policy/tests/whitelist/owner.key
Binary files differ
diff --git a/libbrillo/policy/tests/whitelist/policy_all b/libbrillo/policy/tests/whitelist/policy_all
new file mode 100644
index 0000000..b2b8f10
--- /dev/null
+++ b/libbrillo/policy/tests/whitelist/policy_all
Binary files differ
diff --git a/libbrillo/policy/tests/whitelist/policy_none b/libbrillo/policy/tests/whitelist/policy_none
new file mode 100644
index 0000000..5d1cf1f
--- /dev/null
+++ b/libbrillo/policy/tests/whitelist/policy_none
Binary files differ
diff --git a/libbrillo/testrunner.cc b/libbrillo/testrunner.cc
new file mode 100644
index 0000000..7122b9c
--- /dev/null
+++ b/libbrillo/testrunner.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// based on pam_google_testrunner.cc
+
+#include <glib-object.h>
+#include <gtest/gtest.h>
+
+#include <base/at_exit.h>
+#include <brillo/test_helpers.h>
+
+int main(int argc, char** argv) {
+  base::AtExitManager at_exit_manager;
+  ::g_type_init();
+  SetUpTests(&argc, argv, true);
+  return RUN_ALL_TESTS();
+}
diff --git a/libbrillo/testrunner_android.cc b/libbrillo/testrunner_android.cc
new file mode 100644
index 0000000..93377bf
--- /dev/null
+++ b/libbrillo/testrunner_android.cc
@@ -0,0 +1,26 @@
+//Copyright (C) 2015 The Android Open Source Project
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+// based on testrunner.cc with the glib bits removed.
+
+#include <gtest/gtest.h>
+
+#include <base/at_exit.h>
+#include <brillo/test_helpers.h>
+
+int main(int argc, char** argv) {
+  base::AtExitManager at_exit_manager;
+  SetUpTests(&argc, argv, true);
+  return RUN_ALL_TESTS();
+}