am e1c3a7c1: am 45288223: Merge "libbase: logging fixes"

* commit 'e1c3a7c19e790a9bbffb1dba012a24de0c9e53e2':
  libbase: logging fixes
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 1c5b5bd..2b496cc 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -137,8 +137,15 @@
         "                               - remove a specific reversed socket connection\n"
         "  adb reverse --remove-all     - remove all reversed socket connections from device\n"
         "  adb jdwp                     - list PIDs of processes hosting a JDWP transport\n"
-        "  adb install [-lrtsd] <file>\n"
-        "  adb install-multiple [-lrtsdp] <file...>\n"
+        "  adb install [-lrtsdg] <file>\n"
+        "                               - push this package file to the device and install it\n"
+        "                                 (-l: forward lock application)\n"
+        "                                 (-r: replace existing application)\n"
+        "                                 (-t: allow test packages)\n"
+        "                                 (-s: install application on sdcard)\n"
+        "                                 (-d: allow version code downgrade)\n"
+        "                                 (-g: grant all runtime permissions)\n"
+        "  adb install-multiple [-lrtsdpg] <file...>\n"
         "                               - push this package file to the device and install it\n"
         "                                 (-l: forward lock application)\n"
         "                                 (-r: replace existing application)\n"
@@ -146,6 +153,7 @@
         "                                 (-s: install application on sdcard)\n"
         "                                 (-d: allow version code downgrade)\n"
         "                                 (-p: partial application install)\n"
+        "                                 (-g: grant all runtime permissions)\n"
         "  adb uninstall [-k] <package> - remove this app package from the device\n"
         "                                 ('-k' means keep the data and cache directories)\n"
         "  adb bugreport                - return all information from the device\n"
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index ea019f4..a503327 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -60,7 +60,7 @@
         partial_path += path_component;
 
         if (should_use_fs_config(partial_path)) {
-            fs_config(partial_path.c_str(), 1, &uid, &gid, &mode, &cap);
+            fs_config(partial_path.c_str(), 1, nullptr, &uid, &gid, &mode, &cap);
         }
         if (adb_mkdir(partial_path.c_str(), mode) == -1) {
             if (errno != EEXIST) {
@@ -360,7 +360,7 @@
         tmp++;
     }
     if (should_use_fs_config(path)) {
-        fs_config(tmp, 0, &uid, &gid, &mode, &cap);
+        fs_config(tmp, 0, NULL, &uid, &gid, &mode, &cap);
     }
     return handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
 }
diff --git a/cpio/mkbootfs.c b/cpio/mkbootfs.c
index 7175749..0e35323 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -41,6 +41,7 @@
 };
 
 static struct fs_config_entry* canned_config = NULL;
+static char *target_out_path = NULL;
 
 /* Each line in the canned file should be a path plus three ints (uid,
  * gid, mode). */
@@ -79,7 +80,8 @@
     } else {
         // Use the compiled-in fs_config() function.
         unsigned st_mode = s->st_mode;
-        fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &st_mode, &capabilities);
+        fs_config(path, S_ISDIR(s->st_mode), target_out_path,
+                       &s->st_uid, &s->st_gid, &st_mode, &capabilities);
         s->st_mode = (typeof(s->st_mode)) st_mode;
     }
 }
@@ -328,6 +330,12 @@
     argc--;
     argv++;
 
+    if (argc > 1 && strcmp(argv[0], "-d") == 0) {
+        target_out_path = argv[1];
+        argc -= 2;
+        argv += 2;
+    }
+
     if (argc > 1 && strcmp(argv[0], "-f") == 0) {
         read_canned_config(argv[1]);
         argc -= 2;
diff --git a/fingerprintd/Android.mk b/fingerprintd/Android.mk
new file mode 100644
index 0000000..48b9525
--- /dev/null
+++ b/fingerprintd/Android.mk
@@ -0,0 +1,33 @@
+#
+# 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
new file mode 100644
index 0000000..beb95de
--- /dev/null
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -0,0 +1,253 @@
+/*
+ * 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, 0);
+
+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;
+        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);
+}
+
+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
new file mode 100644
index 0000000..871c0e6
--- /dev/null
+++ b/fingerprintd/FingerprintDaemonProxy.h
@@ -0,0 +1,63 @@
+/*
+ * 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 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
new file mode 100644
index 0000000..7131793
--- /dev/null
+++ b/fingerprintd/IFingerprintDaemon.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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 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
new file mode 100644
index 0000000..1eb4ac1
--- /dev/null
+++ b/fingerprintd/IFingerprintDaemon.h
@@ -0,0 +1,86 @@
+/*
+ * 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,
+        };
+
+        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 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
new file mode 100644
index 0000000..44d8020
--- /dev/null
+++ b/fingerprintd/IFingerprintDaemonCallback.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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:
+    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, const int32_t* fpIds, const int32_t* gpIds,
+            int32_t sz) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IFingerprintDaemonCallback::getInterfaceDescriptor());
+        data.writeInt64(devId);
+        data.writeInt32Array(sz, fpIds);
+        data.writeInt32Array(sz, gpIds);
+        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
new file mode 100644
index 0000000..6e32213
--- /dev/null
+++ b/fingerprintd/IFingerprintDaemonCallback.h
@@ -0,0 +1,55 @@
+/*
+ * 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, const int32_t* fpIds, const int32_t* gpIds,
+                int32_t sz) = 0;
+
+        DECLARE_META_INTERFACE(FingerprintDaemonCallback);
+};
+
+}; // namespace android
+
+#endif // IFINGERPRINT_DAEMON_CALLBACK_H_
diff --git a/fingerprintd/fingerprintd.cpp b/fingerprintd/fingerprintd.cpp
new file mode 100644
index 0000000..8fa7ed1
--- /dev/null
+++ b/fingerprintd/fingerprintd.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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 <cutils/log.h>
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include <utils/String16.h>
+
+#include <keystore/IKeystoreService.h>
+#include <keystore/keystore.h> // for error codes
+
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.h>
+#include <hardware/hw_auth_token.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/Android.mk b/fs_mgr/Android.mk
index 08d0671..8ed5cc9 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -4,8 +4,12 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c fs_mgr_fstab.c
+LOCAL_SRC_FILES += fs_mgr_format.c
 
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include \
+    system/vold \
+    system/extras/ext4_utils \
+    external/openssl/include
 
 LOCAL_MODULE:= libfs_mgr
 LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static libsquashfs_utils
@@ -35,6 +39,7 @@
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
 
 LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static libsquashfs_utils
+LOCAL_STATIC_LIBRARIES += libsparse_static libz libselinux
 LOCAL_CXX_STL := libc++_static
 
 LOCAL_CFLAGS := -Werror
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 459daec..00961c5 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -44,6 +44,9 @@
 #include "mincrypt/sha.h"
 #include "mincrypt/sha256.h"
 
+#include "ext4_utils.h"
+#include "wipe.h"
+
 #include "fs_mgr_priv.h"
 #include "fs_mgr_priv_verity.h"
 
@@ -557,6 +560,8 @@
             }
         }
         int last_idx_inspected;
+        int top_idx = i;
+
         mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
         i = last_idx_inspected;
         mount_errno = errno;
@@ -582,10 +587,38 @@
             continue;
         }
 
-        /* mount(2) returned an error, check if it's encryptable and deal with it */
+        /* mount(2) returned an error, handle the encryptable/formattable case */
+        bool wiped = partition_wiped(fstab->recs[top_idx].blk_device);
+        if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
+            fs_mgr_is_formattable(&fstab->recs[top_idx]) && wiped) {
+            /* top_idx and attempted_idx point at the same partition, but sometimes
+             * at two different lines in the fstab.  Use the top one for formatting
+             * as that is the preferred one.
+             */
+            ERROR("%s(): %s is wiped and %s %s is formattable. Format it.\n", __func__,
+                  fstab->recs[top_idx].blk_device, fstab->recs[top_idx].mount_point,
+                  fstab->recs[top_idx].fs_type);
+            if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) &&
+                strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) {
+                int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY, 0644);
+                if (fd >= 0) {
+                    INFO("%s(): also wipe %s\n", __func__, fstab->recs[top_idx].key_loc);
+                    wipe_block_device(fd, get_file_size(fd));
+                    close(fd);
+                } else {
+                    ERROR("%s(): %s wouldn't open (%s)\n", __func__,
+                          fstab->recs[top_idx].key_loc, strerror(errno));
+                }
+            }
+            if (fs_mgr_do_format(&fstab->recs[top_idx]) == 0) {
+                /* Let's replay the mount actions. */
+                i = top_idx - 1;
+                continue;
+            }
+        }
         if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
             fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
-            if(partition_wiped(fstab->recs[attempted_idx].blk_device)) {
+            if (wiped) {
                 ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__,
                       fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
                       fstab->recs[attempted_idx].fs_type);
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
new file mode 100644
index 0000000..c73045d
--- /dev/null
+++ b/fs_mgr/fs_mgr_format.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <cutils/partition_utils.h>
+#include <sys/mount.h>
+#include "ext4_utils.h"
+#include "ext4.h"
+#include "make_ext4fs.h"
+#include "fs_mgr_priv.h"
+
+extern struct fs_info info;     /* magic global from ext4_utils */
+extern void reset_ext4fs_info();
+
+static int format_ext4(char *fs_blkdev, char *fs_mnt_point)
+{
+    unsigned int nr_sec;
+    int fd, rc = 0;
+
+    if ((fd = open(fs_blkdev, O_WRONLY, 0644)) < 0) {
+        ERROR("Cannot open block device.  %s\n", strerror(errno));
+        return -1;
+    }
+
+    if ((ioctl(fd, BLKGETSIZE, &nr_sec)) == -1) {
+        ERROR("Cannot get block device size.  %s\n", strerror(errno));
+        close(fd);
+        return -1;
+    }
+
+    /* Format the partition using the calculated length */
+    reset_ext4fs_info();
+    info.len = ((off64_t)nr_sec * 512);
+
+    /* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
+    rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
+    if (rc) {
+        ERROR("make_ext4fs returned %d.\n", rc);
+    }
+    close(fd);
+
+    return rc;
+}
+
+static int format_f2fs(char *fs_blkdev)
+{
+    char * args[3];
+    int pid;
+    int rc = 0;
+
+    args[0] = (char *)"/sbin/mkfs.f2fs";
+    args[1] = fs_blkdev;
+    args[2] = (char *)0;
+
+    pid = fork();
+    if (pid < 0) {
+       return pid;
+    }
+    if (!pid) {
+        /* This doesn't return */
+        execv("/sbin/mkfs.f2fs", args);
+        exit(1);
+    }
+    for(;;) {
+        pid_t p = waitpid(pid, &rc, 0);
+        if (p != pid) {
+            ERROR("Error waiting for child process - %d\n", p);
+            rc = -1;
+            break;
+        }
+        if (WIFEXITED(rc)) {
+            rc = WEXITSTATUS(rc);
+            INFO("%s done, status %d\n", args[0], rc);
+            if (rc) {
+                rc = -1;
+            }
+            break;
+        }
+        ERROR("Still waiting for %s...\n", args[0]);
+    }
+
+    return rc;
+}
+
+int fs_mgr_do_format(struct fstab_rec *fstab)
+{
+    int rc = -EINVAL;
+
+    ERROR("%s: Format %s as '%s'.\n", __func__, fstab->blk_device, fstab->fs_type);
+
+    if (!strncmp(fstab->fs_type, "f2fs", 4)) {
+        rc = format_f2fs(fstab->blk_device);
+    } else if (!strncmp(fstab->fs_type, "ext4", 4)) {
+        rc = format_ext4(fstab->blk_device, fstab->mount_point);
+    } else {
+        ERROR("File system type '%s' is not supported\n", fstab->fs_type);
+    }
+
+    return rc;
+}
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 8b0f714..f24af1f 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -15,10 +15,12 @@
  */
 
 #include <ctype.h>
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mount.h>
+#include <unistd.h>
 
 #include "fs_mgr_priv.h"
 
@@ -70,10 +72,25 @@
     { "zramsize=",   MF_ZRAMSIZE },
     { "verify",      MF_VERIFY },
     { "noemulatedsd", MF_NOEMULATEDSD },
+    { "notrim",       MF_NOTRIM },
+    { "formattable", MF_FORMATTABLE },
     { "defaults",    0 },
     { 0,             0 },
 };
 
+static uint64_t calculate_zram_size(unsigned int percentage)
+{
+    uint64_t total;
+
+    total  = sysconf(_SC_PHYS_PAGES);
+    total *= percentage;
+    total /= 100;
+
+    total *= sysconf(_SC_PAGESIZE);
+
+    return total;
+}
+
 static int parse_flags(char *flags, struct flag_list *fl,
                        struct fs_mgr_flag_values *flag_vals,
                        char *fs_options, int fs_options_len)
@@ -155,7 +172,12 @@
                 } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
                     flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
                 } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
-                    flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0);
+                    int is_percent = !!strrchr(p, '%');
+                    unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);
+                    if (is_percent)
+                        flag_vals->zram_size = calculate_zram_size(val);
+                    else
+                        flag_vals->zram_size = val;
                 }
                 break;
             }
@@ -448,3 +470,13 @@
 {
     return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
 }
+
+int fs_mgr_is_notrim(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_NOTRIM;
+}
+
+int fs_mgr_is_formattable(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & (MF_FORMATTABLE);
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index d56111a..682fd11 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -76,11 +76,12 @@
 #define MF_FORCECRYPT   0x400
 #define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
                                  external storage */
+#define MF_NOTRIM       0x1000
 #define MF_FILEENCRYPTION 0x2000
+#define MF_FORMATTABLE  0x4000
 
 #define DM_BUF_SIZE 4096
 
 int fs_mgr_set_blk_ro(const char *blockdev);
 
 #endif /* __CORE_FS_MGR_PRIV_H */
-
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index c58a888..27fccf7 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -103,10 +103,14 @@
 int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
 int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
+int fs_mgr_is_notrim(struct fstab_rec *fstab);
+int fs_mgr_is_formattable(struct fstab_rec *fstab);
 int fs_mgr_swapon_all(struct fstab *fstab);
+
+int fs_mgr_do_format(struct fstab_rec *fstab);
+
 #ifdef __cplusplus
 }
 #endif
 
 #endif /* __CORE_FS_MGR_H */
