Merge "adb: set max_rw to USB_FFS_BULK_SIZE explicitly" am: b63d47356a am: d59b93a5f5
am: dd01d2f779

Change-Id: I35d01f0a0059c8d02af5faf574bacafac3b903e2
diff --git a/fingerprintd/Android.mk b/fingerprintd/Android.mk
deleted file mode 100644
index 48b9525..0000000
--- a/fingerprintd/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# 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_CFLAGS := -Wall -Wextra -Werror -Wunused
-LOCAL_SRC_FILES := \
-	FingerprintDaemonProxy.cpp \
-	IFingerprintDaemon.cpp \
-	IFingerprintDaemonCallback.cpp \
-	fingerprintd.cpp
-LOCAL_MODULE := fingerprintd
-LOCAL_SHARED_LIBRARIES := \
-	libbinder \
-	liblog \
-	libhardware \
-	libutils \
-	libkeystore_binder
-include $(BUILD_EXECUTABLE)
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
deleted file mode 100644
index b3c0cd7..0000000
--- a/fingerprintd/FingerprintDaemonProxy.cpp
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "fingerprintd"
-
-#include <binder/IServiceManager.h>
-#include <hardware/hardware.h>
-#include <hardware/fingerprint.h>
-#include <hardware/hw_auth_token.h>
-#include <keystore/IKeystoreService.h>
-#include <keystore/keystore.h> // for error codes
-#include <utils/Log.h>
-
-#include "FingerprintDaemonProxy.h"
-
-namespace android {
-
-FingerprintDaemonProxy* FingerprintDaemonProxy::sInstance = NULL;
-
-// Supported fingerprint HAL version
-static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 1);
-
-FingerprintDaemonProxy::FingerprintDaemonProxy() : mModule(NULL), mDevice(NULL), mCallback(NULL) {
-
-}
-
-FingerprintDaemonProxy::~FingerprintDaemonProxy() {
-    closeHal();
-}
-
-void FingerprintDaemonProxy::hal_notify_callback(const fingerprint_msg_t *msg) {
-    FingerprintDaemonProxy* instance = FingerprintDaemonProxy::getInstance();
-    const sp<IFingerprintDaemonCallback> callback = instance->mCallback;
-    if (callback == NULL) {
-        ALOGE("Invalid callback object");
-        return;
-    }
-    const int64_t device = (int64_t) instance->mDevice;
-    switch (msg->type) {
-        case FINGERPRINT_ERROR:
-            ALOGD("onError(%d)", msg->data.error);
-            callback->onError(device, msg->data.error);
-            break;
-        case FINGERPRINT_ACQUIRED:
-            ALOGD("onAcquired(%d)", msg->data.acquired.acquired_info);
-            callback->onAcquired(device, msg->data.acquired.acquired_info);
-            break;
-        case FINGERPRINT_AUTHENTICATED:
-            ALOGD("onAuthenticated(fid=%d, gid=%d)",
-                    msg->data.authenticated.finger.fid,
-                    msg->data.authenticated.finger.gid);
-            if (msg->data.authenticated.finger.fid != 0) {
-                const uint8_t* hat = reinterpret_cast<const uint8_t *>(&msg->data.authenticated.hat);
-                instance->notifyKeystore(hat, sizeof(msg->data.authenticated.hat));
-            }
-            callback->onAuthenticated(device,
-                    msg->data.authenticated.finger.fid,
-                    msg->data.authenticated.finger.gid);
-            break;
-        case FINGERPRINT_TEMPLATE_ENROLLING:
-            ALOGD("onEnrollResult(fid=%d, gid=%d, rem=%d)",
-                    msg->data.enroll.finger.fid,
-                    msg->data.enroll.finger.gid,
-                    msg->data.enroll.samples_remaining);
-            callback->onEnrollResult(device,
-                    msg->data.enroll.finger.fid,
-                    msg->data.enroll.finger.gid,
-                    msg->data.enroll.samples_remaining);
-            break;
-        case FINGERPRINT_TEMPLATE_REMOVED:
-            ALOGD("onRemove(fid=%d, gid=%d)",
-                    msg->data.removed.finger.fid,
-                    msg->data.removed.finger.gid);
-            callback->onRemoved(device,
-                    msg->data.removed.finger.fid,
-                    msg->data.removed.finger.gid);
-            break;
-        case FINGERPRINT_TEMPLATE_ENUMERATING:
-            ALOGD("onEnumerate(fid=%d, gid=%d, rem=%d)",
-                    msg->data.enumerated.finger.fid,
-                    msg->data.enumerated.finger.gid,
-                    msg->data.enumerated.remaining_templates);
-            callback->onEnumerate(device,
-                    msg->data.enumerated.finger.fid,
-                    msg->data.enumerated.finger.gid,
-                    msg->data.enumerated.remaining_templates);
-            break;
-        default:
-            ALOGE("invalid msg type: %d", msg->type);
-            return;
-    }
-}
-
-void FingerprintDaemonProxy::notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length) {
-    if (auth_token != NULL && auth_token_length > 0) {
-        // TODO: cache service?
-        sp < IServiceManager > sm = defaultServiceManager();
-        sp < IBinder > binder = sm->getService(String16("android.security.keystore"));
-        sp < IKeystoreService > service = interface_cast < IKeystoreService > (binder);
-        if (service != NULL) {
-            status_t ret = service->addAuthToken(auth_token, auth_token_length);
-            if (ret != ResponseCode::NO_ERROR) {
-                ALOGE("Falure sending auth token to KeyStore: %d", ret);
-            }
-        } else {
-            ALOGE("Unable to communicate with KeyStore");
-        }
-    }
-}
-
-void FingerprintDaemonProxy::init(const sp<IFingerprintDaemonCallback>& callback) {
-    if (mCallback != NULL && IInterface::asBinder(callback) != IInterface::asBinder(mCallback)) {
-        IInterface::asBinder(mCallback)->unlinkToDeath(this);
-    }
-    IInterface::asBinder(callback)->linkToDeath(this);
-    mCallback = callback;
-}
-
-int32_t FingerprintDaemonProxy::enroll(const uint8_t* token, ssize_t tokenSize, int32_t groupId,
-        int32_t timeout) {
-    ALOG(LOG_VERBOSE, LOG_TAG, "enroll(gid=%d, timeout=%d)\n", groupId, timeout);
-    if (tokenSize != sizeof(hw_auth_token_t) ) {
-        ALOG(LOG_VERBOSE, LOG_TAG, "enroll() : invalid token size %zu\n", tokenSize);
-        return -1;
-    }
-    const hw_auth_token_t* authToken = reinterpret_cast<const hw_auth_token_t*>(token);
-    return mDevice->enroll(mDevice, authToken, groupId, timeout);
-}
-
-uint64_t FingerprintDaemonProxy::preEnroll() {
-    return mDevice->pre_enroll(mDevice);
-}
-
-int32_t FingerprintDaemonProxy::postEnroll() {
-    return mDevice->post_enroll(mDevice);
-}
-
-int32_t FingerprintDaemonProxy::stopEnrollment() {
-    ALOG(LOG_VERBOSE, LOG_TAG, "stopEnrollment()\n");
-    return mDevice->cancel(mDevice);
-}
-
-int32_t FingerprintDaemonProxy::authenticate(uint64_t sessionId, uint32_t groupId) {
-    ALOG(LOG_VERBOSE, LOG_TAG, "authenticate(sid=%" PRId64 ", gid=%d)\n", sessionId, groupId);
-    return mDevice->authenticate(mDevice, sessionId, groupId);
-}
-
-int32_t FingerprintDaemonProxy::stopAuthentication() {
-    ALOG(LOG_VERBOSE, LOG_TAG, "stopAuthentication()\n");
-    return mDevice->cancel(mDevice);
-}
-
-int32_t FingerprintDaemonProxy::remove(int32_t fingerId, int32_t groupId) {
-    ALOG(LOG_VERBOSE, LOG_TAG, "remove(fid=%d, gid=%d)\n", fingerId, groupId);
-    return mDevice->remove(mDevice, groupId, fingerId);
-}
-
-int32_t FingerprintDaemonProxy::enumerate() {
-    ALOG(LOG_VERBOSE, LOG_TAG, "enumerate()\n");
-    return mDevice->enumerate(mDevice);
-}
-
-uint64_t FingerprintDaemonProxy::getAuthenticatorId() {
-    return mDevice->get_authenticator_id(mDevice);
-}
-
-int32_t FingerprintDaemonProxy::setActiveGroup(int32_t groupId, const uint8_t* path,
-        ssize_t pathlen) {
-    if (pathlen >= PATH_MAX || pathlen <= 0) {
-        ALOGE("Bad path length: %zd", pathlen);
-        return -1;
-    }
-    // Convert to null-terminated string
-    char path_name[PATH_MAX];
-    memcpy(path_name, path, pathlen);
-    path_name[pathlen] = '\0';
-    ALOG(LOG_VERBOSE, LOG_TAG, "setActiveGroup(%d, %s, %zu)", groupId, path_name, pathlen);
-    return mDevice->set_active_group(mDevice, groupId, path_name);
-}
-
-int64_t FingerprintDaemonProxy::openHal() {
-    ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n");
-    int err;
-    const hw_module_t *hw_module = NULL;
-    if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) {
-        ALOGE("Can't open fingerprint HW Module, error: %d", err);
-        return 0;
-    }
-    if (NULL == hw_module) {
-        ALOGE("No valid fingerprint module");
-        return 0;
-    }
-
-    mModule = reinterpret_cast<const fingerprint_module_t*>(hw_module);
-
-    if (mModule->common.methods->open == NULL) {
-        ALOGE("No valid open method");
-        return 0;
-    }
-
-    hw_device_t *device = NULL;
-
-    if (0 != (err = mModule->common.methods->open(hw_module, NULL, &device))) {
-        ALOGE("Can't open fingerprint methods, error: %d", err);
-        return 0;
-    }
-
-    if (kVersion != device->version) {
-        ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
-        // return 0; // FIXME
-    }
-
-    mDevice = reinterpret_cast<fingerprint_device_t*>(device);
-    err = mDevice->set_notify(mDevice, hal_notify_callback);
-    if (err < 0) {
-        ALOGE("Failed in call to set_notify(), err=%d", err);
-        return 0;
-    }
-
-    // Sanity check - remove
-    if (mDevice->notify != hal_notify_callback) {
-        ALOGE("NOTIFY not set properly: %p != %p", mDevice->notify, hal_notify_callback);
-    }
-
-    ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized");
-    return reinterpret_cast<int64_t>(mDevice); // This is just a handle
-}
-
-int32_t FingerprintDaemonProxy::closeHal() {
-    ALOG(LOG_VERBOSE, LOG_TAG, "nativeCloseHal()\n");
-    if (mDevice == NULL) {
-        ALOGE("No valid device");
-        return -ENOSYS;
-    }
-    int err;
-    if (0 != (err = mDevice->common.close(reinterpret_cast<hw_device_t*>(mDevice)))) {
-        ALOGE("Can't close fingerprint module, error: %d", err);
-        return err;
-    }
-    mDevice = NULL;
-    return 0;
-}
-
-void FingerprintDaemonProxy::binderDied(const wp<IBinder>& who) {
-    ALOGD("binder died");
-    int err;
-    if (0 != (err = closeHal())) {
-        ALOGE("Can't close fingerprint device, error: %d", err);
-    }
-    if (IInterface::asBinder(mCallback) == who) {
-        mCallback = NULL;
-    }
-}
-
-}
diff --git a/fingerprintd/FingerprintDaemonProxy.h b/fingerprintd/FingerprintDaemonProxy.h
deleted file mode 100644
index 145b4c9..0000000
--- a/fingerprintd/FingerprintDaemonProxy.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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 FINGERPRINT_DAEMON_PROXY_H_
-#define FINGERPRINT_DAEMON_PROXY_H_
-
-#include "IFingerprintDaemon.h"
-#include "IFingerprintDaemonCallback.h"
-
-namespace android {
-
-class FingerprintDaemonProxy : public BnFingerprintDaemon {
-    public:
-        static FingerprintDaemonProxy* getInstance() {
-            if (sInstance == NULL) {
-                sInstance = new FingerprintDaemonProxy();
-            }
-            return sInstance;
-        }
-
-        // These reflect binder methods.
-        virtual void init(const sp<IFingerprintDaemonCallback>& callback);
-        virtual int32_t enroll(const uint8_t* token, ssize_t tokenLength, int32_t groupId, int32_t timeout);
-        virtual uint64_t preEnroll();
-        virtual int32_t postEnroll();
-        virtual int32_t stopEnrollment();
-        virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId);
-        virtual int32_t stopAuthentication();
-        virtual int32_t remove(int32_t fingerId, int32_t groupId);
-        virtual int32_t enumerate();
-        virtual uint64_t getAuthenticatorId();
-        virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen);
-        virtual int64_t openHal();
-        virtual int32_t closeHal();
-
-    private:
-        FingerprintDaemonProxy();
-        virtual ~FingerprintDaemonProxy();
-        void binderDied(const wp<IBinder>& who);
-        void notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length);
-        static void hal_notify_callback(const fingerprint_msg_t *msg);
-
-        static FingerprintDaemonProxy* sInstance;
-        fingerprint_module_t const* mModule;
-        fingerprint_device_t* mDevice;
-        sp<IFingerprintDaemonCallback> mCallback;
-};
-
-} // namespace android
-
-#endif // FINGERPRINT_DAEMON_PROXY_H_
diff --git a/fingerprintd/IFingerprintDaemon.cpp b/fingerprintd/IFingerprintDaemon.cpp
deleted file mode 100644
index bc4af56..0000000
--- a/fingerprintd/IFingerprintDaemon.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * 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 <inttypes.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/PermissionCache.h>
-#include <utils/String16.h>
-#include <utils/Looper.h>
-#include <keystore/IKeystoreService.h>
-#include <keystore/keystore.h> // for error code
-#include <hardware/hardware.h>
-#include <hardware/fingerprint.h>
-#include <hardware/hw_auth_token.h>
-#include "IFingerprintDaemon.h"
-#include "IFingerprintDaemonCallback.h"
-
-namespace android {
-
-static const String16 USE_FINGERPRINT_PERMISSION("android.permission.USE_FINGERPRINT");
-static const String16 MANAGE_FINGERPRINT_PERMISSION("android.permission.MANAGE_FINGERPRINT");
-static const String16 HAL_FINGERPRINT_PERMISSION("android.permission.MANAGE_FINGERPRINT"); // TODO
-static const String16 DUMP_PERMISSION("android.permission.DUMP");
-
-const android::String16
-IFingerprintDaemon::descriptor("android.hardware.fingerprint.IFingerprintDaemon");
-
-const android::String16&
-IFingerprintDaemon::getInterfaceDescriptor() const {
-    return IFingerprintDaemon::descriptor;
-}
-
-status_t BnFingerprintDaemon::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-        uint32_t flags) {
-    switch(code) {
-        case AUTHENTICATE: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            const uint64_t sessionId = data.readInt64();
-            const uint32_t groupId = data.readInt32();
-            const int32_t ret = authenticate(sessionId, groupId);
-            reply->writeNoException();
-            reply->writeInt32(ret);
-            return NO_ERROR;
-        };
-        case CANCEL_AUTHENTICATION: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            const int32_t ret = stopAuthentication();
-            reply->writeNoException();
-            reply->writeInt32(ret);
-            return NO_ERROR;
-        }
-        case ENROLL: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            const ssize_t tokenSize = data.readInt32();
-            const uint8_t* token = static_cast<const uint8_t *>(data.readInplace(tokenSize));
-            const int32_t groupId = data.readInt32();
-            const int32_t timeout = data.readInt32();
-            const int32_t ret = enroll(token, tokenSize, groupId, timeout);
-            reply->writeNoException();
-            reply->writeInt32(ret);
-            return NO_ERROR;
-        }
-        case CANCEL_ENROLLMENT: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            const int32_t ret = stopEnrollment();
-            reply->writeNoException();
-            reply->writeInt32(ret);
-            return NO_ERROR;
-        }
-        case PRE_ENROLL: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            const uint64_t ret = preEnroll();
-            reply->writeNoException();
-            reply->writeInt64(ret);
-            return NO_ERROR;
-        }
-        case POST_ENROLL: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            const int32_t ret = postEnroll();
-            reply->writeNoException();
-            reply->writeInt32(ret);
-            return NO_ERROR;
-        }
-        case REMOVE: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            const int32_t fingerId = data.readInt32();
-            const int32_t groupId = data.readInt32();
-            const int32_t ret = remove(fingerId, groupId);
-            reply->writeNoException();
-            reply->writeInt32(ret);
-            return NO_ERROR;
-        }
-        case ENUMERATE: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            const int32_t ret = enumerate();
-            reply->writeNoException();
-            reply->writeInt32(ret);
-            return NO_ERROR;
-        }
-        case GET_AUTHENTICATOR_ID: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            const uint64_t ret = getAuthenticatorId();
-            reply->writeNoException();
-            reply->writeInt64(ret);
-            return NO_ERROR;
-        }
-        case SET_ACTIVE_GROUP: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            const int32_t group = data.readInt32();
-            const ssize_t pathSize = data.readInt32();
-            const uint8_t* path = static_cast<const uint8_t *>(data.readInplace(pathSize));
-            const int32_t ret = setActiveGroup(group, path, pathSize);
-            reply->writeNoException();
-            reply->writeInt32(ret);
-            return NO_ERROR;
-        }
-        case OPEN_HAL: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            const int64_t ret = openHal();
-            reply->writeNoException();
-            reply->writeInt64(ret);
-            return NO_ERROR;
-        }
-        case CLOSE_HAL: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            const int32_t ret = closeHal();
-            reply->writeNoException();
-            reply->writeInt32(ret);
-            return NO_ERROR;
-        }
-        case INIT: {
-            CHECK_INTERFACE(IFingerprintDaemon, data, reply);
-            if (!checkPermission(HAL_FINGERPRINT_PERMISSION)) {
-                return PERMISSION_DENIED;
-            }
-            sp<IFingerprintDaemonCallback> callback =
-                    interface_cast<IFingerprintDaemonCallback>(data.readStrongBinder());
-            init(callback);
-            reply->writeNoException();
-            return NO_ERROR;
-        }
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-};
-
-bool BnFingerprintDaemon::checkPermission(const String16& permission) {
-    const IPCThreadState* ipc = IPCThreadState::self();
-    const int calling_pid = ipc->getCallingPid();
-    const int calling_uid = ipc->getCallingUid();
-    return PermissionCache::checkPermission(permission, calling_pid, calling_uid);
-}
-
-
-}; // namespace android
diff --git a/fingerprintd/IFingerprintDaemon.h b/fingerprintd/IFingerprintDaemon.h
deleted file mode 100644
index 23c36ff..0000000
--- a/fingerprintd/IFingerprintDaemon.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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 IFINGERPRINT_DAEMON_H_
-#define IFINGERPRINT_DAEMON_H_
-
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class IFingerprintDaemonCallback;
-
-/*
-* Abstract base class for native implementation of FingerprintService.
-*
-* Note: This must be kept manually in sync with IFingerprintDaemon.aidl
-*/
-class IFingerprintDaemon : public IInterface, public IBinder::DeathRecipient {
-    public:
-        enum {
-           AUTHENTICATE = IBinder::FIRST_CALL_TRANSACTION + 0,
-           CANCEL_AUTHENTICATION = IBinder::FIRST_CALL_TRANSACTION + 1,
-           ENROLL = IBinder::FIRST_CALL_TRANSACTION + 2,
-           CANCEL_ENROLLMENT = IBinder::FIRST_CALL_TRANSACTION + 3,
-           PRE_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 4,
-           REMOVE = IBinder::FIRST_CALL_TRANSACTION + 5,
-           GET_AUTHENTICATOR_ID = IBinder::FIRST_CALL_TRANSACTION + 6,
-           SET_ACTIVE_GROUP = IBinder::FIRST_CALL_TRANSACTION + 7,
-           OPEN_HAL = IBinder::FIRST_CALL_TRANSACTION + 8,
-           CLOSE_HAL = IBinder::FIRST_CALL_TRANSACTION + 9,
-           INIT = IBinder::FIRST_CALL_TRANSACTION + 10,
-           POST_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 11,
-           ENUMERATE = IBinder::FIRST_CALL_TRANSACTION + 12,
-        };
-
-        IFingerprintDaemon() { }
-        virtual ~IFingerprintDaemon() { }
-        virtual const android::String16& getInterfaceDescriptor() const;
-
-        // Binder interface methods
-        virtual void init(const sp<IFingerprintDaemonCallback>& callback) = 0;
-        virtual int32_t enroll(const uint8_t* token, ssize_t tokenLength, int32_t groupId,
-                int32_t timeout) = 0;
-        virtual uint64_t preEnroll() = 0;
-        virtual int32_t postEnroll() = 0;
-        virtual int32_t stopEnrollment() = 0;
-        virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId) = 0;
-        virtual int32_t stopAuthentication() = 0;
-        virtual int32_t remove(int32_t fingerId, int32_t groupId) = 0;
-        virtual int32_t enumerate() = 0;
-        virtual uint64_t getAuthenticatorId() = 0;
-        virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen) = 0;
-        virtual int64_t openHal() = 0;
-        virtual int32_t closeHal() = 0;
-
-        // DECLARE_META_INTERFACE - C++ client interface not needed
-        static const android::String16 descriptor;
-        static void hal_notify_callback(const fingerprint_msg_t *msg);
-};
-
-// ----------------------------------------------------------------------------
-
-class BnFingerprintDaemon: public BnInterface<IFingerprintDaemon> {
-    public:
-       virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-               uint32_t flags = 0);
-    private:
-       bool checkPermission(const String16& permission);
-};
-
-} // namespace android
-
-#endif // IFINGERPRINT_DAEMON_H_
-
diff --git a/fingerprintd/IFingerprintDaemonCallback.cpp b/fingerprintd/IFingerprintDaemonCallback.cpp
deleted file mode 100644
index 1d75aa7..0000000
--- a/fingerprintd/IFingerprintDaemonCallback.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "IFingerprintDaemonCallback"
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/Log.h>
-#include <binder/Parcel.h>
-
-#include "IFingerprintDaemonCallback.h"
-
-namespace android {
-
-class BpFingerprintDaemonCallback : public BpInterface<IFingerprintDaemonCallback>
-{
-public:
-    explicit BpFingerprintDaemonCallback(const sp<IBinder>& impl) :
-            BpInterface<IFingerprintDaemonCallback>(impl) {
-    }
-    virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
-        data.writeInt64(devId);
-        data.writeInt32(fpId);
-        data.writeInt32(gpId);
-        data.writeInt32(rem);
-        return remote()->transact(ON_ENROLL_RESULT, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-
-    virtual status_t onAcquired(int64_t devId, int32_t acquiredInfo) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
-        data.writeInt64(devId);
-        data.writeInt32(acquiredInfo);
-        return remote()->transact(ON_ACQUIRED, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-
-    virtual status_t onAuthenticated(int64_t devId, int32_t fpId, int32_t gpId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
-        data.writeInt64(devId);
-        data.writeInt32(fpId);
-        data.writeInt32(gpId);
-        return remote()->transact(ON_AUTHENTICATED, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-
-    virtual status_t onError(int64_t devId, int32_t error) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
-        data.writeInt64(devId);
-        data.writeInt32(error);
-        return remote()->transact(ON_ERROR, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-
-    virtual status_t onRemoved(int64_t devId, int32_t fpId, int32_t gpId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
-        data.writeInt64(devId);
-        data.writeInt32(fpId);
-        data.writeInt32(gpId);
-        return remote()->transact(ON_REMOVED, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-
-    virtual status_t onEnumerate(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
-        data.writeInt64(devId);
-        data.writeInt32(fpId);
-        data.writeInt32(gpId);
-        data.writeInt32(rem);
-        return remote()->transact(ON_ENUMERATE, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-};
-
-IMPLEMENT_META_INTERFACE(FingerprintDaemonCallback,
-        "android.hardware.fingerprint.IFingerprintDaemonCallback");
-
-}; // namespace android
diff --git a/fingerprintd/IFingerprintDaemonCallback.h b/fingerprintd/IFingerprintDaemonCallback.h
deleted file mode 100644
index e343cb4..0000000
--- a/fingerprintd/IFingerprintDaemonCallback.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 IFINGERPRINT_DAEMON_CALLBACK_H_
-#define IFINGERPRINT_DAEMON_CALLBACK_H_
-
-#include <inttypes.h>
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-/*
-* Communication channel back to FingerprintService.java
-*/
-class IFingerprintDaemonCallback : public IInterface {
-    public:
-        // must be kept in sync with IFingerprintService.aidl
-        enum {
-            ON_ENROLL_RESULT = IBinder::FIRST_CALL_TRANSACTION + 0,
-            ON_ACQUIRED = IBinder::FIRST_CALL_TRANSACTION + 1,
-            ON_AUTHENTICATED = IBinder::FIRST_CALL_TRANSACTION + 2,
-            ON_ERROR = IBinder::FIRST_CALL_TRANSACTION + 3,
-            ON_REMOVED = IBinder::FIRST_CALL_TRANSACTION + 4,
-            ON_ENUMERATE = IBinder::FIRST_CALL_TRANSACTION + 5,
-        };
-
-        virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) = 0;
-        virtual status_t onAcquired(int64_t devId, int32_t acquiredInfo) = 0;
-        virtual status_t onAuthenticated(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
-        virtual status_t onError(int64_t devId, int32_t error) = 0;
-        virtual status_t onRemoved(int64_t devId, int32_t fingerId, int32_t groupId) = 0;
-        virtual status_t onEnumerate(int64_t devId, int32_t fingerId, int32_t groupId, int32_t rem) = 0;
-
-        DECLARE_META_INTERFACE(FingerprintDaemonCallback);
-};
-
-}; // namespace android
-
-#endif // IFINGERPRINT_DAEMON_CALLBACK_H_
diff --git a/fingerprintd/fingerprintd.cpp b/fingerprintd/fingerprintd.cpp
deleted file mode 100644
index 2fc2d0a..0000000
--- a/fingerprintd/fingerprintd.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "fingerprintd"
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/PermissionCache.h>
-#include <hardware/hardware.h>
-#include <hardware/fingerprint.h>
-#include <hardware/hw_auth_token.h>
-#include <keystore/IKeystoreService.h>
-#include <keystore/keystore.h> // for error codes
-#include <log/log.h>
-#include <utils/Log.h>
-#include <utils/String16.h>
-
-#include "FingerprintDaemonProxy.h"
-
-int main() {
-    ALOGI("Starting " LOG_TAG);
-    android::sp<android::IServiceManager> serviceManager = android::defaultServiceManager();
-    android::sp<android::FingerprintDaemonProxy> proxy =
-            android::FingerprintDaemonProxy::getInstance();
-    android::status_t ret = serviceManager->addService(
-            android::FingerprintDaemonProxy::descriptor, proxy);
-    if (ret != android::OK) {
-        ALOGE("Couldn't register " LOG_TAG " binder service!");
-        return -1;
-    }
-
-    /*
-     * We're the only thread in existence, so we're just going to process
-     * Binder transaction as a single-threaded program.
-     */
-    android::IPCThreadState::self()->joinThreadPool();
-    ALOGI("Done");
-    return 0;
-}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 48ddf29..44789cc 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -34,7 +34,8 @@
     int max_comp_streams;
     unsigned int zram_size;
     uint64_t reserved_size;
-    unsigned int file_encryption_mode;
+    unsigned int file_contents_mode;
+    unsigned int file_names_mode;
     unsigned int erase_blk_size;
     unsigned int logical_blk_size;
 };
@@ -94,15 +95,51 @@
     { 0,                    0 },
 };
 
-#define EM_SOFTWARE 1
-#define EM_ICE      2
+#define EM_AES_256_XTS  1
+#define EM_ICE          2
+#define EM_AES_256_CTS  3
+#define EM_AES_256_HEH  4
 
-static struct flag_list encryption_modes[] = {
-    {"software", EM_SOFTWARE},
-    {"ice", EM_ICE},
-    {0, 0}
+static const struct flag_list file_contents_encryption_modes[] = {
+    {"aes-256-xts", EM_AES_256_XTS},
+    {"software", EM_AES_256_XTS}, /* alias for backwards compatibility */
+    {"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
+    {0, 0},
 };
 
+static const struct flag_list file_names_encryption_modes[] = {
+    {"aes-256-cts", EM_AES_256_CTS},
+    {"aes-256-heh", EM_AES_256_HEH},
+    {0, 0},
+};
+
+static unsigned int encryption_mode_to_flag(const struct flag_list *list,
+                                            const char *mode, const char *type)
+{
+    const struct flag_list *j;
+
+    for (j = list; j->name; ++j) {
+        if (!strcmp(mode, j->name)) {
+            return j->flag;
+        }
+    }
+    LERROR << "Unknown " << type << " encryption mode: " << mode;
+    return 0;
+}
+
+static const char *flag_to_encryption_mode(const struct flag_list *list,
+                                           unsigned int flag)
+{
+    const struct flag_list *j;
+
+    for (j = list; j->name; ++j) {
+        if (flag == j->flag) {
+            return j->name;
+        }
+    }
+    return nullptr;
+}
+
 static uint64_t calculate_zram_size(unsigned int percentage)
 {
     uint64_t total;
@@ -183,20 +220,28 @@
                      * location of the keys.  Get it and return it.
                      */
                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
-                    flag_vals->file_encryption_mode = EM_SOFTWARE;
+                    flag_vals->file_contents_mode = EM_AES_256_XTS;
+                    flag_vals->file_names_mode = EM_AES_256_CTS;
                 } else if ((fl[i].flag == MF_FILEENCRYPTION) && flag_vals) {
-                    /* The fileencryption flag is followed by an = and the
-                     * type of the encryption.  Get it and return it.
+                    /* The fileencryption flag is followed by an = and
+                     * the mode of contents encryption, then optionally a
+                     * : and the mode of filenames encryption (defaults
+                     * to aes-256-cts).  Get it and return it.
                      */
-                    const struct flag_list *j;
-                    const char *mode = strchr(p, '=') + 1;
-                    for (j = encryption_modes; j->name; ++j) {
-                        if (!strcmp(mode, j->name)) {
-                            flag_vals->file_encryption_mode = j->flag;
-                        }
+                    char *mode = strchr(p, '=') + 1;
+                    char *colon = strchr(mode, ':');
+                    if (colon) {
+                        *colon = '\0';
                     }
-                    if (flag_vals->file_encryption_mode == 0) {
-                        LERROR << "Unknown file encryption mode: " << mode;
+                    flag_vals->file_contents_mode =
+                        encryption_mode_to_flag(file_contents_encryption_modes,
+                                                mode, "file contents");
+                    if (colon) {
+                        flag_vals->file_names_mode =
+                            encryption_mode_to_flag(file_names_encryption_modes,
+                                                    colon + 1, "file names");
+                    } else {
+                        flag_vals->file_names_mode = EM_AES_256_CTS;
                     }
                 } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
                     /* The length flag is followed by an = and the
@@ -406,7 +451,8 @@
         fstab->recs[cnt].max_comp_streams = flag_vals.max_comp_streams;
         fstab->recs[cnt].zram_size = flag_vals.zram_size;
         fstab->recs[cnt].reserved_size = flag_vals.reserved_size;
-        fstab->recs[cnt].file_encryption_mode = flag_vals.file_encryption_mode;
+        fstab->recs[cnt].file_contents_mode = flag_vals.file_contents_mode;
+        fstab->recs[cnt].file_names_mode = flag_vals.file_names_mode;
         fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
         fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
         cnt++;
@@ -567,15 +613,14 @@
     return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
 }
 
-const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab)
+void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab,
+                                      const char **contents_mode_ret,
+                                      const char **filenames_mode_ret)
 {
-    const struct flag_list *j;
-    for (j = encryption_modes; j->name; ++j) {
-        if (fstab->file_encryption_mode == j->flag) {
-            return j->name;
-        }
-    }
-    return NULL;
+    *contents_mode_ret = flag_to_encryption_mode(file_contents_encryption_modes,
+                                                 fstab->file_contents_mode);
+    *filenames_mode_ret = flag_to_encryption_mode(file_names_encryption_modes,
+                                                  fstab->file_names_mode);
 }
 
 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index a9deed9..5976514 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -76,7 +76,8 @@
     int max_comp_streams;
     unsigned int zram_size;
     uint64_t reserved_size;
-    unsigned int file_encryption_mode;
+    unsigned int file_contents_mode;
+    unsigned int file_names_mode;
     unsigned int erase_blk_size;
     unsigned int logical_blk_size;
 };
@@ -118,7 +119,9 @@
 int fs_mgr_is_verified(const struct fstab_rec *fstab);
 int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
 int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
-const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab);
+void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab,
+                                      const char **contents_mode_ret,
+                                      const char **filenames_mode_ret);
 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab);
 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
 int fs_mgr_is_notrim(struct fstab_rec *fstab);
diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk
index 3f78955..0dfd9d8 100644
--- a/gatekeeperd/Android.mk
+++ b/gatekeeperd/Android.mk
@@ -33,7 +33,12 @@
 	libbase \
 	libutils \
 	libcrypto \
-	libkeystore_binder
+	libkeystore_binder \
+	libhidlbase \
+	libhidltransport \
+	libhwbinder \
+	android.hardware.gatekeeper@1.0 \
+
 LOCAL_STATIC_LIBRARIES := libscrypt_static
 LOCAL_C_INCLUDES := external/scrypt/lib/crypto
 LOCAL_INIT_RC := gatekeeperd.rc
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index 96bda07..86b6287 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -39,6 +39,15 @@
 #include "SoftGateKeeperDevice.h"
 #include "IUserManager.h"
 
+#include <hidl/HidlSupport.h>
+#include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
+
+using android::sp;
+using android::hardware::gatekeeper::V1_0::IGatekeeper;
+using android::hardware::gatekeeper::V1_0::GatekeeperStatusCode;
+using android::hardware::gatekeeper::V1_0::GatekeeperResponse;
+using android::hardware::Return;
+
 namespace android {
 
 static const String16 KEYGUARD_PERMISSION("android.permission.ACCESS_KEYGUARD_SECURE_STORAGE");
@@ -47,28 +56,22 @@
 class GateKeeperProxy : public BnGateKeeperService {
 public:
     GateKeeperProxy() {
-        int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module);
-        device = NULL;
+        hw_device = IGatekeeper::getService("gatekeeper");
 
-        if (ret < 0) {
+        if (hw_device == nullptr) {
             ALOGW("falling back to software GateKeeper");
             soft_device.reset(new SoftGateKeeperDevice());
-        } else {
-            ret = gatekeeper_open(module, &device);
-            if (ret < 0)
-                LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to open GateKeeper HAL");
         }
 
         if (mark_cold_boot()) {
             ALOGI("cold boot: clearing state");
-            if (device != NULL && device->delete_all_users != NULL) {
-                device->delete_all_users(device);
+            if (hw_device != nullptr) {
+                hw_device->deleteAllUsers([](const GatekeeperResponse &){});
             }
         }
     }
 
     virtual ~GateKeeperProxy() {
-        if (device) gatekeeper_close(device);
     }
 
     void store_sid(uint32_t uid, uint64_t sid) {
@@ -141,7 +144,7 @@
         if (desired_password_length == 0) return -EINVAL;
 
         int ret;
-        if (device) {
+        if (hw_device != nullptr) {
             const gatekeeper::password_handle_t *handle =
                     reinterpret_cast<const gatekeeper::password_handle_t *>(current_password_handle);
 
@@ -154,10 +157,37 @@
                 current_password_length = 0;
             }
 
-            ret = device->enroll(device, uid, current_password_handle, current_password_handle_length,
-                    current_password, current_password_length,
-                    desired_password, desired_password_length,
-                    enrolled_password_handle, enrolled_password_handle_length);
+            android::hardware::hidl_vec<uint8_t> curPwdHandle;
+            curPwdHandle.setToExternal(const_cast<uint8_t*>(current_password_handle),
+                                       current_password_handle_length);
+            android::hardware::hidl_vec<uint8_t> curPwd;
+            curPwd.setToExternal(const_cast<uint8_t*>(current_password),
+                                 current_password_length);
+            android::hardware::hidl_vec<uint8_t> newPwd;
+            newPwd.setToExternal(const_cast<uint8_t*>(desired_password),
+                                 desired_password_length);
+
+            Return<void> hwRes = hw_device->enroll(uid, curPwdHandle, curPwd, newPwd,
+                              [&ret, enrolled_password_handle, enrolled_password_handle_length]
+                                   (const GatekeeperResponse &rsp) {
+                ret = static_cast<int>(rsp.code); // propagate errors
+                if (rsp.code >= GatekeeperStatusCode::STATUS_OK) {
+                    if (enrolled_password_handle != nullptr &&
+                        enrolled_password_handle_length != nullptr) {
+                        *enrolled_password_handle = new uint8_t[rsp.data.size()];
+                        *enrolled_password_handle_length = rsp.data.size();
+                        memcpy(*enrolled_password_handle, rsp.data.data(),
+                               *enrolled_password_handle_length);
+                    }
+                    ret = 0; // all success states are reported as 0
+                } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT && rsp.timeout > 0) {
+                    ret = rsp.timeout;
+                }
+            });
+            if (!hwRes.isOk()) {
+                ALOGE("enroll transaction failed\n");
+                ret = -1;
+            }
         } else {
             ret = soft_device->enroll(uid,
                     current_password_handle, current_password_handle_length,
@@ -214,16 +244,40 @@
             return -EINVAL;
 
         int ret;
-        if (device) {
+        if (hw_device != nullptr) {
             const gatekeeper::password_handle_t *handle =
                     reinterpret_cast<const gatekeeper::password_handle_t *>(enrolled_password_handle);
             // handle version 0 does not have hardware backed flag, and thus cannot be upgraded to
             // a HAL if there was none before
             if (handle->version == 0 || handle->hardware_backed) {
-                ret = device->verify(device, uid, challenge,
-                    enrolled_password_handle, enrolled_password_handle_length,
-                    provided_password, provided_password_length, auth_token, auth_token_length,
-                    request_reenroll);
+                android::hardware::hidl_vec<uint8_t> curPwdHandle;
+                curPwdHandle.setToExternal(const_cast<uint8_t*>(enrolled_password_handle),
+                                           enrolled_password_handle_length);
+                android::hardware::hidl_vec<uint8_t> enteredPwd;
+                enteredPwd.setToExternal(const_cast<uint8_t*>(provided_password),
+                                         provided_password_length);
+                Return<void> hwRes = hw_device->verify(uid, challenge, curPwdHandle, enteredPwd,
+                                        [&ret, request_reenroll, auth_token, auth_token_length]
+                                             (const GatekeeperResponse &rsp) {
+                    ret = static_cast<int>(rsp.code); // propagate errors
+                    if (auth_token != nullptr && auth_token_length != nullptr &&
+                        rsp.code >= GatekeeperStatusCode::STATUS_OK) {
+                        *auth_token = new uint8_t[rsp.data.size()];
+                        *auth_token_length = rsp.data.size();
+                        memcpy(*auth_token, rsp.data.data(), *auth_token_length);
+                        if (request_reenroll != nullptr) {
+                            *request_reenroll = (rsp.code == GatekeeperStatusCode::STATUS_REENROLL);
+                        }
+                        ret = 0; // all success states are reported as 0
+                    } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT &&
+                               rsp.timeout > 0) {
+                        ret = rsp.timeout;
+                    }
+                });
+                if (!hwRes.isOk()) {
+                    ALOGE("verify transaction failed\n");
+                    ret = -1;
+                }
             } else {
                 // upgrade scenario, a HAL has been added to this device where there was none before
                 SoftGateKeeperDevice soft_dev;
@@ -250,9 +304,9 @@
             sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
             sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
             if (service != NULL) {
-                status_t ret = service->addAuthToken(*auth_token, *auth_token_length);
-                if (ret != ResponseCode::NO_ERROR) {
-                    ALOGE("Falure sending auth token to KeyStore: %d", ret);
+                auto ret = service->addAuthToken(*auth_token, *auth_token_length);
+                if (!ret.isOk()) {
+                    ALOGE("Failure sending auth token to KeyStore: %" PRId32, int32_t(ret));
                 }
             } else {
                 ALOGE("Unable to communicate with KeyStore");
@@ -295,8 +349,8 @@
         }
         clear_sid(uid);
 
-        if (device != NULL && device->delete_user != NULL) {
-            device->delete_user(device, uid);
+        if (hw_device != nullptr) {
+            hw_device->deleteUser(uid, [] (const GatekeeperResponse &){});
         }
     }
 
@@ -308,7 +362,7 @@
             return PERMISSION_DENIED;
         }
 
-        if (device == NULL) {
+        if (hw_device == NULL) {
             const char *result = "Device not available";
             write(fd, result, strlen(result) + 1);
         } else {
@@ -320,9 +374,8 @@
     }
 
 private:
-    gatekeeper_device_t *device;
+    sp<IGatekeeper> hw_device;
     UniquePtr<SoftGateKeeperDevice> soft_device;
-    const hw_module_t *module;
 };
 }// namespace android
 
diff --git a/healthd/Android.mk b/healthd/Android.mk
index b292725..8b59964 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -3,16 +3,6 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := healthd_board_default.cpp
-LOCAL_MODULE := libhealthd.default
-LOCAL_CFLAGS := -Werror
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libbinder
-LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libbinder
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
 LOCAL_SRC_FILES := BatteryMonitor.cpp
 LOCAL_MODULE := libbatterymonitor
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
@@ -21,26 +11,47 @@
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
-ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
-LOCAL_SHARED_LIBRARIES += libsuspend
-endif
 LOCAL_SRC_FILES := \
     healthd_mode_android.cpp \
-    healthd_mode_charger.cpp \
-    AnimationParser.cpp \
-    BatteryPropertiesRegistrar.cpp \
+    BatteryPropertiesRegistrar.cpp
 
-LOCAL_MODULE := libhealthd_internal
-LOCAL_C_INCLUDES := bootable/recovery
+LOCAL_MODULE := libhealthd_android
 LOCAL_EXPORT_C_INCLUDE_DIRS := \
     $(LOCAL_PATH) \
-    $(LOCAL_PATH)/include \
+    $(LOCAL_PATH)/include
 
 LOCAL_STATIC_LIBRARIES := \
     libbatterymonitor \
     libbatteryservice \
-    libbinder \
+    libutils \
+    libbase \
+    libcutils \
+    liblog \
+    libc \
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := -Werror
+ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
+LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
+endif
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
+endif
+
+LOCAL_SRC_FILES := \
+    healthd_mode_charger.cpp \
+    AnimationParser.cpp
+
+LOCAL_MODULE := libhealthd_charger
+LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+    $(LOCAL_PATH) \
+    $(LOCAL_PATH)/include
+
+LOCAL_STATIC_LIBRARIES := \
     libminui \
     libpng \
     libz \
@@ -51,11 +62,14 @@
     libm \
     libc \
 
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_STATIC_LIBRARIES += libsuspend
+endif
+
 include $(BUILD_STATIC_LIBRARY)
 
-
+### charger ###
 include $(CLEAR_VARS)
-
 ifeq ($(strip $(BOARD_CHARGER_NO_UI)),true)
 LOCAL_CHARGER_NO_UI := true
 endif
@@ -64,80 +78,57 @@
 endif
 
 LOCAL_SRC_FILES := \
-	healthd.cpp \
-	healthd_mode_android.cpp \
-	BatteryPropertiesRegistrar.cpp \
+    healthd_common.cpp \
+    charger.cpp \
 
-ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
-LOCAL_SRC_FILES += healthd_mode_charger.cpp
-endif
-
-LOCAL_MODULE := healthd
+LOCAL_MODULE := charger
 LOCAL_MODULE_TAGS := optional
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
 
-LOCAL_CFLAGS := -D__STDC_LIMIT_MACROS -Werror
-
-ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
-LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
-endif
-
-ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
-endif
-
+LOCAL_CFLAGS := -Werror
 ifeq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
 LOCAL_CFLAGS += -DCHARGER_NO_UI
 endif
-
-LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include
-
 ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),)
 LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST)
 endif
-
 ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),)
 LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
 endif
 
 LOCAL_STATIC_LIBRARIES := \
-    libhealthd_internal \
+    libhealthd_charger \
     libbatterymonitor \
-    libbatteryservice \
-    libbinder \
     libbase \
-
-ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
-LOCAL_STATIC_LIBRARIES += \
-   libminui \
-   libpng \
-   libz \
-
-endif
-
-
-LOCAL_STATIC_LIBRARIES += \
     libutils \
     libcutils \
     liblog \
     libm \
     libc \
 
+ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
+LOCAL_STATIC_LIBRARIES += \
+    libminui \
+    libpng \
+    libz \
+
+endif
+
 ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
 LOCAL_STATIC_LIBRARIES += libsuspend
 endif
 
 LOCAL_HAL_STATIC_LIBRARIES := libhealthd
 
-# Symlink /charger to /sbin/healthd
+# Symlink /charger to /sbin/charger
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT) \
-    && ln -sf /sbin/healthd $(TARGET_ROOT_OUT)/charger
+    && ln -sf /sbin/charger $(TARGET_ROOT_OUT)/charger
 
 include $(BUILD_EXECUTABLE)
 
-
 ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
 define _add-charger-image
 include $$(CLEAR_VARS)
@@ -165,3 +156,41 @@
 _add-charger-image :=
 _img_modules :=
 endif # LOCAL_CHARGER_NO_UI
+
+### healthd ###
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    healthd_common.cpp \
+    healthd.cpp \
+
+LOCAL_MODULE := healthd
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
+ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_FAST),)
+LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_FAST=$(BOARD_PERIODIC_CHORES_INTERVAL_FAST)
+endif
+ifneq ($(BOARD_PERIODIC_CHORES_INTERVAL_SLOW),)
+LOCAL_CFLAGS += -DBOARD_PERIODIC_CHORES_INTERVAL_SLOW=$(BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
+endif
+
+LOCAL_STATIC_LIBRARIES := \
+    libhealthd_android \
+    libbatterymonitor \
+    libbatteryservice \
+    android.hardware.health@1.0-convert \
+
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libbase \
+    libutils \
+    libcutils \
+    liblog \
+    libm \
+    libc \
+    libhidlbase \
+    libhidltransport \
+    android.hardware.health@1.0 \
+
+include $(BUILD_EXECUTABLE)
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 0c90a54..4007203 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -141,6 +141,7 @@
     struct sysfsStringEnumMap supplyTypeMap[] = {
             { "Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN },
             { "Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY },
+            { "BMS", ANDROID_POWER_SUPPLY_TYPE_BATTERY },
             { "UPS", ANDROID_POWER_SUPPLY_TYPE_AC },
             { "Mains", ANDROID_POWER_SUPPLY_TYPE_AC },
             { "USB", ANDROID_POWER_SUPPLY_TYPE_USB },
@@ -347,6 +348,7 @@
 
 status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
     status_t ret = BAD_VALUE;
+    std::string buf;
 
     val->valueInt64 = LONG_MIN;
 
@@ -399,6 +401,15 @@
         }
         break;
 
+    case BATTERY_PROP_BATTERY_STATUS:
+        if (mAlwaysPluggedDevice) {
+            val->valueInt64 = BATTERY_STATUS_CHARGING;
+        } else {
+            val->valueInt64 = getChargeStatus();
+        }
+        ret = NO_ERROR;
+        break;
+
     default:
         break;
     }
diff --git a/healthd/charger.cpp b/healthd/charger.cpp
new file mode 100644
index 0000000..5a8fe1a
--- /dev/null
+++ b/healthd/charger.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "charger"
+#define KLOG_LEVEL 6
+
+#include <healthd/healthd.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <cutils/klog.h>
+
+using namespace android;
+
+// main healthd loop
+extern int healthd_main(void);
+
+// Charger mode
+
+extern void healthd_mode_charger_init(struct healthd_config *config);
+extern int healthd_mode_charger_preparetowait(void);
+extern void healthd_mode_charger_heartbeat(void);
+extern void healthd_mode_charger_battery_update(
+    struct android::BatteryProperties *props);
+
+// NOPs for modes that need no special action
+
+static void healthd_mode_nop_init(struct healthd_config *config);
+static int healthd_mode_nop_preparetowait(void);
+static void healthd_mode_nop_heartbeat(void);
+static void healthd_mode_nop_battery_update(
+    struct android::BatteryProperties *props);
+
+static struct healthd_mode_ops healthd_nops = {
+    .init = healthd_mode_nop_init,
+    .preparetowait = healthd_mode_nop_preparetowait,
+    .heartbeat = healthd_mode_nop_heartbeat,
+    .battery_update = healthd_mode_nop_battery_update,
+};
+
+#ifdef CHARGER_NO_UI
+static struct healthd_mode_ops charger_ops = healthd_nops;
+#else
+static struct healthd_mode_ops charger_ops = {
+    .init = healthd_mode_charger_init,
+    .preparetowait = healthd_mode_charger_preparetowait,
+    .heartbeat = healthd_mode_charger_heartbeat,
+    .battery_update = healthd_mode_charger_battery_update,
+};
+#endif
+
+static void healthd_mode_nop_init(struct healthd_config* /*config*/) {
+}
+
+static int healthd_mode_nop_preparetowait(void) {
+    return -1;
+}
+
+static void healthd_mode_nop_heartbeat(void) {
+}
+
+static void healthd_mode_nop_battery_update(
+    struct android::BatteryProperties* /*props*/) {
+}
+
+int main(int argc, char **argv) {
+    int ch;
+
+    healthd_mode_ops = &charger_ops;
+
+    while ((ch = getopt(argc, argv, "cr")) != -1) {
+        switch (ch) {
+            case 'c':
+                // -c is now a noop
+                break;
+            case 'r':
+                // force nops for recovery
+                healthd_mode_ops = &healthd_nops;
+                break;
+            case '?':
+            default:
+                KLOG_ERROR(LOG_TAG, "Unrecognized charger option: %c\n",
+                        optopt);
+                exit(1);
+        }
+    }
+
+    return healthd_main();
+}
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index aa6735d..cae6c4c 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 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.
@@ -18,369 +18,106 @@
 #define KLOG_LEVEL 6
 
 #include <healthd/healthd.h>
-#include <healthd/BatteryMonitor.h>
 
-#include <errno.h>
-#include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include <unistd.h>
-#include <batteryservice/BatteryService.h>
 #include <cutils/klog.h>
-#include <cutils/uevent.h>
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <utils/Errors.h>
+
+#include <android/hardware/health/1.0/IHealth.h>
+#include <android/hardware/health/1.0/types.h>
+#include <hal_conversion.h>
 
 using namespace android;
 
-#ifndef BOARD_PERIODIC_CHORES_INTERVAL_FAST
-  // Periodic chores fast interval in seconds
-  #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
-#else
-  #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (BOARD_PERIODIC_CHORES_INTERVAL_FAST)
-#endif
+using IHealth = ::android::hardware::health::V1_0::IHealth;
+using Result = ::android::hardware::health::V1_0::Result;
+using HealthConfig = ::android::hardware::health::V1_0::HealthConfig;
+using HealthInfo = ::android::hardware::health::V1_0::HealthInfo;
 
-#ifndef BOARD_PERIODIC_CHORES_INTERVAL_SLOW
-  // Periodic chores fast interval in seconds
-  #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
-#else
-  #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
-#endif
+using ::android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
+using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig;
+using ::android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
 
-static struct healthd_config healthd_config = {
-    .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
-    .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
-    .batteryStatusPath = String8(String8::kEmptyString),
-    .batteryHealthPath = String8(String8::kEmptyString),
-    .batteryPresentPath = String8(String8::kEmptyString),
-    .batteryCapacityPath = String8(String8::kEmptyString),
-    .batteryVoltagePath = String8(String8::kEmptyString),
-    .batteryTemperaturePath = String8(String8::kEmptyString),
-    .batteryTechnologyPath = String8(String8::kEmptyString),
-    .batteryCurrentNowPath = String8(String8::kEmptyString),
-    .batteryCurrentAvgPath = String8(String8::kEmptyString),
-    .batteryChargeCounterPath = String8(String8::kEmptyString),
-    .batteryFullChargePath = String8(String8::kEmptyString),
-    .batteryCycleCountPath = String8(String8::kEmptyString),
-    .energyCounter = NULL,
-    .boot_min_cap = 0,
-    .screen_on = NULL,
-};
+// device specific hal interface;
+static sp<IHealth> gHealth;
 
-static int eventct;
-static int epollfd;
-
-#define POWER_SUPPLY_SUBSYSTEM "power_supply"
-
-// epoll_create() parameter is actually unused
-#define MAX_EPOLL_EVENTS 40
-static int uevent_fd;
-static int wakealarm_fd;
-
-// -1 for no epoll timeout
-static int awake_poll_interval = -1;
-
-static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
-
-static BatteryMonitor* gBatteryMonitor;
-
-struct healthd_mode_ops *healthd_mode_ops;
+// main healthd loop
+extern int healthd_main(void);
 
 // Android mode
-
 extern void healthd_mode_android_init(struct healthd_config *config);
 extern int healthd_mode_android_preparetowait(void);
+extern void healthd_mode_android_heartbeat(void);
 extern void healthd_mode_android_battery_update(
     struct android::BatteryProperties *props);
 
-// Charger mode
-
-extern void healthd_mode_charger_init(struct healthd_config *config);
-extern int healthd_mode_charger_preparetowait(void);
-extern void healthd_mode_charger_heartbeat(void);
-extern void healthd_mode_charger_battery_update(
-    struct android::BatteryProperties *props);
-
-// NOPs for modes that need no special action
-
-static void healthd_mode_nop_init(struct healthd_config *config);
-static int healthd_mode_nop_preparetowait(void);
-static void healthd_mode_nop_heartbeat(void);
-static void healthd_mode_nop_battery_update(
-    struct android::BatteryProperties *props);
-
 static struct healthd_mode_ops android_ops = {
     .init = healthd_mode_android_init,
     .preparetowait = healthd_mode_android_preparetowait,
-    .heartbeat = healthd_mode_nop_heartbeat,
+    .heartbeat = healthd_mode_android_heartbeat,
     .battery_update = healthd_mode_android_battery_update,
 };
 
-static struct healthd_mode_ops charger_ops = {
-#ifdef CHARGER_NO_UI
-    .init = healthd_mode_nop_init,
-    .preparetowait = healthd_mode_nop_preparetowait,
-    .heartbeat = healthd_mode_nop_heartbeat,
-    .battery_update = healthd_mode_nop_battery_update,
-#else
-    .init = healthd_mode_charger_init,
-    .preparetowait = healthd_mode_charger_preparetowait,
-    .heartbeat = healthd_mode_charger_heartbeat,
-    .battery_update = healthd_mode_charger_battery_update,
-#endif
-};
+// default energy counter property redirect to talk to device
+// HAL
+static int healthd_board_get_energy_counter(int64_t *energy) {
 
-static struct healthd_mode_ops recovery_ops = {
-    .init = healthd_mode_nop_init,
-    .preparetowait = healthd_mode_nop_preparetowait,
-    .heartbeat = healthd_mode_nop_heartbeat,
-    .battery_update = healthd_mode_nop_battery_update,
-};
-
-static void healthd_mode_nop_init(struct healthd_config* /*config*/) {
-}
-
-static int healthd_mode_nop_preparetowait(void) {
-    return -1;
-}
-
-static void healthd_mode_nop_heartbeat(void) {
-}
-
-static void healthd_mode_nop_battery_update(
-    struct android::BatteryProperties* /*props*/) {
-}
-
-int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
-    struct epoll_event ev;
-
-    ev.events = EPOLLIN;
-
-    if (wakeup == EVENT_WAKEUP_FD)
-        ev.events |= EPOLLWAKEUP;
-
-    ev.data.ptr = (void *)handler;
-    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
-        KLOG_ERROR(LOG_TAG,
-                   "epoll_ctl failed; errno=%d\n", errno);
-        return -1;
+    if (gHealth == nullptr) {
+        return NAME_NOT_FOUND;
     }
 
-    eventct++;
-    return 0;
+    Result result = Result::NOT_SUPPORTED;
+    gHealth->energyCounter([=, &result] (Result ret, int64_t energyOut) {
+                result = ret;
+                *energy = energyOut;
+            });
+
+    return result == Result::SUCCESS ? OK : NAME_NOT_FOUND;
 }
 
-static void wakealarm_set_interval(int interval) {
-    struct itimerspec itval;
+void healthd_board_init(struct healthd_config *config) {
 
-    if (wakealarm_fd == -1)
-            return;
+    // Initialize the board HAL - Equivalent of healthd_board_init(config)
+    // in charger/recovery mode.
 
-    wakealarm_wake_interval = interval;
-
-    if (interval == -1)
-        interval = 0;
-
-    itval.it_interval.tv_sec = interval;
-    itval.it_interval.tv_nsec = 0;
-    itval.it_value.tv_sec = interval;
-    itval.it_value.tv_nsec = 0;
-
-    if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
-        KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
-}
-
-status_t healthd_get_property(int id, struct BatteryProperty *val) {
-    return gBatteryMonitor->getProperty(id, val);
-}
-
-void healthd_battery_update(void) {
-    // Fast wake interval when on charger (watch for overheat);
-    // slow wake interval when on battery (watch for drained battery).
-
-   int new_wake_interval = gBatteryMonitor->update() ?
-       healthd_config.periodic_chores_interval_fast :
-           healthd_config.periodic_chores_interval_slow;
-
-    if (new_wake_interval != wakealarm_wake_interval)
-            wakealarm_set_interval(new_wake_interval);
-
-    // During awake periods poll at fast rate.  If wake alarm is set at fast
-    // rate then just use the alarm; if wake alarm is set at slow rate then
-    // poll at fast rate while awake and let alarm wake up at slow rate when
-    // asleep.
-
-    if (healthd_config.periodic_chores_interval_fast == -1)
-        awake_poll_interval = -1;
-    else
-        awake_poll_interval =
-            new_wake_interval == healthd_config.periodic_chores_interval_fast ?
-                -1 : healthd_config.periodic_chores_interval_fast * 1000;
-}
-
-void healthd_dump_battery_state(int fd) {
-    gBatteryMonitor->dumpState(fd);
-    fsync(fd);
-}
-
-static void periodic_chores() {
-    healthd_battery_update();
-}
-
-#define UEVENT_MSG_LEN 2048
-static void uevent_event(uint32_t /*epevents*/) {
-    char msg[UEVENT_MSG_LEN+2];
-    char *cp;
-    int n;
-
-    n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
-    if (n <= 0)
-        return;
-    if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
-        return;
-
-    msg[n] = '\0';
-    msg[n+1] = '\0';
-    cp = msg;
-
-    while (*cp) {
-        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
-            healthd_battery_update();
-            break;
-        }
-
-        /* advance to after the next \0 */
-        while (*cp++)
-            ;
-    }
-}
-
-static void uevent_init(void) {
-    uevent_fd = uevent_open_socket(64*1024, true);
-
-    if (uevent_fd < 0) {
-        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+    gHealth = IHealth::getService("health");
+    if (gHealth == nullptr) {
+        KLOG_WARNING(LOG_TAG, "unable to get HAL interface, using defaults\n");
         return;
     }
 
-    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
-    if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
-        KLOG_ERROR(LOG_TAG,
-                   "register for uevent events failed\n");
+    HealthConfig halConfig;
+    convertToHealthConfig(config, halConfig);
+    gHealth->init(halConfig, [=] (const auto &halConfigOut) {
+            convertFromHealthConfig(halConfigOut, config);
+            // always redirect energy counter queries
+            config->energyCounter = healthd_board_get_energy_counter;
+            });
 }
 
-static void wakealarm_event(uint32_t /*epevents*/) {
-    unsigned long long wakeups;
+int healthd_board_battery_update(struct android::BatteryProperties *props) {
+    int logthis = 0;
 
-    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
-        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
-        return;
+    if (gHealth == nullptr) {
+        return logthis;
     }
 
-    periodic_chores();
+    HealthInfo info;
+    convertToHealthInfo(props, info);
+    gHealth->update(info,
+            [=, &logthis] (int32_t ret, const auto &infoOut) {
+                logthis = ret;
+                convertFromHealthInfo(infoOut, props);
+            });
+
+    return logthis;
 }
 
-static void wakealarm_init(void) {
-    wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
-    if (wakealarm_fd == -1) {
-        KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
-        return;
-    }
+int main(int /*argc*/, char ** /*argv*/) {
 
-    if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
-        KLOG_ERROR(LOG_TAG,
-                   "Registration of wakealarm event failed\n");
-
-    wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
-}
-
-static void healthd_mainloop(void) {
-    int nevents = 0;
-    while (1) {
-        struct epoll_event events[eventct];
-        int timeout = awake_poll_interval;
-        int mode_timeout;
-
-        /* Don't wait for first timer timeout to run periodic chores */
-        if (!nevents)
-            periodic_chores();
-
-        healthd_mode_ops->heartbeat();
-
-        mode_timeout = healthd_mode_ops->preparetowait();
-        if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
-            timeout = mode_timeout;
-        nevents = epoll_wait(epollfd, events, eventct, timeout);
-        if (nevents == -1) {
-            if (errno == EINTR)
-                continue;
-            KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
-            break;
-        }
-
-        for (int n = 0; n < nevents; ++n) {
-            if (events[n].data.ptr)
-                (*(void (*)(int))events[n].data.ptr)(events[n].events);
-        }
-    }
-
-    return;
-}
-
-static int healthd_init() {
-    epollfd = epoll_create(MAX_EPOLL_EVENTS);
-    if (epollfd == -1) {
-        KLOG_ERROR(LOG_TAG,
-                   "epoll_create failed; errno=%d\n",
-                   errno);
-        return -1;
-    }
-
-    healthd_board_init(&healthd_config);
-    healthd_mode_ops->init(&healthd_config);
-    wakealarm_init();
-    uevent_init();
-    gBatteryMonitor = new BatteryMonitor();
-    gBatteryMonitor->init(&healthd_config);
-    return 0;
-}
-
-int main(int argc, char **argv) {
-    int ch;
-    int ret;
-
-    klog_set_level(KLOG_LEVEL);
     healthd_mode_ops = &android_ops;
 
-    if (!strcmp(basename(argv[0]), "charger")) {
-        healthd_mode_ops = &charger_ops;
-    } else {
-        while ((ch = getopt(argc, argv, "cr")) != -1) {
-            switch (ch) {
-            case 'c':
-                healthd_mode_ops = &charger_ops;
-                break;
-            case 'r':
-                healthd_mode_ops = &recovery_ops;
-                break;
-            case '?':
-            default:
-                KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",
-                           optopt);
-                exit(1);
-            }
-        }
-    }
-
-    ret = healthd_init();
-    if (ret) {
-        KLOG_ERROR("Initialization failed, exiting\n");
-        exit(2);
-    }
-
-    healthd_mainloop();
-    KLOG_ERROR("Main loop terminated, exiting\n");
-    return 3;
+    return healthd_main();
 }
diff --git a/healthd/healthd_board_default.cpp b/healthd/healthd_board_default.cpp
deleted file mode 100644
index eb55773..0000000
--- a/healthd/healthd_board_default.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2013 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 <healthd/healthd.h>
-
-void healthd_board_init(struct healthd_config*)
-{
-    // use defaults
-}
-
-
-int healthd_board_battery_update(struct android::BatteryProperties*)
-{
-    // return 0 to log periodic polled battery status to kernel log
-    return 0;
-}
diff --git a/healthd/healthd_common.cpp b/healthd/healthd_common.cpp
new file mode 100644
index 0000000..6599919
--- /dev/null
+++ b/healthd/healthd_common.cpp
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#define LOG_TAG "healthd-common"
+#define KLOG_LEVEL 6
+
+#include <healthd/healthd.h>
+#include <healthd/BatteryMonitor.h>
+
+#include <errno.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <batteryservice/BatteryService.h>
+#include <cutils/klog.h>
+#include <cutils/uevent.h>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <utils/Errors.h>
+
+using namespace android;
+
+#ifndef BOARD_PERIODIC_CHORES_INTERVAL_FAST
+  // Periodic chores fast interval in seconds
+  #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
+#else
+  #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (BOARD_PERIODIC_CHORES_INTERVAL_FAST)
+#endif
+
+#ifndef BOARD_PERIODIC_CHORES_INTERVAL_SLOW
+  // Periodic chores fast interval in seconds
+  #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
+#else
+  #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (BOARD_PERIODIC_CHORES_INTERVAL_SLOW)
+#endif
+
+static struct healthd_config healthd_config = {
+    .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
+    .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
+    .batteryStatusPath = String8(String8::kEmptyString),
+    .batteryHealthPath = String8(String8::kEmptyString),
+    .batteryPresentPath = String8(String8::kEmptyString),
+    .batteryCapacityPath = String8(String8::kEmptyString),
+    .batteryVoltagePath = String8(String8::kEmptyString),
+    .batteryTemperaturePath = String8(String8::kEmptyString),
+    .batteryTechnologyPath = String8(String8::kEmptyString),
+    .batteryCurrentNowPath = String8(String8::kEmptyString),
+    .batteryCurrentAvgPath = String8(String8::kEmptyString),
+    .batteryChargeCounterPath = String8(String8::kEmptyString),
+    .batteryFullChargePath = String8(String8::kEmptyString),
+    .batteryCycleCountPath = String8(String8::kEmptyString),
+    .energyCounter = NULL,
+    .boot_min_cap = 0,
+    .screen_on = NULL,
+};
+
+static int eventct;
+static int epollfd;
+
+#define POWER_SUPPLY_SUBSYSTEM "power_supply"
+
+// epoll_create() parameter is actually unused
+#define MAX_EPOLL_EVENTS 40
+static int uevent_fd;
+static int wakealarm_fd;
+
+// -1 for no epoll timeout
+static int awake_poll_interval = -1;
+
+static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
+
+static BatteryMonitor* gBatteryMonitor;
+
+struct healthd_mode_ops *healthd_mode_ops;
+
+int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
+    struct epoll_event ev;
+
+    ev.events = EPOLLIN;
+
+    if (wakeup == EVENT_WAKEUP_FD)
+        ev.events |= EPOLLWAKEUP;
+
+    ev.data.ptr = (void *)handler;
+    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+        KLOG_ERROR(LOG_TAG,
+                   "epoll_ctl failed; errno=%d\n", errno);
+        return -1;
+    }
+
+    eventct++;
+    return 0;
+}
+
+static void wakealarm_set_interval(int interval) {
+    struct itimerspec itval;
+
+    if (wakealarm_fd == -1)
+            return;
+
+    wakealarm_wake_interval = interval;
+
+    if (interval == -1)
+        interval = 0;
+
+    itval.it_interval.tv_sec = interval;
+    itval.it_interval.tv_nsec = 0;
+    itval.it_value.tv_sec = interval;
+    itval.it_value.tv_nsec = 0;
+
+    if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
+        KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
+}
+
+status_t healthd_get_property(int id, struct BatteryProperty *val) {
+    return gBatteryMonitor->getProperty(id, val);
+}
+
+void healthd_battery_update(void) {
+    // Fast wake interval when on charger (watch for overheat);
+    // slow wake interval when on battery (watch for drained battery).
+
+   int new_wake_interval = gBatteryMonitor->update() ?
+       healthd_config.periodic_chores_interval_fast :
+           healthd_config.periodic_chores_interval_slow;
+
+    if (new_wake_interval != wakealarm_wake_interval)
+            wakealarm_set_interval(new_wake_interval);
+
+    // During awake periods poll at fast rate.  If wake alarm is set at fast
+    // rate then just use the alarm; if wake alarm is set at slow rate then
+    // poll at fast rate while awake and let alarm wake up at slow rate when
+    // asleep.
+
+    if (healthd_config.periodic_chores_interval_fast == -1)
+        awake_poll_interval = -1;
+    else
+        awake_poll_interval =
+            new_wake_interval == healthd_config.periodic_chores_interval_fast ?
+                -1 : healthd_config.periodic_chores_interval_fast * 1000;
+}
+
+void healthd_dump_battery_state(int fd) {
+    gBatteryMonitor->dumpState(fd);
+    fsync(fd);
+}
+
+static void periodic_chores() {
+    healthd_battery_update();
+}
+
+#define UEVENT_MSG_LEN 2048
+static void uevent_event(uint32_t /*epevents*/) {
+    char msg[UEVENT_MSG_LEN+2];
+    char *cp;
+    int n;
+
+    n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
+    if (n <= 0)
+        return;
+    if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
+        return;
+
+    msg[n] = '\0';
+    msg[n+1] = '\0';
+    cp = msg;
+
+    while (*cp) {
+        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
+            healthd_battery_update();
+            break;
+        }
+
+        /* advance to after the next \0 */
+        while (*cp++)
+            ;
+    }
+}
+
+static void uevent_init(void) {
+    uevent_fd = uevent_open_socket(64*1024, true);
+
+    if (uevent_fd < 0) {
+        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+        return;
+    }
+
+    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+    if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
+        KLOG_ERROR(LOG_TAG,
+                   "register for uevent events failed\n");
+}
+
+static void wakealarm_event(uint32_t /*epevents*/) {
+    unsigned long long wakeups;
+
+    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
+        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
+        return;
+    }
+
+    periodic_chores();
+}
+
+static void wakealarm_init(void) {
+    wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
+    if (wakealarm_fd == -1) {
+        KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
+        return;
+    }
+
+    if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
+        KLOG_ERROR(LOG_TAG,
+                   "Registration of wakealarm event failed\n");
+
+    wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
+}
+
+static void healthd_mainloop(void) {
+    int nevents = 0;
+    while (1) {
+        struct epoll_event events[eventct];
+        int timeout = awake_poll_interval;
+        int mode_timeout;
+
+        /* Don't wait for first timer timeout to run periodic chores */
+        if (!nevents)
+            periodic_chores();
+
+        healthd_mode_ops->heartbeat();
+
+        mode_timeout = healthd_mode_ops->preparetowait();
+        if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
+            timeout = mode_timeout;
+        nevents = epoll_wait(epollfd, events, eventct, timeout);
+        if (nevents == -1) {
+            if (errno == EINTR)
+                continue;
+            KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
+            break;
+        }
+
+        for (int n = 0; n < nevents; ++n) {
+            if (events[n].data.ptr)
+                (*(void (*)(int))events[n].data.ptr)(events[n].events);
+        }
+    }
+
+    return;
+}
+
+static int healthd_init() {
+    epollfd = epoll_create(MAX_EPOLL_EVENTS);
+    if (epollfd == -1) {
+        KLOG_ERROR(LOG_TAG,
+                   "epoll_create failed; errno=%d\n",
+                   errno);
+        return -1;
+    }
+
+    healthd_board_init(&healthd_config);
+    healthd_mode_ops->init(&healthd_config);
+    wakealarm_init();
+    uevent_init();
+    gBatteryMonitor = new BatteryMonitor();
+    gBatteryMonitor->init(&healthd_config);
+    return 0;
+}
+
+int healthd_main() {
+    int ret;
+
+    klog_set_level(KLOG_LEVEL);
+
+    if (!healthd_mode_ops) {
+        KLOG_ERROR("healthd ops not set, exiting\n");
+        exit(1);
+    }
+
+    ret = healthd_init();
+    if (ret) {
+        KLOG_ERROR("Initialization failed, exiting\n");
+        exit(2);
+    }
+
+    healthd_mainloop();
+    KLOG_ERROR("Main loop terminated, exiting\n");
+    return 3;
+}
diff --git a/healthd/healthd_mode_android.cpp b/healthd/healthd_mode_android.cpp
index 323ef52..c612313 100644
--- a/healthd/healthd_mode_android.cpp
+++ b/healthd/healthd_mode_android.cpp
@@ -42,6 +42,9 @@
     return -1;
 }
 
+void healthd_mode_android_heartbeat(void) {
+}
+
 static void binder_event(uint32_t /*epevents*/) {
     IPCThreadState::self()->handlePolledCommands();
 }
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 91774c6..49a534c 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -39,12 +39,12 @@
 #include <linux/netlink.h>
 
 #include <batteryservice/BatteryService.h>
-#include <cutils/android_reboot.h>
 #include <cutils/klog.h>
 #include <cutils/misc.h>
 #include <cutils/uevent.h>
 #include <cutils/properties.h>
 #include <minui/minui.h>
+#include <sys/reboot.h>
 
 #ifdef CHARGER_ENABLE_SUSPEND
 #include <suspend/autosuspend.h>
@@ -636,7 +636,7 @@
                 } else {
                     if (charger->batt_anim->cur_level >= charger->boot_min_cap) {
                         LOGW("[%" PRId64 "] rebooting\n", now);
-                        android_reboot(ANDROID_RB_RESTART, 0, 0);
+                        reboot(RB_AUTOBOOT);
                     } else {
                         LOGV("[%" PRId64 "] ignore power-button press, battery level "
                             "less than minimum\n", now);
@@ -691,7 +691,7 @@
                  now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
         } else if (now >= charger->next_pwr_check) {
             LOGW("[%" PRId64 "] shutting down\n", now);
-            android_reboot(ANDROID_RB_POWEROFF, 0, 0);
+            reboot(RB_POWER_OFF);
         } else {
             /* otherwise we already have a shutdown timer scheduled */
         }
diff --git a/include/system/graphics-base.h b/include/system/graphics-base.h
new file mode 100644
index 0000000..2aac2d8
--- /dev/null
+++ b/include/system/graphics-base.h
@@ -0,0 +1,139 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+// Source: android.hardware.graphics.common@1.0
+
+#ifndef HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_
+#define HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    HAL_PIXEL_FORMAT_RGBA_8888 = 1,
+    HAL_PIXEL_FORMAT_RGBX_8888 = 2,
+    HAL_PIXEL_FORMAT_RGB_888 = 3,
+    HAL_PIXEL_FORMAT_RGB_565 = 4,
+    HAL_PIXEL_FORMAT_BGRA_8888 = 5,
+    HAL_PIXEL_FORMAT_RGBA_1010102 = 43, // 0x2B
+    HAL_PIXEL_FORMAT_RGBA_FP16 = 22, // 0x16
+    HAL_PIXEL_FORMAT_YV12 = 842094169, // 0x32315659
+    HAL_PIXEL_FORMAT_Y8 = 538982489, // 0x20203859
+    HAL_PIXEL_FORMAT_Y16 = 540422489, // 0x20363159
+    HAL_PIXEL_FORMAT_RAW16 = 32, // 0x20
+    HAL_PIXEL_FORMAT_RAW10 = 37, // 0x25
+    HAL_PIXEL_FORMAT_RAW12 = 38, // 0x26
+    HAL_PIXEL_FORMAT_RAW_OPAQUE = 36, // 0x24
+    HAL_PIXEL_FORMAT_BLOB = 33, // 0x21
+    HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 34, // 0x22
+    HAL_PIXEL_FORMAT_YCBCR_420_888 = 35, // 0x23
+    HAL_PIXEL_FORMAT_YCBCR_422_888 = 39, // 0x27
+    HAL_PIXEL_FORMAT_YCBCR_444_888 = 40, // 0x28
+    HAL_PIXEL_FORMAT_FLEX_RGB_888 = 41, // 0x29
+    HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 42, // 0x2A
+    HAL_PIXEL_FORMAT_YCBCR_422_SP = 16, // 0x10
+    HAL_PIXEL_FORMAT_YCRCB_420_SP = 17, // 0x11
+    HAL_PIXEL_FORMAT_YCBCR_422_I = 20, // 0x14
+    HAL_PIXEL_FORMAT_JPEG = 256, // 0x100
+} android_pixel_format_t;
+
+typedef enum {
+    HAL_TRANSFORM_FLIP_H = 1, // 0x01
+    HAL_TRANSFORM_FLIP_V = 2, // 0x02
+    HAL_TRANSFORM_ROT_90 = 4, // 0x04
+    HAL_TRANSFORM_ROT_180 = 3, // 0x03
+    HAL_TRANSFORM_ROT_270 = 7, // 0x07
+} android_transform_t;
+
+typedef enum {
+    HAL_DATASPACE_UNKNOWN = 0, // 0x0
+    HAL_DATASPACE_ARBITRARY = 1, // 0x1
+    HAL_DATASPACE_STANDARD_SHIFT = 16,
+    HAL_DATASPACE_STANDARD_MASK = 4128768, // (63 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_UNSPECIFIED = 0, // (0 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT709 = 65536, // (1 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT601_625 = 131072, // (2 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 196608, // (3 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT601_525 = 262144, // (4 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 327680, // (5 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT2020 = 393216, // (6 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 458752, // (7 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_BT470M = 524288, // (8 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_FILM = 589824, // (9 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_DCI_P3 = 655360, // (10 << STANDARD_SHIFT)
+    HAL_DATASPACE_STANDARD_ADOBE_RGB = 720896, // (11 << STANDARD_SHIFT)
+    HAL_DATASPACE_TRANSFER_SHIFT = 22,
+    HAL_DATASPACE_TRANSFER_MASK = 130023424, // (31 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0, // (0 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_LINEAR = 4194304, // (1 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_SRGB = 8388608, // (2 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_SMPTE_170M = 12582912, // (3 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_GAMMA2_2 = 16777216, // (4 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_GAMMA2_6 = 20971520, // (5 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_GAMMA2_8 = 25165824, // (6 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_ST2084 = 29360128, // (7 << TRANSFER_SHIFT)
+    HAL_DATASPACE_TRANSFER_HLG = 33554432, // (8 << TRANSFER_SHIFT)
+    HAL_DATASPACE_RANGE_SHIFT = 27,
+    HAL_DATASPACE_RANGE_MASK = 939524096, // (7 << RANGE_SHIFT)
+    HAL_DATASPACE_RANGE_UNSPECIFIED = 0, // (0 << RANGE_SHIFT)
+    HAL_DATASPACE_RANGE_FULL = 134217728, // (1 << RANGE_SHIFT)
+    HAL_DATASPACE_RANGE_LIMITED = 268435456, // (2 << RANGE_SHIFT)
+    HAL_DATASPACE_RANGE_EXTENDED = 402653184, // (3 << RANGE_SHIFT)
+    HAL_DATASPACE_SRGB_LINEAR = 512, // 0x200
+    HAL_DATASPACE_V0_SRGB_LINEAR = 138477568, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_FULL)
+    HAL_DATASPACE_V0_SCRGB_LINEAR = 406913024, // ((STANDARD_BT709 | TRANSFER_LINEAR) | RANGE_EXTENDED)
+    HAL_DATASPACE_SRGB = 513, // 0x201
+    HAL_DATASPACE_V0_SRGB = 142671872, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_FULL)
+    HAL_DATASPACE_V0_SCRGB = 411107328, // ((STANDARD_BT709 | TRANSFER_SRGB) | RANGE_EXTENDED)
+    HAL_DATASPACE_JFIF = 257, // 0x101
+    HAL_DATASPACE_V0_JFIF = 146931712, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_FULL)
+    HAL_DATASPACE_BT601_625 = 258, // 0x102
+    HAL_DATASPACE_V0_BT601_625 = 281149440, // ((STANDARD_BT601_625 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+    HAL_DATASPACE_BT601_525 = 259, // 0x103
+    HAL_DATASPACE_V0_BT601_525 = 281280512, // ((STANDARD_BT601_525 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+    HAL_DATASPACE_BT709 = 260, // 0x104
+    HAL_DATASPACE_V0_BT709 = 281083904, // ((STANDARD_BT709 | TRANSFER_SMPTE_170M) | RANGE_LIMITED)
+    HAL_DATASPACE_DCI_P3_LINEAR = 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL)
+    HAL_DATASPACE_DCI_P3 = 155844608, // ((STANDARD_DCI_P3 | TRANSFER_GAMMA2_6) | RANGE_FULL)
+    HAL_DATASPACE_DISPLAY_P3_LINEAR = 139067392, // ((STANDARD_DCI_P3 | TRANSFER_LINEAR) | RANGE_FULL)
+    HAL_DATASPACE_DISPLAY_P3 = 143261696, // ((STANDARD_DCI_P3 | TRANSFER_SRGB) | RANGE_FULL)
+    HAL_DATASPACE_ADOBE_RGB = 151715840, // ((STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2) | RANGE_FULL)
+    HAL_DATASPACE_BT2020_LINEAR = 138805248, // ((STANDARD_BT2020 | TRANSFER_LINEAR) | RANGE_FULL)
+    HAL_DATASPACE_BT2020 = 147193856, // ((STANDARD_BT2020 | TRANSFER_SMPTE_170M) | RANGE_FULL)
+    HAL_DATASPACE_DEPTH = 4096, // 0x1000
+    HAL_DATASPACE_SENSOR = 4097, // 0x1001
+} android_dataspace_t;
+
+typedef enum {
+    HAL_COLOR_MODE_NATIVE = 0,
+    HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
+    HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
+    HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
+    HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
+    HAL_COLOR_MODE_STANDARD_BT709 = 5,
+    HAL_COLOR_MODE_DCI_P3 = 6,
+    HAL_COLOR_MODE_SRGB = 7,
+    HAL_COLOR_MODE_ADOBE_RGB = 8,
+    HAL_COLOR_MODE_DISPLAY_P3 = 9,
+} android_color_mode_t;
+
+typedef enum {
+    HAL_COLOR_TRANSFORM_IDENTITY = 0,
+    HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
+    HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
+    HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
+    HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
+    HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
+    HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6,
+} android_color_transform_t;
+
+typedef enum {
+    HAL_HDR_DOLBY_VISION = 1,
+    HAL_HDR_HDR10 = 2,
+    HAL_HDR_HLG = 3,
+} android_hdr_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_0_EXPORTED_CONSTANTS_H_
diff --git a/include/system/graphics.h b/include/system/graphics.h
index ae10fa0..1a99187 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -20,10 +20,30 @@
 #include <stddef.h>
 #include <stdint.h>
 
+/*
+ * Some of the enums are now defined in HIDL in hardware/interfaces and are
+ * generated.
+ */
+#include "graphics-base.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/* for compatibility */
+#define HAL_PIXEL_FORMAT_YCbCr_420_888 HAL_PIXEL_FORMAT_YCBCR_420_888
+#define HAL_PIXEL_FORMAT_YCbCr_422_888 HAL_PIXEL_FORMAT_YCBCR_422_888
+#define HAL_PIXEL_FORMAT_YCbCr_444_888 HAL_PIXEL_FORMAT_YCBCR_444_888
+#define HAL_PIXEL_FORMAT_YCbCr_422_SP HAL_PIXEL_FORMAT_YCBCR_422_SP
+#define HAL_PIXEL_FORMAT_YCrCb_420_SP HAL_PIXEL_FORMAT_YCRCB_420_SP
+#define HAL_PIXEL_FORMAT_YCbCr_422_I HAL_PIXEL_FORMAT_YCBCR_422_I
+typedef android_pixel_format_t android_pixel_format;
+typedef android_transform_t android_transform;
+typedef android_dataspace_t android_dataspace;
+typedef android_color_mode_t android_color_mode;
+typedef android_color_transform_t android_color_transform;
+typedef android_hdr_t android_hdr;
+
 /*
  * If the HAL needs to create service threads to handle graphics related
  * tasks, these threads need to run at HAL_PRIORITY_URGENT_DISPLAY priority
@@ -38,411 +58,6 @@
 
 #define HAL_PRIORITY_URGENT_DISPLAY     (-8)
 
-/**
- * pixel format definitions
- */
-
-typedef enum android_pixel_format {
-    /*
-     * "linear" color pixel formats:
-     *
-     * When used with ANativeWindow, the dataSpace field describes the color
-     * space of the buffer.
-     *
-     * The color space determines, for example, if the formats are linear or
-     * gamma-corrected; or whether any special operations are performed when
-     * reading or writing into a buffer in one of these formats.
-     */
-    HAL_PIXEL_FORMAT_RGBA_8888          = 1,
-    HAL_PIXEL_FORMAT_RGBX_8888          = 2,
-    HAL_PIXEL_FORMAT_RGB_888            = 3,
-    HAL_PIXEL_FORMAT_RGB_565            = 4,
-    HAL_PIXEL_FORMAT_BGRA_8888          = 5,
-
-    /*
-     * 0x100 - 0x1FF
-     *
-     * This range is reserved for pixel formats that are specific to the HAL
-     * implementation.  Implementations can use any value in this range to
-     * communicate video pixel formats between their HAL modules.  These formats
-     * must not have an alpha channel.  Additionally, an EGLimage created from a
-     * gralloc buffer of one of these formats must be supported for use with the
-     * GL_OES_EGL_image_external OpenGL ES extension.
-     */
-
-    /*
-     * Android YUV format:
-     *
-     * This format is exposed outside of the HAL to software decoders and
-     * applications.  EGLImageKHR must support it in conjunction with the
-     * OES_EGL_image_external extension.
-     *
-     * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed
-     * by (W/2) x (H/2) Cr and Cb planes.
-     *
-     * This format assumes
-     * - an even width
-     * - an even height
-     * - a horizontal stride multiple of 16 pixels
-     * - a vertical stride equal to the height
-     *
-     *   y_size = stride * height
-     *   c_stride = ALIGN(stride/2, 16)
-     *   c_size = c_stride * height/2
-     *   size = y_size + c_size * 2
-     *   cr_offset = y_size
-     *   cb_offset = y_size + c_size
-     *
-     * When used with ANativeWindow, the dataSpace field describes the color
-     * space of the buffer.
-     */
-    HAL_PIXEL_FORMAT_YV12   = 0x32315659, // YCrCb 4:2:0 Planar
-
-
-    /*
-     * Android Y8 format:
-     *
-     * This format is exposed outside of the HAL to the framework.
-     * The expected gralloc usage flags are SW_* and HW_CAMERA_*,
-     * and no other HW_ flags will be used.
-     *
-     * Y8 is a YUV planar format comprised of a WxH Y plane,
-     * with each pixel being represented by 8 bits.
-     *
-     * It is equivalent to just the Y plane from YV12.
-     *
-     * This format assumes
-     * - an even width
-     * - an even height
-     * - a horizontal stride multiple of 16 pixels
-     * - a vertical stride equal to the height
-     *
-     *   size = stride * height
-     *
-     * When used with ANativeWindow, the dataSpace field describes the color
-     * space of the buffer.
-     */
-    HAL_PIXEL_FORMAT_Y8     = 0x20203859,
-
-    /*
-     * Android Y16 format:
-     *
-     * This format is exposed outside of the HAL to the framework.
-     * The expected gralloc usage flags are SW_* and HW_CAMERA_*,
-     * and no other HW_ flags will be used.
-     *
-     * Y16 is a YUV planar format comprised of a WxH Y plane,
-     * with each pixel being represented by 16 bits.
-     *
-     * It is just like Y8, but has double the bits per pixel (little endian).
-     *
-     * This format assumes
-     * - an even width
-     * - an even height
-     * - a horizontal stride multiple of 16 pixels
-     * - a vertical stride equal to the height
-     * - strides are specified in pixels, not in bytes
-     *
-     *   size = stride * height * 2
-     *
-     * When used with ANativeWindow, the dataSpace field describes the color
-     * space of the buffer, except that dataSpace field
-     * HAL_DATASPACE_DEPTH indicates that this buffer contains a depth
-     * image where each sample is a distance value measured by a depth camera,
-     * plus an associated confidence value.
-     */
-    HAL_PIXEL_FORMAT_Y16    = 0x20363159,
-
-    /*
-     * Android RAW sensor format:
-     *
-     * This format is exposed outside of the camera HAL to applications.
-     *
-     * RAW16 is a single-channel, 16-bit, little endian format, typically
-     * representing raw Bayer-pattern images from an image sensor, with minimal
-     * processing.
-     *
-     * The exact pixel layout of the data in the buffer is sensor-dependent, and
-     * needs to be queried from the camera device.
-     *
-     * Generally, not all 16 bits are used; more common values are 10 or 12
-     * bits. If not all bits are used, the lower-order bits are filled first.
-     * All parameters to interpret the raw data (black and white points,
-     * color space, etc) must be queried from the camera device.
-     *
-     * This format assumes
-     * - an even width
-     * - an even height
-     * - a horizontal stride multiple of 16 pixels
-     * - a vertical stride equal to the height
-     * - strides are specified in pixels, not in bytes
-     *
-     *   size = stride * height * 2
-     *
-     * This format must be accepted by the gralloc module when used with the
-     * following usage flags:
-     *    - GRALLOC_USAGE_HW_CAMERA_*
-     *    - GRALLOC_USAGE_SW_*
-     *    - GRALLOC_USAGE_RENDERSCRIPT
-     *
-     * When used with ANativeWindow, the dataSpace should be
-     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
-     * extra metadata to define.
-     */
-    HAL_PIXEL_FORMAT_RAW16 = 0x20,
-
-    /*
-     * Android RAW10 format:
-     *
-     * This format is exposed outside of the camera HAL to applications.
-     *
-     * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row,
-     * unprocessed format, usually representing raw Bayer-pattern images coming from
-     * an image sensor.
-     *
-     * In an image buffer with this format, starting from the first pixel of each
-     * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one
-     * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte
-     * contains the 2 least significant bits of the 4 pixels, the exact layout data
-     * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth
-     * bit of the ith pixel):
-     *
-     *          bit 7                                     bit 0
-     *          =====|=====|=====|=====|=====|=====|=====|=====|
-     * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]|
-     *         |-----|-----|-----|-----|-----|-----|-----|-----|
-     * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]|
-     *         |-----|-----|-----|-----|-----|-----|-----|-----|
-     * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]|
-     *         |-----|-----|-----|-----|-----|-----|-----|-----|
-     * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]|
-     *         |-----|-----|-----|-----|-----|-----|-----|-----|
-     * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]|
-     *          ===============================================
-     *
-     * This format assumes
-     * - a width multiple of 4 pixels
-     * - an even height
-     * - a vertical stride equal to the height
-     * - strides are specified in bytes, not in pixels
-     *
-     *   size = stride * height
-     *
-     * When stride is equal to width * (10 / 8), there will be no padding bytes at
-     * the end of each row, the entire image data is densely packed. When stride is
-     * larger than width * (10 / 8), padding bytes will be present at the end of each
-     * row (including the last row).
-     *
-     * This format must be accepted by the gralloc module when used with the
-     * following usage flags:
-     *    - GRALLOC_USAGE_HW_CAMERA_*
-     *    - GRALLOC_USAGE_SW_*
-     *    - GRALLOC_USAGE_RENDERSCRIPT
-     *
-     * When used with ANativeWindow, the dataSpace field should be
-     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
-     * extra metadata to define.
-     */
-    HAL_PIXEL_FORMAT_RAW10 = 0x25,
-
-    /*
-     * Android RAW12 format:
-     *
-     * This format is exposed outside of camera HAL to applications.
-     *
-     * RAW12 is a single-channel, 12-bit per pixel, densely packed in each row,
-     * unprocessed format, usually representing raw Bayer-pattern images coming from
-     * an image sensor.
-     *
-     * In an image buffer with this format, starting from the first pixel of each
-     * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first
-     * and second byte contains the top 8 bits of first and second pixel. The third
-     * byte contains the 4 least significant bits of the two pixels, the exact layout
-     * data for each two consecutive pixels is illustrated below (Pi[j] stands for
-     * the jth bit of the ith pixel):
-     *
-     *           bit 7                                            bit 0
-     *          ======|======|======|======|======|======|======|======|
-     * Byte 0: |P0[11]|P0[10]|P0[ 9]|P0[ 8]|P0[ 7]|P0[ 6]|P0[ 5]|P0[ 4]|
-     *         |------|------|------|------|------|------|------|------|
-     * Byte 1: |P1[11]|P1[10]|P1[ 9]|P1[ 8]|P1[ 7]|P1[ 6]|P1[ 5]|P1[ 4]|
-     *         |------|------|------|------|------|------|------|------|
-     * Byte 2: |P1[ 3]|P1[ 2]|P1[ 1]|P1[ 0]|P0[ 3]|P0[ 2]|P0[ 1]|P0[ 0]|
-     *          =======================================================
-     *
-     * This format assumes:
-     * - a width multiple of 4 pixels
-     * - an even height
-     * - a vertical stride equal to the height
-     * - strides are specified in bytes, not in pixels
-     *
-     *   size = stride * height
-     *
-     * When stride is equal to width * (12 / 8), there will be no padding bytes at
-     * the end of each row, the entire image data is densely packed. When stride is
-     * larger than width * (12 / 8), padding bytes will be present at the end of
-     * each row (including the last row).
-     *
-     * This format must be accepted by the gralloc module when used with the
-     * following usage flags:
-     *    - GRALLOC_USAGE_HW_CAMERA_*
-     *    - GRALLOC_USAGE_SW_*
-     *    - GRALLOC_USAGE_RENDERSCRIPT
-     *
-     * When used with ANativeWindow, the dataSpace field should be
-     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
-     * extra metadata to define.
-     */
-    HAL_PIXEL_FORMAT_RAW12 = 0x26,
-
-    /*
-     * Android opaque RAW format:
-     *
-     * This format is exposed outside of the camera HAL to applications.
-     *
-     * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an
-     * image sensor. The actual structure of buffers of this format is
-     * implementation-dependent.
-     *
-     * This format must be accepted by the gralloc module when used with the
-     * following usage flags:
-     *    - GRALLOC_USAGE_HW_CAMERA_*
-     *    - GRALLOC_USAGE_SW_*
-     *    - GRALLOC_USAGE_RENDERSCRIPT
-     *
-     * When used with ANativeWindow, the dataSpace field should be
-     * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial
-     * extra metadata to define.
-     */
-    HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24,
-
-    /*
-     * Android binary blob graphics buffer format:
-     *
-     * This format is used to carry task-specific data which does not have a
-     * standard image structure. The details of the format are left to the two
-     * endpoints.
-     *
-     * A typical use case is for transporting JPEG-compressed images from the
-     * Camera HAL to the framework or to applications.
-     *
-     * Buffers of this format must have a height of 1, and width equal to their
-     * size in bytes.
-     *
-     * When used with ANativeWindow, the mapping of the dataSpace field to
-     * buffer contents for BLOB is as follows:
-     *
-     *  dataSpace value               | Buffer contents
-     * -------------------------------+-----------------------------------------
-     *  HAL_DATASPACE_JFIF            | An encoded JPEG image
-     *  HAL_DATASPACE_DEPTH           | An android_depth_points buffer
-     *  Other                         | Unsupported
-     *
-     */
-    HAL_PIXEL_FORMAT_BLOB = 0x21,
-
-    /*
-     * Android format indicating that the choice of format is entirely up to the
-     * device-specific Gralloc implementation.
-     *
-     * The Gralloc implementation should examine the usage bits passed in when
-     * allocating a buffer with this format, and it should derive the pixel
-     * format from those usage flags.  This format will never be used with any
-     * of the GRALLOC_USAGE_SW_* usage flags.
-     *
-     * If a buffer of this format is to be used as an OpenGL ES texture, the
-     * framework will assume that sampling the texture will always return an
-     * alpha value of 1.0 (i.e. the buffer contains only opaque pixel values).
-     *
-     * When used with ANativeWindow, the dataSpace field describes the color
-     * space of the buffer.
-     */
-    HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22,
-
-    /*
-     * Android flexible YCbCr 4:2:0 formats
-     *
-     * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:0
-     * buffer layout, while still describing the general format in a
-     * layout-independent manner.  While called YCbCr, it can be
-     * used to describe formats with either chromatic ordering, as well as
-     * whole planar or semiplanar layouts.
-     *
-     * struct android_ycbcr (below) is the the struct used to describe it.
-     *
-     * This format must be accepted by the gralloc module when
-     * USAGE_SW_WRITE_* or USAGE_SW_READ_* are set.
-     *
-     * This format is locked for use by gralloc's (*lock_ycbcr) method, and
-     * locking with the (*lock) method will return an error.
-     *
-     * When used with ANativeWindow, the dataSpace field describes the color
-     * space of the buffer.
-     */
-    HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23,
-
-    /*
-     * Android flexible YCbCr 4:2:2 formats
-     *
-     * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:2
-     * buffer layout, while still describing the general format in a
-     * layout-independent manner.  While called YCbCr, it can be
-     * used to describe formats with either chromatic ordering, as well as
-     * whole planar or semiplanar layouts.
-     *
-     * This format is currently only used by SW readable buffers
-     * produced by MediaCodecs, so the gralloc module can ignore this format.
-     */
-    HAL_PIXEL_FORMAT_YCbCr_422_888 = 0x27,
-
-    /*
-     * Android flexible YCbCr 4:4:4 formats
-     *
-     * This format allows platforms to use an efficient YCbCr/YCrCb 4:4:4
-     * buffer layout, while still describing the general format in a
-     * layout-independent manner.  While called YCbCr, it can be
-     * used to describe formats with either chromatic ordering, as well as
-     * whole planar or semiplanar layouts.
-     *
-     * This format is currently only used by SW readable buffers
-     * produced by MediaCodecs, so the gralloc module can ignore this format.
-     */
-    HAL_PIXEL_FORMAT_YCbCr_444_888 = 0x28,
-
-    /*
-     * Android flexible RGB 888 formats
-     *
-     * This format allows platforms to use an efficient RGB/BGR/RGBX/BGRX
-     * buffer layout, while still describing the general format in a
-     * layout-independent manner.  While called RGB, it can be
-     * used to describe formats with either color ordering and optional
-     * padding, as well as whole planar layout.
-     *
-     * This format is currently only used by SW readable buffers
-     * produced by MediaCodecs, so the gralloc module can ignore this format.
-     */
-    HAL_PIXEL_FORMAT_FLEX_RGB_888 = 0x29,
-
-    /*
-     * Android flexible RGBA 8888 formats
-     *
-     * This format allows platforms to use an efficient RGBA/BGRA/ARGB/ABGR
-     * buffer layout, while still describing the general format in a
-     * layout-independent manner.  While called RGBA, it can be
-     * used to describe formats with any of the component orderings, as
-     * well as whole planar layout.
-     *
-     * This format is currently only used by SW readable buffers
-     * produced by MediaCodecs, so the gralloc module can ignore this format.
-     */
-    HAL_PIXEL_FORMAT_FLEX_RGBA_8888 = 0x2A,
-
-    /* Legacy formats (deprecated), used by ImageFormat.java */
-    HAL_PIXEL_FORMAT_YCbCr_422_SP       = 0x10, // NV16
-    HAL_PIXEL_FORMAT_YCrCb_420_SP       = 0x11, // NV21
-    HAL_PIXEL_FORMAT_YCbCr_422_I        = 0x14, // YUY2
-} android_pixel_format_t;
-
 /*
  * Structure for describing YCbCr formats for consumption by applications.
  * This is used with HAL_PIXEL_FORMAT_YCbCr_*_888.
@@ -623,795 +238,24 @@
 };
 
 /**
- * Transformation definitions
- *
- * IMPORTANT NOTE:
- * HAL_TRANSFORM_ROT_90 is applied CLOCKWISE and AFTER HAL_TRANSFORM_FLIP_{H|V}.
- *
- */
+  * These structures are used to define the reference display's
+  * capabilities for HDR content. Display engine can use this
+  * to better tone map content to user's display.
+  * Color is defined in CIE XYZ coordinates
+  */
+struct android_xy_color {
+    float x;
+    float y;
+};
 
-typedef enum android_transform {
-    /* flip source image horizontally (around the vertical axis) */
-    HAL_TRANSFORM_FLIP_H    = 0x01,
-    /* flip source image vertically (around the horizontal axis)*/
-    HAL_TRANSFORM_FLIP_V    = 0x02,
-    /* rotate source image 90 degrees clockwise */
-    HAL_TRANSFORM_ROT_90    = 0x04,
-    /* rotate source image 180 degrees */
-    HAL_TRANSFORM_ROT_180   = 0x03,
-    /* rotate source image 270 degrees clockwise */
-    HAL_TRANSFORM_ROT_270   = 0x07,
-    /* don't use. see system/window.h */
-    HAL_TRANSFORM_RESERVED  = 0x08,
-} android_transform_t;
-
-/**
- * Dataspace Definitions
- * ======================
- *
- * Dataspace is the definition of how pixel values should be interpreted.
- *
- * For many formats, this is the colorspace of the image data, which includes
- * primaries (including white point) and the transfer characteristic function,
- * which describes both gamma curve and numeric range (within the bit depth).
- *
- * Other dataspaces include depth measurement data from a depth camera.
- *
- * A dataspace is comprised of a number of fields.
- *
- * Version
- * --------
- * The top 2 bits represent the revision of the field specification. This is
- * currently always 0.
- *
- *
- * bits    31-30 29                      -                          0
- *        +-----+----------------------------------------------------+
- * fields | Rev |            Revision specific fields                |
- *        +-----+----------------------------------------------------+
- *
- * Field layout for version = 0:
- * ----------------------------
- *
- * A dataspace is comprised of the following fields:
- *      Standard
- *      Transfer function
- *      Range
- *
- * bits    31-30 29-27 26 -  22 21 -  16 15             -           0
- *        +-----+-----+--------+--------+----------------------------+
- * fields |  0  |Range|Transfer|Standard|    Legacy and custom       |
- *        +-----+-----+--------+--------+----------------------------+
- *          VV    RRR   TTTTT    SSSSSS    LLLLLLLL       LLLLLLLL
- *
- * If range, transfer and standard fields are all 0 (e.g. top 16 bits are
- * all zeroes), the bottom 16 bits contain either a legacy dataspace value,
- * or a custom value.
- */
-
-typedef enum android_dataspace {
-    /*
-     * Default-assumption data space, when not explicitly specified.
-     *
-     * It is safest to assume the buffer is an image with sRGB primaries and
-     * encoding ranges, but the consumer and/or the producer of the data may
-     * simply be using defaults. No automatic gamma transform should be
-     * expected, except for a possible display gamma transform when drawn to a
-     * screen.
-     */
-    HAL_DATASPACE_UNKNOWN = 0x0,
-
-    /*
-     * Arbitrary dataspace with manually defined characteristics.  Definition
-     * for colorspaces or other meaning must be communicated separately.
-     *
-     * This is used when specifying primaries, transfer characteristics,
-     * etc. separately.
-     *
-     * A typical use case is in video encoding parameters (e.g. for H.264),
-     * where a colorspace can have separately defined primaries, transfer
-     * characteristics, etc.
-     */
-    HAL_DATASPACE_ARBITRARY = 0x1,
-
-    /*
-     * Color-description aspects
-     *
-     * The following aspects define various characteristics of the color
-     * specification. These represent bitfields, so that a data space value
-     * can specify each of them independently.
-     */
-
-    HAL_DATASPACE_STANDARD_SHIFT = 16,
-
-    /*
-     * Standard aspect
-     *
-     * Defines the chromaticity coordinates of the source primaries in terms of
-     * the CIE 1931 definition of x and y specified in ISO 11664-1.
-     */
-    HAL_DATASPACE_STANDARD_MASK = 63 << HAL_DATASPACE_STANDARD_SHIFT,  // 0x3F
-
-    /*
-     * Chromacity coordinates are unknown or are determined by the application.
-     * Implementations shall use the following suggested standards:
-     *
-     * All YCbCr formats: BT709 if size is 720p or larger (since most video
-     *                    content is letterboxed this corresponds to width is
-     *                    1280 or greater, or height is 720 or greater).
-     *                    BT601_625 if size is smaller than 720p or is JPEG.
-     * All RGB formats:   BT709.
-     *
-     * For all other formats standard is undefined, and implementations should use
-     * an appropriate standard for the data represented.
-     */
-    HAL_DATASPACE_STANDARD_UNSPECIFIED = 0 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.300   0.600
-     *  blue            0.150   0.060
-     *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
-     *
-     * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
-     * for RGB conversion.
-     */
-    HAL_DATASPACE_STANDARD_BT709 = 1 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.290   0.600
-     *  blue            0.150   0.060
-     *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
-     *
-     *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
-     *  for RGB conversion from the one purely determined by the primaries
-     *  to minimize the color shift into RGB space that uses BT.709
-     *  primaries.
-     */
-    HAL_DATASPACE_STANDARD_BT601_625 = 2 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.290   0.600
-     *  blue            0.150   0.060
-     *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
-     *
-     * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
-     * for RGB conversion.
-     */
-    HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED = 3 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.310   0.595
-     *  blue            0.155   0.070
-     *  red             0.630   0.340
-     *  white (D65)     0.3127  0.3290
-     *
-     *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
-     *  for RGB conversion from the one purely determined by the primaries
-     *  to minimize the color shift into RGB space that uses BT.709
-     *  primaries.
-     */
-    HAL_DATASPACE_STANDARD_BT601_525 = 4 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.310   0.595
-     *  blue            0.155   0.070
-     *  red             0.630   0.340
-     *  white (D65)     0.3127  0.3290
-     *
-     * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
-     * for RGB conversion (as in SMPTE 240M).
-     */
-    HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED = 5 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.170   0.797
-     *  blue            0.131   0.046
-     *  red             0.708   0.292
-     *  white (D65)     0.3127  0.3290
-     *
-     * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
-     * for RGB conversion.
-     */
-    HAL_DATASPACE_STANDARD_BT2020 = 6 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.170   0.797
-     *  blue            0.131   0.046
-     *  red             0.708   0.292
-     *  white (D65)     0.3127  0.3290
-     *
-     * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
-     * for RGB conversion using the linear domain.
-     */
-    HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x      y
-     *  green           0.21   0.71
-     *  blue            0.14   0.08
-     *  red             0.67   0.33
-     *  white (C)       0.310  0.316
-     *
-     * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
-     * for RGB conversion.
-     */
-    HAL_DATASPACE_STANDARD_BT470M = 8 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    /*
-     * Primaries:       x       y
-     *  green           0.243   0.692
-     *  blue            0.145   0.049
-     *  red             0.681   0.319
-     *  white (C)       0.310   0.316
-     *
-     * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
-     * for RGB conversion.
-     */
-    HAL_DATASPACE_STANDARD_FILM = 9 << HAL_DATASPACE_STANDARD_SHIFT,
-
-    HAL_DATASPACE_TRANSFER_SHIFT = 22,
-
-    /*
-     * Transfer aspect
-     *
-     * Transfer characteristics are the opto-electronic transfer characteristic
-     * at the source as a function of linear optical intensity (luminance).
-     *
-     * For digital signals, E corresponds to the recorded value. Normally, the
-     * transfer function is applied in RGB space to each of the R, G and B
-     * components independently. This may result in color shift that can be
-     * minized by applying the transfer function in Lab space only for the L
-     * component. Implementation may apply the transfer function in RGB space
-     * for all pixel formats if desired.
-     */
-
-    HAL_DATASPACE_TRANSFER_MASK = 31 << HAL_DATASPACE_TRANSFER_SHIFT,  // 0x1F
-
-    /*
-     * Transfer characteristics are unknown or are determined by the
-     * application.
-     *
-     * Implementations should use the following transfer functions:
-     *
-     * For YCbCr formats: use HAL_DATASPACE_TRANSFER_SMPTE_170M
-     * For RGB formats: use HAL_DATASPACE_TRANSFER_SRGB
-     *
-     * For all other formats transfer function is undefined, and implementations
-     * should use an appropriate standard for the data represented.
-     */
-    HAL_DATASPACE_TRANSFER_UNSPECIFIED = 0 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     * Transfer characteristic curve:
-     *  E = L
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_LINEAR = 1 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     * Transfer characteristic curve:
-     *
-     * E = 1.055 * L^(1/2.4) - 0.055  for 0.0031308 <= L <= 1
-     *   = 12.92 * L                  for 0 <= L < 0.0031308
-     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *     E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_SRGB = 2 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     * BT.601 525, BT.601 625, BT.709, BT.2020
-     *
-     * Transfer characteristic curve:
-     *  E = 1.099 * L ^ 0.45 - 0.099  for 0.018 <= L <= 1
-     *    = 4.500 * L                 for 0 <= L < 0.018
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_SMPTE_170M = 3 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     * Assumed display gamma 2.2.
-     *
-     * Transfer characteristic curve:
-     *  E = L ^ (1/2.2)
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_GAMMA2_2 = 4 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     *  display gamma 2.8.
-     *
-     * Transfer characteristic curve:
-     *  E = L ^ (1/2.8)
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_GAMMA2_8 = 5 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     * SMPTE ST 2084
-     *
-     * Transfer characteristic curve:
-     *  E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
-     *  c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
-     *  c2 = 32 * 2413 / 4096 = 18.8515625
-     *  c3 = 32 * 2392 / 4096 = 18.6875
-     *  m = 128 * 2523 / 4096 = 78.84375
-     *  n = 0.25 * 2610 / 4096 = 0.1593017578125
-     *      L - luminance of image 0 <= L <= 1 for HDR colorimetry.
-     *          L = 1 corresponds to 10000 cd/m2
-     *      E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_ST2084 = 6 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    /*
-     * ARIB STD-B67 Hybrid Log Gamma
-     *
-     * Transfer characteristic curve:
-     *  E = r * L^0.5                 for 0 <= L <= 1
-     *    = a * ln(L - b) + c         for 1 < L
-     *  a = 0.17883277
-     *  b = 0.28466892
-     *  c = 0.55991073
-     *  r = 0.5
-     *      L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
-     *          to reference white level of 100 cd/m2
-     *      E - corresponding electrical signal
-     */
-    HAL_DATASPACE_TRANSFER_HLG = 7 << HAL_DATASPACE_TRANSFER_SHIFT,
-
-    HAL_DATASPACE_RANGE_SHIFT = 27,
-
-    /*
-     * Range aspect
-     *
-     * Defines the range of values corresponding to the unit range of 0-1.
-     * This is defined for YCbCr only, but can be expanded to RGB space.
-     */
-    HAL_DATASPACE_RANGE_MASK = 7 << HAL_DATASPACE_RANGE_SHIFT,  // 0x7
-
-    /*
-     * Range is unknown or are determined by the application.  Implementations
-     * shall use the following suggested ranges:
-     *
-     * All YCbCr formats: limited range.
-     * All RGB or RGBA formats (including RAW and Bayer): full range.
-     * All Y formats: full range
-     *
-     * For all other formats range is undefined, and implementations should use
-     * an appropriate range for the data represented.
-     */
-    HAL_DATASPACE_RANGE_UNSPECIFIED = 0 << HAL_DATASPACE_RANGE_SHIFT,
-
-    /*
-     * Full range uses all values for Y, Cb and Cr from
-     * 0 to 2^b-1, where b is the bit depth of the color format.
-     */
-    HAL_DATASPACE_RANGE_FULL = 1 << HAL_DATASPACE_RANGE_SHIFT,
-
-    /*
-     * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
-     * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of
-     * the color format.
-     *
-     * E.g. For 8-bit-depth formats:
-     * Luma (Y) samples should range from 16 to 235, inclusive
-     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
-     *
-     * For 10-bit-depth formats:
-     * Luma (Y) samples should range from 64 to 940, inclusive
-     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
-     */
-    HAL_DATASPACE_RANGE_LIMITED = 2 << HAL_DATASPACE_RANGE_SHIFT,
-
-    /*
-     * Legacy dataspaces
-     */
-
-    /*
-     * sRGB linear encoding:
-     *
-     * The red, green, and blue components are stored in sRGB space, but
-     * are linear, not gamma-encoded.
-     * The RGB primaries and the white point are the same as BT.709.
-     *
-     * The values are encoded using the full range ([0,255] for 8-bit) for all
-     * components.
-     */
-    HAL_DATASPACE_SRGB_LINEAR = 0x200, // deprecated, use HAL_DATASPACE_V0_SRGB_LINEAR
-
-    HAL_DATASPACE_V0_SRGB_LINEAR = HAL_DATASPACE_STANDARD_BT709 |
-            HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL,
-
-
-    /*
-     * sRGB gamma encoding:
-     *
-     * The red, green and blue components are stored in sRGB space, and
-     * converted to linear space when read, using the SRGB transfer function
-     * for each of the R, G and B components. When written, the inverse
-     * transformation is performed.
-     *
-     * The alpha component, if present, is always stored in linear space and
-     * is left unmodified when read or written.
-     *
-     * Use full range and BT.709 standard.
-     */
-    HAL_DATASPACE_SRGB = 0x201, // deprecated, use HAL_DATASPACE_V0_SRGB
-
-    HAL_DATASPACE_V0_SRGB = HAL_DATASPACE_STANDARD_BT709 |
-            HAL_DATASPACE_TRANSFER_SRGB | HAL_DATASPACE_RANGE_FULL,
-
-
-    /*
-     * YCbCr Colorspaces
-     * -----------------
-     *
-     * Primaries are given using (x,y) coordinates in the CIE 1931 definition
-     * of x and y specified by ISO 11664-1.
-     *
-     * Transfer characteristics are the opto-electronic transfer characteristic
-     * at the source as a function of linear optical intensity (luminance).
-     */
-
-    /*
-     * JPEG File Interchange Format (JFIF)
-     *
-     * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
-     *
-     * Use full range, BT.601 transfer and BT.601_625 standard.
-     */
-    HAL_DATASPACE_JFIF = 0x101, // deprecated, use HAL_DATASPACE_V0_JFIF
-
-    HAL_DATASPACE_V0_JFIF = HAL_DATASPACE_STANDARD_BT601_625 |
-            HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_FULL,
-
-    /*
-     * ITU-R Recommendation 601 (BT.601) - 625-line
-     *
-     * Standard-definition television, 625 Lines (PAL)
-     *
-     * Use limited range, BT.601 transfer and BT.601_625 standard.
-     */
-    HAL_DATASPACE_BT601_625 = 0x102, // deprecated, use HAL_DATASPACE_V0_BT601_625
-
-    HAL_DATASPACE_V0_BT601_625 = HAL_DATASPACE_STANDARD_BT601_625 |
-            HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
-
-
-    /*
-     * ITU-R Recommendation 601 (BT.601) - 525-line
-     *
-     * Standard-definition television, 525 Lines (NTSC)
-     *
-     * Use limited range, BT.601 transfer and BT.601_525 standard.
-     */
-    HAL_DATASPACE_BT601_525 = 0x103, // deprecated, use HAL_DATASPACE_V0_BT601_525
-
-    HAL_DATASPACE_V0_BT601_525 = HAL_DATASPACE_STANDARD_BT601_525 |
-            HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
-
-    /*
-     * ITU-R Recommendation 709 (BT.709)
-     *
-     * High-definition television
-     *
-     * Use limited range, BT.709 transfer and BT.709 standard.
-     */
-    HAL_DATASPACE_BT709 = 0x104, // deprecated, use HAL_DATASPACE_V0_BT709
-
-    HAL_DATASPACE_V0_BT709 = HAL_DATASPACE_STANDARD_BT709 |
-            HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_LIMITED,
-
-    /*
-     * Data spaces for non-color formats
-     */
-
-    /*
-     * The buffer contains depth ranging measurements from a depth camera.
-     * This value is valid with formats:
-     *    HAL_PIXEL_FORMAT_Y16: 16-bit samples, consisting of a depth measurement
-     *       and an associated confidence value. The 3 MSBs of the sample make
-     *       up the confidence value, and the low 13 LSBs of the sample make up
-     *       the depth measurement.
-     *       For the confidence section, 0 means 100% confidence, 1 means 0%
-     *       confidence. The mapping to a linear float confidence value between
-     *       0.f and 1.f can be obtained with
-     *         float confidence = (((depthSample >> 13) - 1) & 0x7) / 7.0f;
-     *       The depth measurement can be extracted simply with
-     *         uint16_t range = (depthSample & 0x1FFF);
-     *    HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as
-     *       a variable-length float (x,y,z, confidence) coordinate point list.
-     *       The point cloud will be represented with the android_depth_points
-     *       structure.
-     */
-    HAL_DATASPACE_DEPTH = 0x1000
-
-} android_dataspace_t;
-
-/*
- * Color modes that may be supported by a display.
- *
- * Definitions:
- * Rendering intent generally defines the goal in mapping a source (input)
- * color to a destination device color for a given color mode.
- *
- *  It is important to keep in mind three cases where mapping may be applied:
- *  1. The source gamut is much smaller than the destination (display) gamut
- *  2. The source gamut is much larger than the destination gamut (this will
- *  ordinarily be handled using colorimetric rendering, below)
- *  3. The source and destination gamuts are roughly equal, although not
- *  completely overlapping
- *  Also, a common requirement for mappings is that skin tones should be
- *  preserved, or at least remain natural in appearance.
- *
- *  Colorimetric Rendering Intent (All cases):
- *  Colorimetric indicates that colors should be preserved. In the case
- *  that the source gamut lies wholly within the destination gamut or is
- *  about the same (#1, #3), this will simply mean that no manipulations
- *  (no saturation boost, for example) are applied. In the case where some
- *  source colors lie outside the destination gamut (#2, #3), those will
- *  need to be mapped to colors that are within the destination gamut,
- *  while the already in-gamut colors remain unchanged.
- *
- *  Non-colorimetric transforms can take many forms. There are no hard
- *  rules and it's left to the implementation to define.
- *  Two common intents are described below.
- *
- *  Stretched-Gamut Enhancement Intent (Source < Destination):
- *  When the destination gamut is much larger than the source gamut (#1), the
- *  source primaries may be redefined to reflect the full extent of the
- *  destination space, or to reflect an intermediate gamut.
- *  Skin-tone preservation would likely be applied. An example might be sRGB
- *  input displayed on a DCI-P3 capable device, with skin-tone preservation.
- *
- *  Within-Gamut Enhancement Intent (Source >= Destination):
- *  When the device (destination) gamut is not larger than the source gamut
- *  (#2 or #3), but the appearance of a larger gamut is desired, techniques
- *  such as saturation boost may be applied to the source colors. Skin-tone
- *  preservation may be applied. There is no unique method for within-gamut
- *  enhancement; it would be defined within a flexible color mode.
- *
- */
-typedef enum android_color_mode {
-
-  /*
-   * HAL_COLOR_MODE_DEFAULT is the "native" gamut of the display.
-   * White Point: Vendor/OEM defined
-   * Panel Gamma: Vendor/OEM defined (typically 2.2)
-   * Rendering Intent: Vendor/OEM defined (typically 'enhanced')
-   */
-  HAL_COLOR_MODE_NATIVE = 0,
-
-  /*
-   * HAL_COLOR_MODE_STANDARD_BT601_625 corresponds with display
-   * settings that implement the ITU-R Recommendation BT.601
-   * or Rec 601. Using 625 line version
-   * Rendering Intent: Colorimetric
-   * Primaries:
-   *                  x       y
-   *  green           0.290   0.600
-   *  blue            0.150   0.060
-   *  red             0.640   0.330
-   *  white (D65)     0.3127  0.3290
-   *
-   *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
-   *  for RGB conversion from the one purely determined by the primaries
-   *  to minimize the color shift into RGB space that uses BT.709
-   *  primaries.
-   *
-   * Gamma Correction (GC):
-   *
-   *  if Vlinear < 0.018
-   *    Vnonlinear = 4.500 * Vlinear
-   *  else
-   *    Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
-   */
-  HAL_COLOR_MODE_STANDARD_BT601_625 = 1,
-
-  /*
-   * Primaries:
-   *                  x       y
-   *  green           0.290   0.600
-   *  blue            0.150   0.060
-   *  red             0.640   0.330
-   *  white (D65)     0.3127  0.3290
-   *
-   *  Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
-   *  for RGB conversion.
-   *
-   * Gamma Correction (GC):
-   *
-   *  if Vlinear < 0.018
-   *    Vnonlinear = 4.500 * Vlinear
-   *  else
-   *    Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
-   */
-  HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED = 2,
-
-  /*
-   * Primaries:
-   *                  x       y
-   *  green           0.310   0.595
-   *  blue            0.155   0.070
-   *  red             0.630   0.340
-   *  white (D65)     0.3127  0.3290
-   *
-   *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
-   *  for RGB conversion from the one purely determined by the primaries
-   *  to minimize the color shift into RGB space that uses BT.709
-   *  primaries.
-   *
-   * Gamma Correction (GC):
-   *
-   *  if Vlinear < 0.018
-   *    Vnonlinear = 4.500 * Vlinear
-   *  else
-   *    Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
-   */
-  HAL_COLOR_MODE_STANDARD_BT601_525 = 3,
-
-  /*
-   * Primaries:
-   *                  x       y
-   *  green           0.310   0.595
-   *  blue            0.155   0.070
-   *  red             0.630   0.340
-   *  white (D65)     0.3127  0.3290
-   *
-   *  Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
-   *  for RGB conversion (as in SMPTE 240M).
-   *
-   * Gamma Correction (GC):
-   *
-   *  if Vlinear < 0.018
-   *    Vnonlinear = 4.500 * Vlinear
-   *  else
-   *    Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099
-   */
-  HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED = 4,
-
-  /*
-   * HAL_COLOR_MODE_REC709 corresponds with display settings that implement
-   * the ITU-R Recommendation BT.709 / Rec. 709 for high-definition television.
-   * Rendering Intent: Colorimetric
-   * Primaries:
-   *                  x       y
-   *  green           0.300   0.600
-   *  blue            0.150   0.060
-   *  red             0.640   0.330
-   *  white (D65)     0.3127  0.3290
-   *
-   * HDTV REC709 Inverse Gamma Correction (IGC): V represents normalized
-   * (with [0 to 1] range) value of R, G, or B.
-   *
-   *  if Vnonlinear < 0.081
-   *    Vlinear = Vnonlinear / 4.5
-   *  else
-   *    Vlinear = ((Vnonlinear + 0.099) / 1.099) ^ (1/0.45)
-   *
-   * HDTV REC709 Gamma Correction (GC):
-   *
-   *  if Vlinear < 0.018
-   *    Vnonlinear = 4.5 * Vlinear
-   *  else
-   *    Vnonlinear = 1.099 * (Vlinear) ^ 0.45 – 0.099
-   */
-  HAL_COLOR_MODE_STANDARD_BT709 = 5,
-
-  /*
-   * HAL_COLOR_MODE_DCI_P3 corresponds with display settings that implement
-   * SMPTE EG 432-1 and SMPTE RP 431-2
-   * Rendering Intent: Colorimetric
-   * Primaries:
-   *                  x       y
-   *  green           0.265   0.690
-   *  blue            0.150   0.060
-   *  red             0.680   0.320
-   *  white (D65)     0.3127  0.3290
-   *
-   * Gamma: 2.2
-   */
-  HAL_COLOR_MODE_DCI_P3 = 6,
-
-  /*
-   * HAL_COLOR_MODE_SRGB corresponds with display settings that implement
-   * the sRGB color space. Uses the same primaries as ITU-R Recommendation
-   * BT.709
-   * Rendering Intent: Colorimetric
-   * Primaries:
-   *                  x       y
-   *  green           0.300   0.600
-   *  blue            0.150   0.060
-   *  red             0.640   0.330
-   *  white (D65)     0.3127  0.3290
-   *
-   * PC/Internet (sRGB) Inverse Gamma Correction (IGC):
-   *
-   *  if Vnonlinear ≤ 0.03928
-   *    Vlinear = Vnonlinear / 12.92
-   *  else
-   *    Vlinear = ((Vnonlinear + 0.055)/1.055) ^ 2.4
-   *
-   * PC/Internet (sRGB) Gamma Correction (GC):
-   *
-   *  if Vlinear ≤ 0.0031308
-   *    Vnonlinear = 12.92 * Vlinear
-   *  else
-   *    Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055
-   */
-  HAL_COLOR_MODE_SRGB = 7,
-
-  /*
-   * HAL_COLOR_MODE_ADOBE_RGB corresponds with the RGB color space developed
-   * by Adobe Systems, Inc. in 1998.
-   * Rendering Intent: Colorimetric
-   * Primaries:
-   *                  x       y
-   *  green           0.210   0.710
-   *  blue            0.150   0.060
-   *  red             0.640   0.330
-   *  white (D65)     0.3127  0.3290
-   *
-   * Gamma: 2.2
-   */
-  HAL_COLOR_MODE_ADOBE_RGB = 8
-
-} android_color_mode_t;
-
-/*
- * Color transforms that may be applied by hardware composer to the whole
- * display.
- */
-typedef enum android_color_transform {
-    /* Applies no transform to the output color */
-    HAL_COLOR_TRANSFORM_IDENTITY = 0,
-
-    /* Applies an arbitrary transform defined by a 4x4 affine matrix */
-    HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX = 1,
-
-    /* Applies a transform that inverts the value or luminance of the color, but
-     * does not modify hue or saturation */
-    HAL_COLOR_TRANSFORM_VALUE_INVERSE = 2,
-
-    /* Applies a transform that maps all colors to shades of gray */
-    HAL_COLOR_TRANSFORM_GRAYSCALE = 3,
-
-    /* Applies a transform which corrects for protanopic color blindness */
-    HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA = 4,
-
-    /* Applies a transform which corrects for deuteranopic color blindness */
-    HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA = 5,
-
-    /* Applies a transform which corrects for tritanopic color blindness */
-    HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA = 6
-} android_color_transform_t;
-
-/*
- * Supported HDR formats. Must be kept in sync with equivalents in Display.java.
- */
-typedef enum android_hdr {
-    /* Device supports Dolby Vision HDR */
-    HAL_HDR_DOLBY_VISION = 1,
-
-    /* Device supports HDR10 */
-    HAL_HDR_HDR10 = 2,
-
-    /* Device supports hybrid log-gamma HDR */
-    HAL_HDR_HLG = 3
-} android_hdr_t;
+struct android_smpte2086_metadata {
+    struct android_xy_color displayPrimaryRed;
+    struct android_xy_color displayPrimaryGreen;
+    struct android_xy_color displayPrimaryBlue;
+    struct android_xy_color whitePoint;
+    float maxLuminance;
+    float minLuminance;
+};
 
 #ifdef __cplusplus
 }
