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