-
diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk
new file mode 100644
index 0000000..55b2d5e
--- /dev/null
+++ b/gatekeeperd/Android.mk
@@ -0,0 +1,41 @@
+#
+# 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 := \
+	SoftGateKeeperDevice.cpp \
+	IGateKeeperService.cpp \
+	gatekeeperd.cpp \
+	IUserManager.cpp
+
+LOCAL_MODULE := gatekeeperd
+LOCAL_SHARED_LIBRARIES := \
+	libbinder \
+	libgatekeeper \
+	liblog \
+	libhardware \
+	libbase \
+	libutils \
+	libcrypto \
+	libkeystore_binder
+LOCAL_STATIC_LIBRARIES := libscrypt_static
+LOCAL_C_INCLUDES := external/scrypt/lib/crypto
+include $(BUILD_EXECUTABLE)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/gatekeeperd/IGateKeeperService.cpp b/gatekeeperd/IGateKeeperService.cpp
new file mode 100644
index 0000000..95fbfd1
--- /dev/null
+++ b/gatekeeperd/IGateKeeperService.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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.
+*/
+
+#define LOG_TAG "GateKeeperService"
+#include <utils/Log.h>
+
+#include "IGateKeeperService.h"
+
+namespace android {
+
+const android::String16 IGateKeeperService::descriptor("android.service.gatekeeper.IGateKeeperService");
+const android::String16& IGateKeeperService::getInterfaceDescriptor() const {
+    return IGateKeeperService::descriptor;
+}
+
+status_t BnGateKeeperService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    switch(code) {
+        case ENROLL: {
+            CHECK_INTERFACE(IGateKeeperService, data, reply);
+            uint32_t uid = data.readInt32();
+
+            ssize_t currentPasswordHandleSize = data.readInt32();
+            const uint8_t *currentPasswordHandle =
+                    static_cast<const uint8_t *>(data.readInplace(currentPasswordHandleSize));
+            if (!currentPasswordHandle) currentPasswordHandleSize = 0;
+
+            ssize_t currentPasswordSize = data.readInt32();
+            const uint8_t *currentPassword =
+                    static_cast<const uint8_t *>(data.readInplace(currentPasswordSize));
+            if (!currentPassword) currentPasswordSize = 0;
+
+            ssize_t desiredPasswordSize = data.readInt32();
+            const uint8_t *desiredPassword =
+                    static_cast<const uint8_t *>(data.readInplace(desiredPasswordSize));
+            if (!desiredPassword) desiredPasswordSize = 0;
+
+            uint8_t *out = NULL;
+            uint32_t outSize = 0;
+            int ret = enroll(uid, currentPasswordHandle, currentPasswordHandleSize,
+                    currentPassword, currentPasswordSize, desiredPassword,
+                    desiredPasswordSize, &out, &outSize);
+
+            reply->writeNoException();
+            reply->writeInt32(1);
+            if (ret == 0 && outSize > 0 && out != NULL) {
+                reply->writeInt32(GATEKEEPER_RESPONSE_OK);
+                reply->writeInt32(0);
+                reply->writeInt32(outSize);
+                reply->writeInt32(outSize);
+                void *buf = reply->writeInplace(outSize);
+                memcpy(buf, out, outSize);
+                delete[] out;
+            } else if (ret > 0) {
+                reply->writeInt32(GATEKEEPER_RESPONSE_RETRY);
+                reply->writeInt32(ret);
+            } else {
+                reply->writeInt32(GATEKEEPER_RESPONSE_ERROR);
+            }
+            return NO_ERROR;
+        }
+        case VERIFY: {
+            CHECK_INTERFACE(IGateKeeperService, data, reply);
+            uint32_t uid = data.readInt32();
+            ssize_t currentPasswordHandleSize = data.readInt32();
+            const uint8_t *currentPasswordHandle =
+                    static_cast<const uint8_t *>(data.readInplace(currentPasswordHandleSize));
+            if (!currentPasswordHandle) currentPasswordHandleSize = 0;
+
+            ssize_t currentPasswordSize = data.readInt32();
+            const uint8_t *currentPassword =
+                static_cast<const uint8_t *>(data.readInplace(currentPasswordSize));
+            if (!currentPassword) currentPasswordSize = 0;
+
+            bool request_reenroll = false;
+            int ret = verify(uid, (uint8_t *) currentPasswordHandle,
+                    currentPasswordHandleSize, (uint8_t *) currentPassword, currentPasswordSize,
+                    &request_reenroll);
+
+            reply->writeNoException();
+            reply->writeInt32(1);
+            if (ret == 0) {
+                reply->writeInt32(GATEKEEPER_RESPONSE_OK);
+                reply->writeInt32(request_reenroll ? 1 : 0);
+                reply->writeInt32(0); // no payload returned from this call
+            } else if (ret > 0) {
+                reply->writeInt32(GATEKEEPER_RESPONSE_RETRY);
+                reply->writeInt32(ret);
+            } else {
+                reply->writeInt32(GATEKEEPER_RESPONSE_ERROR);
+            }
+            return NO_ERROR;
+        }
+        case VERIFY_CHALLENGE: {
+            CHECK_INTERFACE(IGateKeeperService, data, reply);
+            uint32_t uid = data.readInt32();
+            uint64_t challenge = data.readInt64();
+            ssize_t currentPasswordHandleSize = data.readInt32();
+            const uint8_t *currentPasswordHandle =
+                    static_cast<const uint8_t *>(data.readInplace(currentPasswordHandleSize));
+            if (!currentPasswordHandle) currentPasswordHandleSize = 0;
+
+            ssize_t currentPasswordSize = data.readInt32();
+            const uint8_t *currentPassword =
+                static_cast<const uint8_t *>(data.readInplace(currentPasswordSize));
+            if (!currentPassword) currentPasswordSize = 0;
+
+
+            uint8_t *out = NULL;
+            uint32_t outSize = 0;
+            bool request_reenroll = false;
+            int ret = verifyChallenge(uid, challenge, (uint8_t *) currentPasswordHandle,
+                    currentPasswordHandleSize, (uint8_t *) currentPassword, currentPasswordSize,
+                    &out, &outSize, &request_reenroll);
+            reply->writeNoException();
+            reply->writeInt32(1);
+            if (ret == 0 && outSize > 0 && out != NULL) {
+                reply->writeInt32(GATEKEEPER_RESPONSE_OK);
+                reply->writeInt32(request_reenroll ? 1 : 0);
+                reply->writeInt32(outSize);
+                reply->writeInt32(outSize);
+                void *buf = reply->writeInplace(outSize);
+                memcpy(buf, out, outSize);
+                delete[] out;
+            } else if (ret > 0) {
+                reply->writeInt32(GATEKEEPER_RESPONSE_RETRY);
+                reply->writeInt32(ret);
+            } else {
+                reply->writeInt32(GATEKEEPER_RESPONSE_ERROR);
+            }
+            return NO_ERROR;
+        }
+        case GET_SECURE_USER_ID: {
+            CHECK_INTERFACE(IGateKeeperService, data, reply);
+            uint32_t uid = data.readInt32();
+            uint64_t sid = getSecureUserId(uid);
+            reply->writeNoException();
+            reply->writeInt64(sid);
+            return NO_ERROR;
+        }
+        case CLEAR_SECURE_USER_ID: {
+            CHECK_INTERFACE(IGateKeeperService, data, reply);
+            uint32_t uid = data.readInt32();
+            clearSecureUserId(uid);
+            reply->writeNoException();
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+};
+
+
+}; // namespace android
diff --git a/gatekeeperd/IGateKeeperService.h b/gatekeeperd/IGateKeeperService.h
new file mode 100644
index 0000000..f070486
--- /dev/null
+++ b/gatekeeperd/IGateKeeperService.h
@@ -0,0 +1,111 @@
+/*
+ * 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 IGATEKEEPER_SERVICE_H_
+#define IGATEKEEPER_SERVICE_H_
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+/*
+ * This must be kept manually in sync with frameworks/base's IGateKeeperService.aidl
+ */
+class IGateKeeperService : public IInterface {
+public:
+    enum {
+        ENROLL = IBinder::FIRST_CALL_TRANSACTION + 0,
+        VERIFY = IBinder::FIRST_CALL_TRANSACTION + 1,
+        VERIFY_CHALLENGE = IBinder::FIRST_CALL_TRANSACTION + 2,
+        GET_SECURE_USER_ID = IBinder::FIRST_CALL_TRANSACTION + 3,
+        CLEAR_SECURE_USER_ID = IBinder::FIRST_CALL_TRANSACTION + 4,
+    };
+
+    enum {
+        GATEKEEPER_RESPONSE_OK = 0,
+        GATEKEEPER_RESPONSE_RETRY = 1,
+        GATEKEEPER_RESPONSE_ERROR = -1,
+    };
+
+    // DECLARE_META_INTERFACE - C++ client interface not needed
+    static const android::String16 descriptor;
+    virtual const android::String16& getInterfaceDescriptor() const;
+    IGateKeeperService() {}
+    virtual ~IGateKeeperService() {}
+
+    /**
+     * Enrolls a password with the GateKeeper. Returns 0 on success, negative on failure.
+     * Returns:
+     * - 0 on success
+     * - A timestamp T > 0 if the call has failed due to throttling and should not
+     *   be reattempted until T milliseconds have elapsed
+     * - -1 on failure
+     */
+    virtual int enroll(uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) = 0;
+
+    /**
+     * Verifies a password previously enrolled with the GateKeeper.
+     * Returns:
+     * - 0 on success
+     * - A timestamp T > 0 if the call has failed due to throttling and should not
+     *   be reattempted until T milliseconds have elapsed
+     * - -1 on failure
+     */
+    virtual int verify(uint32_t uid, const uint8_t *enrolled_password_handle,
+            uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length,
+            bool *request_reenroll) = 0;
+
+    /**
+     * Verifies a password previously enrolled with the GateKeeper.
+     * Returns:
+     * - 0 on success
+     * - A timestamp T > 0 if the call has failed due to throttling and should not
+     *   be reattempted until T milliseconds have elapsed
+     * - -1 on failure
+     */
+    virtual int verifyChallenge(uint32_t uid, uint64_t challenge,
+            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length,
+            uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) = 0;
+    /**
+     * Returns the secure user ID for the provided android user
+     */
+    virtual uint64_t getSecureUserId(uint32_t uid) = 0;
+
+    /**
+     * Clears the secure user ID associated with the user.
+     */
+    virtual void clearSecureUserId(uint32_t uid) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnGateKeeperService: public BnInterface<IGateKeeperService> {
+public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+            uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif
+
diff --git a/gatekeeperd/IUserManager.cpp b/gatekeeperd/IUserManager.cpp
new file mode 100644
index 0000000..8645fc2
--- /dev/null
+++ b/gatekeeperd/IUserManager.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 "IUserManager"
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+
+#include "IUserManager.h"
+
+namespace android {
+
+class BpUserManager : public BpInterface<IUserManager>
+{
+public:
+    BpUserManager(const sp<IBinder>& impl) :
+            BpInterface<IUserManager>(impl) {
+    }
+    virtual int32_t getCredentialOwnerProfile(int32_t user_id) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IUserManager::getInterfaceDescriptor());
+        data.writeInt32(user_id);
+        status_t rc = remote()->transact(GET_CREDENTIAL_OWNER_PROFILE, data, &reply, 0);
+        if (rc != NO_ERROR) {
+            ALOGE("%s: failed (%d)\n", __func__, rc);
+            return -1;
+        }
+
+        int32_t exception = reply.readExceptionCode();
+        if (exception != 0) {
+            ALOGE("%s: got exception (%d)\n", __func__, exception);
+            return -1;
+        }
+
+        return reply.readInt32();
+    }
+
+};
+
+IMPLEMENT_META_INTERFACE(UserManager, "android.os.IUserManager");
+
+}; // namespace android
+
diff --git a/gatekeeperd/IUserManager.h b/gatekeeperd/IUserManager.h
new file mode 100644
index 0000000..640e9b5
--- /dev/null
+++ b/gatekeeperd/IUserManager.h
@@ -0,0 +1,46 @@
+/*
+ * 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 IUSERMANAGER_H_
+#define IUSERMANAGER_H_
+
+#include <inttypes.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+/*
+* Communication channel to UserManager
+*/
+class IUserManager : public IInterface {
+    public:
+        // must be kept in sync with IUserManager.aidl
+        enum {
+            GET_CREDENTIAL_OWNER_PROFILE = IBinder::FIRST_CALL_TRANSACTION + 0,
+        };
+
+        virtual int32_t getCredentialOwnerProfile(int32_t user_id) = 0;
+
+        DECLARE_META_INTERFACE(UserManager);
+};
+
+}; // namespace android
+
+#endif // IUSERMANAGER_H_
+
diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h
new file mode 100644
index 0000000..75fe11d
--- /dev/null
+++ b/gatekeeperd/SoftGateKeeper.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef SOFT_GATEKEEPER_H_
+#define SOFT_GATEKEEPER_H_
+
+extern "C" {
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+#include <crypto_scrypt.h>
+}
+
+#include <UniquePtr.h>
+#include <gatekeeper/gatekeeper.h>
+#include <iostream>
+#include <unordered_map>
+
+namespace gatekeeper {
+
+struct fast_hash_t {
+    uint64_t salt;
+    uint8_t digest[SHA256_DIGEST_LENGTH];
+};
+
+class SoftGateKeeper : public GateKeeper {
+public:
+    static const uint32_t SIGNATURE_LENGTH_BYTES = 32;
+
+    // scrypt params
+    static const uint64_t N = 16384;
+    static const uint32_t r = 8;
+    static const uint32_t p = 1;
+
+    static const int MAX_UINT_32_CHARS = 11;
+
+    SoftGateKeeper() {
+        key_.reset(new uint8_t[SIGNATURE_LENGTH_BYTES]);
+        memset(key_.get(), 0, SIGNATURE_LENGTH_BYTES);
+    }
+
+    virtual ~SoftGateKeeper() {
+    }
+
+    virtual bool GetAuthTokenKey(const uint8_t **auth_token_key,
+            uint32_t *length) const {
+        if (auth_token_key == NULL || length == NULL) return false;
+        uint8_t *auth_token_key_copy = new uint8_t[SIGNATURE_LENGTH_BYTES];
+        memcpy(auth_token_key_copy, key_.get(), SIGNATURE_LENGTH_BYTES);
+
+        *auth_token_key = auth_token_key_copy;
+        *length = SIGNATURE_LENGTH_BYTES;
+        return true;
+    }
+
+    virtual void GetPasswordKey(const uint8_t **password_key, uint32_t *length) {
+        if (password_key == NULL || length == NULL) return;
+        uint8_t *password_key_copy = new uint8_t[SIGNATURE_LENGTH_BYTES];
+        memcpy(password_key_copy, key_.get(), SIGNATURE_LENGTH_BYTES);
+
+        *password_key = password_key_copy;
+        *length = SIGNATURE_LENGTH_BYTES;
+    }
+
+    virtual void ComputePasswordSignature(uint8_t *signature, uint32_t signature_length,
+            const uint8_t *, uint32_t, const uint8_t *password,
+            uint32_t password_length, salt_t salt) const {
+        if (signature == NULL) return;
+        crypto_scrypt(password, password_length, reinterpret_cast<uint8_t *>(&salt),
+                sizeof(salt), N, r, p, signature, signature_length);
+    }
+
+    virtual void GetRandom(void *random, uint32_t requested_length) const {
+        if (random == NULL) return;
+        RAND_pseudo_bytes((uint8_t *) random, requested_length);
+    }
+
+    virtual void ComputeSignature(uint8_t *signature, uint32_t signature_length,
+            const uint8_t *, uint32_t, const uint8_t *, const uint32_t) const {
+        if (signature == NULL) return;
+        memset(signature, 0, signature_length);
+    }
+
+    virtual uint64_t GetMillisecondsSinceBoot() const {
+        struct timespec time;
+        int res = clock_gettime(CLOCK_BOOTTIME, &time);
+        if (res < 0) return 0;
+        return (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000);
+    }
+
+    virtual bool IsHardwareBacked() const {
+        return false;
+    }
+
+    virtual bool GetFailureRecord(uint32_t uid, secure_id_t user_id, failure_record_t *record,
+            bool /* secure */) {
+        failure_record_t *stored = &failure_map_[uid];
+        if (user_id != stored->secure_user_id) {
+            stored->secure_user_id = user_id;
+            stored->last_checked_timestamp = 0;
+            stored->failure_counter = 0;
+        }
+        memcpy(record, stored, sizeof(*record));
+        return true;
+    }
+
+    virtual bool ClearFailureRecord(uint32_t uid, secure_id_t user_id, bool /* secure */) {
+        failure_record_t *stored = &failure_map_[uid];
+        stored->secure_user_id = user_id;
+        stored->last_checked_timestamp = 0;
+        stored->failure_counter = 0;
+        return true;
+    }
+
+    virtual bool WriteFailureRecord(uint32_t uid, failure_record_t *record, bool /* secure */) {
+        failure_map_[uid] = *record;
+        return true;
+    }
+
+    fast_hash_t ComputeFastHash(const SizedBuffer &password, uint64_t salt) {
+        fast_hash_t fast_hash;
+        size_t digest_size = password.length + sizeof(salt);
+        std::unique_ptr<uint8_t[]> digest(new uint8_t[digest_size]);
+        memcpy(digest.get(), &salt, sizeof(salt));
+        memcpy(digest.get() + sizeof(salt), password.buffer.get(), password.length);
+
+        SHA256(digest.get(), digest_size, (uint8_t *) &fast_hash.digest);
+
+        fast_hash.salt = salt;
+        return fast_hash;
+    }
+
+    bool VerifyFast(const fast_hash_t &fast_hash, const SizedBuffer &password) {
+        fast_hash_t computed = ComputeFastHash(password, fast_hash.salt);
+        return memcmp(computed.digest, fast_hash.digest, SHA256_DIGEST_LENGTH) == 0;
+    }
+
+    bool DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) {
+        FastHashMap::const_iterator it = fast_hash_map_.find(expected_handle->user_id);
+        if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) {
+            return true;
+        } else {
+            if (GateKeeper::DoVerify(expected_handle, password)) {
+                uint64_t salt;
+                GetRandom(&salt, sizeof(salt));
+                fast_hash_map_[expected_handle->user_id] = ComputeFastHash(password, salt);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+private:
+
+    typedef std::unordered_map<uint32_t, failure_record_t> FailureRecordMap;
+    typedef std::unordered_map<uint64_t, fast_hash_t> FastHashMap;
+
+    UniquePtr<uint8_t[]> key_;
+    FailureRecordMap failure_map_;
+    FastHashMap fast_hash_map_;
+};
+}
+
+#endif // SOFT_GATEKEEPER_H_
+
diff --git a/gatekeeperd/SoftGateKeeperDevice.cpp b/gatekeeperd/SoftGateKeeperDevice.cpp
new file mode 100644
index 0000000..f5e2ce6
--- /dev/null
+++ b/gatekeeperd/SoftGateKeeperDevice.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "SoftGateKeeper.h"
+#include "SoftGateKeeperDevice.h"
+
+namespace android {
+
+int SoftGateKeeperDevice::enroll(uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) {
+
+    if (enrolled_password_handle == NULL || enrolled_password_handle_length == NULL ||
+            desired_password == NULL || desired_password_length == 0)
+        return -EINVAL;
+
+    // Current password and current password handle go together
+    if (current_password_handle == NULL || current_password_handle_length == 0 ||
+            current_password == NULL || current_password_length == 0) {
+        current_password_handle = NULL;
+        current_password_handle_length = 0;
+        current_password = NULL;
+        current_password_length = 0;
+    }
+
+    SizedBuffer desired_password_buffer(desired_password_length);
+    memcpy(desired_password_buffer.buffer.get(), desired_password, desired_password_length);
+
+    SizedBuffer current_password_handle_buffer(current_password_handle_length);
+    if (current_password_handle) {
+        memcpy(current_password_handle_buffer.buffer.get(), current_password_handle,
+                current_password_handle_length);
+    }
+
+    SizedBuffer current_password_buffer(current_password_length);
+    if (current_password) {
+        memcpy(current_password_buffer.buffer.get(), current_password, current_password_length);
+    }
+
+    EnrollRequest request(uid, &current_password_handle_buffer, &desired_password_buffer,
+            &current_password_buffer);
+    EnrollResponse response;
+
+    impl_->Enroll(request, &response);
+
+    if (response.error == ERROR_RETRY) {
+        return response.retry_timeout;
+    } else if (response.error != ERROR_NONE) {
+        return -EINVAL;
+    }
+
+    *enrolled_password_handle = response.enrolled_password_handle.buffer.release();
+    *enrolled_password_handle_length = response.enrolled_password_handle.length;
+    return 0;
+}
+
+int SoftGateKeeperDevice::verify(uint32_t uid,
+        uint64_t challenge, const uint8_t *enrolled_password_handle,
+        uint32_t enrolled_password_handle_length, const uint8_t *provided_password,
+        uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length,
+        bool *request_reenroll) {
+
+    if (enrolled_password_handle == NULL ||
+            provided_password == NULL) {
+        return -EINVAL;
+    }
+
+    SizedBuffer password_handle_buffer(enrolled_password_handle_length);
+    memcpy(password_handle_buffer.buffer.get(), enrolled_password_handle,
+            enrolled_password_handle_length);
+    SizedBuffer provided_password_buffer(provided_password_length);
+    memcpy(provided_password_buffer.buffer.get(), provided_password, provided_password_length);
+
+    VerifyRequest request(uid, challenge, &password_handle_buffer, &provided_password_buffer);
+    VerifyResponse response;
+
+    impl_->Verify(request, &response);
+
+    if (response.error == ERROR_RETRY) {
+        return response.retry_timeout;
+    } else if (response.error != ERROR_NONE) {
+        return -EINVAL;
+    }
+
+    if (auth_token != NULL && auth_token_length != NULL) {
+       *auth_token = response.auth_token.buffer.release();
+       *auth_token_length = response.auth_token.length;
+    }
+
+    if (request_reenroll != NULL) {
+        *request_reenroll = response.request_reenroll;
+    }
+
+    return 0;
+}
+} // namespace android
diff --git a/gatekeeperd/SoftGateKeeperDevice.h b/gatekeeperd/SoftGateKeeperDevice.h
new file mode 100644
index 0000000..3463c29
--- /dev/null
+++ b/gatekeeperd/SoftGateKeeperDevice.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_GATEKEEPER_DEVICE_H_
+#define SOFT_GATEKEEPER_DEVICE_H_
+
+#include "SoftGateKeeper.h"
+
+#include <UniquePtr.h>
+
+using namespace gatekeeper;
+
+namespace android {
+
+/**
+ * Software based GateKeeper implementation
+ */
+class SoftGateKeeperDevice {
+public:
+    SoftGateKeeperDevice() {
+        impl_.reset(new SoftGateKeeper());
+    }
+
+   // Wrappers to translate the gatekeeper HAL API to the Kegyuard Messages API.
+
+    /**
+     * Enrolls password_payload, which should be derived from a user selected pin or password,
+     * with the authentication factor private key used only for enrolling authentication
+     * factor data.
+     *
+     * Returns: 0 on success or an error code less than 0 on error.
+     * On error, enrolled_password_handle will not be allocated.
+     */
+    int enroll(uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length);
+
+    /**
+     * Verifies provided_password matches enrolled_password_handle.
+     *
+     * Implementations of this module may retain the result of this call
+     * to attest to the recency of authentication.
+     *
+     * On success, writes the address of a verification token to auth_token,
+     * usable to attest password verification to other trusted services. Clients
+     * may pass NULL for this value.
+     *
+     * Returns: 0 on success or an error code less than 0 on error
+     * On error, verification token will not be allocated
+     */
+    int verify(uint32_t uid, uint64_t challenge,
+            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length,
+            uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll);
+private:
+    UniquePtr<SoftGateKeeper> impl_;
+};
+
+} // namespace gatekeeper
+
+#endif //SOFT_GATEKEEPER_DEVICE_H_
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
new file mode 100644
index 0000000..b4fdab0
--- /dev/null
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -0,0 +1,351 @@
+/*
+ * 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 "gatekeeperd"
+
+#include "IGateKeeperService.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <cutils/log.h>
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include <utils/String16.h>
+#include <utils/Log.h>
+
+#include <keystore/IKeystoreService.h>
+#include <keystore/keystore.h> // For error code
+#include <gatekeeper/password_handle.h> // for password_handle_t
+#include <hardware/gatekeeper.h>
+#include <hardware/hw_auth_token.h>
+
+#include "SoftGateKeeperDevice.h"
+#include "IUserManager.h"
+
+namespace android {
+
+static const String16 KEYGUARD_PERMISSION("android.permission.ACCESS_KEYGUARD_SECURE_STORAGE");
+static const String16 DUMP_PERMISSION("android.permission.DUMP");
+
+class GateKeeperProxy : public BnGateKeeperService {
+public:
+    GateKeeperProxy() {
+        int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module);
+        device = NULL;
+
+        if (ret < 0) {
+            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);
+            }
+        }
+    }
+
+    virtual ~GateKeeperProxy() {
+        if (device) gatekeeper_close(device);
+    }
+
+    void store_sid(uint32_t uid, uint64_t sid) {
+        char filename[21];
+        sprintf(filename, "%u", uid);
+        int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
+        if (fd < 0) {
+            ALOGE("could not open file: %s: %s", filename, strerror(errno));
+            return;
+        }
+        write(fd, &sid, sizeof(sid));
+        close(fd);
+    }
+
+    bool mark_cold_boot() {
+        const char *filename = ".coldboot";
+        if (access(filename, F_OK) == -1) {
+            int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
+            if (fd < 0) {
+                ALOGE("could not open file: %s : %s", filename, strerror(errno));
+                return false;
+            }
+            close(fd);
+            return true;
+        }
+        return false;
+    }
+
+    void maybe_store_sid(uint32_t uid, uint64_t sid) {
+        char filename[21];
+        sprintf(filename, "%u", uid);
+        if (access(filename, F_OK) == -1) {
+            store_sid(uid, sid);
+        }
+    }
+
+    uint64_t read_sid(uint32_t uid) {
+        char filename[21];
+        uint64_t sid;
+        sprintf(filename, "%u", uid);
+        int fd = open(filename, O_RDONLY);
+        if (fd < 0) return 0;
+        read(fd, &sid, sizeof(sid));
+        close(fd);
+        return sid;
+    }
+
+    void clear_sid(uint32_t uid) {
+        char filename[21];
+        sprintf(filename, "%u", uid);
+        if (remove(filename) < 0) {
+            ALOGE("%s: could not remove file [%s], attempting 0 write", __func__, strerror(errno));
+            store_sid(uid, 0);
+        }
+    }
+
+    virtual int enroll(uint32_t uid,
+            const uint8_t *current_password_handle, uint32_t current_password_handle_length,
+            const uint8_t *current_password, uint32_t current_password_length,
+            const uint8_t *desired_password, uint32_t desired_password_length,
+            uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) {
+        IPCThreadState* ipc = IPCThreadState::self();
+        const int calling_pid = ipc->getCallingPid();
+        const int calling_uid = ipc->getCallingUid();
+        if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) {
+            return PERMISSION_DENIED;
+        }
+
+        // need a desired password to enroll
+        if (desired_password_length == 0) return -EINVAL;
+
+        int ret;
+        if (device) {
+            const gatekeeper::password_handle_t *handle =
+                    reinterpret_cast<const gatekeeper::password_handle_t *>(current_password_handle);
+
+            if (handle != NULL && handle->version != 0 && !handle->hardware_backed) {
+                // handle is being re-enrolled from a software version. HAL probably won't accept
+                // the handle as valid, so we nullify it and enroll from scratch
+                current_password_handle = NULL;
+                current_password_handle_length = 0;
+                current_password = NULL;
+                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);
+        } else {
+            ret = soft_device->enroll(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);
+        }
+
+        if (ret == 0) {
+            gatekeeper::password_handle_t *handle =
+                    reinterpret_cast<gatekeeper::password_handle_t *>(*enrolled_password_handle);
+            store_sid(uid, handle->user_id);
+            bool rr;
+
+            // immediately verify this password so we don't ask the user to enter it again
+            // if they just created it.
+            verify(uid, *enrolled_password_handle, sizeof(password_handle_t), desired_password,
+                    desired_password_length, &rr);
+        }
+
+        return ret;
+    }
+
+    virtual int verify(uint32_t uid,
+            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length, bool *request_reenroll) {
+        uint8_t *auth_token;
+        uint32_t auth_token_length;
+        return verifyChallenge(uid, 0, enrolled_password_handle, enrolled_password_handle_length,
+                provided_password, provided_password_length,
+                &auth_token, &auth_token_length, request_reenroll);
+    }
+
+    virtual int verifyChallenge(uint32_t uid, uint64_t challenge,
+            const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,
+            const uint8_t *provided_password, uint32_t provided_password_length,
+            uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) {
+        IPCThreadState* ipc = IPCThreadState::self();
+        const int calling_pid = ipc->getCallingPid();
+        const int calling_uid = ipc->getCallingUid();
+        if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) {
+            return PERMISSION_DENIED;
+        }
+
+        // can't verify if we're missing either param
+        if ((enrolled_password_handle_length | provided_password_length) == 0)
+            return -EINVAL;
+
+        int ret;
+        if (device) {
+            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);
+            } else {
+                // upgrade scenario, a HAL has been added to this device where there was none before
+                SoftGateKeeperDevice soft_dev;
+                ret = soft_dev.verify(uid, challenge,
+                    enrolled_password_handle, enrolled_password_handle_length,
+                    provided_password, provided_password_length, auth_token, auth_token_length,
+                    request_reenroll);
+
+                if (ret == 0) {
+                    // success! re-enroll with HAL
+                    *request_reenroll = true;
+                }
+            }
+        } else {
+            ret = soft_device->verify(uid, challenge,
+                enrolled_password_handle, enrolled_password_handle_length,
+                provided_password, provided_password_length, auth_token, auth_token_length,
+                request_reenroll);
+        }
+
+        if (ret == 0 && *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");
+            }
+        }
+
+        if (ret == 0) {
+            maybe_store_sid(uid, reinterpret_cast<const gatekeeper::password_handle_t *>(
+                        enrolled_password_handle)->user_id);
+        }
+
+        return ret;
+    }
+
+    virtual uint64_t getSecureUserId(uint32_t uid) {
+        uint64_t sid = read_sid(uid);
+         if (sid == 0) {
+            // might be a work profile, look up the parent
+            sp<IServiceManager> sm = defaultServiceManager();
+            sp<IBinder> binder = sm->getService(String16("user"));
+            sp<IUserManager> um = interface_cast<IUserManager>(binder);
+            int32_t parent = um->getCredentialOwnerProfile(uid);
+            if (parent < 0) {
+                return 0;
+            } else if (parent != (int32_t) uid) {
+                return read_sid(parent);
+            }
+        }
+        return sid;
+
+    }
+
+    virtual void clearSecureUserId(uint32_t uid) {
+        IPCThreadState* ipc = IPCThreadState::self();
+        const int calling_pid = ipc->getCallingPid();
+        const int calling_uid = ipc->getCallingUid();
+        if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) {
+            ALOGE("%s: permission denied for [%d:%d]", __func__, calling_pid, calling_uid);
+            return;
+        }
+        clear_sid(uid);
+
+        if (device != NULL && device->delete_user != NULL) {
+            device->delete_user(device, uid);
+        }
+    }
+
+    virtual status_t dump(int fd, const Vector<String16> &) {
+        IPCThreadState* ipc = IPCThreadState::self();
+        const int pid = ipc->getCallingPid();
+        const int uid = ipc->getCallingUid();
+        if (!PermissionCache::checkPermission(DUMP_PERMISSION, pid, uid)) {
+            return PERMISSION_DENIED;
+        }
+
+        if (device == NULL) {
+            const char *result = "Device not available";
+            write(fd, result, strlen(result) + 1);
+        } else {
+            const char *result = "OK";
+            write(fd, result, strlen(result) + 1);
+        }
+
+        return NO_ERROR;
+    }
+
+private:
+    gatekeeper_device_t *device;
+    UniquePtr<SoftGateKeeperDevice> soft_device;
+    const hw_module_t *module;
+};
+}// namespace android
+
+int main(int argc, char* argv[]) {
+    ALOGI("Starting gatekeeperd...");
+    if (argc < 2) {
+        ALOGE("A directory must be specified!");
+        return 1;
+    }
+    if (chdir(argv[1]) == -1) {
+        ALOGE("chdir: %s: %s", argv[1], strerror(errno));
+        return 1;
+    }
+
+    android::sp<android::IServiceManager> sm = android::defaultServiceManager();
+    android::sp<android::GateKeeperProxy> proxy = new android::GateKeeperProxy();
+    android::status_t ret = sm->addService(
+            android::String16("android.service.gatekeeper.IGateKeeperService"), proxy);
+    if (ret != android::OK) {
+        ALOGE("Couldn't register 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();
+    return 0;
+}
diff --git a/gatekeeperd/tests/Android.mk b/gatekeeperd/tests/Android.mk
new file mode 100644
index 0000000..6fc4ac0
--- /dev/null
+++ b/gatekeeperd/tests/Android.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := gatekeeperd-unit-tests
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
+LOCAL_SHARED_LIBRARIES := libgatekeeper libcrypto
+LOCAL_STATIC_LIBRARIES := libscrypt_static
+LOCAL_C_INCLUDES := external/scrypt/lib/crypto
+LOCAL_SRC_FILES := \
+	gatekeeper_test.cpp
+include $(BUILD_NATIVE_TEST)
+
diff --git a/gatekeeperd/tests/gatekeeper_test.cpp b/gatekeeperd/tests/gatekeeper_test.cpp
new file mode 100644
index 0000000..c504f92
--- /dev/null
+++ b/gatekeeperd/tests/gatekeeper_test.cpp
@@ -0,0 +1,206 @@
+/*
+ * 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 <arpa/inet.h>
+#include <iostream>
+
+#include <gtest/gtest.h>
+#include <UniquePtr.h>
+
+#include <hardware/hw_auth_token.h>
+
+#include "../SoftGateKeeper.h"
+
+using ::gatekeeper::SizedBuffer;
+using ::testing::Test;
+using ::gatekeeper::EnrollRequest;
+using ::gatekeeper::EnrollResponse;
+using ::gatekeeper::VerifyRequest;
+using ::gatekeeper::VerifyResponse;
+using ::gatekeeper::SoftGateKeeper;
+using ::gatekeeper::secure_id_t;
+
+static void do_enroll(SoftGateKeeper &gatekeeper, EnrollResponse *response) {
+    SizedBuffer password;
+
+    password.buffer.reset(new uint8_t[16]);
+    password.length = 16;
+    memset(password.buffer.get(), 0, 16);
+    EnrollRequest request(0, NULL, &password, NULL);
+
+    gatekeeper.Enroll(request, response);
+}
+
+TEST(GateKeeperTest, EnrollSuccess) {
+    SoftGateKeeper gatekeeper;
+    EnrollResponse response;
+    do_enroll(gatekeeper, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+}
+
+TEST(GateKeeperTest, EnrollBogusData) {
+    SoftGateKeeper gatekeeper;
+    SizedBuffer password;
+    EnrollResponse response;
+
+    EnrollRequest request(0, NULL, &password, NULL);
+
+    gatekeeper.Enroll(request, &response);
+
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_INVALID, response.error);
+}
+
+TEST(GateKeeperTest, VerifySuccess) {
+    SoftGateKeeper gatekeeper;
+    SizedBuffer provided_password;
+    EnrollResponse enroll_response;
+
+    provided_password.buffer.reset(new uint8_t[16]);
+    provided_password.length = 16;
+    memset(provided_password.buffer.get(), 0, 16);
+
+    do_enroll(gatekeeper, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+    VerifyRequest request(0, 1, &enroll_response.enrolled_password_handle,
+            &provided_password);
+    VerifyResponse response;
+
+    gatekeeper.Verify(request, &response);
+
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+
+    hw_auth_token_t *auth_token =
+        reinterpret_cast<hw_auth_token_t *>(response.auth_token.buffer.get());
+
+    ASSERT_EQ((uint32_t) HW_AUTH_PASSWORD, ntohl(auth_token->authenticator_type));
+    ASSERT_EQ((uint64_t) 1, auth_token->challenge);
+    ASSERT_NE(~((uint32_t) 0), auth_token->timestamp);
+    ASSERT_NE((uint64_t) 0, auth_token->user_id);
+    ASSERT_NE((uint64_t) 0, auth_token->authenticator_id);
+}
+
+TEST(GateKeeperTest, TrustedReEnroll) {
+    SoftGateKeeper gatekeeper;
+    SizedBuffer provided_password;
+    EnrollResponse enroll_response;
+    SizedBuffer password_handle;
+
+    // do_enroll enrolls an all 0 password
+    provided_password.buffer.reset(new uint8_t[16]);
+    provided_password.length = 16;
+    memset(provided_password.buffer.get(), 0, 16);
+    do_enroll(gatekeeper, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+    // keep a copy of the handle
+    password_handle.buffer.reset(new uint8_t[enroll_response.enrolled_password_handle.length]);
+    password_handle.length = enroll_response.enrolled_password_handle.length;
+    memcpy(password_handle.buffer.get(), enroll_response.enrolled_password_handle.buffer.get(),
+            password_handle.length);
+
+    // verify first password
+    VerifyRequest request(0, 0, &enroll_response.enrolled_password_handle,
+            &provided_password);
+    VerifyResponse response;
+    gatekeeper.Verify(request, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+    hw_auth_token_t *auth_token =
+        reinterpret_cast<hw_auth_token_t *>(response.auth_token.buffer.get());
+
+    secure_id_t secure_id = auth_token->user_id;
+
+    // enroll new password
+    provided_password.buffer.reset(new uint8_t[16]);
+    provided_password.length = 16;
+    memset(provided_password.buffer.get(), 0, 16);
+    SizedBuffer password;
+    password.buffer.reset(new uint8_t[16]);
+    memset(password.buffer.get(), 1, 16);
+    password.length = 16;
+    EnrollRequest enroll_request(0, &password_handle, &password, &provided_password);
+    gatekeeper.Enroll(enroll_request, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+    // verify new password
+    password.buffer.reset(new uint8_t[16]);
+    memset(password.buffer.get(), 1, 16);
+    password.length = 16;
+    VerifyRequest new_request(0, 0, &enroll_response.enrolled_password_handle,
+            &password);
+    gatekeeper.Verify(new_request, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+    ASSERT_EQ(secure_id,
+        reinterpret_cast<hw_auth_token_t *>(response.auth_token.buffer.get())->user_id);
+}
+
+
+TEST(GateKeeperTest, UntrustedReEnroll) {
+    SoftGateKeeper gatekeeper;
+    SizedBuffer provided_password;
+    EnrollResponse enroll_response;
+
+    // do_enroll enrolls an all 0 password
+    provided_password.buffer.reset(new uint8_t[16]);
+    provided_password.length = 16;
+    memset(provided_password.buffer.get(), 0, 16);
+    do_enroll(gatekeeper, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+    // verify first password
+    VerifyRequest request(0, 0, &enroll_response.enrolled_password_handle,
+            &provided_password);
+    VerifyResponse response;
+    gatekeeper.Verify(request, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+    hw_auth_token_t *auth_token =
+        reinterpret_cast<hw_auth_token_t *>(response.auth_token.buffer.get());
+
+    secure_id_t secure_id = auth_token->user_id;
+
+    // enroll new password
+    SizedBuffer password;
+    password.buffer.reset(new uint8_t[16]);
+    memset(password.buffer.get(), 1, 16);
+    password.length = 16;
+    EnrollRequest enroll_request(0, NULL, &password, NULL);
+    gatekeeper.Enroll(enroll_request, &enroll_response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error);
+
+    // verify new password
+    password.buffer.reset(new uint8_t[16]);
+    memset(password.buffer.get(), 1, 16);
+    password.length = 16;
+    VerifyRequest new_request(0, 0, &enroll_response.enrolled_password_handle,
+            &password);
+    gatekeeper.Verify(new_request, &response);
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error);
+    ASSERT_NE(secure_id,
+        reinterpret_cast<hw_auth_token_t *>(response.auth_token.buffer.get())->user_id);
+}
+
+
+TEST(GateKeeperTest, VerifyBogusData) {
+    SoftGateKeeper gatekeeper;
+    SizedBuffer provided_password;
+    SizedBuffer password_handle;
+    VerifyResponse response;
+
+    VerifyRequest request(0, 0, &provided_password, &password_handle);
+
+    gatekeeper.Verify(request, &response);
+
+    ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_INVALID, response.error);
+}
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index 1fee855..b0002cc 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -53,6 +53,7 @@
     .batteryCurrentAvgPath = String8(String8::kEmptyString),
     .batteryChargeCounterPath = String8(String8::kEmptyString),
     .energyCounter = NULL,
+    .boot_min_cap = 0,
     .screen_on = NULL,
 };
 
diff --git a/healthd/healthd.h b/healthd/healthd.h
index 4704f0b..84b6d76 100644
--- a/healthd/healthd.h
+++ b/healthd/healthd.h
@@ -67,6 +67,7 @@
     android::String8 batteryChargeCounterPath;
 
     int (*energyCounter)(int64_t *);
+    int boot_min_cap;
     bool (*screen_on)(android::BatteryProperties *props);
 };
 
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 78f8403..6800ad2 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -116,6 +116,7 @@
 
     struct animation *batt_anim;
     GRSurface* surf_unknown;
+    int boot_min_cap;
 };
 
 static struct frame batt_anim_frames[] = {
@@ -520,19 +521,29 @@
                     LOGW("[%" PRId64 "] booting from charger mode\n", now);
                     property_set("sys.boot_from_charger_mode", "1");
                 } else {
-                    LOGW("[%" PRId64 "] rebooting\n", now);
-                    android_reboot(ANDROID_RB_RESTART, 0, 0);
+                    if (charger->batt_anim->capacity >= charger->boot_min_cap) {
+                        LOGW("[%" PRId64 "] rebooting\n", now);
+                        android_reboot(ANDROID_RB_RESTART, 0, 0);
+                    } else {
+                        LOGV("[%" PRId64 "] ignore power-button press, battery level "
+                            "less than minimum\n", now);
+                    }
                 }
             } else {
                 /* if the key is pressed but timeout hasn't expired,
                  * make sure we wake up at the right-ish time to check
                  */
                 set_next_key_check(charger, key, POWER_ON_KEY_TIME);
+
+               /* Turn on the display and kick animation on power-key press
+                * rather than on key release
+                */
+                kick_animation(charger->batt_anim);
+                request_suspend(false);
             }
         } else {
             /* if the power key got released, force screen state cycle */
             if (key->pending) {
-                request_suspend(false);
                 kick_animation(charger->batt_anim);
             }
         }
@@ -555,6 +566,11 @@
         return;
 
     if (!charger->charger_connected) {
+
+        /* Last cycle would have stopped at the extreme top of battery-icon
+         * Need to show the correct level corresponding to capacity.
+         */
+        kick_animation(charger->batt_anim);
         request_suspend(false);
         if (charger->next_pwr_check == -1) {
             charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
@@ -705,4 +721,5 @@
     charger->next_key_check = -1;
     charger->next_pwr_check = -1;
     healthd_config = config;
+    charger->boot_min_cap = config->boot_min_cap;
 }
diff --git a/include/cutils/sched_policy.h b/include/cutils/sched_policy.h
index ba84ce3..6a8d570 100644
--- a/include/cutils/sched_policy.h
+++ b/include/cutils/sched_policy.h
@@ -34,6 +34,8 @@
     SP_SYSTEM_DEFAULT = SP_FOREGROUND,
 } SchedPolicy;
 
+extern int set_cpuset_policy(int tid, SchedPolicy policy);
+
 /* Assign thread tid to the cgroup associated with the specified policy.
  * If the thread is a thread group leader, that is it's gettid() == getpid(),
  * then the other threads in the same thread group are _not_ affected.
diff --git a/include/netutils/dhcp.h b/include/netutils/dhcp.h
index de6bc82..008dbd8 100644
--- a/include/netutils/dhcp.h
+++ b/include/netutils/dhcp.h
@@ -23,26 +23,18 @@
 __BEGIN_DECLS
 
 extern int do_dhcp(char *iname);
-extern int dhcp_do_request(const char *ifname,
-                          char *ipaddr,
-                          char *gateway,
-                          uint32_t *prefixLength,
-                          char *dns[],
-                          char *server,
-                          uint32_t *lease,
-                          char *vendorInfo,
-                          char *domain,
-                          char *mtu);
-extern int dhcp_do_request_renew(const char *ifname,
-                                char *ipaddr,
-                                char *gateway,
-                                uint32_t *prefixLength,
-                                char *dns[],
-                                char *server,
-                                uint32_t *lease,
-                                char *vendorInfo,
-                                char *domain,
-                                char *mtu);
+extern int dhcp_start(const char *ifname);
+extern int dhcp_start_renew(const char *ifname);
+extern int dhcp_get_results(const char *ifname,
+                            char *ipaddr,
+                            char *gateway,
+                            uint32_t *prefixLength,
+                            char *dns[],
+                            char *server,
+                            uint32_t *lease,
+                            char *vendorInfo,
+                            char *domain,
+                            char *mtu);
 extern int dhcp_stop(const char *ifname);
 extern int dhcp_release_lease(const char *ifname);
 extern char *dhcp_get_errmsg();
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 7047e0f..a843171 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -212,13 +212,13 @@
  * Used in:
  *  build/tools/fs_config/fs_config.c
  *  build/tools/fs_get_stats/fs_get_stats.c
- *  external/genext2fs/genext2fs.c
+ *  system/extras/ext4_utils/make_ext4fs_main.c
  *  external/squashfs-tools/squashfs-tools/android.c
  *  system/core/cpio/mkbootfs.c
  *  system/core/adb/file_sync_service.cpp
  *  system/extras/ext4_utils/canned_fs_config.c
  */
-void fs_config(const char *path, int dir,
+void fs_config(const char *path, int dir, const char *target_out_path,
                unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities);
 
 ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc);
