Project import
diff --git a/common/MODULE_LICENSE_APACHE2 b/common/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/common/MODULE_LICENSE_APACHE2
diff --git a/common/NOTICE b/common/NOTICE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/common/NOTICE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/common/brillo_camera/Android.mk b/common/brillo_camera/Android.mk
new file mode 100644
index 0000000..950ed33
--- /dev/null
+++ b/common/brillo_camera/Android.mk
@@ -0,0 +1,33 @@
+# Copyright 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := brillo_camera_client
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libbrillo \
+    libbrillo-binder \
+    libcamera_client \
+    libcamera_metadata \
+    libchrome \
+    libcutils \
+    libgui \
+    libutils
+LOCAL_SRC_FILES := \
+    main.cpp
+include $(BUILD_EXECUTABLE)
diff --git a/common/brillo_camera/main.cpp b/common/brillo_camera/main.cpp
new file mode 100644
index 0000000..6d5a3f8
--- /dev/null
+++ b/common/brillo_camera/main.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2016 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 <iostream>
+#include <string>
+
+#include <base/at_exit.h>
+#include <base/bind.h>
+#include <base/logging.h>
+#include <binder/IServiceManager.h>
+#include <brillo/binder_watcher.h>
+#include <brillo/message_loops/base_message_loop.h>
+#include <brillo/syslog_logging.h>
+#include <camera/CameraMetadata.h>
+#include <camera/ICameraService.h>
+#include <camera/camera2/CaptureRequest.h>
+#include <camera/camera2/ICameraDeviceCallbacks.h>
+#include <camera/camera2/ICameraDeviceUser.h>
+#include <camera/camera2/OutputConfiguration.h>
+#include <gui/BufferQueue.h>
+#include <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/CpuConsumer.h>
+#include <gui/Surface.h>
+#include <hardware/camera3.h>
+#include <system/camera_metadata.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
+using android::BnCameraDeviceCallbacks;
+using android::BufferQueue;
+using android::CameraMetadata;
+using android::CaptureRequest;
+using android::CaptureResultExtras;
+using android::CpuConsumer;
+using android::ICameraDeviceCallbacks;
+using android::ICameraDeviceUser;
+using android::ICameraService;
+using android::IGraphicBufferConsumer;
+using android::IGraphicBufferProducer;
+using android::OK;
+using android::String16;
+using android::Surface;
+using android::sp;
+
+namespace {
+
+// TODO(wiley) This constant should probably come out that client library, but
+//             where is not obvious.
+const char kCameraServiceName[] = "media.camera";
+// TODO(wiley) This happens to be a format supported by both gralloc.default and
+//             the golfish camera HAL, but I have no idea how to get this into
+//             an actual viewable image.
+const int kHalPixelFormat = HAL_PIXEL_FORMAT_RAW16;
+
+class CameraDeviceCallbacks : public BnCameraDeviceCallbacks {
+ public:
+  explicit CameraDeviceCallbacks(brillo::MessageLoop* loop) : loop_(loop) {}
+
+  void onDeviceError(ICameraDeviceCallbacks::CameraErrorCode error_code,
+                     const CaptureResultExtras& /* result_extras */) override {
+    LOG(ERROR) << "Received camera error = " << error_code;
+    loop_->BreakLoop();
+  }
+
+  void onDeviceIdle() override {
+    LOG(INFO) << "Camera device is idle";
+  }
+
+  void onCaptureStarted(
+      const CaptureResultExtras& /* result_extras */,
+      int64_t /* timestamp */) override {
+    LOG(INFO) << "Capture started.";
+  }
+
+  void onResultReceived(
+      const CameraMetadata& /* metadata */,
+      const CaptureResultExtras& /* result_extras */) override {
+    LOG(INFO) << "Capture result received";
+    result_received_ = true;
+    loop_->BreakLoop();
+  }
+
+  void onPrepared(int stream_id) override {
+    LOG(INFO) << "Camera is prepared for stream " << stream_id;
+  }
+
+  bool result_received() { return result_received_; }
+
+ private:
+  brillo::MessageLoop* loop_ = nullptr;
+  bool result_received_ = false;
+};
+
+}  // namespace
+
+
+int main() {
+  base::AtExitManager at_exit_manager;
+  brillo::InitLog(brillo::kLogToStderr);
+
+  // Create a message loop.
+  brillo::BaseMessageLoop message_loop;
+
+  // Initialize a binder watcher.
+  brillo::BinderWatcher watcher(&message_loop);
+  watcher.Init();
+
+  LOG(INFO) << "Retrieving a binder for the camera service.";
+  sp<ICameraService> camera_service;
+  android::status_t status = android::getService(
+      String16(kCameraServiceName), &camera_service);
+  CHECK(status == OK)
+      << "Failed to get ICameraService binder from service manager!";
+
+  LOG(INFO) << "Asking how many cameras we have.";
+  const int32_t num_cameras = camera_service->getNumberOfCameras(
+      ICameraService::CAMERA_TYPE_ALL);
+  CHECK(num_cameras > 0)
+      << "ICameraService reports no cameras available";
+
+  const int camera_id = 0;
+  LOG(INFO) << "Connecting to camera " << camera_id;
+  sp<CameraDeviceCallbacks> camera_cb =
+      new CameraDeviceCallbacks(&message_loop);
+  sp<ICameraDeviceCallbacks> camera_cb_alias = camera_cb;
+  const String16 client_package_name("brillo");
+  sp<ICameraDeviceUser> camera_device_user;
+  status = camera_service->connectDevice(
+      camera_cb_alias, camera_id, client_package_name,
+      ICameraService::USE_CALLING_UID,
+      camera_device_user);
+  CHECK(status == OK) << "Failed to connect to camera id=" << camera_id
+                      << " error=" << status;
+
+  LOG(INFO) << "Obtaining camera info";
+  CameraMetadata camera_metadata;
+  status = camera_device_user->getCameraInfo(&camera_metadata);
+  CHECK(status == OK) << "Failed to get camera info, error=" << status;
+
+  LOG(INFO) << "Calculating smallest stream configuration";
+  camera_metadata_entry streamConfigs =
+      camera_metadata.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+  int32_t width = std::numeric_limits<int32_t>::max();
+  int32_t height = 1;
+  for (size_t i = 0; i < streamConfigs.count; i += 4) {
+    int32_t fmt = streamConfigs.data.i32[i];
+    int32_t inout = streamConfigs.data.i32[i + 3];
+    if (fmt == ANDROID_SCALER_AVAILABLE_FORMATS_RAW16 &&
+        inout == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) {
+      int32_t w = streamConfigs.data.i32[i + 1];
+      int32_t h = streamConfigs.data.i32[i + 2];
+
+      if (width * height > w * h) {
+        width = w;
+        height = h;
+      }
+    }
+  }
+  LOG(INFO) << "width = " << width << " height = " << height;
+  CHECK(width != std::numeric_limits<int32_t>::max())
+      << "Unable to configure stream dimensions";
+
+  LOG(INFO) << "Obtaining buffer queue";
+  sp<IGraphicBufferProducer> buffer_producer = nullptr;
+  sp<IGraphicBufferConsumer> buffer_consumer = nullptr;
+  BufferQueue::createBufferQueue(&buffer_producer, &buffer_consumer);
+  CHECK(buffer_producer.get() != nullptr && buffer_consumer.get() != nullptr);
+
+  LOG(INFO) << "Creating buffer consumer";
+  sp<CpuConsumer> consumer = new CpuConsumer(
+      buffer_consumer, 1 /* one frame only */, true /* controlled by app */);
+  consumer->setDefaultBufferSize(width, height);
+  consumer->setDefaultBufferFormat(kHalPixelFormat);
+
+  LOG(INFO) << "Configuring the camera";
+  status = camera_device_user->beginConfigure();
+  CHECK(status == OK) << "Failed calling ICameraDeviceUser::beginConfigure()"
+                      << " error = " << status;
+  android::OutputConfiguration output_configuration(
+      buffer_producer, CAMERA3_STREAM_ROTATION_0);
+  status = camera_device_user->createStream(output_configuration);
+  CHECK(status == OK) << "Failed calling ICameraDeviceUser::createStream()"
+                      << " error = " << status;
+  status = camera_device_user->endConfigure(false /* isConstrainedHighSpeed */);
+  CHECK(status == OK) << "Failed calling ICameraDeviceUser::endConfigure()"
+                      << " error = " << status;
+
+  LOG(INFO) << "Creating capture_request";
+  sp<CaptureRequest> capture_request = new CaptureRequest;
+  status = camera_device_user->createDefaultRequest(
+      CAMERA3_TEMPLATE_STILL_CAPTURE, &capture_request->mMetadata);
+  sp<Surface> surface = new Surface(
+      buffer_producer, true /* controlled by app */);
+  capture_request->mSurfaceList.push_back(surface);
+  capture_request->mIsReprocess = false;
+
+  LOG(INFO) << "Submitting capture request";
+  int64_t last_frame_number = 0;
+  status = camera_device_user->submitRequest(
+      capture_request, false, &last_frame_number);
+  CHECK(status == OK) << "Got error=" << status
+                      << " while submitting capture request.";
+
+  LOG(INFO) << "Waiting for the camera to take a picture.";
+  // If we don't hear back from the camera for long enough, just time out.
+  message_loop.PostDelayedTask(
+      base::Bind(&brillo::BaseMessageLoop::BreakLoop,
+                 base::Unretained(&message_loop)),
+      base::TimeDelta::FromSeconds(30));
+  message_loop.Run();  // We'll exit on a callback from the camera.
+
+  CHECK(camera_cb->result_received());
+
+  // TODO(wiley) render this image to a file to save somewhere.
+
+  return 0;
+}
diff --git a/common/brillo_gpios/AndroidProducts.mk b/common/brillo_gpios/AndroidProducts.mk
new file mode 100644
index 0000000..e31e144
--- /dev/null
+++ b/common/brillo_gpios/AndroidProducts.mk
@@ -0,0 +1,16 @@
+#
+# 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.
+#
+PRODUCT_MAKEFILES := $(LOCAL_DIR)/brillo_gpios.mk
diff --git a/common/brillo_gpios/README b/common/brillo_gpios/README
new file mode 100644
index 0000000..be80916
--- /dev/null
+++ b/common/brillo_gpios/README
@@ -0,0 +1,43 @@
+README for Brillo GPIO sample
+
+This GPIO sample demonstrates how to set up GPIO and write/read to GPIO pins.
+Specifically this app does the following.
+
+ - Export an input and output GPIO pins
+ - Set output e.g. pin 24 direction to "out" and value to 1
+ - Set input e.g. pin 28 direction to "in" and edge to "both"
+ - Read input pin by polling
+ - Once input pin is triggered to input value 1, set output value to 0
+
+Once built, you can find the binary inside your tree at:
+
+out/target/product/dragonboard/symbols/system/bin/gpio_playground
+
+Do the following to deploy the sample:
+ - adb root
+ - adb remount
+ - adb sync
+
+Hardware setup:
+ - You need to connect a GPIO pin as output to an LED
+ - You need to connect a GPIO pin as input to a push button switch
+
+Do the following to run the sample on Dragonboard and check logs for info:
+ - Open a shell window and run: adb logcat
+ - Open another shell window and run:
+   - Default input pin 28 and output pin 24
+     - adb shell '/system/bin/gpio_playground &'
+   - Choose your own output and input pins
+     - adb shell '/system/bin/gpio_playground --gin=<input> --gout=<output> &'
+     - For example, adb shell '/system/bin/gpio_playground --gin=28 --gout=24 &'
+ - Observe the logging info from the first window
+ - Observe that the LED of pin 24 is turned on
+ - Now push the switch of pin 28 and see that the LED gets turned off
+
+Notes:
+ - There is a GPIO port offset defined by const kDefaultGpioOffset that depends 
+   on what kind of boards you use. For Dragonboard it is 902. This offset can
+   also be configured by a commandline parameter.
+ - There is an output pin and input pin defined by const kDefaultGpioOut and
+   kDefaultGpioIn respectively.  They can both be configured by commandline
+   parameters.
diff --git a/common/brillo_gpios/brillo_gpios.mk b/common/brillo_gpios/brillo_gpios.mk
new file mode 100644
index 0000000..2c92214
--- /dev/null
+++ b/common/brillo_gpios/brillo_gpios.mk
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+$(call inherit-product, device/generic/brillo/brillo_base.mk)
+
+PRODUCT_NAME := brillo_gpios
+PRODUCT_BRAND := Brillo
+
+PRODUCT_DEVICE := dragonboard
+PRODUCT_PACKAGES += gpio_playground
diff --git a/common/brillo_gpios/src/gpio_playground/Android.mk b/common/brillo_gpios/src/gpio_playground/Android.mk
new file mode 100644
index 0000000..cf4ca71
--- /dev/null
+++ b/common/brillo_gpios/src/gpio_playground/Android.mk
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := gpio_playground
+LOCAL_SRC_FILES := gpio_playground.cpp
+LOCAL_SHARED_LIBRARIES := libchrome libbrillo libbrillo-stream
+LOCAL_C_INCLUDES := external/gtest/include
+LOCAL_CFLAGS := -Wall -Werror -Wno-error=unused-parameter
+include $(BUILD_EXECUTABLE)
diff --git a/common/brillo_gpios/src/gpio_playground/gpio_playground.cpp b/common/brillo_gpios/src/gpio_playground/gpio_playground.cpp
new file mode 100644
index 0000000..2e6319d
--- /dev/null
+++ b/common/brillo_gpios/src/gpio_playground/gpio_playground.cpp
@@ -0,0 +1,212 @@
+/* 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 <string>
+#include <sys/poll.h>
+#include <sys/signalfd.h>
+#include <sys/timerfd.h>
+
+#include <base/files/file_path.h>
+#include <base/format_macros.h>
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_util.h>
+
+#include <brillo/flag_helper.h>
+#include <brillo/streams/file_stream.h>
+#include <brillo/streams/stream_utils.h>
+
+// Define defaults that work on the Dragonboard 410c.
+const int kDefaultGpioPortOffset = 902;
+const int kDefaultGpioOut = 24;
+const int kDefaultGpioIn = 28;
+
+// GPIO sysfs path
+const char* const kGPIOSysfsPath = "/sys/class/gpio";
+// GPIO polling timeout in milliseconds
+const int kPollTimeoutMsecs = 3000; /* 3 seconds */
+const int kBufSize = 10;
+
+namespace {
+
+/*
+ * Get a file stream for GPIO export
+ * bool write: access mode with true for write
+ * return: file stream pointer
+ */
+brillo::StreamPtr GetGPIOExportStream(bool write) {
+  std::string gpio_path;
+  gpio_path = base::StringPrintf("%s/export", kGPIOSysfsPath);
+  base::FilePath dev_path{gpio_path};
+  auto access_mode = brillo::stream_utils::MakeAccessMode(!write, write);
+  return brillo::FileStream::Open(
+      dev_path, access_mode, brillo::FileStream::Disposition::OPEN_EXISTING,
+      nullptr);
+}
+
+/*
+ * Get a file stream for GPIO data
+ * int gpio: GPIO pin number
+ * std::string type: GPIO type e.g. direction, edge, value
+ * bool write: access mode with true for write
+ * return: file stream pointer
+ */
+brillo::StreamPtr GetGPIODataStream(int gpio, const std::string type, bool write) {
+  std::string gpio_path;
+  gpio_path = base::StringPrintf("%s/gpio%d/%s", kGPIOSysfsPath, gpio, type.c_str());
+  base::FilePath dev_path{gpio_path};
+  auto access_mode = brillo::stream_utils::MakeAccessMode(!write, write);
+  return brillo::FileStream::Open(
+      dev_path, access_mode, brillo::FileStream::Disposition::OPEN_EXISTING,
+      nullptr);
+}
+
+}  // anonymous namespace
+
+/*
+ * Export GPIO to user space
+ * int gpio: GPIO pin number
+ */
+void export_gpio(int gpio) {
+
+  brillo::StreamPtr stream = GetGPIOExportStream(true);
+  if (!stream)
+    return;
+
+  std::string value = base::StringPrintf("%d", gpio);
+  stream->WriteAllBlocking(value.data(), value.size(), nullptr);
+}
+
+/*
+ * Write to GPIO
+ * std::string type: what GPIO type i.e. direction, value, edge
+ * std::string v: value to be written
+ * return: true
+ */
+bool write_gpio(int gpio, const std::string type, std::string v) {
+
+  brillo::StreamPtr stream = GetGPIODataStream(gpio, type, true);
+  if (!stream)
+    return false;
+
+  stream->WriteAllBlocking(v.data(), v.size(), nullptr);
+  return true;
+}
+
+/*
+ * This method polls GPIO pin for 0 -> 1 transition.
+ * int gpio: GPIO pin to be polled.
+ * return:
+ *   true if polling reads back successfully
+ *   false if GPIO open error or polling error
+ */
+bool poll_gpio(int gpio) {
+  char buf[kBufSize];
+  struct pollfd fdset[1];
+  int nfds = 1;
+  int fd = -1;
+  int rc = -1;
+  int len = -1;
+
+  std::string gpio_path;
+  gpio_path = base::StringPrintf("%s/gpio%d/value", kGPIOSysfsPath, gpio);
+  fd = open(gpio_path.c_str(), O_RDONLY | O_NONBLOCK );
+  if (fd < 0) {
+     PLOG(ERROR) << "GPIO open error";
+     return false;
+  }
+
+  // Use this sawZeroValue to ignore the first spurious interrupt.
+  bool sawZeroValue = false;
+
+  while(1) {
+    memset((void*)fdset, 0, sizeof(fdset));
+    fdset[0].fd = fd;
+    fdset[0].events = POLLPRI;
+
+    rc = poll(fdset, nfds, kPollTimeoutMsecs);
+    if (rc < 0) {
+      PLOG(ERROR) << "poll() failed!";
+      close(fd);
+      return false;
+    } else if (rc == 0) {
+      LOG(INFO) << "polling...";
+    } else if (fdset[0].revents & POLLPRI) {
+      len = read(fdset[0].fd, buf, kBufSize - 1);
+      lseek(fdset[0].fd, 0, SEEK_SET);
+      if (len >= 0) {
+        buf[len] = '\0';
+      }
+      // TODO: http://b/25317933 Handle the case where read()
+      // might result in multiple events being read.
+      if (buf[0] == '0') {
+        LOG(INFO) << "First interrupt with value 0 ignored.";
+        sawZeroValue = true;
+        continue;
+      }
+      if (sawZeroValue && buf[0] == '1') {
+        LOG(INFO) << "GPIO pin reset and interrupt with value 1 caught.";
+        close(fd);
+        return true;
+      }
+    }
+  }
+  close(fd);
+  return true;
+}
+
+int main(int argc, char **argv) {
+  int gpio_out = -1;
+  int gpio_in = -1;
+  int goffset = kDefaultGpioPortOffset;
+
+  DEFINE_int32(gin, 28, "GPIO input");
+  DEFINE_int32(gout, 24, "GPIO output");
+  DEFINE_int32(goffset, 902, "GPIO port offset for Dragonboard");
+  brillo::FlagHelper::Init(argc, argv, "GPIO Playground.");
+
+  if (argc == 1 || argc == 3 || argc == 4) {
+    if (FLAGS_goffset) {
+      goffset = FLAGS_goffset;
+    }
+    gpio_out = FLAGS_gout + goffset;
+    gpio_in = FLAGS_gin + goffset;
+  } else {
+    printf("Pass input & output GPIO pin as follows\n");
+    printf("adb shell '/system/bin/gpio_playground --gin=28 --gout=24 --goffset=902 &'\n");
+    return -1;
+  }
+
+  LOG(INFO) << "Export pin " << kDefaultGpioOut << " to userspace";
+  export_gpio(gpio_out);
+  LOG(INFO) << "Set pin " << kDefaultGpioOut << " direction to out";
+  write_gpio(gpio_out, "direction", "out");
+  LOG(INFO) << "Set pin " << kDefaultGpioOut << " value to 1";
+  write_gpio(gpio_out, "value", "1");
+
+  LOG(INFO) << "Export pin " << kDefaultGpioIn << " to userspace";
+  export_gpio(gpio_in);
+  LOG(INFO) << "Set pin " << kDefaultGpioIn << " direction to in";
+  write_gpio(gpio_in, "direction", "in");
+  LOG(INFO) << "Set pin " << kDefaultGpioIn << " edge to both";
+  write_gpio(gpio_in, "edge", "both");
+
+  if (poll_gpio(gpio_in)) {
+    LOG(INFO) << "Pin " << kDefaultGpioIn << " pushed. Now turn off LED";
+    write_gpio(gpio_out, "value", "0");
+  }
+  return 0;
+}
diff --git a/common/brillo_gpios/vendorsetup.sh b/common/brillo_gpios/vendorsetup.sh
new file mode 100644
index 0000000..cdec5ff
--- /dev/null
+++ b/common/brillo_gpios/vendorsetup.sh
@@ -0,0 +1 @@
+add_lunch_combo brillo_gpios-userdebug
diff --git a/common/brillo_i2c/AndroidProducts.mk b/common/brillo_i2c/AndroidProducts.mk
new file mode 100644
index 0000000..bb7c051
--- /dev/null
+++ b/common/brillo_i2c/AndroidProducts.mk
@@ -0,0 +1,14 @@
+# 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.
+PRODUCT_MAKEFILES := $(LOCAL_DIR)/brillo_i2c.mk
diff --git a/common/brillo_i2c/brillo_i2c.mk b/common/brillo_i2c/brillo_i2c.mk
new file mode 100644
index 0000000..5ebc92a
--- /dev/null
+++ b/common/brillo_i2c/brillo_i2c.mk
@@ -0,0 +1,20 @@
+# 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.
+
+$(call inherit-product, device/generic/brillo/brillo_base.mk)
+
+PRODUCT_NAME := brillo_i2c
+PRODUCT_BRAND := Brillo
+
+PRODUCT_DEVICE := dragonboard
diff --git a/common/brillo_i2c/src/i2c_service/Android.mk b/common/brillo_i2c/src/i2c_service/Android.mk
new file mode 100644
index 0000000..4f4df94
--- /dev/null
+++ b/common/brillo_i2c/src/i2c_service/Android.mk
@@ -0,0 +1,23 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := i2c_service
+LOCAL_REQUIRED_MODULES := init.i2c_service.rc
+LOCAL_SRC_FILES := i2c_service.cpp i2c_device.cpp
+LOCAL_SHARED_LIBRARIES := libc libbase
+LOCAL_CFLAGS := -Werror
+include $(BUILD_EXECUTABLE)
diff --git a/common/brillo_i2c/src/i2c_service/i2c_device.cpp b/common/brillo_i2c/src/i2c_service/i2c_device.cpp
new file mode 100644
index 0000000..35089b6
--- /dev/null
+++ b/common/brillo_i2c/src/i2c_service/i2c_device.cpp
@@ -0,0 +1,131 @@
+// 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 "i2c_device.h"
+
+I2CDevice::I2CDevice(const char* device_filename,
+                     const uint8_t device_address) :
+  // Does nothing except store the constant values.
+  address_(device_address),
+  filename_(device_filename)
+
+  {
+    LOG(INFO) << "New i2c device for " << address_ << " at " << filename_;
+  }
+
+
+int I2CDevice::Begin() {
+  // First, this opens the /dev device.
+  int rc = open_i2c();
+  if (rc < 0) {
+    return rc;
+  }
+  // Then, registers it as a slave.
+  rc = enslave_i2c();
+  if (rc < 0) {
+    return rc;
+  }
+  return 0;
+}
+
+
+int I2CDevice::End() {
+  return close(fd_);
+}
+
+
+int I2CDevice::open_i2c() {
+  // Opening the device is just a R/W file open.
+  int fd = open(filename_, O_RDWR);
+  if (-1 == fd) {
+    PLOG(ERROR) << "Could not open i2c device.";
+    return -1;
+  }
+  LOG(INFO) << "i2c device opened at " << filename_;
+  fd_ = fd;
+  return fd;
+}
+
+
+int I2CDevice::enslave_i2c() {
+  // The I2C_SLAVE ioctl is sent to the device at the given address.
+  int rc = ioctl(fd_, I2C_SLAVE, address_);
+  if (rc < 0) {
+    PLOG(ERROR) << "i2c device failed to become a slave.";
+    return rc;
+  }
+  printf("yes %x\n", address_);
+  LOG(INFO) << "i2c device is a slave at" << filename_;
+  return rc;
+}
+
+
+int I2CDevice::Send(struct i2c_msg messages[],
+                    const size_t count) {
+  // Sending messages requires them to be wrapped in the i2c_rdwr_ioctl_data
+  // struct and sending them using the I2C_RDWR ioctl.
+  struct i2c_rdwr_ioctl_data data = {
+    .msgs = messages,
+    .nmsgs = count
+  };
+  int rc = ioctl(fd_, I2C_RDWR, &data);
+  if (rc < 0) {
+    PLOG(ERROR) << "Unable to send data.";
+  }
+  return rc;
+}
+
+
+int I2CDevice::SetRegister(const uint8_t register_address,
+                           const uint8_t value) {
+  // Setting a register involves sending a single message with a 2-byte payload.
+  // The first byte is the register address, and the second is the value.
+  uint8_t outbuf[] = {register_address, value};
+  struct i2c_msg messages[1];
+  messages[0] = {
+    .addr = address_,
+    .flags = 0,
+    .len = sizeof(outbuf),
+    .buf = outbuf
+  };
+  return Send(messages, 1);
+}
+
+
+int I2CDevice::GetRegister(const uint8_t register_address,
+                           uint8_t& value) {
+  // Reading a register involves sending two messages, each with a single-byte
+  // payload. The first message contains the register address and the second
+  // message is empty and will contain the response value.
+  struct i2c_msg messages[2];
+  uint8_t outbuf = register_address;
+  // Both messages need the addr value set.
+  messages[0] = {
+    .addr = address_,
+    .flags = 0,
+    .len = 1,
+    .buf = &outbuf
+  };
+  // Needs to pass the I2C_M_RD flag in order to get the value.
+  messages[1] = {
+    .addr = address_,
+    .flags = I2C_M_RD,
+    .len = 1,
+    .buf = &value,
+  };
+  // Will contain the register value.
+  int rc = Send(messages, 2);
+  return rc;
+}
diff --git a/common/brillo_i2c/src/i2c_service/i2c_device.h b/common/brillo_i2c/src/i2c_service/i2c_device.h
new file mode 100644
index 0000000..62eec04
--- /dev/null
+++ b/common/brillo_i2c/src/i2c_service/i2c_device.h
@@ -0,0 +1,70 @@
+// 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.
+
+// Defines a single i2c device at an address for a named i2c bus.
+//
+// Can be used to read and write i2c registers, or send arbitrary streams of
+// messages.
+
+
+#include <fcntl.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <android-base/logging.h>
+
+
+class I2CDevice {
+
+ public:
+  // Creates an I2CDevice for a given filename and address.
+  //
+  // For example: I2CDevice my_device("/dev/i2c-0", 0x20);
+  //
+  // Note: this constructor does not actually open the device, Begin() must be
+  // called at the appropriate time.
+  I2CDevice(const char* device_filename,
+            const uint8_t device_address);
+  // Opens the device for reading and writing. Returns 0 on success, or the
+  // error code from the open/ioctl operations.
+  int Begin();
+  // Closes the device. Returns 0 on success or the error code from the close
+  // operation.
+  int End();
+  // Sends a sequence of I2C messages. This is used for write operations AND
+  // read operations, since reads are just an empty outbound message. Returns 0
+  // on success or the error code from the ioctl operation.
+  int Send(struct i2c_msg messages[],
+           const size_t count);
+  // Sets a register at a given address to a given value. Returns 0 on success
+  // or the error code from the ioctl operation.
+  int SetRegister(const uint8_t register_address,
+                  const uint8_t value);
+  // Reads a register into a passed value. Returns 0 on success or the error
+  // code from the ioctl operation.
+  int GetRegister(const uint8_t register_address,
+                  uint8_t& value);
+
+ private:
+  // Demonstrates opening a device.
+  int open_i2c();
+  // Demonstrates sending the I2C_SLAVE ioctl.
+  int enslave_i2c();
+
+  // Stores the device address.
+  const uint8_t address_;
+  // Stores the device filename.
+  const char* filename_;
+  // Stores the open file descriptor for the device.
+  int fd_;
+};
diff --git a/common/brillo_i2c/src/i2c_service/i2c_service.cpp b/common/brillo_i2c/src/i2c_service/i2c_service.cpp
new file mode 100644
index 0000000..dd6f9c8
--- /dev/null
+++ b/common/brillo_i2c/src/i2c_service/i2c_service.cpp
@@ -0,0 +1,121 @@
+// 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.
+//
+//
+// Example of using i2c devices with Brillo.
+//
+// These use /dev/i2c-6. On the dragonboard 410c, this device maps to i2c1 on
+// pins 19 (SCL) and 21 (SDA).
+
+
+#include <android-base/logging.h>
+
+#include "i2c_device.h"
+
+
+// Example of using the mcp23017 IO port expander.
+//
+// On the expander, pin0 is an output pin, and pin1 is an input pin, simply
+// connected to gnd through an led or switch.
+//
+// 0 -> LED -> gnd
+// 1 -> SWITCH -> gnd
+//
+// i2c is connected directly to the board. Pin1 will use the internal pullup
+// resistor of the mcp23017.
+//
+void io_expander_demo() {
+  // Opens the device at i2c1 at the default address (the default address is
+  // calculated when A0 A1 A2 pins are all pulled low).
+  I2CDevice mcp23017("/dev/i2c-6", 0x20);
+  mcp23017.Begin();
+  // Sets the pin1 as an input, the rest as output.
+  mcp23017.SetRegister(0x0,  0b00000010);
+  // Sets the internal pullup resistor for pin1.
+  mcp23017.SetRegister(0xC,  0b00000010);
+  // Sets the initial values of the GPIOA register.
+  mcp23017.SetRegister(0x12, 0b00000010);
+  uint8_t register_value;
+  while(1) {
+    // Reads the GPIOA register.
+    mcp23017.GetRegister(0x12, register_value);
+    // Decides if switch is on based on whether pin1 is low.
+    uint8_t is_switch_on = (register_value & 0b00000010) >> 1;
+    // Sets the GPIO register at pin0 to reflect the switch state on pin1.
+    mcp23017.SetRegister(0x12, is_switch_on ^ 0b10000001);
+    LOG(INFO) << (is_switch_on ? "On." : "Off.");
+    // Waiting a bit is sensible.
+    usleep(0x10000);
+  }
+}
+
+
+// Example of using the ds1307 real time clock.
+//
+// i2c is connected directly to the board.
+//
+void rtc_demo() {
+  // Opens the device at i2c1 at the default address (the default address is
+  // calculated when A0 A1 A2 pins are all pulled low).
+  I2CDevice ds1307("/dev/i2c-6", 0x68);
+  ds1307.Begin();
+  // Needs three bytes, one for each of seconds, minutes, hours.
+  uint8_t seconds_register_value = 0x0;
+  uint8_t minutes_register_value = 0x0;
+  uint8_t hours_register_value   = 0x0;
+  char time_string[10];
+  while (1) {
+    ds1307.GetRegister(0x0, seconds_register_value);
+    ds1307.GetRegister(0x1, minutes_register_value);
+    ds1307.GetRegister(0x2, hours_register_value);
+    // Munges the values based on their storage scheme.
+    int seconds = 10 * ((seconds_register_value & 0b01110000) >> 4) +
+        (seconds_register_value & 0b00001111);
+    int minutes = 10 * ((minutes_register_value & 0b01110000) >> 4) +
+        (minutes_register_value & 0b00001111);
+    int hours   = 10 * ((hours_register_value & 0b00110000) >> 4) +
+        (hours_register_value & 0b00001111);
+    sprintf(time_string, "%02d:%02d:%02d", hours, minutes, seconds);
+    LOG(INFO) << "Time is:" << time_string;
+    sleep(1);
+  }
+}
+
+
+// Example of reading the ds1307 real time clock, and writing to the mcp23017
+// port expander.
+//
+// This demo uses both devices at the same time.
+void binary_watch_demo() {
+  I2CDevice mcp23017("/dev/i2c-6", 0x20);
+  mcp23017.Begin();
+  mcp23017.SetRegister(0x0,  0b00000000);
+  mcp23017.SetRegister(0x12, 0b00000000);
+  I2CDevice ds1307("/dev/i2c-6", 0x68);
+  ds1307.Begin();
+  uint8_t seconds_register_value = 0x0;
+  while(1) {
+    ds1307.GetRegister(0x0, seconds_register_value);
+    mcp23017.SetRegister(0x12, seconds_register_value << 2);
+    sleep(1);
+  }
+}
+
+
+int main(int argc __unused, char **argv __unused) {
+  //io_expander_demo();
+  //rtc_demo();
+  binary_watch_demo();
+  return 0;
+}
diff --git a/common/brillo_i2c/vendorsetup.sh b/common/brillo_i2c/vendorsetup.sh
new file mode 100644
index 0000000..907895a
--- /dev/null
+++ b/common/brillo_i2c/vendorsetup.sh
@@ -0,0 +1,14 @@
+# 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.
+add_lunch_combo brillo_i2c-userdebug
diff --git a/common/brillo_leds/AndroidProducts.mk b/common/brillo_leds/AndroidProducts.mk
new file mode 100644
index 0000000..7f9fdb1
--- /dev/null
+++ b/common/brillo_leds/AndroidProducts.mk
@@ -0,0 +1 @@
+PRODUCT_MAKEFILES := $(LOCAL_DIR)/brillo_leds.mk
diff --git a/common/brillo_leds/README b/common/brillo_leds/README
new file mode 100644
index 0000000..e0fe8ec
--- /dev/null
+++ b/common/brillo_leds/README
@@ -0,0 +1,23 @@
+README for Brillo LED sample
+
+This LED sample creates a service that can be run on Brillo Dragonboard. It animates LED 1 through LED 4.
+
+Once built, you can find the binary inside your AOSP tree at:
+
+out/target/product/dragonboard/symbols/system/bin/led_service
+
+Do the following to deploy the sample:
+
+ - adb root
+ - adb remount
+ - adb sync
+
+Do the following to run the sample on Dragonboard:
+
+ - adb shell
+ - /system/bin/led_service &
+ - logcat
+
+Note the last step shows logging info
+
+
diff --git a/common/brillo_leds/brillo_leds.mk b/common/brillo_leds/brillo_leds.mk
new file mode 100644
index 0000000..cc2b31e
--- /dev/null
+++ b/common/brillo_leds/brillo_leds.mk
@@ -0,0 +1,8 @@
+$(call inherit-product, device/generic/brillo/brillo_base.mk)
+
+PRODUCT_NAME := brillo_leds
+PRODUCT_BRAND := Brillo
+
+PRODUCT_DEVICE := dragonboard
+PRODUCT_PACKAGES += brillo_led_tool
+
diff --git a/common/brillo_leds/src/brillo_led_tool/Android.mk b/common/brillo_leds/src/brillo_led_tool/Android.mk
new file mode 100644
index 0000000..b9a1320
--- /dev/null
+++ b/common/brillo_leds/src/brillo_led_tool/Android.mk
@@ -0,0 +1,7 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := brillo_led_tool
+LOCAL_SRC_FILES := brillo_led_tool.cpp
+LOCAL_SHARED_LIBRARIES := libc libbase
+LOCAL_CFLAGS := -Werror
+include $(BUILD_EXECUTABLE)
diff --git a/common/brillo_leds/src/brillo_led_tool/brillo_led_tool.cpp b/common/brillo_leds/src/brillo_led_tool/brillo_led_tool.cpp
new file mode 100644
index 0000000..10454f7
--- /dev/null
+++ b/common/brillo_leds/src/brillo_led_tool/brillo_led_tool.cpp
@@ -0,0 +1,33 @@
+#include <unistd.h>
+#include <android-base/logging.h>
+
+int main(int argc __unused, char **argv __unused) {
+  static const char* const leds[] = {
+    "/sys/class/leds/led1/brightness",
+    "/sys/class/leds/led2/brightness",
+    "/sys/class/leds/led3/brightness",
+    "/sys/class/leds/boot/brightness"
+  };
+
+  LOG(INFO) << "starting blinking LEDs";
+  int i = 0;
+  for(;;) {
+    FILE *fp;
+    fp = fopen(leds[i], "w");
+    if (fp == NULL) {
+      PLOG(ERROR) << "Error opening file";
+      return 0;
+    } else {
+      fputs("255", fp);
+      fseek(fp, 0, SEEK_SET);
+      sleep(1);
+      fputs("0", fp);
+      fclose(fp);
+      LOG(INFO) << "toggling LED " << i + 1 << " on/off";
+      i++;
+      i = i % 4;
+    }
+  }
+  LOG(INFO) << "exiting";
+  return 0;
+}
diff --git a/common/brillo_leds/vendorsetup.sh b/common/brillo_leds/vendorsetup.sh
new file mode 100644
index 0000000..ace4f2e
--- /dev/null
+++ b/common/brillo_leds/vendorsetup.sh
@@ -0,0 +1 @@
+add_lunch_combo brillo_leds-userdebug
diff --git a/common/dbus_example/Android.mk b/common/dbus_example/Android.mk
new file mode 100644
index 0000000..5b97f08
--- /dev/null
+++ b/common/dbus_example/Android.mk
@@ -0,0 +1,42 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+dbus_exampleCommonCppExtension := .cc
+dbus_exampleCommonCFlags := -Wall -Werror -Wno-sign-promo \
+  -Wno-unused-parameter
+dbus_exampleCommonSharedLibraries := \
+  libchrome \
+  libchrome-dbus \
+  libdbus \
+  liblog \
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dbus-example-daemon
+LOCAL_SRC_FILES := dbus-example-daemon.cc
+LOCAL_SHARED_LIBRARIES := $(dbus_exampleCommonSharedLibraries)
+LOCAL_CPP_EXTENSION := $(dbus_exampleCommonCppExtension)
+LOCAL_CFLAGS := $(dbus_exampleCommonCFlags)
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dbus-example-client
+LOCAL_SRC_FILES := dbus-example-client.cc
+LOCAL_SHARED_LIBRARIES := $(dbus_exampleCommonSharedLibraries)
+LOCAL_CPP_EXTENSION := $(dbus_exampleCommonCppExtension)
+LOCAL_CFLAGS := $(dbus_exampleCommonCFlags)
+include $(BUILD_EXECUTABLE)
diff --git a/common/dbus_example/build.gradle b/common/dbus_example/build.gradle
new file mode 100644
index 0000000..4271050
--- /dev/null
+++ b/common/dbus_example/build.gradle
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+/* Return the android build root. */
+def gettop = {
+    File cwd = new File('.').absoluteFile
+    while (!(new File(cwd, 'build/core/envsetup.mk')).isFile()) {
+        cwd = cwd.parentFile
+    }
+    return cwd
+}
+
+ext.android_build_root = gettop()
+ext.nr_threads = Runtime.runtime.availableProcessors()
+
+/* Invoke an Android Build System command. */
+def call_abs(cmd) {
+    String full_cmd = 'source "' + android_build_root + '/build/envsetup.sh" && ' + cmd
+    println 'Calling ' + full_cmd
+    exec {
+        commandLine 'sh', '-c', full_cmd
+    }
+}
+
+task build << {
+    call_abs 'mm -j ' + nr_threads
+}
+
+task clean << {
+    call_abs 'm clean'
+}
+
+task buildAll << {
+    call_abs 'm -j ' + nr_threads
+}
+
+task emulator(type: Exec) {
+    commandLine 'emulator-arm'
+}
diff --git a/common/dbus_example/constants.h b/common/dbus_example/constants.h
new file mode 100644
index 0000000..2286440
--- /dev/null
+++ b/common/dbus_example/constants.h
@@ -0,0 +1,30 @@
+/*
+ * 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 DEVICE_GENERIC_BRILLO_EXAMPLES_DBUS_CONSTANTS_H_
+#define DEVICE_GENERIC_BRILLO_EXAMPLES_DBUS_CONSTANTS_H_
+
+namespace dbus_example {
+
+// D-Bus-related constants.
+static const char kServicePath[] = "/com/android/brillo/DBusExample";
+static const char kServiceName[] = "com.android.brillo.DBusExample";
+static const char kInterface[] = "com.android.brillo.DBusExample";
+static const char kMethodName[] = "Ping";
+
+}  // namespace dbus_example
+
+#endif  // DEVICE_GENERIC_BRILLO_EXAMPLES_DBUS_CONSTANTS_H_
diff --git a/common/dbus_example/dbus-example-client.cc b/common/dbus_example/dbus-example-client.cc
new file mode 100644
index 0000000..171bc6f
--- /dev/null
+++ b/common/dbus_example/dbus-example-client.cc
@@ -0,0 +1,68 @@
+/*
+ * 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 <unistd.h>
+
+#include <memory>
+
+#include <dbus/bus.h>
+#include <dbus/message.h>
+#include <dbus/object_proxy.h>
+#include <utils/Log.h>
+
+#include "constants.h"
+
+// Used implicitly.
+#undef LOG_TAG
+#define LOG_TAG "dbus-example-client"
+
+int main(int argc, char *argv[]) {
+  dbus::Bus::Options options;
+  options.bus_type = dbus::Bus::SYSTEM;
+  scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));
+  CHECK(bus->Connect());
+  dbus::ObjectProxy* proxy = bus->GetObjectProxy(
+      dbus_example::kServiceName, dbus::ObjectPath(dbus_example::kServicePath));
+  CHECK(proxy);
+
+  int32_t token = 1;
+  while (true) {
+    dbus::MethodCall method_call(dbus_example::kInterface,
+                                 dbus_example::kMethodName);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendInt32(token);
+
+    ALOGI("Calling %s with %d", dbus_example::kMethodName, token);
+    std::unique_ptr<dbus::Response> response(
+        proxy->CallMethodAndBlock(
+            &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
+    if (!response) {
+      ALOGE("Didn't receive response from server");
+    } else {
+      int32_t response_token = 0;
+      dbus::MessageReader reader(response.get());
+      if (!reader.PopInt32(&response_token))
+        ALOGE("Missing token in response from server");
+      else
+        ALOGI("Received %d", response_token);
+    }
+
+    token++;
+    sleep(1);
+  }
+
+  return 0;
+}
diff --git a/common/dbus_example/dbus-example-daemon.cc b/common/dbus_example/dbus-example-daemon.cc
new file mode 100644
index 0000000..6a069e1
--- /dev/null
+++ b/common/dbus_example/dbus-example-daemon.cc
@@ -0,0 +1,98 @@
+/*
+ * 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 <memory>
+
+#include <base/at_exit.h>
+#include <base/bind.h>
+#include <base/memory/ref_counted.h>
+#include <base/message_loop/message_loop.h>
+#include <base/run_loop.h>
+#include <dbus/bus.h>
+#include <dbus/exported_object.h>
+#include <dbus/message.h>
+#include <utils/Log.h>
+
+#include "constants.h"
+
+// Used implicitly.
+#undef LOG_TAG
+#define LOG_TAG "dbus-example-daemon"
+
+namespace dbus_example {
+namespace {
+
+class Daemon {
+ public:
+  Daemon() : dbus_object_(nullptr) {}
+  ~Daemon() {}
+
+  void Init() {
+    ALOGI("Connecting to system bus");
+    dbus::Bus::Options options;
+    options.bus_type = dbus::Bus::SYSTEM;
+    bus_ = new dbus::Bus(options);
+    CHECK(bus_->Connect());
+
+    ALOGI("Exporting method %s on %s", kMethodName, kServicePath);
+    dbus_object_ = bus_->GetExportedObject(dbus::ObjectPath(kServicePath));
+    CHECK(dbus_object_->ExportMethodAndBlock(
+        kInterface, kMethodName,
+        base::Bind(&Daemon::HandleMethodCall, base::Unretained(this))));
+
+    ALOGI("Requesting ownership of %s", kServiceName);
+    CHECK(bus_->RequestOwnershipAndBlock(kServiceName,
+                                         dbus::Bus::REQUIRE_PRIMARY));
+  }
+
+ private:
+  void HandleMethodCall(dbus::MethodCall* method_call,
+                        dbus::ExportedObject::ResponseSender response_sender) {
+    int32_t token = 0;
+    dbus::MessageReader reader(method_call);
+    if (!reader.PopInt32(&token)) {
+      ALOGE("Request didn't have token");
+      response_sender.Run(std::unique_ptr<dbus::Response>(
+          dbus::ErrorResponse::FromMethodCall(method_call,
+              DBUS_ERROR_INVALID_ARGS, "Expected token argument")));
+      return;
+    }
+
+    std::unique_ptr<dbus::Response> response =
+        dbus::Response::FromMethodCall(method_call);
+    dbus::MessageWriter writer(response.get());
+    writer.AppendInt32(token);
+    ALOGI("Replying to request with token %d", token);
+    response_sender.Run(std::move(response));
+  }
+
+  scoped_refptr<dbus::Bus> bus_;
+  dbus::ExportedObject* dbus_object_;  // weak; owned by |bus_|
+
+  DISALLOW_COPY_AND_ASSIGN(Daemon);
+};
+
+}  // namespace
+}  // namespace dbus_example
+
+int main(int argc, char *argv[]) {
+  base::AtExitManager at_exit;
+  base::MessageLoopForIO loop;
+  dbus_example::Daemon daemon;
+  daemon.Init();
+  base::RunLoop().Run();
+  return 0;
+}
diff --git a/common/keyboard_example/Android.mk b/common/keyboard_example/Android.mk
new file mode 100644
index 0000000..f2c5942
--- /dev/null
+++ b/common/keyboard_example/Android.mk
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := keyboard-example
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := keyboard_example.cpp
+include $(BUILD_EXECUTABLE)
diff --git a/common/keyboard_example/README b/common/keyboard_example/README
new file mode 100644
index 0000000..7ecd119
--- /dev/null
+++ b/common/keyboard_example/README
@@ -0,0 +1,14 @@
+This folder contains example code for writing native apps that use keyboard
+inputs.
+
+Example file:
+  keyboard_example.cpp:
+    Demos listing devices and querying their metadata, polling for keyboard
+    events and detecting different events (pressed, released, hold) for a given
+    key.
+
+    This uses the evdev kernel mechanism to handle input events. It does not use
+    the input HAL.
+    See https://www.kernel.org/doc/Documentation/input/input.txt and
+    https://www.kernel.org/doc/Documentation/input/event-codes.txt for more
+    information.
diff --git a/common/keyboard_example/keyboard_example.cpp b/common/keyboard_example/keyboard_example.cpp
new file mode 100644
index 0000000..3358be9
--- /dev/null
+++ b/common/keyboard_example/keyboard_example.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/poll.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+using std::string;
+using std::vector;
+
+static const int kMaxDeviceName = 80;
+
+// Reads the list of files in |directory_path| into |filenames|.
+void ListDirectory(const string& directory_path, vector<string>* filenames) {
+  if (!filenames) {
+    printf("Error: filenames is null.\n");
+    exit(1);
+  }
+  DIR* directory = opendir(directory_path.c_str());
+  if (!directory) {
+    printf("Failed to open %s.\n", directory_path.c_str());
+    return;
+  }
+  struct dirent *entry = NULL;
+  while ((entry = readdir(directory))) {
+    if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
+      filenames->push_back(directory_path + "/" + entry->d_name);
+    }
+  }
+}
+
+// Returns true iff the device reports EV_KEY events.
+bool HasKeyEvents(int device_fd) {
+  unsigned long evbit = 0;
+  // Get the bit field of available event types.
+  ioctl(device_fd, EVIOCGBIT(0, sizeof(evbit)), &evbit);
+  return evbit & (1 << EV_KEY);
+}
+
+// Returns true iff the given device has |key|.
+bool HasSpecificKey(int device_fd, unsigned int key) {
+  size_t nchar = KEY_MAX/8 + 1;
+  unsigned char bits[nchar];
+  // Get the bit fields of available keys.
+  ioctl(device_fd, EVIOCGBIT(EV_KEY, sizeof(bits)), &bits);
+  return bits[key/8] & (1 << (key % 8));
+}
+
+int main(int argc, char** argv) {
+  string input_directory = "/dev/input";
+  if (argc < 2) {
+    printf("No input directory specified, using the default one: %s.\n",
+           input_directory.c_str());
+  } else {
+    input_directory = argv[1];
+  }
+
+  vector<string> filenames;
+  ListDirectory(input_directory, &filenames);
+  printf("%i devices found in %s.\n", filenames.size(),
+         input_directory.c_str());
+
+  // Initializing the pollfd structures.
+  vector<pollfd> poll_fds;
+  char device_name[kMaxDeviceName];
+  for (size_t i = 0; i < filenames.size(); i++) {
+    int fd = open(filenames[i].c_str(), O_RDONLY);
+    if (fd < 0) {
+      printf("Failed to open %s for reading: %s\n", filenames[i].c_str(),
+             strerror(errno));
+      return 1;
+    }
+
+    // Reads the device name.
+    if(ioctl(fd, EVIOCGNAME(sizeof(device_name) - 1),
+             &device_name) < 1) {
+      device_name[0] = '\0';
+    }
+
+    if (!HasKeyEvents(fd)) {
+      printf("Discarding %s (%s): does not report any EV_KEY events.\n",
+             filenames[i].c_str(), device_name);
+      continue;
+    }
+    if (!HasSpecificKey(fd, KEY_B)) {
+      printf("Discarding %s (%s): does not have a B key.\n",
+             filenames[i].c_str(), device_name);
+      continue;
+    }
+    poll_fds.push_back(pollfd{fd, POLLIN, 0});
+
+    printf("Adding device %s: %s\n", filenames[i].c_str(), device_name);
+  }
+
+  if (poll_fds.empty()) {
+    printf("No keyboard detected, exiting.\n");
+    return 1;
+  }
+
+  // Number of repeated events + 1.
+  int count = 1;
+  // Events accumulated for each device.
+  vector<vector<input_event>> events(poll_fds.size());
+
+  const char instructions[] = "Press B to start the game and release B to go "
+      "back to the main menu.";
+  printf("%s\n", instructions);
+  while (true) {
+    // Wait for data to be available on one of the file descriptors without
+    // timeout (-1).
+    poll(poll_fds.data(), poll_fds.size(), -1);
+
+    for (size_t i = 0; i < poll_fds.size(); i++) {
+      if (poll_fds[i].revents & POLLIN) {
+        struct input_event event;
+        if (read(poll_fds[i].fd, &event, sizeof(event)) != sizeof(event)) {
+          printf("Failed to read an event.\n");
+          return 1;
+        }
+
+        // When receiving a key event for B, add it to the list of events.
+        // Don't process it yet as there might be other events in that report.
+        if (event.type == EV_KEY && event.code == KEY_B) {
+          events[i].push_back(event);
+        }
+
+        // A SYN_REPORT event signals the end of a report, process all the
+        // previously accumulated events.
+        // At that point we only have events for B in the event vector.
+        if (event.type == EV_SYN && event.code == SYN_REPORT) {
+          for (vector<input_event>::iterator it = events[i].begin();
+               it != events[i].end(); it++) {
+            switch (it->value) {
+              case 0: {
+                // A value of 0 indicates a "key released" event.
+                double percent = 1. - 1./count;
+                printf("%.02f%% loaded.\n", percent * 100);
+                printf("B released, returning to the main menu.\n\n");
+                printf("%s\n", instructions);
+                break;
+              }
+              case 1: {
+                // A value of 1 indicates a "key pressed" event.
+                printf("B pressed, starting the game...\n");
+                count = 1;
+                break;
+              }
+              case 2: {
+                // A value of 2 indicates a "key repeat" event.
+                count++;
+                break;
+              }
+              default: {}
+            }
+          }
+          // Discard all processed events.
+          events[i].clear();
+        }
+      }
+    }
+  }
+  return 0;
+}
+
diff --git a/common/lights_example/example-app/Android.mk b/common/lights_example/example-app/Android.mk
new file mode 100644
index 0000000..6e3caae
--- /dev/null
+++ b/common/lights_example/example-app/Android.mk
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := lights-hal-example-app
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := hal-example-app.cpp
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_SHARED_LIBRARIES := \
+  libc \
+  libhardware \
+
+include $(BUILD_EXECUTABLE)
diff --git a/common/lights_example/example-app/README b/common/lights_example/example-app/README
new file mode 100644
index 0000000..a8fc128
--- /dev/null
+++ b/common/lights_example/example-app/README
@@ -0,0 +1,8 @@
+This folder contains example code for writing native apps that use Brillo LED
+lights.
+
+Example files:
+  hal-example-app.cpp:
+    An example app that uses the lights HAL (defined in
+    hardware/libhardware/include/lights.h) directly. The app turns on the LED
+    light used for notifications, and turns it off 3 seconds later.
diff --git a/common/lights_example/example-app/hal-example-app.cpp b/common/lights_example/example-app/hal-example-app.cpp
new file mode 100644
index 0000000..f014bd0
--- /dev/null
+++ b/common/lights_example/example-app/hal-example-app.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 <err.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <hardware/hardware.h>
+#include <hardware/lights.h>
+
+int main() {
+  const hw_module_t* module = nullptr;
+  struct light_device_t* light_device = nullptr;
+
+  int ret = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, &module);
+  if (ret || !module) {
+    err(1, "Failed to load %s module", LIGHTS_HARDWARE_MODULE_ID);
+  }
+
+  ret = module->methods->open(
+      module, LIGHT_ID_NOTIFICATIONS,
+      reinterpret_cast<struct hw_device_t**>(&light_device));
+  if (ret || !light_device) {
+    err(1, "Failed to open light device for %s", LIGHT_ID_NOTIFICATIONS);
+  }
+
+  struct light_state_t state = {
+      .color = 0,
+      .flashMode = LIGHT_FLASH_NONE,
+      .flashOnMS = 0,
+      .flashOffMS = 0,
+      .brightnessMode = 0,
+  };
+
+  // Turn light on for three seconds.
+  state.color = 1;
+  light_device->set_light(light_device, &state);
+  sleep(3);
+
+  // Flash for three seconds.
+  state.flashMode = LIGHT_FLASH_TIMED;
+  state.flashOnMS = 50;
+  state.flashOffMS = 50;
+  light_device->set_light(light_device, &state);
+  sleep(3);
+
+  // Turn light off.
+  state.color = 0;
+  state.flashMode = LIGHT_FLASH_NONE;
+  light_device->set_light(light_device, &state);
+
+  light_device->common.close(
+      reinterpret_cast<struct hw_device_t*>(light_device));
+
+  return 0;
+}
diff --git a/common/sensors_example/Android.mk b/common/sensors_example/Android.mk
new file mode 100644
index 0000000..e423f15
--- /dev/null
+++ b/common/sensors_example/Android.mk
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# Example Sensors HAL implementation.
+include $(CLEAR_VARS)
+LOCAL_MODULE := sensors.example
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wno-unused-parameter
+LOCAL_SRC_FILES := \
+  example_sensors.cpp \
+  sensors_hal.cpp
+include $(BUILD_SHARED_LIBRARY)
+
+# Example app that uses sensors HAL.
+include $(CLEAR_VARS)
+LOCAL_MODULE := sensors-hal-example-app
+LOCAL_SRC_FILES := hal-example-app.cpp
+LOCAL_CFLAGS := -Wno-unused-parameter
+LOCAL_SHARED_LIBRARIES := libhardware
+include $(BUILD_EXECUTABLE)
+
+# Example app that uses NDK sensors API.
+include $(CLEAR_VARS)
+LOCAL_MODULE := sensors-ndk-example-app
+LOCAL_SRC_FILES := ndk-example-app.cpp
+LOCAL_CFLAGS := -Wno-unused-parameter
+LOCAL_SHARED_LIBRARIES := libsensor
+include $(BUILD_EXECUTABLE)
diff --git a/common/sensors_example/README b/common/sensors_example/README
new file mode 100644
index 0000000..a8d2c61
--- /dev/null
+++ b/common/sensors_example/README
@@ -0,0 +1,26 @@
+This folder contains example code for writing native apps that use Brillo
+sensors. The sensors HAL implementation must exist on the device for the apps
+in this folder to run successfully.
+
+Example files:
+  hal-example-app.cpp:
+    An example app that uses the sensors HAL (defined in
+    hardware/libhardware/include/sensors.h) directly. In the app, the list of
+    sensors found on the device is printed. And if an accelerometer exists, the
+    app will read the data and print it out.
+
+  ndk-example-app.cpp:
+    An example app that uses the NDK sensors interface. In the app, the list of
+    sensors found on the device is printed. And then the app tries to read data
+    from accelerometer, proximity sensor, and significant motion sensor, which
+    has continuous, on-change, and one-shot reporting modes respectively.
+
+  sensors_hal.cpp
+    An example implementation of a sensors HAL. It implements a fake
+    accelerometer and custom sensor (defined in example_sensors.{h|cpp}). The
+    accelerometer always returns random data. The custom sensor returns the hour
+    for the local time.
+
+    To use this HAL implementation, push the binary file sensors.example into
+    /system/lib/hw/ folder and rename it to sensors.default (make sure there is
+    no other sensors.* file under that folder).
diff --git a/common/sensors_example/example_sensors.cpp b/common/sensors_example/example_sensors.cpp
new file mode 100644
index 0000000..22d5381
--- /dev/null
+++ b/common/sensors_example/example_sensors.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 "example_sensors.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+#include <hardware/sensors.h>
+
+SensorBase::SensorBase() {}
+SensorBase::~SensorBase() {}
+
+int SensorBase::activate(int handle, int enabled) {
+  return 0;
+}
+
+int SensorBase::setDelay(int handle, int64_t ns) {
+  return 0;
+}
+
+int SensorBase::batch(int handle, int flags,
+                      int64_t period_ns, int64_t timeout) {
+  return 0;
+}
+
+int SensorBase::flush(int handle) {
+  return 0;
+}
+
+
+Accelerometer::Accelerometer() {}
+Accelerometer::~Accelerometer() {}
+
+int Accelerometer::pollEvents(sensors_event_t* data, int count) {
+  // Returns fake random values.
+  data->acceleration.x = static_cast<float>(random() % kMaxRange);
+  data->acceleration.y = static_cast<float>(random() % kMaxRange);
+  data->acceleration.z = static_cast<float>(random() % kMaxRange);
+  return 1;
+}
+
+
+CustomSensor::CustomSensor() {}
+CustomSensor::~CustomSensor() {}
+
+int CustomSensor::pollEvents(sensors_event_t* data, int count) {
+  if (data) {
+    // For this custom sensor, we will return the hour of the local time.
+    time_t t = time(NULL);
+    struct tm* now = localtime(&t);
+    if (now) {
+      // Any field can be used to return data for a custom sensor.
+      // See definition of struct sensors_event_t in hardware/sensors.h for the
+      // available fields.
+      data->data[0] = now->tm_hour;
+      return 1;
+    }
+  }
+  // Note: poll() return value is the number of events being returned. We use
+  // -1 to signal an error.
+  return -1;
+}
diff --git a/common/sensors_example/example_sensors.h b/common/sensors_example/example_sensors.h
new file mode 100644
index 0000000..5e984ea
--- /dev/null
+++ b/common/sensors_example/example_sensors.h
@@ -0,0 +1,54 @@
+/*
+ * 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 SENSORS_EXAMPLE_SENSORS_H
+#define SENSORS_EXAMPLE_SENSORS_H
+
+#include <stdint.h>
+
+struct sensors_event_t;
+
+class SensorBase {
+ public:
+  SensorBase();
+  virtual ~SensorBase();
+
+  virtual int activate(int handle, int enabled);
+  virtual int setDelay(int handle, int64_t ns);
+  virtual int pollEvents(sensors_event_t* data, int count) = 0;
+  virtual int batch(int handle, int flags, int64_t period_ns, int64_t timeout);
+  virtual int flush(int handle);
+};
+
+class Accelerometer : public SensorBase {
+ public:
+  static const int kMaxRange = 1000;
+
+  Accelerometer();
+  ~Accelerometer() override;
+
+  int pollEvents(sensors_event_t* data, int count) override;
+};
+
+class CustomSensor : public SensorBase {
+ public:
+  CustomSensor();
+  ~CustomSensor() override;
+
+  int pollEvents(sensors_event_t* data, int count) override;
+};
+
+#endif  // SENSORS_EXAMPLE_SENSORS_H
diff --git a/common/sensors_example/hal-example-app.cpp b/common/sensors_example/hal-example-app.cpp
new file mode 100644
index 0000000..dfec435
--- /dev/null
+++ b/common/sensors_example/hal-example-app.cpp
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ */
+
+/* This file contains an example app that uses sensors HAL.
+ * It accepts a sensor type as an input argument and reads data from a
+ * sensor of that type.
+ *
+ * For any specified sensor type, there may be multiple such sensors defined
+ * in the HAL. Some or all of the defined sensors will actually be equipped.
+ * This test program will scan the HAL for the first equipped sensor of
+ * the specified sensor type and dump data from that sensor.
+ */
+
+#include <getopt.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <hardware/hardware.h>
+#include <hardware/sensors.h>
+
+#include <sys/types.h>
+
+#define DEFAULT_SENSOR_TYPE SENSOR_TYPE_ACCELEROMETER
+
+// Structure to hold the decoded command line options
+struct pgm_options {
+  int    sensor_type;
+};
+
+// Be sure to keep the options for longopts and shortopts in the same order
+// so that Usage() is correct.
+static struct option longopts[] = {
+  {"help",     no_argument,  NULL,  '?'},
+  {"accel",    no_argument,  NULL,  'a'},
+  {"temp",     no_argument,  NULL,  't'},
+  {"light",    no_argument,  NULL,  'l'},
+  {"orient",   no_argument,  NULL,  'o'},
+  {"prox",     no_argument,  NULL,  'p'},
+  {"motion",   no_argument,  NULL,  'm'},
+  {NULL,       0,            NULL,   0}
+};
+static char shortopts[] = "?atlopm";
+
+// Describes the options for this program.
+void Usage(char *pgm_name) {
+  printf("Usage: %s [options...]\n", pgm_name);
+  printf("Exercises the sensors HAL by direct calling.\n");
+  printf("Options:\n");
+  for (int i = 0; longopts[i].name; i++) {
+    printf("  --%-6s or -%c\n", longopts[i].name, shortopts[i]);
+  }
+}
+
+// Processes all command line options.
+//   sets the options members for commnd line options
+//   returns (0) on success, -1 otherwise.
+int ReadOpts(int argc, char **argv, struct pgm_options *options) {
+  int ch = 0;
+
+  if (!options) {
+    fprintf(stderr, "Invalid options pointer\n");
+    return 1;
+  }
+
+  while ((ch = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
+    switch (ch) {
+    case 'a':
+      options->sensor_type  = SENSOR_TYPE_ACCELEROMETER;
+      break;
+    case 't':
+      options->sensor_type  = SENSOR_TYPE_TEMPERATURE;
+      break;
+    case 'l':
+      options->sensor_type  = SENSOR_TYPE_LIGHT;
+      break;
+    case 'o':
+      options->sensor_type  = SENSOR_TYPE_ORIENTATION;
+      break;
+    case 'p':
+      options->sensor_type  = SENSOR_TYPE_PROXIMITY;
+      break;
+    case 'm':
+      options->sensor_type  = SENSOR_TYPE_SIGNIFICANT_MOTION;
+      break;
+    default:
+      Usage(argv[0]);
+      return -1;
+    }
+  }
+  argc -= optind;
+  argv += optind;
+  return 0;
+}
+
+// Prints data associated with each supported sensor type.
+// Be sure to provide a case for each sensor type supported in
+// the ReadOpts() function.
+void DisplaySensorData(int sensor_type, const sensors_event_t *data) {
+  switch (sensor_type) {
+    case SENSOR_TYPE_PROXIMITY:
+      printf("Proximity distance: %f\n", data->distance);
+      break;
+    case SENSOR_TYPE_SIGNIFICANT_MOTION:
+      if (data->data[0] == 1) {
+        printf("Significant motion detected\n");
+      }
+      break;
+    case SENSOR_TYPE_ACCELEROMETER:
+      printf("Acceleration: x = %f, y = %f, z = %f\n",
+             data->acceleration.x, data->acceleration.y, data->acceleration.z);
+      break;
+    case SENSOR_TYPE_TEMPERATURE:
+      printf("Temperature: %f\n", data->temperature);
+      break;
+    case SENSOR_TYPE_LIGHT:
+      printf("Light: %f\n", data->light);
+      break;
+    case SENSOR_TYPE_ORIENTATION: {
+      float heading =
+        atan2(static_cast<double>(data->orientation.y),
+              static_cast<double>(data->orientation.x)) * 180.0 / M_PI;
+      if (heading < 0.0)
+        heading += 360.0;
+      printf("Heading: %f, Orientation: x = %f, y = %f, z = %f\n",
+             heading, data->orientation.x, data->orientation.y,
+             data->orientation.z);
+      }
+      break;
+  }
+}
+
+int main(int argc, char* argv[]) {
+  pgm_options options = {DEFAULT_SENSOR_TYPE};
+  if (ReadOpts(argc, argv, &options) < 0)
+    return 1;
+
+  sensors_module_t* sensor_module = nullptr;
+  int ret = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
+      const_cast<hw_module_t const**>(
+      reinterpret_cast<hw_module_t**>(&sensor_module)));
+  if (ret || !sensor_module) {
+    fprintf(stderr, "Failed to load %s module: %s\n",
+            SENSORS_HARDWARE_MODULE_ID, strerror(-ret));
+    return 1;
+  }
+
+  const sensor_t *sensor_list = nullptr;
+  int sensor_count =
+      sensor_module->get_sensors_list(sensor_module, &sensor_list);
+  printf("Found %d supported sensors\n", sensor_count);
+  for (int i = 0; i < sensor_count; i++) {
+    printf("HAL supports sensor %s\n", sensor_list[i].name);
+  }
+
+  // sensors_open_1 is used in HAL versions >= 1.0.
+  sensors_poll_device_1_t* sensor_device = nullptr;
+  ret = sensors_open_1(&sensor_module->common, &sensor_device);
+  if (ret || !sensor_device) {
+    fprintf(stderr, "Failed to open the sensor HAL\n");
+    return 1;
+  }
+
+  // Find the first sensor of the specified type that can be opened
+  bool sensor_found = false;
+  const sensor_t *sensor = nullptr;
+  for (int i = 0; i < sensor_count; i++) {
+    sensor = &sensor_list[i];
+    if (sensor->type != options.sensor_type)
+      continue;
+    if (sensor_device->activate(
+        reinterpret_cast<sensors_poll_device_t*>(sensor_device),
+        sensor->handle, 1 /* enabled */) < 0) {
+      continue;
+    }
+
+    // Found an equipped sensor of the specified type.
+    sensor_found = true;
+    break;
+  }
+
+  if (!sensor_found) {
+    fprintf(stderr, "No sensor of the specified type found\n");
+    ret = sensors_close_1(sensor_device);
+    if (ret)
+      fprintf(stderr, "Failed to close the sensor device\n");
+    return 1;
+  }
+  printf("\nSensor %s activated\n", sensor->name);
+
+  const int kNumEvents = 1;
+  const int kNumSamples = 10;
+  const int kWaitTimeSecs = 1;
+  for (int i = 0; i < kNumSamples; i++) {
+    sensors_event_t data[kNumEvents];
+    memset(data, 0, sizeof(data));
+    int event_count = sensor_device->poll(
+        reinterpret_cast<sensors_poll_device_t*>(sensor_device),
+        data, kNumEvents);
+    if (!event_count) {
+      fprintf(stderr, "Failed to read data from the sensor.\n");
+      continue;
+    }
+
+    DisplaySensorData(options.sensor_type, data);
+    sleep(kWaitTimeSecs);
+  }
+
+  ret = sensor_device->activate(
+      reinterpret_cast<sensors_poll_device_t*>(sensor_device),
+      sensor->handle, 0 /* disabled */);
+  if (ret) {
+    fprintf(stderr, "Failed to disable %s: %s\n", sensor->name, strerror(ret));
+    return 1;
+  }
+
+  // sensors_close_1 is used in HAL versions >= 1.0.
+  ret = sensors_close_1(sensor_device);
+  if (ret) {
+    fprintf(stderr, "Failed to close the sensor device\n");
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/common/sensors_example/ndk-example-app.cpp b/common/sensors_example/ndk-example-app.cpp
new file mode 100644
index 0000000..628068d
--- /dev/null
+++ b/common/sensors_example/ndk-example-app.cpp
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+
+/* This file contains an example app that uses sensors NDK.
+ * It accepts a sensor type as an input argument and reads data from a
+ * sensor of that type.
+ *
+ * For any specified sensor type, there may be multiple such sensors defined
+ * in the HAL. Some or all of the defined sensors will actually be equipped.
+ * This test program will scan the HAL for the first equipped sensor of
+ * the specified sensor type and dump data from that sensor.
+ */
+
+#include <getopt.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <android/looper.h>
+#include <android/sensor.h>
+#include <hardware/sensors.h>
+
+#define DEFAULT_SENSOR_TYPE SENSOR_TYPE_ACCELEROMETER
+
+// Structure to hold the decoded command line options
+struct pgm_options {
+  int    sensor_type;
+};
+
+// Be sure to keep the options for longopts and shortopts in the same order
+// so that Usage() is correct.
+static struct option longopts[] = {
+  {"help",     no_argument,  NULL,  '?'},
+  {"accel",    no_argument,  NULL,  'a'},
+  {"temp",     no_argument,  NULL,  't'},
+  {"light",    no_argument,  NULL,  'l'},
+  {"orient",   no_argument,  NULL,  'o'},
+  {"prox",     no_argument,  NULL,  'p'},
+  {"motion",   no_argument,  NULL,  'm'},
+  {NULL,       0,            NULL,   0}
+};
+static char shortopts[] = "?atlopm";
+
+// Describes the options for this program.
+void Usage(char *pgm_name) {
+  printf("Usage: %s [options...]\n", pgm_name);
+  printf("Exercises the sensors NDK by calling into the sensorserver.\n");
+  printf("Options:\n");
+  for (int i = 0; longopts[i].name; i++) {
+    printf("  --%-6s or -%c\n", longopts[i].name, shortopts[i]);
+  }
+}
+
+// Processes all command line options.
+//   sets the options members for commnd line options
+//   returns (0) on success, -1 otherwise.
+int ReadOpts(int argc, char **argv, struct pgm_options *options) {
+  int ch = 0;
+
+  if (!options) {
+    fprintf(stderr, "Invalid options pointer\n");
+    return 1;
+  }
+
+  while ((ch = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
+    switch (ch) {
+    case 'a':
+      options->sensor_type  = SENSOR_TYPE_ACCELEROMETER;
+      break;
+    case 't':
+      options->sensor_type  = SENSOR_TYPE_TEMPERATURE;
+      break;
+    case 'l':
+      options->sensor_type  = SENSOR_TYPE_LIGHT;
+      break;
+    case 'o':
+      options->sensor_type  = SENSOR_TYPE_ORIENTATION;
+      break;
+    case 'p':
+      options->sensor_type  = SENSOR_TYPE_PROXIMITY;
+      break;
+    case 'm':
+      options->sensor_type  = SENSOR_TYPE_SIGNIFICANT_MOTION;
+      break;
+    default:
+      Usage(argv[0]);
+      return -1;
+    }
+  }
+  argc -= optind;
+  argv += optind;
+  return 0;
+}
+
+// Prints data associated with each supported sensor type.
+// Be sure to provide a case for each sensor type supported in
+// the ReadOpts() function.
+void DisplaySensorData(int sensor_type, const ASensorEvent *data) {
+  switch (sensor_type) {
+    case SENSOR_TYPE_PROXIMITY:
+      printf("Proximity distance: %f\n", data->distance);
+      break;
+    case SENSOR_TYPE_SIGNIFICANT_MOTION:
+      if (data->data[0] == 1) {
+        printf("Significant motion detected\n");
+      }
+      break;
+    case SENSOR_TYPE_ACCELEROMETER:
+      printf("Acceleration: x = %f, y = %f, z = %f\n",
+             data->acceleration.x, data->acceleration.y, data->acceleration.z);
+      break;
+    case SENSOR_TYPE_TEMPERATURE:
+      printf("Temperature: %f\n", data->temperature);
+      break;
+    case SENSOR_TYPE_LIGHT:
+      printf("Light: %f\n", data->light);
+      break;
+    case SENSOR_TYPE_ORIENTATION: {
+      float heading =
+        atan2(static_cast<double>(data->magnetic.y),
+              static_cast<double>(data->magnetic.x)) * 180.0 / M_PI;
+      if (heading < 0.0)
+        heading += 360.0;
+      printf("Heading: %f, Orientation: x = %f, y = %f, z = %f\n",
+             heading, data->magnetic.x, data->magnetic.y, data->magnetic.z);
+      }
+      break;
+  }
+}
+
+int main(int argc, char* argv[]) {
+  pgm_options options = {DEFAULT_SENSOR_TYPE};
+  if (ReadOpts(argc, argv, &options) < 0)
+    return 1;
+
+  const char kPackageName[] = "ndk-example-app";
+  ASensorManager* sensor_manager =
+    ASensorManager_getInstanceForPackage(kPackageName);
+  if (!sensor_manager) {
+    fprintf(stderr, "Failed to get a sensor manager\n");
+    return 1;
+  }
+
+  ASensorList sensor_list = nullptr;
+  int sensor_count = ASensorManager_getSensorList(sensor_manager, &sensor_list);
+  printf("Found %d supported sensors\n", sensor_count);
+  for (int i = 0; i < sensor_count; i++) {
+    printf("HAL supports sensor %s\n", ASensor_getName(sensor_list[i]));
+  }
+
+  const int kLooperId = 1;
+  ASensorEventQueue* queue = ASensorManager_createEventQueue(
+      sensor_manager,
+      ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS),
+      kLooperId,
+      NULL, /* no callback */
+      NULL  /* no private data for a callback  */);
+  if (!queue) {
+    fprintf(stderr, "Failed to create a sensor event queue\n");
+    return 1;
+  }
+
+  // Find the first sensor of the specified type that can be opened
+  const int kTimeoutMicroSecs = 1000000;
+  const int kTimeoutMilliSecs = 1000;
+  ASensorRef sensor = nullptr;
+  bool sensor_found = false;
+  for (int i = 0; i < sensor_count; i++) {
+    sensor = sensor_list[i];
+    if (ASensor_getType(sensor) != options.sensor_type)
+      continue;
+    if (ASensorEventQueue_enableSensor(queue, sensor) < 0)
+      continue;
+    if (ASensorEventQueue_setEventRate(queue, sensor, kTimeoutMicroSecs) < 0) {
+      fprintf(stderr, "Failed to set the %s sample rate\n",
+          ASensor_getName(sensor));
+      return 1;
+    }
+
+    // Found an equipped sensor of the specified type.
+    sensor_found = true;
+    break;
+  }
+
+  if (!sensor_found) {
+    fprintf(stderr, "No sensor of the specified type found\n");
+    int ret = ASensorManager_destroyEventQueue(sensor_manager, queue);
+    if (ret < 0)
+      fprintf(stderr, "Failed to destroy event queue: %s\n", strerror(-ret));
+    return 1;
+  }
+  printf("\nSensor %s activated\n", ASensor_getName(sensor));
+
+  const int kNumEvents = 1;
+  const int kNumSamples = 10;
+  const int kWaitTimeSecs = 1;
+  for (int i = 0; i < kNumSamples; i++) {
+    ASensorEvent data[kNumEvents];
+    memset(data, 0, sizeof(data));
+    int ident = ALooper_pollAll(
+        kTimeoutMilliSecs,
+        NULL /* no output file descriptor */,
+        NULL /* no output event */,
+        NULL /* no output data */);
+    if (ident != kLooperId) {
+      fprintf(stderr, "Incorrect Looper ident read from poll.\n");
+      continue;
+    }
+    if (ASensorEventQueue_getEvents(queue, data, kNumEvents) <= 0) {
+      fprintf(stderr, "Failed to read data from the sensor.\n");
+      continue;
+    }
+
+    DisplaySensorData(options.sensor_type, data);
+    sleep(kWaitTimeSecs);
+  }
+
+  int ret = ASensorEventQueue_disableSensor(queue, sensor);
+  if (ret < 0) {
+    fprintf(stderr, "Failed to disable %s: %s\n",
+            ASensor_getName(sensor), strerror(-ret));
+  }
+
+  ret = ASensorManager_destroyEventQueue(sensor_manager, queue);
+  if (ret < 0) {
+    fprintf(stderr, "Failed to destroy event queue: %s\n", strerror(-ret));
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/common/sensors_example/sensors_hal.cpp b/common/sensors_example/sensors_hal.cpp
new file mode 100644
index 0000000..5b89e59
--- /dev/null
+++ b/common/sensors_example/sensors_hal.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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 "sensors_hal.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include "example_sensors.h"
+
+SensorContext::SensorContext(const hw_module_t* module) {
+  memset(&device, 0, sizeof(device));
+
+  device.common.tag = HARDWARE_DEVICE_TAG;
+  device.common.version = SENSORS_DEVICE_API_VERSION_1_0;
+  device.common.module = const_cast<hw_module_t*>(module);
+  device.common.close = CloseWrapper;
+  device.activate = ActivateWrapper;
+  device.setDelay = SetDelayWrapper;
+  device.poll = PollEventsWrapper;
+  device.batch = BatchWrapper;
+  device.flush = FlushWrapper;
+
+  sensors[AvailableSensors::kAccelerometer] = new Accelerometer();
+  sensors[AvailableSensors::kCustom] = new CustomSensor();
+}
+
+SensorContext::~SensorContext() {
+  for (int i = 0; i < AvailableSensors::kNumSensors; i++) {
+    if (sensors[i]) delete sensors[i];
+  }
+}
+
+int SensorContext::activate(int handle, int enabled) {
+  return sensors[handle]->activate(handle, enabled);
+}
+
+int SensorContext::setDelay(int handle, int64_t ns) {
+  return sensors[handle]->setDelay(handle, ns);
+}
+
+int SensorContext::pollEvents(sensors_event_t* data, int count) {
+  return sensors[0]->pollEvents(data, count);
+}
+
+int SensorContext::batch(int handle, int flags,
+                         int64_t period_ns, int64_t timeout) {
+  return sensors[handle]->batch(handle, flags, period_ns, timeout);
+}
+
+int SensorContext::flush(int handle) {
+  return sensors[handle]->flush(handle);
+}
+
+// static
+int SensorContext::CloseWrapper(hw_device_t* dev) {
+  SensorContext* sensor_context = reinterpret_cast<SensorContext*>(dev);
+  if (sensor_context) {
+    delete sensor_context;
+  }
+  return 0;
+}
+
+// static
+int SensorContext::ActivateWrapper(sensors_poll_device_t* dev,
+                                   int handle, int enabled) {
+  return reinterpret_cast<SensorContext*>(dev)->activate(handle, enabled);
+}
+
+// static
+int SensorContext::SetDelayWrapper(sensors_poll_device_t* dev,
+                                   int handle, int64_t ns) {
+  return reinterpret_cast<SensorContext*>(dev)->setDelay(handle, ns);
+}
+
+// static
+int SensorContext::PollEventsWrapper(sensors_poll_device_t* dev,
+                                     sensors_event_t* data, int count) {
+  return reinterpret_cast<SensorContext*>(dev)->pollEvents(data, count);
+}
+
+// static
+int SensorContext::BatchWrapper(sensors_poll_device_1_t* dev, int handle,
+                                int flags, int64_t period_ns, int64_t timeout) {
+  return reinterpret_cast<SensorContext*>(dev)->batch(handle, flags, period_ns,
+                                                      timeout);
+}
+
+// static
+int SensorContext::FlushWrapper(sensors_poll_device_1_t* dev,
+                                int handle) {
+  return reinterpret_cast<SensorContext*>(dev)->flush(handle);
+}
+
+
+static int open_sensors(const struct hw_module_t* module,
+                        const char* id, struct hw_device_t** device) {
+  SensorContext* ctx = new SensorContext(module);
+  *device = &ctx->device.common;
+
+  return 0;
+}
+
+static struct hw_module_methods_t sensors_module_methods = {
+  .open = open_sensors,
+};
+
+static struct sensor_t kSensorList[] = {
+  { .name = "Broken Accelerometer",
+    .vendor = "Unknown",
+    .version = 1,
+    .handle = SensorContext::AvailableSensors::kAccelerometer,
+    .type = SENSOR_TYPE_ACCELEROMETER,
+    .maxRange = static_cast<float>(Accelerometer::kMaxRange),
+    .resolution = 100.0f,
+    .power = 0.0f,
+    .minDelay = 10000,
+    .fifoReservedEventCount = 0,
+    .fifoMaxEventCount = 0,
+    .stringType = SENSOR_STRING_TYPE_ACCELEROMETER,
+    .requiredPermission = "",
+    .maxDelay = 0,
+    .flags = SENSOR_FLAG_CONTINUOUS_MODE,
+    .reserved = {},
+  },
+  { .name = "Custom Hour of Day Sensor",
+    .vendor = "Unknown",
+    .version = 1,
+    .handle = SensorContext::AvailableSensors::kCustom,
+    .type = SENSOR_TYPE_CUSTOM,
+    .maxRange = 24.0f,
+    .resolution = 1.0f,
+    .power = 0.0f,
+    .minDelay = 1,
+    .fifoReservedEventCount = 0,
+    .fifoMaxEventCount = 0,
+    .stringType = SENSOR_STRING_TYPE_CUSTOM,
+    .requiredPermission = "",
+    .maxDelay = 0,
+    .flags = SENSOR_FLAG_CONTINUOUS_MODE,
+    .reserved = {},
+  },
+};
+
+static int get_sensors_list(struct sensors_module_t* module,
+                            struct sensor_t const** list) {
+  if (!list) return 0;
+  *list = kSensorList;
+  return sizeof(kSensorList) / sizeof(kSensorList[0]);
+}
+
+struct sensors_module_t HAL_MODULE_INFO_SYM = {
+    .common = {
+        .tag = HARDWARE_MODULE_TAG,
+        .version_major = 1,
+        .version_minor = 0,
+        .id = SENSORS_HARDWARE_MODULE_ID,
+        .name = "Example Sensor Module",
+        .author = "Google",
+        .methods = &sensors_module_methods,
+        .dso = NULL,
+        .reserved = {0},
+    },
+    .get_sensors_list = get_sensors_list,
+    .set_operation_mode = NULL
+};
diff --git a/common/sensors_example/sensors_hal.h b/common/sensors_example/sensors_hal.h
new file mode 100644
index 0000000..e563d7e
--- /dev/null
+++ b/common/sensors_example/sensors_hal.h
@@ -0,0 +1,70 @@
+/*
+ * 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 SENSORS_SENSORS_HAL_H
+#define SENSORS_SENSORS_HAL_H
+
+/*
+ * SENSOR_TYPE_CUSTOM
+ * The custom sensor type must have a integer constant starting from 27.
+ * The string name of the custom type must also be defined.
+ */
+#define SENSOR_TYPE_CUSTOM         (27)
+#define SENSOR_STRING_TYPE_CUSTOM  "brillo.custom"
+
+#include <stdint.h>
+
+#include <hardware/sensors.h>
+
+#include "example_sensors.h"
+
+class SensorContext {
+ public:
+  sensors_poll_device_1_t device;
+
+  SensorContext(const hw_module_t* module);
+  ~SensorContext();
+
+  enum AvailableSensors {
+    kAccelerometer,
+    kCustom,
+    kNumSensors
+  };
+
+ private:
+  int activate(int handle, int enabled);
+  int setDelay(int handle, int64_t ns);
+  int pollEvents(sensors_event_t* data, int count);
+  int batch(int handle, int flags, int64_t period_ns, int64_t timeout);
+  int flush(int handle);
+
+  // The wrapper pass through to the specific instantiation of
+  // the SensorContext.
+  static int CloseWrapper(hw_device_t* dev);
+  static int ActivateWrapper(sensors_poll_device_t* dev, int handle,
+                             int enabled);
+  static int SetDelayWrapper(sensors_poll_device_t* dev, int handle,
+                             int64_t ns);
+  static int PollEventsWrapper(sensors_poll_device_t* dev,
+                               sensors_event_t* data, int count);
+  static int BatchWrapper(sensors_poll_device_1_t* dev, int handle, int flags,
+                          int64_t period_ns, int64_t timeout);
+  static int FlushWrapper(sensors_poll_device_1_t* dev, int handle);
+
+  SensorBase* sensors[AvailableSensors::kNumSensors];
+};
+
+#endif  // SENSORS_SENSORS_HAL_H
diff --git a/common/service_example/Android.mk b/common/service_example/Android.mk
new file mode 100644
index 0000000..31165a9
--- /dev/null
+++ b/common/service_example/Android.mk
@@ -0,0 +1,52 @@
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := brillo_example_service
+LOCAL_SRC_FILES := \
+    brillo_example_service.cpp \
+    android/brillo/example/IAlertCallback.aidl \
+    android/brillo/example/IExampleService.aidl
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)
+LOCAL_CFLAGS := -Wall
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libbrillo \
+    libbrillo-binder \
+    libchrome \
+    libutils
+# Uncomment the following line to have this service started automatically on
+# boot by init.
+#LOCAL_INIT_RC := example_service.rc
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := brillo_example_client
+LOCAL_SRC_FILES := \
+    brillo_example_client.cpp \
+    android/brillo/example/IAlertCallback.aidl \
+    android/brillo/example/IExampleService.aidl
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)
+LOCAL_CFLAGS := -Wall
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libbrillo \
+    libbrillo-binder \
+    libchrome \
+    libcutils \
+    libutils
+include $(BUILD_EXECUTABLE)
diff --git a/common/service_example/README.md b/common/service_example/README.md
new file mode 100644
index 0000000..47838d6
--- /dev/null
+++ b/common/service_example/README.md
@@ -0,0 +1,70 @@
+Brillo Example Service
+======================
+
+This folder contains an example Brillo service and client that use AIDL. This
+example is intended to show:
+
+1. Implementing an interface defined in AIDL.
+2. Registering a service with the service manager.
+3. Calling a service from a client.
+4. Registering a callback object from the client so the service can talk back
+     to the client.
+
+Folder layout
+-------------
+
+* android/brillo/example/IExampleService.aidl - AIDL interface for an example
+  service that accepts a string and logs it. The service also provides an
+  interface to let a client be notified once it has called the service n
+  times.
+* android/brillo/example/IAlertCallback.aidl - AIDL interface for the callback
+  object that the client registers with the service. Note the use of the
+  keyword oneway in the interface. This keyword prevents the service from
+  blocking on the client handling the callback.
+* brillo_example_service.cpp - The implementation of the AIDL service
+  interface. The service has to implement
+  android::brillo::example::BnExampleService which is done in ExampleService
+  class. The service also illustrates how to use brillo::BinderWatcher with a
+  message loop to drive the service.
+* brillo_example_client.cpp - Client application that calls the service and
+  receives callbacks. The client implements the callback object in
+  AlertCallback. AlertCallback by extending
+  android::brillo::example::BnAlertCallback. The client also uses
+  brillo::BinderWatcher and message loops to receive callbacks.
+
+The brillo_example_client reads std::in and passes that information to the
+brillo_example_service which logs it using logcat.
+
+Usage
+-----
+
+To use this example service/client:
+
+1. Open two terminals.
+2. In the first one, run
+
+        adb shell
+
+    and then start the example service in the background (not required if the
+    service is started by init)
+
+        brillo_example_service &
+
+3. Start logcat in the second terminal
+
+        adb logcat
+
+4. In the first terminal, start the example client as root.
+
+        brillo_example_client
+
+5. If you type "foo" in the first terminal followed by a newline, you should see
+   the following text in the logcat output:
+
+        brillo_example_service: foo
+
+6. After 3 messages have been sent to the service by the client, the following
+   statement will be logged by the client.
+
+        brillo_example_client: Received Callback from service: Received 3 log messages.
+
diff --git a/common/service_example/android/brillo/example/IAlertCallback.aidl b/common/service_example/android/brillo/example/IAlertCallback.aidl
new file mode 100644
index 0000000..a3eb9ee
--- /dev/null
+++ b/common/service_example/android/brillo/example/IAlertCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+package android.brillo.example;
+
+// Interface for a callback object that is to be registered with
+// IExampleService.
+interface IAlertCallback {
+  // This should be a oneway call since we don't want services to be blocked on
+  // clients.
+  oneway void OnNLogEventsReceivedCallback(int n);
+}
diff --git a/common/service_example/android/brillo/example/IExampleService.aidl b/common/service_example/android/brillo/example/IExampleService.aidl
new file mode 100644
index 0000000..d478abd
--- /dev/null
+++ b/common/service_example/android/brillo/example/IExampleService.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package android.brillo.example;
+
+import android.brillo.example.IAlertCallback;
+
+// Interface for an example service that accepts a string and logs it using
+// logcat. It also provides a method to register a callback.
+interface IExampleService {
+  // Registers a callback object of type IAlertCallback with the service. Once
+  // the service has recieved n calls to Log, then the method
+  // OnNEventsReceivedCallback on the callback object will be called.
+  void RegisterCallback(IAlertCallback callback, int n);
+
+  // Logs a string.
+  void Log(String s);
+}
diff --git a/common/service_example/brillo_example_client.cpp b/common/service_example/brillo_example_client.cpp
new file mode 100644
index 0000000..cb49720
--- /dev/null
+++ b/common/service_example/brillo_example_client.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 <iostream>
+#include <string>
+
+#include <base/at_exit.h>
+#include <base/bind.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
+#include <brillo/binder_watcher.h>
+#include <brillo/message_loops/base_message_loop.h>
+#include <brillo/syslog_logging.h>
+#include <utils/String16.h>
+
+#include "android/brillo/example/BnAlertCallback.h"
+#include "android/brillo/example/IExampleService.h"
+
+namespace android {
+
+class AlertCallback : public android::brillo::example::BnAlertCallback {
+ public:
+  binder::Status OnNLogEventsReceivedCallback(int n) {
+    LOG(INFO) << "Received Callback from service: Received " << n << " log "
+              << "messages.";
+    return binder::Status::ok();
+  }
+};
+
+}  // namespace android
+
+// A function to read user input on the console and pass it along to the example
+// service for logging.
+void StdinCallback(
+    android::sp<android::brillo::example::IExampleService> service) {
+  std::string line;
+  std::getline(std::cin, line);
+  service->Log(android::String16(line.c_str()));
+}
+
+int main() {
+  // TODO(ralphnathan): Hide this in brillo::BaseMessageLoop.
+  base::AtExitManager at_exit_manager;
+  brillo::InitLog(brillo::kLogToSyslog);
+  // Get handle for the example service.
+  android::sp<android::brillo::example::IExampleService> service;
+  android::status_t status = android::getService(
+      android::String16("android.brillo.example.ExampleService"), &service);
+  CHECK(status == android::OK) <<
+      "Failed to get IExampleService binder from service manager!";
+
+  // Register a callback object with the service.
+  android::sp<android::AlertCallback> cbo = new android::AlertCallback();
+  service->RegisterCallback(cbo, 3);
+
+  // Create a message loop.
+  base::MessageLoopForIO message_loop_for_io;
+  brillo::BaseMessageLoop message_loop{&message_loop_for_io};
+
+  // Initialize a binder watcher.
+  brillo::BinderWatcher watcher(&message_loop);
+  watcher.Init();
+
+  // Poll stdin.
+  base::Closure stdin_callback = base::Bind(&StdinCallback, service);
+  message_loop.WatchFileDescriptor(
+      STDIN_FILENO, brillo::BaseMessageLoop::kWatchRead, true, stdin_callback);
+  // Start the message loop.
+  message_loop.Run();
+}
diff --git a/common/service_example/brillo_example_service.cpp b/common/service_example/brillo_example_service.cpp
new file mode 100644
index 0000000..fd24a7e
--- /dev/null
+++ b/common/service_example/brillo_example_service.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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 <base/at_exit.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <brillo/binder_watcher.h>
+#include <brillo/message_loops/base_message_loop.h>
+#include <brillo/syslog_logging.h>
+#include <utils/String16.h>
+
+#include "android/brillo/example/BnExampleService.h"
+#include "android/brillo/example/IAlertCallback.h"
+
+namespace android {
+
+class ExampleService : public android::brillo::example::BnExampleService {
+ public:
+  binder::Status Log(const String16& s) {
+    LOG(INFO) << String8(s).string();
+    count_++;
+    if (count_ == max_events_) {
+      cbo_->OnNLogEventsReceivedCallback(count_);
+      count_ = 0;
+    }
+    return binder::Status::ok();
+  }
+
+  binder::Status RegisterCallback(
+      const sp<android::brillo::example::IAlertCallback>& callback, int n) {
+    cbo_ = callback;
+    max_events_ = n;
+    count_ = 0;
+    return binder::Status::ok();
+  }
+
+ private:
+  sp<android::brillo::example::IAlertCallback> cbo_;
+  int count_ = 0;
+  int max_events_ = 0;
+};
+
+}  // namespace android
+
+int main() {
+  // TODO(ralphnathan): Hide this in brillo::BaseMessageLoop.
+  base::AtExitManager at_exit_manager;
+  brillo::InitLog(brillo::kLogToSyslog);
+  // Register service with the service manager.
+  android::status_t status = android::defaultServiceManager()->addService(
+      android::String16("android.brillo.example.ExampleService"),
+      new android::ExampleService());
+  CHECK(status == android::OK) <<
+      "Failed to get IExampleService binder from service manager!";
+
+  // Create a message loop.
+  base::MessageLoopForIO message_loop_for_io;
+  brillo::BaseMessageLoop message_loop{&message_loop_for_io};
+
+  // Initialize a binder watcher.
+  brillo::BinderWatcher watcher(&message_loop);
+  watcher.Init();
+
+  // Run the message loop.
+  message_loop.Run();
+}
diff --git a/common/service_example/example_service.rc b/common/service_example/example_service.rc
new file mode 100644
index 0000000..79200e8
--- /dev/null
+++ b/common/service_example/example_service.rc
@@ -0,0 +1,4 @@
+service example_service /system/bin/brillo_example_service
+    class main
+    user system
+    group system
diff --git a/common/service_example/sepolicy/brillo_example_service.te b/common/service_example/sepolicy/brillo_example_service.te
new file mode 100644
index 0000000..9586a40
--- /dev/null
+++ b/common/service_example/sepolicy/brillo_example_service.te
@@ -0,0 +1,12 @@
+# Domain for the Brillo example service.
+type brillo_example_service, domain;
+type brillo_example_service_exec, exec_type, file_type;
+
+# Allow domain transition from init, and access to D-Bus and Binder.
+brillo_domain(brillo_example_service)
+
+# Allow the example service to add itself to service_manager.
+allow brillo_example_service brilloexampleservice:service_manager add;
+
+# Allow crash_reporter access to core dump files.
+allow_crash_reporter(brillo_example_service)
diff --git a/common/service_example/sepolicy/file_contexts b/common/service_example/sepolicy/file_contexts
new file mode 100644
index 0000000..017e759
--- /dev/null
+++ b/common/service_example/sepolicy/file_contexts
@@ -0,0 +1,3 @@
+# Associate the example service's executable with the domain defined in
+# brillo_example_service.te.
+/system/bin/brillo_example_service     u:object_r:brillo_example_service_exec:s0
diff --git a/common/service_example/sepolicy/service.te b/common/service_example/sepolicy/service.te
new file mode 100644
index 0000000..6544432
--- /dev/null
+++ b/common/service_example/sepolicy/service.te
@@ -0,0 +1,2 @@
+# Add a context for the Brillo example service.
+type brilloexampleservice, service_manager_type;
diff --git a/common/service_example/sepolicy/service_contexts b/common/service_example/sepolicy/service_contexts
new file mode 100644
index 0000000..d78561e
--- /dev/null
+++ b/common/service_example/sepolicy/service_contexts
@@ -0,0 +1,3 @@
+# Associate the Brillo example service's name (as defined when it is added to
+# the service manager) with a context.
+android.brillo.example.ExampleService u:object_r:brilloexampleservice:s0