diff --git a/include/system/radio.h b/include/system/radio.h
index 03b252e..acf3ea7 100644
--- a/include/system/radio.h
+++ b/include/system/radio.h
@@ -81,7 +81,7 @@
 } radio_direction_t;
 
 /* unique handle allocated to a radio module */
-typedef unsigned int radio_handle_t;
+typedef uint32_t radio_handle_t;
 
 /* Opaque meta data structure used by radio meta data API (see system/radio_metadata.h) */
 typedef struct radio_metadata radio_metadata_t;
@@ -109,10 +109,10 @@
 typedef struct radio_hal_band_config {
     radio_band_t type;
     bool         antenna_connected;
-    unsigned int lower_limit;
-    unsigned int upper_limit;
-    unsigned int num_spacings;
-    unsigned int spacings[RADIO_NUM_SPACINGS_MAX];
+    uint32_t     lower_limit;
+    uint32_t     upper_limit;
+    uint32_t     num_spacings;
+    uint32_t     spacings[RADIO_NUM_SPACINGS_MAX];
     union {
         radio_hal_fm_band_config_t fm;
         radio_hal_am_band_config_t am;
@@ -137,10 +137,10 @@
     char            product[RADIO_STRING_LEN_MAX];  /* product name */
     char            version[RADIO_STRING_LEN_MAX];  /* product version */
     char            serial[RADIO_STRING_LEN_MAX];  /* serial number (for subscription services) */
-    unsigned int    num_tuners;     /* number of tuners controllable independently */
-    unsigned int    num_audio_sources; /* number of audio sources driven simultaneously */
+    uint32_t        num_tuners;     /* number of tuners controllable independently */
+    uint32_t        num_audio_sources; /* number of audio sources driven simultaneously */
     bool            supports_capture; /* the hardware supports capture of audio source audio HAL */
-    unsigned int    num_bands;      /* number of band descriptors */
+    uint32_t        num_bands;      /* number of band descriptors */
     radio_hal_band_config_t bands[RADIO_NUM_BANDS_MAX]; /* band descriptors */
 } radio_hal_properties_t;
 
@@ -153,10 +153,10 @@
     char                product[RADIO_STRING_LEN_MAX];
     char                version[RADIO_STRING_LEN_MAX];
     char                serial[RADIO_STRING_LEN_MAX];
-    unsigned int        num_tuners;
-    unsigned int        num_audio_sources;
+    uint32_t            num_tuners;
+    uint32_t            num_audio_sources;
     bool                supports_capture;
-    unsigned int        num_bands;
+    uint32_t            num_bands;
     radio_band_config_t bands[RADIO_NUM_BANDS_MAX];
 } radio_properties_t;
 