diff --git a/include/system/audio.h b/include/system/audio.h
deleted file mode 100644
index ced2005..0000000
--- a/include/system/audio.h
+++ /dev/null
@@ -1,1375 +0,0 @@
-/*
- * Copyright (C) 2011 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 ANDROID_AUDIO_CORE_H
-#define ANDROID_AUDIO_CORE_H
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <cutils/bitops.h>
-
-__BEGIN_DECLS
-
-/* The enums were moved here mostly from
- * frameworks/base/include/media/AudioSystem.h
- */
-
-/* device address used to refer to the standard remote submix */
-#define AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS "0"
-
-/* AudioFlinger and AudioPolicy services use I/O handles to identify audio sources and sinks */
-typedef int audio_io_handle_t;
-#define AUDIO_IO_HANDLE_NONE    0
-
-/* Audio stream types */
-typedef enum {
-    /* These values must kept in sync with
-     * frameworks/base/media/java/android/media/AudioSystem.java
-     */
-    AUDIO_STREAM_DEFAULT          = -1,
-    AUDIO_STREAM_MIN              = 0,
-    AUDIO_STREAM_VOICE_CALL       = 0,
-    AUDIO_STREAM_SYSTEM           = 1,
-    AUDIO_STREAM_RING             = 2,
-    AUDIO_STREAM_MUSIC            = 3,
-    AUDIO_STREAM_ALARM            = 4,
-    AUDIO_STREAM_NOTIFICATION     = 5,
-    AUDIO_STREAM_BLUETOOTH_SCO    = 6,
-    AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user
-                                        * and must be routed to speaker
-                                        */
-    AUDIO_STREAM_DTMF             = 8,
-    AUDIO_STREAM_TTS              = 9,  /* Transmitted Through Speaker.
-                                         * Plays over speaker only, silent on other devices.
-                                         */
-    AUDIO_STREAM_ACCESSIBILITY    = 10, /* For accessibility talk back prompts */
-    AUDIO_STREAM_REROUTING        = 11, /* For dynamic policy output mixes */
-    AUDIO_STREAM_PATCH            = 12, /* For internal audio flinger tracks. Fixed volume */
-    AUDIO_STREAM_PUBLIC_CNT       = AUDIO_STREAM_TTS + 1,
-    AUDIO_STREAM_CNT              = AUDIO_STREAM_PATCH + 1,
-} audio_stream_type_t;
-
-/* Do not change these values without updating their counterparts
- * in frameworks/base/media/java/android/media/AudioAttributes.java
- */
-typedef enum {
-    AUDIO_CONTENT_TYPE_UNKNOWN      = 0,
-    AUDIO_CONTENT_TYPE_SPEECH       = 1,
-    AUDIO_CONTENT_TYPE_MUSIC        = 2,
-    AUDIO_CONTENT_TYPE_MOVIE        = 3,
-    AUDIO_CONTENT_TYPE_SONIFICATION = 4,
-
-    AUDIO_CONTENT_TYPE_CNT,
-    AUDIO_CONTENT_TYPE_MAX          = AUDIO_CONTENT_TYPE_CNT - 1,
-} audio_content_type_t;
-
-/* Do not change these values without updating their counterparts
- * in frameworks/base/media/java/android/media/AudioAttributes.java
- */
-typedef enum {
-    AUDIO_USAGE_UNKNOWN                            = 0,
-    AUDIO_USAGE_MEDIA                              = 1,
-    AUDIO_USAGE_VOICE_COMMUNICATION                = 2,
-    AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING     = 3,
-    AUDIO_USAGE_ALARM                              = 4,
-    AUDIO_USAGE_NOTIFICATION                       = 5,
-    AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE    = 6,
-    AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7,
-    AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8,
-    AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9,
-    AUDIO_USAGE_NOTIFICATION_EVENT                 = 10,
-    AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY           = 11,
-    AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE     = 12,
-    AUDIO_USAGE_ASSISTANCE_SONIFICATION            = 13,
-    AUDIO_USAGE_GAME                               = 14,
-    AUDIO_USAGE_VIRTUAL_SOURCE                     = 15,
-
-    AUDIO_USAGE_CNT,
-    AUDIO_USAGE_MAX                                = AUDIO_USAGE_CNT - 1,
-} audio_usage_t;
-
-typedef uint32_t audio_flags_mask_t;
-
-/* Do not change these values without updating their counterparts
- * in frameworks/base/media/java/android/media/AudioAttributes.java
- */
-enum {
-    AUDIO_FLAG_AUDIBILITY_ENFORCED = 0x1,
-    AUDIO_FLAG_SECURE              = 0x2,
-    AUDIO_FLAG_SCO                 = 0x4,
-    AUDIO_FLAG_BEACON              = 0x8,
-    AUDIO_FLAG_HW_AV_SYNC          = 0x10,
-    AUDIO_FLAG_HW_HOTWORD          = 0x20,
-};
-
-/* Do not change these values without updating their counterparts
- * in frameworks/base/media/java/android/media/MediaRecorder.java,
- * frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
- * and system/media/audio_effects/include/audio_effects/audio_effects_conf.h!
- */
-typedef enum {
-    AUDIO_SOURCE_DEFAULT             = 0,
-    AUDIO_SOURCE_MIC                 = 1,
-    AUDIO_SOURCE_VOICE_UPLINK        = 2,
-    AUDIO_SOURCE_VOICE_DOWNLINK      = 3,
-    AUDIO_SOURCE_VOICE_CALL          = 4,
-    AUDIO_SOURCE_CAMCORDER           = 5,
-    AUDIO_SOURCE_VOICE_RECOGNITION   = 6,
-    AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
-    AUDIO_SOURCE_REMOTE_SUBMIX       = 8, /* Source for the mix to be presented remotely.      */
-                                          /* An example of remote presentation is Wifi Display */
-                                          /*  where a dongle attached to a TV can be used to   */
-                                          /*  play the mix captured by this audio source.      */
-    AUDIO_SOURCE_CNT,
-    AUDIO_SOURCE_MAX                 = AUDIO_SOURCE_CNT - 1,
-    AUDIO_SOURCE_FM_TUNER            = 1998,
-    AUDIO_SOURCE_HOTWORD             = 1999, /* A low-priority, preemptible audio source for
-                                                for background software hotword detection.
-                                                Same tuning as AUDIO_SOURCE_VOICE_RECOGNITION.
-                                                Used only internally to the framework. Not exposed
-                                                at the audio HAL. */
-} audio_source_t;
-
-/* Audio attributes */
-#define AUDIO_ATTRIBUTES_TAGS_MAX_SIZE 256
-typedef struct {
-    audio_content_type_t content_type;
-    audio_usage_t        usage;
-    audio_source_t       source;
-    audio_flags_mask_t   flags;
-    char                 tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */
-} audio_attributes_t;
-
-/* special audio session values
- * (XXX: should this be living in the audio effects land?)
- */
-typedef enum {
-    /* session for effects attached to a particular output stream
-     * (value must be less than 0)
-     */
-    AUDIO_SESSION_OUTPUT_STAGE = -1,
-
-    /* session for effects applied to output mix. These effects can
-     * be moved by audio policy manager to another output stream
-     * (value must be 0)
-     */
-    AUDIO_SESSION_OUTPUT_MIX = 0,
-
-    /* application does not specify an explicit session ID to be used,
-     * and requests a new session ID to be allocated
-     * TODO use unique values for AUDIO_SESSION_OUTPUT_MIX and AUDIO_SESSION_ALLOCATE,
-     * after all uses have been updated from 0 to the appropriate symbol, and have been tested.
-     */
-    AUDIO_SESSION_ALLOCATE = 0,
-} audio_session_t;
-
-/* a unique ID allocated by AudioFlinger for use as a audio_io_handle_t or audio_session_t */
-typedef int audio_unique_id_t;
-
-#define AUDIO_UNIQUE_ID_ALLOCATE AUDIO_SESSION_ALLOCATE
-
-/* Audio sub formats (see enum audio_format). */
-
-/* PCM sub formats */
-typedef enum {
-    /* All of these are in native byte order */
-    AUDIO_FORMAT_PCM_SUB_16_BIT          = 0x1, /* DO NOT CHANGE - PCM signed 16 bits */
-    AUDIO_FORMAT_PCM_SUB_8_BIT           = 0x2, /* DO NOT CHANGE - PCM unsigned 8 bits */
-    AUDIO_FORMAT_PCM_SUB_32_BIT          = 0x3, /* PCM signed .31 fixed point */
-    AUDIO_FORMAT_PCM_SUB_8_24_BIT        = 0x4, /* PCM signed 7.24 fixed point */
-    AUDIO_FORMAT_PCM_SUB_FLOAT           = 0x5, /* PCM single-precision floating point */
-    AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED   = 0x6, /* PCM signed .23 fixed point packed in 3 bytes */
-} audio_format_pcm_sub_fmt_t;
-
-/* The audio_format_*_sub_fmt_t declarations are not currently used */
-
-/* MP3 sub format field definition : can use 11 LSBs in the same way as MP3
- * frame header to specify bit rate, stereo mode, version...
- */
-typedef enum {
-    AUDIO_FORMAT_MP3_SUB_NONE            = 0x0,
-} audio_format_mp3_sub_fmt_t;
-
-/* AMR NB/WB sub format field definition: specify frame block interleaving,
- * bandwidth efficient or octet aligned, encoding mode for recording...
- */
-typedef enum {
-    AUDIO_FORMAT_AMR_SUB_NONE            = 0x0,
-} audio_format_amr_sub_fmt_t;
-
-/* AAC sub format field definition: specify profile or bitrate for recording... */
-typedef enum {
-    AUDIO_FORMAT_AAC_SUB_MAIN            = 0x1,
-    AUDIO_FORMAT_AAC_SUB_LC              = 0x2,
-    AUDIO_FORMAT_AAC_SUB_SSR             = 0x4,
-    AUDIO_FORMAT_AAC_SUB_LTP             = 0x8,
-    AUDIO_FORMAT_AAC_SUB_HE_V1           = 0x10,
-    AUDIO_FORMAT_AAC_SUB_SCALABLE        = 0x20,
-    AUDIO_FORMAT_AAC_SUB_ERLC            = 0x40,
-    AUDIO_FORMAT_AAC_SUB_LD              = 0x80,
-    AUDIO_FORMAT_AAC_SUB_HE_V2           = 0x100,
-    AUDIO_FORMAT_AAC_SUB_ELD             = 0x200,
-} audio_format_aac_sub_fmt_t;
-
-/* VORBIS sub format field definition: specify quality for recording... */
-typedef enum {
-    AUDIO_FORMAT_VORBIS_SUB_NONE         = 0x0,
-} audio_format_vorbis_sub_fmt_t;
-
-/* Audio format consists of a main format field (upper 8 bits) and a sub format
- * field (lower 24 bits).
- *
- * The main format indicates the main codec type. The sub format field
- * indicates options and parameters for each format. The sub format is mainly
- * used for record to indicate for instance the requested bitrate or profile.
- * It can also be used for certain formats to give informations not present in
- * the encoded audio stream (e.g. octet alignement for AMR).
- */
-typedef enum {
-    AUDIO_FORMAT_INVALID             = 0xFFFFFFFFUL,
-    AUDIO_FORMAT_DEFAULT             = 0,
-    AUDIO_FORMAT_PCM                 = 0x00000000UL, /* DO NOT CHANGE */
-    AUDIO_FORMAT_MP3                 = 0x01000000UL,
-    AUDIO_FORMAT_AMR_NB              = 0x02000000UL,
-    AUDIO_FORMAT_AMR_WB              = 0x03000000UL,
-    AUDIO_FORMAT_AAC                 = 0x04000000UL,
-    AUDIO_FORMAT_HE_AAC_V1           = 0x05000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V1*/
-    AUDIO_FORMAT_HE_AAC_V2           = 0x06000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V2*/
-    AUDIO_FORMAT_VORBIS              = 0x07000000UL,
-    AUDIO_FORMAT_OPUS                = 0x08000000UL,
-    AUDIO_FORMAT_AC3                 = 0x09000000UL,
-    AUDIO_FORMAT_E_AC3               = 0x0A000000UL,
-    AUDIO_FORMAT_MAIN_MASK           = 0xFF000000UL,
-    AUDIO_FORMAT_SUB_MASK            = 0x00FFFFFFUL,
-
-    /* Aliases */
-    /* note != AudioFormat.ENCODING_PCM_16BIT */
-    AUDIO_FORMAT_PCM_16_BIT          = (AUDIO_FORMAT_PCM |
-                                        AUDIO_FORMAT_PCM_SUB_16_BIT),
-    /* note != AudioFormat.ENCODING_PCM_8BIT */
-    AUDIO_FORMAT_PCM_8_BIT           = (AUDIO_FORMAT_PCM |
-                                        AUDIO_FORMAT_PCM_SUB_8_BIT),
-    AUDIO_FORMAT_PCM_32_BIT          = (AUDIO_FORMAT_PCM |
-                                        AUDIO_FORMAT_PCM_SUB_32_BIT),
-    AUDIO_FORMAT_PCM_8_24_BIT        = (AUDIO_FORMAT_PCM |
-                                        AUDIO_FORMAT_PCM_SUB_8_24_BIT),
-    AUDIO_FORMAT_PCM_FLOAT           = (AUDIO_FORMAT_PCM |
-                                        AUDIO_FORMAT_PCM_SUB_FLOAT),
-    AUDIO_FORMAT_PCM_24_BIT_PACKED   = (AUDIO_FORMAT_PCM |
-                                        AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED),
-    AUDIO_FORMAT_AAC_MAIN            = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_MAIN),
-    AUDIO_FORMAT_AAC_LC              = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_LC),
-    AUDIO_FORMAT_AAC_SSR             = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_SSR),
-    AUDIO_FORMAT_AAC_LTP             = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_LTP),
-    AUDIO_FORMAT_AAC_HE_V1           = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_HE_V1),
-    AUDIO_FORMAT_AAC_SCALABLE        = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_SCALABLE),
-    AUDIO_FORMAT_AAC_ERLC            = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_ERLC),
-    AUDIO_FORMAT_AAC_LD              = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_LD),
-    AUDIO_FORMAT_AAC_HE_V2           = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_HE_V2),
-    AUDIO_FORMAT_AAC_ELD             = (AUDIO_FORMAT_AAC |
-                                        AUDIO_FORMAT_AAC_SUB_ELD),
-} audio_format_t;
-
-/* For the channel mask for position assignment representation */
-enum {
-
-/* These can be a complete audio_channel_mask_t. */
-
-    AUDIO_CHANNEL_NONE                      = 0x0,
-    AUDIO_CHANNEL_INVALID                   = 0xC0000000,
-
-/* These can be the bits portion of an audio_channel_mask_t
- * with representation AUDIO_CHANNEL_REPRESENTATION_POSITION.
- * Using these bits as a complete audio_channel_mask_t is deprecated.
- */
-
-    /* output channels */
-    AUDIO_CHANNEL_OUT_FRONT_LEFT            = 0x1,
-    AUDIO_CHANNEL_OUT_FRONT_RIGHT           = 0x2,
-    AUDIO_CHANNEL_OUT_FRONT_CENTER          = 0x4,
-    AUDIO_CHANNEL_OUT_LOW_FREQUENCY         = 0x8,
-    AUDIO_CHANNEL_OUT_BACK_LEFT             = 0x10,
-    AUDIO_CHANNEL_OUT_BACK_RIGHT            = 0x20,
-    AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER  = 0x40,
-    AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80,
-    AUDIO_CHANNEL_OUT_BACK_CENTER           = 0x100,
-    AUDIO_CHANNEL_OUT_SIDE_LEFT             = 0x200,
-    AUDIO_CHANNEL_OUT_SIDE_RIGHT            = 0x400,
-    AUDIO_CHANNEL_OUT_TOP_CENTER            = 0x800,
-    AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT        = 0x1000,
-    AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER      = 0x2000,
-    AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT       = 0x4000,
-    AUDIO_CHANNEL_OUT_TOP_BACK_LEFT         = 0x8000,
-    AUDIO_CHANNEL_OUT_TOP_BACK_CENTER       = 0x10000,
-    AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT        = 0x20000,
-
-/* TODO: should these be considered complete channel masks, or only bits? */
-
-    AUDIO_CHANNEL_OUT_MONO     = AUDIO_CHANNEL_OUT_FRONT_LEFT,
-    AUDIO_CHANNEL_OUT_STEREO   = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT),
-    AUDIO_CHANNEL_OUT_QUAD     = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_BACK_LEFT |
-                                  AUDIO_CHANNEL_OUT_BACK_RIGHT),
-    AUDIO_CHANNEL_OUT_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD,
-    /* like AUDIO_CHANNEL_OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
-    AUDIO_CHANNEL_OUT_QUAD_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_SIDE_LEFT |
-                                  AUDIO_CHANNEL_OUT_SIDE_RIGHT),
-    AUDIO_CHANNEL_OUT_5POINT1  = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
-                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
-                                  AUDIO_CHANNEL_OUT_BACK_LEFT |
-                                  AUDIO_CHANNEL_OUT_BACK_RIGHT),
-    AUDIO_CHANNEL_OUT_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1,
-    /* like AUDIO_CHANNEL_OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */
-    AUDIO_CHANNEL_OUT_5POINT1_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
-                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
-                                  AUDIO_CHANNEL_OUT_SIDE_LEFT |
-                                  AUDIO_CHANNEL_OUT_SIDE_RIGHT),
-    // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1
-    AUDIO_CHANNEL_OUT_7POINT1  = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
-                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
-                                  AUDIO_CHANNEL_OUT_BACK_LEFT |
-                                  AUDIO_CHANNEL_OUT_BACK_RIGHT |
-                                  AUDIO_CHANNEL_OUT_SIDE_LEFT |
-                                  AUDIO_CHANNEL_OUT_SIDE_RIGHT),
-    AUDIO_CHANNEL_OUT_ALL      = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
-                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
-                                  AUDIO_CHANNEL_OUT_BACK_LEFT |
-                                  AUDIO_CHANNEL_OUT_BACK_RIGHT |
-                                  AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER |
-                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER |
-                                  AUDIO_CHANNEL_OUT_BACK_CENTER|
-                                  AUDIO_CHANNEL_OUT_SIDE_LEFT|
-                                  AUDIO_CHANNEL_OUT_SIDE_RIGHT|
-                                  AUDIO_CHANNEL_OUT_TOP_CENTER|
-                                  AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT|
-                                  AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER|
-                                  AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT|
-                                  AUDIO_CHANNEL_OUT_TOP_BACK_LEFT|
-                                  AUDIO_CHANNEL_OUT_TOP_BACK_CENTER|
-                                  AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
-
-/* These are bits only, not complete values */
-
-    /* input channels */
-    AUDIO_CHANNEL_IN_LEFT            = 0x4,
-    AUDIO_CHANNEL_IN_RIGHT           = 0x8,
-    AUDIO_CHANNEL_IN_FRONT           = 0x10,
-    AUDIO_CHANNEL_IN_BACK            = 0x20,
-    AUDIO_CHANNEL_IN_LEFT_PROCESSED  = 0x40,
-    AUDIO_CHANNEL_IN_RIGHT_PROCESSED = 0x80,
-    AUDIO_CHANNEL_IN_FRONT_PROCESSED = 0x100,
-    AUDIO_CHANNEL_IN_BACK_PROCESSED  = 0x200,
-    AUDIO_CHANNEL_IN_PRESSURE        = 0x400,
-    AUDIO_CHANNEL_IN_X_AXIS          = 0x800,
-    AUDIO_CHANNEL_IN_Y_AXIS          = 0x1000,
-    AUDIO_CHANNEL_IN_Z_AXIS          = 0x2000,
-    AUDIO_CHANNEL_IN_VOICE_UPLINK    = 0x4000,
-    AUDIO_CHANNEL_IN_VOICE_DNLINK    = 0x8000,
-
-/* TODO: should these be considered complete channel masks, or only bits, or deprecated? */
-
-    AUDIO_CHANNEL_IN_MONO   = AUDIO_CHANNEL_IN_FRONT,
-    AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT),
-    AUDIO_CHANNEL_IN_FRONT_BACK = (AUDIO_CHANNEL_IN_FRONT | AUDIO_CHANNEL_IN_BACK),
-    AUDIO_CHANNEL_IN_ALL    = (AUDIO_CHANNEL_IN_LEFT |
-                               AUDIO_CHANNEL_IN_RIGHT |
-                               AUDIO_CHANNEL_IN_FRONT |
-                               AUDIO_CHANNEL_IN_BACK|
-                               AUDIO_CHANNEL_IN_LEFT_PROCESSED |
-                               AUDIO_CHANNEL_IN_RIGHT_PROCESSED |
-                               AUDIO_CHANNEL_IN_FRONT_PROCESSED |
-                               AUDIO_CHANNEL_IN_BACK_PROCESSED|
-                               AUDIO_CHANNEL_IN_PRESSURE |
-                               AUDIO_CHANNEL_IN_X_AXIS |
-                               AUDIO_CHANNEL_IN_Y_AXIS |
-                               AUDIO_CHANNEL_IN_Z_AXIS |
-                               AUDIO_CHANNEL_IN_VOICE_UPLINK |
-                               AUDIO_CHANNEL_IN_VOICE_DNLINK),
-};
-
-/* A channel mask per se only defines the presence or absence of a channel, not the order.
- * But see AUDIO_INTERLEAVE_* below for the platform convention of order.
- *
- * audio_channel_mask_t is an opaque type and its internal layout should not
- * be assumed as it may change in the future.
- * Instead, always use the functions declared in this header to examine.
- *
- * These are the current representations:
- *
- *   AUDIO_CHANNEL_REPRESENTATION_POSITION
- *     is a channel mask representation for position assignment.
- *     Each low-order bit corresponds to the spatial position of a transducer (output),
- *     or interpretation of channel (input).
- *     The user of a channel mask needs to know the context of whether it is for output or input.
- *     The constants AUDIO_CHANNEL_OUT_* or AUDIO_CHANNEL_IN_* apply to the bits portion.
- *     It is not permitted for no bits to be set.
- *
- *   AUDIO_CHANNEL_REPRESENTATION_INDEX
- *     is a channel mask representation for index assignment.
- *     Each low-order bit corresponds to a selected channel.
- *     There is no platform interpretation of the various bits.
- *     There is no concept of output or input.
- *     It is not permitted for no bits to be set.
- *
- * All other representations are reserved for future use.
- *
- * Warning: current representation distinguishes between input and output, but this will not the be
- * case in future revisions of the platform. Wherever there is an ambiguity between input and output
- * that is currently resolved by checking the channel mask, the implementer should look for ways to
- * fix it with additional information outside of the mask.
- */
-typedef uint32_t audio_channel_mask_t;
-
-/* Maximum number of channels for all representations */
-#define AUDIO_CHANNEL_COUNT_MAX             30
-
-/* log(2) of maximum number of representations, not part of public API */
-#define AUDIO_CHANNEL_REPRESENTATION_LOG2   2
-
-/* Representations */
-typedef enum {
-    AUDIO_CHANNEL_REPRESENTATION_POSITION    = 0,    // must be zero for compatibility
-    // 1 is reserved for future use
-    AUDIO_CHANNEL_REPRESENTATION_INDEX       = 2,
-    // 3 is reserved for future use
-} audio_channel_representation_t;
-
-/* The return value is undefined if the channel mask is invalid. */
-static inline uint32_t audio_channel_mask_get_bits(audio_channel_mask_t channel)
-{
-    return channel & ((1 << AUDIO_CHANNEL_COUNT_MAX) - 1);
-}
-
-/* The return value is undefined if the channel mask is invalid. */
-static inline audio_channel_representation_t audio_channel_mask_get_representation(
-        audio_channel_mask_t channel)
-{
-    // The right shift should be sufficient, but also "and" for safety in case mask is not 32 bits
-    return (audio_channel_representation_t)
-            ((channel >> AUDIO_CHANNEL_COUNT_MAX) & ((1 << AUDIO_CHANNEL_REPRESENTATION_LOG2) - 1));
-}
-
-/* Returns true if the channel mask is valid,
- * or returns false for AUDIO_CHANNEL_NONE, AUDIO_CHANNEL_INVALID, and other invalid values.
- * This function is unable to determine whether a channel mask for position assignment
- * is invalid because an output mask has an invalid output bit set,
- * or because an input mask has an invalid input bit set.
- * All other APIs that take a channel mask assume that it is valid.
- */
-static inline bool audio_channel_mask_is_valid(audio_channel_mask_t channel)
-{
-    uint32_t bits = audio_channel_mask_get_bits(channel);
-    audio_channel_representation_t representation = audio_channel_mask_get_representation(channel);
-    switch (representation) {
-    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
-    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
-        break;
-    default:
-        bits = 0;
-        break;
-    }
-    return bits != 0;
-}
-
-/* Not part of public API */
-static inline audio_channel_mask_t audio_channel_mask_from_representation_and_bits(
-        audio_channel_representation_t representation, uint32_t bits)
-{
-    return (audio_channel_mask_t) ((representation << AUDIO_CHANNEL_COUNT_MAX) | bits);
-}
-
-/* Expresses the convention when stereo audio samples are stored interleaved
- * in an array.  This should improve readability by allowing code to use
- * symbolic indices instead of hard-coded [0] and [1].
- *
- * For multi-channel beyond stereo, the platform convention is that channels
- * are interleaved in order from least significant channel mask bit
- * to most significant channel mask bit, with unused bits skipped.
- * Any exceptions to this convention will be noted at the appropriate API.
- */
-enum {
-    AUDIO_INTERLEAVE_LEFT   = 0,
-    AUDIO_INTERLEAVE_RIGHT  = 1,
-};
-
-typedef enum {
-    AUDIO_MODE_INVALID          = -2,
-    AUDIO_MODE_CURRENT          = -1,
-    AUDIO_MODE_NORMAL           = 0,
-    AUDIO_MODE_RINGTONE         = 1,
-    AUDIO_MODE_IN_CALL          = 2,
-    AUDIO_MODE_IN_COMMUNICATION = 3,
-
-    AUDIO_MODE_CNT,
-    AUDIO_MODE_MAX              = AUDIO_MODE_CNT - 1,
-} audio_mode_t;
-
-/* This enum is deprecated */
-typedef enum {
-    AUDIO_IN_ACOUSTICS_NONE          = 0,
-    AUDIO_IN_ACOUSTICS_AGC_ENABLE    = 0x0001,
-    AUDIO_IN_ACOUSTICS_AGC_DISABLE   = 0,
-    AUDIO_IN_ACOUSTICS_NS_ENABLE     = 0x0002,
-    AUDIO_IN_ACOUSTICS_NS_DISABLE    = 0,
-    AUDIO_IN_ACOUSTICS_TX_IIR_ENABLE = 0x0004,
-    AUDIO_IN_ACOUSTICS_TX_DISABLE    = 0,
-} audio_in_acoustics_t;
-
-enum {
-    AUDIO_DEVICE_NONE                          = 0x0,
-    /* reserved bits */
-    AUDIO_DEVICE_BIT_IN                        = 0x80000000,
-    AUDIO_DEVICE_BIT_DEFAULT                   = 0x40000000,
-    /* output devices */
-    AUDIO_DEVICE_OUT_EARPIECE                  = 0x1,
-    AUDIO_DEVICE_OUT_SPEAKER                   = 0x2,
-    AUDIO_DEVICE_OUT_WIRED_HEADSET             = 0x4,
-    AUDIO_DEVICE_OUT_WIRED_HEADPHONE           = 0x8,
-    AUDIO_DEVICE_OUT_BLUETOOTH_SCO             = 0x10,
-    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET     = 0x20,
-    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT      = 0x40,
-    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP            = 0x80,
-    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
-    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER    = 0x200,
-    AUDIO_DEVICE_OUT_AUX_DIGITAL               = 0x400,
-    AUDIO_DEVICE_OUT_HDMI                      = AUDIO_DEVICE_OUT_AUX_DIGITAL,
-    /* uses an analog connection (multiplexed over the USB connector pins for instance) */
-    AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET         = 0x800,
-    AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET         = 0x1000,
-    /* USB accessory mode: your Android device is a USB device and the dock is a USB host */
-    AUDIO_DEVICE_OUT_USB_ACCESSORY             = 0x2000,
-    /* USB host mode: your Android device is a USB host and the dock is a USB device */
-    AUDIO_DEVICE_OUT_USB_DEVICE                = 0x4000,
-    AUDIO_DEVICE_OUT_REMOTE_SUBMIX             = 0x8000,
-    /* Telephony voice TX path */
-    AUDIO_DEVICE_OUT_TELEPHONY_TX              = 0x10000,
-    /* Analog jack with line impedance detected */
-    AUDIO_DEVICE_OUT_LINE                      = 0x20000,
-    /* HDMI Audio Return Channel */
-    AUDIO_DEVICE_OUT_HDMI_ARC                  = 0x40000,
-    /* S/PDIF out */
-    AUDIO_DEVICE_OUT_SPDIF                     = 0x80000,
-    /* FM transmitter out */
-    AUDIO_DEVICE_OUT_FM                        = 0x100000,
-    /* Line out for av devices */
-    AUDIO_DEVICE_OUT_AUX_LINE                  = 0x200000,
-    /* limited-output speaker device for acoustic safety */
-    AUDIO_DEVICE_OUT_SPEAKER_SAFE              = 0x400000,
-    AUDIO_DEVICE_OUT_DEFAULT                   = AUDIO_DEVICE_BIT_DEFAULT,
-    AUDIO_DEVICE_OUT_ALL      = (AUDIO_DEVICE_OUT_EARPIECE |
-                                 AUDIO_DEVICE_OUT_SPEAKER |
-                                 AUDIO_DEVICE_OUT_WIRED_HEADSET |
-                                 AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
-                                 AUDIO_DEVICE_OUT_HDMI |
-                                 AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
-                                 AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
-                                 AUDIO_DEVICE_OUT_USB_ACCESSORY |
-                                 AUDIO_DEVICE_OUT_USB_DEVICE |
-                                 AUDIO_DEVICE_OUT_REMOTE_SUBMIX |
-                                 AUDIO_DEVICE_OUT_TELEPHONY_TX |
-                                 AUDIO_DEVICE_OUT_LINE |
-                                 AUDIO_DEVICE_OUT_HDMI_ARC |
-                                 AUDIO_DEVICE_OUT_SPDIF |
-                                 AUDIO_DEVICE_OUT_FM |
-                                 AUDIO_DEVICE_OUT_AUX_LINE |
-                                 AUDIO_DEVICE_OUT_SPEAKER_SAFE |
-                                 AUDIO_DEVICE_OUT_DEFAULT),
-    AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
-    AUDIO_DEVICE_OUT_ALL_SCO  = (AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
-                                 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
-    AUDIO_DEVICE_OUT_ALL_USB  = (AUDIO_DEVICE_OUT_USB_ACCESSORY |
-                                 AUDIO_DEVICE_OUT_USB_DEVICE),
-
-    /* input devices */
-    AUDIO_DEVICE_IN_COMMUNICATION         = AUDIO_DEVICE_BIT_IN | 0x1,
-    AUDIO_DEVICE_IN_AMBIENT               = AUDIO_DEVICE_BIT_IN | 0x2,
-    AUDIO_DEVICE_IN_BUILTIN_MIC           = AUDIO_DEVICE_BIT_IN | 0x4,
-    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8,
-    AUDIO_DEVICE_IN_WIRED_HEADSET         = AUDIO_DEVICE_BIT_IN | 0x10,
-    AUDIO_DEVICE_IN_AUX_DIGITAL           = AUDIO_DEVICE_BIT_IN | 0x20,
-    AUDIO_DEVICE_IN_HDMI                  = AUDIO_DEVICE_IN_AUX_DIGITAL,
-    /* Telephony voice RX path */
-    AUDIO_DEVICE_IN_VOICE_CALL            = AUDIO_DEVICE_BIT_IN | 0x40,
-    AUDIO_DEVICE_IN_TELEPHONY_RX          = AUDIO_DEVICE_IN_VOICE_CALL,
-    AUDIO_DEVICE_IN_BACK_MIC              = AUDIO_DEVICE_BIT_IN | 0x80,
-    AUDIO_DEVICE_IN_REMOTE_SUBMIX         = AUDIO_DEVICE_BIT_IN | 0x100,
-    AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET     = AUDIO_DEVICE_BIT_IN | 0x200,
-    AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET     = AUDIO_DEVICE_BIT_IN | 0x400,
-    AUDIO_DEVICE_IN_USB_ACCESSORY         = AUDIO_DEVICE_BIT_IN | 0x800,
-    AUDIO_DEVICE_IN_USB_DEVICE            = AUDIO_DEVICE_BIT_IN | 0x1000,
-    /* FM tuner input */
-    AUDIO_DEVICE_IN_FM_TUNER              = AUDIO_DEVICE_BIT_IN | 0x2000,
-    /* TV tuner input */
-    AUDIO_DEVICE_IN_TV_TUNER              = AUDIO_DEVICE_BIT_IN | 0x4000,
-    /* Analog jack with line impedance detected */
-    AUDIO_DEVICE_IN_LINE                  = AUDIO_DEVICE_BIT_IN | 0x8000,
-    /* S/PDIF in */
-    AUDIO_DEVICE_IN_SPDIF                 = AUDIO_DEVICE_BIT_IN | 0x10000,
-    AUDIO_DEVICE_IN_BLUETOOTH_A2DP        = AUDIO_DEVICE_BIT_IN | 0x20000,
-    AUDIO_DEVICE_IN_LOOPBACK              = AUDIO_DEVICE_BIT_IN | 0x40000,
-    AUDIO_DEVICE_IN_DEFAULT               = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT,
-
-    AUDIO_DEVICE_IN_ALL     = (AUDIO_DEVICE_IN_COMMUNICATION |
-                               AUDIO_DEVICE_IN_AMBIENT |
-                               AUDIO_DEVICE_IN_BUILTIN_MIC |
-                               AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET |
-                               AUDIO_DEVICE_IN_WIRED_HEADSET |
-                               AUDIO_DEVICE_IN_HDMI |
-                               AUDIO_DEVICE_IN_TELEPHONY_RX |
-                               AUDIO_DEVICE_IN_BACK_MIC |
-                               AUDIO_DEVICE_IN_REMOTE_SUBMIX |
-                               AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET |
-                               AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET |
-                               AUDIO_DEVICE_IN_USB_ACCESSORY |
-                               AUDIO_DEVICE_IN_USB_DEVICE |
-                               AUDIO_DEVICE_IN_FM_TUNER |
-                               AUDIO_DEVICE_IN_TV_TUNER |
-                               AUDIO_DEVICE_IN_LINE |
-                               AUDIO_DEVICE_IN_SPDIF |
-                               AUDIO_DEVICE_IN_BLUETOOTH_A2DP |
-                               AUDIO_DEVICE_IN_LOOPBACK |
-                               AUDIO_DEVICE_IN_DEFAULT),
-    AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
-    AUDIO_DEVICE_IN_ALL_USB  = (AUDIO_DEVICE_IN_USB_ACCESSORY |
-                                AUDIO_DEVICE_IN_USB_DEVICE),
-};
-
-typedef uint32_t audio_devices_t;
-
-/* the audio output flags serve two purposes:
- * - when an AudioTrack is created they indicate a "wish" to be connected to an
- * output stream with attributes corresponding to the specified flags
- * - when present in an output profile descriptor listed for a particular audio
- * hardware module, they indicate that an output stream can be opened that
- * supports the attributes indicated by the flags.
- * the audio policy manager will try to match the flags in the request
- * (when getOuput() is called) to an available output stream.
- */
-typedef enum {
-    AUDIO_OUTPUT_FLAG_NONE = 0x0,       // no attributes
-    AUDIO_OUTPUT_FLAG_DIRECT = 0x1,     // this output directly connects a track
-                                        // to one output stream: no software mixer
-    AUDIO_OUTPUT_FLAG_PRIMARY = 0x2,    // this output is the primary output of
-                                        // the device. It is unique and must be
-                                        // present. It is opened by default and
-                                        // receives routing, audio mode and volume
-                                        // controls related to voice calls.
-    AUDIO_OUTPUT_FLAG_FAST = 0x4,       // output supports "fast tracks",
-                                        // defined elsewhere
-    AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8, // use deep audio buffers
-    AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 0x10,  // offload playback of compressed
-                                                // streams to hardware codec
-    AUDIO_OUTPUT_FLAG_NON_BLOCKING = 0x20, // use non-blocking write
-    AUDIO_OUTPUT_FLAG_HW_AV_SYNC = 0x40 // output uses a hardware A/V synchronization source
-} audio_output_flags_t;
-
-/* The audio input flags are analogous to audio output flags.
- * Currently they are used only when an AudioRecord is created,
- * to indicate a preference to be connected to an input stream with
- * attributes corresponding to the specified flags.
- */
-typedef enum {
-    AUDIO_INPUT_FLAG_NONE       = 0x0,  // no attributes
-    AUDIO_INPUT_FLAG_FAST       = 0x1,  // prefer an input that supports "fast tracks"
-    AUDIO_INPUT_FLAG_HW_HOTWORD = 0x2,  // prefer an input that captures from hw hotword source
-} audio_input_flags_t;
-
-/* Additional information about compressed streams offloaded to
- * hardware playback
- * The version and size fields must be initialized by the caller by using
- * one of the constants defined here.
- */
-typedef struct {
-    uint16_t version;                   // version of the info structure
-    uint16_t size;                      // total size of the structure including version and size
-    uint32_t sample_rate;               // sample rate in Hz
-    audio_channel_mask_t channel_mask;  // channel mask
-    audio_format_t format;              // audio format
-    audio_stream_type_t stream_type;    // stream type
-    uint32_t bit_rate;                  // bit rate in bits per second
-    int64_t duration_us;                // duration in microseconds, -1 if unknown
-    bool has_video;                     // true if stream is tied to a video stream
-    bool is_streaming;                  // true if streaming, false if local playback
-} audio_offload_info_t;
-
-#define AUDIO_MAKE_OFFLOAD_INFO_VERSION(maj,min) \
-            ((((maj) & 0xff) << 8) | ((min) & 0xff))
-
-#define AUDIO_OFFLOAD_INFO_VERSION_0_1 AUDIO_MAKE_OFFLOAD_INFO_VERSION(0, 1)
-#define AUDIO_OFFLOAD_INFO_VERSION_CURRENT AUDIO_OFFLOAD_INFO_VERSION_0_1
-
-static const audio_offload_info_t AUDIO_INFO_INITIALIZER = {
-    version: AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
-    size: sizeof(audio_offload_info_t),
-    sample_rate: 0,
-    channel_mask: 0,
-    format: AUDIO_FORMAT_DEFAULT,
-    stream_type: AUDIO_STREAM_VOICE_CALL,
-    bit_rate: 0,
-    duration_us: 0,
-    has_video: false,
-    is_streaming: false
-};
-
-/* common audio stream configuration parameters
- * You should memset() the entire structure to zero before use to
- * ensure forward compatibility
- */
-struct audio_config {
-    uint32_t sample_rate;
-    audio_channel_mask_t channel_mask;
-    audio_format_t  format;
-    audio_offload_info_t offload_info;
-    size_t frame_count;
-};
-typedef struct audio_config audio_config_t;
-
-static const audio_config_t AUDIO_CONFIG_INITIALIZER = {
-    sample_rate: 0,
-    channel_mask: AUDIO_CHANNEL_NONE,
-    format: AUDIO_FORMAT_DEFAULT,
-    offload_info: {
-        version: AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
-        size: sizeof(audio_offload_info_t),
-        sample_rate: 0,
-        channel_mask: 0,
-        format: AUDIO_FORMAT_DEFAULT,
-        stream_type: AUDIO_STREAM_VOICE_CALL,
-        bit_rate: 0,
-        duration_us: 0,
-        has_video: false,
-        is_streaming: false
-    },
-    frame_count: 0,
-};
-
-
-/* audio hw module handle functions or structures referencing a module */
-typedef int audio_module_handle_t;
-
-/******************************
- *  Volume control
- *****************************/
-
-/* If the audio hardware supports gain control on some audio paths,
- * the platform can expose them in the audio_policy.conf file. The audio HAL
- * will then implement gain control functions that will use the following data
- * structures. */
-
-/* Type of gain control exposed by an audio port */
-#define AUDIO_GAIN_MODE_JOINT     0x1 /* supports joint channel gain control */
-#define AUDIO_GAIN_MODE_CHANNELS  0x2 /* supports separate channel gain control */
-#define AUDIO_GAIN_MODE_RAMP      0x4 /* supports gain ramps */
-
-typedef uint32_t audio_gain_mode_t;
-
-
-/* An audio_gain struct is a representation of a gain stage.
- * A gain stage is always attached to an audio port. */
-struct audio_gain  {
-    audio_gain_mode_t    mode;          /* e.g. AUDIO_GAIN_MODE_JOINT */
-    audio_channel_mask_t channel_mask;  /* channels which gain an be controlled.
-                                           N/A if AUDIO_GAIN_MODE_CHANNELS is not supported */
-    int                  min_value;     /* minimum gain value in millibels */
-    int                  max_value;     /* maximum gain value in millibels */
-    int                  default_value; /* default gain value in millibels */
-    unsigned int         step_value;    /* gain step in millibels */
-    unsigned int         min_ramp_ms;   /* minimum ramp duration in ms */
-    unsigned int         max_ramp_ms;   /* maximum ramp duration in ms */
-};
-
-/* The gain configuration structure is used to get or set the gain values of a
- * given port */
-struct audio_gain_config  {
-    int                  index;             /* index of the corresponding audio_gain in the
-                                               audio_port gains[] table */
-    audio_gain_mode_t    mode;              /* mode requested for this command */
-    audio_channel_mask_t channel_mask;      /* channels which gain value follows.
-                                               N/A in joint mode */
-    int                  values[sizeof(audio_channel_mask_t) * 8]; /* gain values in millibels
-                                               for each channel ordered from LSb to MSb in
-                                               channel mask. The number of values is 1 in joint
-                                               mode or popcount(channel_mask) */
-    unsigned int         ramp_duration_ms; /* ramp duration in ms */
-};
-
-/******************************
- *  Routing control
- *****************************/
-
-/* Types defined here are used to describe an audio source or sink at internal
- * framework interfaces (audio policy, patch panel) or at the audio HAL.
- * Sink and sources are grouped in a concept of “audio port” representing an
- * audio end point at the edge of the system managed by the module exposing
- * the interface. */
-
-/* Audio port role: either source or sink */
-typedef enum {
-    AUDIO_PORT_ROLE_NONE,
-    AUDIO_PORT_ROLE_SOURCE,
-    AUDIO_PORT_ROLE_SINK,
-} audio_port_role_t;
-
-/* Audio port type indicates if it is a session (e.g AudioTrack),
- * a mix (e.g PlaybackThread output) or a physical device
- * (e.g AUDIO_DEVICE_OUT_SPEAKER) */
-typedef enum {
-    AUDIO_PORT_TYPE_NONE,
-    AUDIO_PORT_TYPE_DEVICE,
-    AUDIO_PORT_TYPE_MIX,
-    AUDIO_PORT_TYPE_SESSION,
-} audio_port_type_t;
-
-/* Each port has a unique ID or handle allocated by policy manager */
-typedef int audio_port_handle_t;
-#define AUDIO_PORT_HANDLE_NONE 0
-
-
-/* maximum audio device address length */
-#define AUDIO_DEVICE_MAX_ADDRESS_LEN 32
-
-/* extension for audio port configuration structure when the audio port is a
- * hardware device */
-struct audio_port_config_device_ext {
-    audio_module_handle_t hw_module;                /* module the device is attached to */
-    audio_devices_t       type;                     /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
-    char                  address[AUDIO_DEVICE_MAX_ADDRESS_LEN]; /* device address. "" if N/A */
-};
-
-/* extension for audio port configuration structure when the audio port is a
- * sub mix */
-struct audio_port_config_mix_ext {
-    audio_module_handle_t hw_module;    /* module the stream is attached to */
-    audio_io_handle_t handle;           /* I/O handle of the input/output stream */
-    union {
-        //TODO: change use case for output streams: use strategy and mixer attributes
-        audio_stream_type_t stream;
-        audio_source_t      source;
-    } usecase;
-};
-
-/* extension for audio port configuration structure when the audio port is an
- * audio session */
-struct audio_port_config_session_ext {
-    audio_session_t   session; /* audio session */
-};
-
-/* Flags indicating which fields are to be considered in struct audio_port_config */
-#define AUDIO_PORT_CONFIG_SAMPLE_RATE  0x1
-#define AUDIO_PORT_CONFIG_CHANNEL_MASK 0x2
-#define AUDIO_PORT_CONFIG_FORMAT       0x4
-#define AUDIO_PORT_CONFIG_GAIN         0x8
-#define AUDIO_PORT_CONFIG_ALL (AUDIO_PORT_CONFIG_SAMPLE_RATE | \
-                               AUDIO_PORT_CONFIG_CHANNEL_MASK | \
-                               AUDIO_PORT_CONFIG_FORMAT | \
-                               AUDIO_PORT_CONFIG_GAIN)
-
-/* audio port configuration structure used to specify a particular configuration of
- * an audio port */
-struct audio_port_config {
-    audio_port_handle_t      id;           /* port unique ID */
-    audio_port_role_t        role;         /* sink or source */
-    audio_port_type_t        type;         /* device, mix ... */
-    unsigned int             config_mask;  /* e.g AUDIO_PORT_CONFIG_ALL */
-    unsigned int             sample_rate;  /* sampling rate in Hz */
-    audio_channel_mask_t     channel_mask; /* channel mask if applicable */
-    audio_format_t           format;       /* format if applicable */
-    struct audio_gain_config gain;         /* gain to apply if applicable */
-    union {
-        struct audio_port_config_device_ext  device;  /* device specific info */
-        struct audio_port_config_mix_ext     mix;     /* mix specific info */
-        struct audio_port_config_session_ext session; /* session specific info */
-    } ext;
-};
-
-
-/* max number of sampling rates in audio port */
-#define AUDIO_PORT_MAX_SAMPLING_RATES 16
-/* max number of channel masks in audio port */
-#define AUDIO_PORT_MAX_CHANNEL_MASKS 16
-/* max number of audio formats in audio port */
-#define AUDIO_PORT_MAX_FORMATS 16
-/* max number of gain controls in audio port */
-#define AUDIO_PORT_MAX_GAINS 16
-
-/* extension for audio port structure when the audio port is a hardware device */
-struct audio_port_device_ext {
-    audio_module_handle_t hw_module;    /* module the device is attached to */
-    audio_devices_t       type;         /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
-    char                  address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
-};
-
-/* Latency class of the audio mix */
-typedef enum {
-    AUDIO_LATENCY_LOW,
-    AUDIO_LATENCY_NORMAL,
-} audio_mix_latency_class_t;
-
-/* extension for audio port structure when the audio port is a sub mix */
-struct audio_port_mix_ext {
-    audio_module_handle_t     hw_module;     /* module the stream is attached to */
-    audio_io_handle_t         handle;        /* I/O handle of the input.output stream */
-    audio_mix_latency_class_t latency_class; /* latency class */
-    // other attributes: routing strategies
-};
-
-/* extension for audio port structure when the audio port is an audio session */
-struct audio_port_session_ext {
-    audio_session_t   session; /* audio session */
-};
-
-
-struct audio_port {
-    audio_port_handle_t      id;                /* port unique ID */
-    audio_port_role_t        role;              /* sink or source */
-    audio_port_type_t        type;              /* device, mix ... */
-    unsigned int             num_sample_rates;  /* number of sampling rates in following array */
-    unsigned int             sample_rates[AUDIO_PORT_MAX_SAMPLING_RATES];
-    unsigned int             num_channel_masks; /* number of channel masks in following array */
-    audio_channel_mask_t     channel_masks[AUDIO_PORT_MAX_CHANNEL_MASKS];
-    unsigned int             num_formats;       /* number of formats in following array */
-    audio_format_t           formats[AUDIO_PORT_MAX_FORMATS];
-    unsigned int             num_gains;         /* number of gains in following array */
-    struct audio_gain        gains[AUDIO_PORT_MAX_GAINS];
-    struct audio_port_config active_config;     /* current audio port configuration */
-    union {
-        struct audio_port_device_ext  device;
-        struct audio_port_mix_ext     mix;
-        struct audio_port_session_ext session;
-    } ext;
-};
-
-/* An audio patch represents a connection between one or more source ports and
- * one or more sink ports. Patches are connected and disconnected by audio policy manager or by
- * applications via framework APIs.
- * Each patch is identified by a handle at the interface used to create that patch. For instance,
- * when a patch is created by the audio HAL, the HAL allocates and returns a handle.
- * This handle is unique to a given audio HAL hardware module.
- * But the same patch receives another system wide unique handle allocated by the framework.
- * This unique handle is used for all transactions inside the framework.
- */
-typedef int audio_patch_handle_t;
-#define AUDIO_PATCH_HANDLE_NONE 0
-
-#define AUDIO_PATCH_PORTS_MAX   16
-
-struct audio_patch {
-    audio_patch_handle_t id;            /* patch unique ID */
-    unsigned int      num_sources;      /* number of sources in following array */
-    struct audio_port_config sources[AUDIO_PATCH_PORTS_MAX];
-    unsigned int      num_sinks;        /* number of sinks in following array */
-    struct audio_port_config sinks[AUDIO_PATCH_PORTS_MAX];
-};
-
-
-
-/* a HW synchronization source returned by the audio HAL */
-typedef uint32_t audio_hw_sync_t;
-
-/* an invalid HW synchronization source indicating an error */
-#define AUDIO_HW_SYNC_INVALID 0
-
-static inline bool audio_is_output_device(audio_devices_t device)
-{
-    if (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
-            (popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL) == 0))
-        return true;
-    else
-        return false;
-}
-
-static inline bool audio_is_input_device(audio_devices_t device)
-{
-    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
-        device &= ~AUDIO_DEVICE_BIT_IN;
-        if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_ALL) == 0))
-            return true;
-    }
-    return false;
-}
-
-static inline bool audio_is_output_devices(audio_devices_t device)
-{
-    return (device & AUDIO_DEVICE_BIT_IN) == 0;
-}
-
-static inline bool audio_is_a2dp_in_device(audio_devices_t device)
-{
-    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
-        device &= ~AUDIO_DEVICE_BIT_IN;
-        if ((popcount(device) == 1) && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP))
-            return true;
-    }
-    return false;
-}
-
-static inline bool audio_is_a2dp_out_device(audio_devices_t device)
-{
-    if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_A2DP))
-        return true;
-    else
-        return false;
-}
-
-// Deprecated - use audio_is_a2dp_out_device() instead
-static inline bool audio_is_a2dp_device(audio_devices_t device)
-{
-    return audio_is_a2dp_out_device(device);
-}
-
-static inline bool audio_is_bluetooth_sco_device(audio_devices_t device)
-{
-    if ((device & AUDIO_DEVICE_BIT_IN) == 0) {
-        if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL_SCO) == 0))
-            return true;
-    } else {
-        device &= ~AUDIO_DEVICE_BIT_IN;
-        if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) == 0))
-            return true;
-    }
-
-    return false;
-}
-
-static inline bool audio_is_usb_out_device(audio_devices_t device)
-{
-    return ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_USB));
-}
-
-static inline bool audio_is_usb_in_device(audio_devices_t device)
-{
-    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
-        device &= ~AUDIO_DEVICE_BIT_IN;
-        if (popcount(device) == 1 && (device & AUDIO_DEVICE_IN_ALL_USB) != 0)
-            return true;
-    }
-    return false;
-}
-
-/* OBSOLETE - use audio_is_usb_out_device() instead. */
-static inline bool audio_is_usb_device(audio_devices_t device)
-{
-    return audio_is_usb_out_device(device);
-}
-
-static inline bool audio_is_remote_submix_device(audio_devices_t device)
-{
-    if ((audio_is_output_devices(device) &&
-         (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) == AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
-        || (!audio_is_output_devices(device) &&
-         (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX))
-        return true;
-    else
-        return false;
-}
-
-/* Returns true if:
- *  representation is valid, and
- *  there is at least one channel bit set which _could_ correspond to an input channel, and
- *  there are no channel bits set which could _not_ correspond to an input channel.
- * Otherwise returns false.
- */
-static inline bool audio_is_input_channel(audio_channel_mask_t channel)
-{
-    uint32_t bits = audio_channel_mask_get_bits(channel);
-    switch (audio_channel_mask_get_representation(channel)) {
-    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
-        if (bits & ~AUDIO_CHANNEL_IN_ALL) {
-            bits = 0;
-        }
-        // fall through
-    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
-        return bits != 0;
-    default:
-        return false;
-    }
-}
-
-/* Returns true if:
- *  representation is valid, and
- *  there is at least one channel bit set which _could_ correspond to an output channel, and
- *  there are no channel bits set which could _not_ correspond to an output channel.
- * Otherwise returns false.
- */
-static inline bool audio_is_output_channel(audio_channel_mask_t channel)
-{
-    uint32_t bits = audio_channel_mask_get_bits(channel);
-    switch (audio_channel_mask_get_representation(channel)) {
-    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
-        if (bits & ~AUDIO_CHANNEL_OUT_ALL) {
-            bits = 0;
-        }
-        // fall through
-    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
-        return bits != 0;
-    default:
-        return false;
-    }
-}
-
-/* Returns the number of channels from an input channel mask,
- * used in the context of audio input or recording.
- * If a channel bit is set which could _not_ correspond to an input channel,
- * it is excluded from the count.
- * Returns zero if the representation is invalid.
- */
-static inline uint32_t audio_channel_count_from_in_mask(audio_channel_mask_t channel)
-{
-    uint32_t bits = audio_channel_mask_get_bits(channel);
-    switch (audio_channel_mask_get_representation(channel)) {
-    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
-        // TODO: We can now merge with from_out_mask and remove anding
-        bits &= AUDIO_CHANNEL_IN_ALL;
-        // fall through
-    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
-        return popcount(bits);
-    default:
-        return 0;
-    }
-}
-
-/* Returns the number of channels from an output channel mask,
- * used in the context of audio output or playback.
- * If a channel bit is set which could _not_ correspond to an output channel,
- * it is excluded from the count.
- * Returns zero if the representation is invalid.
- */
-static inline uint32_t audio_channel_count_from_out_mask(audio_channel_mask_t channel)
-{
-    uint32_t bits = audio_channel_mask_get_bits(channel);
-    switch (audio_channel_mask_get_representation(channel)) {
-    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
-        // TODO: We can now merge with from_in_mask and remove anding
-        bits &= AUDIO_CHANNEL_OUT_ALL;
-        // fall through
-    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
-        return popcount(bits);
-    default:
-        return 0;
-    }
-}
-
-/* Derive an output channel mask for position assignment from a channel count.
- * This is to be used when the content channel mask is unknown. The 1, 2, 4, 5, 6, 7 and 8 channel
- * cases are mapped to the standard game/home-theater layouts, but note that 4 is mapped to quad,
- * and not stereo + FC + mono surround. A channel count of 3 is arbitrarily mapped to stereo + FC
- * for continuity with stereo.
- * Returns the matching channel mask,
- * or AUDIO_CHANNEL_NONE if the channel count is zero,
- * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
- * configurations for which a default output channel mask is defined.
- */
-static inline audio_channel_mask_t audio_channel_out_mask_from_count(uint32_t channel_count)
-{
-    uint32_t bits;
-    switch (channel_count) {
-    case 0:
-        return AUDIO_CHANNEL_NONE;
-    case 1:
-        bits = AUDIO_CHANNEL_OUT_MONO;
-        break;
-    case 2:
-        bits = AUDIO_CHANNEL_OUT_STEREO;
-        break;
-    case 3:
-        bits = AUDIO_CHANNEL_OUT_STEREO | AUDIO_CHANNEL_OUT_FRONT_CENTER;
-        break;
-    case 4: // 4.0
-        bits = AUDIO_CHANNEL_OUT_QUAD;
-        break;
-    case 5: // 5.0
-        bits = AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER;
-        break;
-    case 6: // 5.1
-        bits = AUDIO_CHANNEL_OUT_5POINT1;
-        break;
-    case 7: // 6.1
-        bits = AUDIO_CHANNEL_OUT_5POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER;
-        break;
-    case 8:
-        bits = AUDIO_CHANNEL_OUT_7POINT1;
-        break;
-    default:
-        return AUDIO_CHANNEL_INVALID;
-    }
-    return audio_channel_mask_from_representation_and_bits(
-            AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
-}
-
-/* Derive an input channel mask for position assignment from a channel count.
- * Currently handles only mono and stereo.
- * Returns the matching channel mask,
- * or AUDIO_CHANNEL_NONE if the channel count is zero,
- * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
- * configurations for which a default input channel mask is defined.
- */
-static inline audio_channel_mask_t audio_channel_in_mask_from_count(uint32_t channel_count)
-{
-    uint32_t bits;
-    switch (channel_count) {
-    case 0:
-        return AUDIO_CHANNEL_NONE;
-    case 1:
-        bits = AUDIO_CHANNEL_IN_MONO;
-        break;
-    case 2:
-        bits = AUDIO_CHANNEL_IN_STEREO;
-        break;
-    default:
-        return AUDIO_CHANNEL_INVALID;
-    }
-    return audio_channel_mask_from_representation_and_bits(
-            AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
-}
-
-/* Derive a channel mask for index assignment from a channel count.
- * Returns the matching channel mask,
- * or AUDIO_CHANNEL_NONE if the channel count is zero,
- * or AUDIO_CHANNEL_INVALID if the channel count exceeds AUDIO_CHANNEL_COUNT_MAX.
- */
-static inline audio_channel_mask_t audio_channel_mask_for_index_assignment_from_count(
-        uint32_t channel_count)
-{
-    if (channel_count == 0) {
-        return AUDIO_CHANNEL_NONE;
-    }
-    if (channel_count > AUDIO_CHANNEL_COUNT_MAX) {
-        return AUDIO_CHANNEL_INVALID;
-    }
-    uint32_t bits = (1 << channel_count) - 1;
-    return audio_channel_mask_from_representation_and_bits(
-            AUDIO_CHANNEL_REPRESENTATION_INDEX, bits);
-}
-
-static inline bool audio_is_valid_format(audio_format_t format)
-{
-    switch (format & AUDIO_FORMAT_MAIN_MASK) {
-    case AUDIO_FORMAT_PCM:
-        switch (format) {
-        case AUDIO_FORMAT_PCM_16_BIT:
-        case AUDIO_FORMAT_PCM_8_BIT:
-        case AUDIO_FORMAT_PCM_32_BIT:
-        case AUDIO_FORMAT_PCM_8_24_BIT:
-        case AUDIO_FORMAT_PCM_FLOAT:
-        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
-            return true;
-        default:
-            return false;
-        }
-        /* not reached */
-    case AUDIO_FORMAT_MP3:
-    case AUDIO_FORMAT_AMR_NB:
-    case AUDIO_FORMAT_AMR_WB:
-    case AUDIO_FORMAT_AAC:
-    case AUDIO_FORMAT_HE_AAC_V1:
-    case AUDIO_FORMAT_HE_AAC_V2:
-    case AUDIO_FORMAT_VORBIS:
-    case AUDIO_FORMAT_OPUS:
-    case AUDIO_FORMAT_AC3:
-    case AUDIO_FORMAT_E_AC3:
-        return true;
-    default:
-        return false;
-    }
-}
-
-static inline bool audio_is_linear_pcm(audio_format_t format)
-{
-    return ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM);
-}
-
-static inline size_t audio_bytes_per_sample(audio_format_t format)
-{
-    size_t size = 0;
-
-    switch (format) {
-    case AUDIO_FORMAT_PCM_32_BIT:
-    case AUDIO_FORMAT_PCM_8_24_BIT:
-        size = sizeof(int32_t);
-        break;
-    case AUDIO_FORMAT_PCM_24_BIT_PACKED:
-        size = sizeof(uint8_t) * 3;
-        break;
-    case AUDIO_FORMAT_PCM_16_BIT:
-        size = sizeof(int16_t);
-        break;
-    case AUDIO_FORMAT_PCM_8_BIT:
-        size = sizeof(uint8_t);
-        break;
-    case AUDIO_FORMAT_PCM_FLOAT:
-        size = sizeof(float);
-        break;
-    default:
-        break;
-    }
-    return size;
-}
-
-/* converts device address to string sent to audio HAL via set_parameters */
-static inline char *audio_device_address_to_parameter(audio_devices_t device, const char *address)
-{
-    const size_t kSize = AUDIO_DEVICE_MAX_ADDRESS_LEN + sizeof("a2dp_sink_address=");
-    char param[kSize];
-
-    if (device & AUDIO_DEVICE_OUT_ALL_A2DP)
-        snprintf(param, kSize, "%s=%s", "a2dp_sink_address", address);
-    else if (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
-        snprintf(param, kSize, "%s=%s", "mix", address);
-    else
-        snprintf(param, kSize, "%s", address);
-
-    return strdup(param);
-}
-
-
-__END_DECLS
-
-#endif  // ANDROID_AUDIO_CORE_H
diff --git a/include/system/audio_policy.h b/include/system/audio_policy.h
deleted file mode 100644
index 2881104..0000000
--- a/include/system/audio_policy.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2011 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 ANDROID_AUDIO_POLICY_CORE_H
-#define ANDROID_AUDIO_POLICY_CORE_H
-
-#include <stdint.h>
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <cutils/bitops.h>
-
-__BEGIN_DECLS
-
-/* The enums were moved here mostly from
- * frameworks/base/include/media/AudioSystem.h
- */
-
-/* device categories used for audio_policy->set_force_use() */
-typedef enum {
-    AUDIO_POLICY_FORCE_NONE,
-    AUDIO_POLICY_FORCE_SPEAKER,
-    AUDIO_POLICY_FORCE_HEADPHONES,
-    AUDIO_POLICY_FORCE_BT_SCO,
-    AUDIO_POLICY_FORCE_BT_A2DP,
-    AUDIO_POLICY_FORCE_WIRED_ACCESSORY,
-    AUDIO_POLICY_FORCE_BT_CAR_DOCK,
-    AUDIO_POLICY_FORCE_BT_DESK_DOCK,
-    AUDIO_POLICY_FORCE_ANALOG_DOCK,
-    AUDIO_POLICY_FORCE_DIGITAL_DOCK,
-    AUDIO_POLICY_FORCE_NO_BT_A2DP, /* A2DP sink is not preferred to speaker or wired HS */
-    AUDIO_POLICY_FORCE_SYSTEM_ENFORCED,
-    AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED,
-
-    AUDIO_POLICY_FORCE_CFG_CNT,
-    AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1,
-
-    AUDIO_POLICY_FORCE_DEFAULT = AUDIO_POLICY_FORCE_NONE,
-} audio_policy_forced_cfg_t;
-
-/* usages used for audio_policy->set_force_use() */
-typedef enum {
-    AUDIO_POLICY_FORCE_FOR_COMMUNICATION,
-    AUDIO_POLICY_FORCE_FOR_MEDIA,
-    AUDIO_POLICY_FORCE_FOR_RECORD,
-    AUDIO_POLICY_FORCE_FOR_DOCK,
-    AUDIO_POLICY_FORCE_FOR_SYSTEM,
-    AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO,
-
-    AUDIO_POLICY_FORCE_USE_CNT,
-    AUDIO_POLICY_FORCE_USE_MAX = AUDIO_POLICY_FORCE_USE_CNT - 1,
-} audio_policy_force_use_t;
-
-/* device connection states used for audio_policy->set_device_connection_state()
- */
-typedef enum {
-    AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-    AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
-
-    AUDIO_POLICY_DEVICE_STATE_CNT,
-    AUDIO_POLICY_DEVICE_STATE_MAX = AUDIO_POLICY_DEVICE_STATE_CNT - 1,
-} audio_policy_dev_state_t;
-
-typedef enum {
-    /* Used to generate a tone to notify the user of a
-     * notification/alarm/ringtone while they are in a call. */
-    AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION = 0,
-
-    AUDIO_POLICY_TONE_CNT,
-    AUDIO_POLICY_TONE_MAX                  = AUDIO_POLICY_TONE_CNT - 1,
-} audio_policy_tone_t;
-
-
-static inline bool audio_is_low_visibility(audio_stream_type_t stream)
-{
-    switch (stream) {
-    case AUDIO_STREAM_SYSTEM:
-    case AUDIO_STREAM_NOTIFICATION:
-    case AUDIO_STREAM_RING:
-        return true;
-    default:
-        return false;
-    }
-}
-
-
-__END_DECLS
-
-#endif  // ANDROID_AUDIO_POLICY_CORE_H
diff --git a/include/system/camera.h b/include/system/camera.h
index 7a4dd53..5d0873a 100644
--- a/include/system/camera.h
+++ b/include/system/camera.h
@@ -174,6 +174,22 @@
      * count is non-positive or too big to be realized.
      */
     CAMERA_CMD_SET_VIDEO_BUFFER_COUNT = 10,
+
+    /**
+     * Configure an explicit format to use for video recording metadata mode.
+     * This can be used to switch the format from the
+     * default IMPLEMENTATION_DEFINED gralloc format to some other
+     * device-supported format, and the default dataspace from the BT_709 color
+     * space to some other device-supported dataspace. arg1 is the HAL pixel
+     * format, and arg2 is the HAL dataSpace. This command returns
+     * INVALID_OPERATION error if it is sent after video recording is started,
+     * or the command is not supported at all.
+     *
+     * If the gralloc format is set to a format other than
+     * IMPLEMENTATION_DEFINED, then HALv3 devices will use gralloc usage flags
+     * of SW_READ_OFTEN.
+     */
+    CAMERA_CMD_SET_VIDEO_FORMAT = 11
 };
 
 /** camera fatal errors */
@@ -194,7 +210,12 @@
     /** The facing of the camera is opposite to that of the screen. */
     CAMERA_FACING_BACK = 0,
     /** The facing of the camera is the same as that of the screen. */
-    CAMERA_FACING_FRONT = 1
+    CAMERA_FACING_FRONT = 1,
+    /**
+     * The facing of the camera is not fixed relative to the screen.
+     * The cameras with this facing are external cameras, e.g. USB cameras.
+     */
+    CAMERA_FACING_EXTERNAL = 2
 };
 
 enum {
diff --git a/include/system/graphics.h b/include/system/graphics.h
index efd48cb..afd9f7b 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -58,11 +58,6 @@
     HAL_PIXEL_FORMAT_RGB_565            = 4,
     HAL_PIXEL_FORMAT_BGRA_8888          = 5,
 
-    // Deprecated sRGB formats for source code compatibility
-    // Not for use in new code
-    HAL_PIXEL_FORMAT_sRGB_A_8888        = 0xC,
-    HAL_PIXEL_FORMAT_sRGB_X_8888        = 0xD,
-
     /*
      * 0x100 - 0x1FF
      *
@@ -152,7 +147,8 @@
      * 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.
+     * image where each sample is a distance value measured by a depth camera,
+     * plus an associated confidence value.
      */
     HAL_PIXEL_FORMAT_Y16    = 0x20363159,
 
@@ -194,9 +190,6 @@
      */
     HAL_PIXEL_FORMAT_RAW16 = 0x20,
 
-    // Temporary alias for source code compatibility; do not use in new code
-    HAL_PIXEL_FORMAT_RAW_SENSOR = HAL_PIXEL_FORMAT_RAW16,
-
     /*
      * Android RAW10 format:
      *
@@ -252,6 +245,56 @@
     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.
@@ -316,18 +359,18 @@
     HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22,
 
     /*
-     * Android flexible YCbCr formats
+     * Android flexible YCbCr 4:2:0 formats
      *
-     * This format allows platforms to use an efficient YCbCr/YCrCb buffer
-     * layout, while still describing the buffer layout in a way accessible to
-     * the CPU in a device-independent manner.  While called YCbCr, it can be
+     * 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_HW_CAMERA_WRITE and USAGE_SW_READ_* are set.
+     * 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.
@@ -337,6 +380,62 @@
      */
     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
@@ -383,25 +482,31 @@
  * When locking a native buffer of the above format and dataSpace value,
  * the vaddr pointer can be cast to this structure.
  *
- * A variable-length list of (x,y,z) 3D points, as floats.
+ * A variable-length list of (x,y,z, confidence) 3D points, as floats.  (x, y,
+ * z) represents a measured point's position, with the coordinate system defined
+ * by the data source.  Confidence represents the estimated likelihood that this
+ * measurement is correct. It is between 0.f and 1.f, inclusive, with 1.f ==
+ * 100% confidence.
  *
  * @num_points is the number of points in the list
  *
  * @xyz_points is the flexible array of floating-point values.
- *   It contains (num_points) * 3 floats.
+ *   It contains (num_points) * 4 floats.
  *
  *   For example:
  *     android_depth_points d = get_depth_buffer();
  *     struct {
- *       float x; float y; float z;
+ *       float x; float y; float z; float confidence;
  *     } firstPoint, lastPoint;
  *
- *     firstPoint.x = d.xyz_points[0];
- *     firstPoint.y = d.xyz_points[1];
- *     firstPoint.z = d.xyz_points[2];
- *     lastPoint.x = d.xyz_points[(d.num_points - 1) * 3 + 0];
- *     lastPoint.y = d.xyz_points[(d.num_points - 1) * 3 + 1];
- *     lastPoint.z = d.xyz_points[(d.num_points - 1) * 3 + 2];
+ *     firstPoint.x = d.xyzc_points[0];
+ *     firstPoint.y = d.xyzc_points[1];
+ *     firstPoint.z = d.xyzc_points[2];
+ *     firstPoint.confidence = d.xyzc_points[3];
+ *     lastPoint.x = d.xyzc_points[(d.num_points - 1) * 4 + 0];
+ *     lastPoint.y = d.xyzc_points[(d.num_points - 1) * 4 + 1];
+ *     lastPoint.z = d.xyzc_points[(d.num_points - 1) * 4 + 2];
+ *     lastPoint.confidence = d.xyzc_points[(d.num_points - 1) * 4 + 3];
  */
 
 struct android_depth_points {
@@ -410,7 +515,7 @@
     /** reserved for future use, set to 0 by gralloc's (*lock)() */
     uint32_t reserved[8];
 
-    float xyz_points[];
+    float xyzc_points[];
 };
 
 /**
@@ -632,9 +737,18 @@
     /*
      * The buffer contains depth ranging measurements from a depth camera.
      * This value is valid with formats:
-     *    HAL_PIXEL_FORMAT_Y16: 16-bit single channel depth image.
+     *    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) coordinate point list.
+     *       a variable-length float (x,y,z, confidence) coordinate point list.
      *       The point cloud will be represented with the android_depth_points
      *       structure.
      */
diff --git a/include/system/radio.h b/include/system/radio.h
new file mode 100644
index 0000000..a088526
--- /dev/null
+++ b/include/system/radio.h
@@ -0,0 +1,247 @@
+/*
+ * 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 ANDROID_RADIO_H
+#define ANDROID_RADIO_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+
+#define RADIO_NUM_BANDS_MAX     16
+#define RADIO_NUM_SPACINGS_MAX  16
+#define RADIO_STRING_LEN_MAX    128
+
+/*
+ * Radio hardware module class. A given radio hardware module HAL is of one class
+ * only. The platform can not have more than one hardware module of each class.
+ * Current version of the framework only supports RADIO_CLASS_AM_FM.
+ */
+typedef enum {
+    RADIO_CLASS_AM_FM = 0,  /* FM (including HD radio) and AM */
+    RADIO_CLASS_SAT   = 1,  /* Satellite Radio */
+    RADIO_CLASS_DT    = 2,  /* Digital Radio (DAB) */
+} radio_class_t;
+
+/* value for field "type" of radio band described in struct radio_hal_band_config */
+typedef enum {
+    RADIO_BAND_AM     = 0,  /* Amplitude Modulation band: LW, MW, SW */
+    RADIO_BAND_FM     = 1,  /* Frequency Modulation band: FM */
+    RADIO_BAND_FM_HD  = 2,  /* FM HD Radio / DRM (IBOC) */
+    RADIO_BAND_AM_HD  = 3,  /* AM HD Radio / DRM (IBOC) */
+} radio_band_t;
+
+/* RDS variant implemented. A struct radio_hal_fm_band_config can list none or several. */
+enum {
+    RADIO_RDS_NONE   = 0x0,
+    RADIO_RDS_WORLD  = 0x01,
+    RADIO_RDS_US     = 0x02,
+};
+typedef unsigned int radio_rds_t;
+
+/* FM deemphasis variant implemented. A struct radio_hal_fm_band_config can list one or more. */
+enum {
+    RADIO_DEEMPHASIS_50   = 0x1,
+    RADIO_DEEMPHASIS_75   = 0x2,
+};
+typedef unsigned int radio_deemphasis_t;
+
+/* Region a particular radio band configuration corresponds to. Not used at the HAL.
+ * Derived by the framework when converting the band descriptors retrieved from the HAL to
+ * individual band descriptors for each supported region. */
+typedef enum {
+    RADIO_REGION_NONE  = -1,
+    RADIO_REGION_ITU_1 = 0,
+    RADIO_REGION_ITU_2 = 1,
+    RADIO_REGION_OIRT  = 2,
+    RADIO_REGION_JAPAN = 3,
+    RADIO_REGION_KOREA = 4,
+} radio_region_t;
+
+/* scanning direction for scan() and step() tuner APIs */
+typedef enum {
+    RADIO_DIRECTION_UP,
+    RADIO_DIRECTION_DOWN
+} radio_direction_t;
+
+/* unique handle allocated to a radio module */
+typedef unsigned int radio_handle_t;
+
+/* Opaque meta data structure used by radio meta data API (see system/radio_metadata.h) */
+typedef struct radio_medtadata radio_metadata_t;
+
+
+/* Additional attributes for an FM band configuration */
+typedef struct radio_hal_fm_band_config {
+    radio_deemphasis_t  deemphasis; /* deemphasis variant */
+    bool                stereo;     /* stereo supported */
+    radio_rds_t         rds;        /* RDS variants supported */
+    bool                ta;         /* Traffic Announcement supported */
+    bool                af;         /* Alternate Frequency supported */
+} radio_hal_fm_band_config_t;
+
+/* Additional attributes for an AM band configuration */
+typedef struct radio_hal_am_band_config {
+    bool                stereo;     /* stereo supported */
+} radio_hal_am_band_config_t;
+
+/* Radio band configuration. Describes a given band supported by the radio module.
+ * The HAL can expose only one band per type with the the maximum range supported and all options.
+ * THe framework will derive the actual regions were this module can operate and expose separate
+ * band configurations for applications to chose from. */
+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];
+    union {
+        radio_hal_fm_band_config_t fm;
+        radio_hal_am_band_config_t am;
+    };
+} radio_hal_band_config_t;
+
+/* Used internally by the framework to represent a band for s specific region */
+typedef struct radio_band_config {
+    radio_region_t  region;
+    radio_hal_band_config_t band;
+} radio_band_config_t;
+
+
+/* Exposes properties of a given hardware radio module.
+ * NOTE: current framework implementation supports only one audio source (num_audio_sources = 1).
+ * The source corresponds to AUDIO_DEVICE_IN_FM_TUNER.
+ * If more than one tuner is supported (num_tuners > 1), only one can be connected to the audio
+ * source. */
+typedef struct radio_hal_properties {
+    radio_class_t   class_id;   /* Class of this module. E.g RADIO_CLASS_AM_FM */
+    char            implementor[RADIO_STRING_LEN_MAX];  /* implementor name */
+    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 */
+    bool            supports_capture; /* the hardware supports capture of audio source audio HAL */
+    unsigned int    num_bands;      /* number of band descriptors */
+    radio_hal_band_config_t bands[RADIO_NUM_BANDS_MAX]; /* band descriptors */
+} radio_hal_properties_t;
+
+/* Used internally by the framework. Same information as in struct radio_hal_properties plus a
+ * unique handle and one band configuration per region. */
+typedef struct radio_properties {
+    radio_handle_t      handle;
+    radio_class_t       class_id;
+    char                implementor[RADIO_STRING_LEN_MAX];
+    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;
+    bool                supports_capture;
+    unsigned int        num_bands;
+    radio_band_config_t bands[RADIO_NUM_BANDS_MAX];
+} radio_properties_t;
+
+/* Radio program information. Returned by the HAL with event RADIO_EVENT_TUNED.
+ * 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) */
+    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 */
+    radio_metadata_t *metadata; /* non null if meta data are present (e.g PTY, song title ...) */
+} radio_program_info_t;
+
+
+/* Events sent to the framework via the HAL callback. An event can notify the completion of an
+ * asynchronous command (configuration, tune, scan ...) or a spontaneous change (antenna connection,
+ * failure, AF switching, meta data reception... */
+enum {
+    RADIO_EVENT_HW_FAILURE  = 0,  /* hardware module failure. Requires reopening the tuner */
+    RADIO_EVENT_CONFIG      = 1,  /* configuration change completed */
+    RADIO_EVENT_ANTENNA     = 2,  /* Antenna connected, disconnected */
+    RADIO_EVENT_TUNED       = 3,  /* tune, step, scan completed */
+    RADIO_EVENT_METADATA    = 4,  /* New meta data received */
+    RADIO_EVENT_TA          = 5,  /* Traffic announcement start or stop */
+    RADIO_EVENT_AF_SWITCH   = 6,  /* Switch to Alternate Frequency */
+    // begin framework only events
+    RADIO_EVENT_CONTROL     = 100, /* loss/gain of tuner control */
+    RADIO_EVENT_SERVER_DIED = 101, /* radio service died */
+};
+typedef unsigned int radio_event_type_t;
+
+/* 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 */
+    union {
+        bool                    on;     /* RADIO_EVENT_ANTENNA, RADIO_EVENT_TA */
+        radio_hal_band_config_t config; /* RADIO_EVENT_CONFIG */
+        radio_program_info_t    info;   /* RADIO_EVENT_TUNED, RADIO_EVENT_AF_SWITCH */
+        radio_metadata_t        *metadata; /* RADIO_EVENT_METADATA */
+    };
+} radio_hal_event_t;
+
+/* Used internally by the framework. Same information as in struct radio_hal_event */
+typedef struct radio_event {
+    radio_event_type_t  type;
+    int                 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 */
+    };
+} radio_event_t;
+
+
+static radio_rds_t radio_rds_for_region(bool rds, radio_region_t region) {
+    if (!rds)
+        return RADIO_RDS_NONE;
+    switch(region) {
+        case RADIO_REGION_ITU_1:
+        case RADIO_REGION_OIRT:
+        case RADIO_REGION_JAPAN:
+        case RADIO_REGION_KOREA:
+            return RADIO_RDS_WORLD;
+        case RADIO_REGION_ITU_2:
+            return RADIO_RDS_US;
+        default:
+            return RADIO_REGION_NONE;
+    }
+}
+
+static radio_deemphasis_t radio_demephasis_for_region(radio_region_t region) {
+    switch(region) {
+        case RADIO_REGION_KOREA:
+        case RADIO_REGION_ITU_2:
+            return RADIO_DEEMPHASIS_75;
+        case RADIO_REGION_ITU_1:
+        case RADIO_REGION_OIRT:
+        case RADIO_REGION_JAPAN:
+        default:
+            return RADIO_DEEMPHASIS_50;
+    }
+}
+
+#endif  // ANDROID_RADIO_H
diff --git a/include/system/sound_trigger.h b/include/system/sound_trigger.h
deleted file mode 100644
index 773e4f7..0000000
--- a/include/system/sound_trigger.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_SOUND_TRIGGER_H
-#define ANDROID_SOUND_TRIGGER_H
-
-#include <stdbool.h>
-#include <system/audio.h>
-
-#define SOUND_TRIGGER_MAX_STRING_LEN 64 /* max length of strings in properties or
-                                           descriptor structs */
-#define SOUND_TRIGGER_MAX_LOCALE_LEN 6  /* max length of locale string. e.g en_US */
-#define SOUND_TRIGGER_MAX_USERS 10      /* max number of concurrent users */
-#define SOUND_TRIGGER_MAX_PHRASES 10    /* max number of concurrent phrases */
-
-typedef enum {
-    SOUND_TRIGGER_STATE_NO_INIT = -1,   /* The sound trigger service is not initialized */
-    SOUND_TRIGGER_STATE_ENABLED = 0,    /* The sound trigger service is enabled */
-    SOUND_TRIGGER_STATE_DISABLED = 1    /* The sound trigger service is disabled */
-} sound_trigger_service_state_t;
-
-#define RECOGNITION_MODE_VOICE_TRIGGER 0x1       /* simple voice trigger */
-#define RECOGNITION_MODE_USER_IDENTIFICATION 0x2 /* trigger only if one user in model identified */
-#define RECOGNITION_MODE_USER_AUTHENTICATION 0x4 /* trigger only if one user in mode
-                                                    authenticated */
-#define RECOGNITION_STATUS_SUCCESS 0
-#define RECOGNITION_STATUS_ABORT 1
-#define RECOGNITION_STATUS_FAILURE 2
-
-#define SOUND_MODEL_STATUS_UPDATED 0
-
-typedef enum {
-    SOUND_MODEL_TYPE_UNKNOWN = -1,    /* use for unspecified sound model type */
-    SOUND_MODEL_TYPE_KEYPHRASE = 0    /* use for key phrase sound models */
-} sound_trigger_sound_model_type_t;
-
-typedef struct sound_trigger_uuid_s {
-    unsigned int   timeLow;
-    unsigned short timeMid;
-    unsigned short timeHiAndVersion;
-    unsigned short clockSeq;
-    unsigned char  node[6];
-} sound_trigger_uuid_t;
-
-/*
- * sound trigger implementation descriptor read by the framework via get_properties().
- * Used by SoundTrigger service to report to applications and manage concurrency and policy.
- */
-struct sound_trigger_properties {
-    char                 implementor[SOUND_TRIGGER_MAX_STRING_LEN]; /* implementor name */
-    char                 description[SOUND_TRIGGER_MAX_STRING_LEN]; /* implementation description */
-    unsigned int         version;               /* implementation version */
-    sound_trigger_uuid_t uuid;                  /* unique implementation ID.
-                                                   Must change with version each version */
-    unsigned int         max_sound_models;      /* maximum number of concurrent sound models
-                                                   loaded */
-    unsigned int         max_key_phrases;       /* maximum number of key phrases */
-    unsigned int         max_users;             /* maximum number of concurrent users detected */
-    unsigned int         recognition_modes;     /* all supported modes.
-                                                   e.g RECOGNITION_MODE_VOICE_TRIGGER */
-    bool                 capture_transition;    /* supports seamless transition from detection
-                                                   to capture */
-    unsigned int         max_buffer_ms;         /* maximum buffering capacity in ms if
-                                                   capture_transition is true*/
-    bool                 concurrent_capture;    /* supports capture by other use cases while
-                                                   detection is active */
-    bool                 trigger_in_event;      /* returns the trigger capture in event */
-    unsigned int         power_consumption_mw;  /* Rated power consumption when detection is active
-                                                   with TDB silence/sound/speech ratio */
-};
-
-typedef int sound_trigger_module_handle_t;
-
-struct sound_trigger_module_descriptor {
-    sound_trigger_module_handle_t   handle;
-    struct sound_trigger_properties properties;
-};
-
-typedef int sound_model_handle_t;
-
-/*
- * Generic sound model descriptor. This struct is the header of a larger block passed to
- * load_sound_model() and containing the binary data of the sound model.
- * Proprietary representation of users in binary data must match information indicated
- * by users field
- */
-struct sound_trigger_sound_model {
-    sound_trigger_sound_model_type_t type;        /* model type. e.g. SOUND_MODEL_TYPE_KEYPHRASE */
-    sound_trigger_uuid_t             uuid;        /* unique sound model ID. */
-    sound_trigger_uuid_t             vendor_uuid; /* unique vendor ID. Identifies the engine the
-                                                  sound model was build for */
-    unsigned int                     data_size;   /* size of opaque model data */
-    unsigned int                     data_offset; /* offset of opaque data start from head of struct
-                                                    (e.g sizeof struct sound_trigger_sound_model) */
-};
-
-/* key phrase descriptor */
-struct sound_trigger_phrase {
-    unsigned int id;                /* keyphrase ID */
-    unsigned int recognition_mode;  /* recognition modes supported by this key phrase */
-    unsigned int num_users;         /* number of users in the key phrase */
-    unsigned int users[SOUND_TRIGGER_MAX_USERS]; /* users ids: (not uid_t but sound trigger
-                                                 specific IDs */
-    char         locale[SOUND_TRIGGER_MAX_LOCALE_LEN]; /* locale - JAVA Locale style (e.g. en_US) */
-    char         text[SOUND_TRIGGER_MAX_STRING_LEN];   /* phrase text in UTF-8 format. */
-};
-
-/*
- * Specialized sound model for key phrase detection.
- * Proprietary representation of key phrases in binary data must match information indicated
- * by phrases field
- */
-struct sound_trigger_phrase_sound_model {
-    struct sound_trigger_sound_model common;
-    unsigned int                     num_phrases;   /* number of key phrases in model */
-    struct sound_trigger_phrase      phrases[SOUND_TRIGGER_MAX_PHRASES];
-};
-
-
-/*
- * Generic recognition event sent via recognition callback
- */
-struct sound_trigger_recognition_event {
-    int                              status;            /* recognition status e.g.
-                                                           RECOGNITION_STATUS_SUCCESS */
-    sound_trigger_sound_model_type_t type;              /* event type, same as sound model type.
-                                                           e.g. SOUND_MODEL_TYPE_KEYPHRASE */
-    sound_model_handle_t             model;             /* loaded sound model that triggered the
-                                                           event */
-    bool                             capture_available; /* it is possible to capture audio from this
-                                                           utterance buffered by the
-                                                           implementation */
-    int                              capture_session;   /* audio session ID. framework use */
-    int                              capture_delay_ms;  /* delay in ms between end of model
-                                                           detection and start of audio available
-                                                           for capture. A negative value is possible
-                                                           (e.g. if key phrase is also available for
-                                                           capture */
-    int                              capture_preamble_ms; /* duration in ms of audio captured
-                                                            before the start of the trigger.
-                                                            0 if none. */
-    bool                             trigger_in_data; /* the opaque data is the capture of
-                                                            the trigger sound */
-    audio_config_t                   audio_config;        /* audio format of either the trigger in
-                                                             event data or to use for capture of the
-                                                             rest of the utterance */
-    unsigned int                     data_size;         /* size of opaque event data */
-    unsigned int                     data_offset;       /* offset of opaque data start from start of
-                                                          this struct (e.g sizeof struct
-                                                          sound_trigger_phrase_recognition_event) */
-};
-
-/*
- * Confidence level for each user in struct sound_trigger_phrase_recognition_extra
- */
-struct sound_trigger_confidence_level {
-    unsigned int user_id;   /* user ID */
-    unsigned int level;     /* confidence level in percent (0 - 100).
-                               - min level for recognition configuration
-                               - detected level for recognition event */
-};
-
-/*
- * Specialized recognition event for key phrase detection
- */
-struct sound_trigger_phrase_recognition_extra {
-    unsigned int id;                /* keyphrase ID */
-    unsigned int recognition_modes; /* recognition modes used for this keyphrase */
-    unsigned int confidence_level;  /* confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER */
-    unsigned int num_levels;        /* number of user confidence levels */
-    struct sound_trigger_confidence_level levels[SOUND_TRIGGER_MAX_USERS];
-};
-
-struct sound_trigger_phrase_recognition_event {
-    struct sound_trigger_recognition_event common;
-    unsigned int                           num_phrases;
-    struct sound_trigger_phrase_recognition_extra phrase_extras[SOUND_TRIGGER_MAX_PHRASES];
-};
-
-/*
- * configuration for sound trigger capture session passed to start_recognition()
- */
-struct sound_trigger_recognition_config {
-    audio_io_handle_t    capture_handle;    /* IO handle that will be used for capture.
-                                            N/A if capture_requested is false */
-    audio_devices_t      capture_device;    /* input device requested for detection capture */
-    bool                 capture_requested; /* capture and buffer audio for this recognition
-                                            instance */
-    unsigned int         num_phrases;   /* number of key phrases recognition extras */
-    struct sound_trigger_phrase_recognition_extra phrases[SOUND_TRIGGER_MAX_PHRASES];
-                                           /* configuration for each key phrase */
-    unsigned int        data_size;         /* size of opaque capture configuration data */
-    unsigned int        data_offset;       /* offset of opaque data start from start of this struct
-                                           (e.g sizeof struct sound_trigger_recognition_config) */
-};
-
-/*
- * Event sent via load sound model callback
- */
-struct sound_trigger_model_event {
-    int                  status;      /* sound model status e.g. SOUND_MODEL_STATUS_UPDATED */
-    sound_model_handle_t model;       /* loaded sound model that triggered the event */
-    unsigned int         data_size;   /* size of event data if any. Size of updated sound model if
-                                       status is SOUND_MODEL_STATUS_UPDATED */
-    unsigned int         data_offset; /* offset of data start from start of this struct
-                                       (e.g sizeof struct sound_trigger_model_event) */
-};
-
-
-#endif  // ANDROID_SOUND_TRIGGER_H
diff --git a/include/sysutils/NetlinkEvent.h b/include/sysutils/NetlinkEvent.h
index 4fa49c5..b80f3ea 100644
--- a/include/sysutils/NetlinkEvent.h
+++ b/include/sysutils/NetlinkEvent.h
@@ -21,25 +21,29 @@
 #define NL_PARAMS_MAX 32
 
 class NetlinkEvent {
+public:
+    enum class Action {
+        kUnknown = 0,
+        kAdd = 1,
+        kRemove = 2,
+        kChange = 3,
+        kLinkUp = 4,
+        kLinkDown = 5,
+        kAddressUpdated = 6,
+        kAddressRemoved = 7,
+        kRdnss = 8,
+        kRouteUpdated = 9,
+        kRouteRemoved = 10,
+    };
+
+private:
     int  mSeq;
     char *mPath;
-    int  mAction;
+    Action mAction;
     char *mSubsystem;
     char *mParams[NL_PARAMS_MAX];
 
 public:
-    const static int NlActionUnknown;
-    const static int NlActionAdd;
-    const static int NlActionRemove;
-    const static int NlActionChange;
-    const static int NlActionLinkDown;
-    const static int NlActionLinkUp;
-    const static int NlActionAddressUpdated;
-    const static int NlActionAddressRemoved;
-    const static int NlActionRdnss;
-    const static int NlActionRouteUpdated;
-    const static int NlActionRouteRemoved;
-
     NetlinkEvent();
     virtual ~NetlinkEvent();
 
@@ -47,7 +51,7 @@
     const char *findParam(const char *paramName);
 
     const char *getSubsystem() { return mSubsystem; }
-    int getAction() { return mAction; }
+    Action getAction() { return mAction; }
 
     void dump();
 
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index d26e931..4350ec1 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -156,6 +156,10 @@
  */
 char* usb_device_get_product_name(struct usb_device *device);
 
+/* Returns the version number for the USB device.
+ */
+int usb_device_get_version(struct usb_device *device);
+
 /* Returns the USB serial number for the USB device.
  * Call free() to free the result when you are done with it.
  */
diff --git a/include/utils/BlobCache.h b/include/utils/BlobCache.h
index 7d621e4..65dca9f 100644
--- a/include/utils/BlobCache.h
+++ b/include/utils/BlobCache.h
@@ -185,6 +185,12 @@
         // mNumEntries is number of cache entries following the header in the
         // data.
         size_t mNumEntries;
+
+        // mBuildId is the build id of the device when the cache was created.
+        // When an update to the build happens (via an OTA or other update) this
+        // is used to invalidate the cache.
+        int mBuildIdLength;
+        char mBuildId[];
     };
 
     // An EntryHeader is the header for a serialized cache entry.  No need to
diff --git a/include/utils/LinearAllocator.h b/include/utils/LinearAllocator.h
deleted file mode 100644
index 4772bc8..0000000
--- a/include/utils/LinearAllocator.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ANDROID_LINEARALLOCATOR_H
-#define ANDROID_LINEARALLOCATOR_H
-
-#include <stddef.h>
-
-namespace android {
-
-/**
- * A memory manager that internally allocates multi-kbyte buffers for placing objects in. It avoids
- * the overhead of malloc when many objects are allocated. It is most useful when creating many
- * small objects with a similar lifetime, and doesn't add significant overhead for large
- * allocations.
- */
-class LinearAllocator {
-public:
-    LinearAllocator();
-    ~LinearAllocator();
-
-    /**
-     * Reserves and returns a region of memory of at least size 'size', aligning as needed.
-     * Typically this is used in an object's overridden new() method or as a replacement for malloc.
-     *
-     * The lifetime of the returned buffers is tied to that of the LinearAllocator. If calling
-     * delete() on an object stored in a buffer is needed, it should be overridden to use
-     * rewindIfLastAlloc()
-     */
-    void* alloc(size_t size);
-
-    /**
-     * Attempt to deallocate the given buffer, with the LinearAllocator attempting to rewind its
-     * state if possible. No destructors are called.
-     */
-    void rewindIfLastAlloc(void* ptr, size_t allocSize);
-
-    /**
-     * Dump memory usage statistics to the log (allocated and wasted space)
-     */
-    void dumpMemoryStats(const char* prefix = "");
-
-    /**
-     * The number of bytes used for buffers allocated in the LinearAllocator (does not count space
-     * wasted)
-     */
-    size_t usedSize() const { return mTotalAllocated - mWastedSpace; }
-
-private:
-    LinearAllocator(const LinearAllocator& other);
-
-    class Page;
-
-    Page* newPage(size_t pageSize);
-    bool fitsInCurrentPage(size_t size);
-    void ensureNext(size_t size);
-    void* start(Page *p);
-    void* end(Page* p);
-
-    size_t mPageSize;
-    size_t mMaxAllocSize;
-    void* mNext;
-    Page* mCurrentPage;
-    Page* mPages;
-
-    // Memory usage tracking
-    size_t mTotalAllocated;
-    size_t mWastedSpace;
-    size_t mPageCount;
-    size_t mDedicatedPageCount;
-};
-
-}; // namespace android
-
-#endif // ANDROID_LINEARALLOCATOR_H
diff --git a/include/utils/Looper.h b/include/utils/Looper.h
index 15c9891..da2d5f2 100644
--- a/include/utils/Looper.h
+++ b/include/utils/Looper.h
@@ -386,11 +386,12 @@
     void removeMessages(const sp<MessageHandler>& handler, int what);
 
     /**
-     * Return whether this looper's thread is currently idling -- that is, whether it
-     * stopped waiting for more work to do.  Note that this is intrinsically racy, since
-     * its state can change before you get the result back.
+     * Returns whether this looper's thread is currently polling for more work to do.
+     * This is a good signal that the loop is still alive rather than being stuck
+     * handling a callback.  Note that this method is intrinsically racy, since the
+     * state of the loop can change before you get the result back.
      */