@@ -164,12 +164,12 @@
  * Contains information on currently tuned channel.
  */
 typedef struct radio_program_info {
-    unsigned int     channel;   /* current channel. (e.g kHz for band type RADIO_BAND_FM) */
-    unsigned int     sub_channel; /* current sub channel. (used for RADIO_BAND_FM_HD) */
+    uint32_t         channel;   /* current channel. (e.g kHz for band type RADIO_BAND_FM) */
+    uint32_t         sub_channel; /* current sub channel. (used for RADIO_BAND_FM_HD) */
     bool             tuned;     /* tuned to a program or not */
     bool             stereo;    /* program is stereo or not */
     bool             digital;   /* digital program or not (e.g HD Radio program) */
-    unsigned int     signal_strength; /* signal strength from 0 to 100 */
+    uint32_t         signal_strength; /* signal strength from 0 to 100 */
                                 /* meta data (e.g PTY, song title ...), must not be NULL */
     __attribute__((aligned(8))) radio_metadata_t *metadata;
 } radio_program_info_t;
@@ -196,7 +196,7 @@
 /* Event passed to the framework by the HAL callback */
 typedef struct radio_hal_event {
     radio_event_type_t  type;       /* event type */
-    int                 status;     /* used by RADIO_EVENT_CONFIG, RADIO_EVENT_TUNED */
+    int32_t             status;     /* used by RADIO_EVENT_CONFIG, RADIO_EVENT_TUNED */
     union {
         /* RADIO_EVENT_ANTENNA, RADIO_EVENT_TA, RADIO_EVENT_EA */
         bool                    on;
@@ -209,12 +209,13 @@
 /* Used internally by the framework. Same information as in struct radio_hal_event */
 typedef struct radio_event {
     radio_event_type_t  type;
-    int                 status;
+    int32_t             status;
     union {
         bool                    on;
         radio_band_config_t     config;
         radio_program_info_t    info;
-        radio_metadata_t        *metadata; /* offset from start of struct when in shared memory */
+                                /* meta data (e.g PTY, song title ...), must not be NULL */
+        __attribute__((aligned(8))) radio_metadata_t *metadata;
     };
 } radio_event_t;
 
diff --git a/include/system/window.h b/include/system/window.h
index f439705..c340773 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -121,8 +121,9 @@
     int stride;
     int format;
     int usage;
+    uintptr_t layerCount;
 
-    void* reserved[2];
+    void* reserved[1];
 
     buffer_handle_t handle;
 
@@ -297,6 +298,25 @@
      * Returns the duration of the last queueBuffer call in microseconds
      */
     NATIVE_WINDOW_LAST_QUEUE_DURATION = 15,
+
+    /*
+     * Returns the number of image layers that the ANativeWindow buffer
+     * contains. By default this is 1, unless a buffer is explicitly allocated
+     * to contain multiple layers.
+     */
+    NATIVE_WINDOW_LAYER_COUNT = 16,
+
+    /*
+     * Returns 1 if NATIVE_WINDOW_GET_FRAME_TIMESTAMPS will return display
+     * present info, 0 if it won't.
+     */
+    NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT = 17,
+
+    /*
+     * Returns 1 if NATIVE_WINDOW_GET_FRAME_TIMESTAMPS will return display
+     * retire info, 0 if it won't.
+     */
+    NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_RETIRE = 18,
 };
 
 /* Valid operations for the (*perform)() hook.
@@ -333,7 +353,11 @@
     NATIVE_WINDOW_SET_SURFACE_DAMAGE        = 20,   /* private */
     NATIVE_WINDOW_SET_SHARED_BUFFER_MODE    = 21,
     NATIVE_WINDOW_SET_AUTO_REFRESH          = 22,
-    NATIVE_WINDOW_GET_FRAME_TIMESTAMPS      = 23,
+    NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION= 23,
+    NATIVE_WINDOW_GET_NEXT_FRAME_ID         = 24,
+    NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS   = 25,
+    NATIVE_WINDOW_GET_COMPOSITOR_TIMING     = 26,
+    NATIVE_WINDOW_GET_FRAME_TIMESTAMPS      = 27,
 };
 
 /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -996,15 +1020,49 @@
     return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh);
 }
 