-    bool isIdling() const;
+    bool isPolling() const;
 
     /**
      * Prepares a looper associated with the calling thread, and returns it.
@@ -419,8 +420,12 @@
     struct Request {
         int fd;
         int ident;
+        int events;
+        int seq;
         sp<LooperCallback> callback;
         void* data;
+
+        void initEventItem(struct epoll_event* eventItem) const;
     };
 
     struct Response {
@@ -442,8 +447,7 @@
 
     const bool mAllowNonCallbacks; // immutable
 
-    int mWakeReadPipeFd;  // immutable
-    int mWakeWritePipeFd; // immutable
+    int mWakeEventFd;  // immutable
     Mutex mLock;
 
     Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
@@ -451,12 +455,14 @@
 
     // Whether we are currently waiting for work.  Not protected by a lock,
     // any use of it is racy anyway.
-    volatile bool mIdling;
+    volatile bool mPolling;
 
-    int mEpollFd; // immutable
+    int mEpollFd; // guarded by mLock but only modified on the looper thread
+    bool mEpollRebuildRequired; // guarded by mLock
 
     // Locked list of file descriptor monitoring requests.
     KeyedVector<int, Request> mRequests;  // guarded by mLock
+    int mNextRequestSeq;
 
     // This state is only used privately by pollOnce and does not require a lock since
     // it runs on a single thread.
@@ -465,11 +471,15 @@
     nsecs_t mNextMessageUptime; // set to LLONG_MAX when none
 
     int pollInner(int timeoutMillis);
+    int removeFd(int fd, int seq);
     void awoken();
     void pushResponse(int events, const Request& request);
+    void rebuildEpollLocked();
+    void scheduleEpollRebuildLocked();
 
     static void initTLSKey();
     static void threadDestructor(void *st);
+    static void initEpollEvent(struct epoll_event* eventItem);
 };
 
 } // namespace android
diff --git a/init/Android.mk b/init/Android.mk
index 6737be4..e9bab63 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -93,7 +93,9 @@
     libselinux \
     libmincrypt \
     libc++_static \
-    libdl
+    libdl \
+    libsparse_static \
+    libz
 
 # Create symlinks
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
diff --git a/init/devices.cpp b/init/devices.cpp
index 3652c57..d556e30 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -528,7 +528,7 @@
         make_device(devpath, path, block, major, minor, (const char **)links);
         if (links) {
             for (i = 0; links[i]; i++)
-                make_link(devpath, links[i]);
+                make_link_init(devpath, links[i]);
         }
     }
 
diff --git a/init/property_service.cpp b/init/property_service.cpp
index aa939a5..7194820 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -203,6 +203,16 @@
     if (!is_legal_property_name(name, namelen)) return -1;
     if (valuelen >= PROP_VALUE_MAX) return -1;
 
+    if (strcmp("selinux.reload_policy", name) == 0 && strcmp("1", value) == 0) {
+        if (selinux_reload_policy() != 0) {
+            ERROR("Failed to reload policy\n");
+        }
+    } else if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
+        if (restorecon_recursive(value) != 0) {
+            ERROR("Failed to restorecon_recursive %s\n", value);
+        }
+    }
+
     prop_info* pi = (prop_info*) __system_property_find(name);
 
     if(pi != 0) {
@@ -234,9 +244,6 @@
          * to prevent them from being overwritten by default values.
          */
         write_persistent_property(name, value);
-    } else if (strcmp("selinux.reload_policy", name) == 0 &&
-               strcmp("1", value) == 0) {
-        selinux_reload_policy();
     }
     property_changed(name, value);
     return 0;
diff --git a/init/util.cpp b/init/util.cpp
index f6131e3..fdbdc1c 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -336,7 +336,7 @@
     }
 }
 
-void make_link(const char *oldpath, const char *newpath)
+void make_link_init(const char *oldpath, const char *newpath)
 {
     int ret;
     char buf[256];
@@ -375,10 +375,10 @@
 int wait_for_file(const char *filename, int timeout)
 {
     struct stat info;
-    time_t timeout_time = gettime() + timeout;
+    uint64_t timeout_time_ns = gettime_ns() + timeout * UINT64_C(1000000000);
     int ret = -1;
 
-    while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
+    while (gettime_ns() < timeout_time_ns && ((ret = stat(filename, &info)) < 0))
         usleep(10000);
 
     return ret;
diff --git a/init/util.h b/init/util.h
index f08cb8d..502b943 100644
--- a/init/util.h
+++ b/init/util.h
@@ -54,7 +54,7 @@
 
 int mkdir_recursive(const char *pathname, mode_t mode);
 void sanitize(char *p);
-void make_link(const char *oldpath, const char *newpath);
+void make_link_init(const char *oldpath, const char *newpath);
 void remove_link(const char *oldpath, const char *newpath);
 int wait_for_file(const char *filename, int timeout);
 void open_devnull_stdio(void);
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 5330949..6fb8c22 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -122,6 +122,9 @@
 
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
 LOCAL_STATIC_LIBRARIES := liblog
+ifneq ($(ENABLE_CPUSETS),)
+LOCAL_CFLAGS += -DUSE_CPUSETS
+endif
 LOCAL_CFLAGS += -Werror -Wall -Wextra -std=gnu90
 include $(BUILD_STATIC_LIBRARY)
 
@@ -131,6 +134,9 @@
 # liblog symbols present in libcutils.
 LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog
 LOCAL_SHARED_LIBRARIES := liblog
+ifneq ($(ENABLE_CPUSETS),)
+LOCAL_CFLAGS += -DUSE_CPUSETS
+endif
 LOCAL_CFLAGS += -Werror -Wall -Wextra
 LOCAL_C_INCLUDES := $(libcutils_c_includes)
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 5f6f8f9..3a9fb8a 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -154,14 +154,21 @@
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
 };
 
-static int fs_config_open(int dir)
+static int fs_config_open(int dir, const char *target_out_path)
 {
     int fd = -1;
 
-    const char *out = getenv("OUT");
-    if (out && *out) {
+    if (target_out_path && *target_out_path) {
+        /* target_out_path is the path to the directory holding content of system partition
+           but as we cannot guaranty it ends with '/system' we need this below skip_len logic */
         char *name = NULL;
-        if (asprintf(&name, "%s%s", out, dir ? conf_dir : conf_file) != -1) {
+        int target_out_path_len = strlen(target_out_path);
+        int skip_len = strlen("/system");
+
+        if (target_out_path[target_out_path_len] == '/') {
+            skip_len++;
+        }
+        if (asprintf(&name, "%s%s", target_out_path, (dir ? conf_dir : conf_file) + skip_len) != -1) {
             fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY));
             free(name);
         }
@@ -191,7 +198,7 @@
     return !strncmp(prefix, path, len);
 }
 
-void fs_config(const char *path, int dir,
+void fs_config(const char *path, int dir, const char *target_out_path,
                unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
 {
     const struct fs_path_config *pc;
@@ -203,7 +210,7 @@
 
     plen = strlen(path);
 
-    fd = fs_config_open(dir);
+    fd = fs_config_open(dir, target_out_path);
     if (fd >= 0) {
         struct fs_path_config_from_file header;
 
diff --git a/libcutils/native_handle.c b/libcutils/native_handle.c
index 9a4a5bb..61fa38e 100644
--- a/libcutils/native_handle.c
+++ b/libcutils/native_handle.c
@@ -25,11 +25,17 @@
 #include <cutils/log.h>
 #include <cutils/native_handle.h>
 
+static const int kMaxNativeFds = 1024;
+static const int kMaxNativeInts = 1024;
+
 native_handle_t* native_handle_create(int numFds, int numInts)
 {
-    native_handle_t* h = malloc(
-            sizeof(native_handle_t) + sizeof(int)*(numFds+numInts));
+    if (numFds < 0 || numInts < 0 || numFds > kMaxNativeFds || numInts > kMaxNativeInts) {
+        return NULL;
+    }
 
+    size_t mallocSize = sizeof(native_handle_t) + (sizeof(int) * (numFds + numInts));
+    native_handle_t* h = malloc(mallocSize);
     if (h) {
         h->version = sizeof(native_handle_t);
         h->numFds = numFds;
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 103ff66..298e3da 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -1,16 +1,16 @@
 /*
 ** Copyright 2007, 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -50,6 +50,7 @@
 
 // timer slack value in nS enforced when the thread moves to background
 #define TIMER_SLACK_BG 40000000
+#define TIMER_SLACK_FG 50000
 
 static pthread_once_t the_once = PTHREAD_ONCE_INIT;
 
@@ -59,27 +60,18 @@
 static int bg_cgroup_fd = -1;
 static int fg_cgroup_fd = -1;
 
+#ifdef USE_CPUSETS
+// File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
+static int bg_cpuset_fd = -1;
+static int fg_cpuset_fd = -1;
+#endif
+
 /* Add tid to the scheduling group defined by the policy */
-static int add_tid_to_cgroup(int tid, SchedPolicy policy)
+static int add_tid_to_cgroup(int tid, int fd)
 {
-    int fd;
-
-    switch (policy) {
-    case SP_BACKGROUND:
-        fd = bg_cgroup_fd;
-        break;
-    case SP_FOREGROUND:
-    case SP_AUDIO_APP:
-    case SP_AUDIO_SYS:
-        fd = fg_cgroup_fd;
-        break;
-    default:
-        fd = -1;
-        break;
-    }
-
     if (fd < 0) {
-        SLOGE("add_tid_to_cgroup failed; policy=%d\n", policy);
+        SLOGE("add_tid_to_cgroup failed; fd=%d\n", fd);
+        errno = EINVAL;
         return -1;
     }
 
@@ -100,8 +92,9 @@
          */
         if (errno == ESRCH)
                 return 0;
-        SLOGW("add_tid_to_cgroup failed to write '%s' (%s); policy=%d\n",
-              ptr, strerror(errno), policy);
+        SLOGW("add_tid_to_cgroup failed to write '%s' (%s); fd=%d\n",
+              ptr, strerror(errno), fd);
+        errno = EINVAL;
         return -1;
     }
 
@@ -127,6 +120,17 @@
     } else {
         __sys_supports_schedgroups = 0;
     }
+
+#ifdef USE_CPUSETS
+    if (!access("/dev/cpuset/tasks", F_OK)) {
+
+        filename = "/dev/cpuset/foreground/tasks";
+        fg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+        filename = "/dev/cpuset/background/tasks";
+        bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
+    }
+#endif
+
 }
 
 /*
@@ -236,6 +240,42 @@
     return 0;
 }
 
+int set_cpuset_policy(int tid, SchedPolicy policy)
+{
+    // in the absence of cpusets, use the old sched policy
+#ifndef USE_CPUSETS
+    return set_sched_policy(tid, policy);
+#else
+    if (tid == 0) {
+        tid = gettid();
+    }
+    policy = _policy(policy);
+    pthread_once(&the_once, __initialize);
+
+    int fd;
+    switch (policy) {
+    case SP_BACKGROUND:
+        fd = bg_cpuset_fd;
+        break;
+    case SP_FOREGROUND:
+    case SP_AUDIO_APP:
+    case SP_AUDIO_SYS:
+        fd = fg_cpuset_fd;
+        break;
+    default:
+        fd = -1;
+        break;
+    }
+
+    if (add_tid_to_cgroup(tid, fd) != 0) {
+        if (errno != ESRCH && errno != ENOENT)
+            return -errno;
+    }
+
+    return 0;
+#endif
+}
+
 int set_sched_policy(int tid, SchedPolicy policy)
 {
     if (tid == 0) {
@@ -286,7 +326,23 @@
 #endif
 
     if (__sys_supports_schedgroups) {
-        if (add_tid_to_cgroup(tid, policy)) {
+        int fd;
+        switch (policy) {
+        case SP_BACKGROUND:
+            fd = bg_cgroup_fd;
+            break;
+        case SP_FOREGROUND:
+        case SP_AUDIO_APP:
+        case SP_AUDIO_SYS:
+            fd = fg_cgroup_fd;
+            break;
+        default:
+            fd = -1;
+            break;
+        }
+
+
+        if (add_tid_to_cgroup(tid, fd) != 0) {
             if (errno != ESRCH && errno != ENOENT)
                 return -errno;
         }
@@ -296,11 +352,12 @@
         param.sched_priority = 0;
         sched_setscheduler(tid,
                            (policy == SP_BACKGROUND) ?
-                            SCHED_BATCH : SCHED_NORMAL,
+                           SCHED_BATCH : SCHED_NORMAL,
                            &param);
     }
 
-    prctl(PR_SET_TIMERSLACK_PID, policy == SP_BACKGROUND ? TIMER_SLACK_BG : 0, tid);
+    prctl(PR_SET_TIMERSLACK_PID,
+          policy == SP_BACKGROUND ? TIMER_SLACK_BG : TIMER_SLACK_FG, tid);
 
     return 0;
 }
@@ -337,4 +394,3 @@
     else
         return "error";
 }
-
diff --git a/libion/ion.c b/libion/ion.c
index 4908932..d1984bd 100644
--- a/libion/ion.c
+++ b/libion/ion.c
@@ -91,6 +91,7 @@
             int flags, off_t offset, unsigned char **ptr, int *map_fd)
 {
     int ret;
+    unsigned char *tmp_ptr;
     struct ion_fd_data data = {
         .handle = handle,
     };
@@ -103,16 +104,17 @@
     ret = ion_ioctl(fd, ION_IOC_MAP, &data);
     if (ret < 0)
         return ret;
-    *map_fd = data.fd;
-    if (*map_fd < 0) {
+    if (data.fd < 0) {
         ALOGE("map ioctl returned negative fd\n");
         return -EINVAL;
     }
-    *ptr = mmap(NULL, length, prot, flags, *map_fd, offset);
-    if (*ptr == MAP_FAILED) {
+    tmp_ptr = mmap(NULL, length, prot, flags, data.fd, offset);
+    if (tmp_ptr == MAP_FAILED) {
         ALOGE("mmap failed: %s\n", strerror(errno));
         return -errno;
     }
+    *map_fd = data.fd;
+    *ptr = tmp_ptr;
     return ret;
 }
 
@@ -129,11 +131,11 @@
     ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
     if (ret < 0)
         return ret;
-    *share_fd = data.fd;
-    if (*share_fd < 0) {
+    if (data.fd < 0) {
         ALOGE("share ioctl returned negative fd\n");
         return -EINVAL;
     }
+    *share_fd = data.fd;
     return ret;
 }
 
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index 70e37c6..c6b9fe4 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -1,16 +1,16 @@
 /*
  * Copyright 2008, 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 
+ * 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 
+ *     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 
+ * 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.
  */
 
@@ -33,7 +33,7 @@
 static const int NAP_TIME = 200;   /* wait for 200ms at a time */
                                   /* when polling for property values */
 static const char DAEMON_NAME_RENEW[]  = "iprenew";
-static char errmsg[100];
+static char errmsg[100] = "\0";
 /* interface length for dhcpcd daemon start (dhcpcd_<interface> as defined in init.rc file)
  * or for filling up system properties dhcpcd.<interface>.ipaddress, dhcpcd.<interface>.dns1
  * and other properties on a successful bind
@@ -74,7 +74,7 @@
 
     while (maxnaps-- >= 0) {
         if (property_get(name, value, NULL)) {
-            if (desired_value == NULL || 
+            if (desired_value == NULL ||
                     strcmp(value, desired_value) == 0) {
                 return 0;
             }
@@ -169,6 +169,47 @@
 }
 
 /*
+ * Get any available DHCP results.
+ */
+int dhcp_get_results(const char *interface,
+                     char *ipaddr,
+                     char *gateway,
+                     uint32_t *prefixLength,
+                     char *dns[],
+                     char *server,
+                     uint32_t *lease,
+                     char *vendorInfo,
+                     char *domain,
+                     char *mtu)
+{
+    char result_prop_name[PROPERTY_KEY_MAX];
+    char prop_value[PROPERTY_VALUE_MAX];
+
+    /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */
+    char p2p_interface[MAX_INTERFACE_LENGTH];
+    get_p2p_interface_replacement(interface, p2p_interface);
+    snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
+            DHCP_PROP_NAME_PREFIX,
+            p2p_interface);
+
+    memset(prop_value, '\0', PROPERTY_VALUE_MAX);
+    if (!property_get(result_prop_name, prop_value, NULL)) {
+        snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
+        return -1;
+    }
+    if (strcmp(prop_value, "ok") == 0) {
+        if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
+                server, lease, vendorInfo, domain, mtu) == -1) {
+            return -1;
+        }
+        return 0;
+    } else {
+        snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
+        return -1;
+    }
+}
+
+/*
  * Start the dhcp client daemon, and wait for it to finish
  * configuring the interface.
  *
@@ -177,16 +218,7 @@
  * Example:
  * service dhcpcd_<interface> /system/bin/dhcpcd -ABKL -f dhcpcd.conf
  */
-int dhcp_do_request(const char *interface,
-                    char *ipaddr,
-                    char *gateway,
-                    uint32_t *prefixLength,
-                    char *dns[],
-                    char *server,
-                    uint32_t *lease,
-                    char *vendorInfo,
-                    char *domain,
-                    char *mtu)
+int dhcp_start(const char *interface)
 {
     char result_prop_name[PROPERTY_KEY_MAX];
     char daemon_prop_name[PROPERTY_KEY_MAX];
@@ -230,21 +262,7 @@
         return -1;
     }
 
-    if (!property_get(result_prop_name, prop_value, NULL)) {
-        /* shouldn't ever happen, given the success of wait_for_property() */
-        snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
-        return -1;
-    }
-    if (strcmp(prop_value, "ok") == 0) {
-        if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
-                server, lease, vendorInfo, domain, mtu) == -1) {
-            return -1;
-        }
-        return 0;
-    } else {
-        snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
-        return -1;
-    }
+    return 0;
 }
 
 /**
@@ -320,16 +338,7 @@
  * service iprenew_<interface> /system/bin/dhcpcd -n
  *
  */
-int dhcp_do_request_renew(const char *interface,
-                    char *ipaddr,
-                    char *gateway,
-                    uint32_t *prefixLength,
-                    char *dns[],
-                    char *server,
-                    uint32_t *lease,
-                    char *vendorInfo,
-                    char *domain,
-                    char *mtu)
+int dhcp_start_renew(const char *interface)
 {
     char result_prop_name[PROPERTY_KEY_MAX];
     char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
@@ -359,16 +368,5 @@
         return -1;
     }
 
-    if (!property_get(result_prop_name, prop_value, NULL)) {
-        /* shouldn't ever happen, given the success of wait_for_property() */
-        snprintf(errmsg, sizeof(errmsg), "%s", "DHCP Renew result property was not set");
-        return -1;
-    }
-    if (strcmp(prop_value, "ok") == 0) {
-        return fill_ip_info(interface, ipaddr, gateway, prefixLength, dns,
-                server, lease, vendorInfo, domain, mtu);
-    } else {
-        snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
-        return -1;
-    }
+    return 0;
 }
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index a80965f..ad0500d 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -252,14 +252,15 @@
 int killProcessGroup(uid_t uid, int initialPid, int signal)
 {
     int processes;
-    int sleep_us = 100;
+    const int sleep_us = 5 * 1000;  // 5ms
     int64_t startTime = android::uptimeMillis();
+    int retry = 40;
 
     while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
         SLOGV("killed %d processes for processgroup %d\n", processes, initialPid);
-        if (sleep_us < 128000) {
+        if (retry > 0) {
             usleep(sleep_us);
-            sleep_us *= 2;
+            --retry;
         } else {
             SLOGE("failed to kill %d processes for processgroup %d\n",
                     processes, initialPid);
diff --git a/libsuspend/autosuspend_autosleep.c b/libsuspend/autosuspend_autosleep.c
index 0d31e74..7262cc7 100644
--- a/libsuspend/autosuspend_autosleep.c
+++ b/libsuspend/autosuspend_autosleep.c
@@ -40,7 +40,7 @@
 
     ALOGV("autosuspend_autosleep_enable\n");
 
-    ret = write(autosleep_fd, sleep_state, strlen(sleep_state));
+    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);
@@ -62,7 +62,7 @@
 
     ALOGV("autosuspend_autosleep_disable\n");
 
-    ret = write(autosleep_fd, on_state, strlen(on_state));
+    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);
@@ -86,7 +86,7 @@
 {
     char buf[80];
 
-    autosleep_fd = open(SYS_POWER_AUTOSLEEP, O_WRONLY);
+    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);
diff --git a/libsuspend/autosuspend_earlysuspend.c b/libsuspend/autosuspend_earlysuspend.c
index 2bece4c..3793a69 100644
--- a/libsuspend/autosuspend_earlysuspend.c
+++ b/libsuspend/autosuspend_earlysuspend.c
@@ -49,11 +49,9 @@
 {
     int err = 0;
     char buf;
-    int fd = open(EARLYSUSPEND_WAIT_FOR_FB_WAKE, O_RDONLY, 0);
+    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
-    do {
-        err = read(fd, &buf, 1);
-    } while (err < 0 && errno == EINTR);
+    err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
     ALOGE_IF(err < 0,
             "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
     close(fd);
@@ -64,11 +62,9 @@
 {
     int err = 0;
     char buf;
-    int fd = open(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, O_RDONLY, 0);
+    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
-    do {
-        err = read(fd, &buf, 1);
-    } while (err < 0 && errno == EINTR);
+    err = TEMP_FAILURE_RETRY(read(fd, &buf, 1));
     ALOGE_IF(err < 0,
             "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
     close(fd);
@@ -134,7 +130,7 @@
 
     ALOGV("autosuspend_earlysuspend_disable\n");
 
-    ret = write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on));
+    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);
@@ -195,7 +191,7 @@
     char buf[80];
     int ret;
 
-    sPowerStatefd = open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR);
+    sPowerStatefd = TEMP_FAILURE_RETRY(open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR));
 
     if (sPowerStatefd < 0) {
         strerror_r(errno, buf, sizeof(buf));
@@ -203,7 +199,7 @@
         return NULL;
     }
 
-    ret = write(sPowerStatefd, "on", 2);
+    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);
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
index 7483a8f..23a0290 100644
--- a/libsuspend/autosuspend_wakeup_count.c
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -19,6 +19,7 @@
 #include <pthread.h>
 #include <semaphore.h>
 #include <stddef.h>
+#include <stdbool.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -38,7 +39,7 @@
 static pthread_t suspend_thread;
 static sem_t suspend_lockout;
 static const char *sleep_state = "mem";
-static void (*wakeup_func)(void) = NULL;
+static void (*wakeup_func)(bool success) = NULL;
 
 static void *suspend_thread_func(void *arg __attribute__((unused)))
 {
@@ -46,12 +47,14 @@
     char wakeup_count[20];
     int wakeup_count_len;
     int ret;
+    bool success;
 
     while (1) {
         usleep(100000);
         ALOGV("%s: read wakeup_count\n", __func__);
         lseek(wakeup_count_fd, 0, SEEK_SET);
-        wakeup_count_len = read(wakeup_count_fd, wakeup_count, sizeof(wakeup_count));
+        wakeup_count_len = TEMP_FAILURE_RETRY(read(wakeup_count_fd, wakeup_count,
+                sizeof(wakeup_count)));
         if (wakeup_count_len < 0) {
             strerror_r(errno, buf, sizeof(buf));
             ALOGE("Error reading from %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
@@ -71,22 +74,21 @@
             continue;
         }
 
+        success = true;
         ALOGV("%s: write %*s to wakeup_count\n", __func__, wakeup_count_len, wakeup_count);
-        ret = write(wakeup_count_fd, wakeup_count, wakeup_count_len);
+        ret = TEMP_FAILURE_RETRY(write(wakeup_count_fd, wakeup_count, wakeup_count_len));
         if (ret < 0) {
             strerror_r(errno, buf, sizeof(buf));
             ALOGE("Error writing to %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
         } else {
             ALOGV("%s: write %s to %s\n", __func__, sleep_state, SYS_POWER_STATE);
-            ret = write(state_fd, sleep_state, strlen(sleep_state));
+            ret = TEMP_FAILURE_RETRY(write(state_fd, sleep_state, strlen(sleep_state)));
             if (ret < 0) {
-                strerror_r(errno, buf, sizeof(buf));
-                ALOGE("Error writing to %s: %s\n", SYS_POWER_STATE, buf);
-            } else {
-                void (*func)(void) = wakeup_func;
-                if (func != NULL) {
-                    (*func)();
-                }
+                success = false;
+            }
+            void (*func)(bool success) = wakeup_func;
+            if (func != NULL) {
+                (*func)(success);
             }
         }
 
@@ -138,7 +140,7 @@
     return ret;
 }
 
-void set_wakeup_callback(void (*func)(void))
+void set_wakeup_callback(void (*func)(bool success))
 {
     if (wakeup_func != NULL) {
         ALOGE("Duplicate wakeup callback applied, keeping original");
@@ -157,14 +159,14 @@
     int ret;
     char buf[80];
 
-    state_fd = open(SYS_POWER_STATE, O_RDWR);
+    state_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_STATE, O_RDWR));
     if (state_fd < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error opening %s: %s\n", SYS_POWER_STATE, buf);
         goto err_open_state;
     }
 
-    wakeup_count_fd = open(SYS_POWER_WAKEUP_COUNT, O_RDWR);
+    wakeup_count_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_WAKEUP_COUNT, O_RDWR));
     if (wakeup_count_fd < 0) {
         strerror_r(errno, buf, sizeof(buf));
         ALOGE("Error opening %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf);
diff --git a/libsuspend/include/suspend/autosuspend.h b/libsuspend/include/suspend/autosuspend.h
index 10e3d27..59188a8 100644
--- a/libsuspend/include/suspend/autosuspend.h
+++ b/libsuspend/include/suspend/autosuspend.h
@@ -18,6 +18,7 @@
 #define _LIBSUSPEND_AUTOSUSPEND_H_
 
 #include <sys/cdefs.h>
+#include <stdbool.h>
 
 __BEGIN_DECLS
 
@@ -46,9 +47,11 @@
 /*
  * set_wakeup_callback
  *
- * Set a function to be called each time the device wakes up from suspend.
+ * Set a function to be called each time the device returns from suspend.
+ * success is true if the suspend was sucessful and false if the suspend
+ * aborted due to some reason.
  */
-void set_wakeup_callback(void (*func)(void));
+void set_wakeup_callback(void (*func)(bool success));
 
 __END_DECLS
 
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 909df86..23dcd62 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -47,20 +47,8 @@
 #include <netlink/handlers.h>
 #include <netlink/msg.h>
 
-const int NetlinkEvent::NlActionUnknown = 0;
-const int NetlinkEvent::NlActionAdd = 1;
-const int NetlinkEvent::NlActionRemove = 2;
-const int NetlinkEvent::NlActionChange = 3;
-const int NetlinkEvent::NlActionLinkUp = 4;
-const int NetlinkEvent::NlActionLinkDown = 5;
-const int NetlinkEvent::NlActionAddressUpdated = 6;
-const int NetlinkEvent::NlActionAddressRemoved = 7;
-const int NetlinkEvent::NlActionRdnss = 8;
-const int NetlinkEvent::NlActionRouteUpdated = 9;
-const int NetlinkEvent::NlActionRouteRemoved = 10;
-
 NetlinkEvent::NetlinkEvent() {
-    mAction = NlActionUnknown;
+    mAction = Action::kUnknown;
     memset(mParams, 0, sizeof(mParams));
     mPath = NULL;
     mSubsystem = NULL;
@@ -154,8 +142,8 @@
         switch(rta->rta_type) {
             case IFLA_IFNAME:
                 asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta));
-                mAction = (ifi->ifi_flags & IFF_LOWER_UP) ?  NlActionLinkUp :
-                                                             NlActionLinkDown;
+                mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? Action::kLinkUp :
+                                                            Action::kLinkDown;
                 mSubsystem = strdup("net");
                 return true;
         }
@@ -244,8 +232,8 @@
     }
 
     // Fill in netlink event information.
-    mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
-                                      NlActionAddressRemoved;
+    mAction = (type == RTM_NEWADDR) ? Action::kAddressUpdated :
+                                      Action::kAddressRemoved;
     mSubsystem = strdup("net");
     asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
              ifaddr->ifa_prefixlen);
@@ -276,7 +264,7 @@
     asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
     asprintf(&mParams[1], "INTERFACE=%s", devname);
     mSubsystem = strdup("qlog");
-    mAction = NlActionChange;
+    mAction = Action::kChange;
     return true;
 }
 
@@ -311,7 +299,7 @@
     asprintf(&mParams[0], "UID=%d", uid);
     mParams[1] = hex;
     mSubsystem = strdup("strict");
-    mAction = NlActionChange;
+    mAction = Action::kChange;
     return true;
 }
 
@@ -397,8 +385,8 @@
         return false;
 
     // Fill in netlink event information.
-    mAction = (type == RTM_NEWROUTE) ? NlActionRouteUpdated :
-                                       NlActionRouteRemoved;
+    mAction = (type == RTM_NEWROUTE) ? Action::kRouteUpdated :
+                                       Action::kRouteRemoved;
     mSubsystem = strdup("net");
     asprintf(&mParams[0], "ROUTE=%s/%d", dst, prefixLength);
     asprintf(&mParams[1], "GATEWAY=%s", (*gw) ? gw : "");
@@ -467,25 +455,27 @@
             SLOGE("Invalid optlen %d for RDNSS option\n", optlen);
             return false;
         }
-        int numaddrs = (optlen - 1) / 2;
+        const int numaddrs = (optlen - 1) / 2;
 
         // Find the lifetime.
         struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr;
-        uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
+        const uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
 
         // Construct "SERVERS=<comma-separated string of DNS addresses>".
-        // Reserve (INET6_ADDRSTRLEN + 1) chars for each address: all but the
-        // the last address are followed by ','; the last is followed by '\0'.
         static const char kServerTag[] = "SERVERS=";
-        static const int kTagLength = sizeof(kServerTag) - 1;
-        int bufsize = kTagLength + numaddrs * (INET6_ADDRSTRLEN + 1);
+        static const size_t kTagLength = strlen(kServerTag);
+        // Reserve sufficient space for an IPv6 link-local address: all but the
+        // last address are followed by ','; the last is followed by '\0'.
+        static const size_t kMaxSingleAddressLength =
+                INET6_ADDRSTRLEN + strlen("%") + IFNAMSIZ + strlen(",");
+        const size_t bufsize = kTagLength + numaddrs * kMaxSingleAddressLength;
         char *buf = (char *) malloc(bufsize);
         if (!buf) {
             SLOGE("RDNSS option: out of memory\n");
             return false;
         }
         strcpy(buf, kServerTag);
-        int pos = kTagLength;
+        size_t pos = kTagLength;
 
         struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1);
         for (int i = 0; i < numaddrs; i++) {
@@ -494,10 +484,14 @@
             }
             inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos);
             pos += strlen(buf + pos);
+            if (IN6_IS_ADDR_LINKLOCAL(addrs + i)) {
+                buf[pos++] = '%';
+                pos += strlcpy(buf + pos, ifname, bufsize - pos);
+            }
         }
         buf[pos] = '\0';
 
-        mAction = NlActionRdnss;
+        mAction = Action::kRdnss;
         mSubsystem = strdup("net");
         asprintf(&mParams[0], "INTERFACE=%s", ifname);
         asprintf(&mParams[1], "LIFETIME=%u", lifetime);
@@ -617,11 +611,11 @@
             const char* a;
             if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
                 if (!strcmp(a, "add"))
-                    mAction = NlActionAdd;
+                    mAction = Action::kAdd;
                 else if (!strcmp(a, "remove"))
-                    mAction = NlActionRemove;
+                    mAction = Action::kRemove;
                 else if (!strcmp(a, "change"))
-                    mAction = NlActionChange;
+                    mAction = Action::kChange;
             } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
                 mSeq = atoi(a);
             } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 527a6a0..3011ed7 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -86,6 +86,7 @@
             return -1;
         }
         SLOGV("got mSock = %d for %s", mSock, mSocketName);
+        fcntl(mSock, F_SETFD, FD_CLOEXEC);
     }
 
     if (mListen && listen(mSock, backlog) < 0) {
@@ -212,6 +213,7 @@
                 sleep(1);
                 continue;
             }
+            fcntl(c, F_SETFD, FD_CLOEXEC);
             pthread_mutex_lock(&mClientsLock);
             mClients->push_back(new SocketClient(c, true, mUseCmdNum));
             pthread_mutex_unlock(&mClientsLock);
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 684f401..b8e3215 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -56,6 +56,9 @@
 #define USB_FS_ID_SCANNER   USB_FS_DIR "/%d/%d"
 #define USB_FS_ID_FORMAT    USB_FS_DIR "/%03d/%03d"
 
+// Some devices fail to send string descriptors if we attempt reading > 255 bytes
+#define MAX_STRING_DESCRIPTOR_LENGTH    255
+
 // From drivers/usb/core/devio.c
 // I don't know why this isn't in a kernel header
 #define MAX_USBFS_BUFFER_SIZE   16384
@@ -449,8 +452,8 @@
 char* usb_device_get_string(struct usb_device *device, int id)
 {
     char string[256];
-    __u16 buffer[128];
-    __u16 languages[128];
+    __u16 buffer[MAX_STRING_DESCRIPTOR_LENGTH / sizeof(__u16)];
+    __u16 languages[MAX_STRING_DESCRIPTOR_LENGTH / sizeof(__u16)];
     int i, result;
     int languageCount = 0;
 
@@ -498,6 +501,12 @@
     return usb_device_get_string(device, desc->iProduct);
 }
 
+int usb_device_get_version(struct usb_device *device)
+{
+    struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
+    return desc->bcdUSB;
+}
+
 char* usb_device_get_serial(struct usb_device *device)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 8f829f3..677d1e7 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -16,11 +16,9 @@
 
 commonSources:= \
 	BasicHashtable.cpp \
-	BlobCache.cpp \
 	CallStack.cpp \
 	FileMap.cpp \
 	JenkinsHash.cpp \
-	LinearAllocator.cpp \
 	LinearTransform.cpp \
 	Log.cpp \
 	NativeHandle.cpp \
@@ -75,6 +73,7 @@
 # we have the common sources, plus some device-specific stuff
 LOCAL_SRC_FILES:= \
 	$(commonSources) \
+	BlobCache.cpp \
 	Looper.cpp \
 	Trace.cpp
 
@@ -84,7 +83,8 @@
 LOCAL_CFLAGS += -Werror
 
 LOCAL_STATIC_LIBRARIES := \
-	libcutils
+	libcutils \
+	libc
 
 LOCAL_SHARED_LIBRARIES := \
         libbacktrace \
diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp
index 0ea09cf..126995b 100644
--- a/libutils/BlobCache.cpp
+++ b/libutils/BlobCache.cpp
@@ -25,13 +25,15 @@
 #include <utils/Errors.h>
 #include <utils/Log.h>
 
+#include <cutils/properties.h>
+
 namespace android {
 
 // BlobCache::Header::mMagicNumber value
 static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$';
 
 // BlobCache::Header::mBlobCacheVersion value
-static const uint32_t blobCacheVersion = 2;
+static const uint32_t blobCacheVersion = 3;
 
 // BlobCache::Header::mDeviceVersion value
 static const uint32_t blobCacheDeviceVersion = 1;
@@ -165,7 +167,7 @@
 }
 
 size_t BlobCache::getFlattenedSize() const {
-    size_t size = align4(sizeof(Header));
+    size_t size = align4(sizeof(Header) + PROPERTY_VALUE_MAX);
     for (size_t i = 0; i < mCacheEntries.size(); i++) {
         const CacheEntry& e(mCacheEntries[i]);
         sp<Blob> keyBlob = e.getKey();
@@ -187,10 +189,13 @@
     header->mBlobCacheVersion = blobCacheVersion;
     header->mDeviceVersion = blobCacheDeviceVersion;
     header->mNumEntries = mCacheEntries.size();
+    char buildId[PROPERTY_VALUE_MAX];
+    header->mBuildIdLength = property_get("ro.build.id", buildId, "");
+    memcpy(header->mBuildId, buildId, header->mBuildIdLength);
 
     // Write cache entries
     uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer);
-    off_t byteOffset = align4(sizeof(Header));
+    off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength);
     for (size_t i = 0; i < mCacheEntries.size(); i++) {
         const CacheEntry& e(mCacheEntries[i]);
         sp<Blob> keyBlob = e.getKey();
@@ -239,15 +244,19 @@
         ALOGE("unflatten: bad magic number: %" PRIu32, header->mMagicNumber);
         return BAD_VALUE;
     }
+    char buildId[PROPERTY_VALUE_MAX];
+    int len = property_get("ro.build.id", buildId, "");
     if (header->mBlobCacheVersion != blobCacheVersion ||
-            header->mDeviceVersion != blobCacheDeviceVersion) {
+            header->mDeviceVersion != blobCacheDeviceVersion ||
+            len != header->mBuildIdLength ||
+            strncmp(buildId, header->mBuildId, len)) {
         // We treat version mismatches as an empty cache.
         return OK;
     }
 
     // Read cache entries
     const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer);
-    off_t byteOffset = align4(sizeof(Header));
+    off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength);
     size_t numEntries = header->mNumEntries;
     for (size_t i = 0; i < numEntries; i++) {
         if (byteOffset + sizeof(EntryHeader) > size) {
diff --git a/libutils/LinearAllocator.cpp b/libutils/LinearAllocator.cpp
deleted file mode 100644
index 8b90696..0000000
--- a/libutils/LinearAllocator.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define LOG_TAG "LinearAllocator"
-#define LOG_NDEBUG 1
-
-#include <stdlib.h>
-#include <utils/LinearAllocator.h>
-#include <utils/Log.h>
-
-
-// The ideal size of a page allocation (these need to be multiples of 8)
-#define INITIAL_PAGE_SIZE ((size_t)4096) // 4kb
-#define MAX_PAGE_SIZE ((size_t)131072) // 128kb
-
-// The maximum amount of wasted space we can have per page
-// Allocations exceeding this will have their own dedicated page
-// If this is too low, we will malloc too much
-// Too high, and we may waste too much space
-// Must be smaller than INITIAL_PAGE_SIZE
-#define MAX_WASTE_SIZE ((size_t)1024)
-
-#if ALIGN_DOUBLE
-#define ALIGN_SZ (sizeof(double))
-#else
-#define ALIGN_SZ (sizeof(int))
-#endif
-
-#define ALIGN(x) ((x + ALIGN_SZ - 1 ) & ~(ALIGN_SZ - 1))
-#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)p)))
-
-#if LOG_NDEBUG
-#define ADD_ALLOCATION(size)
-#define RM_ALLOCATION(size)
-#else
-#include <utils/Thread.h>
-#include <utils/Timers.h>
-static size_t s_totalAllocations = 0;
-static nsecs_t s_nextLog = 0;
-static android::Mutex s_mutex;
-
-static void _logUsageLocked() {
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    if (now > s_nextLog) {
-        s_nextLog = now + milliseconds_to_nanoseconds(10);
-        ALOGV("Total memory usage: %zu kb", s_totalAllocations / 1024);
-    }
-}
-
-static void _addAllocation(size_t size) {
-    android::AutoMutex lock(s_mutex);
-    s_totalAllocations += size;
-    _logUsageLocked();
-}
-
-#define ADD_ALLOCATION(size) _addAllocation(size);
-#define RM_ALLOCATION(size) _addAllocation(-size);
-#endif
-
-#define min(x,y) (((x) < (y)) ? (x) : (y))
-
-namespace android {
-
-class LinearAllocator::Page {
-public:
-    Page* next() { return mNextPage; }
-    void setNext(Page* next) { mNextPage = next; }
-
-    Page()
-        : mNextPage(0)
-    {}
-
-    void* operator new(size_t /*size*/, void* buf) { return buf; }
-
-    void* start() {
-        return (void*) (((size_t)this) + sizeof(Page));
-    }
-
-    void* end(int pageSize) {
-        return (void*) (((size_t)start()) + pageSize);
-    }
-
-private:
-    Page(const Page& /*other*/) {}
-    Page* mNextPage;
-};
-
-LinearAllocator::LinearAllocator()
-    : mPageSize(INITIAL_PAGE_SIZE)
-    , mMaxAllocSize(MAX_WASTE_SIZE)
-    , mNext(0)
-    , mCurrentPage(0)
-    , mPages(0)
-    , mTotalAllocated(0)
-    , mWastedSpace(0)
-    , mPageCount(0)
-    , mDedicatedPageCount(0) {}
-
-LinearAllocator::~LinearAllocator(void) {
-    Page* p = mPages;
-    while (p) {
-        Page* next = p->next();
-        p->~Page();
-        free(p);
-        RM_ALLOCATION(mPageSize);
-        p = next;
-    }
-}
-
-void* LinearAllocator::start(Page* p) {
-    return ALIGN_PTR(((size_t*)p) + sizeof(Page));
-}
-
-void* LinearAllocator::end(Page* p) {
-    return ((char*)p) + mPageSize;
-}
-
-bool LinearAllocator::fitsInCurrentPage(size_t size) {
-    return mNext && ((char*)mNext + size) <= end(mCurrentPage);
-}
-
-void LinearAllocator::ensureNext(size_t size) {
-    if (fitsInCurrentPage(size)) return;
-
-    if (mCurrentPage && mPageSize < MAX_PAGE_SIZE) {
-        mPageSize = min(MAX_PAGE_SIZE, mPageSize * 2);
-        mPageSize = ALIGN(mPageSize);
-    }
-    mWastedSpace += mPageSize;
-    Page* p = newPage(mPageSize);
-    if (mCurrentPage) {
-        mCurrentPage->setNext(p);
-    }
-    mCurrentPage = p;
-    if (!mPages) {
-        mPages = mCurrentPage;
-    }
-    mNext = start(mCurrentPage);
-}
-
-void* LinearAllocator::alloc(size_t size) {
-    size = ALIGN(size);
-    if (size > mMaxAllocSize && !fitsInCurrentPage(size)) {
-        ALOGV("Exceeded max size %zu > %zu", size, mMaxAllocSize);
-        // Allocation is too large, create a dedicated page for the allocation
-        Page* page = newPage(size);
-        mDedicatedPageCount++;
-        page->setNext(mPages);
-        mPages = page;
-        if (!mCurrentPage)
-            mCurrentPage = mPages;
-        return start(page);
-    }
-    ensureNext(size);
-    void* ptr = mNext;
-    mNext = ((char*)mNext) + size;
-    mWastedSpace -= size;
-    return ptr;
-}
-
-void LinearAllocator::rewindIfLastAlloc(void* ptr, size_t allocSize) {
-    // Don't bother rewinding across pages
-    allocSize = ALIGN(allocSize);
-    if (ptr >= start(mCurrentPage) && ptr < end(mCurrentPage)
-            && ptr == ((char*)mNext - allocSize)) {
-        mTotalAllocated -= allocSize;
-        mWastedSpace += allocSize;
-        mNext = ptr;
-    }
-}
-
-LinearAllocator::Page* LinearAllocator::newPage(size_t pageSize) {
-    pageSize = ALIGN(pageSize + sizeof(LinearAllocator::Page));
-    ADD_ALLOCATION(pageSize);
-    mTotalAllocated += pageSize;
-    mPageCount++;
-    void* buf = malloc(pageSize);
-    return new (buf) Page();
-}
-
-static const char* toSize(size_t value, float& result) {
-    if (value < 2000) {
-        result = value;
-        return "B";
-    }
-    if (value < 2000000) {
-        result = value / 1024.0f;
-        return "KB";
-    }
-    result = value / 1048576.0f;
-    return "MB";
-}
-
-void LinearAllocator::dumpMemoryStats(const char* prefix) {
-    float prettySize;
-    const char* prettySuffix;
-    prettySuffix = toSize(mTotalAllocated, prettySize);
-    ALOGD("%sTotal allocated: %.2f%s", prefix, prettySize, prettySuffix);
-    prettySuffix = toSize(mWastedSpace, prettySize);
-    ALOGD("%sWasted space: %.2f%s (%.1f%%)", prefix, prettySize, prettySuffix,
-          (float) mWastedSpace / (float) mTotalAllocated * 100.0f);
-    ALOGD("%sPages %zu (dedicated %zu)", prefix, mPageCount, mDedicatedPageCount);
-}
-
-}; // namespace android
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 20c1e92..b14884b 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -20,7 +20,9 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <inttypes.h>
 #include <string.h>
+#include <sys/eventfd.h>
 #include <unistd.h>
 
 
@@ -70,41 +72,21 @@
 
 Looper::Looper(bool allowNonCallbacks) :
         mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
-        mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
-    int wakeFds[2];
-    int result = pipe(wakeFds);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe: %s", strerror(errno));
+        mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
+        mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
+    mWakeEventFd = eventfd(0, EFD_NONBLOCK);
+    LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",
+                        strerror(errno));
 
-    mWakeReadPipeFd = wakeFds[0];
-    mWakeWritePipeFd = wakeFds[1];
-
-    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking: %s",
-            strerror(errno));
-
-    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking: %s",
-            strerror(errno));
-
-    mIdling = false;
-
-    // Allocate the epoll instance and register the wake pipe.
-    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
-    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
-
-    struct epoll_event eventItem;
-    memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
-    eventItem.events = EPOLLIN;
-    eventItem.data.fd = mWakeReadPipeFd;
-    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
-    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance: %s",
-            strerror(errno));
+    AutoMutex _l(mLock);
+    rebuildEpollLocked();
 }
 
 Looper::~Looper() {
-    close(mWakeReadPipeFd);
-    close(mWakeWritePipeFd);
-    close(mEpollFd);
+    close(mWakeEventFd);
+    if (mEpollFd >= 0) {
+        close(mEpollFd);
+    }
 }
 
 void Looper::initTLSKey() {
@@ -158,6 +140,50 @@
     return mAllowNonCallbacks;
 }
 