+static inline int native_window_get_refresh_cycle_duration(
+        struct ANativeWindow* window,
+        int64_t* outRefreshDuration)
+{
+    return window->perform(window, NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION,
+            outRefreshDuration);
+}
+
+static inline int native_window_get_next_frame_id(
+        struct ANativeWindow* window, uint64_t* frameId)
+{
+    return window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, frameId);
+}
+
+static inline int native_window_enable_frame_timestamps(
+        struct ANativeWindow* window, bool enable)
+{
+    return window->perform(window, NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS,
+            enable);
+}
+
+static inline int native_window_get_compositor_timing(
+        struct ANativeWindow* window,
+        int64_t* compositeDeadline, int64_t* compositeInterval,
+        int64_t* compositeToPresentLatency)
+{
+    return window->perform(window, NATIVE_WINDOW_GET_COMPOSITOR_TIMING,
+            compositeDeadline, compositeInterval, compositeToPresentLatency);
+}
+
 static inline int native_window_get_frame_timestamps(
-        struct ANativeWindow* window, uint32_t framesAgo,
-        int64_t* outPostedTime, int64_t* outAcquireTime,
-        int64_t* outRefreshStartTime, int64_t* outGlCompositionDoneTime,
-        int64_t* outDisplayRetireTime, int64_t* outReleaseTime)
+        struct ANativeWindow* window, uint64_t frameId,
+        int64_t* outRequestedPresentTime, int64_t* outAcquireTime,
+        int64_t* outLatchTime, int64_t* outFirstRefreshStartTime,
+        int64_t* outLastRefreshStartTime, int64_t* outGpuCompositionDoneTime,
+        int64_t* outDisplayPresentTime, int64_t* outDisplayRetireTime,
+        int64_t* outDequeueReadyTime, int64_t* outReleaseTime)
 {
     return window->perform(window, NATIVE_WINDOW_GET_FRAME_TIMESTAMPS,
-            framesAgo, outPostedTime, outAcquireTime, outRefreshStartTime,
-            outGlCompositionDoneTime, outDisplayRetireTime, outReleaseTime);
+            frameId, outRequestedPresentTime, outAcquireTime, outLatchTime,
+            outFirstRefreshStartTime, outLastRefreshStartTime,
+            outGpuCompositionDoneTime, outDisplayPresentTime,
+            outDisplayRetireTime, outDequeueReadyTime, outReleaseTime);
 }
 
 
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 2388edc..8ab5e30 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -704,6 +704,9 @@
     } else if (strncmp(command, "reboot", 6) == 0) {
         cmd = ANDROID_RB_RESTART2;
         len = 6;
+    } else if (strncmp(command, "thermal-shutdown", 16) == 0) {
+        cmd = ANDROID_RB_THERMOFF;
+        len = 16;
     } else {
         LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
         return -EINVAL;
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index 159a9d4..06026d1 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -189,11 +189,56 @@
     free_entries(&ro_entries);
 }
 