+void Looper::rebuildEpollLocked() {
+    // Close old epoll instance if we have one.
+    if (mEpollFd >= 0) {
+#if DEBUG_CALLBACKS
+        ALOGD("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
+#endif
+        close(mEpollFd);
+    }
+
+    // Allocate the new epoll instance and register the wake pipe.
+    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
+
+    struct epoll_event eventItem;
+    memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
+    eventItem.events = EPOLLIN;
+    eventItem.data.fd = mWakeEventFd;
+    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
+    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake event fd to epoll instance: %s",
+                        strerror(errno));
+
+    for (size_t i = 0; i < mRequests.size(); i++) {
+        const Request& request = mRequests.valueAt(i);
+        struct epoll_event eventItem;
+        request.initEventItem(&eventItem);
+
+        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
+        if (epollResult < 0) {
+            ALOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",
+                  request.fd, strerror(errno));
+        }
+    }
+}
+
+void Looper::scheduleEpollRebuildLocked() {
+    if (!mEpollRebuildRequired) {
+#if DEBUG_CALLBACKS
+        ALOGD("%p ~ scheduleEpollRebuildLocked - scheduling epoll set rebuild", this);
+#endif
+        mEpollRebuildRequired = true;
+        wake();
+    }
+}
+
 int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
     int result = 0;
     for (;;) {
@@ -208,7 +234,7 @@
             timeoutMillis = messageTimeoutMillis;
         }
 #if DEBUG_POLL_AND_WAKE
-        ALOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d",
+        ALOGD("%p ~ pollOnce - next message in %" PRId64 "ns, adjusted timeout: timeoutMillis=%d",
                 this, mNextMessageUptime - now, timeoutMillis);
 #endif
     }
@@ -219,17 +245,24 @@
     mResponseIndex = 0;
 
     // We are about to idle.
-    mIdling = true;
+    mPolling = true;
 
     struct epoll_event eventItems[EPOLL_MAX_EVENTS];
     int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
 
     // No longer idling.
-    mIdling = false;
+    mPolling = false;
 
     // Acquire lock.
     mLock.lock();
 
+    // Rebuild epoll set if needed.
+    if (mEpollRebuildRequired) {
+        mEpollRebuildRequired = false;
+        rebuildEpollLocked();
+        goto Done;
+    }
+
     // Check for poll error.
     if (eventCount < 0) {
         if (errno == EINTR) {
@@ -257,11 +290,11 @@
     for (int i = 0; i < eventCount; i++) {
         int fd = eventItems[i].data.fd;
         uint32_t epollEvents = eventItems[i].events;
-        if (fd == mWakeReadPipeFd) {
+        if (fd == mWakeEventFd) {
             if (epollEvents & EPOLLIN) {
                 awoken();
             } else {
-                ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
+                ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
             }
         } else {
             ssize_t requestIndex = mRequests.indexOfKey(fd);
@@ -328,10 +361,14 @@
             ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
                     this, response.request.callback.get(), fd, events, data);
 #endif
+            // Invoke the callback.  Note that the file descriptor may be closed by
+            // the callback (and potentially even reused) before the function returns so
+            // we need to be a little careful when removing the file descriptor afterwards.
             int callbackResult = response.request.callback->handleEvent(fd, events, data);
             if (callbackResult == 0) {
-                removeFd(fd);
+                removeFd(fd, response.request.seq);
             }
+
             // Clear the callback reference in the response structure promptly because we
             // will not clear the response vector itself until the next poll.
             response.request.callback.clear();
@@ -372,12 +409,9 @@
     ALOGD("%p ~ wake", this);
 #endif
 
-    ssize_t nWrite;
-    do {
-        nWrite = write(mWakeWritePipeFd, "W", 1);
-    } while (nWrite == -1 && errno == EINTR);
-
-    if (nWrite != 1) {
+    uint64_t inc = 1;
+    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));
         }
@@ -389,11 +423,8 @@
     ALOGD("%p ~ awoken", this);
 #endif
 
-    char buffer[16];
-    ssize_t nRead;
-    do {
-        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
-    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
+    uint64_t counter;
+    TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
 }
 
 void Looper::pushResponse(int events, const Request& request) {
@@ -427,23 +458,20 @@
         ident = POLL_CALLBACK;
     }
 
-    int epollEvents = 0;
-    if (events & EVENT_INPUT) epollEvents |= EPOLLIN;
-    if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT;
-
     { // acquire lock
         AutoMutex _l(mLock);
 
         Request request;
         request.fd = fd;
         request.ident = ident;
+        request.events = events;
+        request.seq = mNextRequestSeq++;
         request.callback = callback;
         request.data = data;
+        if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1
 
         struct epoll_event eventItem;
-        memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
-        eventItem.events = epollEvents;
-        eventItem.data.fd = fd;
+        request.initEventItem(&eventItem);
 
         ssize_t requestIndex = mRequests.indexOfKey(fd);
         if (requestIndex < 0) {
@@ -456,8 +484,36 @@
         } else {
             int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
             if (epollResult < 0) {
-                ALOGE("Error modifying epoll events for fd %d: %s", fd, strerror(errno));
-                return -1;
+                if (errno == ENOENT) {
+                    // Tolerate ENOENT because it means that an older file descriptor was
+                    // closed before its callback was unregistered and meanwhile a new
+                    // file descriptor with the same number has been created and is now
+                    // being registered for the first time.  This error may occur naturally
+                    // when a callback has the side-effect of closing the file descriptor
+                    // before returning and unregistering itself.  Callback sequence number
+                    // checks further ensure that the race is benign.
+                    //
+                    // Unfortunately due to kernel limitations we need to rebuild the epoll
+                    // set from scratch because it may contain an old file handle that we are
+                    // now unable to remove since its file descriptor is no longer valid.
+                    // No such problem would have occurred if we were using the poll system
+                    // call instead, but that approach carries others disadvantages.
+#if DEBUG_CALLBACKS
+                    ALOGD("%p ~ addFd - EPOLL_CTL_MOD failed due to file descriptor "
+                            "being recycled, falling back on EPOLL_CTL_ADD: %s",
+                            this, strerror(errno));
+#endif
+                    epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
+                    if (epollResult < 0) {
+                        ALOGE("Error modifying or adding epoll events for fd %d: %s",
+                                fd, strerror(errno));
+                        return -1;
+                    }
+                    scheduleEpollRebuildLocked();
+                } else {
+                    ALOGE("Error modifying epoll events for fd %d: %s", fd, strerror(errno));
+                    return -1;
+                }
             }
             mRequests.replaceValueAt(requestIndex, request);
         }
@@ -466,8 +522,12 @@
 }
 
 int Looper::removeFd(int fd) {
+    return removeFd(fd, -1);
+}
+
+int Looper::removeFd(int fd, int seq) {
 #if DEBUG_CALLBACKS
-    ALOGD("%p ~ removeFd - fd=%d", this, fd);
+    ALOGD("%p ~ removeFd - fd=%d, seq=%d", this, fd, seq);
 #endif
 
     { // acquire lock
@@ -477,13 +537,48 @@
             return 0;
         }
 
-        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
-        if (epollResult < 0) {
-            ALOGE("Error removing epoll events for fd %d: %s", fd, strerror(errno));
-            return -1;
+        // Check the sequence number if one was given.
+        if (seq != -1 && mRequests.valueAt(requestIndex).seq != seq) {
+#if DEBUG_CALLBACKS
+            ALOGD("%p ~ removeFd - sequence number mismatch, oldSeq=%d",
+                    this, mRequests.valueAt(requestIndex).seq);
+#endif
+            return 0;
         }
 
+        // Always remove the FD from the request map even if an error occurs while
+        // updating the epoll set so that we avoid accidentally leaking callbacks.
         mRequests.removeItemsAt(requestIndex);
+
+        int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
+        if (epollResult < 0) {
+            if (seq != -1 && (errno == EBADF || errno == ENOENT)) {
+                // Tolerate EBADF or ENOENT when the sequence number is known because it
+                // means that the file descriptor was closed before its callback was
+                // unregistered.  This error may occur naturally when a callback has the
+                // side-effect of closing the file descriptor before returning and
+                // unregistering itself.
+                //
+                // Unfortunately due to kernel limitations we need to rebuild the epoll
+                // set from scratch because it may contain an old file handle that we are
+                // now unable to remove since its file descriptor is no longer valid.
+                // No such problem would have occurred if we were using the poll system
+                // call instead, but that approach carries others disadvantages.
+#if DEBUG_CALLBACKS
+                ALOGD("%p ~ removeFd - EPOLL_CTL_DEL failed due to file descriptor "
+                        "being closed: %s", this, strerror(errno));
+#endif
+                scheduleEpollRebuildLocked();
+            } else {
+                // Some other error occurred.  This is really weird because it means
+                // our list of callbacks got out of sync with the epoll set somehow.
+                // We defensively rebuild the epoll set to avoid getting spurious
+                // notifications with nowhere to go.
+                ALOGE("Error removing epoll events for fd %d: %s", fd, strerror(errno));
+                scheduleEpollRebuildLocked();
+                return -1;
+            }
+        }
     } // release lock
     return 1;
 }
@@ -502,7 +597,7 @@
 void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
         const Message& message) {
 #if DEBUG_CALLBACKS
-    ALOGD("%p ~ sendMessageAtTime - uptime=%lld, handler=%p, what=%d",
+    ALOGD("%p ~ sendMessageAtTime - uptime=%" PRId64 ", handler=%p, what=%d",
             this, uptime, handler.get(), message.what);
 #endif
 
@@ -568,8 +663,18 @@
     } // release lock
 }
 
-bool Looper::isIdling() const {
-    return mIdling;
+bool Looper::isPolling() const {
+    return mPolling;
+}
+
+void Looper::Request::initEventItem(struct epoll_event* eventItem) const {
+    int epollEvents = 0;
+    if (events & EVENT_INPUT) epollEvents |= EPOLLIN;
+    if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT;
+
+    memset(eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
+    eventItem->events = epollEvents;
+    eventItem->data.fd = fd;
 }
 
 } // namespace android
diff --git a/logd/main.cpp b/logd/main.cpp
index 9b88983..a3241d0 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -103,6 +103,10 @@
         return -1;
     }
 
+    if (setgroups(0, NULL) == -1) {
+        return -1;
+    }
+
     if (setgid(AID_LOGD) != 0) {
         return -1;
     }
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 777dafe..44455d1 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -325,7 +325,7 @@
 
     if (log_target & LOG_KLOG) {
         snprintf(log_info.klog_fmt, sizeof(log_info.klog_fmt),
-                 "<6>%.*s: %%s", MAX_KLOG_TAG, log_info.btag);
+                 "<6>%.*s: %%s\n", MAX_KLOG_TAG, log_info.btag);
     }
 
     if ((log_target & LOG_FILE) && !file_path) {
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index e8b46eb..32817fa 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -5,8 +5,8 @@
     export ANDROID_ASSETS /system/app
     export ANDROID_DATA /data
     export ANDROID_STORAGE /storage
+    export EXTERNAL_STORAGE /sdcard
     export ASEC_MOUNTPOINT /mnt/asec
-    export LOOP_MOUNTPOINT /mnt/obb
     export BOOTCLASSPATH %BOOTCLASSPATH%
     export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
     %EXPORT_GLOBAL_ASAN_OPTIONS%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 12999bd..b48c72b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -49,28 +49,33 @@
     chown root system /sys/fs/cgroup/memory/sw/tasks
     chmod 0660 /sys/fs/cgroup/memory/sw/tasks
 
+    # Mount staging areas for devices managed by vold
     # See storage config details at http://source.android.com/tech/storage/
-    mkdir /mnt/shell 0700 shell shell
-    mkdir /mnt/media_rw 0700 media_rw media_rw
-    mkdir /storage 0751 root sdcard_r
+    mount tmpfs tmpfs /mnt mode=0755,uid=0,gid=1000
+    restorecon_recursive /mnt
 
-    # Directory for putting things only root should see.
     mkdir /mnt/secure 0700 root root
+    mkdir /mnt/secure/asec 0700 root root
+    mkdir /mnt/asec 0755 root system
+    mkdir /mnt/obb 0755 root system
+    mkdir /mnt/media_rw 0750 root media_rw
+    mkdir /mnt/user 0755 root root
+    mkdir /mnt/user/0 0755 root root
+    mkdir /mnt/expand 0771 system system
 
-    # Directory for staging bindmounts
-    mkdir /mnt/secure/staging 0700 root root
+    # Storage views to support runtime permissions
+    mkdir /storage 0755 root root
+    mkdir /mnt/runtime 0700 root root
+    mkdir /mnt/runtime/default 0755 root root
+    mkdir /mnt/runtime/default/self 0755 root root
+    mkdir /mnt/runtime/read 0755 root root
+    mkdir /mnt/runtime/read/self 0755 root root
+    mkdir /mnt/runtime/write 0755 root root
+    mkdir /mnt/runtime/write/self 0755 root root
 
-    # Directory-target for where the secure container
-    # imagefile directory will be bind-mounted
-    mkdir /mnt/secure/asec  0700 root root
-
-    # Secure container public mount points.
-    mkdir /mnt/asec  0700 root system
-    mount tmpfs tmpfs /mnt/asec mode=0755,gid=1000
-
-    # Filesystem image public mount points.
-    mkdir /mnt/obb 0700 root system
-    mount tmpfs tmpfs /mnt/obb mode=0755,gid=1000
+    # Symlink to keep legacy apps working in multi-user world
+    symlink /storage/self/primary /sdcard
+    symlink /mnt/user/0/primary /mnt/runtime/default/self/primary
 
     # memory control cgroup
     mkdir /dev/memcg 0700 root system
@@ -98,6 +103,10 @@
     # set fwmark on accepted sockets
     write /proc/sys/net/ipv4/tcp_fwmark_accept 1
 
+    # disable icmp redirects
+    write /proc/sys/net/ipv4/conf/all/accept_redirects 0
+    write /proc/sys/net/ipv6/conf/all/accept_redirects 0
+
     # Create cgroup mount points for process groups
     mkdir /dev/cpuctl
     mount cgroup none /dev/cpuctl cpu
@@ -116,6 +125,28 @@
     write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 700000
     write /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000
 
+    # sets up initial cpusets for ActivityManager
+    mkdir /dev/cpuset
+    mount cpuset none /dev/cpuset
+    mkdir /dev/cpuset/foreground
+    mkdir /dev/cpuset/background
+    # this ensures that the cpusets are present and usable, but the device's
+    # init.rc must actually set the correct cpus
+    write /dev/cpuset/foreground/cpus 0
+    write /dev/cpuset/background/cpus 0
+    write /dev/cpuset/foreground/mems 0
+    write /dev/cpuset/background/mems 0
+    chown system system /dev/cpuset
+    chown system system /dev/cpuset/foreground
+    chown system system /dev/cpuset/background
+    chown system system /dev/cpuset/tasks
+    chown system system /dev/cpuset/foreground/tasks
+    chown system system /dev/cpuset/background/tasks
+    chmod 0664 /dev/cpuset/foreground/tasks
+    chmod 0664 /dev/cpuset/background/tasks
+    chmod 0664 /dev/cpuset/tasks
+
+
     # qtaguid will limit access to specific data based on group memberships.
     #   net_bw_acct grants impersonation of socket owners.
     #   net_bw_stats grants access to other apps' detailed tagged-socket stats.
@@ -179,8 +210,10 @@
     start logd
     # once everything is setup, no need to modify /
     mount rootfs rootfs / ro remount
-    # mount shared so changes propagate into child namespaces
+    # 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
 
     # We chown/chmod /cache again so because mount is run as root + defaults
     chown system cache /cache
@@ -225,6 +258,8 @@
     start vold
     installkey /data
 
+    # Emulated internal storage area
+    mkdir /data/media 0770 media_rw media_rw
     # Start bootcharting as soon as possible after the data partition is
     # mounted to collect more data.
     mkdir /data/bootchart 0755 shell shell
@@ -236,7 +271,10 @@
     # create basic filesystem structure
     mkdir /data/misc 01771 system misc
     mkdir /data/misc/adb 02750 system shell
-    mkdir /data/misc/bluedroid 0770 bluetooth net_bt_stack
+    mkdir /data/misc/bluedroid 02770 bluetooth net_bt_stack
+    # Fix the access permissions and group ownership for 'bt_config.conf'
+    chmod 0660 /data/misc/bluedroid/bt_config.conf
+    chown bluetooth net_bt_stack /data/misc/bluedroid/bt_config.conf
     mkdir /data/misc/bluetooth 0770 system system
     mkdir /data/misc/keystore 0700 keystore keystore
     mkdir /data/misc/gatekeeper 0700 system system
@@ -340,9 +378,9 @@
     write /proc/sys/vm/overcommit_memory 1
     write /proc/sys/vm/min_free_order_shift 4
     chown root system /sys/module/lowmemorykiller/parameters/adj
-    chmod 0220 /sys/module/lowmemorykiller/parameters/adj
+    chmod 0664 /sys/module/lowmemorykiller/parameters/adj
     chown root system /sys/module/lowmemorykiller/parameters/minfree
-    chmod 0220 /sys/module/lowmemorykiller/parameters/minfree
+    chmod 0664 /sys/module/lowmemorykiller/parameters/minfree
 
     # Tweak background writeout
     write /proc/sys/vm/dirty_expire_centisecs 200
@@ -482,6 +520,7 @@
     socket logd stream 0666 logd logd
     socket logdr seqpacket 0666 logd logd
     socket logdw dgram 0222 logd logd
+    group root system
 
 service logd-reinit /system/bin/logd --reinit
     oneshot
@@ -491,6 +530,7 @@
     class core
     critical
     seclabel u:r:healthd:s0
+    group root system
 
 service console /system/bin/sh
     class core
@@ -530,9 +570,12 @@
     onrestart restart surfaceflinger
     onrestart restart drm
 
-service vold /system/bin/vold
+service vold /system/bin/vold \
+        --blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
+        --fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0
     class core
     socket vold stream 0660 root mount
+    socket cryptd stream 0660 root mount
     ioprio be 2
 
 service netd /system/bin/netd
@@ -551,6 +594,7 @@
 service ril-daemon /system/bin/rild
     class main
     socket rild stream 660 root radio
+    socket sap_uim_socket1 stream 660 bluetooth bluetooth
     socket rild-debug stream 660 radio system
     user root
     group radio cache inet misc audio log
@@ -593,6 +637,10 @@
     disabled
     oneshot
 
+service gatekeeperd /system/bin/gatekeeperd /data/misc/gatekeeper
+    class late_start
+    user system
+
 service installd /system/bin/installd
     class main
     socket installd stream 600 system system
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 9cf9ed9..b735dc3 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -95,3 +95,6 @@
 /sys/devices/virtual/usb_composite/*   enable      0664  root   system
 /sys/devices/system/cpu/cpu*   cpufreq/scaling_max_freq   0664  system system
 /sys/devices/system/cpu/cpu*   cpufreq/scaling_min_freq   0664  system system
+
+# DVB API device nodes
+/dev/dvb*                 0660   root       system
diff --git a/run-as/package.c b/run-as/package.c
index 9e1f5bb..aea89e5 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -16,6 +16,7 @@
 */
 #include <errno.h>
 #include <fcntl.h>
+#include <stdio.h>
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
@@ -421,7 +422,7 @@
  * If the package database is corrupted, return -1 and set errno to EINVAL
  */
 int
-get_package_info(const char* pkgName, PackageInfo *info)
+get_package_info(const char* pkgName, uid_t userId, PackageInfo *info)
 {
     char*        buffer;
     size_t       buffer_len;
@@ -506,7 +507,20 @@
         if (q == p)
             goto BAD_FORMAT;
 
-        p = string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
+        /* If userId == 0 (i.e. user is device owner) we can use dataDir value
+         * from packages.list, otherwise compose data directory as
+         * /data/user/$uid/$packageId
+         */
+        if (userId == 0) {
+            p = string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
+        } else {
+            snprintf(info->dataDir,
+                     sizeof info->dataDir,
+                     "/data/user/%d/%s",
+                     userId,
+                     pkgName);
+            p = q;
+        }
 
         /* skip spaces */
         if (parse_spaces(&p, end) < 0)
diff --git a/run-as/package.h b/run-as/package.h
index 34603c0..eeb5913 100644
--- a/run-as/package.h
+++ b/run-as/package.h
@@ -33,9 +33,11 @@
     char   seinfo[PATH_MAX];
 } PackageInfo;
 
-/* see documentation in package.c for these functiosn */
+/* see documentation in package.c for these functions */
 
-extern int  get_package_info(const char* packageName, PackageInfo*  info);
+extern int  get_package_info(const char* packageName,
+                             uid_t userId,
+                             PackageInfo*  info);
 
 extern int  check_data_path(const char* dataDir, uid_t uid);
 
diff --git a/run-as/run-as.c b/run-as/run-as.c
index 368b8f1..3f32e7d 100644
--- a/run-as/run-as.c
+++ b/run-as/run-as.c
@@ -102,13 +102,14 @@
 static void
 usage(void)
 {
-    panic("Usage:\n    " PROGNAME " <package-name> <command> [<args>]\n");
+    panic("Usage:\n    " PROGNAME " <package-name> [--user <uid>] <command> [<args>]\n");
 }
 
 int main(int argc, char **argv)
 {
     const char* pkgname;
-    int myuid, uid, gid;
+    uid_t myuid, uid, gid, userAppId = 0;
+    int commandArgvOfs = 2, userId = 0;
     PackageInfo info;
     struct __user_cap_header_struct capheader;
     struct __user_cap_data_struct capdata[2];
@@ -136,14 +137,31 @@
         panic("Could not set capabilities: %s\n", strerror(errno));
     }
 
-    /* retrieve package information from system (does setegid) */
     pkgname = argv[1];
-    if (get_package_info(pkgname, &info) < 0) {
+
+    /* get user_id from command line if provided */
+    if ((argc >= 4) && !strcmp(argv[2], "--user")) {
+        userId = atoi(argv[3]);
+        if (userId < 0)
+            panic("Negative user id %d is provided\n", userId);
+        commandArgvOfs += 2;
+    }
+
+    /* retrieve package information from system (does setegid) */
+    if (get_package_info(pkgname, userId, &info) < 0) {
         panic("Package '%s' is unknown\n", pkgname);
     }
 
+    /* verify that user id is not too big. */
+    if ((UID_MAX - info.uid) / AID_USER < (uid_t)userId) {
+        panic("User id %d is too big\n", userId);
+    }
+
+    /* calculate user app ID. */
+    userAppId = (AID_USER * userId) + info.uid;
+
     /* reject system packages */
-    if (info.uid < AID_APP) {
+    if (userAppId < AID_APP) {
         panic("Package '%s' is not an application\n", pkgname);
     }
 
@@ -153,14 +171,14 @@
     }
 
     /* check that the data directory path is valid */
-    if (check_data_path(info.dataDir, info.uid) < 0) {
+    if (check_data_path(info.dataDir, userAppId) < 0) {
         panic("Package '%s' has corrupt installation\n", pkgname);
     }
 
     /* Ensure that we change all real/effective/saved IDs at the
      * same time to avoid nasty surprises.
      */
-    uid = gid = info.uid;
+    uid = gid = userAppId;
     if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) {
         panic("Permission denied\n");
     }
@@ -181,8 +199,9 @@
     }
 
     /* User specified command for exec. */
-    if ((argc >= 3) && (execvp(argv[2], argv+2) < 0)) {
-        panic("exec failed for %s: %s\n", argv[2], strerror(errno));
+    if ((argc >= commandArgvOfs + 1) &&
+        (execvp(argv[commandArgvOfs], argv+commandArgvOfs) < 0)) {
+        panic("exec failed for %s: %s\n", argv[commandArgvOfs], strerror(errno));
     }
 
     /* Default exec shell. */
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 5b657bb..d2d2315 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -74,22 +74,6 @@
  * requiring any additional GIDs.
  * - Separate permissions for protecting directories like Pictures and Music.
  * - Multi-user separation on the same physical device.
- *
- * The derived permissions look like this:
- *
- * rwxrwx--x root:sdcard_rw     /
- * rwxrwx--- root:sdcard_pics   /Pictures
- * rwxrwx--- root:sdcard_av     /Music
- *
- * rwxrwx--x root:sdcard_rw     /Android
- * rwxrwx--x root:sdcard_rw     /Android/data
- * rwxrwx--- u0_a12:sdcard_rw   /Android/data/com.example
- * rwxrwx--x root:sdcard_rw     /Android/obb/
- * rwxrwx--- u0_a12:sdcard_rw   /Android/obb/com.example
- *
- * rwxrwx--- root:sdcard_all    /Android/user
- * rwxrwx--x root:sdcard_rw     /Android/user/10
- * rwxrwx--- u10_a12:sdcard_rw  /Android/user/10/Android/data/com.example
  */
 
 #define FUSE_TRACE 0
@@ -115,9 +99,6 @@
  * the largest possible data payload. */
 #define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
 
-/* Default number of threads. */
-#define DEFAULT_NUM_THREADS 2
-
 /* Pseudo-error constant used to indicate that no fuse status is needed
  * or that a reply has already been written. */
 #define NO_STATUS 1
@@ -135,7 +116,7 @@
     PERM_INHERIT,
     /* This node is one level above a normal root; used for legacy layouts
      * which use the first level to represent user_id. */
-    PERM_LEGACY_PRE_ROOT,
+    PERM_PRE_ROOT,
     /* This node is "/" */
     PERM_ROOT,
     /* This node is "/Android" */
@@ -146,17 +127,8 @@
     PERM_ANDROID_OBB,
     /* This node is "/Android/media" */
     PERM_ANDROID_MEDIA,
-    /* This node is "/Android/user" */
-    PERM_ANDROID_USER,
 } perm_t;
 
-/* Permissions structure to derive */
-typedef enum {
-    DERIVE_NONE,
-    DERIVE_LEGACY,
-    DERIVE_UNIFIED,
-} derive_t;
-
 struct handle {
     int fd;
 };
@@ -179,8 +151,7 @@
     perm_t perm;
     userid_t userid;
     uid_t uid;
-    gid_t gid;
-    mode_t mode;
+    bool under_android;
 
     struct node *next;          /* per-dir sibling list */
     struct node *child;         /* first contained file by this dir */
@@ -212,25 +183,21 @@
     return strcasecmp(keyA, keyB) == 0;
 }
 
-static int int_hash(void *key) {
-    return (int) (uintptr_t) key;
-}
-
-static bool int_equals(void *keyA, void *keyB) {
-    return keyA == keyB;
-}
-
-/* Global data structure shared by all fuse handlers. */
-struct fuse {
+/* Global data for all FUSE mounts */
+struct fuse_global {
     pthread_mutex_t lock;
 
+    uid_t uid;
+    gid_t gid;
+    bool multi_user;
+
+    char source_path[PATH_MAX];
+    char obb_path[PATH_MAX];
+
+    Hashmap* package_to_appid;
+
     __u64 next_generation;
-    int fd;
-    derive_t derive;
-    bool split_perms;
-    gid_t write_gid;
     struct node root;
-    char obbpath[PATH_MAX];
 
     /* Used to allocate unique inode numbers for fuse nodes. We use
      * a simple counter based scheme where inode numbers from deleted
@@ -251,11 +218,24 @@
      */
     __u32 inode_ctr;
 
-    Hashmap* package_to_appid;
-    Hashmap* appid_with_rw;
+    struct fuse* fuse_default;
+    struct fuse* fuse_read;
+    struct fuse* fuse_write;
 };
 
-/* Private data used by a single fuse handler. */
+/* Single FUSE mount */
+struct fuse {
+    struct fuse_global* global;
+
+    char dest_path[PATH_MAX];
+
+    int fd;
+
+    gid_t gid;
+    mode_t mask;
+};
+
+/* Private data used by a single FUSE handler */
 struct fuse_handler {
     struct fuse* fuse;
     int token;
@@ -412,8 +392,8 @@
     return actual;
 }
 
-static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const struct node* node)
-{
+static void attr_from_stat(struct fuse* fuse, struct fuse_attr *attr,
+        const struct stat *s, const struct node* node) {
     attr->ino = node->ino;
     attr->size = s->st_size;
     attr->blocks = s->st_blocks;
@@ -427,12 +407,35 @@
     attr->nlink = s->st_nlink;
 
     attr->uid = node->uid;
-    attr->gid = node->gid;
 
-    /* Filter requested mode based on underlying file, and
-     * pass through file type. */
+    if (fuse->gid == AID_SDCARD_RW) {
+        /* As an optimization, certain trusted system components only run
+         * as owner but operate across all users. Since we're now handing
+         * out the sdcard_rw GID only to trusted apps, we're okay relaxing
+         * the user boundary enforcement for the default view. The UIDs
+         * assigned to app directories are still multiuser aware. */
+        attr->gid = AID_SDCARD_RW;
+    } else {
+        attr->gid = multiuser_get_uid(node->userid, fuse->gid);
+    }
+
+    int visible_mode = 0775 & ~fuse->mask;
+    if (node->perm == PERM_PRE_ROOT) {
+        /* Top of multi-user view should always be visible to ensure
+         * secondary users can traverse inside. */
+        visible_mode = 0711;
+    } else if (node->under_android) {
+        /* Block "other" access to Android directories, since only apps
+         * belonging to a specific user should be in there; we still
+         * leave +x open for the default view. */
+        if (fuse->gid == AID_SDCARD_RW) {
+            visible_mode = visible_mode & ~0006;
+        } else {
+            visible_mode = visible_mode & ~0007;
+        }
+    }
     int owner_mode = s->st_mode & 0700;
-    int filtered_mode = node->mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
+    int filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
     attr->mode = (attr->mode & S_IFMT) | filtered_mode;
 }
 
@@ -458,105 +461,58 @@
     node->perm = PERM_INHERIT;
     node->userid = parent->userid;
     node->uid = parent->uid;
-    node->gid = parent->gid;
-    node->mode = parent->mode;
-
-    if (fuse->derive == DERIVE_NONE) {
-        return;
-    }
+    node->under_android = parent->under_android;
 
     /* Derive custom permissions based on parent and current node */
     switch (parent->perm) {
     case PERM_INHERIT:
         /* Already inherited above */
         break;
-    case PERM_LEGACY_PRE_ROOT:
+    case PERM_PRE_ROOT:
         /* Legacy internal layout places users at top level */
         node->perm = PERM_ROOT;
         node->userid = strtoul(node->name, NULL, 10);
         break;
     case PERM_ROOT:
         /* Assume masked off by default. */
-        node->mode = 0770;
         if (!strcasecmp(node->name, "Android")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID;
-            node->mode = 0771;
-        } else if (fuse->split_perms) {
-            if (!strcasecmp(node->name, "DCIM")
-                    || !strcasecmp(node->name, "Pictures")) {
-                node->gid = AID_SDCARD_PICS;
-            } else if (!strcasecmp(node->name, "Alarms")
-                    || !strcasecmp(node->name, "Movies")
-                    || !strcasecmp(node->name, "Music")
-                    || !strcasecmp(node->name, "Notifications")
-                    || !strcasecmp(node->name, "Podcasts")
-                    || !strcasecmp(node->name, "Ringtones")) {
-                node->gid = AID_SDCARD_AV;
-            }
+            node->under_android = true;
         }
         break;
     case PERM_ANDROID:
         if (!strcasecmp(node->name, "data")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID_DATA;
-            node->mode = 0771;
         } else if (!strcasecmp(node->name, "obb")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID_OBB;
-            node->mode = 0771;
             /* Single OBB directory is always shared */
-            node->graft_path = fuse->obbpath;
-            node->graft_pathlen = strlen(fuse->obbpath);
+            node->graft_path = fuse->global->obb_path;
+            node->graft_pathlen = strlen(fuse->global->obb_path);
         } else if (!strcasecmp(node->name, "media")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID_MEDIA;
-            node->mode = 0771;
-        } else if (!strcasecmp(node->name, "user")) {
-            /* User directories must only be accessible to system, protected
-             * by sdcard_all. Zygote will bind mount the appropriate user-
-             * specific path. */
-            node->perm = PERM_ANDROID_USER;
-            node->gid = AID_SDCARD_ALL;
-            node->mode = 0770;
         }
         break;
     case PERM_ANDROID_DATA:
     case PERM_ANDROID_OBB:
     case PERM_ANDROID_MEDIA:
-        appid = (appid_t) (uintptr_t) hashmapGet(fuse->package_to_appid, node->name);
+        appid = (appid_t) (uintptr_t) hashmapGet(fuse->global->package_to_appid, node->name);
         if (appid != 0) {
             node->uid = multiuser_get_uid(parent->userid, appid);
         }
-        node->mode = 0770;
-        break;
-    case PERM_ANDROID_USER:
-        /* Root of a secondary user */
-        node->perm = PERM_ROOT;
-        node->userid = strtoul(node->name, NULL, 10);
-        node->gid = AID_SDCARD_R;
-        node->mode = 0771;
         break;
     }
 }
 
-/* Return if the calling UID holds sdcard_rw. */
-static bool get_caller_has_rw_locked(struct fuse* fuse, const struct fuse_in_header *hdr) {
-    /* No additional permissions enforcement */
-    if (fuse->derive == DERIVE_NONE) {
-        return true;
-    }
-
-    appid_t appid = multiuser_get_app_id(hdr->uid);
-    return hashmapContainsKey(fuse->appid_with_rw, (void*) (uintptr_t) appid);
-}
-
 /* Kernel has already enforced everything we returned through
  * derive_permissions_locked(), so this is used to lock down access
  * even further, such as enforcing that apps hold sdcard_rw. */
 static bool check_caller_access_to_name(struct fuse* fuse,
         const struct fuse_in_header *hdr, const struct node* parent_node,
-        const char* name, int mode, bool has_rw) {
+        const char* name, int mode) {
     /* Always block security-sensitive files at root */
     if (parent_node && parent_node->perm == PERM_ROOT) {
         if (!strcasecmp(name, "autorun.inf")
@@ -566,34 +522,19 @@
         }
     }
 
-    /* No additional permissions enforcement */
-    if (fuse->derive == DERIVE_NONE) {
-        return true;
-    }
-
     /* Root always has access; access for any other UIDs should always
      * be controlled through packages.list. */
     if (hdr->uid == 0) {
         return true;
     }
 
-    /* If asking to write, verify that caller either owns the
-     * parent or holds sdcard_rw. */
-    if (mode & W_OK) {
-        if (parent_node && hdr->uid == parent_node->uid) {
-            return true;
-        }
-
-        return has_rw;
-    }
-
     /* No extra permissions to enforce */
     return true;
 }
 
 static bool check_caller_access_to_node(struct fuse* fuse,
-        const struct fuse_in_header *hdr, const struct node* node, int mode, bool has_rw) {
-    return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode, has_rw);
+        const struct fuse_in_header *hdr, const struct node* node, int mode) {
+    return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode);
 }
 
 struct node *create_node_locked(struct fuse* fuse,
@@ -604,7 +545,7 @@
 
     // Detect overflows in the inode counter. "4 billion nodes should be enough
     // for everybody".
-    if (fuse->inode_ctr == 0) {
+    if (fuse->global->inode_ctr == 0) {
         ERROR("No more inode numbers available");
         return NULL;
     }
@@ -630,8 +571,8 @@
     }
     node->namelen = namelen;
     node->nid = ptr_to_id(node);
-    node->ino = fuse->inode_ctr++;
-    node->gen = fuse->next_generation++;
+    node->ino = fuse->global->inode_ctr++;
+    node->gen = fuse->global->next_generation++;
 
     node->deleted = false;
 
@@ -685,7 +626,7 @@
 static struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
 {
     if (nid == FUSE_ROOT_ID) {
-        return &fuse->root;
+        return &fuse->global->root;
     } else {
         return id_to_ptr(nid);
     }
@@ -728,59 +669,6 @@
     return child;
 }
 
-static void fuse_init(struct fuse *fuse, int fd, const char *source_path,
-        gid_t write_gid, derive_t derive, bool split_perms) {
-    pthread_mutex_init(&fuse->lock, NULL);
-
-    fuse->fd = fd;
-    fuse->next_generation = 0;
-    fuse->derive = derive;
-    fuse->split_perms = split_perms;
-    fuse->write_gid = write_gid;
-    fuse->inode_ctr = 1;
-
-    memset(&fuse->root, 0, sizeof(fuse->root));
-    fuse->root.nid = FUSE_ROOT_ID; /* 1 */
-    fuse->root.refcount = 2;
-    fuse->root.namelen = strlen(source_path);
-    fuse->root.name = strdup(source_path);
-    fuse->root.userid = 0;
-    fuse->root.uid = AID_ROOT;
-
-    /* Set up root node for various modes of operation */
-    switch (derive) {
-    case DERIVE_NONE:
-        /* Traditional behavior that treats entire device as being accessible
-         * to sdcard_rw, and no permissions are derived. */
-        fuse->root.perm = PERM_ROOT;
-        fuse->root.mode = 0775;
-        fuse->root.gid = AID_SDCARD_RW;
-        break;
-    case DERIVE_LEGACY:
-        /* Legacy behavior used to support internal multiuser layout which
-         * places user_id at the top directory level, with the actual roots
-         * just below that. Shared OBB path is also at top level. */
-        fuse->root.perm = PERM_LEGACY_PRE_ROOT;
-        fuse->root.mode = 0771;
-        fuse->root.gid = AID_SDCARD_R;
-        fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
-        fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
-        snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/obb", source_path);
-        fs_prepare_dir(fuse->obbpath, 0775, getuid(), getgid());
-        break;
-    case DERIVE_UNIFIED:
-        /* Unified multiuser layout which places secondary user_id under
-         * /Android/user and shared OBB path under /Android/obb. */
-        fuse->root.perm = PERM_ROOT;
-        fuse->root.mode = 0771;
-        fuse->root.gid = AID_SDCARD_R;
-        fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
-        fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
-        snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/Android/obb", source_path);
-        break;
-    }
-}
-
 static void fuse_status(struct fuse *fuse, __u64 unique, int err)
 {
     struct fuse_out_header hdr;
@@ -823,19 +711,19 @@
         return -errno;
     }
 
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
     node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
     if (!node) {
-        pthread_mutex_unlock(&fuse->lock);
+        pthread_mutex_unlock(&fuse->global->lock);
         return -ENOMEM;
     }
     memset(&out, 0, sizeof(out));
-    attr_from_stat(&out.attr, &s, node);
+    attr_from_stat(fuse, &out.attr, &s, node);
     out.attr_valid = 10;
     out.entry_valid = 10;
     out.nodeid = node->nid;
     out.generation = node->gen;
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
     fuse_reply(fuse, unique, &out, sizeof(out));
     return NO_STATUS;
 }
@@ -850,12 +738,43 @@
         return -errno;
     }
     memset(&out, 0, sizeof(out));
-    attr_from_stat(&out.attr, &s, node);
+    attr_from_stat(fuse, &out.attr, &s, node);
     out.attr_valid = 10;
     fuse_reply(fuse, unique, &out, sizeof(out));
     return NO_STATUS;
 }
 
+static void fuse_notify_delete(struct fuse* fuse, const __u64 parent,
+        const __u64 child, const char* name) {
+    struct fuse_out_header hdr;
+    struct fuse_notify_delete_out data;
+    struct iovec vec[3];
+    size_t namelen = strlen(name);
+    int res;
+
+    hdr.len = sizeof(hdr) + sizeof(data) + namelen + 1;
+    hdr.error = FUSE_NOTIFY_DELETE;
+    hdr.unique = 0;
+
+    data.parent = parent;
+    data.child = child;
+    data.namelen = namelen;
+    data.padding = 0;
+
+    vec[0].iov_base = &hdr;
+    vec[0].iov_len = sizeof(hdr);
+    vec[1].iov_base = &data;
+    vec[1].iov_len = sizeof(data);
+    vec[2].iov_base = (void*) name;
+    vec[2].iov_len = namelen + 1;
+
+    res = writev(fuse->fd, vec, 3);
+    /* Ignore ENOENT, since other views may not have seen the entry */
+    if (res < 0 && errno != ENOENT) {
+        ERROR("*** NOTIFY FAILED *** %d\n", errno);
+    }
+}
+
 static int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header *hdr, const char* name)
 {
@@ -864,18 +783,18 @@
     char child_path[PATH_MAX];
     const char* actual_name;
 
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
     TRACE("[%d] LOOKUP %s @ %"PRIx64" (%s)\n", handler->token, name, hdr->nodeid,
         parent_node ? parent_node->name : "?");
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     if (!parent_node || !(actual_name = find_file_within(parent_path, name,
             child_path, sizeof(child_path), 1))) {
         return -ENOENT;
     }
-    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK, false)) {
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK)) {
         return -EACCES;
     }
 
@@ -887,7 +806,7 @@
 {
     struct node* node;
 
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_by_id_locked(fuse, hdr->nodeid);
     TRACE("[%d] FORGET #%"PRIu64" @ %"PRIx64" (%s)\n", handler->token, req->nlookup,
             hdr->nodeid, node ? node->name : "?");
@@ -897,7 +816,7 @@
             release_node_locked(node);
         }
     }
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
     return NO_STATUS; /* no reply */
 }
 
@@ -907,16 +826,16 @@
     struct node* node;
     char path[PATH_MAX];
 
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
     TRACE("[%d] GETATTR flags=%x fh=%"PRIx64" @ %"PRIx64" (%s)\n", handler->token,
             req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     if (!node) {
         return -ENOENT;
     }
-    if (!check_caller_access_to_node(fuse, hdr, node, R_OK, false)) {
+    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
         return -EACCES;
     }
 
@@ -926,24 +845,22 @@
 static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
 {
-    bool has_rw;
     struct node* node;
     char path[PATH_MAX];
     struct timespec times[2];
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
     TRACE("[%d] SETATTR fh=%"PRIx64" valid=%x @ %"PRIx64" (%s)\n", handler->token,
             req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     if (!node) {
         return -ENOENT;
     }
 
     if (!(req->valid & FATTR_FH) &&
-            !check_caller_access_to_node(fuse, hdr, node, W_OK, has_rw)) {
+            !check_caller_access_to_node(fuse, hdr, node, W_OK)) {
         return -EACCES;
     }
 
@@ -991,25 +908,23 @@
 static int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
 {
-    bool has_rw;
     struct node* parent_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
     const char* actual_name;
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    pthread_mutex_lock(&fuse->global->lock);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
     TRACE("[%d] MKNOD %s 0%o @ %"PRIx64" (%s)\n", handler->token,
             name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     if (!parent_node || !(actual_name = find_file_within(parent_path, name,
             child_path, sizeof(child_path), 1))) {
         return -ENOENT;
     }
-    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK, has_rw)) {
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
         return -EACCES;
     }
     __u32 mode = (req->mode & (~0777)) | 0664;
@@ -1022,25 +937,23 @@
 static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
 {
-    bool has_rw;
     struct node* parent_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
     const char* actual_name;
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    pthread_mutex_lock(&fuse->global->lock);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
     TRACE("[%d] MKDIR %s 0%o @ %"PRIx64" (%s)\n", handler->token,
             name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     if (!parent_node || !(actual_name = find_file_within(parent_path, name,
             child_path, sizeof(child_path), 1))) {
         return -ENOENT;
     }
-    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK, has_rw)) {
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
         return -EACCES;
     }
     __u32 mode = (req->mode & (~0777)) | 0775;
@@ -1059,7 +972,7 @@
     }
     if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
         char nomedia[PATH_MAX];
-        snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->obbpath);
+        snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->global->obb_path);
         if (touch(nomedia, 0664) != 0) {
             ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
             return -ENOENT;
@@ -1072,72 +985,96 @@
 static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const char* name)
 {
-    bool has_rw;
     struct node* parent_node;
     struct node* child_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    pthread_mutex_lock(&fuse->global->lock);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
     TRACE("[%d] UNLINK %s @ %"PRIx64" (%s)\n", handler->token,
             name, hdr->nodeid, parent_node ? parent_node->name : "?");
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     if (!parent_node || !find_file_within(parent_path, name,
             child_path, sizeof(child_path), 1)) {
         return -ENOENT;
     }
-    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK, has_rw)) {
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
         return -EACCES;
     }
     if (unlink(child_path) < 0) {
         return -errno;
     }
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
     child_node = lookup_child_by_name_locked(parent_node, name);
     if (child_node) {
         child_node->deleted = true;
     }
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
+    if (parent_node && child_node) {
+        /* Tell all other views that node is gone */
+        TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
+                handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
+        if (fuse != fuse->global->fuse_default) {
+            fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
+        }
+        if (fuse != fuse->global->fuse_read) {
+            fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
+        }
+        if (fuse != fuse->global->fuse_write) {
+            fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
+        }
+    }
     return 0;
 }
 
 static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const char* name)
 {
-    bool has_rw;
     struct node* child_node;
     struct node* parent_node;
     char parent_path[PATH_MAX];
     char child_path[PATH_MAX];
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    pthread_mutex_lock(&fuse->global->lock);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
     TRACE("[%d] RMDIR %s @ %"PRIx64" (%s)\n", handler->token,
             name, hdr->nodeid, parent_node ? parent_node->name : "?");
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     if (!parent_node || !find_file_within(parent_path, name,
             child_path, sizeof(child_path), 1)) {
         return -ENOENT;
     }
-    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK, has_rw)) {
+    if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
         return -EACCES;
     }
     if (rmdir(child_path) < 0) {
         return -errno;
     }
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
     child_node = lookup_child_by_name_locked(parent_node, name);
     if (child_node) {
         child_node->deleted = true;
     }
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
+    if (parent_node && child_node) {
+        /* Tell all other views that node is gone */
+        TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
+                handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
+        if (fuse != fuse->global->fuse_default) {
+            fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
+        }
+        if (fuse != fuse->global->fuse_read) {
+            fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
+        }
+        if (fuse != fuse->global->fuse_write) {
+            fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
+        }
+    }
     return 0;
 }
 
@@ -1145,7 +1082,6 @@
         const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
         const char* old_name, const char* new_name)
 {
-    bool has_rw;
     struct node* old_parent_node;
     struct node* new_parent_node;
     struct node* child_node;
@@ -1156,8 +1092,7 @@
     const char* new_actual_name;
     int res;
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    pthread_mutex_lock(&fuse->global->lock);
     old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             old_parent_path, sizeof(old_parent_path));
     new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
@@ -1170,11 +1105,11 @@
         res = -ENOENT;
         goto lookup_error;
     }
-    if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK, has_rw)) {
+    if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK)) {
         res = -EACCES;
         goto lookup_error;
     }
-    if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK, has_rw)) {
+    if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK)) {
         res = -EACCES;
         goto lookup_error;
     }
@@ -1185,7 +1120,7 @@
         goto lookup_error;
     }
     acquire_node_locked(child_node);
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     /* Special case for renaming a file where destination is same path
      * differing only by case.  In this case we don't want to look for a case
@@ -1206,7 +1141,7 @@
         goto io_error;
     }
 
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
     res = rename_node_locked(child_node, new_name, new_actual_name);
     if (!res) {
         remove_node_from_parent_locked(child_node);
@@ -1215,11 +1150,11 @@
     goto done;
 
 io_error:
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
 done:
     release_node_locked(child_node);
 lookup_error:
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
     return res;
 }
 
@@ -1237,24 +1172,22 @@
 static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const struct fuse_open_in* req)
 {
-    bool has_rw;
     struct node* node;
     char path[PATH_MAX];
     struct fuse_open_out out;
     struct handle *h;
 
-    pthread_mutex_lock(&fuse->lock);
-    has_rw = get_caller_has_rw_locked(fuse, hdr);
+    pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
     TRACE("[%d] OPEN 0%o @ %"PRIx64" (%s)\n", handler->token,
             req->flags, hdr->nodeid, node ? node->name : "?");
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     if (!node) {
         return -ENOENT;
     }
     if (!check_caller_access_to_node(fuse, hdr, node,
-            open_flags_to_access_mode(req->flags), has_rw)) {
+            open_flags_to_access_mode(req->flags))) {
         return -EACCES;
     }
     h = malloc(sizeof(*h));
@@ -1335,14 +1268,14 @@
     struct fuse_statfs_out out;
     int res;
 
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
     TRACE("[%d] STATFS\n", handler->token);
-    res = get_node_path_locked(&fuse->root, path, sizeof(path));
-    pthread_mutex_unlock(&fuse->lock);
+    res = get_node_path_locked(&fuse->global->root, path, sizeof(path));
+    pthread_mutex_unlock(&fuse->global->lock);
     if (res < 0) {
         return -ENOENT;
     }
-    if (statfs(fuse->root.name, &stat) < 0) {
+    if (statfs(fuse->global->root.name, &stat) < 0) {
         return -errno;
     }
     memset(&out, 0, sizeof(out));
@@ -1409,16 +1342,16 @@
     struct fuse_open_out out;
     struct dirhandle *h;
 
-    pthread_mutex_lock(&fuse->lock);
+    pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
     TRACE("[%d] OPENDIR @ %"PRIx64" (%s)\n", handler->token,
             hdr->nodeid, node ? node->name : "?");
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&fuse->global->lock);
 
     if (!node) {
         return -ENOENT;
     }
-    if (!check_caller_access_to_node(fuse, hdr, node, R_OK, false)) {
+    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
         return -EACCES;
     }
     h = malloc(sizeof(*h));
@@ -1498,7 +1431,8 @@
         return -1;
     }
 
-    out.minor = MIN(req->minor, FUSE_KERNEL_MINOR_VERSION);
+    /* We limit ourselves to 15 because we don't handle BATCH_FORGET yet */
+    out.minor = MIN(req->minor, 15);
     fuse_struct_size = sizeof(out);
 #if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
     /* FUSE_KERNEL_VERSION >= 23. */
@@ -1648,12 +1582,14 @@
 {
     struct fuse* fuse = handler->fuse;
     for (;;) {
-        ssize_t len = read(fuse->fd,
-                handler->request_buffer, sizeof(handler->request_buffer));
+        ssize_t len = TEMP_FAILURE_RETRY(read(fuse->fd,
+                handler->request_buffer, sizeof(handler->request_buffer)));
         if (len < 0) {
-            if (errno != EINTR) {
-                ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
+            if (errno == ENODEV) {
+                ERROR("[%d] someone stole our marbles!\n", handler->token);
+                exit(2);
             }
+            ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
             continue;
         }
 
@@ -1700,22 +1636,15 @@
     return true;
 }
 
-static bool remove_int_to_null(void *key, void *value, void *context) {
-    Hashmap* map = context;
-    hashmapRemove(map, key);
-    return true;
-}
+static int read_package_list(struct fuse_global* global) {
+    pthread_mutex_lock(&global->lock);
 
-static int read_package_list(struct fuse *fuse) {
-    pthread_mutex_lock(&fuse->lock);
-
-    hashmapForEach(fuse->package_to_appid, remove_str_to_int, fuse->package_to_appid);
-    hashmapForEach(fuse->appid_with_rw, remove_int_to_null, fuse->appid_with_rw);
+    hashmapForEach(global->package_to_appid, remove_str_to_int, global->package_to_appid);
 
     FILE* file = fopen(kPackagesListFile, "r");
     if (!file) {
         ERROR("failed to open package list: %s\n", strerror(errno));
-        pthread_mutex_unlock(&fuse->lock);
+        pthread_mutex_unlock(&global->lock);
         return -1;
     }
 
@@ -1727,28 +1656,18 @@
 
         if (sscanf(buf, "%s %d %*d %*s %*s %s", package_name, &appid, gids) == 3) {
             char* package_name_dup = strdup(package_name);
-            hashmapPut(fuse->package_to_appid, package_name_dup, (void*) (uintptr_t) appid);
-
-            char* token = strtok(gids, ",");
-            while (token != NULL) {
-                if (strtoul(token, NULL, 10) == fuse->write_gid) {
-                    hashmapPut(fuse->appid_with_rw, (void*) (uintptr_t) appid, (void*) (uintptr_t) 1);
-                    break;
-                }
-                token = strtok(NULL, ",");
-            }
+            hashmapPut(global->package_to_appid, package_name_dup, (void*) (uintptr_t) appid);
         }
     }
 
-    TRACE("read_package_list: found %zu packages, %zu with write_gid\n",
-            hashmapSize(fuse->package_to_appid),
-            hashmapSize(fuse->appid_with_rw));
+    TRACE("read_package_list: found %zu packages\n",
+            hashmapSize(global->package_to_appid));
     fclose(file);
-    pthread_mutex_unlock(&fuse->lock);
+    pthread_mutex_unlock(&global->lock);
     return 0;
 }
 
-static void watch_package_list(struct fuse* fuse) {
+static void watch_package_list(struct fuse_global* global) {
     struct inotify_event *event;
     char event_buf[512];
 
@@ -1776,7 +1695,7 @@
 
             /* Watch above will tell us about any future changes, so
              * read the current state. */
-            if (read_package_list(fuse) == -1) {
+            if (read_package_list(global) == -1) {
                 ERROR("read_package_list failed: %s\n", strerror(errno));
                 return;
             }
@@ -1810,138 +1729,178 @@
     }
 }
 
-static int ignite_fuse(struct fuse* fuse, int num_threads)
-{
-    struct fuse_handler* handlers;
-    int i;
-
-    handlers = malloc(num_threads * sizeof(struct fuse_handler));
-    if (!handlers) {
-        ERROR("cannot allocate storage for threads\n");
-        return -ENOMEM;
-    }
-
-    for (i = 0; i < num_threads; i++) {
-        handlers[i].fuse = fuse;
-        handlers[i].token = i;
-    }
-
-    /* When deriving permissions, this thread is used to process inotify events,
-     * otherwise it becomes one of the FUSE handlers. */
-    i = (fuse->derive == DERIVE_NONE) ? 1 : 0;
-    for (; i < num_threads; i++) {
-        pthread_t thread;
-        int res = pthread_create(&thread, NULL, start_handler, &handlers[i]);
-        if (res) {
-            ERROR("failed to start thread #%d, error=%d\n", i, res);
-            goto quit;
-        }
-    }
-
-    if (fuse->derive == DERIVE_NONE) {
-        handle_fuse_requests(&handlers[0]);
-    } else {
-        watch_package_list(fuse);
-    }
-
-    ERROR("terminated prematurely\n");
-
-    /* don't bother killing all of the other threads or freeing anything,
-     * should never get here anyhow */
-quit:
-    exit(1);
-}
-
-static int usage()
-{
-    ERROR("usage: sdcard [OPTIONS] <source_path> <dest_path>\n"
+static int usage() {
+    ERROR("usage: sdcard [OPTIONS] <source_path> <label>\n"
             "    -u: specify UID to run as\n"
             "    -g: specify GID to run as\n"
-            "    -w: specify GID required to write (default sdcard_rw, requires -d or -l)\n"
-            "    -t: specify number of threads to use (default %d)\n"
-            "    -d: derive file permissions based on path\n"
-            "    -l: derive file permissions based on legacy internal layout\n"
-            "    -s: split derived permissions for pics, av\n"
-            "\n", DEFAULT_NUM_THREADS);
+            "    -U: specify user ID that owns device\n"
+            "    -m: source_path is multi-user\n"
+            "    -w: runtime write mount has full write access\n"
+            "\n");
     return 1;
 }
 
-static int run(const char* source_path, const char* dest_path, uid_t uid,
-        gid_t gid, gid_t write_gid, int num_threads, derive_t derive,
-        bool split_perms) {
-    int fd;
+static int fuse_setup(struct fuse* fuse, gid_t gid, mode_t mask) {
     char opts[256];
-    int res;
-    struct fuse fuse;
 
-    /* cleanup from previous instance, if necessary */
-    umount2(dest_path, MNT_DETACH);
-
-    fd = open("/dev/fuse", O_RDWR);
-    if (fd < 0){
-        ERROR("cannot open fuse device: %s\n", strerror(errno));
+    fuse->fd = open("/dev/fuse", O_RDWR);
+    if (fuse->fd == -1) {
+        ERROR("failed to open fuse device: %s\n", strerror(errno));
         return -1;
     }
 
+    umount2(fuse->dest_path, MNT_DETACH);
+
     snprintf(opts, sizeof(opts),
             "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
-            fd, uid, gid);
-
-    res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC |
-            MS_NOATIME, opts);
-    if (res < 0) {
-        ERROR("cannot mount fuse filesystem: %s\n", strerror(errno));
-        goto error;
+            fuse->fd, fuse->global->uid, fuse->global->gid);
+    if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC |
+            MS_NOATIME, opts) != 0) {
+        ERROR("failed to mount fuse filesystem: %s\n", strerror(errno));
+        return -1;
     }
 
-    res = setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups);
-    if (res < 0) {
-        ERROR("cannot setgroups: %s\n", strerror(errno));
-        goto error;
-    }
+    fuse->gid = gid;
+    fuse->mask = mask;
 
-    res = setgid(gid);
-    if (res < 0) {
-        ERROR("cannot setgid: %s\n", strerror(errno));
-        goto error;
-    }
-
-    res = setuid(uid);
-    if (res < 0) {
-        ERROR("cannot setuid: %s\n", strerror(errno));
-        goto error;
-    }
-
-    fuse_init(&fuse, fd, source_path, write_gid, derive, split_perms);
-
-    umask(0);
-    res = ignite_fuse(&fuse, num_threads);
-
-    /* we do not attempt to umount the file system here because we are no longer
-     * running as the root user */
-
-error:
-    close(fd);
-    return res;
+    return 0;
 }
 
-int main(int argc, char **argv)
-{
-    int res;
+static void run(const char* source_path, const char* label, uid_t uid,
+        gid_t gid, userid_t userid, bool multi_user, bool full_write) {
+    struct fuse_global global;
+    struct fuse fuse_default;
+    struct fuse fuse_read;
+    struct fuse fuse_write;
+    struct fuse_handler handler_default;
+    struct fuse_handler handler_read;
+    struct fuse_handler handler_write;
+    pthread_t thread_default;
+    pthread_t thread_read;
+    pthread_t thread_write;
+
+    memset(&global, 0, sizeof(global));
+    memset(&fuse_default, 0, sizeof(fuse_default));
+    memset(&fuse_read, 0, sizeof(fuse_read));
+    memset(&fuse_write, 0, sizeof(fuse_write));
+    memset(&handler_default, 0, sizeof(handler_default));
+    memset(&handler_read, 0, sizeof(handler_read));
+    memset(&handler_write, 0, sizeof(handler_write));
+
+    pthread_mutex_init(&global.lock, NULL);
+    global.package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
+    global.uid = uid;
+    global.gid = gid;
+    global.multi_user = multi_user;
+    global.next_generation = 0;
+    global.inode_ctr = 1;
+
+    memset(&global.root, 0, sizeof(global.root));
+    global.root.nid = FUSE_ROOT_ID; /* 1 */
+    global.root.refcount = 2;
+    global.root.namelen = strlen(source_path);
+    global.root.name = strdup(source_path);
+    global.root.userid = userid;
+    global.root.uid = AID_ROOT;
+    global.root.under_android = false;
+
+    strcpy(global.source_path, source_path);
+
+    if (multi_user) {
+        global.root.perm = PERM_PRE_ROOT;
+        snprintf(global.obb_path, sizeof(global.obb_path), "%s/obb", source_path);
+    } else {
+        global.root.perm = PERM_ROOT;
+        snprintf(global.obb_path, sizeof(global.obb_path), "%s/Android/obb", source_path);
+    }
+
+    fuse_default.global = &global;
+    fuse_read.global = &global;
+    fuse_write.global = &global;
+
+    global.fuse_default = &fuse_default;
+    global.fuse_read = &fuse_read;
+    global.fuse_write = &fuse_write;
+
+    snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime/default/%s", label);
+    snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime/read/%s", label);
+    snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime/write/%s", label);
+
+    handler_default.fuse = &fuse_default;
+    handler_read.fuse = &fuse_read;
+    handler_write.fuse = &fuse_write;
+
+    handler_default.token = 0;
+    handler_read.token = 1;
+    handler_write.token = 2;
+
+    umask(0);
+
+    if (multi_user) {
+        /* Multi-user storage is fully isolated per user, so "other"
+         * permissions are completely masked off. */
+        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
+                || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
+                || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
+            ERROR("failed to fuse_setup\n");
+            exit(1);
+        }
+    } else {
+        /* Physical storage is readable by all users on device, but
+         * the Android directories are masked off to a single user
+         * deep inside attr_from_stat(). */
+        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
+                || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022)
+                || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) {
+            ERROR("failed to fuse_setup\n");
+            exit(1);
+        }
+    }
+
+    /* Drop privs */
+    if (setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups) < 0) {
+        ERROR("cannot setgroups: %s\n", strerror(errno));
+        exit(1);
+    }
+    if (setgid(gid) < 0) {
+        ERROR("cannot setgid: %s\n", strerror(errno));
+        exit(1);
+    }
+    if (setuid(uid) < 0) {
+        ERROR("cannot setuid: %s\n", strerror(errno));
+        exit(1);
+    }
+
+    if (multi_user) {
+        fs_prepare_dir(global.obb_path, 0775, uid, gid);
+    }
+
+    if (pthread_create(&thread_default, NULL, start_handler, &handler_default)
+            || pthread_create(&thread_read, NULL, start_handler, &handler_read)
+            || pthread_create(&thread_write, NULL, start_handler, &handler_write)) {
+        ERROR("failed to pthread_create\n");
+        exit(1);
+    }
+
+    watch_package_list(&global);
+    ERROR("terminated prematurely\n");
+    exit(1);
+}
+
+int main(int argc, char **argv) {
     const char *source_path = NULL;
-    const char *dest_path = NULL;
+    const char *label = NULL;
     uid_t uid = 0;
     gid_t gid = 0;
-    gid_t write_gid = AID_SDCARD_RW;
-    int num_threads = DEFAULT_NUM_THREADS;
-    derive_t derive = DERIVE_NONE;
-    bool split_perms = false;
+    userid_t userid = 0;
+    bool multi_user = false;
+    bool full_write = false;
     int i;
     struct rlimit rlim;
     int fs_version;
 
     int opt;
-    while ((opt = getopt(argc, argv, "u:g:w:t:dls")) != -1) {
+    while ((opt = getopt(argc, argv, "u:g:U:mw")) != -1) {
         switch (opt) {
             case 'u':
                 uid = strtoul(optarg, NULL, 10);
@@ -1949,20 +1908,14 @@
             case 'g':
                 gid = strtoul(optarg, NULL, 10);
                 break;
+            case 'U':
+                userid = strtoul(optarg, NULL, 10);
+                break;
+            case 'm':
+                multi_user = true;
+                break;
             case 'w':
-                write_gid = strtoul(optarg, NULL, 10);
-                break;
-            case 't':
-                num_threads = strtoul(optarg, NULL, 10);
-                break;
-            case 'd':
-                derive = DERIVE_UNIFIED;
-                break;
-            case 'l':
-                derive = DERIVE_LEGACY;
-                break;
-            case 's':
-                split_perms = true;
+                full_write = true;
                 break;
             case '?':
             default:
@@ -1974,12 +1927,8 @@
         char* arg = argv[i];
         if (!source_path) {
             source_path = arg;
-        } else if (!dest_path) {
-            dest_path = arg;
-        } else if (!uid) {
-            uid = strtoul(arg, NULL, 10);
-        } else if (!gid) {
-            gid = strtoul(arg, NULL, 10);
+        } else if (!label) {
+            label = arg;
         } else {
             ERROR("too many arguments\n");
             return usage();
@@ -1990,22 +1939,14 @@
         ERROR("no source path specified\n");
         return usage();
     }
-    if (!dest_path) {
-        ERROR("no dest path specified\n");
+    if (!label) {
+        ERROR("no label specified\n");
         return usage();
     }
     if (!uid || !gid) {
         ERROR("uid and gid must be nonzero\n");
         return usage();
     }
-    if (num_threads < 1) {
-        ERROR("number of threads must be at least 1\n");
-        return usage();
-    }
-    if (split_perms && derive == DERIVE_NONE) {
-        ERROR("cannot split permissions without deriving\n");
-        return usage();
-    }
 
     rlim.rlim_cur = 8192;
     rlim.rlim_max = 8192;
@@ -2018,6 +1959,6 @@
         sleep(1);
     }
 
-    res = run(source_path, dest_path, uid, gid, write_gid, num_threads, derive, split_perms);
-    return res < 0 ? 1 : 0;
+    run(source_path, label, uid, gid, userid, multi_user, full_write);
+    return 1;
 }