+static void save_reboot_reason(int cmd, const char *arg)
+{
+    FILE *fp;
+    const char *reason = NULL;
+
+    fp = fopen(LAST_REBOOT_REASON_FILE, "w");
+    if (fp == NULL) {
+        KLOG_WARNING(TAG, "Error creating " LAST_REBOOT_REASON_FILE
+                     ": %s\n", strerror(errno));
+        return;
+    }
+    switch (cmd) {
+        case ANDROID_RB_RESTART:
+            reason = "restart";
+            break;
+
+        case ANDROID_RB_POWEROFF:
+            reason = "power-off";
+            break;
+
+        case ANDROID_RB_RESTART2:
+            reason = arg && strlen(arg) ? arg : "restart";
+            break;
+
+        case ANDROID_RB_THERMOFF:
+            reason = "thermal-shutdown";
+            break;
+
+        default:
+            fprintf(fp,"0x%08X\n", cmd);
+            break;
+    }
+
+    if (reason) {
+        if (fprintf(fp, "%s\n", reason) < 0) {
+             KLOG_WARNING(TAG, "Error writing " LAST_REBOOT_REASON_FILE
+                          ": %s\n", strerror(errno));
+        }
+    }
+
+    fclose(fp);
+}
+
 int android_reboot_with_callback(
     int cmd, int flags __unused, const char *arg,
     void (*cb_on_remount)(const struct mntent*))
 {
     int ret;
+
+    save_reboot_reason(cmd, arg);
     remount_ro(cb_on_remount);
     switch (cmd) {
         case ANDROID_RB_RESTART:
@@ -209,6 +254,10 @@
                            LINUX_REBOOT_CMD_RESTART2, arg);
             break;
 
+        case ANDROID_RB_THERMOFF:
+            ret = reboot(RB_POWER_OFF);
+            break;
+
         default:
             ret = -1;
     }
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 7e27c3e..394a897 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -149,9 +149,14 @@
                                               "system/bin/run-as" },
     { 00700, AID_SYSTEM,    AID_SHELL,     CAP_MASK_LONG(CAP_BLOCK_SUSPEND),
                                               "system/bin/inputflinger" },
+    { 00750, AID_SYSTEM,    AID_SHELL,     CAP_MASK_LONG(CAP_SETUID) |
+                                           CAP_MASK_LONG(CAP_SETGID) |
+                                           CAP_MASK_LONG(CAP_SYS_PTRACE),
+                                              "system/bin/storaged" },
 
     /* Support FIFO scheduling mode in SurfaceFlinger. */
-    { 00755, AID_SYSTEM,    AID_GRAPHICS,     CAP_MASK_LONG(CAP_SYS_NICE), "system/bin/surfaceflinger" },
+    { 00755, AID_SYSTEM,    AID_GRAPHICS,  CAP_MASK_LONG(CAP_SYS_NICE),
+                                              "system/bin/surfaceflinger" },
 
     /* Support hostapd administering a network interface. */
     { 00755, AID_WIFI,      AID_WIFI,      CAP_MASK_LONG(CAP_NET_ADMIN) |
diff --git a/libcutils/include/cutils/android_reboot.h b/libcutils/include/cutils/android_reboot.h
index a3861a0..2e3b429 100644
--- a/libcutils/include/cutils/android_reboot.h
+++ b/libcutils/include/cutils/android_reboot.h
@@ -25,10 +25,14 @@
 #define ANDROID_RB_RESTART  0xDEAD0001
 #define ANDROID_RB_POWEROFF 0xDEAD0002
 #define ANDROID_RB_RESTART2 0xDEAD0003
+#define ANDROID_RB_THERMOFF 0xDEAD0004
 
 /* Properties */
 #define ANDROID_RB_PROPERTY "sys.powerctl"
 
+/* Android reboot reason stored in this file */
+#define LAST_REBOOT_REASON_FILE "/data/misc/reboot/last_reboot_reason"
+
 int android_reboot(int cmd, int flags, const char *arg);
 int android_reboot_with_callback(
     int cmd, int flags, const char *arg,
diff --git a/libmemtrack/Android.bp b/libmemtrack/Android.bp
index 98413dd..68c580a 100644
--- a/libmemtrack/Android.bp
+++ b/libmemtrack/Android.bp
@@ -2,13 +2,19 @@
 
 cc_library_shared {
     name: "libmemtrack",
-    srcs: ["memtrack.c"],
+    srcs: ["memtrack.cpp"],
     export_include_dirs: ["include"],
     local_include_dirs: ["include"],
     include_dirs: ["hardware/libhardware/include"],
     shared_libs: [
         "libhardware",
         "liblog",
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
+        "android.hardware.memtrack@1.0",
     ],
     cflags: [
         "-Wall",
diff --git a/libmemtrack/include/memtrack/memtrack.h b/libmemtrack/include/memtrack/memtrack.h
index 8c0ab89..2134a6f 100644
--- a/libmemtrack/include/memtrack/memtrack.h
+++ b/libmemtrack/include/memtrack/memtrack.h
@@ -35,16 +35,6 @@
 struct memtrack_proc;
 
 /**
- * memtrack_init
- *
- * Must be called once before calling any other functions.  After this function
- * is called, everything else is thread-safe.
- *
- * Returns 0 on success, -errno on error.
- */
-int memtrack_init(void);
-
-/**
  * memtrack_proc_new
  *
  * Return a new handle to hold process memory stats.
diff --git a/libmemtrack/memtrack.c b/libmemtrack/memtrack.c
deleted file mode 100644
index 9ed9451..0000000
--- a/libmemtrack/memtrack.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#define LOG_TAG "memtrack"
-
-#include <memtrack/memtrack.h>
-
-#include <errno.h>
-#include <malloc.h>
-#include <string.h>
-
-#include <hardware/memtrack.h>
-#include <log/log.h>
-
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
-
-static const memtrack_module_t *module;
-
-struct memtrack_proc {
-    pid_t pid;
-    struct memtrack_proc_type {
-        enum memtrack_type type;
-        size_t num_records;
-        size_t allocated_records;
-        struct memtrack_record *records;
-    } types[MEMTRACK_NUM_TYPES];
-};
-
-int memtrack_init(void)
-{
-    int err;
-
-    if (module) {
-        return 0;
-    }
-
-    err = hw_get_module(MEMTRACK_HARDWARE_MODULE_ID,
-            (hw_module_t const**)&module);
-    if (err) {
-        ALOGE("Couldn't load %s module (%s)", MEMTRACK_HARDWARE_MODULE_ID,
-                strerror(-err));
-        return err;
-    }
-
-    return module->init(module);
-}
-
-struct memtrack_proc *memtrack_proc_new(void)
-{
-    if (!module) {
-        return NULL;
-    }
-
-    return calloc(sizeof(struct memtrack_proc), 1);
-}
-
-void memtrack_proc_destroy(struct memtrack_proc *p)
-{
-    enum memtrack_type i;
-
-    if (p) {
-        for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
-            free(p->types[i].records);
-        }
-    }
-    free(p);
-}
-
-static int memtrack_proc_get_type(struct memtrack_proc_type *t,
-            pid_t pid, enum memtrack_type type)
-{
-    size_t num_records = t->num_records;
-    int ret;
-
-retry:
-    ret = module->getMemory(module, pid, type, t->records, &num_records);
-    if (ret) {
-        t->num_records = 0;
-        return ret;
-    }
-    if (num_records > t->allocated_records) {
-        /* Need more records than allocated */
-        free(t->records);
-        t->records = calloc(sizeof(*t->records), num_records);
-        if (!t->records) {
-            return -ENOMEM;
-        }
-        t->allocated_records = num_records;
-        goto retry;
-    }
-    t->num_records = num_records;
-
-    return 0;
-}
-
-/* TODO: sanity checks on return values from HALs:
- *   make sure no records have invalid flags set
- *    - unknown flags
- *    - too many flags of a single category
- *    - missing ACCOUNTED/UNACCOUNTED
- *   make sure there are not overlapping SHARED and SHARED_PSS records
- */
-static int memtrack_proc_sanity_check(struct memtrack_proc *p)
-{
-    (void)p;
-    return 0;
-}
-
-int memtrack_proc_get(struct memtrack_proc *p, pid_t pid)
-{
-    enum memtrack_type i;
-
-    if (!module) {
-        return -EINVAL;
-    }
-
-    if (!p) {
-        return -EINVAL;
-    }
-
-    p->pid = pid;
-    for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
-        memtrack_proc_get_type(&p->types[i], pid, i);
-    }
-
-    return memtrack_proc_sanity_check(p);
-}
-
-static ssize_t memtrack_proc_sum(struct memtrack_proc *p,
-            enum memtrack_type types[], size_t num_types,
-            unsigned int flags)
-{
-    ssize_t sum = 0;
-    size_t i;
-    size_t j;
-
-    for (i = 0; i < num_types; i++) {
-        enum memtrack_type type = types[i];
-        for (j = 0; j < p->types[type].num_records; j++) {
-            if ((p->types[type].records[j].flags & flags) == flags) {
-                sum += p->types[type].records[j].size_in_bytes;
-            }
-        }
-    }
-
-    return sum;
-}
-
-ssize_t memtrack_proc_graphics_total(struct memtrack_proc *p)
-{
-    enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
-    return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
-}
-
-ssize_t memtrack_proc_graphics_pss(struct memtrack_proc *p)
-{
-    enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
-    return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
-                MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
-}
-
-ssize_t memtrack_proc_gl_total(struct memtrack_proc *p)
-{
-    enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
-    return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
-}
-
-ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p)
-{
-    enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
-    return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
-                MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
-}
-
-ssize_t memtrack_proc_other_total(struct memtrack_proc *p)
-{
-    enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
-                                        MEMTRACK_TYPE_CAMERA,
-                                        MEMTRACK_TYPE_OTHER };
-    return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
-}
-
-ssize_t memtrack_proc_other_pss(struct memtrack_proc *p)
-{
-    enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
-                                        MEMTRACK_TYPE_CAMERA,
-                                        MEMTRACK_TYPE_OTHER };
-    return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
-                MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
-}
diff --git a/libmemtrack/memtrack.cpp b/libmemtrack/memtrack.cpp
new file mode 100644
index 0000000..e83f181
--- /dev/null
+++ b/libmemtrack/memtrack.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+#define LOG_TAG "memtrack"
+#include <android/hardware/memtrack/1.0/IMemtrack.h>
+#include <memtrack/memtrack.h>
+
+#include <errno.h>
+#include <malloc.h>
+#include <vector>
+#include <string.h>
+#include <mutex>
+
+#include <log/log.h>
+
+using android::hardware::memtrack::V1_0::IMemtrack;
+using android::hardware::memtrack::V1_0::MemtrackType;
+using android::hardware::memtrack::V1_0::MemtrackRecord;
+using android::hardware::memtrack::V1_0::MemtrackFlag;
+using android::hardware::memtrack::V1_0::MemtrackStatus;
+using android::hardware::hidl_vec;
+
+struct memtrack_proc_type {
+    MemtrackType type;
+    std::vector<MemtrackRecord> records;
+};
+
+struct memtrack_proc {
+    pid_t pid;
+    memtrack_proc_type types[static_cast<int>(MemtrackType::NUM_TYPES)];
+};
+
+//TODO(b/31632518)
+static android::sp<IMemtrack> get_instance() {
+    static android::sp<IMemtrack> module = IMemtrack::getService();
+    if (module == nullptr) {
+        ALOGE("Couldn't load memtrack module");
+    }
+    return module;
+}
+
+memtrack_proc *memtrack_proc_new(void)
+{
+    return new memtrack_proc();
+}
+
+void memtrack_proc_destroy(memtrack_proc *p)
+{
+    delete(p);
+}
+
+static int memtrack_proc_get_type(memtrack_proc_type *t,
+        pid_t pid, MemtrackType type)
+{
+    int err = 0;
+    android::sp<IMemtrack> memtrack = get_instance();
+    if (memtrack == nullptr)
+        return -1;
+
+    memtrack->getMemory(pid, type,
+        [&t, &err](MemtrackStatus status, hidl_vec<MemtrackRecord> records) {
+            if (status != MemtrackStatus::SUCCESS) {
+                err = -1;
+                t->records.resize(0);
+            }
+            t->records.resize(records.size());
+            for (size_t i = 0; i < records.size(); i++) {
+                t->records[i].sizeInBytes = records[i].sizeInBytes;
+                t->records[i].flags = records[i].flags;
+            }
+    });
+    return err;
+}
+
+/* TODO: sanity checks on return values from HALs:
+ *   make sure no records have invalid flags set
+ *    - unknown flags
+ *    - too many flags of a single category
+ *    - missing ACCOUNTED/UNACCOUNTED
+ *   make sure there are not overlapping SHARED and SHARED_PSS records
+ */
+static int memtrack_proc_sanity_check(memtrack_proc* /*p*/)
+{
+    return 0;
+}
+
+int memtrack_proc_get(memtrack_proc *p, pid_t pid)
+{
+    if (!p) {
+        return -EINVAL;
+    }
+
+    p->pid = pid;
+    for (uint32_t i = 0; i < (uint32_t)MemtrackType::NUM_TYPES; i++) {
+        int ret = memtrack_proc_get_type(&p->types[i], pid, (MemtrackType)i);
+        if (ret != 0)
+           return ret;
+    }
+
+    return memtrack_proc_sanity_check(p);
+}
+
+static ssize_t memtrack_proc_sum(memtrack_proc *p,
+        const std::vector<MemtrackType>& types, uint32_t flags)
+{
+    ssize_t sum = 0;
+
+    for (size_t i = 0; i < types.size(); i++) {
+        memtrack_proc_type type = p->types[static_cast<int>(types[i])];
+        std::vector<MemtrackRecord> records = type.records;
+        for (size_t j = 0; j < records.size(); j++) {
+            if ((records[j].flags & flags) == flags) {
+                sum += records[j].sizeInBytes;
+            }
+        }
+    }
+
+    return sum;
+}
+
+ssize_t memtrack_proc_graphics_total(memtrack_proc *p)
+{
+    std::vector<MemtrackType> types = {MemtrackType::GRAPHICS};
+    return memtrack_proc_sum(p, types, 0);
+}
+
+ssize_t memtrack_proc_graphics_pss(memtrack_proc *p)
+{
+    std::vector<MemtrackType> types = { MemtrackType::GRAPHICS };
+    return memtrack_proc_sum(p, types,
+            (uint32_t)MemtrackFlag::SMAPS_UNACCOUNTED);
+}
+
+ssize_t memtrack_proc_gl_total(memtrack_proc *p)
+{
+    std::vector<MemtrackType> types = { MemtrackType::GL };
+    return memtrack_proc_sum(p, types, 0);
+}
+
+ssize_t memtrack_proc_gl_pss(memtrack_proc *p)
+{
+    std::vector<MemtrackType> types = { MemtrackType::GL };
+    return memtrack_proc_sum(p, types,
+            (uint32_t)MemtrackFlag::SMAPS_UNACCOUNTED);
+}
+
+ssize_t memtrack_proc_other_total(memtrack_proc *p)
+{
+    std::vector<MemtrackType> types = { MemtrackType::MULTIMEDIA,
+            MemtrackType::CAMERA, MemtrackType::OTHER };
+    return memtrack_proc_sum(p, types, 0);
+}
+
+ssize_t memtrack_proc_other_pss(memtrack_proc *p)
+{
+    std::vector<MemtrackType> types = { MemtrackType::MULTIMEDIA,
+            MemtrackType::CAMERA, MemtrackType::OTHER };
+    return memtrack_proc_sum(p, types,
+            (uint32_t)MemtrackFlag::SMAPS_UNACCOUNTED);
+}
diff --git a/libmemtrack/memtrack_test.c b/libmemtrack/memtrack_test.c
index eaadfa7..77c935e 100644
--- a/libmemtrack/memtrack_test.c
+++ b/libmemtrack/memtrack_test.c
@@ -82,12 +82,6 @@
     (void)argc;
     (void)argv;
 
-    ret = memtrack_init();
-    if (ret < 0) {
-        fprintf(stderr, "failed to initialize HAL: %s (%d)\n", strerror(-ret), ret);
-        exit(EXIT_FAILURE);
-    }
-
     ret = pm_kernel_create(&ker);
     if (ret) {
         fprintf(stderr, "Error creating kernel interface -- "
diff --git a/libsparse/simg_dump.py b/libsparse/simg_dump.py
index c70d45f..82a03ad 100755
--- a/libsparse/simg_dump.py
+++ b/libsparse/simg_dump.py
@@ -15,43 +15,64 @@
 # limitations under the License.
 
 from __future__ import print_function
-import getopt, posixpath, signal, struct, sys
+import csv
+import getopt
+import hashlib
+import posixpath
+import signal
+import struct
+import sys
+
 
 def usage(argv0):
   print("""
-Usage: %s [-v] sparse_image_file ...
+Usage: %s [-v] [-s] [-c <filename>] sparse_image_file ...
  -v             verbose output
-""" % ( argv0 ))
+ -s             show sha1sum of data blocks
+ -c <filename>  save .csv file of blocks
+""" % (argv0))
   sys.exit(2)
 
-def main():
 
+def main():
   signal.signal(signal.SIGPIPE, signal.SIG_DFL)
 
   me = posixpath.basename(sys.argv[0])
 
   # Parse the command line
-  verbose = 0			# -v
+  verbose = 0                   # -v
+  showhash = 0                  # -s
+  csvfilename = None            # -c
   try:
     opts, args = getopt.getopt(sys.argv[1:],
-                               "v",
-                               ["verbose"])
+                               "vsc:",
+                               ["verbose", "showhash", "csvfile"])
   except getopt.GetoptError, e:
     print(e)
     usage(me)
   for o, a in opts:
     if o in ("-v", "--verbose"):
       verbose += 1
+    elif o in ("-s", "--showhash"):
+      showhash = True
+    elif o in ("-c", "--csvfile"):
+      csvfilename = a
     else:
       print("Unrecognized option \"%s\"" % (o))
       usage(me)
 
-  if len(args) == 0:
+  if not args:
     print("No sparse_image_file specified")
     usage(me)
 
+  if csvfilename:
+    csvfile = open(csvfilename, "wb")
+    csvwriter = csv.writer(csvfile)
+
+  output = verbose or csvfilename or showhash
+
   for path in args:
-    FH = open(path, 'rb')
+    FH = open(path, "rb")
     header_bin = FH.read(28)
     header = struct.unpack("<I4H4I", header_bin)
 
@@ -88,71 +109,99 @@
     if image_checksum != 0:
       print("checksum=0x%08X" % (image_checksum))
 
-    if not verbose:
+    if not output:
       continue
-    print("            input_bytes      output_blocks")
-    print("chunk    offset     number  offset  number")
+
+    if verbose > 0:
+      print("            input_bytes      output_blocks")
+      print("chunk    offset     number  offset  number")
+
+    if csvfilename:
+      csvwriter.writerow(["chunk", "input offset", "input bytes",
+                          "output offset", "output blocks", "type", "hash"])
+
     offset = 0
-    for i in xrange(1,total_chunks+1):
+    for i in xrange(1, total_chunks + 1):
       header_bin = FH.read(12)
       header = struct.unpack("<2H2I", header_bin)
       chunk_type = header[0]
-      reserved1 = header[1]
       chunk_sz = header[2]
       total_sz = header[3]
       data_sz = total_sz - 12
+      curhash = ""
+      curtype = ""
+      curpos = FH.tell()
 
-      print("%4u %10u %10u %7u %7u" % (i, FH.tell(), data_sz, offset, chunk_sz),
-            end=" ")
+      if verbose > 0:
+        print("%4u %10u %10u %7u %7u" % (i, curpos, data_sz, offset, chunk_sz),
+              end=" ")
 
       if chunk_type == 0xCAC1:
         if data_sz != (chunk_sz * blk_sz):
           print("Raw chunk input size (%u) does not match output size (%u)"
                 % (data_sz, chunk_sz * blk_sz))
-          break;
+          break
         else:
-          print("Raw data", end="")
-          FH.read(data_sz)
+          curtype = "Raw data"
+          data = FH.read(data_sz)
+          if showhash:
+            h = hashlib.sha1()
+            h.update(data)
+            curhash = h.hexdigest()
       elif chunk_type == 0xCAC2:
         if data_sz != 4:
           print("Fill chunk should have 4 bytes of fill, but this has %u"
-                % (data_sz), end="")
-          break;
+                % (data_sz))
+          break
         else:
           fill_bin = FH.read(4)
           fill = struct.unpack("<I", fill_bin)
-          print("Fill with 0x%08X" % (fill))
+          curtype = format("Fill with 0x%08X" % (fill))
+          if showhash:
+            h = hashlib.sha1()
+            data = fill_bin * (blk_sz / 4);
+            for block in xrange(chunk_sz):
+              h.update(data)
+            curhash = h.hexdigest()
       elif chunk_type == 0xCAC3:
         if data_sz != 0:
           print("Don't care chunk input size is non-zero (%u)" % (data_sz))
-          break;
+          break
         else:
-          print("Don't care", end="")
+          curtype = "Don't care"
       elif chunk_type == 0xCAC4:
         if data_sz != 4:
           print("CRC32 chunk should have 4 bytes of CRC, but this has %u"
-                % (data_sz), end="")
-          break;
+                % (data_sz))
+          break
         else:
           crc_bin = FH.read(4)
           crc = struct.unpack("<I", crc_bin)
-          print("Unverified CRC32 0x%08X" % (crc))
+          curtype = format("Unverified CRC32 0x%08X" % (crc))
       else:
-          print("Unknown chunk type 0x%04X" % (chunk_type), end="")
-          break;
+        print("Unknown chunk type 0x%04X" % (chunk_type))
+        break
 
-      if verbose > 1:
-        header = struct.unpack("<12B", header_bin)
-        print(" (%02X%02X %02X%02X %02X%02X%02X%02X %02X%02X%02X%02X)"
-              % (header[0], header[1], header[2], header[3],
-                 header[4], header[5], header[6], header[7],
-                 header[8], header[9], header[10], header[11]))
-      else:
-        print()
+      if verbose > 0:
+        print("%-18s" % (curtype), end=" ")
+
+        if verbose > 1:
+          header = struct.unpack("<12B", header_bin)
+          print(" (%02X%02X %02X%02X %02X%02X%02X%02X %02X%02X%02X%02X)"
+                % (header[0], header[1], header[2], header[3],
+                   header[4], header[5], header[6], header[7],
+                   header[8], header[9], header[10], header[11]), end=" ")
+
+        print(curhash)
+
+      if csvfilename:
+        csvwriter.writerow([i, curpos, data_sz, offset, chunk_sz, curtype,
+                            curhash])
 
       offset += chunk_sz
 
-    print("     %10u            %7u         End" % (FH.tell(), offset))
+    if verbose > 0:
+      print("     %10u            %7u         End" % (FH.tell(), offset))
 
     if total_blks != offset:
       print("The header said we should have %u output blocks, but we saw %u"
@@ -163,6 +212,9 @@
       print("There were %u bytes of extra data at the end of the file."
             % (junk_len))
 
+  if csvfilename:
+    csvfile.close()
+
   sys.exit(0)
 
 if __name__ == "__main__":
diff --git a/libsuspend/Android.bp b/libsuspend/Android.bp
index d27ceea..d442c94 100644
--- a/libsuspend/Android.bp
+++ b/libsuspend/Android.bp
@@ -4,8 +4,6 @@
     name: "libsuspend",
     srcs: [
         "autosuspend.c",
-        "autosuspend_autosleep.c",
-        "autosuspend_earlysuspend.c",
         "autosuspend_wakeup_count.c",
     ],
     export_include_dirs: ["include"],
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index 54730c2..96e1c10 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -34,19 +34,6 @@
         return 0;
     }
 
-    autosuspend_ops = autosuspend_earlysuspend_init();
-    if (autosuspend_ops) {
-        goto out;
-    }
-
-/* Remove autosleep so userspace can manager suspend/resume and keep stats */
-#if 0
-    autosuspend_ops = autosuspend_autosleep_init();
-    if (autosuspend_ops) {
-        goto out;
-    }
-#endif
-
     autosuspend_ops = autosuspend_wakeup_count_init();
     if (autosuspend_ops) {
         goto out;
diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
deleted file mode 100644
index 77d8db0..0000000
--- a/libsuspend/autosuspend_autosleep.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#define LOG_TAG "libsuspend"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "autosuspend_ops.h"
-
-#define SYS_POWER_AUTOSLEEP "/sys/power/autosleep"
-
-static int autosleep_fd;
-static const char *sleep_state = "mem";
-static const char *on_state = "off";
-
-static int autosuspend_autosleep_enable(void)
-{
-    char buf[80];
-    int ret;
-
-    ALOGV("autosuspend_autosleep_enable\n");
-
-    ret = TEMP_FAILURE_RETRY(write(autosleep_fd, sleep_state, strlen(sleep_state)));
-    if (ret < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
-        goto err;
-    }
-
-    ALOGV("autosuspend_autosleep_enable done\n");
-
-    return 0;
-
-err:
-    return ret;
-}
-
-static int autosuspend_autosleep_disable(void)
-{
-    char buf[80];
-    int ret;
-
-    ALOGV("autosuspend_autosleep_disable\n");
-
-    ret = TEMP_FAILURE_RETRY(write(autosleep_fd, on_state, strlen(on_state)));
-    if (ret < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGE("Error writing to %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
-        goto err;
-    }
-
-    ALOGV("autosuspend_autosleep_disable done\n");
-
-    return 0;
-
-err:
-    return ret;
-}
-
-struct autosuspend_ops autosuspend_autosleep_ops = {
-        .enable = autosuspend_autosleep_enable,
-        .disable = autosuspend_autosleep_disable,
-};
-
-struct autosuspend_ops *autosuspend_autosleep_init(void)
-{
-    char buf[80];
-
-    autosleep_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_AUTOSLEEP, O_WRONLY));
-    if (autosleep_fd < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGE("Error opening %s: %s\n", SYS_POWER_AUTOSLEEP, buf);
-        return NULL;
-    }
-
-    ALOGI("Selected autosleep\n");
-
-    autosuspend_autosleep_disable();
-
-    return &autosuspend_autosleep_ops;
-}
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
deleted file mode 100644
index 809ee82..0000000
--- a/libsuspend/autosuspend_earlysuspend.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#define LOG_TAG "libsuspend"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "autosuspend_ops.h"
-
-#define EARLYSUSPEND_SYS_POWER_STATE "/sys/power/state"
-#define EARLYSUSPEND_WAIT_FOR_FB_SLEEP "/sys/power/wait_for_fb_sleep"
-#define EARLYSUSPEND_WAIT_FOR_FB_WAKE "/sys/power/wait_for_fb_wake"
-
-static int sPowerStatefd;
-static const char *pwr_state_mem = "mem";
-static const char *pwr_state_on = "on";
-static pthread_t earlysuspend_thread;
-static pthread_mutex_t earlysuspend_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t earlysuspend_cond = PTHREAD_COND_INITIALIZER;
-static bool wait_for_earlysuspend;
-static enum {
-    EARLYSUSPEND_ON,
-    EARLYSUSPEND_MEM,
-} earlysuspend_state = EARLYSUSPEND_ON;
-
-int wait_for_fb_wake(void)
-{
-    int err = 0;
-    char buf;
-    int fd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_WAIT_FOR_FB_WAKE, O_RDONLY, 0));
-    // if the file doesn't exist, the error will be caught in read() below
-    err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
-    ALOGE_IF(err < 0,
-            "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
-    close(fd);
-    return err < 0 ? err : 0;
-}
-
-static int wait_for_fb_sleep(void)
-{
-    int err = 0;
-    char buf;
-    int fd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, O_RDONLY, 0));
-    // if the file doesn't exist, the error will be caught in read() below
-    err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
-    ALOGE_IF(err < 0,
-            "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
-    close(fd);
-    return err < 0 ? err : 0;
-}
-
-static void *earlysuspend_thread_func(void __unused *arg)
-{
-    while (1) {
-        if (wait_for_fb_sleep()) {
-            ALOGE("Failed reading wait_for_fb_sleep, exiting earlysuspend thread\n");
-            return NULL;
-        }
-        pthread_mutex_lock(&earlysuspend_mutex);
-        earlysuspend_state = EARLYSUSPEND_MEM;
-        pthread_cond_signal(&earlysuspend_cond);
-        pthread_mutex_unlock(&earlysuspend_mutex);
-
-        if (wait_for_fb_wake()) {
-            ALOGE("Failed reading wait_for_fb_wake, exiting earlysuspend thread\n");
-            return NULL;
-        }
-        pthread_mutex_lock(&earlysuspend_mutex);
-        earlysuspend_state = EARLYSUSPEND_ON;
-        pthread_cond_signal(&earlysuspend_cond);
-        pthread_mutex_unlock(&earlysuspend_mutex);
-    }
-}
-static int autosuspend_earlysuspend_enable(void)
-{
-    char buf[80];
-    int ret;
-
-    ALOGV("autosuspend_earlysuspend_enable\n");
-
-    ret = write(sPowerStatefd, pwr_state_mem, strlen(pwr_state_mem));
-    if (ret < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
-        goto err;
-    }
-
-    if (wait_for_earlysuspend) {
-        pthread_mutex_lock(&earlysuspend_mutex);
-        while (earlysuspend_state != EARLYSUSPEND_MEM) {
-            pthread_cond_wait(&earlysuspend_cond, &earlysuspend_mutex);
-        }
-        pthread_mutex_unlock(&earlysuspend_mutex);
-    }
-
-    ALOGV("autosuspend_earlysuspend_enable done\n");
-
-    return 0;
-
-err:
-    return ret;
-}
-
-static int autosuspend_earlysuspend_disable(void)
-{
-    char buf[80];
-    int ret;
-
-    ALOGV("autosuspend_earlysuspend_disable\n");
-
-    ret = TEMP_FAILURE_RETRY(write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on)));
-    if (ret < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
-        goto err;
-    }
-
-    if (wait_for_earlysuspend) {
-        pthread_mutex_lock(&earlysuspend_mutex);
-        while (earlysuspend_state != EARLYSUSPEND_ON) {
-            pthread_cond_wait(&earlysuspend_cond, &earlysuspend_mutex);
-        }
-        pthread_mutex_unlock(&earlysuspend_mutex);
-    }
-
-    ALOGV("autosuspend_earlysuspend_disable done\n");
-
-    return 0;
-
-err:
-    return ret;
-}
-
-struct autosuspend_ops autosuspend_earlysuspend_ops = {
-        .enable = autosuspend_earlysuspend_enable,
-        .disable = autosuspend_earlysuspend_disable,
-};
-
-void start_earlysuspend_thread(void)
-{
-    char buf[80];
-    int ret;
-
-    ret = access(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, F_OK);
-    if (ret < 0) {
-        return;
-    }
-
-    ret = access(EARLYSUSPEND_WAIT_FOR_FB_WAKE, F_OK);
-    if (ret < 0) {
-        return;
-    }
-
-    wait_for_fb_wake();
-
-    ALOGI("Starting early suspend unblocker thread\n");
-    ret = pthread_create(&earlysuspend_thread, NULL, earlysuspend_thread_func, NULL);
-    if (ret) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGE("Error creating thread: %s\n", buf);
-        return;
-    }
-
-    wait_for_earlysuspend = true;
-}
-
-struct autosuspend_ops *autosuspend_earlysuspend_init(void)
-{
-    char buf[80];
-    int ret;
-
-    sPowerStatefd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR));
-
-    if (sPowerStatefd < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGW("Error opening %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
-        return NULL;
-    }
-
-    ret = TEMP_FAILURE_RETRY(write(sPowerStatefd, "on", 2));
-    if (ret < 0) {
-        strerror_r(errno, buf, sizeof(buf));
-        ALOGW("Error writing 'on' to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
-        goto err_write;
-    }
-
-    ALOGI("Selected early suspend\n");
-
-    start_earlysuspend_thread();
-
-    return &autosuspend_earlysuspend_ops;
-
-err_write:
-    close(sPowerStatefd);
-    return NULL;
-}
diff --git a/libusbhost/include/usbhost/usbhost.h b/libusbhost/include/usbhost/usbhost.h
index 84594c8..a8dd673 100644
--- a/libusbhost/include/usbhost/usbhost.h
+++ b/libusbhost/include/usbhost/usbhost.h
@@ -144,17 +144,17 @@
  * usb_device_get_product_name and usb_device_get_serial.
  * Call free() to free the result when you are done with it.
  */
-char* usb_device_get_string(struct usb_device *device, int id);
+char* usb_device_get_string(struct usb_device *device, int id, int timeout);
 
 /* Returns the manufacturer name for the USB device.
  * Call free() to free the result when you are done with it.
  */
-char* usb_device_get_manufacturer_name(struct usb_device *device);
+char* usb_device_get_manufacturer_name(struct usb_device *device, int timeout);
 
 /* Returns the product name for the USB device.
  * Call free() to free the result when you are done with it.
  */
-char* usb_device_get_product_name(struct usb_device *device);
+char* usb_device_get_product_name(struct usb_device *device, int timeout);
 
 /* Returns the version number for the USB device.
  */
@@ -163,7 +163,7 @@
 /* Returns the USB serial number for the USB device.
  * Call free() to free the result when you are done with it.
  */
-char* usb_device_get_serial(struct usb_device *device);
+char* usb_device_get_serial(struct usb_device *device, int timeout);
 
 /* Returns true if we have write access to the USB device,
  * and false if we only have access to the USB device configuration.
@@ -232,10 +232,11 @@
 /* Submits a read or write request on the specified device */
 int usb_request_queue(struct usb_request *req);
 
- /* Waits for the results of a previous usb_request_queue operation.
+ /* Waits for the results of a previous usb_request_queue operation. timeoutMillis == -1 requests
+  * to wait forever.
   * Returns a usb_request, or NULL for error.
   */
-struct usb_request *usb_request_wait(struct usb_device *dev);
+struct usb_request *usb_request_wait(struct usb_device *dev, int timeoutMillis);
 
 /* Cancels a pending usb_request_queue() operation. */
 int usb_request_cancel(struct usb_request *req);
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 68aca17..7adb4f2 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
 // #define DEBUG 1
 #if DEBUG
 
@@ -43,6 +47,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <ctype.h>
+#include <poll.h>
 #include <pthread.h>
 
 #include <linux/usbdevice_fs.h>
@@ -449,7 +454,7 @@
     return (struct usb_device_descriptor*)device->desc;
 }
 
-char* usb_device_get_string(struct usb_device *device, int id)
+char* usb_device_get_string(struct usb_device *device, int id, int timeout)
 {
     char string[256];
     __u16 buffer[MAX_STRING_DESCRIPTOR_LENGTH / sizeof(__u16)];
@@ -465,7 +470,8 @@
     // read list of supported languages
     result = usb_device_control_transfer(device,
             USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
-            (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages), 0);
+            (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages),
+            timeout);
     if (result > 0)
         languageCount = (result - 2) / 2;
 
@@ -474,7 +480,8 @@
 
         result = usb_device_control_transfer(device,
                 USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
-                (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer), 0);
+                (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer),
+                timeout);
         if (result > 0) {
             int i;
             // skip first word, and copy the rest to the string, changing shorts to bytes.
@@ -489,16 +496,16 @@
     return NULL;
 }
 
-char* usb_device_get_manufacturer_name(struct usb_device *device)
+char* usb_device_get_manufacturer_name(struct usb_device *device, int timeout)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-    return usb_device_get_string(device, desc->iManufacturer);
+    return usb_device_get_string(device, desc->iManufacturer, timeout);
 }
 
-char* usb_device_get_product_name(struct usb_device *device)
+char* usb_device_get_product_name(struct usb_device *device, int timeout)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-    return usb_device_get_string(device, desc->iProduct);
+    return usb_device_get_string(device, desc->iProduct, timeout);
 }
 
 int usb_device_get_version(struct usb_device *device)
@@ -507,10 +514,10 @@
     return desc->bcdUSB;
 }
 
-char* usb_device_get_serial(struct usb_device *device)
+char* usb_device_get_serial(struct usb_device *device, int timeout)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-    return usb_device_get_string(device, desc->iSerialNumber);
+    return usb_device_get_string(device, desc->iSerialNumber, timeout);
 }
 
 int usb_device_is_writeable(struct usb_device *device)
@@ -681,29 +688,38 @@
     return res;
 }
 
-struct usb_request *usb_request_wait(struct usb_device *dev)
+struct usb_request *usb_request_wait(struct usb_device *dev, int timeoutMillis)
 {
-    struct usbdevfs_urb *urb = NULL;
-    struct usb_request *req = NULL;
+    // Poll until a request becomes available if there is a timeout
+    if (timeoutMillis > 0) {
+        struct pollfd p = {.fd = dev->fd, .events = POLLOUT, .revents = 0};
 
-    while (1) {
-        int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb);
-        D("USBDEVFS_REAPURB returned %d\n", res);
-        if (res < 0) {
-            if(errno == EINTR) {
-                continue;
-            }
-            D("[ reap urb - error ]\n");
+        int res = poll(&p, 1, timeoutMillis);
+
+        if (res != 1 || p.revents != POLLOUT) {
+            D("[ poll - event %d, error %d]\n", p.revents, errno);
             return NULL;
-        } else {
-            D("[ urb @%p status = %d, actual = %d ]\n",
-                urb, urb->status, urb->actual_length);
-            req = (struct usb_request*)urb->usercontext;
-            req->actual_length = urb->actual_length;
         }
-        break;
     }
-    return req;
+
+    // Read the request. This should usually succeed as we polled before, but it can fail e.g. when
+    // two threads are reading usb requests at the same time and only a single request is available.
+    struct usbdevfs_urb *urb = NULL;
+    int res = TEMP_FAILURE_RETRY(ioctl(dev->fd, timeoutMillis == -1 ? USBDEVFS_REAPURB :
+                                       USBDEVFS_REAPURBNDELAY, &urb));
+    D("%s returned %d\n", timeoutMillis == -1 ? "USBDEVFS_REAPURB" : "USBDEVFS_REAPURBNDELAY", res);
+
+    if (res < 0) {
+        D("[ reap urb - error %d]\n", errno);
+        return NULL;
+    } else {
+        D("[ urb @%p status = %d, actual = %d ]\n", urb, urb->status, urb->actual_length);
+
+        struct usb_request *req = (struct usb_request*)urb->usercontext;
+        req->actual_length = urb->actual_length;
+
+        return req;
+    }
 }
 
 int usb_request_cancel(struct usb_request *req)
@@ -711,4 +727,3 @@
     struct usbdevfs_urb *urb = ((struct usbdevfs_urb*)req->private_data);
     return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, urb);
 }
-
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 77e69e4..84bc028 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -83,6 +83,7 @@
 
 Looper::~Looper() {
     close(mWakeEventFd);
+    mWakeEventFd = -1;
     if (mEpollFd >= 0) {
         close(mEpollFd);
     }
@@ -412,7 +413,8 @@
     ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
     if (nWrite != sizeof(uint64_t)) {
         if (errno != EAGAIN) {
-            ALOGW("Could not write wake signal: %s", strerror(errno));
+            LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s",
+                    mWakeEventFd, strerror(errno));
         }
     }
 }
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index 957aedb..1fa1d7a 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -113,16 +113,26 @@
 
 int32_t SharedBuffer::release(uint32_t flags) const
 {
-    int32_t prev = 1;
-    if (onlyOwner()
-            || (((prev = mRefs.fetch_sub(1, std::memory_order_release)) == 1)
-                && (atomic_thread_fence(std::memory_order_acquire), true))) {
+    const bool useDealloc = ((flags & eKeepStorage) == 0);
+    if (onlyOwner()) {
+        // Since we're the only owner, our reference count goes to zero.
         mRefs.store(0, std::memory_order_relaxed);
-        if ((flags & eKeepStorage) == 0) {
-            free(const_cast<SharedBuffer*>(this));
+        if (useDealloc) {
+            dealloc(this);
+        }
+        // As the only owner, our previous reference count was 1.
+        return 1;
+    }
+    // There's multiple owners, we need to use an atomic decrement.
+    int32_t prevRefCount = mRefs.fetch_sub(1, std::memory_order_release);
+    if (prevRefCount == 1) {
+        // We're the last reference, we need the acquire fence.
+        atomic_thread_fence(std::memory_order_acquire);
+        if (useDealloc) {
+            dealloc(this);
         }
     }
-    return prev;
+    return prevRefCount;
 }
 
 
diff --git a/libutils/include/utils/SortedVector.h b/libutils/include/utils/SortedVector.h
index 86f3496..d57465d 100644
--- a/libutils/include/utils/SortedVector.h
+++ b/libutils/include/utils/SortedVector.h
@@ -37,18 +37,18 @@
 
 public:
             typedef TYPE    value_type;
-    
-    /*! 
+
+    /*!
      * Constructors and destructors
      */
-    
+
                             SortedVector();
                             SortedVector(const SortedVector<TYPE>& rhs);
     virtual                 ~SortedVector();
 
     /*! copy operator */
-    const SortedVector<TYPE>&   operator = (const SortedVector<TYPE>& rhs) const;    
-    SortedVector<TYPE>&         operator = (const SortedVector<TYPE>& rhs);    
+    const SortedVector<TYPE>&   operator = (const SortedVector<TYPE>& rhs) const;
+    SortedVector<TYPE>&         operator = (const SortedVector<TYPE>& rhs);
 
     /*
      * empty the vector
@@ -56,7 +56,7 @@
 
     inline  void            clear()             { VectorImpl::clear(); }
 
-    /*! 
+    /*!
      * vector stats
      */
 
@@ -69,11 +69,11 @@
     //! sets the capacity. capacity can never be reduced less than size()
     inline  ssize_t         setCapacity(size_t size)    { return VectorImpl::setCapacity(size); }
 
-    /*! 
+    /*!
      * C-style array access
      */
-     
-    //! read-only C-style access 
+
+    //! read-only C-style access
     inline  const TYPE*     array() const;
 
     //! read-write C-style access. BE VERY CAREFUL when modifying the array
@@ -82,12 +82,12 @@
 
             //! finds the index of an item
             ssize_t         indexOf(const TYPE& item) const;
-            
+
             //! finds where this item should be inserted
             size_t          orderOf(const TYPE& item) const;
-            
-    
-    /*! 
+
+
+    /*!
      * accessors
      */
 
@@ -104,7 +104,7 @@
 
             //! add an item in the right place (and replace the one that is there)
             ssize_t         add(const TYPE& item);
-            
+
             //! editItemAt() MUST NOT change the order of this item
             TYPE&           editItemAt(size_t index) {
                 return *( static_cast<TYPE *>(VectorImpl::editItemLocation(index)) );
@@ -113,7 +113,7 @@
             //! merges a vector into this one
             ssize_t         merge(const Vector<TYPE>& vector);
             ssize_t         merge(const SortedVector<TYPE>& vector);
-            
+
             //! removes an item
             ssize_t         remove(const TYPE&);
 
@@ -121,7 +121,24 @@
     inline  ssize_t         removeItemsAt(size_t index, size_t count = 1);
     //! remove one item
     inline  ssize_t         removeAt(size_t index)  { return removeItemsAt(index); }
-            
+
+    /*
+     * these inlines add some level of compatibility with STL.
+     */
+    typedef TYPE* iterator;
+    typedef TYPE const* const_iterator;
+
+    inline iterator begin() { return editArray(); }
+    inline iterator end()   { return editArray() + size(); }
+    inline const_iterator begin() const { return array(); }
+    inline const_iterator end() const   { return array() + size(); }
+    inline void reserve(size_t n) { setCapacity(n); }
+    inline bool empty() const{ return isEmpty(); }
+    inline iterator erase(iterator pos) {
+        ssize_t index = removeItemsAt(pos-array());
+        return begin() + index;
+    }
+
 protected:
     virtual void    do_construct(void* storage, size_t num) const;
     virtual void    do_destroy(void* storage, size_t num) const;
@@ -159,13 +176,13 @@
 template<class TYPE> inline
 SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
     SortedVectorImpl::operator = (rhs);
-    return *this; 
+    return *this;
 }
 
 template<class TYPE> inline
 const SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
     SortedVectorImpl::operator = (rhs);
-    return *this; 
+    return *this;
 }
 
 template<class TYPE> inline
diff --git a/libziparchive/testdata/bad_filename.zip b/libziparchive/testdata/bad_filename.zip
new file mode 100644
index 0000000..294eaf5
--- /dev/null
+++ b/libziparchive/testdata/bad_filename.zip
Binary files differ
diff --git a/libziparchive/testdata/crash.apk b/libziparchive/testdata/crash.apk
new file mode 100644
index 0000000..d6dd52d
--- /dev/null
+++ b/libziparchive/testdata/crash.apk
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 0ac6f2c..c2055b7 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -373,6 +373,11 @@
   archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
   archive->hash_table = reinterpret_cast<ZipString*>(calloc(archive->hash_table_size,
       sizeof(ZipString)));
+  if (archive->hash_table == nullptr) {
+    ALOGW("Zip: unable to allocate the %u-entry hash_table, entry size: %zu",
+          archive->hash_table_size, sizeof(ZipString));
+    return -1;
+  }
 
   /*
    * Walk through the central directory, adding entries to the hash
@@ -405,6 +410,11 @@
     const uint16_t comment_length = cdr->comment_length;
     const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
 
+    if (file_name + file_name_length > cd_end) {
+      ALOGW("Zip: file name boundary exceeds the central directory range, file_name_length: "
+            "%" PRIx16 ", cd_length: %zu", file_name_length, cd_length);
+      return -1;
+    }
     /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
     if (!IsValidEntryName(file_name, file_name_length)) {
       return -1;
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 9dd6cc0..493a0ce 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -38,6 +38,8 @@
 static const std::string kValidZip = "valid.zip";
 static const std::string kLargeZip = "large.zip";
 static const std::string kBadCrcZip = "bad_crc.zip";
+static const std::string kCrashApk = "crash.apk";
+static const std::string kBadFilenameZip = "bad_filename.zip";
 static const std::string kUpdateZip = "dummy-update.zip";
 
 static const std::vector<uint8_t> kATxtContents {
@@ -83,7 +85,15 @@
 TEST(ziparchive, Open) {
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+  CloseArchive(handle);
 
+  ASSERT_EQ(-1, OpenArchiveWrapper(kBadFilenameZip, &handle));
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, OutOfBound) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(-8, OpenArchiveWrapper(kCrashApk, &handle));
   CloseArchive(handle);
 }
 
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 7613c1e..e03731b 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -183,7 +183,8 @@
     lenr -= avcr - msgr;
     if (lenl != lenr) return DIFFERENT;
     if (fastcmp<memcmp>(avcl + strlen(avc),
-                        avcr + strlen(avc), lenl)) return DIFFERENT;
+                        avcr + strlen(avc),
+                        lenl - strlen(avc))) return DIFFERENT;
     return SAME;
 }
 
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index e6c94ff..4081982 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -1,4 +1,5 @@
 libandroid.so
+libaaudio.so
 libc.so
 libcamera2ndk.so
 libdl.so
diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt
index 292730a..9f0cde1 100644
--- a/rootdir/etc/public.libraries.wear.txt
+++ b/rootdir/etc/public.libraries.wear.txt
@@ -1,4 +1,5 @@
 libandroid.so
+libaaudio.so
 libc.so
 libcamera2ndk.so
 libdl.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1e5fa50..fe7e3d0 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -306,7 +306,8 @@
     # Mount shared so changes propagate into child namespaces
     mount rootfs rootfs / shared rec
     # Mount default storage into root namespace
-    mount none /mnt/runtime/default /storage slave bind rec
+    mount none /mnt/runtime/default /storage bind rec
+    mount none none /storage slave rec
 
     # Make sure /sys/kernel/debug (if present) is labeled properly
     # Note that tracefs may be mounted under debug, so we need to cross filesystems
@@ -647,10 +648,9 @@
     critical
     seclabel u:r:ueventd:s0
 
-service healthd /sbin/healthd
+service healthd /system/bin/healthd
     class core
     critical
-    seclabel u:r:healthd:s0
     group root system wakelock
 
 service console /system/bin/sh
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 36bb443..09db7b0 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -13,7 +13,7 @@
     onrestart restart wificond
     writepid /dev/cpuset/foreground/tasks
 
-service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
+service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
     class main
     priority -20
     user root
diff --git a/sdcard/fuse.cpp b/sdcard/fuse.cpp
index 3f0f95f..95559d7 100644
--- a/sdcard/fuse.cpp
+++ b/sdcard/fuse.cpp
@@ -997,7 +997,7 @@
 {
     struct node* node;
     char path[PATH_MAX];
-    struct fuse_open_out out;
+    struct fuse_open_out out = {};
     struct handle *h;
 
     pthread_mutex_lock(&fuse->global->lock);
@@ -1026,13 +1026,6 @@
     }
     out.fh = ptr_to_id(h);
     out.open_flags = 0;
-
-#ifdef FUSE_SHORTCIRCUIT
-    out.lower_fd = h->fd;
-#else
-    out.padding = 0;
-#endif
-
     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
     return NO_STATUS;
 }
@@ -1169,7 +1162,7 @@
 {
     struct node* node;
     char path[PATH_MAX];
-    struct fuse_open_out out;
+    struct fuse_open_out out = {};
     struct dirhandle *h;
 
     pthread_mutex_lock(&fuse->global->lock);
@@ -1196,13 +1189,6 @@
     }
     out.fh = ptr_to_id(h);
     out.open_flags = 0;
-
-#ifdef FUSE_SHORTCIRCUIT
-    out.lower_fd = -1;
-#else
-    out.padding = 0;
-#endif
-
     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
     return NO_STATUS;
 }
@@ -1282,11 +1268,6 @@
     out.major = FUSE_KERNEL_VERSION;
     out.max_readahead = req->max_readahead;
     out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
-
-#ifdef FUSE_SHORTCIRCUIT
-    out.flags |= FUSE_SHORTCIRCUIT;
-#endif
-
     out.max_background = 32;
     out.congestion_threshold = 32;
     out.max_write = MAX_WRITE;
diff --git a/storaged/Android.mk b/storaged/Android.mk
new file mode 100644
index 0000000..2adb14d
--- /dev/null
+++ b/storaged/Android.mk
@@ -0,0 +1,44 @@
+# Copyright 2016 The Android Open Source Project
+
+LOCAL_PATH := $(call my-dir)
+
+LIBSTORAGED_SHARED_LIBRARIES := \
+    libbinder \
+    libbase \
+    libutils \
+    libcutils \
+    liblog \
+    libsysutils \
+    libpackagelistparser \
+    libbatteryservice \
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    storaged.cpp \
+    storaged_service.cpp \
+    storaged_utils.cpp \
+    storaged_uid_monitor.cpp \
+    EventLogTags.logtags
+
+LOCAL_MODULE := libstoraged
+LOCAL_CFLAGS := -Werror
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include external/googletest/googletest/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := $(LIBSTORAGED_SHARED_LIBRARIES)
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := storaged
+LOCAL_INIT_RC := storaged.rc
+LOCAL_SRC_FILES := main.cpp
+# libstoraged is an internal static library, only main.cpp and storaged_test.cpp should be using it
+LOCAL_STATIC_LIBRARIES := libstoraged
+LOCAL_SHARED_LIBRARIES := $(LIBSTORAGED_SHARED_LIBRARIES)
+LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
+LOCAL_C_INCLUDES := external/googletest/googletest/include
+
+include $(BUILD_EXECUTABLE)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/storaged/EventLogTags.logtags b/storaged/EventLogTags.logtags
new file mode 100644
index 0000000..2e25d4a
--- /dev/null
+++ b/storaged/EventLogTags.logtags
@@ -0,0 +1,39 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31.  (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_".  Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace.  Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+#    (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+# 5: float
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+2732 storaged_disk_stats (type|3),(start_time|2|3),(end_time|2|3),(read_ios|2|1),(read_merges|2|1),(read_sectors|2|1),(read_ticks|2|3),(write_ios|2|1),(write_merges|2|1),(write_sectors|2|1),(write_ticks|2|3),(o_in_flight|2|1),(io_ticks|2|3),(io_in_queue|2|1)
+
+2733 storaged_emmc_info (mmc_ver|3),(eol|1),(lifetime_a|1),(lifetime_b|1)
\ No newline at end of file
diff --git a/storaged/README.properties b/storaged/README.properties
new file mode 100644
index 0000000..70e6026
--- /dev/null
+++ b/storaged/README.properties
@@ -0,0 +1,6 @@
+ro.storaged.event.interval    # interval storaged scans for IO stats, in seconds
+ro.storaged.event.perf_check  # check for time spent in event loop, in microseconds
+ro.storaged.disk_stats_pub    # interval storaged publish disk stats, in seconds
+ro.storaged.emmc_info_pub     # interval storaged publish emmc info, in seconds
+ro.storaged.uid_io.interval   # interval storaged checks Per UID IO usage, in seconds
+ro.storaged.uid_io.threshold  # Per UID IO usage limit, in bytes
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
new file mode 100644
index 0000000..591719e
--- /dev/null
+++ b/storaged/include/storaged.h
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _STORAGED_H_
+#define _STORAGED_H_
+
+#include <semaphore.h>
+#include <stdint.h>
+#include <time.h>
+
+#include <queue>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <batteryservice/IBatteryPropertiesListener.h>
+
+#include "storaged_uid_monitor.h"
+
+using namespace android;
+
+#define FRIEND_TEST(test_case_name, test_name) \
+friend class test_case_name##_##test_name##_Test
+
+/* For debug */
+#ifdef DEBUG
+#define debuginfo(fmt, ...) \
+ do {printf("%s():\t" fmt "\t[%s:%d]\n", __FUNCTION__, ##__VA_ARGS__, __FILE__, __LINE__);} \
+ while(0)
+#else
+#define debuginfo(...)
+#endif
+
+#define SECTOR_SIZE ( 512 )
+#define SEC_TO_MSEC ( 1000 )
+#define MSEC_TO_USEC ( 1000 )
+#define USEC_TO_NSEC ( 1000 )
+#define SEC_TO_USEC ( 1000000 )
+#define HOUR_TO_SEC ( 3600 )
+#define DAY_TO_SEC ( 3600 * 24 )
+
+// number of attributes diskstats has
+#define DISK_STATS_SIZE ( 11 )
+// maximum size limit of a stats file
+#define DISK_STATS_FILE_MAX_SIZE ( 256 )
+#define DISK_STATS_IO_IN_FLIGHT_IDX ( 8 )
+struct disk_stats {
+    /* It will be extremely unlikely for any of the following entries to overflow.
+     * For read_bytes(which will be greater than any of the following entries), it
+     * will take 27 years to overflow uint64_t at the reading rate of 20GB/s, which
+     * is the peak memory transfer rate for current memory.
+     * The diskstats entries (first 11) need to be at top in this structure _after_
+     * compiler's optimization.
+     */
+    uint64_t read_ios;       // number of read I/Os processed
+    uint64_t read_merges;    // number of read I/Os merged with in-queue I/Os
+    uint64_t read_sectors;   // number of sectors read
+    uint64_t read_ticks;     // total wait time for read requests
+    uint64_t write_ios;      // number of write I/Os processed
+    uint64_t write_merges;   // number of write I/Os merged with in-queue I/Os
+    uint64_t write_sectors;  // number of sectors written
+    uint64_t write_ticks;    // total wait time for write requests
+    uint64_t io_in_flight;   // number of I/Os currently in flight
+    uint64_t io_ticks;       // total time this block device has been active
+    uint64_t io_in_queue;    // total wait time for all requests
+
+    uint64_t start_time;     // monotonic time accounting starts
+    uint64_t end_time;       // monotonic time accounting ends
+    uint32_t counter;        // private counter for accumulate calculations
+    double   io_avg;         // average io_in_flight for accumulate calculations
+};
+
+#define MMC_VER_STR_LEN ( 9 )   // maximum length of the MMC version string, including NULL terminator
+// minimum size of a ext_csd file
+#define EXT_CSD_FILE_MIN_SIZE ( 1024 )
+struct emmc_info {
+    int eol;                        // pre-eol (end of life) information
+    int lifetime_a;                 // device life time estimation (type A)
+    int lifetime_b;                 // device life time estimation (type B)
+    char mmc_ver[MMC_VER_STR_LEN];  // device version string
+};
+
+struct disk_perf {
+    uint32_t read_perf;         // read speed (kbytes/s)
+    uint32_t read_ios;          // read I/Os per second
+    uint32_t write_perf;        // write speed (kbytes/s)
+    uint32_t write_ios;         // write I/Os per second
+    uint32_t queue;             // I/Os in queue
+};
+
+#define CMD_MAX_LEN ( 64 )
+struct task_info {
+    uint32_t pid;                   // task id
+    uint64_t rchar;                 // characters read
+    uint64_t wchar;                 // characters written
+    uint64_t syscr;                 // read syscalls
+    uint64_t syscw;                 // write syscalls
+    uint64_t read_bytes;            // bytes read (from storage layer)
+    uint64_t write_bytes;           // bytes written (to storage layer)
+    uint64_t cancelled_write_bytes; // cancelled write byte by truncate
+
+    uint64_t starttime;             // start time of task
+
+    char cmd[CMD_MAX_LEN];          // filename of the executable
+};
+
+class lock_t {
+    sem_t* mSem;
+public:
+    lock_t(sem_t* sem) {
+        mSem = sem;
+        sem_wait(mSem);
+    }
+    ~lock_t() {
+        sem_post(mSem);
+    }
+};
+
+class stream_stats {
+private:
+    double mSum;
+    double mSquareSum;
+    uint32_t mCnt;
+public:
+    stream_stats() : mSum(0), mSquareSum(0), mCnt(0) {};
+    ~stream_stats() {};
+    double get_mean() {
+        return mSum / mCnt;
+    }
+    double get_std() {
+        return sqrt(mSquareSum / mCnt - mSum * mSum / (mCnt * mCnt));
+    }
+    void add(uint32_t num) {
+        mSum += (double)num;
+        mSquareSum += (double)num * (double)num;
+        mCnt++;
+    }
+    void evict(uint32_t num) {
+        if (mSum < num || mSquareSum < (double)num * (double)num) return;
+        mSum -= (double)num;
+        mSquareSum -= (double)num * (double)num;
+        mCnt--;
+    }
+};
+
+#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat"
+#define SDA_DISK_STATS_PATH "/sys/block/sda/stat"
+#define EMMC_ECSD_PATH "/d/mmc0/mmc0:0001/ext_csd"
+#define UID_IO_STATS_PATH "/proc/uid_io/stats"
+
+class disk_stats_monitor {
+private:
+    FRIEND_TEST(storaged_test, disk_stats_monitor);
+    const char* DISK_STATS_PATH;
+    struct disk_stats mPrevious;
+    struct disk_stats mAccumulate;
+    bool mStall;
+    std::queue<struct disk_perf> mBuffer;
+    struct {
+        stream_stats read_perf;           // read speed (bytes/s)
+        stream_stats read_ios;            // read I/Os per second
+        stream_stats write_perf;          // write speed (bytes/s)
+        stream_stats write_ios;           // write I/O per second
+        stream_stats queue;               // I/Os in queue
+    } mStats;
+    bool mValid;
+    const uint32_t mWindow;
+    const double mSigma;
+    struct disk_perf mMean;
+    struct disk_perf mStd;
+
+    void update_mean();
+    void update_std();
+    void add(struct disk_perf* perf);
+    void evict(struct disk_perf* perf);
+    bool detect(struct disk_perf* perf);
+
+    void update(struct disk_stats* stats);
+
+public:
+    disk_stats_monitor(uint32_t window_size = 5, double sigma = 1.0) :
+            mStall(false),
+            mValid(false),
+            mWindow(window_size),
+            mSigma(sigma) {
+        memset(&mPrevious, 0, sizeof(mPrevious));
+        memset(&mMean, 0, sizeof(mMean));
+        memset(&mStd, 0, sizeof(mStd));
+
+        if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
+            DISK_STATS_PATH = MMC_DISK_STATS_PATH;
+        } else {
+            DISK_STATS_PATH = SDA_DISK_STATS_PATH;
+        }
+    }
+    void update(void);
+};
+
+class disk_stats_publisher {
+private:
+    FRIEND_TEST(storaged_test, disk_stats_publisher);
+    const char* DISK_STATS_PATH;
+    struct disk_stats mAccumulate;
+    struct disk_stats mPrevious;
+public:
+    disk_stats_publisher(void) {
+        memset(&mAccumulate, 0, sizeof(struct disk_stats));
+        memset(&mPrevious, 0, sizeof(struct disk_stats));
+
+        if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
+            DISK_STATS_PATH = MMC_DISK_STATS_PATH;
+        } else {
+            DISK_STATS_PATH = SDA_DISK_STATS_PATH;
+        }
+    }
+
+    ~disk_stats_publisher(void) {}
+    void publish(void);
+    void update(void);
+};
+
+class emmc_info_t {
+private:
+    struct emmc_info mInfo;
+    bool mValid;
+    int mFdEmmc;
+public:
+    emmc_info_t(void) :
+            mValid(false),
+            mFdEmmc(-1) {
+        memset(&mInfo, 0, sizeof(struct emmc_info));
+    }
+    ~emmc_info_t(void) {}
+
+    void publish(void);
+    void update(void);
+    void set_emmc_fd(int fd) {
+        mFdEmmc = fd;
+    }
+};
+
+// Periodic chores intervals in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 60 )
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 )
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH ( 86400 )
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 3600 )
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT (300)
+
+// UID IO threshold in bytes
+#define DEFAULT_PERIODIC_CHORES_UID_IO_THRESHOLD ( 1024 * 1024 * 1024ULL )
+
+struct storaged_config {
+    int periodic_chores_interval_unit;
+    int periodic_chores_interval_disk_stats_publish;
+    int periodic_chores_interval_emmc_info_publish;
+    int periodic_chores_interval_uid_io;
+    bool proc_uid_io_available;      // whether uid_io is accessible
+    bool emmc_available;        // whether eMMC est_csd file is readable
+    bool diskstats_available;   // whether diskstats is accessible
+    int event_time_check_usec;  // check how much cputime spent in event loop
+};
+
+class storaged_t : public BnBatteryPropertiesListener {
+private:
+    time_t mTimer;
+    storaged_config mConfig;
+    disk_stats_publisher mDiskStats;
+    disk_stats_monitor mDsm;
+    emmc_info_t mEmmcInfo;
+    uid_monitor mUidm;
+    time_t mStarttime;
+public:
+    storaged_t(void);
+    ~storaged_t() {}
+    void event(void);
+    void event_checked(void);
+    void pause(void) {
+        sleep(mConfig.periodic_chores_interval_unit);
+    }
+    void set_privileged_fds(int fd_emmc) {
+        mEmmcInfo.set_emmc_fd(fd_emmc);
+    }
+
+    time_t get_starttime(void) {
+        return mStarttime;
+    }
+
+    std::unordered_map<uint32_t, struct uid_info> get_uids(void) {
+        return mUidm.get_uid_io_stats();
+    }
+    std::map<uint64_t, std::vector<struct uid_record>> get_uid_records(
+            double hours, uint64_t threshold, bool force_report) {
+        return mUidm.dump(hours, threshold, force_report);
+    }
+    void update_uid_io_interval(int interval) {
+        if (interval >= DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT) {
+            mConfig.periodic_chores_interval_uid_io = interval;
+        }
+    }
+
+    void init_battery_service();
+    virtual void batteryPropertiesChanged(struct BatteryProperties props);
+};
+
+// Eventlog tag
+// The content must match the definition in EventLogTags.logtags
+#define EVENTLOGTAG_DISKSTATS ( 2732 )
+#define EVENTLOGTAG_EMMCINFO ( 2733 )
+#define EVENTLOGTAG_UID_IO_ALERT ( 2734 )
+
+#endif /* _STORAGED_H_ */
diff --git a/storaged/include/storaged_service.h b/storaged/include/storaged_service.h
new file mode 100644
index 0000000..a8ddf4c
--- /dev/null
+++ b/storaged/include/storaged_service.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _STORAGED_SERVICE_H_
+#define _STORAGED_SERVICE_H_
+
+#include <vector>
+
+#include <binder/IInterface.h>
+#include <binder/IBinder.h>
+
+#include "storaged.h"
+
+using namespace android;
+
+// Interface
+class IStoraged : public IInterface {
+public:
+    enum {
+        DUMPUIDS  = IBinder::FIRST_CALL_TRANSACTION,
+    };
+    // Request the service to run the test function
+    virtual std::vector<struct uid_info> dump_uids(const char* option) = 0;
+
+    DECLARE_META_INTERFACE(Storaged);
+};
+
+// Client
+class BpStoraged : public BpInterface<IStoraged> {
+public:
+    BpStoraged(const sp<IBinder>& impl) : BpInterface<IStoraged>(impl){};
+    virtual std::vector<struct uid_info> dump_uids(const char* option);
+};
+
+// Server
+class BnStoraged : public BnInterface<IStoraged> {
+    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
+};
+
+class Storaged : public BnStoraged {
+    virtual std::vector<struct uid_info> dump_uids(const char* option);
+    virtual status_t dump(int fd, const Vector<String16>& args);
+};
+
+sp<IStoraged> get_storaged_service();
+
+#endif /* _STORAGED_SERVICE_H_ */
\ No newline at end of file
diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h
new file mode 100644
index 0000000..031b7c4
--- /dev/null
+++ b/storaged/include/storaged_uid_monitor.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _STORAGED_UID_MONITOR_H_
+#define _STORAGED_UID_MONITOR_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+enum uid_stat_t {
+    FOREGROUND = 0,
+    BACKGROUND = 1,
+    UID_STATS = 2
+};
+
+enum charger_stat_t {
+    CHARGER_OFF = 0,
+    CHARGER_ON = 1,
+    CHARGER_STATS = 2
+};
+
+enum io_type_t {
+    READ = 0,
+    WRITE = 1,
+    IO_TYPES = 2
+};
+
+struct uid_io_stats {
+    uint64_t rchar;                 // characters read
+    uint64_t wchar;                 // characters written
+    uint64_t read_bytes;            // bytes read (from storage layer)
+    uint64_t write_bytes;           // bytes written (to storage layer)
+};
+
+struct uid_info {
+    uint32_t uid;                   // user id
+    std::string name;               // package name
+    struct uid_io_stats io[UID_STATS];    // [0]:foreground [1]:background
+};
+
+struct uid_io_usage {
+    uint64_t bytes[IO_TYPES][UID_STATS][CHARGER_STATS];
+};
+
+struct uid_record {
+    std::string name;
+    struct uid_io_usage ios;
+};
+
+class uid_monitor {
+private:
+    // last dump from /proc/uid_io/stats, uid -> uid_info
+    std::unordered_map<uint32_t, struct uid_info> last_uid_io_stats;
+    // current io usage for next report, app name -> uid_io_usage
+    std::unordered_map<std::string, struct uid_io_usage> curr_io_stats;
+    // io usage records, timestamp -> vector of events
+    std::map<uint64_t, std::vector<struct uid_record>> records;
+    // charger ON/OFF
+    charger_stat_t charger_stat;
+    // protects curr_io_stats, last_uid_io_stats, records and charger_stat
+    sem_t um_lock;
+
+    // reads from /proc/uid_io/stats
+    std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats_locked();
+    // flushes curr_io_stats to records
+    void add_records_locked(uint64_t curr_ts);
+    // updates curr_io_stats and set last_uid_io_stats
+    void update_curr_io_stats_locked();
+
+public:
+    uid_monitor();
+    ~uid_monitor();
+    // called by storaged main thread
+    void init(charger_stat_t stat);
+    // called by storaged -u
+    std::unordered_map<uint32_t, struct uid_info> get_uid_io_stats();
+    // called by dumpsys
+    std::map<uint64_t, std::vector<struct uid_record>> dump(
+        double hours, uint64_t threshold, bool force_report);
+    // called by battery properties listener
+    void set_charger_state(charger_stat_t stat);
+    // called by storaged periodic_chore or dump with force_report
+    void report();
+};
+
+#endif /* _STORAGED_UID_MONITOR_H_ */
diff --git a/storaged/include/storaged_utils.h b/storaged/include/storaged_utils.h
new file mode 100644
index 0000000..2161c40
--- /dev/null
+++ b/storaged/include/storaged_utils.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef _STORAGED_UTILS_H_
+#define _STORAGED_UTILS_H_
+
+#include <stdint.h>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "storaged.h"
+
+// Diskstats
+bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats);
+struct disk_perf get_disk_perf(struct disk_stats* stats);
+struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr);
+void add_disk_stats(struct disk_stats* src, struct disk_stats* dst);
+bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info);
+
+// UID I/O
+void sort_running_uids_info(std::vector<struct uid_info> &uids);
+
+// Logging
+void log_console_running_uids_info(std::vector<struct uid_info> uids);
+
+void log_debug_disk_perf(struct disk_perf* perf, const char* type);
+
+void log_event_disk_stats(struct disk_stats* stats, const char* type);
+void log_event_emmc_info(struct emmc_info* info_);
+#endif /* _STORAGED_UTILS_H_ */
diff --git a/storaged/main.cpp b/storaged/main.cpp
new file mode 100644
index 0000000..f5a8f39
--- /dev/null
+++ b/storaged/main.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "storaged"
+#define KLOG_LEVEL 6
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <vector>
+
+#include <android-base/macros.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <cutils/android_get_control_file.h>
+#include <cutils/sched_policy.h>
+#include <private/android_filesystem_config.h>
+
+#include <storaged.h>
+#include <storaged_service.h>
+#include <storaged_utils.h>
+
+storaged_t storaged;
+
+static int drop_privs() {
+    // privilege setting
+    struct sched_param param;
+    memset(&param, 0, sizeof(param));
+
+    if (set_sched_policy(0, SP_BACKGROUND) < 0) return -1;
+
+    if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) return -1;
+
+    if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) return -1;
+
+    return 0;
+}
+
+// Function of storaged's main thread
+void* storaged_main(void* s) {
+    storaged_t* storaged = (storaged_t*)s;
+
+    storaged->init_battery_service();
+
+    LOG_TO(SYSTEM, INFO) << "storaged: Start";
+
+    for (;;) {
+        storaged->event_checked();
+        storaged->pause();
+    }
+    return NULL;
+}
+
+static void help_message(void) {
+    printf("usage: storaged [OPTION]\n");
+    printf("  -u    --uid                   Dump uid I/O usage to stdout\n");
+    printf("  -s    --start                 Start storaged (default)\n");
+    fflush(stdout);
+}
+
+int main(int argc, char** argv) {
+    int flag_main_service = 0;
+    int flag_dump_uid = 0;
+    int fd_emmc = -1;
+    int opt;
+
+    for (;;) {
+        int opt_idx = 0;
+        static struct option long_options[] = {
+            {"start",       no_argument,        0, 's'},
+            {"kill",        no_argument,        0, 'k'},
+            {"uid",         no_argument,        0, 'u'},
+            {"help",        no_argument,        0, 'h'}
+        };
+        opt = getopt_long(argc, argv, ":skdhu0", long_options, &opt_idx);
+        if (opt == -1) {
+            break;
+        }
+
+        switch (opt) {
+        case 's':
+            flag_main_service = 1;
+            break;
+        case 'u':
+            flag_dump_uid = 1;
+            break;
+        case 'h':
+            help_message();
+            return 0;
+        case '?':
+        default:
+            fprintf(stderr, "no supported option\n");
+            help_message();
+            return -1;
+        }
+    }
+
+    if (argc == 1) {
+        flag_main_service = 1;
+    }
+
+    if (flag_main_service && flag_dump_uid) {
+        fprintf(stderr, "Invalid arguments. Option \"start\" and \"dump\" cannot be used together.\n");
+        help_message();
+        return -1;
+    }
+
+    if (flag_main_service) { // start main thread
+        static const char mmc0_ext_csd[] = "/d/mmc0/mmc0:0001/ext_csd";
+        fd_emmc = android_get_control_file(mmc0_ext_csd);
+        if (fd_emmc < 0)
+            fd_emmc = TEMP_FAILURE_RETRY(open(mmc0_ext_csd, O_RDONLY));
+
+        if (drop_privs() != 0) {
+            return -1;
+        }
+
+        storaged.set_privileged_fds(fd_emmc);
+
+        // Start the main thread of storaged
+        pthread_t storaged_main_thread;
+        errno = pthread_create(&storaged_main_thread, NULL, storaged_main, &storaged);
+        if (errno != 0) {
+            PLOG_TO(SYSTEM, ERROR) << "Failed to create main thread";
+            return -1;
+        }
+
+        defaultServiceManager()->addService(String16("storaged"), new Storaged());
+        android::ProcessState::self()->startThreadPool();
+        IPCThreadState::self()->joinThreadPool();
+        pthread_join(storaged_main_thread, NULL);
+
+        close(fd_emmc);
+
+        return 0;
+    }
+
+    if (flag_dump_uid) {
+        sp<IStoraged> storaged_service = get_storaged_service();
+        if (storaged_service == NULL) {
+            fprintf(stderr, "Cannot find storaged service.\nMaybe run storaged --start first?\n");
+            return -1;
+        }
+        std::vector<struct uid_info> res = storaged_service->dump_uids(NULL);
+
+        if (res.size() == 0) {
+            fprintf(stderr, "UID I/O is not readable in this version of kernel.\n");
+            return 0;
+        }
+
+        sort_running_uids_info(res);
+        log_console_running_uids_info(res);
+
+        return 0;
+    }
+
+    return 0;
+}
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
new file mode 100644
index 0000000..2f02074
--- /dev/null
+++ b/storaged/storaged.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "storaged"
+
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <batteryservice/BatteryServiceConstants.h>
+#include <batteryservice/IBatteryPropertiesRegistrar.h>
+#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
+#include <log/log.h>
+
+#include <storaged.h>
+#include <storaged_utils.h>
+
+/* disk_stats_publisher */
+void disk_stats_publisher::publish(void) {
+    // Logging
+    struct disk_perf perf = get_disk_perf(&mAccumulate);
+    log_debug_disk_perf(&perf, "regular");
+    log_event_disk_stats(&mAccumulate, "regular");
+    // Reset global structures
+    memset(&mAccumulate, 0, sizeof(struct disk_stats));
+}
+
+void disk_stats_publisher::update(void) {
+    struct disk_stats curr;
+    if (parse_disk_stats(DISK_STATS_PATH, &curr)) {
+        struct disk_stats inc = get_inc_disk_stats(&mPrevious, &curr);
+        add_disk_stats(&inc, &mAccumulate);
+#ifdef DEBUG
+//            log_kernel_disk_stats(&mPrevious, "prev stats");
+//            log_kernel_disk_stats(&curr, "curr stats");
+//            log_kernel_disk_stats(&inc, "inc stats");
+//            log_kernel_disk_stats(&mAccumulate, "accumulated stats");
+#endif
+        mPrevious = curr;
+    }
+}
+
+/* disk_stats_monitor */
+void disk_stats_monitor::update_mean() {
+    CHECK(mValid);
+    mMean.read_perf = (uint32_t)mStats.read_perf.get_mean();
+    mMean.read_ios = (uint32_t)mStats.read_ios.get_mean();
+    mMean.write_perf = (uint32_t)mStats.write_perf.get_mean();
+    mMean.write_ios = (uint32_t)mStats.write_ios.get_mean();
+    mMean.queue = (uint32_t)mStats.queue.get_mean();
+}
+
+void disk_stats_monitor::update_std() {
+    CHECK(mValid);
+    mStd.read_perf = (uint32_t)mStats.read_perf.get_std();
+    mStd.read_ios = (uint32_t)mStats.read_ios.get_std();
+    mStd.write_perf = (uint32_t)mStats.write_perf.get_std();
+    mStd.write_ios = (uint32_t)mStats.write_ios.get_std();
+    mStd.queue = (uint32_t)mStats.queue.get_std();
+}
+
+void disk_stats_monitor::add(struct disk_perf* perf) {
+    mStats.read_perf.add(perf->read_perf);
+    mStats.read_ios.add(perf->read_ios);
+    mStats.write_perf.add(perf->write_perf);
+    mStats.write_ios.add(perf->write_ios);
+    mStats.queue.add(perf->queue);
+}
+
+void disk_stats_monitor::evict(struct disk_perf* perf) {
+    mStats.read_perf.evict(perf->read_perf);
+    mStats.read_ios.evict(perf->read_ios);
+    mStats.write_perf.evict(perf->write_perf);
+    mStats.write_ios.evict(perf->write_ios);
+    mStats.queue.evict(perf->queue);
+}
+
+bool disk_stats_monitor::detect(struct disk_perf* perf) {
+    return ((double)perf->queue >= (double)mMean.queue + mSigma * (double)mStd.queue) &&
+            ((double)perf->read_perf < (double)mMean.read_perf - mSigma * (double)mStd.read_perf) &&
+            ((double)perf->write_perf < (double)mMean.write_perf - mSigma * (double)mStd.write_perf);
+}
+
+void disk_stats_monitor::update(struct disk_stats* stats) {
+    struct disk_stats inc = get_inc_disk_stats(&mPrevious, stats);
+    struct disk_perf perf = get_disk_perf(&inc);
+    // Update internal data structures
+    if (LIKELY(mValid)) {
+        CHECK_EQ(mBuffer.size(), mWindow);
+
+        if (UNLIKELY(detect(&perf))) {
+            mStall = true;
+            add_disk_stats(&inc, &mAccumulate);
+            log_debug_disk_perf(&mMean, "stalled_mean");
+            log_debug_disk_perf(&mStd, "stalled_std");
+        } else {
+            if (mStall) {
+                struct disk_perf acc_perf = get_disk_perf(&mAccumulate);
+                log_debug_disk_perf(&acc_perf, "stalled");
+                log_event_disk_stats(&mAccumulate, "stalled");
+                mStall = false;
+                memset(&mAccumulate, 0, sizeof(mAccumulate));
+            }
+        }
+
+        evict(&mBuffer.front());
+        mBuffer.pop();
+        add(&perf);
+        mBuffer.push(perf);
+
+        update_mean();
+        update_std();
+
+    } else { /* mValid == false */
+        CHECK_LT(mBuffer.size(), mWindow);
+        add(&perf);
+        mBuffer.push(perf);
+        if (mBuffer.size() == mWindow) {
+            mValid = true;
+            update_mean();
+            update_std();
+        }
+    }
+
+    mPrevious = *stats;
+}
+
+void disk_stats_monitor::update(void) {
+    struct disk_stats curr;
+    if (LIKELY(parse_disk_stats(DISK_STATS_PATH, &curr))) {
+        update(&curr);
+    }
+}
+
+/* emmc_info_t */
+void emmc_info_t::publish(void) {
+    if (mValid) {
+        log_event_emmc_info(&mInfo);
+    }
+}
+
+void emmc_info_t::update(void) {
+    if (mFdEmmc >= 0) {
+        mValid = parse_emmc_ecsd(mFdEmmc, &mInfo);
+    }
+}
+
+static sp<IBatteryPropertiesRegistrar> get_battery_properties_service() {
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == NULL) return NULL;
+
+    sp<IBinder> binder = sm->getService(String16("batteryproperties"));
+    if (binder == NULL) return NULL;
+
+    sp<IBatteryPropertiesRegistrar> battery_properties =
+        interface_cast<IBatteryPropertiesRegistrar>(binder);
+
+    return battery_properties;
+}
+
+static inline charger_stat_t is_charger_on(int64_t prop) {
+    return (prop == BATTERY_STATUS_CHARGING || prop == BATTERY_STATUS_FULL) ?
+        CHARGER_ON : CHARGER_OFF;
+}
+
+void storaged_t::batteryPropertiesChanged(struct BatteryProperties props) {
+    mUidm.set_charger_state(is_charger_on(props.batteryStatus));
+}
+
+void storaged_t::init_battery_service() {
+    sp<IBatteryPropertiesRegistrar> battery_properties = get_battery_properties_service();
+    if (battery_properties == NULL) {
+        LOG_TO(SYSTEM, WARNING) << "failed to find batteryproperties service";
+        return;
+    }
+
+    struct BatteryProperty val;
+    battery_properties->getProperty(BATTERY_PROP_BATTERY_STATUS, &val);
+    mUidm.init(is_charger_on(val.valueInt64));
+
+    // register listener after init uid_monitor
+    battery_properties->registerListener(this);
+}
+
+/* storaged_t */
+storaged_t::storaged_t(void) {
+    mConfig.emmc_available = (access(EMMC_ECSD_PATH, R_OK) >= 0);
+
+    if (access(MMC_DISK_STATS_PATH, R_OK) < 0 && access(SDA_DISK_STATS_PATH, R_OK) < 0) {
+        mConfig.diskstats_available = false;
+    } else {
+        mConfig.diskstats_available = true;
+    }
+
+    mConfig.proc_uid_io_available = (access(UID_IO_STATS_PATH, R_OK) == 0);
+
+    mConfig.periodic_chores_interval_unit =
+        property_get_int32("ro.storaged.event.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT);
+
+    mConfig.event_time_check_usec =
+        property_get_int32("ro.storaged.event.perf_check", 0);
+
+    mConfig.periodic_chores_interval_disk_stats_publish =
+        property_get_int32("ro.storaged.disk_stats_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH);
+
+    mConfig.periodic_chores_interval_emmc_info_publish =
+        property_get_int32("ro.storaged.emmc_info_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH);
+
+    mConfig.periodic_chores_interval_uid_io =
+        property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
+
+    mStarttime = time(NULL);
+}
+
+void storaged_t::event(void) {
+    if (mConfig.diskstats_available) {
+        mDiskStats.update();
+        mDsm.update();
+        if (mTimer && (mTimer % mConfig.periodic_chores_interval_disk_stats_publish) == 0) {
+            mDiskStats.publish();
+        }
+    }
+
+    if (mConfig.emmc_available && mTimer &&
+            (mTimer % mConfig.periodic_chores_interval_emmc_info_publish) == 0) {
+        mEmmcInfo.update();
+        mEmmcInfo.publish();
+    }
+
+    if (mConfig.proc_uid_io_available && mTimer &&
+            (mTimer % mConfig.periodic_chores_interval_uid_io) == 0) {
+         mUidm.report();
+    }
+
+    mTimer += mConfig.periodic_chores_interval_unit;
+}
+
+void storaged_t::event_checked(void) {
+    struct timespec start_ts, end_ts;
+    bool check_time = true;
+
+    if (mConfig.event_time_check_usec &&
+        clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ts) < 0) {
+        check_time = false;
+        static time_t state_a;
+        IF_ALOG_RATELIMIT_LOCAL(300, &state_a) {
+            PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+        }
+    }
+
+    event();
+
+    if (mConfig.event_time_check_usec && check_time) {
+        if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ts) < 0) {
+            static time_t state_b;
+            IF_ALOG_RATELIMIT_LOCAL(300, &state_b) {
+                PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+            }
+            return;
+        }
+        int64_t cost = (end_ts.tv_sec - start_ts.tv_sec) * SEC_TO_USEC +
+                       (end_ts.tv_nsec - start_ts.tv_nsec) / USEC_TO_NSEC;
+        if (cost > mConfig.event_time_check_usec) {
+            LOG_TO(SYSTEM, ERROR)
+                << "event loop spent " << cost << " usec, threshold "
+                << mConfig.event_time_check_usec << " usec";
+        }
+    }
+}
diff --git a/storaged/storaged.rc b/storaged/storaged.rc
new file mode 100644
index 0000000..bb7c623
--- /dev/null
+++ b/storaged/storaged.rc
@@ -0,0 +1,6 @@
+service storaged /system/bin/storaged
+    class main
+    file /d/mmc0/mmc0:0001/ext_csd r
+    writepid /dev/cpuset/system-background/tasks
+    user root
+    group system package_info
\ No newline at end of file
diff --git a/storaged/storaged_service.cpp b/storaged/storaged_service.cpp
new file mode 100644
index 0000000..9c8cbf0
--- /dev/null
+++ b/storaged/storaged_service.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 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 <stdint.h>
+
+#include <vector>
+
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include <private/android_filesystem_config.h>
+
+#include <storaged.h>
+#include <storaged_service.h>
+
+extern storaged_t storaged;
+
+std::vector<struct uid_info> BpStoraged::dump_uids(const char* /*option*/) {
+    Parcel data, reply;
+    data.writeInterfaceToken(IStoraged::getInterfaceDescriptor());
+
+    remote()->transact(DUMPUIDS, data, &reply);
+
+    uint32_t res_size = reply.readInt32();
+    std::vector<struct uid_info> res(res_size);
+    for (auto&& uid : res) {
+        uid.uid = reply.readInt32();
+        uid.name = reply.readCString();
+        reply.read(&uid.io, sizeof(uid.io));
+    }
+    return res;
+}
+IMPLEMENT_META_INTERFACE(Storaged, "Storaged");
+
+status_t BnStoraged::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    switch(code) {
+        case DUMPUIDS: {
+                if (!data.checkInterface(this))
+                    return BAD_TYPE;
+                std::vector<struct uid_info> res = dump_uids(NULL);
+                reply->writeInt32(res.size());
+                for (auto uid : res) {
+                    reply->writeInt32(uid.uid);
+                    reply->writeCString(uid.name.c_str());
+                    reply->write(&uid.io, sizeof(uid.io));
+                }
+                return NO_ERROR;
+            }
+            break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+std::vector<struct uid_info> Storaged::dump_uids(const char* /* option */) {
+    std::vector<struct uid_info> uids_v;
+    std::unordered_map<uint32_t, struct uid_info> uids_m = storaged.get_uids();
+
+    for (const auto& it : uids_m) {
+        uids_v.push_back(it.second);
+    }
+    return uids_v;
+}
+
+status_t Storaged::dump(int fd, const Vector<String16>& args) {
+    IPCThreadState* self = IPCThreadState::self();
+    const int pid = self->getCallingPid();
+    const int uid = self->getCallingUid();
+    if ((uid != AID_SHELL) &&
+        !PermissionCache::checkPermission(
+                String16("android.permission.DUMP"), pid, uid)) {
+        return PERMISSION_DENIED;
+    }
+
+    double hours = 0;
+    int time_window = 0;
+    uint64_t threshold = 0;
+    bool force_report = false;
+    for (size_t i = 0; i < args.size(); i++) {
+        const auto& arg = args[i];
+        if (arg == String16("--hours")) {
+            if (++i >= args.size())
+                break;
+            hours = stod(String16::std_string(args[i]));
+            continue;
+        }
+        if (arg == String16("--time_window")) {
+            if (++i >= args.size())
+                break;
+            time_window = stoi(String16::std_string(args[i]));
+            continue;
+        }
+        if (arg == String16("--threshold")) {
+            if (++i >= args.size())
+                break;
+            threshold = stoll(String16::std_string(args[i]));
+            continue;
+        }
+        if (arg == String16("--force")) {
+            force_report = true;
+            continue;
+        }
+    }
+
+    const std::map<uint64_t, std::vector<struct uid_record>>& records =
+                storaged.get_uid_records(hours, threshold, force_report);
+    for (const auto& it : records) {
+        dprintf(fd, "%llu\n", (unsigned long long)it.first);
+        for (const auto& record : it.second) {
+            dprintf(fd, "%s %llu %llu %llu %llu %llu %llu %llu %llu\n",
+                record.name.c_str(),
+                (unsigned long long)record.ios.bytes[READ][FOREGROUND][CHARGER_OFF],
+                (unsigned long long)record.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF],
+                (unsigned long long)record.ios.bytes[READ][BACKGROUND][CHARGER_OFF],
+                (unsigned long long)record.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF],
+                (unsigned long long)record.ios.bytes[READ][FOREGROUND][CHARGER_ON],
+                (unsigned long long)record.ios.bytes[WRITE][FOREGROUND][CHARGER_ON],
+                (unsigned long long)record.ios.bytes[READ][BACKGROUND][CHARGER_ON],
+                (unsigned long long)record.ios.bytes[WRITE][BACKGROUND][CHARGER_ON]);
+        }
+    }
+
+    if (time_window) {
+        storaged.update_uid_io_interval(time_window);
+    }
+
+    return NO_ERROR;
+}
+
+sp<IStoraged> get_storaged_service() {
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == NULL) return NULL;
+
+    sp<IBinder> binder = sm->getService(String16("storaged"));
+    if (binder == NULL) return NULL;
+
+    sp<IStoraged> storaged = interface_cast<IStoraged>(binder);
+
+    return storaged;
+}
diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp
new file mode 100644
index 0000000..49d0d48
--- /dev/null
+++ b/storaged/storaged_uid_monitor.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "storaged"
+
+#include <stdint.h>
+#include <time.h>
+
+#include <string>
+#include <sstream>
+#include <unordered_map>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+#include <log/log_event_list.h>
+#include <packagelistparser/packagelistparser.h>
+
+#include "storaged.h"
+#include "storaged_uid_monitor.h"
+
+using namespace android;
+using namespace android::base;
+
+static bool packagelist_parse_cb(pkg_info* info, void* userdata)
+{
+    std::unordered_map<uint32_t, struct uid_info>* uids =
+        reinterpret_cast<std::unordered_map<uint32_t, struct uid_info>*>(userdata);
+
+    if (uids->find(info->uid) != uids->end()) {
+        (*uids)[info->uid].name = info->name;
+    }
+
+    packagelist_free(info);
+    return true;
+}
+
+std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats()
+{
+    std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
+    return get_uid_io_stats_locked();
+};
+
+std::unordered_map<uint32_t, struct uid_info> uid_monitor::get_uid_io_stats_locked()
+{
+    std::unordered_map<uint32_t, struct uid_info> uid_io_stats;
+    std::string buffer;
+    if (!android::base::ReadFileToString(UID_IO_STATS_PATH, &buffer)) {
+        PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed";
+        return uid_io_stats;
+    }
+
+    std::stringstream ss(buffer);
+    struct uid_info u;
+    bool refresh_uid = false;
+
+    while (ss >> u.uid) {
+        ss >> u.io[FOREGROUND].rchar >> u.io[FOREGROUND].wchar
+           >> u.io[FOREGROUND].read_bytes >> u.io[FOREGROUND].write_bytes
+           >> u.io[BACKGROUND].rchar >> u.io[BACKGROUND].wchar
+           >> u.io[BACKGROUND].read_bytes >> u.io[BACKGROUND].write_bytes;
+
+        if (!ss.good()) {
+            ss.clear(std::ios_base::badbit);
+            break;
+        }
+
+        if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) {
+            refresh_uid = true;
+            u.name = std::to_string(u.uid);
+        } else {
+            u.name = last_uid_io_stats[u.uid].name;
+        }
+        uid_io_stats[u.uid] = u;
+    }
+
+    if (!ss.eof() || ss.bad()) {
+        uid_io_stats.clear();
+        LOG_TO(SYSTEM, ERROR) << "read UID IO stats failed";
+    }
+
+    if (refresh_uid) {
+        packagelist_parse(packagelist_parse_cb, &uid_io_stats);
+    }
+
+    return uid_io_stats;
+}
+
+static const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours
+
+static inline int records_size(
+    const std::map<uint64_t, std::vector<struct uid_record>>& records)
+{
+    int count = 0;
+    for (auto const& it : records) {
+        count += it.second.size();
+    }
+    return count;
+}
+
+static struct uid_io_usage zero_io_usage;
+
+void uid_monitor::add_records_locked(uint64_t curr_ts)
+{
+    // remove records more than 5 days old
+    if (curr_ts > 5 * DAY_TO_SEC) {
+        auto it = records.lower_bound(curr_ts - 5 * DAY_TO_SEC);
+        records.erase(records.begin(), it);
+    }
+
+    std::vector<struct uid_record> new_records;
+    for (const auto& p : curr_io_stats) {
+        struct uid_record record = {};
+        record.name = p.first;
+        record.ios = p.second;
+        if (memcmp(&record.ios, &zero_io_usage, sizeof(struct uid_io_usage))) {
+            new_records.push_back(record);
+        }
+    }
+
+    curr_io_stats.clear();
+
+    if (new_records.empty())
+      return;
+
+    // make some room for new records
+    int overflow = records_size(records) +
+        new_records.size() - MAX_UID_RECORDS_SIZE;
+    while (overflow > 0 && records.size() > 0) {
+        overflow -= records[0].size();
+        records.erase(records.begin());
+    }
+
+    records[curr_ts].insert(records[curr_ts].end(),
+        new_records.begin(), new_records.end());
+}
+
+std::map<uint64_t, std::vector<struct uid_record>> uid_monitor::dump(
+    double hours, uint64_t threshold, bool force_report)
+{
+    if (force_report) {
+        report();
+    }
+
+    std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
+
+    std::map<uint64_t, std::vector<struct uid_record>> dump_records;
+    uint64_t first_ts = 0;
+
+    if (hours != 0) {
+        first_ts = time(NULL) - hours * HOUR_TO_SEC;
+    }
+
+    for (auto it = records.lower_bound(first_ts); it != records.end(); ++it) {
+        const std::vector<struct uid_record>& recs = it->second;
+        std::vector<struct uid_record> filtered;
+
+        for (const auto& rec : recs) {
+            if (rec.ios.bytes[READ][FOREGROUND][CHARGER_ON] +
+                rec.ios.bytes[READ][FOREGROUND][CHARGER_OFF] +
+                rec.ios.bytes[READ][BACKGROUND][CHARGER_ON] +
+                rec.ios.bytes[READ][BACKGROUND][CHARGER_OFF] +
+                rec.ios.bytes[WRITE][FOREGROUND][CHARGER_ON] +
+                rec.ios.bytes[WRITE][FOREGROUND][CHARGER_OFF] +
+                rec.ios.bytes[WRITE][BACKGROUND][CHARGER_ON] +
+                rec.ios.bytes[WRITE][BACKGROUND][CHARGER_OFF] > threshold) {
+                filtered.push_back(rec);
+            }
+        }
+        dump_records.insert(
+            std::pair<uint64_t, std::vector<struct uid_record>>(it->first, filtered));
+    }
+
+    return dump_records;
+}
+
+void uid_monitor::update_curr_io_stats_locked()
+{
+    std::unordered_map<uint32_t, struct uid_info> uid_io_stats =
+        get_uid_io_stats_locked();
+    if (uid_io_stats.empty()) {
+        return;
+    }
+
+    for (const auto& it : uid_io_stats) {
+        const struct uid_info& uid = it.second;
+
+        if (curr_io_stats.find(uid.name) == curr_io_stats.end()) {
+          curr_io_stats[uid.name] = {};
+        }
+
+        struct uid_io_usage& usage = curr_io_stats[uid.name];
+        int64_t fg_rd_delta = uid.io[FOREGROUND].read_bytes -
+            last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes;
+        int64_t bg_rd_delta = uid.io[BACKGROUND].read_bytes -
+            last_uid_io_stats[uid.uid].io[BACKGROUND].read_bytes;
+        int64_t fg_wr_delta = uid.io[FOREGROUND].write_bytes -
+            last_uid_io_stats[uid.uid].io[FOREGROUND].write_bytes;
+        int64_t bg_wr_delta = uid.io[BACKGROUND].write_bytes -
+            last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes;
+
+        usage.bytes[READ][FOREGROUND][charger_stat] +=
+            (fg_rd_delta < 0) ? uid.io[FOREGROUND].read_bytes : fg_rd_delta;
+        usage.bytes[READ][BACKGROUND][charger_stat] +=
+            (bg_rd_delta < 0) ? uid.io[BACKGROUND].read_bytes : bg_rd_delta;
+        usage.bytes[WRITE][FOREGROUND][charger_stat] +=
+            (fg_wr_delta < 0) ? uid.io[FOREGROUND].write_bytes : fg_wr_delta;
+        usage.bytes[WRITE][BACKGROUND][charger_stat] +=
+            (bg_wr_delta < 0) ? uid.io[BACKGROUND].write_bytes : bg_wr_delta;
+    }
+
+    last_uid_io_stats = uid_io_stats;
+}
+
+void uid_monitor::report()
+{
+    std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
+
+    update_curr_io_stats_locked();
+    add_records_locked(time(NULL));
+}
+
+void uid_monitor::set_charger_state(charger_stat_t stat)
+{
+    std::unique_ptr<lock_t> lock(new lock_t(&um_lock));
+
+    if (charger_stat == stat) {
+        return;
+    }
+
+    update_curr_io_stats_locked();
+    charger_stat = stat;
+}
+
+void uid_monitor::init(charger_stat_t stat)
+{
+    charger_stat = stat;
+    last_uid_io_stats = get_uid_io_stats();
+}
+
+uid_monitor::uid_monitor()
+{
+    sem_init(&um_lock, 0, 1);
+}
+
+uid_monitor::~uid_monitor()
+{
+    sem_destroy(&um_lock);
+}
diff --git a/storaged/storaged_utils.cpp b/storaged/storaged_utils.cpp
new file mode 100644
index 0000000..1ef89af
--- /dev/null
+++ b/storaged/storaged_utils.cpp
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "storaged"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <linux/time.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <log/log_event_list.h>
+
+#include <storaged.h>
+#include <storaged_utils.h>
+
+bool parse_disk_stats(const char* disk_stats_path, struct disk_stats* stats) {
+    // Get time
+    struct timespec ts;
+    // Use monotonic to exclude suspend time so that we measure IO bytes/sec
+    // when system is running.
+    int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+    if (ret < 0) {
+        PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+        return false;
+    }
+
+    std::string buffer;
+    if (!android::base::ReadFileToString(disk_stats_path, &buffer)) {
+        PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed.";
+        return false;
+    }
+
+    // Regular diskstats entries
+    std::stringstream ss(buffer);
+    for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
+        ss >> *((uint64_t*)stats + i);
+    }
+    // Other entries
+    stats->start_time = 0;
+    stats->end_time = (uint64_t)ts.tv_sec * SEC_TO_MSEC +
+        ts.tv_nsec / (MSEC_TO_USEC * USEC_TO_NSEC);
+    stats->counter = 1;
+    stats->io_avg = (double)stats->io_in_flight;
+    return true;
+}
+
+struct disk_perf get_disk_perf(struct disk_stats* stats) {
+    struct disk_perf perf;
+    memset(&perf, 0, sizeof(struct disk_perf));  // initialize
+
+    if (stats->io_ticks) {
+        if (stats->read_ticks) {
+            unsigned long long divisor = stats->read_ticks * stats->io_ticks;
+            perf.read_perf = ((unsigned long long)SECTOR_SIZE *
+                                        stats->read_sectors *
+                                        stats->io_in_queue +
+                                        (divisor >> 1)) /
+                                            divisor;
+            perf.read_ios = ((unsigned long long)SEC_TO_MSEC *
+                                        stats->read_ios *
+                                        stats->io_in_queue +
+                                        (divisor >> 1)) /
+                                            divisor;
+        }
+        if (stats->write_ticks) {
+            unsigned long long divisor = stats->write_ticks * stats->io_ticks;
+                        perf.write_perf = ((unsigned long long)SECTOR_SIZE *
+                                                    stats->write_sectors *
+                                                    stats->io_in_queue +
+                                                    (divisor >> 1)) /
+                                                        divisor;
+                        perf.write_ios = ((unsigned long long)SEC_TO_MSEC *
+                                                    stats->write_ios *
+                                                    stats->io_in_queue +
+                                                    (divisor >> 1)) /
+                                                        divisor;
+        }
+        perf.queue = (stats->io_in_queue + (stats->io_ticks >> 1)) /
+                                stats->io_ticks;
+    }
+    return perf;
+}
+
+struct disk_stats get_inc_disk_stats(struct disk_stats* prev, struct disk_stats* curr) {
+    struct disk_stats inc;
+    for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
+        if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
+            continue;
+        }
+
+        *((uint64_t*)&inc + i) =
+                *((uint64_t*)curr + i) - *((uint64_t*)prev + i);
+    }
+    // io_in_flight is exception
+    inc.io_in_flight = curr->io_in_flight;
+
+    inc.start_time = prev->end_time;
+    inc.end_time = curr->end_time;
+    inc.io_avg = curr->io_avg;
+    inc.counter = 1;
+
+    return inc;
+}
+
+// Add src to dst
+void add_disk_stats(struct disk_stats* src, struct disk_stats* dst) {
+    if (dst->end_time != 0 && dst->end_time != src->start_time) {
+        LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats"
+            << " are added. dst end with " << dst->end_time
+            << ", src start with " << src->start_time;
+    }
+
+    for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
+        if (i == DISK_STATS_IO_IN_FLIGHT_IDX) {
+            continue;
+        }
+
+        *((uint64_t*)dst + i) += *((uint64_t*)src + i);
+    }
+
+    dst->io_in_flight = src->io_in_flight;
+    if (dst->counter + src->counter) {
+        dst->io_avg = ((dst->io_avg * dst->counter) + (src->io_avg * src->counter)) /
+                        (dst->counter + src->counter);
+    }
+    dst->counter += src->counter;
+    dst->end_time = src->end_time;
+    if (dst->start_time == 0) {
+        dst->start_time = src->start_time;
+    }
+}
+
+bool parse_emmc_ecsd(int ext_csd_fd, struct emmc_info* info) {
+    CHECK(ext_csd_fd >= 0);
+    struct hex {
+        char str[2];
+    };
+    // List of interesting offsets
+    static const size_t EXT_CSD_REV_IDX = 192 * sizeof(hex);
+    static const size_t EXT_PRE_EOL_INFO_IDX = 267 * sizeof(hex);
+    static const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * sizeof(hex);
+    static const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * sizeof(hex);
+
+    // Read file
+    CHECK(lseek(ext_csd_fd, 0, SEEK_SET) == 0);
+    std::string buffer;
+    if (!android::base::ReadFdToString(ext_csd_fd, &buffer)) {
+        PLOG_TO(SYSTEM, ERROR) << "ReadFdToString failed.";
+        return false;
+    }
+
+    if (buffer.length() < EXT_CSD_FILE_MIN_SIZE) {
+        LOG_TO(SYSTEM, ERROR) << "EMMC ext csd file has truncated content. "
+            << "File length: " << buffer.length();
+        return false;
+    }
+
+    std::string sub;
+    std::stringstream ss;
+    // Parse EXT_CSD_REV
+    int ext_csd_rev = -1;
+    sub = buffer.substr(EXT_CSD_REV_IDX, sizeof(hex));
+    ss << sub;
+    ss >> std::hex >> ext_csd_rev;
+    if (ext_csd_rev < 0) {
+        LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_CSD_REV.";
+        return false;
+    }
+    ss.clear();
+
+    static const char* ver_str[] = {
+        "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
+    };
+
+    strlcpy(info->mmc_ver,
+            (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ?
+                           ver_str[ext_csd_rev] :
+                           "Unknown",
+            MMC_VER_STR_LEN);
+
+    if (ext_csd_rev < 7) {
+        return 0;
+    }
+
+    // Parse EXT_PRE_EOL_INFO
+    info->eol = -1;
+    sub = buffer.substr(EXT_PRE_EOL_INFO_IDX, sizeof(hex));
+    ss << sub;
+    ss >> std::hex >> info->eol;
+    if (info->eol < 0) {
+        LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_PRE_EOL_INFO.";
+        return false;
+    }
+    ss.clear();
+
+    // Parse DEVICE_LIFE_TIME_EST
+    info->lifetime_a = -1;
+    sub = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, sizeof(hex));
+    ss << sub;
+    ss >> std::hex >> info->lifetime_a;
+    if (info->lifetime_a < 0) {
+        LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_A.";
+        return false;
+    }
+    ss.clear();
+
+    info->lifetime_b = -1;
+    sub = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, sizeof(hex));
+    ss << sub;
+    ss >> std::hex >> info->lifetime_b;
+    if (info->lifetime_b < 0) {
+        LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_B.";
+        return false;
+    }
+    ss.clear();
+
+    return true;
+}
+
+static bool cmp_uid_info(struct uid_info l, struct uid_info r) {
+    // Compare background I/O first.
+    for (int i = UID_STATS - 1; i >= 0; i--) {
+        uint64_t l_bytes = l.io[i].read_bytes + l.io[i].write_bytes;
+        uint64_t r_bytes = r.io[i].read_bytes + r.io[i].write_bytes;
+        uint64_t l_chars = l.io[i].rchar + l.io[i].wchar;
+        uint64_t r_chars = r.io[i].rchar + r.io[i].wchar;
+
+        if (l_bytes != r_bytes) {
+            return l_bytes > r_bytes;
+        }
+        if (l_chars != r_chars) {
+            return l_chars > r_chars;
+        }
+    }
+
+    return l.name < r.name;
+}
+
+void sort_running_uids_info(std::vector<struct uid_info> &uids) {
+    std::sort(uids.begin(), uids.end(), cmp_uid_info);
+}
+
+// Logging functions
+void log_console_running_uids_info(std::vector<struct uid_info> uids) {
+// Sample Output:
+//                                       Application        FG Read       FG Write        FG Read       FG Write        BG Read       BG Write        BG Read       BG Write
+//                                          NAME/UID     Characters     Characters          Bytes          Bytes     Characters     Characters          Bytes          Bytes
+//                                        ----------     ----------     ----------     ----------     ----------     ----------     ----------     ----------     ----------
+//                      com.google.android.gsf.login              0              0              0              0       57195097        5137089      176386048        6512640
+//           com.google.android.googlequicksearchbox              0              0              0              0        4196821       12123468       34295808       13225984
+//                                              1037           4572            537              0              0         131352        5145643       34263040        5144576
+//                        com.google.android.youtube           2182             70              0              0       63969383         482939       38731776         466944
+
+    // Title
+    printf("Per-UID I/O stats\n");
+    printf("                                       Application        FG Read       FG Write        FG Read       FG Write        BG Read       BG Write        BG Read       BG Write\n"
+           "                                          NAME/UID     Characters     Characters          Bytes          Bytes     Characters     Characters          Bytes          Bytes\n"
+           "                                        ----------     ----------     ----------     ----------     ----------     ----------     ----------     ----------     ----------\n");
+
+    for (const auto& uid : uids) {
+        printf("%50s%15ju%15ju%15ju%15ju%15ju%15ju%15ju%15ju\n", uid.name.c_str(),
+            uid.io[0].rchar, uid.io[0].wchar, uid.io[0].read_bytes, uid.io[0].write_bytes,
+            uid.io[1].rchar, uid.io[1].wchar, uid.io[1].read_bytes, uid.io[1].write_bytes);
+    }
+    fflush(stdout);
+}
+
+#if DEBUG
+void log_debug_disk_perf(struct disk_perf* perf, const char* type) {
+    // skip if the input structure are all zeros
+    if (perf == NULL) return;
+    struct disk_perf zero_cmp;
+    memset(&zero_cmp, 0, sizeof(zero_cmp));
+    if (memcmp(&zero_cmp, perf, sizeof(struct disk_perf)) == 0) return;
+
+    LOG_TO(SYSTEM, INFO) << "perf(ios) " << type
+              << " rd:" << perf->read_perf << "KB/s(" << perf->read_ios << "/s)"
+              << " wr:" << perf->write_perf << "KB/s(" << perf->write_ios << "/s)"
+              << " q:" << perf->queue;
+}
+#else
+void log_debug_disk_perf(struct disk_perf* /* perf */, const char* /* type */) {}
+#endif
+
+void log_event_disk_stats(struct disk_stats* stats, const char* type) {
+    // skip if the input structure are all zeros
+    if (stats == NULL) return;
+    struct disk_stats zero_cmp;
+    memset(&zero_cmp, 0, sizeof(zero_cmp));
+    // skip event logging diskstats when it is zero increment (all first 11 entries are zero)
+    if (memcmp(&zero_cmp, stats, sizeof(uint64_t) * DISK_STATS_SIZE) == 0) return;
+
+    android_log_event_list(EVENTLOGTAG_DISKSTATS)
+        << type << stats->start_time << stats->end_time
+        << stats->read_ios << stats->read_merges
+        << stats->read_sectors << stats->read_ticks
+        << stats->write_ios << stats->write_merges
+        << stats->write_sectors << stats->write_ticks
+        << (uint64_t)stats->io_avg << stats->io_ticks << stats->io_in_queue
+        << LOG_ID_EVENTS;
+}
+
+void log_event_emmc_info(struct emmc_info* info) {
+    // skip if the input structure are all zeros
+    if (info == NULL) return;
+    struct emmc_info zero_cmp;
+    memset(&zero_cmp, 0, sizeof(zero_cmp));
+    if (memcmp(&zero_cmp, info, sizeof(struct emmc_info)) == 0) return;
+
+    android_log_event_list(EVENTLOGTAG_EMMCINFO)
+        << info->mmc_ver << info->eol << info->lifetime_a << info->lifetime_b
+        << LOG_ID_EVENTS;
+}
diff --git a/storaged/tests/Android.mk b/storaged/tests/Android.mk
new file mode 100644
index 0000000..26d04b1
--- /dev/null
+++ b/storaged/tests/Android.mk
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2014 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)
+
+test_module_prefix := storaged-
+test_tags := tests
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
+
+test_c_flags := \
+    -fstack-protector-all \
+    -g \
+    -Wall -Wextra \
+    -Werror \
+    -fno-builtin \
+
+test_src_files := \
+    storaged_test.cpp \
+
+# Build tests for the logger. Run with:
+#   adb shell /data/nativetest/storaged-unit-tests/storaged-unit-tests
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(test_module_prefix)unit-tests
+LOCAL_MODULE_TAGS := $(test_tags)
+LOCAL_CFLAGS += $(test_c_flags)
+LOCAL_STATIC_LIBRARIES := libstoraged
+LOCAL_SHARED_LIBRARIES := libbase libcutils liblog libpackagelistparser
+LOCAL_SRC_FILES := $(test_src_files)
+include $(BUILD_NATIVE_TEST)
diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp
new file mode 100644
index 0000000..9e03c50
--- /dev/null
+++ b/storaged/tests/storaged_test.cpp
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 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 <deque>
+#include <fcntl.h>
+#include <random>
+#include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#include <storaged.h>               // data structures
+#include <storaged_utils.h>         // functions to test
+
+#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat"
+#define SDA_DISK_STATS_PATH "/sys/block/sda/stat"
+#define EMMC_EXT_CSD_PATH "/d/mmc0/mmc0:0001/ext_csd"
+
+static void pause(uint32_t sec) {
+    const char* path = "/cache/test";
+    int fd = open(path, O_WRONLY | O_CREAT, 0600);
+    ASSERT_LT(-1, fd);
+    char buffer[2048];
+    memset(buffer, 1, sizeof(buffer));
+    int loop_size = 100;
+    for (int i = 0; i < loop_size; ++i) {
+        ASSERT_EQ(2048, write(fd, buffer, sizeof(buffer)));
+    }
+    fsync(fd);
+    close(fd);
+
+    fd = open(path, O_RDONLY);
+    ASSERT_LT(-1, fd);
+    for (int i = 0; i < loop_size; ++i) {
+        ASSERT_EQ(2048, read(fd, buffer, sizeof(buffer)));
+    }
+    close(fd);
+
+    sleep(sec);
+}
+
+// the return values of the tested functions should be the expected ones
+const char* DISK_STATS_PATH;
+TEST(storaged_test, retvals) {
+    struct disk_stats stats;
+    struct emmc_info info;
+    memset(&stats, 0, sizeof(struct disk_stats));
+    memset(&info, 0, sizeof(struct emmc_info));
+
+    int emmc_fd = open(EMMC_EXT_CSD_PATH, O_RDONLY);
+    if (emmc_fd >= 0) {
+        EXPECT_TRUE(parse_emmc_ecsd(emmc_fd, &info));
+    }
+
+    if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
+        DISK_STATS_PATH = MMC_DISK_STATS_PATH;
+    } else if (access(SDA_DISK_STATS_PATH, R_OK) >= 0) {
+        DISK_STATS_PATH = SDA_DISK_STATS_PATH;
+    } else {
+        return;
+    }
+
+    EXPECT_TRUE(parse_disk_stats(DISK_STATS_PATH, &stats));
+
+    struct disk_stats old_stats;
+    memset(&old_stats, 0, sizeof(struct disk_stats));
+    old_stats = stats;
+
+    const char wrong_path[] = "/this/is/wrong";
+    EXPECT_FALSE(parse_disk_stats(wrong_path, &stats));
+
+    // reading a wrong path should not damage the output structure
+    EXPECT_EQ(0, memcmp(&stats, &old_stats, sizeof(disk_stats)));
+}
+
+TEST(storaged_test, disk_stats) {
+    struct disk_stats stats;
+    memset(&stats, 0, sizeof(struct disk_stats));
+
+    ASSERT_TRUE(parse_disk_stats(DISK_STATS_PATH, &stats));
+
+    // every entry of stats (except io_in_flight) should all be greater than 0
+    for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
+        if (i == 8) continue; // skip io_in_flight which can be 0
+        EXPECT_LT((uint64_t)0, *((uint64_t*)&stats + i));
+    }
+
+    // accumulation of the increments should be the same with the overall increment
+    struct disk_stats base, tmp, curr, acc, inc[5];
+    memset(&base, 0, sizeof(struct disk_stats));
+    memset(&tmp, 0, sizeof(struct disk_stats));
+    memset(&acc, 0, sizeof(struct disk_stats));
+
+    for (uint i = 0; i < 5; ++i) {
+        ASSERT_TRUE(parse_disk_stats(DISK_STATS_PATH, &curr));
+        if (i == 0) {
+            base = curr;
+            tmp = curr;
+            sleep(5);
+            continue;
+        }
+        inc[i] = get_inc_disk_stats(&tmp, &curr);
+        add_disk_stats(&inc[i], &acc);
+        tmp = curr;
+        pause(5);
+    }
+    struct disk_stats overall_inc;
+    memset(&overall_inc, 0, sizeof(disk_stats));
+    overall_inc= get_inc_disk_stats(&base, &curr);
+
+    for (uint i = 0; i < DISK_STATS_SIZE; ++i) {
+        if (i == 8) continue; // skip io_in_flight which can be 0
+        EXPECT_EQ(*((uint64_t*)&overall_inc + i), *((uint64_t*)&acc + i));
+    }
+}
+
+TEST(storaged_test, emmc_info) {
+    struct emmc_info info, void_info;
+    memset(&info, 0, sizeof(struct emmc_info));
+    memset(&void_info, 0, sizeof(struct emmc_info));
+
+    if (access(EMMC_EXT_CSD_PATH, R_OK) >= 0) {
+        int emmc_fd = open(EMMC_EXT_CSD_PATH, O_RDONLY);
+        ASSERT_GE(emmc_fd, 0);
+        ASSERT_TRUE(parse_emmc_ecsd(emmc_fd, &info));
+        // parse_emmc_ecsd() should put something in info.
+        EXPECT_NE(0, memcmp(&void_info, &info, sizeof(struct emmc_info)));
+    }
+}
+
+static double mean(std::deque<uint32_t> nums) {
+    double sum = 0.0;
+    for (uint32_t i : nums) {
+    sum += i;
+    }
+    return sum / nums.size();
+}
+
+static double standard_deviation(std::deque<uint32_t> nums) {
+    double sum = 0.0;
+    double avg = mean(nums);
+    for (uint32_t i : nums) {
+    sum += ((double)i - avg) * ((double)i - avg);
+    }
+    return sqrt(sum / nums.size());
+}
+
+TEST(storaged_test, stream_stats) {
+    // 100 random numbers
+    std::vector<uint32_t> data = {8147,9058,1270,9134,6324,975,2785,5469,9575,9649,1576,9706,9572,4854,8003,1419,4218,9157,7922,9595,6557,357,8491,9340,6787,7577,7431,3922,6555,1712,7060,318,2769,462,971,8235,6948,3171,9502,344,4387,3816,7655,7952,1869,4898,4456,6463,7094,7547,2760,6797,6551,1626,1190,4984,9597,3404,5853,2238,7513,2551,5060,6991,8909,9593,5472,1386,1493,2575,8407,2543,8143,2435,9293,3500,1966,2511,6160,4733,3517,8308,5853,5497,9172,2858,7572,7537,3804,5678,759,540,5308,7792,9340,1299,5688,4694,119,3371};
+    std::deque<uint32_t> test_data;
+    stream_stats sstats;
+    for (uint32_t i : data) {
+        test_data.push_back(i);
+        sstats.add(i);
+
+        EXPECT_EQ((int)standard_deviation(test_data), (int)sstats.get_std());
+        EXPECT_EQ((int)mean(test_data), (int)sstats.get_mean());
+    }
+
+    for (uint32_t i : data) {
+        test_data.pop_front();
+        sstats.evict(i);
+
+        EXPECT_EQ((int)standard_deviation(test_data), (int)sstats.get_std());
+        EXPECT_EQ((int)mean(test_data), (int)sstats.get_mean());
+    }
+
+    // some real data
+    std::vector<uint32_t> another_data = {113875,81620,103145,28327,86855,207414,96526,52567,28553,250311};
+    test_data.clear();
+    uint32_t window_size = 2;
+    uint32_t idx;
+    stream_stats sstats1;
+    for (idx = 0; idx < window_size; ++idx) {
+        test_data.push_back(another_data[idx]);
+        sstats1.add(another_data[idx]);
+    }
+    EXPECT_EQ((int)standard_deviation(test_data), (int)sstats1.get_std());
+    EXPECT_EQ((int)mean(test_data), (int)sstats1.get_mean());
+    for (;idx < another_data.size(); ++idx) {
+        test_data.pop_front();
+        sstats1.evict(another_data[idx - window_size]);
+        test_data.push_back(another_data[idx]);
+        sstats1.add(another_data[idx]);
+        EXPECT_EQ((int)standard_deviation(test_data), (int)sstats1.get_std());
+        EXPECT_EQ((int)mean(test_data), (int)sstats1.get_mean());
+    }
+}
+
+static struct disk_perf disk_perf_multiply(struct disk_perf perf, double mul) {
+    struct disk_perf retval;
+    retval.read_perf = (double)perf.read_perf * mul;
+    retval.read_ios = (double)perf.read_ios * mul;
+    retval.write_perf = (double)perf.write_perf * mul;
+    retval.write_ios = (double)perf.write_ios * mul;
+    retval.queue = (double)perf.queue * mul;
+
+    return retval;
+}
+
+static struct disk_stats disk_stats_add(struct disk_stats stats1, struct disk_stats stats2) {
+    struct disk_stats retval;
+    retval.read_ios = stats1.read_ios + stats2.read_ios;
+    retval.read_merges = stats1.read_merges + stats2.read_merges;
+    retval.read_sectors = stats1.read_sectors + stats2.read_sectors;
+    retval.read_ticks = stats1.read_ticks + stats2.read_ticks;
+    retval.write_ios = stats1.write_ios + stats2.write_ios;
+    retval.write_merges = stats1.write_merges + stats2.write_merges;
+    retval.write_sectors = stats1.write_sectors + stats2.write_sectors;
+    retval.write_ticks = stats1.write_ticks + stats2.write_ticks;
+    retval.io_in_flight = stats1.io_in_flight + stats2.io_in_flight;
+    retval.io_ticks = stats1.io_ticks + stats2.io_ticks;
+    retval.io_in_queue = stats1.io_in_queue + stats2.io_in_queue;
+    retval.end_time = stats1.end_time + stats2.end_time;
+
+    return retval;
+}
+
+TEST(storaged_test, disk_stats_monitor) {
+    // asserting that there is one file for diskstats
+    ASSERT_TRUE(access(MMC_DISK_STATS_PATH, R_OK) >= 0 || access(SDA_DISK_STATS_PATH, R_OK) >= 0);
+    // testing if detect() will return the right value
+    disk_stats_monitor dsm_detect;
+    // feed monitor with constant perf data for io perf baseline
+    // using constant perf is reasonable since the functionality of stream_stats
+    // has already been tested
+    struct disk_perf norm_perf = {
+        .read_perf = 10 * 1024,
+        .read_ios = 50,
+        .write_perf = 5 * 1024,
+        .write_ios = 25,
+        .queue = 5
+    };
+
+    std::random_device rd;
+    std::mt19937 gen(rd());
+    std::uniform_real_distribution<> rand(0.8, 1.2);
+
+    for (uint i = 0; i < dsm_detect.mWindow; ++i) {
+        struct disk_perf perf = disk_perf_multiply(norm_perf, rand(gen));
+
+        dsm_detect.add(&perf);
+        dsm_detect.mBuffer.push(perf);
+        EXPECT_EQ(dsm_detect.mBuffer.size(), (uint64_t)i + 1);
+    }
+
+    dsm_detect.mValid = true;
+    dsm_detect.update_mean();
+    dsm_detect.update_std();
+
+    for (double i = 0; i < 2 * dsm_detect.mSigma; i += 0.5) {
+        struct disk_perf test_perf;
+        struct disk_perf test_mean = dsm_detect.mMean;
+        struct disk_perf test_std = dsm_detect.mStd;
+
+        test_perf.read_perf = (double)test_mean.read_perf - i * test_std.read_perf;
+        test_perf.read_ios = (double)test_mean.read_ios - i * test_std.read_ios;
+        test_perf.write_perf = (double)test_mean.write_perf - i * test_std.write_perf;
+        test_perf.write_ios = (double)test_mean.write_ios - i * test_std.write_ios;
+        test_perf.queue = (double)test_mean.queue + i * test_std.queue;
+
+        EXPECT_EQ((i > dsm_detect.mSigma), dsm_detect.detect(&test_perf));
+    }
+
+    // testing if stalled disk_stats can be correctly accumulated in the monitor
+    disk_stats_monitor dsm_acc;
+    struct disk_stats norm_inc = {
+        .read_ios = 200,
+        .read_merges = 0,
+        .read_sectors = 200,
+        .read_ticks = 200,
+        .write_ios = 100,
+        .write_merges = 0,
+        .write_sectors = 100,
+        .write_ticks = 100,
+        .io_in_flight = 0,
+        .io_ticks = 600,
+        .io_in_queue = 300,
+        .start_time = 0,
+        .end_time = 100,
+        .counter = 0,
+        .io_avg = 0
+    };
+
+    struct disk_stats stall_inc = {
+        .read_ios = 200,
+        .read_merges = 0,
+        .read_sectors = 20,
+        .read_ticks = 200,
+        .write_ios = 100,
+        .write_merges = 0,
+        .write_sectors = 10,
+        .write_ticks = 100,
+        .io_in_flight = 0,
+        .io_ticks = 600,
+        .io_in_queue = 1200,
+        .start_time = 0,
+        .end_time = 100,
+        .counter = 0,
+        .io_avg = 0
+    };
+
+    struct disk_stats stats_base;
+    memset(&stats_base, 0, sizeof(stats_base));
+
+    int loop_size = 100;
+    for (int i = 0; i < loop_size; ++i) {
+        stats_base = disk_stats_add(stats_base, norm_inc);
+        dsm_acc.update(&stats_base);
+        EXPECT_EQ(dsm_acc.mValid, (uint32_t)(i + 1) >= dsm_acc.mWindow);
+        EXPECT_FALSE(dsm_acc.mStall);
+    }
+
+    stats_base = disk_stats_add(stats_base, stall_inc);
+    dsm_acc.update(&stats_base);
+    EXPECT_TRUE(dsm_acc.mValid);
+    EXPECT_TRUE(dsm_acc.mStall);
+
+    for (int i = 0; i < 10; ++i) {
+        stats_base = disk_stats_add(stats_base, norm_inc);
+        dsm_acc.update(&stats_base);
+        EXPECT_TRUE(dsm_acc.mValid);
+        EXPECT_FALSE(dsm_acc.mStall);
+    }
+}
+
+static void expect_increasing(struct disk_stats stats1, struct disk_stats stats2) {
+    EXPECT_LE(stats1.read_ios, stats2.read_ios);
+    EXPECT_LE(stats1.read_merges, stats2.read_merges);
+    EXPECT_LE(stats1.read_sectors, stats2.read_sectors);
+    EXPECT_LE(stats1.read_ticks, stats2.read_ticks);
+
+    EXPECT_LE(stats1.write_ios, stats2.write_ios);
+    EXPECT_LE(stats1.write_merges, stats2.write_merges);
+    EXPECT_LE(stats1.write_sectors, stats2.write_sectors);
+    EXPECT_LE(stats1.write_ticks, stats2.write_ticks);
+
+    EXPECT_LE(stats1.io_ticks, stats2.io_ticks);
+    EXPECT_LE(stats1.io_in_queue, stats2.io_in_queue);
+}
+
+#define TEST_LOOPS 20
+TEST(storaged_test, disk_stats_publisher) {
+    // asserting that there is one file for diskstats
+    ASSERT_TRUE(access(MMC_DISK_STATS_PATH, R_OK) >= 0 || access(SDA_DISK_STATS_PATH, R_OK) >= 0);
+    disk_stats_publisher dsp;
+    struct disk_stats prev;
+    memset(&prev, 0, sizeof(prev));
+
+    for (int i = 0; i < TEST_LOOPS; ++i) {
+        dsp.update();
+        expect_increasing(prev, dsp.mPrevious);
+        prev = dsp.mPrevious;
+        pause(10);
+    }
+}
+