Merge "Add unique audio port IDs to AudioTrack and AudioRecord"
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 68e73f2..ece64fd 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -39,7 +39,7 @@
 
 namespace hardware {
 
-status_t CameraInfo::writeToParcel(Parcel* parcel) const {
+status_t CameraInfo::writeToParcel(android::Parcel* parcel) const {
     status_t res;
     res = parcel->writeInt32(facing);
     if (res != OK) return res;
@@ -47,7 +47,7 @@
     return res;
 }
 
-status_t CameraInfo::readFromParcel(const Parcel* parcel) {
+status_t CameraInfo::readFromParcel(const android::Parcel* parcel) {
     status_t res;
     res = parcel->readInt32(&facing);
     if (res != OK) return res;
@@ -55,8 +55,24 @@
     return res;
 }
 
+status_t CameraStatus::writeToParcel(android::Parcel* parcel) const {
+    status_t res;
+    res = parcel->writeString8(cameraId);
+    if (res != OK) return res;
+    res = parcel->writeInt32(status);
+    return res;
 }
 
+status_t CameraStatus::readFromParcel(const android::Parcel* parcel) {
+    status_t res;
+    res = parcel->readString8(&cameraId);
+    if (res != OK) return res;
+    res = parcel->readInt32(&status);
+    return res;
+}
+
+} // namespace hardware
+
 namespace {
     sp<::android::hardware::ICameraService> gCameraService;
     const int                 kCameraServicePollDelay = 500000; // 0.5s
@@ -239,24 +255,6 @@
     return res.isOk() ? OK : res.serviceSpecificErrorCode();
 }
 
-template <typename TCam, typename TCamTraits>
-status_t CameraBase<TCam, TCamTraits>::addServiceListener(
-        const sp<::android::hardware::ICameraServiceListener>& listener) {
-    const sp<::android::hardware::ICameraService>& cs = getCameraService();
-    if (cs == 0) return UNKNOWN_ERROR;
-    binder::Status res = cs->addListener(listener);
-    return res.isOk() ? OK : res.serviceSpecificErrorCode();
-}
-
-template <typename TCam, typename TCamTraits>
-status_t CameraBase<TCam, TCamTraits>::removeServiceListener(
-        const sp<::android::hardware::ICameraServiceListener>& listener) {
-    const sp<::android::hardware::ICameraService>& cs = getCameraService();
-    if (cs == 0) return UNKNOWN_ERROR;
-    binder::Status res = cs->removeListener(listener);
-    return res.isOk() ? OK : res.serviceSpecificErrorCode();
-}
-
 template class CameraBase<Camera>;
 
 } // namespace android
diff --git a/camera/CaptureResult.cpp b/camera/CaptureResult.cpp
index 0a447e7..e6c0d00 100644
--- a/camera/CaptureResult.cpp
+++ b/camera/CaptureResult.cpp
@@ -26,7 +26,7 @@
     return requestId >= 0;
 }
 
-status_t CaptureResultExtras::readFromParcel(const Parcel *parcel) {
+status_t CaptureResultExtras::readFromParcel(const android::Parcel *parcel) {
     if (parcel == NULL) {
         ALOGE("%s: Null parcel", __FUNCTION__);
         return BAD_VALUE;
@@ -43,7 +43,7 @@
     return OK;
 }
 
-status_t CaptureResultExtras::writeToParcel(Parcel *parcel) const {
+status_t CaptureResultExtras::writeToParcel(android::Parcel *parcel) const {
     if (parcel == NULL) {
         ALOGE("%s: Null parcel", __FUNCTION__);
         return BAD_VALUE;
@@ -69,7 +69,7 @@
     mMetadata = otherResult.mMetadata;
 }
 
-status_t CaptureResult::readFromParcel(Parcel *parcel) {
+status_t CaptureResult::readFromParcel(android::Parcel *parcel) {
 
     ALOGV("%s: parcel = %p", __FUNCTION__, parcel);
 
@@ -100,7 +100,7 @@
     return OK;
 }
 
-status_t CaptureResult::writeToParcel(Parcel *parcel) const {
+status_t CaptureResult::writeToParcel(android::Parcel *parcel) const {
 
     ALOGV("%s: parcel = %p", __FUNCTION__, parcel);
 
diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp
index f3b3dbb..ed09b60 100644
--- a/camera/VendorTagDescriptor.cpp
+++ b/camera/VendorTagDescriptor.cpp
@@ -96,7 +96,7 @@
     mVendorOps = src.mVendorOps;
 }
 
-status_t VendorTagDescriptor::readFromParcel(const Parcel* parcel) {
+status_t VendorTagDescriptor::readFromParcel(const android::Parcel* parcel) {
     status_t res = OK;
     if (parcel == NULL) {
         ALOGE("%s: parcel argument was NULL.", __FUNCTION__);
@@ -244,7 +244,7 @@
     return mTagToTypeMap.valueFor(tag);
 }
 
-status_t VendorTagDescriptor::writeToParcel(Parcel* parcel) const {
+status_t VendorTagDescriptor::writeToParcel(android::Parcel* parcel) const {
     status_t res = OK;
     if (parcel == NULL) {
         ALOGE("%s: parcel argument was NULL.", __FUNCTION__);
diff --git a/camera/aidl/android/hardware/CameraStatus.aidl b/camera/aidl/android/hardware/CameraStatus.aidl
new file mode 100644
index 0000000..2089b8b
--- /dev/null
+++ b/camera/aidl/android/hardware/CameraStatus.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+/** @hide */
+parcelable CameraStatus cpp_header "camera/CameraBase.h";
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index e94fd0c..99c479c 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -24,6 +24,7 @@
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.ICameraServiceListener;
 import android.hardware.CameraInfo;
+import android.hardware.CameraStatus;
 
 /**
  * Binder interface for the native camera service running in mediaserver.
@@ -83,7 +84,7 @@
      * Only supported for device HAL versions >= 3.2
      */
     ICameraDeviceUser connectDevice(ICameraDeviceCallbacks callbacks,
-            int cameraId,
+            String cameraId,
             String opPackageName,
             int clientUid);
 
@@ -102,16 +103,24 @@
             int clientUid);
 
     /**
-     * Add/remove listeners for changes to camera device and flashlight state
+     * Add listener for changes to camera device and flashlight state.
+     *
+     * Also returns the set of currently-known camera IDs and state of each device.
+     * Adding a listener will trigger the torch status listener to fire for all
+     * devices that have a flash unit
      */
-    void addListener(ICameraServiceListener listener);
+    CameraStatus[] addListener(ICameraServiceListener listener);
+
+    /**
+     * Remove listener for changes to camera device and flashlight state.
+     */
     void removeListener(ICameraServiceListener listener);
 
     /**
      * Read the static camera metadata for a camera device.
      * Only supported for device HAL versions >= 3.2
      */
-    CameraMetadataNative getCameraCharacteristics(int cameraId);
+    CameraMetadataNative getCameraCharacteristics(String cameraId);
 
     /**
      * Read in the vendor tag descriptors from the camera module HAL.
@@ -132,9 +141,9 @@
     const int API_VERSION_2 = 2;
 
     // Determines if a particular API version is supported directly
-    boolean supportsCameraApi(int cameraId, int apiVersion);
+    boolean supportsCameraApi(String cameraId, int apiVersion);
 
-    void setTorchMode(String CameraId, boolean enabled, IBinder clientBinder);
+    void setTorchMode(String cameraId, boolean enabled, IBinder clientBinder);
 
     /**
      * Notify the camera service of a system event.  Should only be called from system_server.
diff --git a/camera/aidl/android/hardware/ICameraServiceListener.aidl b/camera/aidl/android/hardware/ICameraServiceListener.aidl
index 4e2a8c7..f871ce4 100644
--- a/camera/aidl/android/hardware/ICameraServiceListener.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceListener.aidl
@@ -40,7 +40,7 @@
      */
     // Device physically unplugged
     const int STATUS_NOT_PRESENT      = 0;
-    // Device physically has been plugged in and the camera can be used exlusively
+    // Device physically has been plugged in and the camera can be used exclusively
     const int STATUS_PRESENT          = 1;
     // Device physically has been plugged in but it will not be connect-able until enumeration is
     // complete
@@ -51,7 +51,7 @@
     // Use to initialize variables only
     const int STATUS_UNKNOWN          = -1;
 
-    oneway void onStatusChanged(int status, int cameraId);
+    oneway void onStatusChanged(int status, String cameraId);
 
     /**
      * The torch mode status of a camera.
diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp
index 0d689a6..4daf35b 100644
--- a/camera/camera2/CaptureRequest.cpp
+++ b/camera/camera2/CaptureRequest.cpp
@@ -28,7 +28,7 @@
 namespace hardware {
 namespace camera2 {
 
-status_t CaptureRequest::readFromParcel(const Parcel* parcel) {
+status_t CaptureRequest::readFromParcel(const android::Parcel* parcel) {
     if (parcel == NULL) {
         ALOGE("%s: Null parcel", __FUNCTION__);
         return BAD_VALUE;
@@ -90,7 +90,7 @@
     return OK;
 }
 
-status_t CaptureRequest::writeToParcel(Parcel* parcel) const {
+status_t CaptureRequest::writeToParcel(android::Parcel* parcel) const {
     if (parcel == NULL) {
         ALOGE("%s: Null parcel", __FUNCTION__);
         return BAD_VALUE;
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 38e1c01..12d0da8 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -62,13 +62,13 @@
         mHeight(0) {
 }
 
-OutputConfiguration::OutputConfiguration(const Parcel& parcel) :
+OutputConfiguration::OutputConfiguration(const android::Parcel& parcel) :
         mRotation(INVALID_ROTATION),
         mSurfaceSetID(INVALID_SET_ID) {
     readFromParcel(&parcel);
 }
 
-status_t OutputConfiguration::readFromParcel(const Parcel* parcel) {
+status_t OutputConfiguration::readFromParcel(const android::Parcel* parcel) {
     status_t err = OK;
     int rotation = 0;
 
@@ -138,7 +138,7 @@
     mSurfaceSetID = surfaceSetID;
 }
 
-status_t OutputConfiguration::writeToParcel(Parcel* parcel) const {
+status_t OutputConfiguration::writeToParcel(android::Parcel* parcel) const {
 
     if (parcel == nullptr) return BAD_VALUE;
     status_t err = OK;
diff --git a/camera/camera2/SubmitInfo.cpp b/camera/camera2/SubmitInfo.cpp
index d739c79..6ebd810 100644
--- a/camera/camera2/SubmitInfo.cpp
+++ b/camera/camera2/SubmitInfo.cpp
@@ -22,7 +22,7 @@
 namespace camera2 {
 namespace utils {
 
-status_t SubmitInfo::writeToParcel(Parcel *parcel) const {
+status_t SubmitInfo::writeToParcel(android::Parcel *parcel) const {
     status_t res;
     if (parcel == nullptr) return BAD_VALUE;
 
@@ -33,7 +33,7 @@
     return res;
 }
 
-status_t SubmitInfo::readFromParcel(const Parcel *parcel) {
+status_t SubmitInfo::readFromParcel(const android::Parcel *parcel) {
     status_t res;
     if (parcel == nullptr) return BAD_VALUE;
 
diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
index 36e3927..8c06833 100644
--- a/camera/cameraserver/Android.mk
+++ b/camera/cameraserver/Android.mk
@@ -24,6 +24,7 @@
 	liblog \
 	libutils \
 	libbinder \
+	android.hardware.camera.common@1.0
 
 LOCAL_MODULE:= cameraserver
 LOCAL_32_BIT_ONLY := true
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 1609da1..f656008 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -28,11 +28,6 @@
 
 using namespace android;
 
-//constants shared between ACameraManager and CameraManagerGlobal
-namespace {
-    const int kMaxCameraIdLen = 32;
-}
-
 namespace android {
 // Static member definitions
 const char* CameraManagerGlobal::kCameraIdKey   = "CameraId";
@@ -125,7 +120,11 @@
         if (mCameraServiceListener == nullptr) {
             mCameraServiceListener = new CameraServiceListener(this);
         }
-        mCameraService->addListener(mCameraServiceListener);
+        std::vector<hardware::CameraStatus> cameraStatuses{};
+        mCameraService->addListener(mCameraServiceListener, &cameraStatuses);
+        for (auto& c : cameraStatuses) {
+            onStatusChangedLocked(c.status, c.cameraId);
+        }
 
         // setup vendor tags
         sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
@@ -157,8 +156,8 @@
     sp<CameraManagerGlobal> cm = mCameraManager.promote();
     if (cm != nullptr) {
         AutoMutex lock(cm->mLock);
-        for (auto pair : cm->mDeviceStatusMap) {
-            int32_t cameraId = pair.first;
+        for (auto& pair : cm->mDeviceStatusMap) {
+            const String8 &cameraId = pair.first;
             cm->onStatusChangedLocked(
                     CameraServiceListener::STATUS_NOT_PRESENT, cameraId);
         }
@@ -174,8 +173,8 @@
     auto pair = mCallbacks.insert(cb);
     // Send initial callbacks if callback is newly registered
     if (pair.second) {
-        for (auto pair : mDeviceStatusMap) {
-            int32_t cameraId = pair.first;
+        for (auto& pair : mDeviceStatusMap) {
+            const String8& cameraId = pair.first;
             int32_t status = pair.second;
 
             sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
@@ -183,7 +182,7 @@
                     callback->onCameraAvailable : callback->onCameraUnavailable;
             msg->setPointer(kCallbackFpKey, (void *) cb);
             msg->setPointer(kContextKey, callback->context);
-            msg->setInt32(kCameraIdKey, cameraId);
+            msg->setString(kCameraIdKey, AString(cameraId));
             msg->post();
         }
     }
@@ -196,6 +195,26 @@
     mCallbacks.erase(cb);
 }
 
+void CameraManagerGlobal::getCameraIdList(std::vector<String8> *cameraIds) {
+    // Ensure that we have initialized/refreshed the list of available devices
+    auto cs = getCameraService();
+    Mutex::Autolock _l(mLock);
+
+    for(auto& deviceStatus : mDeviceStatusMap) {
+        if (deviceStatus.second == hardware::ICameraServiceListener::STATUS_NOT_PRESENT ||
+                deviceStatus.second == hardware::ICameraServiceListener::STATUS_ENUMERATING) {
+            continue;
+        }
+        bool camera2Support = false;
+        binder::Status serviceRet = cs->supportsCameraApi(String16(deviceStatus.first),
+                hardware::ICameraService::API_VERSION_2, &camera2Support);
+        if (!serviceRet.isOk() || !camera2Support) {
+            continue;
+        }
+        cameraIds->push_back(deviceStatus.first);
+    }
+}
+
 bool CameraManagerGlobal::validStatus(int32_t status) {
     switch (status) {
         case hardware::ICameraServiceListener::STATUS_NOT_PRESENT:
@@ -217,14 +236,6 @@
     }
 }
 
-void CameraManagerGlobal::CallbackHandler::sendSingleCallback(
-        int32_t cameraId, void* context,
-        ACameraManager_AvailabilityCallback cb) const {
-    char cameraIdStr[kMaxCameraIdLen];
-    snprintf(cameraIdStr, sizeof(cameraIdStr), "%d", cameraId);
-    (*cb)(context, cameraIdStr);
-}
-
 void CameraManagerGlobal::CallbackHandler::onMessageReceived(
         const sp<AMessage> &msg) {
     switch (msg->what()) {
@@ -232,7 +243,7 @@
         {
             ACameraManager_AvailabilityCallback cb;
             void* context;
-            int32_t cameraId;
+            AString cameraId;
             bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
             if (!found) {
                 ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
@@ -243,12 +254,12 @@
                 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
                 return;
             }
-            found = msg->findInt32(kCameraIdKey, &cameraId);
+            found = msg->findString(kCameraIdKey, &cameraId);
             if (!found) {
                 ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
                 return;
             }
-            sendSingleCallback(cameraId, context, cb);
+            (*cb)(context, cameraId.c_str());
             break;
         }
         default:
@@ -258,10 +269,10 @@
 }
 
 binder::Status CameraManagerGlobal::CameraServiceListener::onStatusChanged(
-        int32_t status, int32_t cameraId) {
+        int32_t status, const String16& cameraId) {
     sp<CameraManagerGlobal> cm = mCameraManager.promote();
     if (cm != nullptr) {
-        cm->onStatusChanged(status, cameraId);
+        cm->onStatusChanged(status, String8(cameraId));
     } else {
         ALOGE("Cannot deliver status change. Global camera manager died");
     }
@@ -269,40 +280,40 @@
 }
 
 void CameraManagerGlobal::onStatusChanged(
-        int32_t status, int32_t cameraId) {
+        int32_t status, const String8& cameraId) {
     Mutex::Autolock _l(mLock);
     onStatusChangedLocked(status, cameraId);
 }
 
 void CameraManagerGlobal::onStatusChangedLocked(
-        int32_t status, int32_t cameraId) {
-        if (!validStatus(status)) {
-            ALOGE("%s: Invalid status %d", __FUNCTION__, status);
-            return;
-        }
+        int32_t status, const String8& cameraId) {
+    if (!validStatus(status)) {
+        ALOGE("%s: Invalid status %d", __FUNCTION__, status);
+        return;
+    }
 
-        bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
-        int32_t oldStatus = firstStatus ?
-                status : // first status
-                mDeviceStatusMap[cameraId];
+    bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
+    int32_t oldStatus = firstStatus ?
+            status : // first status
+            mDeviceStatusMap[cameraId];
 
-        if (!firstStatus &&
-                isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
-            // No status update. No need to send callback
-            return;
-        }
+    if (!firstStatus &&
+            isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
+        // No status update. No need to send callback
+        return;
+    }
 
-        // Iterate through all registered callbacks
-        mDeviceStatusMap[cameraId] = status;
-        for (auto cb : mCallbacks) {
-            sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
-            ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
-                    cb.mAvailable : cb.mUnavailable;
-            msg->setPointer(kCallbackFpKey, (void *) cbFp);
-            msg->setPointer(kContextKey, cb.mContext);
-            msg->setInt32(kCameraIdKey, cameraId);
-            msg->post();
-        }
+    // Iterate through all registered callbacks
+    mDeviceStatusMap[cameraId] = status;
+    for (auto cb : mCallbacks) {
+        sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+        ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
+                cb.mAvailable : cb.mUnavailable;
+        msg->setPointer(kCallbackFpKey, (void *) cbFp);
+        msg->setPointer(kContextKey, cb.mContext);
+        msg->setString(kCameraIdKey, AString(cameraId));
+        msg->post();
+    }
 }
 
 } // namespace android
@@ -311,94 +322,32 @@
  * ACameraManger Implementation
  */
 camera_status_t
-ACameraManager::getOrCreateCameraIdListLocked(ACameraIdList** cameraIdList) {
-    if (mCachedCameraIdList.numCameras == kCameraIdListNotInit) {
-        if (isCameraServiceDisabled()) {
-            mCachedCameraIdList.numCameras = 0;
-            mCachedCameraIdList.cameraIds = new const char*[0];
-            *cameraIdList = &mCachedCameraIdList;
-            return ACAMERA_OK;
-        }
-
-        int numCameras = 0;
-        Vector<char *> cameraIds;
-        sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
-        if (cs == nullptr) {
-            ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
-            return ACAMERA_ERROR_CAMERA_DISCONNECTED;
-        }
-        // Get number of cameras
-        int numAllCameras = 0;
-        binder::Status serviceRet = cs->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_ALL,
-                &numAllCameras);
-        if (!serviceRet.isOk()) {
-            ALOGE("%s: Error getting camera count: %s", __FUNCTION__,
-                    serviceRet.toString8().string());
-            numAllCameras = 0;
-        }
-        // Filter API2 compatible cameras and push to cameraIds
-        for (int i = 0; i < numAllCameras; i++) {
-            // TODO: Only suppot HALs that supports API2 directly now
-            bool camera2Support = false;
-            serviceRet = cs->supportsCameraApi(i, hardware::ICameraService::API_VERSION_2,
-                    &camera2Support);
-            char buf[kMaxCameraIdLen];
-            if (camera2Support) {
-                numCameras++;
-                mCameraIds.insert(i);
-                snprintf(buf, sizeof(buf), "%d", i);
-                size_t cameraIdSize = strlen(buf) + 1;
-                char *cameraId = new char[cameraIdSize];
-                if (!cameraId) {
-                    ALOGE("Allocate memory for ACameraIdList failed!");
-                    return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
-                }
-                strlcpy(cameraId, buf, cameraIdSize);
-                cameraIds.push(cameraId);
-            }
-        }
-        mCachedCameraIdList.numCameras = numCameras;
-        mCachedCameraIdList.cameraIds = new const char*[numCameras];
-        if (!mCachedCameraIdList.cameraIds) {
-            ALOGE("Allocate memory for ACameraIdList failed!");
-            return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
-        }
-        for (int i = 0; i < numCameras; i++) {
-            mCachedCameraIdList.cameraIds[i] = cameraIds[i];
-        }
-    }
-    *cameraIdList = &mCachedCameraIdList;
-    return ACAMERA_OK;
-}
-
-camera_status_t
 ACameraManager::getCameraIdList(ACameraIdList** cameraIdList) {
     Mutex::Autolock _l(mLock);
-    ACameraIdList* cachedList;
-    camera_status_t ret = getOrCreateCameraIdListLocked(&cachedList);
-    if (ret != ACAMERA_OK) {
-        ALOGE("Get camera ID list failed! err: %d", ret);
-        return ret;
-    }
 
-    int numCameras = cachedList->numCameras;
+    std::vector<String8> idList;
+    CameraManagerGlobal::getInstance().getCameraIdList(&idList);
+
+    int numCameras = idList.size();
     ACameraIdList *out = new ACameraIdList;
     if (!out) {
         ALOGE("Allocate memory for ACameraIdList failed!");
         return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
     }
     out->numCameras = numCameras;
-    out->cameraIds = new const char*[numCameras];
+    out->cameraIds = new const char*[numCameras] {nullptr};
     if (!out->cameraIds) {
         ALOGE("Allocate memory for ACameraIdList failed!");
+        deleteCameraIdList(out);
         return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
     }
     for (int i = 0; i < numCameras; i++) {
-        const char* src = cachedList->cameraIds[i];
+        const char* src = idList[i].string();
         size_t dstSize = strlen(src) + 1;
         char* dst = new char[dstSize];
         if (!dst) {
             ALOGE("Allocate memory for ACameraIdList failed!");
+            deleteCameraIdList(out);
             return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
         }
         strlcpy(dst, src, dstSize);
@@ -413,7 +362,9 @@
     if (cameraIdList != nullptr) {
         if (cameraIdList->cameraIds != nullptr) {
             for (int i = 0; i < cameraIdList->numCameras; i ++) {
-                delete[] cameraIdList->cameraIds[i];
+                if (cameraIdList->cameraIds[i] != nullptr) {
+                    delete[] cameraIdList->cameraIds[i];
+                }
             }
             delete[] cameraIdList->cameraIds;
         }
@@ -424,29 +375,27 @@
 camera_status_t ACameraManager::getCameraCharacteristics(
         const char *cameraIdStr, ACameraMetadata **characteristics) {
     Mutex::Autolock _l(mLock);
-    ACameraIdList* cachedList;
-    // Make sure mCameraIds is initialized
-    camera_status_t ret = getOrCreateCameraIdListLocked(&cachedList);
-    if (ret != ACAMERA_OK) {
-        ALOGE("%s: Get camera ID list failed! err: %d", __FUNCTION__, ret);
-        return ret;
-    }
-    int cameraId = atoi(cameraIdStr);
-    if (mCameraIds.count(cameraId) == 0) {
-        ALOGE("%s: Camera ID %s does not exist!", __FUNCTION__, cameraIdStr);
-        return ACAMERA_ERROR_INVALID_PARAMETER;
-    }
+
     sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
     if (cs == nullptr) {
         ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
         return ACAMERA_ERROR_CAMERA_DISCONNECTED;
     }
     CameraMetadata rawMetadata;
-    binder::Status serviceRet = cs->getCameraCharacteristics(cameraId, &rawMetadata);
+    binder::Status serviceRet = cs->getCameraCharacteristics(String16(cameraIdStr), &rawMetadata);
     if (!serviceRet.isOk()) {
-        ALOGE("Get camera characteristics from camera service failed: %s",
-                serviceRet.toString8().string());
-        return ACAMERA_ERROR_UNKNOWN; // should not reach here
+        switch(serviceRet.serviceSpecificErrorCode()) {
+            case hardware::ICameraService::ERROR_DISCONNECTED:
+                ALOGE("%s: Camera %s has been disconnected", __FUNCTION__, cameraIdStr);
+                return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+            case hardware::ICameraService::ERROR_ILLEGAL_ARGUMENT:
+                ALOGE("%s: Camera ID %s does not exist!", __FUNCTION__, cameraIdStr);
+                return ACAMERA_ERROR_INVALID_PARAMETER;
+            default:
+                ALOGE("Get camera characteristics from camera service failed: %s",
+                        serviceRet.toString8().string());
+                return ACAMERA_ERROR_UNKNOWN; // should not reach here
+        }
     }
 
     *characteristics = new ACameraMetadata(
@@ -479,13 +428,12 @@
         return ACAMERA_ERROR_CAMERA_DISCONNECTED;
     }
 
-    int id = atoi(cameraId);
     sp<hardware::camera2::ICameraDeviceCallbacks> callbacks = device->getServiceCallback();
     sp<hardware::camera2::ICameraDeviceUser> deviceRemote;
     // No way to get package name from native.
     // Send a zero length package name and let camera service figure it out from UID
     binder::Status serviceRet = cs->connectDevice(
-            callbacks, id, String16(""),
+            callbacks, String16(cameraId), String16(""),
             hardware::ICameraService::USE_CALLING_UID, /*out*/&deviceRemote);
 
     if (!serviceRet.isOk()) {
@@ -534,11 +482,5 @@
 }
 
 ACameraManager::~ACameraManager() {
-    Mutex::Autolock _l(mLock);
-    if (mCachedCameraIdList.numCameras != kCameraIdListNotInit) {
-        for (int i = 0; i < mCachedCameraIdList.numCameras; i++) {
-            delete[] mCachedCameraIdList.cameraIds[i];
-        }
-        delete[] mCachedCameraIdList.cameraIds;
-    }
+
 }
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index 5b88904..97e4fd9 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -40,7 +40,7 @@
  * instances. Created when first ACameraManager is created and destroyed when
  * all ACameraManager instances are deleted.
  *
- * TODO: maybe CameraManagerGlobal is better sutied in libcameraclient?
+ * TODO: maybe CameraManagerGlobal is better suited in libcameraclient?
  */
 class CameraManagerGlobal final : public RefBase {
   public:
@@ -52,6 +52,11 @@
     void unregisterAvailabilityCallback(
             const ACameraManager_AvailabilityCallbacks *callback);
 
+    /**
+     * Return camera IDs that support camera2
+     */
+    void getCameraIdList(std::vector<String8> *cameraIds);
+
   private:
     sp<hardware::ICameraService> mCameraService;
     const int          kCameraServicePollDelay = 500000; // 0.5s
@@ -72,7 +77,7 @@
     class CameraServiceListener final : public hardware::BnCameraServiceListener {
       public:
         explicit CameraServiceListener(CameraManagerGlobal* cm) : mCameraManager(cm) {}
-        virtual binder::Status onStatusChanged(int32_t status, int32_t cameraId);
+        virtual binder::Status onStatusChanged(int32_t status, const String16& cameraId);
 
         // Torch API not implemented yet
         virtual binder::Status onTorchStatusChanged(int32_t, const String16&) {
@@ -125,22 +130,18 @@
       public:
         CallbackHandler() {}
         void onMessageReceived(const sp<AMessage> &msg) override;
-      private:
-        inline void sendSingleCallback(
-                int32_t cameraId, void* context,
-                ACameraManager_AvailabilityCallback cb) const;
     };
     sp<CallbackHandler> mHandler;
     sp<ALooper>         mCbLooper; // Looper thread where callbacks actually happen on
 
-    void onStatusChanged(int32_t status, int32_t cameraId);
-    void onStatusChangedLocked(int32_t status, int32_t cameraId);
+    void onStatusChanged(int32_t status, const String8& cameraId);
+    void onStatusChangedLocked(int32_t status, const String8& cameraId);
     // Utils for status
     static bool validStatus(int32_t status);
     static bool isStatusAvailable(int32_t status);
 
     // Map camera_id -> status
-    std::map<int32_t, int32_t> mDeviceStatusMap;
+    std::map<String8, int32_t> mDeviceStatusMap;
 
     // For the singleton instance
     static Mutex sLock;
@@ -157,7 +158,6 @@
  */
 struct ACameraManager {
     ACameraManager() :
-            mCachedCameraIdList({kCameraIdListNotInit, nullptr}),
             mGlobalManager(&(android::CameraManagerGlobal::getInstance())) {}
     ~ACameraManager();
     camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
@@ -170,14 +170,10 @@
                                /*out*/ACameraDevice** device);
 
   private:
-    camera_status_t getOrCreateCameraIdListLocked(ACameraIdList** cameraIdList);
-
     enum {
         kCameraIdListNotInit = -1
     };
     android::Mutex         mLock;
-    std::set<int> mCameraIds;          // Init by getOrCreateCameraIdListLocked
-    ACameraIdList mCachedCameraIdList; // Init by getOrCreateCameraIdListLocked
     android::sp<android::CameraManagerGlobal> mGlobalManager;
 };
 
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index b91e0f3..946e3b8 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -65,14 +65,14 @@
 // Stub listener implementation
 class TestCameraServiceListener : public hardware::BnCameraServiceListener {
     std::map<String16, int32_t> mCameraTorchStatuses;
-    std::map<int32_t, int32_t> mCameraStatuses;
+    std::map<String16, int32_t> mCameraStatuses;
     mutable Mutex mLock;
     mutable Condition mCondition;
     mutable Condition mTorchCondition;
 public:
     virtual ~TestCameraServiceListener() {};
 
-    virtual binder::Status onStatusChanged(int32_t status, int32_t cameraId) {
+    virtual binder::Status onStatusChanged(int32_t status, const String16& cameraId) {
         Mutex::Autolock l(mLock);
         mCameraStatuses[cameraId] = status;
         mCondition.broadcast();
@@ -130,7 +130,7 @@
         return iter->second;
     };
 
-    int32_t getStatus(int32_t cameraId) const {
+    int32_t getStatus(const String16& cameraId) const {
         Mutex::Autolock l(mLock);
         const auto& iter = mCameraStatuses.find(cameraId);
         if (iter == mCameraStatuses.end()) {
@@ -310,14 +310,16 @@
 
     // Check listener binder calls
     sp<TestCameraServiceListener> listener(new TestCameraServiceListener());
-    res = service->addListener(listener);
+    std::vector<hardware::CameraStatus> statuses;
+    res = service->addListener(listener, &statuses);
     EXPECT_TRUE(res.isOk()) << res;
 
-    EXPECT_TRUE(listener->waitForNumCameras(numCameras));
+    EXPECT_EQ(numCameras, static_cast<const int>(statuses.size()));
 
     for (int32_t i = 0; i < numCameras; i++) {
+        String16 cameraId = String16(String8::format("%d", i));
         bool isSupported = false;
-        res = service->supportsCameraApi(i,
+        res = service->supportsCameraApi(cameraId,
                 hardware::ICameraService::API_VERSION_2, &isSupported);
         EXPECT_TRUE(res.isOk()) << res;
 
@@ -328,12 +330,12 @@
 
         // Check metadata binder call
         CameraMetadata metadata;
-        res = service->getCameraCharacteristics(i, &metadata);
+        res = service->getCameraCharacteristics(cameraId, &metadata);
         EXPECT_TRUE(res.isOk()) << res;
         EXPECT_FALSE(metadata.isEmpty());
 
         // Make sure we're available, or skip device tests otherwise
-        int32_t s = listener->getStatus(i);
+        int32_t s = listener->getStatus(cameraId);
         EXPECT_EQ(::android::hardware::ICameraServiceListener::STATUS_PRESENT, s);
         if (s != ::android::hardware::ICameraServiceListener::STATUS_PRESENT) {
             continue;
@@ -342,7 +344,7 @@
         // Check connect binder calls
         sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks());
         sp<hardware::camera2::ICameraDeviceUser> device;
-        res = service->connectDevice(callbacks, i, String16("meeeeeeeee!"),
+        res = service->connectDevice(callbacks, cameraId, String16("meeeeeeeee!"),
                 hardware::ICameraService::USE_CALLING_UID, /*out*/&device);
         EXPECT_TRUE(res.isOk()) << res;
         ASSERT_NE(nullptr, device.get());
@@ -352,12 +354,12 @@
         int32_t torchStatus = listener->getTorchStatus(i);
         if (torchStatus == hardware::ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF) {
             // Check torch calls
-            res = service->setTorchMode(String16(String8::format("%d", i)),
+            res = service->setTorchMode(cameraId,
                     /*enabled*/true, callbacks);
             EXPECT_TRUE(res.isOk()) << res;
             EXPECT_TRUE(listener->waitForTorchState(
                     hardware::ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON, i));
-            res = service->setTorchMode(String16(String8::format("%d", i)),
+            res = service->setTorchMode(cameraId,
                     /*enabled*/false, callbacks);
             EXPECT_TRUE(res.isOk()) << res;
             EXPECT_TRUE(listener->waitForTorchState(
@@ -379,7 +381,7 @@
     sp<TestCameraServiceListener> serviceListener;
 
     std::pair<sp<TestCameraDeviceCallbacks>, sp<hardware::camera2::ICameraDeviceUser>>
-            openNewDevice(int deviceId) {
+            openNewDevice(const String16& deviceId) {
         sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks());
         sp<hardware::camera2::ICameraDeviceUser> device;
         {
@@ -415,7 +417,8 @@
         sp<IBinder> binder = sm->getService(String16("media.camera"));
         service = interface_cast<hardware::ICameraService>(binder);
         serviceListener = new TestCameraServiceListener();
-        service->addListener(serviceListener);
+        std::vector<hardware::CameraStatus> statuses;
+        service->addListener(serviceListener, &statuses);
         service->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_BACKWARD_COMPATIBLE,
                 &numCameras);
     }
@@ -435,14 +438,14 @@
     EXPECT_TRUE(serviceListener->waitForNumCameras(numCameras));
     for (int32_t i = 0; i < numCameras; i++) {
         // Make sure we're available, or skip device tests otherwise
-        int32_t s = serviceListener->getStatus(i);
+        String16 cameraId(String8::format("%d",i));
+        int32_t s = serviceListener->getStatus(cameraId);
         EXPECT_EQ(hardware::ICameraServiceListener::STATUS_PRESENT, s);
         if (s != hardware::ICameraServiceListener::STATUS_PRESENT) {
             continue;
         }
         binder::Status res;
-
-        auto p = openNewDevice(i);
+        auto p = openNewDevice(cameraId);
         sp<TestCameraDeviceCallbacks> callbacks = p.first;
         sp<hardware::camera2::ICameraDeviceUser> device = p.second;
 
diff --git a/cmds/stagefright/SimplePlayer.h b/cmds/stagefright/SimplePlayer.h
index 918fd24..1269162 100644
--- a/cmds/stagefright/SimplePlayer.h
+++ b/cmds/stagefright/SimplePlayer.h
@@ -22,7 +22,7 @@
 
 struct ABuffer;
 struct ALooper;
-struct AudioTrack;
+class AudioTrack;
 class IGraphicBufferProducer;
 struct MediaCodec;
 class MediaCodecBuffer;
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
index 86bf047..8356bcc 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.cpp
@@ -75,6 +75,8 @@
     }
     status_t res = session->provideKeyResponse(response);
     if (res == android::OK) {
+        // This is for testing AMediaDrm_setOnEventListener only.
+        sendEvent(kDrmPluginEventVendorDefined, 0, &scope, NULL);
         keySetId.clear();
     }
     return res;
@@ -90,6 +92,8 @@
         value = "ClearKey CDM";
     } else if (name == "algorithms") {
         value = "";
+    } else if (name == "listenerTestSupport") {
+        value = "true";
     } else {
         ALOGE("App requested unknown string property %s", name.string());
         return android::ERROR_DRM_CANNOT_HANDLE;
diff --git a/include/camera/CameraBase.h b/include/camera/CameraBase.h
index 0692a27..03fbdfd 100644
--- a/include/camera/CameraBase.h
+++ b/include/camera/CameraBase.h
@@ -17,7 +17,10 @@
 #ifndef ANDROID_HARDWARE_CAMERA_BASE_H
 #define ANDROID_HARDWARE_CAMERA_BASE_H
 
+#include <android/hardware/ICameraServiceListener.h>
+
 #include <utils/Mutex.h>
+#include <binder/BinderService.h>
 
 struct camera_frame_metadata;
 
@@ -29,6 +32,13 @@
 class ICameraService;
 class ICameraServiceListener;
 
+enum {
+    /** 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,
+};
+
 struct CameraInfo : public android::Parcelable {
     /**
      * The direction that the camera faces to. It should be CAMERA_FACING_BACK
@@ -50,11 +60,33 @@
      */
     int orientation;
 
-    virtual status_t writeToParcel(Parcel* parcel) const;
-    virtual status_t readFromParcel(const Parcel* parcel);
+    virtual status_t writeToParcel(android::Parcel* parcel) const;
+    virtual status_t readFromParcel(const android::Parcel* parcel);
 
 };
 
+/**
+ * Basic status information about a camera device - its name and its current
+ * state.
+ */
+struct CameraStatus : public android::Parcelable {
+    /**
+     * The name of the camera device
+     */
+    String8 cameraId;
+
+    /**
+     * Its current status, one of the ICameraService::STATUS_* fields
+     */
+    int32_t status;
+
+    virtual status_t writeToParcel(android::Parcel* parcel) const;
+    virtual status_t readFromParcel(const android::Parcel* parcel);
+
+    CameraStatus(String8 id, int32_t s) : cameraId(id), status(s) {}
+    CameraStatus() : status(ICameraServiceListener::STATUS_PRESENT) {}
+};
+
 } // namespace hardware
 
 using hardware::CameraInfo;
@@ -86,12 +118,6 @@
                                        /*out*/
                                        struct hardware::CameraInfo* cameraInfo);
 
-    static status_t      addServiceListener(
-        const sp<::android::hardware::ICameraServiceListener>& listener);
-
-    static status_t      removeServiceListener(
-        const sp<::android::hardware::ICameraServiceListener>& listener);
-
     sp<TCamUser>         remote();
 
     // Status is set to 'UNKNOWN_ERROR' after successful (re)connection
diff --git a/include/camera/CameraParameters2.h b/include/camera/CameraParameters2.h
index 88ad812..f691cd6 100644
--- a/include/camera/CameraParameters2.h
+++ b/include/camera/CameraParameters2.h
@@ -151,7 +151,7 @@
         }
 
         ssize_t removeItem(const KeyT& key) {
-            size_t vectorIdx = (size_t) indexOfKey(key);
+            ssize_t vectorIdx = indexOfKey(key);
 
             if (vectorIdx < 0) {
                 return vectorIdx;
diff --git a/include/camera/CaptureResult.h b/include/camera/CaptureResult.h
index 45e4518..917d953 100644
--- a/include/camera/CaptureResult.h
+++ b/include/camera/CaptureResult.h
@@ -88,8 +88,8 @@
      */
     bool isValid();
 
-    virtual status_t                readFromParcel(const Parcel* parcel) override;
-    virtual status_t                writeToParcel(Parcel* parcel) const override;
+    virtual status_t                readFromParcel(const android::Parcel* parcel) override;
+    virtual status_t                writeToParcel(android::Parcel* parcel) const override;
 };
 } // namespace impl
 } // namespace camera2
@@ -105,8 +105,8 @@
 
     CaptureResult(const CaptureResult& otherResult);
 
-    status_t                readFromParcel(Parcel* parcel);
-    status_t                writeToParcel(Parcel* parcel) const;
+    status_t                readFromParcel(android::Parcel* parcel);
+    status_t                writeToParcel(android::Parcel* parcel) const;
 };
 
 }
diff --git a/include/camera/VendorTagDescriptor.h b/include/camera/VendorTagDescriptor.h
index bfc8c96..adfc8c7 100644
--- a/include/camera/VendorTagDescriptor.h
+++ b/include/camera/VendorTagDescriptor.h
@@ -76,7 +76,7 @@
          */
         virtual status_t writeToParcel(
                 /*out*/
-                Parcel* parcel) const override;
+                android::Parcel* parcel) const override;
 
         /**
          * Convenience method to get a vector containing all vendor tag
@@ -103,7 +103,7 @@
          *
          * Returns OK on success, or a negative error code.
          */
-        virtual status_t readFromParcel(const Parcel* parcel) override;
+        virtual status_t readFromParcel(const android::Parcel* parcel) override;
 
     protected:
         KeyedVector<String8, KeyedVector<String8, uint32_t>*> mReverseMapping;
diff --git a/include/camera/android/hardware/ICamera.h b/include/camera/android/hardware/ICamera.h
index 3b12afe..315669e 100644
--- a/include/camera/android/hardware/ICamera.h
+++ b/include/camera/android/hardware/ICamera.h
@@ -33,7 +33,7 @@
 
 class ICameraClient;
 
-class ICamera: public IInterface
+class ICamera: public android::IInterface
 {
     /**
      * Keep up-to-date with ICamera.aidl in frameworks/base
@@ -139,7 +139,7 @@
 
 // ----------------------------------------------------------------------------
 
-class BnCamera: public BnInterface<ICamera>
+class BnCamera: public android::BnInterface<ICamera>
 {
 public:
     virtual status_t    onTransact( uint32_t code,
diff --git a/include/camera/android/hardware/ICameraClient.h b/include/camera/android/hardware/ICameraClient.h
index 3f835a9..f6ee311 100644
--- a/include/camera/android/hardware/ICameraClient.h
+++ b/include/camera/android/hardware/ICameraClient.h
@@ -27,7 +27,7 @@
 namespace android {
 namespace hardware {
 
-class ICameraClient: public IInterface
+class ICameraClient: public android::IInterface
 {
 public:
     DECLARE_META_INTERFACE(CameraClient);
@@ -45,7 +45,7 @@
 
 // ----------------------------------------------------------------------------
 
-class BnCameraClient: public BnInterface<ICameraClient>
+class BnCameraClient: public android::BnInterface<ICameraClient>
 {
 public:
     virtual status_t    onTransact( uint32_t code,
diff --git a/include/camera/camera2/CaptureRequest.h b/include/camera/camera2/CaptureRequest.h
index c989f26..978f48d 100644
--- a/include/camera/camera2/CaptureRequest.h
+++ b/include/camera/camera2/CaptureRequest.h
@@ -37,8 +37,8 @@
     /**
      * Keep impl up-to-date with CaptureRequest.java in frameworks/base
      */
-    status_t                readFromParcel(const Parcel* parcel) override;
-    status_t                writeToParcel(Parcel* parcel) const override;
+    status_t                readFromParcel(const android::Parcel* parcel) override;
+    status_t                writeToParcel(android::Parcel* parcel) const override;
 };
 
 } // namespace camera2
diff --git a/include/camera/camera2/OutputConfiguration.h b/include/camera/camera2/OutputConfiguration.h
index cf8f3c6..cb04c0e 100644
--- a/include/camera/camera2/OutputConfiguration.h
+++ b/include/camera/camera2/OutputConfiguration.h
@@ -47,9 +47,9 @@
     /**
      * Keep impl up-to-date with OutputConfiguration.java in frameworks/base
      */
-    virtual status_t           writeToParcel(Parcel* parcel) const override;
+    virtual status_t           writeToParcel(android::Parcel* parcel) const override;
 
-    virtual status_t           readFromParcel(const Parcel* parcel) override;
+    virtual status_t           readFromParcel(const android::Parcel* parcel) override;
 
     // getGraphicBufferProducer will be NULL
     // getRotation will be INVALID_ROTATION
@@ -59,7 +59,7 @@
     // getGraphicBufferProducer will be NULL if error occurred
     // getRotation will be INVALID_ROTATION if error occurred
     // getSurfaceSetID will be INVALID_SET_ID if error occurred
-    OutputConfiguration(const Parcel& parcel);
+    OutputConfiguration(const android::Parcel& parcel);
 
     OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
             int surfaceSetID = INVALID_SET_ID);
@@ -105,7 +105,7 @@
     int                        mWidth;
     int                        mHeight;
     // helper function
-    static String16 readMaybeEmptyString16(const Parcel* parcel);
+    static String16 readMaybeEmptyString16(const android::Parcel* parcel);
 };
 } // namespace params
 } // namespace camera2
diff --git a/include/camera/camera2/SubmitInfo.h b/include/camera/camera2/SubmitInfo.h
index 3b47b32..8f271c0 100644
--- a/include/camera/camera2/SubmitInfo.h
+++ b/include/camera/camera2/SubmitInfo.h
@@ -31,8 +31,8 @@
     int32_t mRequestId;
     int64_t mLastFrameNumber;
 
-    virtual status_t writeToParcel(Parcel *parcel) const override;
-    virtual status_t readFromParcel(const Parcel* parcel) override;
+    virtual status_t writeToParcel(android::Parcel *parcel) const override;
+    virtual status_t readFromParcel(const android::Parcel* parcel) override;
 
 };
 
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
index c69c11d..bfc068b 100644
--- a/include/media/AudioEffect.h
+++ b/include/media/AudioEffect.h
@@ -462,7 +462,7 @@
         }
 
         // IBinder::DeathRecipient
-        virtual void binderDied(const wp<IBinder>& who) {
+        virtual void binderDied(const wp<IBinder>& /*who*/) {
             sp<AudioEffect> effect = mEffect.promote();
             if (effect != 0) {
                 effect->binderDied();
diff --git a/include/media/ExtendedAudioBufferProvider.h b/include/media/ExtendedAudioBufferProvider.h
index 168ceed..51e4713 100644
--- a/include/media/ExtendedAudioBufferProvider.h
+++ b/include/media/ExtendedAudioBufferProvider.h
@@ -31,7 +31,7 @@
 
     // Invoked by buffer consumer when a new timestamp is available.
     // Default implementation ignores the timestamp.
-    virtual void    onTimestamp(const ExtendedTimestamp& timestamp) { }
+    virtual void    onTimestamp(const ExtendedTimestamp& /*timestamp*/) { }
 };
 
 }   // namespace android
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 56cecea..8c5e61a 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -198,6 +198,7 @@
                                     audio_io_handle_t output,
                                     audio_session_t sessionId,
                                     const String16& callingPackage,
+                                    pid_t pid,
                                     status_t *status,
                                     int *id,
                                     int *enabled) = 0;
diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
index 34b15e9..e0a81f1 100644
--- a/include/media/IMediaExtractor.h
+++ b/include/media/IMediaExtractor.h
@@ -54,8 +54,6 @@
     virtual uint32_t flags() const = 0;
 
     // for DRM
-    virtual void setDrmFlag(bool flag) = 0;
-    virtual bool getDrmFlag() = 0;
     virtual char* getDrmTrackInfo(size_t trackID, int *len)  = 0;
     virtual void setUID(uid_t uid)  = 0;
 
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 8266b0b..f21bb3a 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -32,7 +32,7 @@
 namespace android {
 
 struct IHDCP;
-struct IMediaCodecList;
+class IMediaCodecList;
 struct IMediaHTTPService;
 class IMediaRecorder;
 class IOMX;
diff --git a/include/media/MediaCodecInfo.h b/include/media/MediaCodecInfo.h
index 48d0407..6b50f22 100644
--- a/include/media/MediaCodecInfo.h
+++ b/include/media/MediaCodecInfo.h
@@ -74,7 +74,7 @@
 
         DISALLOW_EVIL_CONSTRUCTORS(Capabilities);
 
-        friend class MediaCodecInfo;
+        friend struct MediaCodecInfo;
     };
 
     // Use a subclass to allow setting fields on construction without allowing
@@ -136,7 +136,7 @@
 
     DISALLOW_EVIL_CONSTRUCTORS(MediaCodecInfo);
 
-    friend class MediaCodecList;
+    friend struct MediaCodecList;
     friend class MediaCodecListOverridesTest;
 };
 
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h
index bce6ee3..a5e1350 100644
--- a/include/media/MediaMetadataRetrieverInterface.h
+++ b/include/media/MediaMetadataRetrieverInterface.h
@@ -54,9 +54,9 @@
     MediaMetadataRetrieverInterface() {}
 
     virtual             ~MediaMetadataRetrieverInterface() {}
-    virtual VideoFrame* getFrameAtTime(int64_t timeUs, int option) { return NULL; }
+    virtual VideoFrame* getFrameAtTime(int64_t /*timeUs*/, int /*option*/) { return NULL; }
     virtual MediaAlbumArt* extractAlbumArt() { return NULL; }
-    virtual const char* extractMetadata(int keyCode) { return NULL; }
+    virtual const char* extractMetadata(int /*keyCode*/) { return NULL; }
 };
 
 }; // namespace android
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index 59dfd18..b9105b1 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -45,7 +45,7 @@
                                const sp<ICameraRecordingProxy>& proxy) = 0;
     virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface) = 0;
     virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
-    virtual status_t setOutputFileAuxiliary(int fd) {return INVALID_OPERATION;}
+    virtual status_t setOutputFileAuxiliary(int /*fd*/) {return INVALID_OPERATION;}
     virtual status_t setParameters(const String8& params) = 0;
     virtual status_t setListener(const sp<IMediaRecorderClient>& listener) = 0;
     virtual status_t setClientName(const String16& clientName) = 0;
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
index 3fd97ac..9dd9125 100644
--- a/include/media/nbaio/NBAIO.h
+++ b/include/media/nbaio/NBAIO.h
@@ -215,7 +215,7 @@
     // Returns NO_ERROR if a timestamp is available.  The timestamp includes the total number
     // of frames presented to an external observer, together with the value of CLOCK_MONOTONIC
     // as of this presentation count.  The timestamp parameter is undefined if error is returned.
-    virtual status_t getTimestamp(ExtendedTimestamp &timestamp) { return INVALID_OPERATION; }
+    virtual status_t getTimestamp(ExtendedTimestamp& /*timestamp*/) { return INVALID_OPERATION; }
 
 protected:
     NBAIO_Sink(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0)
@@ -313,7 +313,7 @@
 
     // Invoked asynchronously by corresponding sink when a new timestamp is available.
     // Default implementation ignores the timestamp.
-    virtual void    onTimestamp(const ExtendedTimestamp& timestamp) { }
+    virtual void    onTimestamp(const ExtendedTimestamp& /*timestamp*/) { }
 
 protected:
     NBAIO_Source(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0)
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index cde188c..3420617 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -37,7 +37,7 @@
 struct ABuffer;
 class ACodecBufferChannel;
 class MediaCodecBuffer;
-struct MemoryDealer;
+class MemoryDealer;
 struct DescribeColorFormat2Params;
 struct DataConverter;
 
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index c2e75a6..c604f2d 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -216,10 +216,10 @@
 
     // Returns true if need to skip the current frame.
     // Called from dataCallbackTimestamp.
-    virtual bool skipCurrentFrame(int64_t timestampUs) {return false;}
+    virtual bool skipCurrentFrame(int64_t /*timestampUs*/) {return false;}
 
     // Callback called when still camera raw data is available.
-    virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) {}
+    virtual void dataCallback(int32_t /*msgType*/, const sp<IMemory>& /*data*/) {}
 
     virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
             const sp<IMemory> &data);
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index 52daa9e..cfbaea4 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -209,10 +209,10 @@
     virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
 
     virtual status_t queryCapabilities(
-            const AString &name, const AString &mime, bool isEncoder,
-            sp<MediaCodecInfo::Capabilities> *caps /* nonnull */) { return INVALID_OPERATION; }
+            const AString& /*name*/, const AString& /*mime*/, bool /*isEncoder*/,
+            sp<MediaCodecInfo::Capabilities>* /*caps*/ /* nonnull */) { return INVALID_OPERATION; }
 
-    virtual status_t setSurface(const sp<Surface> &surface) { return INVALID_OPERATION; }
+    virtual status_t setSurface(const sp<Surface>& /*surface*/) { return INVALID_OPERATION; }
 
     virtual void signalFlush() = 0;
     virtual void signalResume() = 0;
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index a8dcbe0..e7135a2 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -97,17 +97,17 @@
         return String8("<unspecified>");
     }
 
-    virtual status_t reconnectAtOffset(off64_t offset) {
+    virtual status_t reconnectAtOffset(off64_t /*offset*/) {
         return ERROR_UNSUPPORTED;
     }
 
     ////////////////////////////////////////////////////////////////////////////
 
     // for DRM
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL) {
+    virtual sp<DecryptHandle> DrmInitialization(const char * /*mime*/ = NULL) {
         return NULL;
     }
-    virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) {};
+    virtual void getDrmInfo(sp<DecryptHandle> &/*handle*/, DrmManagerClient ** /*client*/) {};
 
     virtual String8 getUri() {
         return String8();
diff --git a/include/media/stagefright/FrameRenderTracker.h b/include/media/stagefright/FrameRenderTracker.h
index 6c572b8..6cbf85d 100644
--- a/include/media/stagefright/FrameRenderTracker.h
+++ b/include/media/stagefright/FrameRenderTracker.h
@@ -82,7 +82,7 @@
     sp<GraphicBuffer> mGraphicBuffer;
     sp<Fence> mFence;
 
-    friend class FrameRenderTracker;
+    friend struct FrameRenderTracker;
 };
 
 struct FrameRenderTracker {
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 9434047..d415b8b 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -27,7 +27,7 @@
 
 namespace android {
 
-class AMessage;
+struct AMessage;
 class MediaBuffer;
 class MetaData;
 
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 50fb312..2e367bf 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -44,7 +44,7 @@
 class IResourceManagerClient;
 class IResourceManagerService;
 struct PersistentSurface;
-struct SoftwareRenderer;
+class SoftwareRenderer;
 class Surface;
 
 struct MediaCodec : public AHandler {
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index e5ee72e..fbb4a67 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -24,7 +24,7 @@
 namespace android {
 
 class DataSource;
-class MediaSource;
+struct MediaSource;
 class MetaData;
 
 class MediaExtractor : public BnMediaExtractor {
@@ -59,16 +59,10 @@
     virtual uint32_t flags() const;
 
     // for DRM
-    void setDrmFlag(bool flag) {
-        mIsDrm = flag;
-    };
-    bool getDrmFlag() {
-        return mIsDrm;
-    }
-    virtual char* getDrmTrackInfo(size_t trackID, int *len) {
+    virtual char* getDrmTrackInfo(size_t /*trackID*/, int * /*len*/) {
         return NULL;
     }
-    virtual void setUID(uid_t uid) {
+    virtual void setUID(uid_t /*uid*/) {
     }
 
     virtual const char * name() { return "<unspecified>"; }
diff --git a/include/media/stagefright/MediaFilter.h b/include/media/stagefright/MediaFilter.h
index 0e4539b..0c10d11 100644
--- a/include/media/stagefright/MediaFilter.h
+++ b/include/media/stagefright/MediaFilter.h
@@ -23,7 +23,7 @@
 
 class ACodecBufferChannel;
 struct GraphicBufferListener;
-struct MemoryDealer;
+class MemoryDealer;
 struct SimpleFilter;
 
 struct MediaFilter : public CodecBase {
diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h
index b6476c9..2b19523 100644
--- a/include/media/stagefright/MediaWriter.h
+++ b/include/media/stagefright/MediaWriter.h
@@ -44,11 +44,11 @@
         mListener = listener;
     }
 
-    virtual status_t dump(int fd, const Vector<String16>& args) {
+    virtual status_t dump(int /*fd*/, const Vector<String16>& /*args*/) {
         return OK;
     }
 
-    virtual void setStartTimeOffsetMs(int ms) {}
+    virtual void setStartTimeOffsetMs(int /*ms*/) {}
     virtual int32_t getStartTimeOffsetMs() const { return 0; }
 
 protected:
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index a8aca5a..e414757 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -34,7 +34,7 @@
 class DataSource;
 struct IMediaHTTPService;
 class MediaBuffer;
-struct MediaExtractor;
+class MediaExtractor;
 struct MediaSource;
 class MetaData;
 
diff --git a/include/media/stagefright/SimpleDecodingSource.h b/include/media/stagefright/SimpleDecodingSource.h
index 534097b..e6aee6a 100644
--- a/include/media/stagefright/SimpleDecodingSource.h
+++ b/include/media/stagefright/SimpleDecodingSource.h
@@ -71,12 +71,13 @@
     // Construct this using a codec, source and looper.
     SimpleDecodingSource(
             const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
-            bool usingSurface, const sp<AMessage> &format);
+            bool usingSurface, bool isVorbis, const sp<AMessage> &format);
 
     sp<MediaCodec> mCodec;
     sp<IMediaSource> mSource;
     sp<ALooper> mLooper;
     bool mUsingSurface;
+    bool mIsVorbis;
     enum State {
         INIT,
         STARTED,
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index 590952f..a5f9ab6 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -128,9 +128,11 @@
     mDescriptor.uuid = *(uuid != NULL ? uuid : EFFECT_UUID_NULL);
 
     mIEffectClient = new EffectClient(this);
+    mClientPid = IPCThreadState::self()->getCallingPid();
 
     iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor,
-            mIEffectClient, priority, io, mSessionId, mOpPackageName, &mStatus, &mId, &enabled);
+            mIEffectClient, priority, io, mSessionId, mOpPackageName, mClientPid,
+            &mStatus, &mId, &enabled);
 
     if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
         ALOGE("set(): AudioFlinger could not create effect, status: %d", mStatus);
@@ -156,7 +158,6 @@
     mCblk->buffer = (uint8_t *)mCblk + bufOffset;
 
     IInterface::asBinder(iEffect)->linkToDeath(mIEffectClient);
-    mClientPid = IPCThreadState::self()->getCallingPid();
     ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId,
             mStatus, mEnabled, mClientPid);
 
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index b532deb..255e350 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -720,6 +720,7 @@
                                     audio_io_handle_t output,
                                     audio_session_t sessionId,
                                     const String16& opPackageName,
+                                    pid_t pid,
                                     status_t *status,
                                     int *id,
                                     int *enabled)
@@ -741,6 +742,7 @@
         data.writeInt32((int32_t) output);
         data.writeInt32(sessionId);
         data.writeString16(opPackageName);
+        data.writeInt32((int32_t) pid);
 
         status_t lStatus = remote()->transact(CREATE_EFFECT, data, &reply);
         if (lStatus != NO_ERROR) {
@@ -1300,12 +1302,14 @@
             audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
             audio_session_t sessionId = (audio_session_t) data.readInt32();
             const String16 opPackageName = data.readString16();
+            pid_t pid = (pid_t)data.readInt32();
+
             status_t status = NO_ERROR;
             int id = 0;
             int enabled = 0;
 
             sp<IEffect> effect = createEffect(&desc, client, priority, output, sessionId,
-                    opPackageName, &status, &id, &enabled);
+                    opPackageName, pid, &status, &id, &enabled);
             reply->writeInt32(status);
             reply->writeInt32(id);
             reply->writeInt32(enabled);
diff --git a/media/libaudiohal/Android.mk b/media/libaudiohal/Android.mk
index 63aa9c6..e82766f 100644
--- a/media/libaudiohal/Android.mk
+++ b/media/libaudiohal/Android.mk
@@ -29,9 +29,8 @@
     android.hardware.audio@2.0             \
     android.hardware.audio.common@2.0      \
     android.hardware.audio.common@2.0-util \
-    android.hardware.audio.effect@2.0
-
-LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
+    android.hardware.audio.effect@2.0 \
+    libmedia_helper
 
 else  # if !ENABLE_TREBLE
 
diff --git a/media/libaudiohal/ConversionHelperHidl.cpp b/media/libaudiohal/ConversionHelperHidl.cpp
index ebbc02c..1fabfbe 100644
--- a/media/libaudiohal/ConversionHelperHidl.cpp
+++ b/media/libaudiohal/ConversionHelperHidl.cpp
@@ -82,17 +82,25 @@
     }
 }
 
+// static
+void ConversionHelperHidl::crashIfHalIsDead(const Status& status) {
+    LOG_ALWAYS_FATAL_IF(
+            status.transactionError() == DEAD_OBJECT, "HAL server crashed, need to restart");
+}
+
 status_t ConversionHelperHidl::processReturn(const char* funcName, const Status& status) {
     const status_t st = status.transactionError();
     ALOGE_IF(st, "%s %p %s: %s (from rpc)", mClassName, this, funcName, strerror(-st));
+    crashIfHalIsDead(status);
     return st;
 }
 
 status_t ConversionHelperHidl::processReturn(
         const char* funcName, const Status& status, hardware::audio::V2_0::Result retval) {
     const status_t st = status.isOk() ? analyzeResult(retval) : status.transactionError();
-    ALOGE_IF(st, "%s %p %s: %s (from %s)",
-            mClassName, this, funcName, strerror(-st), status.isOk() ? "hal" : "rpc");
+    ALOGE_IF(!status.isOk() && st, "%s %p %s: %s (from rpc)",
+            mClassName, this, funcName, strerror(-st));
+    crashIfHalIsDead(status);
     return st;
 }
 
diff --git a/media/libaudiohal/ConversionHelperHidl.h b/media/libaudiohal/ConversionHelperHidl.h
index 628913a..428daf2 100644
--- a/media/libaudiohal/ConversionHelperHidl.h
+++ b/media/libaudiohal/ConversionHelperHidl.h
@@ -30,6 +30,9 @@
 namespace android {
 
 class ConversionHelperHidl {
+  public:
+    static void crashIfHalIsDead(const Status& status);
+
   protected:
     static status_t keysFromHal(const String8& keys, hidl_vec<hidl_string> *hidlKeys);
     static status_t parametersFromHal(const String8& kvPairs, hidl_vec<ParameterValue> *hidlParams);
diff --git a/media/libaudiohal/DevicesFactoryHalHidl.cpp b/media/libaudiohal/DevicesFactoryHalHidl.cpp
index 155b1a8..efcc089 100644
--- a/media/libaudiohal/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/DevicesFactoryHalHidl.cpp
@@ -22,6 +22,7 @@
 #include <android/hardware/audio/2.0/IDevice.h>
 #include <utils/Log.h>
 
+#include "ConversionHelperHidl.h"
 #include "DeviceHalHidl.h"
 #include "DevicesFactoryHalHidl.h"
 
@@ -82,6 +83,7 @@
         else if (retval == Result::INVALID_ARGUMENTS) return BAD_VALUE;
         else return NO_INIT;
     }
+    ConversionHelperHidl::crashIfHalIsDead(ret.getStatus());
     return ret.getStatus().transactionError();
 }
 
diff --git a/media/libaudiohal/EffectHalHidl.cpp b/media/libaudiohal/EffectHalHidl.cpp
index b508cb5..1cd1997 100644
--- a/media/libaudiohal/EffectHalHidl.cpp
+++ b/media/libaudiohal/EffectHalHidl.cpp
@@ -20,6 +20,7 @@
 #include <media/EffectsFactoryApi.h>
 #include <utils/Log.h>
 
+#include "ConversionHelperHidl.h"
 #include "EffectHalHidl.h"
 #include "HidlUtils.h"
 
@@ -102,6 +103,7 @@
                     effectDescriptorToHal(result, pDescriptor);
                 }
             });
+    ConversionHelperHidl::crashIfHalIsDead(ret.getStatus());
     return ret.getStatus().isOk() ? analyzeResult(retval) : ret.getStatus().transactionError();
 }
 
diff --git a/media/libaudiohal/EffectsFactoryHalHidl.cpp b/media/libaudiohal/EffectsFactoryHalHidl.cpp
index 4f2eef0..bacbe4e 100644
--- a/media/libaudiohal/EffectsFactoryHalHidl.cpp
+++ b/media/libaudiohal/EffectsFactoryHalHidl.cpp
@@ -20,6 +20,7 @@
 #include <cutils/native_handle.h>
 #include <media/EffectsFactoryApi.h>
 
+#include "ConversionHelperHidl.h"
 #include "EffectHalHidl.h"
 #include "EffectsFactoryHalHidl.h"
 #include "HidlUtils.h"
@@ -63,6 +64,7 @@
         return retval == Result::OK ? OK : NO_INIT;
     }
     mLastDescriptors.resize(0);
+    ConversionHelperHidl::crashIfHalIsDead(ret.getStatus());
     return ret.getStatus().transactionError();
 }
 
@@ -107,6 +109,7 @@
         else if (retval == Result::INVALID_ARGUMENTS) return NAME_NOT_FOUND;
         else return NO_INIT;
     }
+    ConversionHelperHidl::crashIfHalIsDead(ret.getStatus());
     return ret.getStatus().transactionError();
 }
 
@@ -130,6 +133,7 @@
         else if (retval == Result::INVALID_ARGUMENTS) return NAME_NOT_FOUND;
         else return NO_INIT;
     }
+    ConversionHelperHidl::crashIfHalIsDead(ret.getStatus());
     return ret.getStatus().transactionError();
 }
 
@@ -139,6 +143,7 @@
     hidlHandle->data[0] = fd;
     Return<void> ret = mEffectsFactory->debugDump(hidlHandle);
     native_handle_delete(hidlHandle);
+    ConversionHelperHidl::crashIfHalIsDead(ret.getStatus());
     return ret.getStatus().transactionError();
 }
 
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 6e28ba9..4b14543 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -1,4 +1,4 @@
-cc_library_static {
+cc_library {
     name: "libmedia_helper",
     srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
     cflags: [
@@ -6,5 +6,8 @@
         "-Wno-error=deprecated-declarations",
         "-Wall",
     ],
+    shared: {
+      shared_libs: ["libutils", "liblog"],
+    },
     clang: true,
 }
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 02947b0..8fff414 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -59,12 +59,11 @@
 LOCAL_SHARED_LIBRARIES := \
 	libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
         libcamera_client libstagefright_foundation \
-        libgui libdl libaudioutils libaudioclient
+        libgui libdl libaudioutils libaudioclient \
+        libmedia_helper
 
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libsonivox
 
-LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
-
 # for memory heap analysis
 LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging
 
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 94c96f6..7776313 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -34,8 +34,6 @@
     GETTRACKMETADATA,
     GETMETADATA,
     FLAGS,
-    SETDRMFLAG,
-    GETDRMFLAG,
     GETDRMTRACKINFO,
     SETUID,
     NAME
@@ -101,13 +99,6 @@
         return 0;
     }
 
-    virtual void setDrmFlag(bool flag __unused) {
-        ALOGV("setDrmFlag NOT IMPLEMENTED");
-    }
-    virtual bool getDrmFlag() {
-        ALOGV("getDrmFlag NOT IMPLEMENTED");
-       return false;
-    }
     virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) {
         ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
         return NULL;
diff --git a/media/libmediaplayerservice/ActivityManager.cpp b/media/libmediaplayerservice/ActivityManager.cpp
index 0e6cf7b..438d422 100644
--- a/media/libmediaplayerservice/ActivityManager.cpp
+++ b/media/libmediaplayerservice/ActivityManager.cpp
@@ -14,18 +14,14 @@
  * limitations under the License.
  */
 
-#include <unistd.h>
+#include <binder/IActivityManager.h>
 #include <binder/IBinder.h>
 #include <binder/IServiceManager.h>
-#include <binder/Parcel.h>
-#include <utils/String8.h>
 
 #include "ActivityManager.h"
 
 namespace android {
 
-const uint32_t OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION;
-
 // Perform ContentProvider.openFile() on the given URI, returning
 // the resulting native file descriptor.  Returns < 0 on error.
 int openContentProviderFile(const String16& uri)
@@ -33,26 +29,10 @@
     int fd = -1;
 
     sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> am = sm->getService(String16("activity"));
+    sp<IBinder> binder = sm->getService(String16("activity"));
+    sp<IActivityManager> am = interface_cast<IActivityManager>(binder);
     if (am != NULL) {
-        Parcel data, reply;
-        data.writeInterfaceToken(String16("android.app.IActivityManager"));
-        data.writeString16(uri);
-        status_t ret = am->transact(OPEN_CONTENT_URI_TRANSACTION, data, &reply);
-        if (ret == NO_ERROR) {
-            int32_t exceptionCode = reply.readExceptionCode();
-            if (!exceptionCode) {
-                // Success is indicated here by a nonzero int followed by the fd;
-                // failure by a zero int with no data following.
-                if (reply.readInt32() != 0) {
-                    fd = dup(reply.readFileDescriptor());
-                }
-            } else {
-                // An exception was thrown back; fall through to return failure
-                ALOGD("openContentUri(%s) caught exception %d\n",
-                        String8(uri).string(), exceptionCode);
-            }
-        }
+        fd = am->openContentUri(uri);
     }
 
     return fd;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 3ad461c..065738e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -577,7 +577,7 @@
     mLoop = false;
     mStatus = NO_INIT;
     mAudioSessionId = audioSessionId;
-    mUID = uid;
+    mUid = uid;
     mRetransmitEndpointValid = false;
     mAudioAttributes = NULL;
 
@@ -643,7 +643,7 @@
     }
 
     if (p != NULL) {
-        p->setUID(mUID);
+        p->setUID(mUid);
     }
 
     return p;
@@ -1422,7 +1422,7 @@
 
 #undef LOG_TAG
 #define LOG_TAG "AudioSink"
-MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, int uid, int pid,
+MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
         const audio_attributes_t* attr)
     : mCallback(NULL),
       mCallbackCookie(NULL),
@@ -2384,7 +2384,7 @@
         return;
     }
 
-    int uid = IPCThreadState::self()->getCallingUid();
+    uid_t uid = IPCThreadState::self()->getCallingUid();
     if (uid == AID_MEDIA) {
         return;
     }
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 8a6ada0..db182b2 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -75,7 +75,7 @@
         class CallbackData;
 
      public:
-                                AudioOutput(audio_session_t sessionId, int uid, int pid,
+                                AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
                                         const audio_attributes_t * attr);
         virtual                 ~AudioOutput();
 
@@ -152,7 +152,7 @@
         float                   mMsecsPerFrame;
         size_t                  mFrameSize;
         audio_session_t         mSessionId;
-        int                     mUid;
+        uid_t                   mUid;
         int                     mPid;
         float                   mSendLevel;
         int                     mAuxEffectId;
@@ -407,7 +407,7 @@
                     int32_t                     mConnId;
                     audio_session_t             mAudioSessionId;
                     audio_attributes_t *        mAudioAttributes;
-                    uid_t                       mUID;
+                    uid_t                       mUid;
                     sp<ANativeWindow>           mConnectedWindow;
                     sp<IBinder>                 mConnectedWindowBinder;
                     struct sockaddr_in          mRetransmitEndpoint;
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 12656cf..83ef80a 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -22,7 +22,7 @@
 
 namespace android {
 
-class MediaRecorderBase;
+struct MediaRecorderBase;
 class MediaPlayerService;
 class ICameraRecordingProxy;
 
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 8761e9d..d1d1077 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -145,10 +145,6 @@
         return UNKNOWN_ERROR;
     }
 
-    if (extractor->getDrmFlag()) {
-        checkDrmStatus(mDataSource);
-    }
-
     mFileMeta = extractor->getMetaData();
     if (mFileMeta != NULL) {
         int64_t duration;
@@ -262,18 +258,6 @@
     return OK;
 }
 
-void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
-    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
-    if (mDecryptHandle != NULL) {
-        CHECK(mDrmManagerClient);
-        if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
-            sp<AMessage> msg = dupNotify();
-            msg->setInt32("what", kWhatDrmNoLicense);
-            msg->post();
-        }
-    }
-}
-
 int64_t NuPlayer::GenericSource::getLastReadPosition() {
     if (mAudioTrack.mSource != NULL) {
         return mAudioTimeUs;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 38d8616..a14056f 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -234,7 +234,6 @@
     void resetDataSource();
 
     status_t initFromDataSource();
-    void checkDrmStatus(const sp<DataSource>& dataSource);
     int64_t getLastReadPosition();
     void setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position);
 
diff --git a/media/liboboe/Android.bp b/media/liboboe/Android.bp
new file mode 100644
index 0000000..0d22e65
--- /dev/null
+++ b/media/liboboe/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+ndk_headers {
+    name: "libOboe_headers",
+    from: "include",
+    to: "",
+    srcs: ["include/oboe/*.h"],
+    license: "include/oboe/NOTICE",
+}
+
+ndk_library {
+    name: "liboboe.ndk",
+    symbol_file: "liboboe.map.txt",
+    first_version: "26",
+}
diff --git a/media/liboboe/Android.mk b/media/liboboe/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/media/liboboe/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/media/liboboe/include/oboe/NOTICE b/media/liboboe/include/oboe/NOTICE
new file mode 100644
index 0000000..d6c0922
--- /dev/null
+++ b/media/liboboe/include/oboe/NOTICE
@@ -0,0 +1,13 @@
+Copyright (C) 2016 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/media/liboboe/include/oboe/OboeAudio.h b/media/liboboe/include/oboe/OboeAudio.h
index 6804ce8..788cf5f 100644
--- a/media/liboboe/include/oboe/OboeAudio.h
+++ b/media/liboboe/include/oboe/OboeAudio.h
@@ -29,11 +29,14 @@
 typedef int32_t OboeDeviceId;
 typedef oboe_handle_t OboeStream;
 typedef oboe_handle_t OboeStreamBuilder;
-typedef oboe_handle_t OboeThread;
 
 #define OBOE_STREAM_NONE         ((OboeStream)OBOE_HANDLE_INVALID)
 #define OBOE_STREAM_BUILDER_NONE ((OboeStreamBuilder)OBOE_HANDLE_INVALID)
 
+/* OBOE_API will probably get defined in a Makefile for a specific platform. */
+#ifndef OBOE_API
+#define OBOE_API /* for exporting symbols */
+#endif
 
 // ============================================================
 // Audio System
@@ -42,7 +45,7 @@
 /**
  * @return time in the same clock domain as the timestamps
  */
-oboe_nanoseconds_t Oboe_getNanoseconds(oboe_clockid_t clockid);
+OBOE_API oboe_nanoseconds_t Oboe_getNanoseconds(oboe_clockid_t clockid);
 
 /**
  * The text is the ASCII symbol corresponding to the returnCode,
@@ -52,7 +55,7 @@
  *
  * @return pointer to a text representation of an Oboe result code.
  */
-const char * Oboe_convertResultToText(oboe_result_t returnCode);
+OBOE_API const char * Oboe_convertResultToText(oboe_result_t returnCode);
 
 /**
  * The text is the ASCII symbol corresponding to the stream state,
@@ -62,7 +65,7 @@
  *
  * @return pointer to a text representation of an Oboe state.
  */
-const char * Oboe_convertStreamStateToText(oboe_stream_state_t state);
+OBOE_API const char * Oboe_convertStreamStateToText(oboe_stream_state_t state);
 
 // ============================================================
 // StreamBuilder
@@ -80,7 +83,7 @@
  *
  * OboeStreamBuilder_delete() must be called when you are done using the builder.
  */
-oboe_result_t Oboe_createStreamBuilder(OboeStreamBuilder *builder);
+OBOE_API oboe_result_t Oboe_createStreamBuilder(OboeStreamBuilder *builder);
 
 /**
  * Request an audio device identified device using an ID.
@@ -91,7 +94,8 @@
  *
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStreamBuilder_setDeviceId(OboeStreamBuilder builder, OboeDeviceId deviceId);
+OBOE_API oboe_result_t OboeStreamBuilder_setDeviceId(OboeStreamBuilder builder,
+                                                     OboeDeviceId deviceId);
 
 /**
  * Request a sample rate in Hz.
@@ -106,14 +110,14 @@
  *
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStreamBuilder_setSampleRate(OboeStreamBuilder builder,
+OBOE_API oboe_result_t OboeStreamBuilder_setSampleRate(OboeStreamBuilder builder,
                                               oboe_sample_rate_t sampleRate);
 
 /**
  * Returns sample rate in Hertz (samples per second).
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStreamBuilder_getSampleRate(OboeStreamBuilder builder,
+OBOE_API oboe_result_t OboeStreamBuilder_getSampleRate(OboeStreamBuilder builder,
                                               oboe_sample_rate_t *sampleRate);
 
 
@@ -128,7 +132,7 @@
  *
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStreamBuilder_setSamplesPerFrame(OboeStreamBuilder builder,
+OBOE_API oboe_result_t OboeStreamBuilder_setSamplesPerFrame(OboeStreamBuilder builder,
                                                    int32_t samplesPerFrame);
 
 /**
@@ -138,7 +142,7 @@
  * @param samplesPerFrame pointer to a variable to be set to samplesPerFrame.
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStreamBuilder_getSamplesPerFrame(OboeStreamBuilder builder,
+OBOE_API oboe_result_t OboeStreamBuilder_getSamplesPerFrame(OboeStreamBuilder builder,
                                                    int32_t *samplesPerFrame);
 
 
@@ -148,12 +152,14 @@
  *
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStreamBuilder_setFormat(OboeStreamBuilder builder, oboe_audio_format_t format);
+OBOE_API oboe_result_t OboeStreamBuilder_setFormat(OboeStreamBuilder builder,
+                                                   oboe_audio_format_t format);
 
 /**
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStreamBuilder_getFormat(OboeStreamBuilder builder, oboe_audio_format_t *format);
+OBOE_API oboe_result_t OboeStreamBuilder_getFormat(OboeStreamBuilder builder,
+                                                   oboe_audio_format_t *format);
 
 /**
  * Request a mode for sharing the device.
@@ -164,15 +170,15 @@
  * @param sharingMode OBOE_SHARING_MODE_LEGACY or OBOE_SHARING_MODE_EXCLUSIVE
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStreamBuilder_setSharingMode(OboeStreamBuilder builder,
-                                               oboe_sharing_mode_t sharingMode);
+OBOE_API oboe_result_t OboeStreamBuilder_setSharingMode(OboeStreamBuilder builder,
+                                                        oboe_sharing_mode_t sharingMode);
 
 /**
  * Return requested sharing mode.
  * @return OBOE_OK or a negative error
  */
-oboe_result_t OboeStreamBuilder_getSharingMode(OboeStreamBuilder builder,
-                                               oboe_sharing_mode_t *sharingMode);
+OBOE_API oboe_result_t OboeStreamBuilder_getSharingMode(OboeStreamBuilder builder,
+                                                        oboe_sharing_mode_t *sharingMode);
 
 /**
  * Request the direction for a stream. The default is OBOE_DIRECTION_OUTPUT.
@@ -181,16 +187,16 @@
  * @param direction OBOE_DIRECTION_OUTPUT or OBOE_DIRECTION_INPUT
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStreamBuilder_setDirection(OboeStreamBuilder builder,
-                                             oboe_direction_t direction);
+OBOE_API oboe_result_t OboeStreamBuilder_setDirection(OboeStreamBuilder builder,
+                                                      oboe_direction_t direction);
 
 /**
  * @param builder handle provided by Oboe_createStreamBuilder()
  * @param direction pointer to a variable to be set to the currently requested direction.
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStreamBuilder_getDirection(OboeStreamBuilder builder,
-                                             oboe_direction_t *direction);
+OBOE_API oboe_result_t OboeStreamBuilder_getDirection(OboeStreamBuilder builder,
+                                                      oboe_direction_t *direction);
 
 /**
  * Open a stream based on the options in the StreamBuilder.
@@ -202,7 +208,8 @@
  * @param stream pointer to a variable to receive the new stream handle
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t  OboeStreamBuilder_openStream(OboeStreamBuilder builder, OboeStream *stream);
+OBOE_API oboe_result_t  OboeStreamBuilder_openStream(OboeStreamBuilder builder,
+                                                     OboeStream *stream);
 
 /**
  * Delete the resources associated with the StreamBuilder.
@@ -210,7 +217,7 @@
  * @param builder handle provided by Oboe_createStreamBuilder()
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t  OboeStreamBuilder_delete(OboeStreamBuilder builder);
+OBOE_API oboe_result_t  OboeStreamBuilder_delete(OboeStreamBuilder builder);
 
 // ============================================================
 // Stream Control
@@ -222,7 +229,7 @@
  * @param stream handle provided by OboeStreamBuilder_openStream()
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t  OboeStream_close(OboeStream stream);
+OBOE_API oboe_result_t  OboeStream_close(OboeStream stream);
 
 /**
  * Asynchronously request to start playing the stream. For output streams, one should
@@ -233,7 +240,7 @@
  * @param stream handle provided by OboeStreamBuilder_openStream()
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t  OboeStream_requestStart(OboeStream stream);
+OBOE_API oboe_result_t  OboeStream_requestStart(OboeStream stream);
 
 /**
  * Asynchronous request for the stream to pause.
@@ -244,7 +251,7 @@
  * @param stream handle provided by OboeStreamBuilder_openStream()
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t  OboeStream_requestPause(OboeStream stream);
+OBOE_API oboe_result_t  OboeStream_requestPause(OboeStream stream);
 
 /**
  * Asynchronous request for the stream to flush.
@@ -256,7 +263,7 @@
  * @param stream handle provided by OboeStreamBuilder_openStream()
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t  OboeStream_requestFlush(OboeStream stream);
+OBOE_API oboe_result_t  OboeStream_requestFlush(OboeStream stream);
 
 /**
  * Asynchronous request for the stream to stop.
@@ -266,7 +273,7 @@
  * @param stream handle provided by OboeStreamBuilder_openStream()
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t  OboeStream_requestStop(OboeStream stream);
+OBOE_API oboe_result_t  OboeStream_requestStop(OboeStream stream);
 
 /**
  * Query the current state, eg. OBOE_STREAM_STATE_PAUSING
@@ -275,7 +282,7 @@
  * @param state pointer to a variable that will be set to the current state
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_getState(OboeStream stream, oboe_stream_state_t *state);
+OBOE_API oboe_result_t OboeStream_getState(OboeStream stream, oboe_stream_state_t *state);
 
 /**
  * Wait until the current state no longer matches the input state.
@@ -295,7 +302,7 @@
  * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_waitForStateChange(OboeStream stream,
+OBOE_API oboe_result_t OboeStream_waitForStateChange(OboeStream stream,
                                             oboe_stream_state_t inputState,
                                             oboe_stream_state_t *nextState,
                                             oboe_nanoseconds_t timeoutNanoseconds);
@@ -322,9 +329,9 @@
  * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
  * @return The number of frames actually written or a negative error.
  */
-oboe_result_t OboeStream_read(OboeStream stream,
+OBOE_API oboe_result_t OboeStream_read(OboeStream stream,
                                void *buffer,
-                               int32_t numFrames,
+                               oboe_size_frames_t numFrames,
                                oboe_nanoseconds_t timeoutNanoseconds);
 
 /**
@@ -345,9 +352,9 @@
  * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
  * @return The number of frames actually written or a negative error.
  */
-oboe_result_t OboeStream_write(OboeStream stream,
+OBOE_API oboe_result_t OboeStream_write(OboeStream stream,
                                const void *buffer,
-                               int32_t numFrames,
+                               oboe_size_frames_t numFrames,
                                oboe_nanoseconds_t timeoutNanoseconds);
 
 
@@ -356,31 +363,33 @@
 // ============================================================
 
 /**
- * Create a thread with special properties for low latency audio performance.
- * This thread can be used to implement a callback API.
+ * Create a thread associated with a stream. The thread has special properties for
+ * low latency audio performance. This thread can be used to implement a callback API.
+ *
+ * Only one thread may be associated with a stream.
  *
  * Note that this API is in flux.
  *
- * @param threadHandlePtr a pointer to receive a thread handle
+ * @param stream A stream created using OboeStreamBuilder_openStream().
  * @param periodNanoseconds the estimated period at which the audio thread will need to wake up
  * @param start_routine your thread entry point
  * @param arg an argument that will be passed to your thread entry point
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t Oboe_createAudioThread(OboeThread *threadHandlePtr,
+OBOE_API oboe_result_t OboeStream_createThread(OboeStream stream,
                                      oboe_nanoseconds_t periodNanoseconds,
-                                     void *(*start_routine)(void *), void *arg);
+                                     void *(*startRoutine)(void *), void *arg);
 
 /**
  * Wait until the thread exits or an error occurs.
  * The thread handle will be deleted.
  *
- * @param thread the thread handle passed back from Oboe_createAudioThread()
+ * @param stream A stream created using OboeStreamBuilder_openStream().
  * @param returnArg a pointer to a variable to receive the return value
  * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t Oboe_joinAudioThread(OboeThread thread,
+OBOE_API oboe_result_t OboeStream_joinThread(OboeStream stream,
                                    void **returnArg,
                                    oboe_nanoseconds_t timeoutNanoseconds);
 
@@ -398,10 +407,13 @@
  * This cannot be set higher than OboeStream_getBufferCapacity().
  *
  * @param stream handle provided by OboeStreamBuilder_openStream()
- * @param frames requested number of frames that can be filled without blocking
- * @return actual number of frames or a negative error
+ * @param requestedFrames requested number of frames that can be filled without blocking
+ * @return actualFrames receives final number of frames
+ * @return OBOE_OK or a negative error
  */
-oboe_result_t OboeStream_setBufferSize(OboeStream stream, oboe_size_frames_t frames);
+OBOE_API oboe_result_t OboeStream_setBufferSize(OboeStream stream,
+                                                oboe_size_frames_t requestedFrames,
+                                                oboe_size_frames_t *actualFrames);
 
 /**
  * Query the maximum number of frames that can be filled without blocking.
@@ -410,7 +422,7 @@
  * @param frames pointer to variable to receive the buffer size
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_getBufferSize(OboeStream stream, oboe_size_frames_t *frames);
+OBOE_API oboe_result_t OboeStream_getBufferSize(OboeStream stream, oboe_size_frames_t *frames);
 
 /**
  * Query the number of frames that are read or written by the endpoint at one time.
@@ -419,7 +431,7 @@
  * @param frames pointer to variable to receive the burst size
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_getFramesPerBurst(OboeStream stream, oboe_size_frames_t *frames);
+OBOE_API oboe_result_t OboeStream_getFramesPerBurst(OboeStream stream, oboe_size_frames_t *frames);
 
 /**
  * Query maximum buffer capacity in frames.
@@ -428,7 +440,7 @@
  * @param frames pointer to variable to receive the buffer capacity
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_getBufferCapacity(OboeStream stream, oboe_size_frames_t *frames);
+OBOE_API oboe_result_t OboeStream_getBufferCapacity(OboeStream stream, oboe_size_frames_t *frames);
 
 /**
  * An XRun is an Underrun or an Overrun.
@@ -443,14 +455,14 @@
  * @param xRunCount pointer to variable to receive the underrun or overrun count
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_getXRunCount(OboeStream stream, int32_t *xRunCount);
+OBOE_API oboe_result_t OboeStream_getXRunCount(OboeStream stream, int32_t *xRunCount);
 
 /**
  * @param stream handle provided by OboeStreamBuilder_openStream()
  * @param sampleRate pointer to variable to receive the actual sample rate
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_getSampleRate(OboeStream stream, int32_t *sampleRate);
+OBOE_API oboe_result_t OboeStream_getSampleRate(OboeStream stream, oboe_sample_rate_t *sampleRate);
 
 /**
  * The samplesPerFrame is also known as channelCount.
@@ -459,14 +471,14 @@
  * @param samplesPerFrame pointer to variable to receive the actual samples per frame
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_getSamplesPerFrame(OboeStream stream, int32_t *samplesPerFrame);
+OBOE_API oboe_result_t OboeStream_getSamplesPerFrame(OboeStream stream, int32_t *samplesPerFrame);
 
 /**
  * @param stream handle provided by OboeStreamBuilder_openStream()
  * @param format pointer to variable to receive the actual data format
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_getFormat(OboeStream stream, oboe_audio_format_t *format);
+OBOE_API oboe_result_t OboeStream_getFormat(OboeStream stream, oboe_audio_format_t *format);
 
 /**
  * Provide actual sharing mode.
@@ -474,7 +486,7 @@
  * @param sharingMode pointer to variable to receive the actual sharing mode
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_getSharingMode(OboeStream stream,
+OBOE_API oboe_result_t OboeStream_getSharingMode(OboeStream stream,
                                         oboe_sharing_mode_t *sharingMode);
 
 /**
@@ -482,7 +494,7 @@
  * @param direction pointer to a variable to be set to the current direction.
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_getDirection(OboeStream stream, uint32_t *direction);
+OBOE_API oboe_result_t OboeStream_getDirection(OboeStream stream, oboe_direction_t *direction);
 
 /**
  * Passes back the number of frames that have been written since the stream was created.
@@ -495,7 +507,8 @@
  * @param frames pointer to variable to receive the frames written
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_getFramesWritten(OboeStream stream, oboe_position_frames_t *frames);
+OBOE_API oboe_result_t OboeStream_getFramesWritten(OboeStream stream,
+                                                   oboe_position_frames_t *frames);
 
 /**
  * Passes back the number of frames that have been read since the stream was created.
@@ -508,7 +521,7 @@
  * @param frames pointer to variable to receive the frames written
  * @return OBOE_OK or a negative error.
  */
-oboe_result_t OboeStream_getFramesRead(OboeStream stream, oboe_position_frames_t *frames);
+OBOE_API oboe_result_t OboeStream_getFramesRead(OboeStream stream, oboe_position_frames_t *frames);
 
 /**
  * Passes back the time at which a particular frame was presented.
@@ -527,12 +540,12 @@
  * The position and time passed back are monotonically increasing.
  *
  * @param stream A handle provided by OboeStreamBuilder_openStream()
- * @param clockId OBOE_CLOCK_MONOTONIC or OBOE_CLOCK_BOOTTIME
+ * @param clockid OBOE_CLOCK_MONOTONIC or OBOE_CLOCK_BOOTTIME
  * @param framePosition pointer to a variable to receive the position
  * @param timeNanoseconds pointer to a variable to receive the time
  * @return OBOE_OK or a negative error
  */
-oboe_result_t OboeStream_getTimestamp(OboeStream stream,
+OBOE_API oboe_result_t OboeStream_getTimestamp(OboeStream stream,
                                       oboe_clockid_t clockid,
                                       oboe_position_frames_t *framePosition,
                                       oboe_nanoseconds_t *timeNanoseconds);
diff --git a/media/liboboe/include/oboe/OboeDefinitions.h b/media/liboboe/include/oboe/OboeDefinitions.h
index 79fef3a..d80c958 100644
--- a/media/liboboe/include/oboe/OboeDefinitions.h
+++ b/media/liboboe/include/oboe/OboeDefinitions.h
@@ -28,7 +28,10 @@
 typedef int32_t  oboe_sample_rate_t;
 /** This is used for small quantities such as the number of frames in a buffer. */
 typedef int32_t  oboe_size_frames_t;
-/** This is used for large quantities, such as the number of frames that have
+/** This is used for small quantities such as the number of bytes in a frame. */
+typedef int32_t  oboe_size_bytes_t;
+/**
+ * This is used for large quantities, such as the number of frames that have
  * been played since a stream was started.
  * At 48000 Hz, a 32-bit integer would wrap around in just over 12 hours.
  */
@@ -85,7 +88,8 @@
 
 /**
  * Fields packed into oboe_audio_format_t, from most to least significant bits.
- *   Reserved:8
+ *   Invalid:1
+ *   Reserved:7
  *   Wrapper:8
  *   Content:8
  *   Data Type:8
@@ -97,7 +101,7 @@
                 OBOE_AUDIO_FORMAT(dataType, content, OBOE_AUDIO_WRAPPER_NONE)
 
 #define OBOE_AUDIO_FORMAT_DATA_TYPE(format) \
-    (format & 0x0FF)
+    ((oboe_datatype_t)(format & 0x0FF))
 
 // Define some common formats.
 #define OBOE_AUDIO_FORMAT_PCM16  \
@@ -106,6 +110,9 @@
                 OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_FLOAT32, OBOE_AUDIO_CONTENT_PCM)
 #define OBOE_AUDIO_FORMAT_PCM824 \
                 OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_INT824, OBOE_AUDIO_CONTENT_PCM)
+#define OBOE_AUDIO_FORMAT_PCM32 \
+                OBOE_AUDIO_FORMAT_RAW(OBOE_AUDIO_DATATYPE_INT32, OBOE_AUDIO_CONTENT_PCM)
+#define OBOE_AUDIO_FORMAT_INVALID ((oboe_audio_format_t)-1)
 
 enum {
     OBOE_OK,
@@ -126,7 +133,8 @@
     OBOE_ERROR_NULL,
     OBOE_ERROR_TIMEOUT,
     OBOE_ERROR_WOULD_BLOCK,
-    OBOE_ERROR_INVALID_ORDER
+    OBOE_ERROR_INVALID_ORDER,
+    OBOE_ERROR_OUT_OF_RANGE
 };
 
 typedef enum {
diff --git a/media/liboboe/liboboe.map.txt b/media/liboboe/liboboe.map.txt
new file mode 100644
index 0000000..229038f
--- /dev/null
+++ b/media/liboboe/liboboe.map.txt
@@ -0,0 +1,46 @@
+LIBOBOE {
+  global:
+    Oboe_getNanoseconds;
+    Oboe_convertResultToText;
+    Oboe_convertStreamStateToText;
+    Oboe_createStreamBuilder;
+    OboeStreamBuilder_setDeviceId;
+    OboeStreamBuilder_setSampleRate;
+    OboeStreamBuilder_getSampleRate;
+    OboeStreamBuilder_setSamplesPerFrame;
+    OboeStreamBuilder_getSamplesPerFrame;
+    OboeStreamBuilder_setFormat;
+    OboeStreamBuilder_getFormat;
+    OboeStreamBuilder_setSharingMode;
+    OboeStreamBuilder_getSharingMode;
+    OboeStreamBuilder_setDirection;
+    OboeStreamBuilder_getDirection;
+    OboeStreamBuilder_openStream;
+    OboeStreamBuilder_delete;
+    OboeStream_close;
+    OboeStream_requestStart;
+    OboeStream_requestPause;
+    OboeStream_requestFlush;
+    OboeStream_requestStop;
+    OboeStream_getState;
+    OboeStream_waitForStateChange;
+    OboeStream_read;
+    OboeStream_write;
+    Oboe_createAudioThread;
+    Oboe_joinAudioThread;
+    OboeStream_setBufferSize;
+    OboeStream_getBufferSize;
+    OboeStream_getFramesPerBurst;
+    OboeStream_getBufferCapacity;
+    OboeStream_getXRunCount;
+    OboeStream_getSampleRate;
+    OboeStream_getSamplesPerFrame;
+    OboeStream_getFormat;
+    OboeStream_getSharingMode;
+    OboeStream_getDirection;
+    OboeStream_getFramesWritten;
+    OboeStream_getFramesRead;
+    OboeStream_getTimestamp;
+  local:
+    *;
+};
diff --git a/media/liboboe/src/Android.mk b/media/liboboe/src/Android.mk
new file mode 100644
index 0000000..7b9a906
--- /dev/null
+++ b/media/liboboe/src/Android.mk
@@ -0,0 +1,70 @@
+LOCAL_PATH:= $(call my-dir)
+
+# ======================= STATIC LIBRARY ==========================
+# This is being built because it make Oboe testing very easy with a complete executable.
+# TODO Remove this target later, when not needed.
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := liboboe
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/native/include \
+    system/core/base/include \
+    frameworks/native/media/liboboe/include/include \
+    frameworks/av/media/liboboe/include \
+    $(LOCAL_PATH)/core \
+    $(LOCAL_PATH)/utility \
+    $(LOCAL_PATH)/legacy
+
+LOCAL_SRC_FILES += core/AudioStream.cpp
+LOCAL_SRC_FILES += core/AudioStreamBuilder.cpp
+LOCAL_SRC_FILES += core/OboeAudio.cpp
+LOCAL_SRC_FILES += legacy/AudioStreamRecord.cpp
+LOCAL_SRC_FILES += legacy/AudioStreamTrack.cpp
+LOCAL_SRC_FILES += utility/HandleTracker.cpp
+LOCAL_SRC_FILES += utility/OboeUtilities.cpp
+
+LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_CFLAGS += -Wall -Werror
+# By default, all symbols are hidden.
+LOCAL_CFLAGS += -fvisibility=hidden
+# OBOE_API is used to explicitly export a function or a variable as a visible symbol.
+LOCAL_CFLAGS += -DOBOE_API='__attribute__((visibility("default")))'
+
+include $(BUILD_STATIC_LIBRARY)
+
+# ======================= SHARED LIBRARY ==========================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := liboboe
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/native/include \
+    system/core/base/include \
+    frameworks/native/media/liboboe/include/include \
+    frameworks/av/media/liboboe/include \
+    $(LOCAL_PATH)/core \
+    $(LOCAL_PATH)/utility \
+    $(LOCAL_PATH)/legacy
+
+LOCAL_SRC_FILES += core/AudioStream.cpp
+LOCAL_SRC_FILES += core/AudioStreamBuilder.cpp
+LOCAL_SRC_FILES += core/OboeAudio.cpp
+LOCAL_SRC_FILES += legacy/AudioStreamRecord.cpp
+LOCAL_SRC_FILES += legacy/AudioStreamTrack.cpp
+LOCAL_SRC_FILES += utility/HandleTracker.cpp
+LOCAL_SRC_FILES += utility/OboeUtilities.cpp
+
+LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_CFLAGS += -Wall -Werror
+# By default, all symbols are hidden.
+LOCAL_CFLAGS += -fvisibility=hidden
+# OBOE_API is used to explicitly export a function or a variable as a visible symbol.
+LOCAL_CFLAGS += -DOBOE_API='__attribute__((visibility("default")))'
+
+LOCAL_SHARED_LIBRARIES := libaudioclient liblog libutils
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/liboboe/src/core/AudioStream.cpp b/media/liboboe/src/core/AudioStream.cpp
new file mode 100644
index 0000000..f154002
--- /dev/null
+++ b/media/liboboe/src/core/AudioStream.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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 "OboeAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <oboe/OboeAudio.h>
+
+#include "AudioStreamBuilder.h"
+#include "AudioStream.h"
+#include "AudioClock.h"
+
+using namespace oboe;
+
+/*
+ * AudioStream
+ */
+AudioStream::AudioStream() {
+}
+
+oboe_result_t AudioStream::open(const AudioStreamBuilder& builder)
+{
+    // TODO validate parameters.
+    // Copy parameters from the Builder because the Builder may be deleted after this call.
+    mSamplesPerFrame = builder.getSamplesPerFrame();
+    mSampleRate = builder.getSampleRate();
+    mDeviceId = builder.getDeviceId();
+    mFormat = builder.getFormat();
+    mSharingMode = builder.getSharingMode();
+    return OBOE_OK;
+}
+
+AudioStream::~AudioStream() {
+    close();
+}
+
+oboe_result_t AudioStream::waitForStateTransition(oboe_stream_state_t startingState,
+                                               oboe_stream_state_t endingState,
+                                               oboe_nanoseconds_t timeoutNanoseconds)
+{
+    oboe_stream_state_t state = getState();
+    oboe_stream_state_t nextState = state;
+    if (state == startingState && state != endingState) {
+        oboe_result_t result = waitForStateChange(state, &nextState, timeoutNanoseconds);
+        if (result != OBOE_OK) {
+            return result;
+        }
+    }
+// It's OK if the expected transition has already occurred.
+// But if we reach an unexpected state then that is an error.
+    if (nextState != endingState) {
+        return OBOE_ERROR_UNEXPECTED_STATE;
+    } else {
+        return OBOE_OK;
+    }
+}
+
+oboe_result_t AudioStream::waitForStateChange(oboe_stream_state_t currentState,
+                                                oboe_stream_state_t *nextState,
+                                                oboe_nanoseconds_t timeoutNanoseconds)
+{
+    // TODO replace this when similar functionality added to AudioTrack.cpp
+    oboe_nanoseconds_t durationNanos = 20 * OBOE_NANOS_PER_MILLISECOND;
+    oboe_stream_state_t state = getState();
+    while (state == currentState && timeoutNanoseconds > 0) {
+        if (durationNanos > timeoutNanoseconds) {
+            durationNanos = timeoutNanoseconds;
+        }
+        AudioClock::sleepForNanos(durationNanos);
+        timeoutNanoseconds -= durationNanos;
+
+        oboe_result_t result = updateState();
+        if (result != OBOE_OK) {
+            return result;
+        }
+
+        state = getState();
+    }
+    if (nextState != NULL) {
+        *nextState = state;
+    }
+    return (state == currentState) ? OBOE_ERROR_TIMEOUT : OBOE_OK;
+}
+
+oboe_result_t AudioStream::createThread(oboe_nanoseconds_t periodNanoseconds,
+                                     void *(*startRoutine)(void *), void *arg)
+{
+    if (mHasThread) {
+        return OBOE_ERROR_INVALID_STATE;
+    }
+    if (startRoutine == NULL) {
+        return OBOE_ERROR_NULL;
+    }
+    int err = pthread_create(&mThread, NULL, startRoutine, arg);
+    if (err != 0) {
+        return OBOE_ERROR_INTERNAL;
+    } else {
+        mHasThread = true;
+        return OBOE_OK;
+    }
+}
+
+oboe_result_t AudioStream::joinThread(void **returnArg, oboe_nanoseconds_t timeoutNanoseconds)
+{
+    if (!mHasThread) {
+        return OBOE_ERROR_INVALID_STATE;
+    }
+#if 0
+    // TODO implement equivalent of pthread_timedjoin_np()
+    struct timespec abstime;
+    int err = pthread_timedjoin_np(mThread, returnArg, &abstime);
+#else
+    int err = pthread_join(mThread, returnArg);
+#endif
+    mHasThread = false;
+    // TODO Just leaked a thread?
+    return err ? OBOE_ERROR_INTERNAL : OBOE_OK;
+}
+
diff --git a/media/liboboe/src/core/AudioStream.h b/media/liboboe/src/core/AudioStream.h
new file mode 100644
index 0000000..9cb9b1b
--- /dev/null
+++ b/media/liboboe/src/core/AudioStream.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OBOE_AUDIOSTREAM_H
+#define OBOE_AUDIOSTREAM_H
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <oboe/OboeAudio.h>
+#include "OboeUtilities.h"
+#include "MonotonicCounter.h"
+
+namespace oboe {
+
+class AudioStreamBuilder;
+
+/**
+ * Oboe audio stream.
+ */
+class AudioStream {
+public:
+
+    AudioStream();
+
+    virtual ~AudioStream();
+
+
+    // =========== Begin ABSTRACT methods ===========================
+
+    /* Asynchronous requests.
+     * Use waitForStateChange() to wait for completion.
+     */
+    virtual oboe_result_t requestStart() = 0;
+    virtual oboe_result_t requestPause() = 0;
+    virtual oboe_result_t requestFlush() = 0;
+    virtual oboe_result_t requestStop() = 0;
+
+    // TODO use oboe_clockid_t all the way down to AudioClock
+    virtual oboe_result_t getTimestamp(clockid_t clockId,
+                                       oboe_position_frames_t *framePosition,
+                                       oboe_nanoseconds_t *timeNanoseconds) = 0;
+
+
+    virtual oboe_result_t updateState() = 0;
+
+
+    // =========== End ABSTRACT methods ===========================
+
+    virtual oboe_result_t waitForStateChange(oboe_stream_state_t currentState,
+                                          oboe_stream_state_t *nextState,
+                                          oboe_nanoseconds_t timeoutNanoseconds);
+
+    /**
+     * Open the stream using the parameters in the builder.
+     * Allocate the necessary resources.
+     */
+    virtual oboe_result_t open(const AudioStreamBuilder& builder);
+
+    /**
+     * Close the stream and deallocate any resources from the open() call.
+     * It is safe to call close() multiple times.
+     */
+    virtual oboe_result_t close() {
+        return OBOE_OK;
+    }
+
+    virtual oboe_result_t setBufferSize(oboe_size_frames_t requestedFrames,
+                                        oboe_size_frames_t *actualFrames) {
+        return OBOE_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual oboe_result_t createThread(oboe_nanoseconds_t periodNanoseconds,
+                                     void *(*start_routine)(void *), void *arg);
+
+    virtual oboe_result_t joinThread(void **returnArg, oboe_nanoseconds_t timeoutNanoseconds);
+
+    // ============== Queries ===========================
+
+    virtual oboe_stream_state_t getState() const {
+        return mState;
+    }
+
+    virtual oboe_size_frames_t getBufferSize() const {
+        return OBOE_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual oboe_size_frames_t getBufferCapacity() const {
+        return OBOE_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual oboe_size_frames_t getFramesPerBurst() const {
+        return OBOE_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual int32_t getXRunCount() const {
+        return OBOE_ERROR_UNIMPLEMENTED;
+    }
+
+    bool isPlaying() const {
+        return mState == OBOE_STREAM_STATE_STARTING || mState == OBOE_STREAM_STATE_STARTED;
+    }
+
+    oboe_result_t getSampleRate() const {
+        return mSampleRate;
+    }
+
+    oboe_audio_format_t getFormat()  const {
+        return mFormat;
+    }
+
+    oboe_result_t getSamplesPerFrame() const {
+        return mSamplesPerFrame;
+    }
+
+    OboeDeviceId getDeviceId() const {
+        return mDeviceId;
+    }
+
+    oboe_sharing_mode_t getSharingMode() const {
+        return mSharingMode;
+    }
+
+    oboe_direction_t getDirection() const {
+        return mDirection;
+    }
+
+    oboe_size_bytes_t getBytesPerFrame() const {
+        return mSamplesPerFrame * getBytesPerSample();
+    }
+
+    oboe_size_bytes_t getBytesPerSample() const {
+        return OboeConvert_formatToSizeInBytes(mFormat);
+    }
+
+    virtual oboe_position_frames_t getFramesWritten() {
+        return mFramesWritten.get();
+    }
+
+    virtual oboe_position_frames_t getFramesRead() {
+        return mFramesRead.get();
+    }
+
+
+    // ============== I/O ===========================
+    // A Stream will only implement read() or write() depending on its direction.
+    virtual oboe_result_t write(const void *buffer,
+                             oboe_size_frames_t numFrames,
+                             oboe_nanoseconds_t timeoutNanoseconds) {
+        return OBOE_ERROR_UNIMPLEMENTED;
+    }
+
+    virtual oboe_result_t read(void *buffer,
+                            oboe_size_frames_t numFrames,
+                            oboe_nanoseconds_t timeoutNanoseconds) {
+        return OBOE_ERROR_UNIMPLEMENTED;
+    }
+
+protected:
+
+    virtual oboe_position_frames_t incrementFramesWritten(oboe_size_frames_t frames) {
+        return static_cast<oboe_position_frames_t>(mFramesWritten.increment(frames));
+    }
+
+    virtual oboe_position_frames_t incrementFramesRead(oboe_size_frames_t frames) {
+        return static_cast<oboe_position_frames_t>(mFramesRead.increment(frames));
+    }
+
+    /**
+     * Wait for a transition from one state to another.
+     * @return OBOE_OK if the endingState was observed, or OBOE_ERROR_UNEXPECTED_STATE
+     *   if any state that was not the startingState or endingState was observed
+     *   or OBOE_ERROR_TIMEOUT
+     */
+    virtual oboe_result_t waitForStateTransition(oboe_stream_state_t startingState,
+                                              oboe_stream_state_t endingState,
+                                              oboe_nanoseconds_t timeoutNanoseconds);
+
+    /**
+     * This should not be called after the open() call.
+     */
+    void setSampleRate(oboe_sample_rate_t sampleRate) {
+        mSampleRate = sampleRate;
+    }
+
+    /**
+     * This should not be called after the open() call.
+     */
+    void setSamplesPerFrame(int32_t samplesPerFrame) {
+        mSamplesPerFrame = samplesPerFrame;
+    }
+
+    /**
+     * This should not be called after the open() call.
+     */
+    void setSharingMode(oboe_sharing_mode_t sharingMode) {
+        mSharingMode = sharingMode;
+    }
+
+    /**
+     * This should not be called after the open() call.
+     */
+    void setFormat(oboe_audio_format_t format) {
+        mFormat = format;
+    }
+
+    void setState(oboe_stream_state_t state) {
+        mState = state;
+    }
+
+    MonotonicCounter     mFramesWritten;
+    MonotonicCounter     mFramesRead;
+
+private:
+    // These do not change after open().
+    int32_t              mSamplesPerFrame = OBOE_UNSPECIFIED;
+    oboe_sample_rate_t   mSampleRate = OBOE_UNSPECIFIED;
+    oboe_stream_state_t  mState = OBOE_STREAM_STATE_UNINITIALIZED;
+    OboeDeviceId         mDeviceId = OBOE_UNSPECIFIED;
+    oboe_sharing_mode_t  mSharingMode = OBOE_SHARING_MODE_LEGACY;
+    oboe_audio_format_t  mFormat = OBOE_UNSPECIFIED;
+    oboe_direction_t     mDirection = OBOE_DIRECTION_OUTPUT;
+
+    bool                 mHasThread;
+    pthread_t            mThread;
+};
+
+} /* namespace oboe */
+
+#endif /* OBOE_AUDIOSTREAM_H */
diff --git a/media/liboboe/src/core/AudioStreamBuilder.cpp b/media/liboboe/src/core/AudioStreamBuilder.cpp
new file mode 100644
index 0000000..56e6706
--- /dev/null
+++ b/media/liboboe/src/core/AudioStreamBuilder.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 "OboeAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include "AudioStream.h"
+#include "AudioStreamBuilder.h"
+#include "AudioStreamRecord.h"
+#include "AudioStreamTrack.h"
+
+using namespace oboe;
+
+/*
+ * AudioStreamBuilder
+ */
+AudioStreamBuilder::AudioStreamBuilder() {
+}
+
+AudioStreamBuilder::~AudioStreamBuilder() {
+}
+
+oboe_result_t AudioStreamBuilder::build(AudioStream **streamPtr) {
+    // TODO Is there a better place to put the code that decides which class to use?
+    AudioStream *audioStream = nullptr;
+    const oboe_sharing_mode_t sharingMode = getSharingMode();
+    switch (getDirection()) {
+    case OBOE_DIRECTION_INPUT:
+        switch (sharingMode) {
+            case OBOE_SHARING_MODE_LEGACY:
+                audioStream = new AudioStreamRecord();
+                break;
+            default:
+                ALOGE("AudioStreamBuilder(): bad sharing mode = %d", sharingMode);
+                return OBOE_ERROR_ILLEGAL_ARGUMENT;
+                break;
+        }
+        break;
+    case OBOE_DIRECTION_OUTPUT:
+        switch (sharingMode) {
+            case OBOE_SHARING_MODE_LEGACY:
+                audioStream = new AudioStreamTrack();
+                break;
+            default:
+                ALOGE("AudioStreamBuilder(): bad sharing mode = %d", sharingMode);
+                return OBOE_ERROR_ILLEGAL_ARGUMENT;
+                break;
+        }
+        break;
+    default:
+        ALOGE("AudioStreamBuilder(): bad direction = %d", getDirection());
+        return OBOE_ERROR_ILLEGAL_ARGUMENT;
+        break;
+    }
+    if (audioStream == nullptr) {
+        return OBOE_ERROR_NO_MEMORY;
+    }
+    ALOGD("AudioStreamBuilder(): created audioStream = %p", audioStream);
+
+    // TODO maybe move this out of build and pass the builder to the constructors
+    // Open the stream using the parameters from the builder.
+    const oboe_result_t result = audioStream->open(*this);
+    if (result != OBOE_OK) {
+        delete audioStream;
+    } else {
+        *streamPtr = audioStream;
+    }
+    return result;
+}
diff --git a/media/liboboe/src/core/AudioStreamBuilder.h b/media/liboboe/src/core/AudioStreamBuilder.h
new file mode 100644
index 0000000..3f98ebb
--- /dev/null
+++ b/media/liboboe/src/core/AudioStreamBuilder.h
@@ -0,0 +1,104 @@
+/*
+ * 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 OBOE_AUDIOSTREAMBUILDER_H
+#define OBOE_AUDIOSTREAMBUILDER_H
+
+#include <oboe/OboeAudio.h>
+#include "AudioStream.h"
+
+namespace oboe {
+
+/**
+ * Factory class for an AudioStream.
+ */
+class AudioStreamBuilder {
+public:
+    AudioStreamBuilder();
+
+    ~AudioStreamBuilder();
+
+    int getSamplesPerFrame() const {
+        return mSamplesPerFrame;
+    }
+
+    /**
+     * This is also known as channelCount.
+     */
+    AudioStreamBuilder *setSamplesPerFrame(int samplesPerFrame) {
+        mSamplesPerFrame = samplesPerFrame;
+        return this;
+    }
+
+    oboe_direction_t getDirection() const {
+        return mDirection;
+    }
+
+    AudioStreamBuilder *setDirection(oboe_direction_t direction) {
+        mDirection = direction;
+        return this;
+    }
+
+    oboe_sample_rate_t getSampleRate() const {
+        return mSampleRate;
+    }
+
+    AudioStreamBuilder *setSampleRate(oboe_sample_rate_t sampleRate) {
+        mSampleRate = sampleRate;
+        return this;
+    }
+
+    oboe_audio_format_t getFormat() const {
+        return mFormat;
+    }
+
+    AudioStreamBuilder *setFormat(oboe_audio_format_t format) {
+        mFormat = format;
+        return this;
+    }
+
+    oboe_sharing_mode_t getSharingMode() const {
+        return mSharingMode;
+    }
+
+    AudioStreamBuilder *setSharingMode(oboe_sharing_mode_t sharingMode) {
+        mSharingMode = sharingMode;
+        return this;
+    }
+
+    OboeDeviceId getDeviceId() const {
+        return mDeviceId;
+    }
+
+    AudioStreamBuilder *setDeviceId(OboeDeviceId deviceId) {
+        mDeviceId = deviceId;
+        return this;
+    }
+
+    oboe_result_t build(AudioStream **streamPtr);
+
+private:
+    int32_t              mSamplesPerFrame = OBOE_UNSPECIFIED;
+    oboe_sample_rate_t   mSampleRate = OBOE_UNSPECIFIED;
+    OboeDeviceId         mDeviceId = OBOE_UNSPECIFIED; // TODO need better default
+    oboe_sharing_mode_t  mSharingMode = OBOE_SHARING_MODE_LEGACY;
+    oboe_audio_format_t  mFormat = OBOE_UNSPECIFIED;
+    oboe_direction_t     mDirection = OBOE_DIRECTION_OUTPUT;
+};
+
+} /* namespace oboe */
+
+#endif /* OBOE_AUDIOSTREAMBUILDER_H */
diff --git a/media/liboboe/src/core/OboeAudio.cpp b/media/liboboe/src/core/OboeAudio.cpp
new file mode 100644
index 0000000..a02f226
--- /dev/null
+++ b/media/liboboe/src/core/OboeAudio.cpp
@@ -0,0 +1,555 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OboeAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <time.h>
+#include <pthread.h>
+
+#include <oboe/OboeDefinitions.h>
+#include <oboe/OboeAudio.h>
+#include "AudioStreamBuilder.h"
+#include "AudioStream.h"
+#include "AudioClock.h"
+#include "HandleTracker.h"
+
+// temporary, as I stage in the MMAP/NOIRQ support, do not review
+#ifndef OBOE_SUPPORT_MMAP
+#define OBOE_SUPPORT_MMAP 0
+#endif
+
+#if OBOE_SUPPORT_MMAP
+#include "AudioStreamInternal.h"
+#include "OboeServiceGateway.h"
+#endif
+
+using namespace oboe;
+
+// This is not the maximum theoretic possible number of handles that the HandlerTracker
+// class could support; instead it is the maximum number of handles that we are configuring
+// for our HandleTracker instance (sHandleTracker).
+#define OBOE_MAX_HANDLES  64
+
+// Macros for common code that includes a return.
+// TODO Consider using do{}while(0) construct. I tried but it hung AndroidStudio
+#define CONVERT_BUILDER_HANDLE_OR_RETURN() \
+    convertOboeBuilderToStreamBuilder(builder); \
+    if (streamBuilder == nullptr) { \
+        return OBOE_ERROR_INVALID_HANDLE; \
+    }
+
+#define COMMON_GET_FROM_BUILDER_OR_RETURN(resultPtr) \
+    CONVERT_BUILDER_HANDLE_OR_RETURN() \
+    if ((resultPtr) == nullptr) { \
+        return OBOE_ERROR_NULL; \
+    }
+
+#define CONVERT_STREAM_HANDLE_OR_RETURN() \
+    convertOboeStreamToAudioStream(stream); \
+    if (audioStream == nullptr) { \
+        return OBOE_ERROR_INVALID_HANDLE; \
+    }
+
+#define COMMON_GET_FROM_STREAM_OR_RETURN(resultPtr) \
+    CONVERT_STREAM_HANDLE_OR_RETURN(); \
+    if ((resultPtr) == nullptr) { \
+        return OBOE_ERROR_NULL; \
+    }
+
+static HandleTracker sHandleTracker(OBOE_MAX_HANDLES);
+
+typedef enum
+{
+    OBOE_HANDLE_TYPE_STREAM,
+    OBOE_HANDLE_TYPE_STREAM_BUILDER,
+    OBOE_HANDLE_TYPE_COUNT
+} oboe_handle_type_t;
+static_assert(OBOE_HANDLE_TYPE_COUNT <= HANDLE_TRACKER_MAX_TYPES, "Too many handle types.");
+
+#if OBOE_SUPPORT_MMAP
+static OboeServiceGateway sOboeServiceGateway;
+#endif
+
+#define OBOE_CASE_ENUM(name) case name: return #name
+
+OBOE_API const char * Oboe_convertResultToText(oboe_result_t returnCode) {
+    switch (returnCode) {
+        OBOE_CASE_ENUM(OBOE_OK);
+        OBOE_CASE_ENUM(OBOE_ERROR_ILLEGAL_ARGUMENT);
+        OBOE_CASE_ENUM(OBOE_ERROR_INCOMPATIBLE);
+        OBOE_CASE_ENUM(OBOE_ERROR_INTERNAL);
+        OBOE_CASE_ENUM(OBOE_ERROR_INVALID_STATE);
+        OBOE_CASE_ENUM(OBOE_ERROR_INVALID_HANDLE);
+        OBOE_CASE_ENUM(OBOE_ERROR_INVALID_QUERY);
+        OBOE_CASE_ENUM(OBOE_ERROR_UNIMPLEMENTED);
+        OBOE_CASE_ENUM(OBOE_ERROR_UNAVAILABLE);
+        OBOE_CASE_ENUM(OBOE_ERROR_NO_FREE_HANDLES);
+        OBOE_CASE_ENUM(OBOE_ERROR_NO_MEMORY);
+        OBOE_CASE_ENUM(OBOE_ERROR_NULL);
+        OBOE_CASE_ENUM(OBOE_ERROR_TIMEOUT);
+        OBOE_CASE_ENUM(OBOE_ERROR_WOULD_BLOCK);
+        OBOE_CASE_ENUM(OBOE_ERROR_INVALID_ORDER);
+        OBOE_CASE_ENUM(OBOE_ERROR_OUT_OF_RANGE);
+    }
+    return "Unrecognized Oboe error.";
+}
+
+OBOE_API const char * Oboe_convertStreamStateToText(oboe_stream_state_t state) {
+    switch (state) {
+        OBOE_CASE_ENUM(OBOE_STREAM_STATE_UNINITIALIZED);
+        OBOE_CASE_ENUM(OBOE_STREAM_STATE_OPEN);
+        OBOE_CASE_ENUM(OBOE_STREAM_STATE_STARTING);
+        OBOE_CASE_ENUM(OBOE_STREAM_STATE_STARTED);
+        OBOE_CASE_ENUM(OBOE_STREAM_STATE_PAUSING);
+        OBOE_CASE_ENUM(OBOE_STREAM_STATE_PAUSED);
+        OBOE_CASE_ENUM(OBOE_STREAM_STATE_FLUSHING);
+        OBOE_CASE_ENUM(OBOE_STREAM_STATE_FLUSHED);
+        OBOE_CASE_ENUM(OBOE_STREAM_STATE_STOPPING);
+        OBOE_CASE_ENUM(OBOE_STREAM_STATE_STOPPED);
+        OBOE_CASE_ENUM(OBOE_STREAM_STATE_CLOSING);
+        OBOE_CASE_ENUM(OBOE_STREAM_STATE_CLOSED);
+    }
+    return "Unrecognized Oboe state.";
+}
+
+#undef OBOE_CASE_ENUM
+
+static AudioStream *convertOboeStreamToAudioStream(OboeStream stream)
+{
+    return (AudioStream *) sHandleTracker.get(OBOE_HANDLE_TYPE_STREAM,
+                                              (oboe_handle_t) stream);
+}
+
+static AudioStreamBuilder *convertOboeBuilderToStreamBuilder(OboeStreamBuilder builder)
+{
+    return (AudioStreamBuilder *) sHandleTracker.get(OBOE_HANDLE_TYPE_STREAM_BUILDER,
+                                                     (oboe_handle_t) builder);
+}
+
+OBOE_API oboe_result_t Oboe_createStreamBuilder(OboeStreamBuilder *builder)
+{
+    ALOGD("Oboe_createStreamBuilder(): check sHandleTracker.isInitialized ()");
+    if (!sHandleTracker.isInitialized()) {
+        return OBOE_ERROR_NO_MEMORY;
+    }
+    AudioStreamBuilder *audioStreamBuilder =  new AudioStreamBuilder();
+    if (audioStreamBuilder == nullptr) {
+        return OBOE_ERROR_NO_MEMORY;
+    }
+    ALOGD("Oboe_createStreamBuilder(): created AudioStreamBuilder = %p", audioStreamBuilder);
+    // TODO protect the put() with a Mutex
+    OboeStreamBuilder handle = sHandleTracker.put(OBOE_HANDLE_TYPE_STREAM_BUILDER,
+            audioStreamBuilder);
+    if (handle < 0) {
+        delete audioStreamBuilder;
+        return static_cast<oboe_result_t>(handle);
+    } else {
+        *builder = handle;
+    }
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStreamBuilder_setDeviceId(OboeStreamBuilder builder,
+                                                     OboeDeviceId deviceId)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    streamBuilder->setDeviceId(deviceId);
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStreamBuilder_setSampleRate(OboeStreamBuilder builder,
+                                              oboe_sample_rate_t sampleRate)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    streamBuilder->setSampleRate(sampleRate);
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStreamBuilder_getSampleRate(OboeStreamBuilder builder,
+                                              oboe_sample_rate_t *sampleRate)
+{
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(sampleRate);
+    *sampleRate = streamBuilder->getSampleRate();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStreamBuilder_setSamplesPerFrame(OboeStreamBuilder builder,
+                                                   int32_t samplesPerFrame)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    streamBuilder->setSamplesPerFrame(samplesPerFrame);
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStreamBuilder_getSamplesPerFrame(OboeStreamBuilder builder,
+                                                   int32_t *samplesPerFrame)
+{
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(samplesPerFrame);
+    *samplesPerFrame = streamBuilder->getSamplesPerFrame();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStreamBuilder_setDirection(OboeStreamBuilder builder,
+                                             oboe_direction_t direction)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    streamBuilder->setDirection(direction);
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStreamBuilder_getDirection(OboeStreamBuilder builder,
+                                             oboe_direction_t *direction)
+{
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(direction);
+    *direction = streamBuilder->getDirection();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStreamBuilder_setFormat(OboeStreamBuilder builder,
+                                                   oboe_audio_format_t format)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    streamBuilder->setFormat(format);
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStreamBuilder_getFormat(OboeStreamBuilder builder,
+                                                   oboe_audio_format_t *format)
+{
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(format);
+    *format = streamBuilder->getFormat();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStreamBuilder_setSharingMode(OboeStreamBuilder builder,
+                                                        oboe_sharing_mode_t sharingMode)
+{
+    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
+    if ((sharingMode < 0) || (sharingMode >= OBOE_SHARING_MODE_COUNT)) {
+        return OBOE_ERROR_ILLEGAL_ARGUMENT;
+    } else {
+        streamBuilder->setSharingMode(sharingMode);
+        return OBOE_OK;
+    }
+}
+
+OBOE_API oboe_result_t OboeStreamBuilder_getSharingMode(OboeStreamBuilder builder,
+                                                        oboe_sharing_mode_t *sharingMode)
+{
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(sharingMode);
+    *sharingMode = streamBuilder->getSharingMode();
+    return OBOE_OK;
+}
+
+static oboe_result_t  OboeInternal_openStream(AudioStreamBuilder *streamBuilder,
+                                              OboeStream *streamPtr)
+{
+    AudioStream *audioStream = nullptr;
+    oboe_result_t result = streamBuilder->build(&audioStream);
+    if (result != OBOE_OK) {
+        return result;
+    } else {
+        // Create a handle for referencing the object.
+        // TODO protect the put() with a Mutex
+        OboeStream handle = sHandleTracker.put(OBOE_HANDLE_TYPE_STREAM, audioStream);
+        if (handle < 0) {
+            delete audioStream;
+            return static_cast<oboe_result_t>(handle);
+        }
+        *streamPtr = handle;
+        return OBOE_OK;
+    }
+}
+
+OBOE_API oboe_result_t  OboeStreamBuilder_openStream(OboeStreamBuilder builder,
+                                                     OboeStream *streamPtr)
+{
+    ALOGD("OboeStreamBuilder_openStream(): builder = 0x%08X", builder);
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(streamPtr);
+    return OboeInternal_openStream(streamBuilder, streamPtr);
+}
+
+OBOE_API oboe_result_t  OboeStreamBuilder_delete(OboeStreamBuilder builder)
+{
+    // TODO protect the remove() with a Mutex
+    AudioStreamBuilder *streamBuilder = (AudioStreamBuilder *)
+            sHandleTracker.remove(OBOE_HANDLE_TYPE_STREAM_BUILDER, builder);
+    if (streamBuilder != nullptr) {
+        delete streamBuilder;
+        return OBOE_OK;
+    }
+    return OBOE_ERROR_INVALID_HANDLE;
+}
+
+OBOE_API oboe_result_t  OboeStream_close(OboeStream stream)
+{
+    // TODO protect the remove() with a Mutex
+    AudioStream *audioStream = (AudioStream *)
+            sHandleTracker.remove(OBOE_HANDLE_TYPE_STREAM, (oboe_handle_t)stream);
+    if (audioStream != nullptr) {
+        audioStream->close();
+        delete audioStream;
+        return OBOE_OK;
+    }
+    return OBOE_ERROR_INVALID_HANDLE;
+}
+
+OBOE_API oboe_result_t  OboeStream_requestStart(OboeStream stream)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    ALOGD("OboeStream_requestStart(0x%08X), audioStream = %p", stream, audioStream);
+    return audioStream->requestStart();
+}
+
+OBOE_API oboe_result_t  OboeStream_requestPause(OboeStream stream)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    ALOGD("OboeStream_requestPause(0x%08X), audioStream = %p", stream, audioStream);
+    return audioStream->requestPause();
+}
+
+OBOE_API oboe_result_t  OboeStream_requestFlush(OboeStream stream)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    ALOGD("OboeStream_requestFlush(0x%08X), audioStream = %p", stream, audioStream);
+    return audioStream->requestFlush();
+}
+
+OBOE_API oboe_result_t  OboeStream_requestStop(OboeStream stream)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    ALOGD("OboeStream_requestStop(0x%08X), audioStream = %p", stream, audioStream);
+    return audioStream->requestStop();
+}
+
+OBOE_API oboe_result_t OboeStream_waitForStateChange(OboeStream stream,
+                                            oboe_stream_state_t inputState,
+                                            oboe_stream_state_t *nextState,
+                                            oboe_nanoseconds_t timeoutNanoseconds)
+{
+
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    return audioStream->waitForStateChange(inputState, nextState, timeoutNanoseconds);
+}
+
+// ============================================================
+// Stream - non-blocking I/O
+// ============================================================
+
+OBOE_API oboe_result_t OboeStream_read(OboeStream stream,
+                               void *buffer,
+                               oboe_size_frames_t numFrames,
+                               oboe_nanoseconds_t timeoutNanoseconds)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    if (buffer == nullptr) {
+        return OBOE_ERROR_NULL;
+    }
+    if (numFrames < 0) {
+        return OBOE_ERROR_ILLEGAL_ARGUMENT;
+    } else if (numFrames == 0) {
+        return 0;
+    }
+
+    oboe_result_t result = audioStream->read(buffer, numFrames, timeoutNanoseconds);
+    // ALOGD("OboeStream_read(): read returns %d", result);
+
+    return result;
+}
+
+OBOE_API oboe_result_t OboeStream_write(OboeStream stream,
+                               const void *buffer,
+                               oboe_size_frames_t numFrames,
+                               oboe_nanoseconds_t timeoutNanoseconds)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    if (buffer == nullptr) {
+        return OBOE_ERROR_NULL;
+    }
+    if (numFrames < 0) {
+        return OBOE_ERROR_ILLEGAL_ARGUMENT;
+    } else if (numFrames == 0) {
+        return 0;
+    }
+
+    oboe_result_t result = audioStream->write(buffer, numFrames, timeoutNanoseconds);
+    // ALOGD("OboeStream_write(): write returns %d", result);
+
+    return result;
+}
+
+// ============================================================
+// Miscellaneous
+// ============================================================
+
+OBOE_API oboe_result_t OboeStream_createThread(OboeStream stream,
+                                     oboe_nanoseconds_t periodNanoseconds,
+                                     void *(*startRoutine)(void *), void *arg)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    return audioStream->createThread(periodNanoseconds, startRoutine, arg);
+}
+
+OBOE_API oboe_result_t OboeStream_joinThread(OboeStream stream,
+                                   void **returnArg,
+                                   oboe_nanoseconds_t timeoutNanoseconds)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    return audioStream->joinThread(returnArg, timeoutNanoseconds);
+}
+
+// ============================================================
+// Stream - queries
+// ============================================================
+
+// TODO Use oboe_clockid_t all the way down through the C++ streams.
+static clockid_t OboeConvert_fromOboeClockId(oboe_clockid_t clockid)
+{
+    clockid_t hostClockId;
+    switch (clockid) {
+        case OBOE_CLOCK_MONOTONIC:
+            hostClockId = CLOCK_MONOTONIC;
+            break;
+        case OBOE_CLOCK_BOOTTIME:
+            hostClockId = CLOCK_BOOTTIME;
+            break;
+        default:
+            hostClockId = 0; // TODO review
+    }
+    return hostClockId;
+}
+
+oboe_nanoseconds_t Oboe_getNanoseconds(oboe_clockid_t clockid)
+{
+    clockid_t hostClockId = OboeConvert_fromOboeClockId(clockid);
+   return AudioClock::getNanoseconds(hostClockId);
+}
+
+OBOE_API oboe_result_t OboeStream_getSampleRate(OboeStream stream, oboe_sample_rate_t *sampleRate)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(sampleRate);
+    *sampleRate = audioStream->getSampleRate();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStream_getSamplesPerFrame(OboeStream stream, int32_t *samplesPerFrame)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(samplesPerFrame);
+    *samplesPerFrame = audioStream->getSamplesPerFrame();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStream_getState(OboeStream stream, oboe_stream_state_t *state)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(state);
+    *state = audioStream->getState();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStream_getFormat(OboeStream stream, oboe_audio_format_t *format)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(format);
+    *format = audioStream->getFormat();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStream_setBufferSize(OboeStream stream,
+                                                oboe_size_frames_t requestedFrames,
+                                                oboe_size_frames_t *actualFrames)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    return audioStream->setBufferSize(requestedFrames, actualFrames);
+}
+
+OBOE_API oboe_result_t OboeStream_getBufferSize(OboeStream stream, oboe_size_frames_t *frames)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(frames);
+    *frames = audioStream->getBufferSize();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStream_getDirection(OboeStream stream, int32_t *direction)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(direction);
+    *direction = audioStream->getDirection();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStream_getFramesPerBurst(OboeStream stream,
+                                                    oboe_size_frames_t *framesPerBurst)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(framesPerBurst);
+    *framesPerBurst = audioStream->getFramesPerBurst();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStream_getBufferCapacity(OboeStream stream,
+                                           oboe_size_frames_t *capacity)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(capacity);
+    *capacity = audioStream->getBufferCapacity();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStream_getXRunCount(OboeStream stream, int32_t *xRunCount)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(xRunCount);
+    *xRunCount = audioStream->getXRunCount();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStream_getSharingMode(OboeStream stream,
+                                                 oboe_sharing_mode_t *sharingMode)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(sharingMode);
+    *sharingMode = audioStream->getSharingMode();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStream_getFramesWritten(OboeStream stream,
+                                                   oboe_position_frames_t *frames)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(frames);
+    *frames = audioStream->getFramesWritten();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStream_getFramesRead(OboeStream stream, oboe_position_frames_t *frames)
+{
+    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(frames);
+    *frames = audioStream->getFramesRead();
+    return OBOE_OK;
+}
+
+OBOE_API oboe_result_t OboeStream_getTimestamp(OboeStream stream,
+                                      oboe_clockid_t clockid,
+                                      oboe_position_frames_t *framePosition,
+                                      oboe_nanoseconds_t *timeNanoseconds)
+{
+    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
+    if (framePosition == nullptr) {
+        return OBOE_ERROR_NULL;
+    } else if (timeNanoseconds == nullptr) {
+        return OBOE_ERROR_NULL;
+    } else if (clockid != OBOE_CLOCK_MONOTONIC && clockid != OBOE_CLOCK_BOOTTIME) {
+        return OBOE_ERROR_ILLEGAL_ARGUMENT;
+    }
+
+    clockid_t hostClockId = OboeConvert_fromOboeClockId(clockid);
+    return audioStream->getTimestamp(hostClockId, framePosition, timeNanoseconds);
+}
diff --git a/media/liboboe/src/core/README.md b/media/liboboe/src/core/README.md
new file mode 100644
index 0000000..dd99286
--- /dev/null
+++ b/media/liboboe/src/core/README.md
@@ -0,0 +1,2 @@
+The core folder contains the essential Oboe files common to all implementations.
+The OboeAudio.cpp contains the 'C' API.
diff --git a/media/liboboe/src/core/VersionExperiment.txt b/media/liboboe/src/core/VersionExperiment.txt
new file mode 100644
index 0000000..071239b
--- /dev/null
+++ b/media/liboboe/src/core/VersionExperiment.txt
@@ -0,0 +1,55 @@
+
+// TODO Experiment with versioning. This may be removed or changed dramatically.
+// Please ignore for now. Do not review.
+#define OBOE_VERSION_EXPERIMENT  0
+#if OBOE_VERSION_EXPERIMENT
+
+#define OBOE_EARLIEST_SUPPORTED_VERSION  1
+#define OBOE_CURRENT_VERSION  2
+
+typedef struct OboeInterface_s {
+    int32_t size; // do not use size_t because its size can vary
+    int32_t version;
+    int32_t reserved1;
+    void *  reserved2;
+    oboe_result_t (*createStreamBuilder)(OboeStreamBuilder *);
+} OboeInterface_t;
+
+OboeInterface_t s_oboe_template = {
+        .size = sizeof(OboeInterface_t),
+        .version = OBOE_CURRENT_VERSION,
+        .reserved1 = 0,
+        .reserved2 = NULL,
+        .createStreamBuilder = Oboe_createStreamBuilder
+};
+
+oboe_result_t Oboe_Unimplemented(OboeInterface_t *oboe) {
+    (void) oboe;
+    return OBOE_ERROR_UNIMPLEMENTED;
+}
+
+typedef oboe_result_t (*OboeFunction_t)(OboeInterface_t *oboe);
+
+int32_t Oboe_Initialize(OboeInterface_t *oboe, uint32_t flags) {
+    if (oboe->version < OBOE_EARLIEST_SUPPORTED_VERSION) {
+        return OBOE_ERROR_INCOMPATIBLE;
+    }
+    // Fill in callers vector table.
+    uint8_t *start = (uint8_t*)&oboe->reserved1;
+    uint8_t *end;
+    if (oboe->size <= s_oboe_template.size) {
+        end = ((uint8_t *)oboe) + oboe->size;
+    } else {
+        end = ((uint8_t *)oboe) + s_oboe_template.size;
+        // Assume the rest of the structure is vectors.
+        // Point them all to OboeInternal_Unimplemented()
+        // Point to first vector past end of the known structure.
+        OboeFunction_t *next = (OboeFunction_t*)end;
+        while ((((uint8_t *)next) - ((uint8_t *)oboe)) < oboe->size) {
+            *next++ = Oboe_Unimplemented;
+        }
+    }
+    memcpy(&oboe->reserved1, &s_oboe_template.reserved1, end - start);
+    return OBOE_OK;
+}
+#endif /* OBOE_VERSION_EXPERIMENT -------------------------- */
diff --git a/media/liboboe/src/legacy/AudioStreamRecord.cpp b/media/liboboe/src/legacy/AudioStreamRecord.cpp
new file mode 100644
index 0000000..f130cad
--- /dev/null
+++ b/media/liboboe/src/legacy/AudioStreamRecord.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioStreamRecord"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <utils/String16.h>
+#include <media/AudioRecord.h>
+#include <oboe/OboeAudio.h>
+
+#include "AudioClock.h"
+#include "AudioStreamRecord.h"
+
+using namespace android;
+using namespace oboe;
+
+AudioStreamRecord::AudioStreamRecord()
+    : AudioStream()
+{
+}
+
+AudioStreamRecord::~AudioStreamRecord()
+{
+    const oboe_stream_state_t state = getState();
+    bool bad = !(state == OBOE_STREAM_STATE_UNINITIALIZED || state == OBOE_STREAM_STATE_CLOSED);
+    ALOGE_IF(bad, "stream not closed, in state %d", state);
+}
+
+oboe_result_t AudioStreamRecord::open(const AudioStreamBuilder& builder)
+{
+    oboe_result_t result = OBOE_OK;
+
+    result = AudioStream::open(builder);
+    if (result != OBOE_OK) {
+        return result;
+    }
+
+    // Try to create an AudioRecord
+
+    // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified.
+    int32_t samplesPerFrame = (getSamplesPerFrame() == OBOE_UNSPECIFIED)
+                              ? 2 : getSamplesPerFrame();
+    audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame);
+
+    AudioRecord::callback_t callback = NULL;
+    audio_input_flags_t flags = (audio_input_flags_t) AUDIO_INPUT_FLAG_NONE;
+
+    // TODO implement an unspecified Android format then use that.
+    audio_format_t format = (getFormat() == OBOE_UNSPECIFIED)
+            ? AUDIO_FORMAT_PCM_FLOAT
+            : OboeConvert_oboeToAndroidDataFormat(getFormat());
+
+    mAudioRecord = new AudioRecord(
+            AUDIO_SOURCE_DEFAULT,
+            getSampleRate(),
+            format,
+            channelMask,
+
+            mOpPackageName, // const String16& opPackageName TODO does not compile
+
+            0,    //    size_t frameCount = 0,
+            callback,
+            NULL, //    void* user = NULL,
+            0,    //    uint32_t notificationFrames = 0,
+            AUDIO_SESSION_ALLOCATE,
+            AudioRecord::TRANSFER_DEFAULT,
+            flags
+             //   int uid = -1,
+             //   pid_t pid = -1,
+             //   const audio_attributes_t* pAttributes = NULL
+             );
+
+    // Did we get a valid track?
+    status_t status = mAudioRecord->initCheck();
+    if (status != OK) {
+        close();
+        ALOGE("AudioStreamRecord::open(), initCheck() returned %d", status);
+        return OboeConvert_androidToOboeError(status);
+    }
+
+    // Get the actual rate.
+    setSampleRate(mAudioRecord->getSampleRate());
+    setSamplesPerFrame(mAudioRecord->channelCount());
+    setFormat(OboeConvert_androidToOboeDataFormat(mAudioRecord->format()));
+
+    setState(OBOE_STREAM_STATE_OPEN);
+
+    return OBOE_OK;
+}
+
+oboe_result_t AudioStreamRecord::close()
+{
+    // TODO add close() or release() to AudioRecord API then call it from here
+    if (getState() != OBOE_STREAM_STATE_CLOSED) {
+        mAudioRecord.clear();
+        setState(OBOE_STREAM_STATE_CLOSED);
+    }
+    return OBOE_OK;
+}
+
+oboe_result_t AudioStreamRecord::requestStart()
+{
+    if (mAudioRecord.get() == NULL) {
+        return OBOE_ERROR_INVALID_STATE;
+    }
+    // Get current position so we can detect when the track is playing.
+    status_t err = mAudioRecord->getPosition(&mPositionWhenStarting);
+    if (err != OK) {
+        return OboeConvert_androidToOboeError(err);
+    }
+    err = mAudioRecord->start();
+    if (err != OK) {
+        return OboeConvert_androidToOboeError(err);
+    } else {
+        setState(OBOE_STREAM_STATE_STARTING);
+    }
+    return OBOE_OK;
+}
+
+oboe_result_t AudioStreamRecord::requestPause()
+{
+    return OBOE_ERROR_UNIMPLEMENTED;
+}
+
+oboe_result_t AudioStreamRecord::requestFlush() {
+    return OBOE_ERROR_UNIMPLEMENTED;
+}
+
+oboe_result_t AudioStreamRecord::requestStop() {
+    if (mAudioRecord.get() == NULL) {
+        return OBOE_ERROR_INVALID_STATE;
+    }
+    setState(OBOE_STREAM_STATE_STOPPING);
+    mAudioRecord->stop();
+    return OBOE_OK;
+}
+
+oboe_result_t AudioStreamRecord::updateState()
+{
+    oboe_result_t result = OBOE_OK;
+    oboe_wrapping_frames_t position;
+    status_t err;
+    switch (getState()) {
+    // TODO add better state visibility to AudioRecord
+    case OBOE_STREAM_STATE_STARTING:
+        err = mAudioRecord->getPosition(&position);
+        if (err != OK) {
+            result = OboeConvert_androidToOboeError(err);
+        } else if (position != mPositionWhenStarting) {
+            setState(OBOE_STREAM_STATE_STARTED);
+        }
+        break;
+    case OBOE_STREAM_STATE_STOPPING:
+        if (mAudioRecord->stopped()) {
+            setState(OBOE_STREAM_STATE_STOPPED);
+        }
+        break;
+    default:
+        break;
+    }
+    return result;
+}
+
+oboe_result_t AudioStreamRecord::read(void *buffer,
+                                      oboe_size_frames_t numFrames,
+                                      oboe_nanoseconds_t timeoutNanoseconds)
+{
+    oboe_size_frames_t bytesPerFrame = getBytesPerFrame();
+    oboe_size_bytes_t numBytes;
+    oboe_result_t result = OboeConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
+    if (result != OBOE_OK) {
+        return result;
+    }
+
+    // TODO add timeout to AudioRecord
+    bool blocking = (timeoutNanoseconds > 0);
+    ssize_t bytesRead = mAudioRecord->read(buffer, numBytes, blocking);
+    if (bytesRead == WOULD_BLOCK) {
+        return 0;
+    } else if (bytesRead < 0) {
+        return OboeConvert_androidToOboeError(bytesRead);
+    }
+    oboe_size_frames_t framesRead = (oboe_size_frames_t)(bytesRead / bytesPerFrame);
+    return (oboe_result_t) framesRead;
+}
+
+oboe_result_t AudioStreamRecord::setBufferSize(oboe_size_frames_t requestedFrames,
+                                             oboe_size_frames_t *actualFrames)
+{
+    *actualFrames = getBufferCapacity();
+    return OBOE_OK;
+}
+
+oboe_size_frames_t AudioStreamRecord::getBufferSize() const
+{
+    return getBufferCapacity(); // TODO implement in AudioRecord?
+}
+
+oboe_size_frames_t AudioStreamRecord::getBufferCapacity() const
+{
+    return static_cast<oboe_size_frames_t>(mAudioRecord->frameCount());
+}
+
+int32_t AudioStreamRecord::getXRunCount() const
+{
+    return OBOE_ERROR_UNIMPLEMENTED; // TODO implement when AudioRecord supports it
+}
+
+oboe_size_frames_t AudioStreamRecord::getFramesPerBurst() const
+{
+    return 192; // TODO add query to AudioRecord.cpp
+}
+
+// TODO implement getTimestamp
+
diff --git a/media/liboboe/src/legacy/AudioStreamRecord.h b/media/liboboe/src/legacy/AudioStreamRecord.h
new file mode 100644
index 0000000..02ff220
--- /dev/null
+++ b/media/liboboe/src/legacy/AudioStreamRecord.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LEGACY_AUDIOSTREAMRECORD_H
+#define LEGACY_AUDIOSTREAMRECORD_H
+
+#include <media/AudioRecord.h>
+#include <oboe/OboeAudio.h>
+
+#include "AudioStreamBuilder.h"
+#include "AudioStream.h"
+#include "OboeLegacy.h"
+
+namespace oboe {
+
+/**
+ * Internal stream that uses the legacy AudioTrack path.
+ */
+class AudioStreamRecord : public AudioStream {
+public:
+    AudioStreamRecord();
+
+    virtual ~AudioStreamRecord();
+
+    virtual oboe_result_t open(const AudioStreamBuilder & builder) override;
+    virtual oboe_result_t close() override;
+
+    virtual oboe_result_t requestStart() override;
+    virtual oboe_result_t requestPause() override;
+    virtual oboe_result_t requestFlush() override;
+    virtual oboe_result_t requestStop() override;
+
+    virtual oboe_result_t getTimestamp(clockid_t clockId,
+                                       oboe_position_frames_t *framePosition,
+                                       oboe_nanoseconds_t *timeNanoseconds) override {
+        return OBOE_ERROR_UNIMPLEMENTED; // TODO
+    }
+
+    virtual oboe_result_t read(void *buffer,
+                             oboe_size_frames_t numFrames,
+                             oboe_nanoseconds_t timeoutNanoseconds) override;
+
+    virtual oboe_result_t setBufferSize(oboe_size_frames_t requestedFrames,
+                                             oboe_size_frames_t *actualFrames) override;
+
+    virtual oboe_size_frames_t getBufferSize() const override;
+
+    virtual oboe_size_frames_t getBufferCapacity() const override;
+
+    virtual int32_t getXRunCount() const override;
+
+    virtual oboe_size_frames_t getFramesPerBurst() const override;
+
+    virtual oboe_result_t updateState() override;
+
+private:
+    android::sp<android::AudioRecord> mAudioRecord;
+    // TODO add 64-bit position reporting to AudioRecord and use it.
+    oboe_wrapping_frames_t   mPositionWhenStarting = 0;
+    android::String16        mOpPackageName;
+};
+
+} /* namespace oboe */
+
+#endif /* LEGACY_AUDIOSTREAMRECORD_H */
diff --git a/media/liboboe/src/legacy/AudioStreamTrack.cpp b/media/liboboe/src/legacy/AudioStreamTrack.cpp
new file mode 100644
index 0000000..5205fc5
--- /dev/null
+++ b/media/liboboe/src/legacy/AudioStreamTrack.cpp
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioStreamTrack"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <media/AudioTrack.h>
+
+#include <oboe/OboeAudio.h>
+#include "AudioClock.h"
+#include "AudioStreamTrack.h"
+
+
+using namespace android;
+using namespace oboe;
+
+/*
+ * Create a stream that uses the AudioTrack.
+ */
+AudioStreamTrack::AudioStreamTrack()
+    : AudioStream()
+{
+}
+
+AudioStreamTrack::~AudioStreamTrack()
+{
+    const oboe_stream_state_t state = getState();
+    bool bad = !(state == OBOE_STREAM_STATE_UNINITIALIZED || state == OBOE_STREAM_STATE_CLOSED);
+    ALOGE_IF(bad, "stream not closed, in state %d", state);
+}
+
+oboe_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder)
+{
+    oboe_result_t result = OBOE_OK;
+
+    result = AudioStream::open(builder);
+    if (result != OK) {
+        return result;
+    }
+
+    // Try to create an AudioTrack
+    // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified.
+    int32_t samplesPerFrame = (getSamplesPerFrame() == OBOE_UNSPECIFIED)
+                              ? 2 : getSamplesPerFrame();
+    audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame);
+    ALOGE("AudioStreamTrack::open(), samplesPerFrame = %d, channelMask = 0x%08x",
+            samplesPerFrame, channelMask);
+
+    AudioTrack::callback_t callback = NULL;
+    // TODO add more performance options
+    audio_output_flags_t flags = (audio_output_flags_t) AUDIO_OUTPUT_FLAG_FAST;
+    size_t frameCount = 0;
+    // TODO implement an unspecified AudioTrack format then use that.
+    audio_format_t format = (getFormat() == OBOE_UNSPECIFIED)
+            ? AUDIO_FORMAT_PCM_FLOAT
+            : OboeConvert_oboeToAndroidDataFormat(getFormat());
+
+    mAudioTrack = new AudioTrack(
+            (audio_stream_type_t) AUDIO_STREAM_MUSIC,
+            getSampleRate(),
+            format,
+            channelMask,
+            frameCount,
+            flags,
+            callback,
+            NULL,    // user callback data
+            0,       // notificationFrames
+            AUDIO_SESSION_ALLOCATE,
+            AudioTrack::transfer_type::TRANSFER_SYNC // TODO - this does not allow FAST
+            );
+
+    // Did we get a valid track?
+    status_t status = mAudioTrack->initCheck();
+    // FIXME - this should work - if (status != NO_ERROR) {
+    //         But initCheck() is returning 1 !
+    if (status < 0) {
+        close();
+        ALOGE("AudioStreamTrack::open(), initCheck() returned %d", status);
+        return OboeConvert_androidToOboeError(status);
+    }
+
+    // Get the actual values from the AudioTrack.
+    setSamplesPerFrame(mAudioTrack->channelCount());
+    setSampleRate(mAudioTrack->getSampleRate());
+    setFormat(OboeConvert_androidToOboeDataFormat(mAudioTrack->format()));
+
+    setState(OBOE_STREAM_STATE_OPEN);
+
+    return OBOE_OK;
+}
+
+oboe_result_t AudioStreamTrack::close()
+{
+    // TODO maybe add close() or release() to AudioTrack API then call it from here
+    if (getState() != OBOE_STREAM_STATE_CLOSED) {
+        mAudioTrack.clear(); // TODO is this right?
+        setState(OBOE_STREAM_STATE_CLOSED);
+    }
+    return OBOE_OK;
+}
+
+oboe_result_t AudioStreamTrack::requestStart()
+{
+    if (mAudioTrack.get() == NULL) {
+        return OBOE_ERROR_INVALID_STATE;
+    }
+    // Get current position so we can detect when the track is playing.
+    status_t err = mAudioTrack->getPosition(&mPositionWhenStarting);
+    if (err != OK) {
+        return OboeConvert_androidToOboeError(err);
+    }
+    err = mAudioTrack->start();
+    if (err != OK) {
+        return OboeConvert_androidToOboeError(err);
+    } else {
+        setState(OBOE_STREAM_STATE_STARTING);
+    }
+    return OBOE_OK;
+}
+
+oboe_result_t AudioStreamTrack::requestPause()
+{
+    if (mAudioTrack.get() == NULL) {
+        return OBOE_ERROR_INVALID_STATE;
+    } else if (getState() != OBOE_STREAM_STATE_STARTING
+            && getState() != OBOE_STREAM_STATE_STARTED) {
+        ALOGE("requestPause(), called when state is %s", Oboe_convertStreamStateToText(getState()));
+        return OBOE_ERROR_INVALID_STATE;
+    }
+    setState(OBOE_STREAM_STATE_PAUSING);
+    mAudioTrack->pause();
+    status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
+    if (err != OK) {
+        return OboeConvert_androidToOboeError(err);
+    }
+    return OBOE_OK;
+}
+
+oboe_result_t AudioStreamTrack::requestFlush() {
+    if (mAudioTrack.get() == NULL) {
+        return OBOE_ERROR_INVALID_STATE;
+    } else if (getState() != OBOE_STREAM_STATE_PAUSED) {
+        return OBOE_ERROR_INVALID_STATE;
+    }
+    setState(OBOE_STREAM_STATE_FLUSHING);
+    incrementFramesRead(getFramesWritten() - getFramesRead());
+    mAudioTrack->flush();
+    mFramesWritten.reset32();
+    return OBOE_OK;
+}
+
+oboe_result_t AudioStreamTrack::requestStop() {
+    if (mAudioTrack.get() == NULL) {
+        return OBOE_ERROR_INVALID_STATE;
+    }
+    setState(OBOE_STREAM_STATE_STOPPING);
+    incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
+    mAudioTrack->stop();
+    mFramesWritten.reset32();
+    return OBOE_OK;
+}
+
+oboe_result_t AudioStreamTrack::updateState()
+{
+    status_t err;
+    oboe_wrapping_frames_t position;
+    switch (getState()) {
+    // TODO add better state visibility to AudioTrack
+    case OBOE_STREAM_STATE_STARTING:
+        if (mAudioTrack->hasStarted()) {
+            setState(OBOE_STREAM_STATE_STARTED);
+        }
+        break;
+    case OBOE_STREAM_STATE_PAUSING:
+        if (mAudioTrack->stopped()) {
+            err = mAudioTrack->getPosition(&position);
+            if (err != OK) {
+                return OboeConvert_androidToOboeError(err);
+            } else if (position == mPositionWhenPausing) {
+                // Has stream really stopped advancing?
+                setState(OBOE_STREAM_STATE_PAUSED);
+            }
+            mPositionWhenPausing = position;
+        }
+        break;
+    case OBOE_STREAM_STATE_FLUSHING:
+        {
+            err = mAudioTrack->getPosition(&position);
+            if (err != OK) {
+                return OboeConvert_androidToOboeError(err);
+            } else if (position == 0) {
+                // Advance frames read to match written.
+                setState(OBOE_STREAM_STATE_FLUSHED);
+            }
+        }
+        break;
+    case OBOE_STREAM_STATE_STOPPING:
+        if (mAudioTrack->stopped()) {
+            setState(OBOE_STREAM_STATE_STOPPED);
+        }
+        break;
+    default:
+        break;
+    }
+    return OBOE_OK;
+}
+
+oboe_result_t AudioStreamTrack::write(const void *buffer,
+                                      oboe_size_frames_t numFrames,
+                                      oboe_nanoseconds_t timeoutNanoseconds)
+{
+    oboe_size_frames_t bytesPerFrame = getBytesPerFrame();
+    oboe_size_bytes_t numBytes;
+    oboe_result_t result = OboeConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
+    if (result != OBOE_OK) {
+        return result;
+    }
+
+    // TODO add timeout to AudioTrack
+    bool blocking = timeoutNanoseconds > 0;
+    ssize_t bytesWritten = mAudioTrack->write(buffer, numBytes, blocking);
+    if (bytesWritten == WOULD_BLOCK) {
+        return 0;
+    } else if (bytesWritten < 0) {
+        ALOGE("invalid write, returned %d", (int)bytesWritten);
+        return OboeConvert_androidToOboeError(bytesWritten);
+    }
+    oboe_size_frames_t framesWritten = (oboe_size_frames_t)(bytesWritten / bytesPerFrame);
+    incrementFramesWritten(framesWritten);
+    return framesWritten;
+}
+
+oboe_result_t AudioStreamTrack::setBufferSize(oboe_size_frames_t requestedFrames,
+                                             oboe_size_frames_t *actualFrames)
+{
+    ssize_t result = mAudioTrack->setBufferSizeInFrames(requestedFrames);
+    if (result != OK) {
+        return OboeConvert_androidToOboeError(result);
+    } else {
+        *actualFrames = result;
+        return OBOE_OK;
+    }
+}
+
+oboe_size_frames_t AudioStreamTrack::getBufferSize() const
+{
+    return static_cast<oboe_size_frames_t>(mAudioTrack->getBufferSizeInFrames());
+}
+
+oboe_size_frames_t AudioStreamTrack::getBufferCapacity() const
+{
+    return static_cast<oboe_size_frames_t>(mAudioTrack->frameCount());
+}
+
+int32_t AudioStreamTrack::getXRunCount() const
+{
+    return static_cast<int32_t>(mAudioTrack->getUnderrunCount());
+}
+
+int32_t AudioStreamTrack::getFramesPerBurst() const
+{
+    return 192; // TODO add query to AudioTrack.cpp
+}
+
+oboe_position_frames_t AudioStreamTrack::getFramesRead() {
+    oboe_wrapping_frames_t position;
+    status_t result;
+    switch (getState()) {
+    case OBOE_STREAM_STATE_STARTING:
+    case OBOE_STREAM_STATE_STARTED:
+    case OBOE_STREAM_STATE_STOPPING:
+        result = mAudioTrack->getPosition(&position);
+        if (result == OK) {
+            mFramesRead.update32(position);
+        }
+        break;
+    default:
+        break;
+    }
+    return AudioStream::getFramesRead();
+}
diff --git a/media/liboboe/src/legacy/AudioStreamTrack.h b/media/liboboe/src/legacy/AudioStreamTrack.h
new file mode 100644
index 0000000..8c40884
--- /dev/null
+++ b/media/liboboe/src/legacy/AudioStreamTrack.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LEGACY_AUDIOSTREAMTRACK_H
+#define LEGACY_AUDIOSTREAMTRACK_H
+
+#include <media/AudioTrack.h>
+#include <oboe/OboeAudio.h>
+
+#include "AudioStreamBuilder.h"
+#include "AudioStream.h"
+#include "OboeLegacy.h"
+
+namespace oboe {
+
+
+/**
+ * Internal stream that uses the legacy AudioTrack path.
+ */
+class AudioStreamTrack : public AudioStream {
+public:
+    AudioStreamTrack();
+
+    virtual ~AudioStreamTrack();
+
+
+    virtual oboe_result_t open(const AudioStreamBuilder & builder) override;
+    virtual oboe_result_t close() override;
+
+    virtual oboe_result_t requestStart() override;
+    virtual oboe_result_t requestPause() override;
+    virtual oboe_result_t requestFlush() override;
+    virtual oboe_result_t requestStop() override;
+
+    virtual oboe_result_t getTimestamp(clockid_t clockId,
+                                       oboe_position_frames_t *framePosition,
+                                       oboe_nanoseconds_t *timeNanoseconds) override {
+        return OBOE_ERROR_UNIMPLEMENTED; // TODO call getTimestamp(ExtendedTimestamp *timestamp);
+    }
+
+    virtual oboe_result_t write(const void *buffer,
+                             oboe_size_frames_t numFrames,
+                             oboe_nanoseconds_t timeoutNanoseconds) override;
+
+    virtual oboe_result_t setBufferSize(oboe_size_frames_t requestedFrames,
+                                             oboe_size_frames_t *actualFrames) override;
+    virtual oboe_size_frames_t getBufferSize() const override;
+    virtual oboe_size_frames_t getBufferCapacity() const override;
+    virtual oboe_size_frames_t getFramesPerBurst()const  override;
+    virtual int32_t getXRunCount() const override;
+
+    virtual oboe_position_frames_t getFramesRead() override;
+
+    virtual oboe_result_t updateState() override;
+
+private:
+    android::sp<android::AudioTrack> mAudioTrack;
+    // TODO add 64-bit position reporting to AudioRecord and use it.
+    oboe_wrapping_frames_t           mPositionWhenStarting = 0;
+    oboe_wrapping_frames_t           mPositionWhenPausing = 0;
+};
+
+} /* namespace oboe */
+
+#endif /* LEGACY_AUDIOSTREAMTRACK_H */
diff --git a/media/liboboe/src/legacy/OboeLegacy.h b/media/liboboe/src/legacy/OboeLegacy.h
new file mode 100644
index 0000000..6803837
--- /dev/null
+++ b/media/liboboe/src/legacy/OboeLegacy.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OBOE_LEGACY_H
+#define OBOE_LEGACY_H
+
+#include <stdint.h>
+#include <oboe/OboeAudio.h>
+
+/**
+ * Common code for legacy classes.
+ */
+
+/* AudioTrack uses a 32-bit frame counter that can wrap around in about a day. */
+typedef uint32_t oboe_wrapping_frames_t;
+
+#endif /* OBOE_LEGACY_H */
diff --git a/media/liboboe/src/legacy/README.md b/media/liboboe/src/legacy/README.md
new file mode 100644
index 0000000..b51c44b
--- /dev/null
+++ b/media/liboboe/src/legacy/README.md
@@ -0,0 +1,2 @@
+The legacy folder contains the classes that implement Oboe AudioStream on top of
+Android AudioTrack and AudioRecord.
diff --git a/media/liboboe/src/utility/AudioClock.h b/media/liboboe/src/utility/AudioClock.h
new file mode 100644
index 0000000..da2f74a
--- /dev/null
+++ b/media/liboboe/src/utility/AudioClock.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UTILITY_AUDIOCLOCK_H
+#define UTILITY_AUDIOCLOCK_H
+
+#include <sys/types.h>
+#include <time.h>
+#include "oboe/OboeDefinitions.h"
+#include "oboe/OboeAudio.h"
+
+class AudioClock {
+public:
+    static oboe_nanoseconds_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
+        struct timespec time;
+        int result = clock_gettime(clockId, &time);
+        if (result < 0) {
+            return -errno;
+        }
+        return (time.tv_sec * OBOE_NANOS_PER_SECOND) + time.tv_nsec;
+    }
+
+    /**
+     * Sleep until the specified absolute time.
+     * Return immediately with OBOE_ERROR_ILLEGAL_ARGUMENT if a negative
+     * nanoTime is specified.
+     *
+     * @param nanoTime time to wake up
+     * @param clockId CLOCK_MONOTONIC is default
+     * @return 0, a negative error, or 1 if the call is interrupted by a signal handler (EINTR)
+     */
+    static int sleepUntilNanoTime(oboe_nanoseconds_t nanoTime,
+                                  clockid_t clockId = CLOCK_MONOTONIC) {
+        if (nanoTime > 0) {
+            struct timespec time;
+            time.tv_sec = nanoTime / OBOE_NANOS_PER_SECOND;
+            // Calculate the fractional nanoseconds. Avoids expensive % operation.
+            time.tv_nsec = nanoTime - (time.tv_sec * OBOE_NANOS_PER_SECOND);
+            int err = clock_nanosleep(clockId, TIMER_ABSTIME, &time, nullptr);
+            switch (err) {
+            case EINTR:
+                return 1;
+            case 0:
+                return 0;
+            default:
+                // Subtract because clock_nanosleep() returns a positive error number!
+                return 0 - err;
+            }
+        } else {
+            return OBOE_ERROR_ILLEGAL_ARGUMENT;
+        }
+    }
+
+    /**
+     * Sleep for the specified number of relative nanoseconds in real-time.
+     * Return immediately with 0 if a negative nanoseconds is specified.
+     *
+     * @param nanoseconds time to sleep
+     * @param clockId CLOCK_MONOTONIC is default
+     * @return 0, a negative error, or 1 if the call is interrupted by a signal handler (EINTR)
+     */
+    static int sleepForNanos(oboe_nanoseconds_t nanoseconds, clockid_t clockId = CLOCK_MONOTONIC) {
+        if (nanoseconds > 0) {
+            struct timespec time;
+            time.tv_sec = nanoseconds / OBOE_NANOS_PER_SECOND;
+            // Calculate the fractional nanoseconds. Avoids expensive % operation.
+            time.tv_nsec = nanoseconds - (time.tv_sec * OBOE_NANOS_PER_SECOND);
+            const int flags = 0; // documented as relative sleep
+            int err = clock_nanosleep(clockId, flags, &time, nullptr);
+            switch (err) {
+            case EINTR:
+                return 1;
+            case 0:
+                return 0;
+            default:
+                // Subtract because clock_nanosleep() returns a positive error number!
+                return 0 - err;
+            }
+        }
+        return 0;
+    }
+};
+
+
+#endif // UTILITY_AUDIOCLOCK_H
diff --git a/media/liboboe/src/utility/HandleTracker.cpp b/media/liboboe/src/utility/HandleTracker.cpp
new file mode 100644
index 0000000..be2a64c
--- /dev/null
+++ b/media/liboboe/src/utility/HandleTracker.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#define LOG_TAG "OboeAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <assert.h>
+
+#include <oboe/OboeDefinitions.h>
+#include "HandleTracker.h"
+
+// Handle format is: tgggiiii
+// where each letter is 4 bits, t=type, g=generation, i=index
+
+#define TYPE_SIZE           4
+#define GENERATION_SIZE    12
+#define INDEX_SIZE         16
+
+#define GENERATION_INVALID  0
+#define GENERATION_SHIFT    INDEX_SIZE
+
+#define TYPE_MASK           ((1 << TYPE_SIZE) - 1)
+#define GENERATION_MASK     ((1 << GENERATION_SIZE) - 1)
+#define INDEX_MASK          ((1 << INDEX_SIZE) - 1)
+
+#define SLOT_UNAVAILABLE    (-1)
+
+// Error if handle is negative so type is limited to bottom half.
+#define HANDLE_INVALID_TYPE TYPE_MASK
+
+static_assert(HANDLE_TRACKER_MAX_TYPES == (1 << (TYPE_SIZE - 1)),
+    "Mismatch between header and cpp.");
+static_assert(HANDLE_TRACKER_MAX_HANDLES == (1 << (INDEX_SIZE)),
+    "Mismatch between header and cpp.");
+
+HandleTracker::HandleTracker(uint32_t maxHandles)
+        : mMaxHandleCount(maxHandles)
+        , mHandleAddresses(nullptr)
+        , mHandleHeaders(nullptr)
+{
+    assert(maxHandles <= HANDLE_TRACKER_MAX_HANDLES);
+    // Allocate arrays to hold addresses and validation info.
+    mHandleAddresses = (handle_tracker_address_t *) new handle_tracker_address_t[maxHandles];
+    if (mHandleAddresses != nullptr) {
+        mHandleHeaders = new handle_tracker_header_t[maxHandles];
+        if (mHandleHeaders != nullptr) {
+            // Initialize linked list of free nodes. NULL terminated.
+            for (uint32_t i = 0; i < (maxHandles - 1); i++) {
+                mHandleAddresses[i] = &mHandleAddresses[i + 1]; // point to next node
+                mHandleHeaders[i] = 0;
+            }
+            mNextFreeAddress = &mHandleAddresses[0];
+            mHandleAddresses[maxHandles - 1] = nullptr;
+            mHandleHeaders[maxHandles - 1] = 0;
+        } else {
+            delete[] mHandleAddresses; // so the class appears uninitialized
+        }
+    }
+}
+
+HandleTracker::~HandleTracker()
+{
+    delete[] mHandleAddresses;
+    delete[] mHandleHeaders;
+}
+
+bool HandleTracker::isInitialized() const {
+    return mHandleAddresses != nullptr;
+}
+
+handle_tracker_slot_t HandleTracker::allocateSlot() {
+    void **allocated = mNextFreeAddress;
+    if (allocated == nullptr) {
+        return SLOT_UNAVAILABLE;
+    }
+    // Remove this slot from the head of the linked list.
+    mNextFreeAddress = (void **) *allocated;
+    return (allocated - mHandleAddresses);
+}
+
+handle_tracker_generation_t HandleTracker::nextGeneration(handle_tracker_slot_t index) {
+    handle_tracker_generation_t generation = (mHandleHeaders[index] + 1) & GENERATION_MASK;
+    // Avoid generation zero so that 0x0 is not a valid handle.
+    if (generation == GENERATION_INVALID) {
+        generation++;
+    }
+    return generation;
+}
+
+oboe_handle_t HandleTracker::put(handle_tracker_type_t type, void *address)
+{
+    if (type < 0 || type >= HANDLE_TRACKER_MAX_TYPES) {
+        return static_cast<oboe_handle_t>(OBOE_ERROR_OUT_OF_RANGE);
+    }
+    if (!isInitialized()) {
+        return static_cast<oboe_handle_t>(OBOE_ERROR_NO_MEMORY);
+    }
+
+    // Find an empty slot.
+    handle_tracker_slot_t index = allocateSlot();
+    if (index == SLOT_UNAVAILABLE) {
+        ALOGE("HandleTracker::put() no room for more handles");
+        return static_cast<oboe_handle_t>(OBOE_ERROR_NO_FREE_HANDLES);
+    }
+
+    // Cycle the generation counter so stale handles can be detected.
+    handle_tracker_generation_t generation = nextGeneration(index); // reads header table
+    handle_tracker_header_t inputHeader = buildHeader(type, generation);
+
+    // These two writes may need to be observed by other threads or cores during get().
+    mHandleHeaders[index] = inputHeader;
+    mHandleAddresses[index] = address;
+    // TODO use store release to enforce memory order with get()
+
+    // Generate a handle.
+    oboe_handle_t handle = buildHandle(inputHeader, index);
+
+    //ALOGD("HandleTracker::put(%p) returns 0x%08x", address, handle);
+    return handle;
+}
+
+handle_tracker_slot_t HandleTracker::handleToIndex(handle_tracker_type_t type,
+                                                   oboe_handle_t handle) const
+{
+    // Validate the handle.
+    handle_tracker_slot_t index = extractIndex(handle);
+    if (index >= mMaxHandleCount) {
+        ALOGE("HandleTracker::handleToIndex() invalid handle = 0x%08X", handle);
+        return static_cast<oboe_handle_t>(OBOE_ERROR_INVALID_HANDLE);
+    }
+    handle_tracker_generation_t handleGeneration = extractGeneration(handle);
+    handle_tracker_header_t inputHeader = buildHeader(type, handleGeneration);
+    if (inputHeader != mHandleHeaders[index]) {
+        ALOGE("HandleTracker::handleToIndex() inputHeader = 0x%08x != mHandleHeaders[%d] = 0x%08x",
+             inputHeader, index, mHandleHeaders[index]);
+        return static_cast<oboe_handle_t>(OBOE_ERROR_INVALID_HANDLE);
+    }
+    return index;
+}
+
+handle_tracker_address_t HandleTracker::get(handle_tracker_type_t type, oboe_handle_t handle) const
+{
+    if (!isInitialized()) {
+        return nullptr;
+    }
+    handle_tracker_slot_t index = handleToIndex(type, handle);
+    if (index >= 0) {
+        return mHandleAddresses[index];
+    } else {
+        return nullptr;
+    }
+}
+
+handle_tracker_address_t HandleTracker::remove(handle_tracker_type_t type, oboe_handle_t handle) {
+    if (!isInitialized()) {
+        return nullptr;
+    }
+    handle_tracker_slot_t index = handleToIndex(type,handle);
+    if (index >= 0) {
+        handle_tracker_address_t address = mHandleAddresses[index];
+
+        // Invalidate the header type but preserve the generation count.
+        handle_tracker_generation_t generation = mHandleHeaders[index] & GENERATION_MASK;
+        handle_tracker_header_t inputHeader = buildHeader(
+                (handle_tracker_type_t) HANDLE_INVALID_TYPE, generation);
+        mHandleHeaders[index] = inputHeader;
+
+        // Add this slot to the head of the linked list.
+        mHandleAddresses[index] = mNextFreeAddress;
+        mNextFreeAddress = (handle_tracker_address_t *) &mHandleAddresses[index];
+        return address;
+    } else {
+        return nullptr;
+    }
+}
+
+oboe_handle_t HandleTracker::buildHandle(handle_tracker_header_t typeGeneration,
+                                         handle_tracker_slot_t index) {
+    return (oboe_handle_t)((typeGeneration << GENERATION_SHIFT) | (index & INDEX_MASK));
+}
+
+handle_tracker_header_t HandleTracker::buildHeader(handle_tracker_type_t type,
+                                    handle_tracker_generation_t generation)
+{
+    return (handle_tracker_header_t) (((type & TYPE_MASK) << GENERATION_SIZE)
+        | (generation & GENERATION_MASK));
+}
+
+handle_tracker_slot_t HandleTracker::extractIndex(oboe_handle_t handle)
+{
+    return handle & INDEX_MASK;
+}
+
+handle_tracker_generation_t HandleTracker::extractGeneration(oboe_handle_t handle)
+{
+    return (handle >> GENERATION_SHIFT) & GENERATION_MASK;
+}
diff --git a/media/liboboe/src/utility/HandleTracker.h b/media/liboboe/src/utility/HandleTracker.h
new file mode 100644
index 0000000..da5b654
--- /dev/null
+++ b/media/liboboe/src/utility/HandleTracker.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UTILITY_HANDLETRACKER_H
+#define UTILITY_HANDLETRACKER_H
+
+#include <stdint.h>
+
+typedef int32_t  handle_tracker_type_t;       // what kind of handle
+typedef int32_t  handle_tracker_slot_t;       // index in allocation table
+typedef int32_t  handle_tracker_generation_t; // incremented when slot used
+typedef uint16_t handle_tracker_header_t;     // combines type and generation
+typedef void    *handle_tracker_address_t;    // address of something that is stored here
+
+#define HANDLE_TRACKER_MAX_TYPES    (1 << 3)
+#define HANDLE_TRACKER_MAX_HANDLES  (1 << 16)
+
+/**
+ * Represent Objects using an integer handle that can be used with Java.
+ * This also makes the 'C' ABI more robust.
+ *
+ * Note that this should only be called from a single thread.
+ * If you call it from more than one thread then you need to use your own mutex.
+ */
+class HandleTracker {
+
+public:
+    /**
+     * @param maxHandles cannot exceed HANDLE_TRACKER_MAX_HANDLES
+     */
+    HandleTracker(uint32_t maxHandles);
+    virtual ~HandleTracker();
+
+    /**
+     * Don't use if this returns false;
+     * @return true if the internal allocation succeeded
+     */
+    bool isInitialized() const;
+
+    /**
+     * Store a pointer and return a handle that can be used to retrieve the pointer.
+     *
+     * @param type the type of the object to be tracked
+     * @param address pointer to be converted to a handle
+     * @return a valid handle or a negative error
+     */
+    oboe_handle_t put(handle_tracker_type_t expectedType, handle_tracker_address_t address);
+
+    /**
+     * Get the original pointer associated with the handle.
+     * The handle will be validated to prevent stale handles from being reused.
+     * Note that the validation is designed to prevent common coding errors and not
+     * to prevent deliberate hacking.
+     *
+     * @param expectedType shouldmatch the type we passed to put()
+     * @param handle to be converted to a pointer
+     * @return address associated with handle or nullptr
+     */
+    handle_tracker_address_t get(handle_tracker_type_t expectedType, oboe_handle_t handle) const;
+
+    /**
+     * Free up the storage associated with the handle.
+     * Subsequent attempts to use the handle will fail.
+     *
+     * @param expectedType shouldmatch the type we passed to put()
+     * @param handle to be removed from tracking
+     * @return address associated with handle or nullptr if not found
+     */
+    handle_tracker_address_t remove(handle_tracker_type_t expectedType, oboe_handle_t handle);
+
+private:
+    const int32_t               mMaxHandleCount;   // size of array
+    // This is const after initialization.
+    handle_tracker_address_t  * mHandleAddresses;  // address of objects or a free linked list node
+    // This is const after initialization.
+    handle_tracker_header_t   * mHandleHeaders;    // combination of type and generation
+    handle_tracker_address_t  * mNextFreeAddress; // head of the linked list of free nodes in mHandleAddresses
+
+    /**
+     * Pull slot off of a list of empty slots.
+     * @return index or a negative error
+     */
+    handle_tracker_slot_t allocateSlot();
+
+    /**
+     * Validate the handle and return the corresponding index.
+     * @return slot index or a negative error
+     */
+    handle_tracker_slot_t handleToIndex(oboe_handle_t handle, handle_tracker_type_t type) const;
+
+    /**
+     * Construct a handle from a header and an index.
+     * @param header combination of a type and a generation
+     * @param index slot index returned from allocateSlot
+     * @return handle or a negative error
+     */
+    oboe_handle_t buildHandle(handle_tracker_header_t header, handle_tracker_slot_t index);
+
+    /**
+     * Combine a type and a generation field into a header.
+     */
+    static handle_tracker_header_t buildHeader(handle_tracker_type_t type,
+                handle_tracker_generation_t generation);
+
+    /**
+     * Extract the index from a handle.
+     * Does not validate the handle.
+     * @return index associated with a handle
+     */
+    static handle_tracker_slot_t extractIndex(oboe_handle_t handle);
+
+    /**
+     * Extract the generation from a handle.
+     * Does not validate the handle.
+     * @return generation associated with a handle
+     */
+    static handle_tracker_generation_t extractGeneration(oboe_handle_t handle);
+
+    /**
+     * Increment the generation for the slot, avoiding zero.
+     */
+    handle_tracker_generation_t nextGeneration(handle_tracker_slot_t index);
+
+};
+
+#endif //UTILITY_HANDLETRACKER_H
diff --git a/media/liboboe/src/utility/MonotonicCounter.h b/media/liboboe/src/utility/MonotonicCounter.h
new file mode 100644
index 0000000..befad21
--- /dev/null
+++ b/media/liboboe/src/utility/MonotonicCounter.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UTILITY_MONOTONICCOUNTER_H
+#define UTILITY_MONOTONICCOUNTER_H
+
+#include <stdint.h>
+
+/**
+ * Maintain a 64-bit monotonic counter.
+ * Can be used to track a 32-bit counter that wraps or gets reset.
+ *
+ * Note that this is not atomic and has no interior locks.
+ * A caller will need to provide their own exterior locking
+ * if they need to use it from multiple threads.
+ */
+class MonotonicCounter {
+
+public:
+    MonotonicCounter() {};
+    virtual ~MonotonicCounter() {};
+
+    /**
+     * @return current value of the counter
+     */
+    int64_t get() const {
+        return mCounter64;
+    }
+
+    /**
+     * Advance the counter if delta is positive.
+     * @return current value of the counter
+     */
+    int64_t increment(int64_t delta) {
+        if (delta > 0) {
+            mCounter64 += delta;
+        }
+        return mCounter64;
+    }
+
+    /**
+     * Advance the 64-bit counter if (current32 - previousCurrent32) > 0.
+     * This can be used to convert a 32-bit counter that may be wrapping into
+     * a monotonic 64-bit counter.
+     *
+     * This counter32 should NOT be allowed to advance by more than 0x7FFFFFFF between calls.
+     * Think of the wrapping counter like a sine wave. If the frequency of the signal
+     * is more than half the sampling rate (Nyquist rate) then you cannot measure it properly.
+     * If the counter wraps around every 24 hours then we should measure it with a period
+     * of less than 12 hours.
+     *
+     * @return current value of the 64-bit counter
+     */
+    int64_t update32(int32_t counter32) {
+        int32_t delta = counter32 - mCounter32;
+        // protect against the mCounter64 going backwards
+        if (delta > 0) {
+            mCounter64 += delta;
+            mCounter32 = counter32;
+        }
+        return mCounter64;
+    }
+
+    /**
+     * Reset the stored value of the 32-bit counter.
+     * This is used if your counter32 has been reset to zero.
+     */
+    void reset32() {
+        mCounter32 = 0;
+    }
+
+private:
+    int64_t mCounter64 = 0;
+    int32_t mCounter32 = 0;
+};
+
+
+#endif //UTILITY_MONOTONICCOUNTER_H
diff --git a/media/liboboe/src/utility/OboeUtilities.cpp b/media/liboboe/src/utility/OboeUtilities.cpp
new file mode 100644
index 0000000..b28f7c7
--- /dev/null
+++ b/media/liboboe/src/utility/OboeUtilities.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OboeAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+#include "oboe/OboeDefinitions.h"
+#include "OboeUtilities.h"
+
+using namespace android;
+
+oboe_size_bytes_t OboeConvert_formatToSizeInBytes(oboe_audio_format_t format) {
+    oboe_datatype_t dataType = OBOE_AUDIO_FORMAT_DATA_TYPE(format);
+    oboe_size_bytes_t size;
+    switch (dataType) {
+        case OBOE_AUDIO_DATATYPE_UINT8:
+            size = sizeof(uint8_t);
+            break;
+        case OBOE_AUDIO_DATATYPE_INT16:
+            size = sizeof(int16_t);
+            break;
+        case OBOE_AUDIO_DATATYPE_INT32:
+        case OBOE_AUDIO_DATATYPE_INT824:
+            size = sizeof(int32_t);
+            break;
+        case OBOE_AUDIO_DATATYPE_FLOAT32:
+            size = sizeof(float);
+            break;
+        default:
+            size = OBOE_ERROR_ILLEGAL_ARGUMENT;
+            break;
+    }
+    return size;
+}
+
+// TODO This similar to a function in audio_utils. Consider using that instead.
+void OboeConvert_floatToPcm16(const float *source, int32_t numSamples, int16_t *destination) {
+    for (int i = 0; i < numSamples; i++) {
+        float fval = source[i];
+        fval += 1.0; // to avoid discontinuity at 0.0 caused by truncation
+        fval *= 32768.0f;
+        int32_t sample = (int32_t) fval;
+        // clip to 16-bit range
+        if (sample < 0) sample = 0;
+        else if (sample > 0x0FFFF) sample = 0x0FFFF;
+        sample -= 32768; // center at zero
+        destination[i] = (int16_t) sample;
+    }
+}
+
+void OboeConvert_pcm16ToFloat(const float *source, int32_t numSamples, int16_t *destination) {
+    for (int i = 0; i < numSamples; i++) {
+        destination[i] = source[i] * (1.0f / 32768.0f);
+    }
+}
+
+oboe_result_t OboeConvert_androidToOboeError(status_t error) {
+    if (error >= 0) {
+        return error;
+    }
+    oboe_result_t result;
+    switch (error) {
+    case OK:
+        result = OBOE_OK;
+        break;
+    case INVALID_OPERATION:
+        result = OBOE_ERROR_INVALID_STATE;
+        break;
+    case BAD_VALUE:
+        result = OBOE_ERROR_UNEXPECTED_VALUE;
+        break;
+    case WOULD_BLOCK:
+        result = OBOE_ERROR_WOULD_BLOCK;
+        break;
+    // TODO add more error codes
+    default:
+        result = OBOE_ERROR_INTERNAL;
+        break;
+    }
+    return result;
+}
+
+audio_format_t OboeConvert_oboeToAndroidDataFormat(oboe_audio_format_t oboeFormat) {
+    audio_format_t androidFormat;
+    switch (oboeFormat) {
+    case OBOE_AUDIO_FORMAT_PCM16:
+        androidFormat = AUDIO_FORMAT_PCM_16_BIT;
+        break;
+    case OBOE_AUDIO_FORMAT_PCM_FLOAT:
+        androidFormat = AUDIO_FORMAT_PCM_FLOAT;
+        break;
+    case OBOE_AUDIO_FORMAT_PCM824:
+        androidFormat = AUDIO_FORMAT_PCM_8_24_BIT;
+        break;
+    case OBOE_AUDIO_FORMAT_PCM32:
+        androidFormat = AUDIO_FORMAT_PCM_32_BIT;
+        break;
+    default:
+        androidFormat = AUDIO_FORMAT_DEFAULT;
+        ALOGE("OboeConvert_oboeToAndroidDataFormat 0x%08X unrecognized", oboeFormat);
+        break;
+    }
+    return androidFormat;
+}
+
+oboe_audio_format_t OboeConvert_androidToOboeDataFormat(audio_format_t androidFormat) {
+    oboe_audio_format_t oboeFormat = OBOE_AUDIO_FORMAT_INVALID;
+    switch (androidFormat) {
+    case AUDIO_FORMAT_PCM_16_BIT:
+        oboeFormat = OBOE_AUDIO_FORMAT_PCM16;
+        break;
+    case AUDIO_FORMAT_PCM_FLOAT:
+        oboeFormat = OBOE_AUDIO_FORMAT_PCM_FLOAT;
+        break;
+    case AUDIO_FORMAT_PCM_32_BIT:
+        oboeFormat = OBOE_AUDIO_FORMAT_PCM32;
+        break;
+    case AUDIO_FORMAT_PCM_8_24_BIT:
+        oboeFormat = OBOE_AUDIO_FORMAT_PCM824;
+        break;
+    default:
+        oboeFormat = OBOE_AUDIO_FORMAT_INVALID;
+        ALOGE("OboeConvert_androidToOboeDataFormat 0x%08X unrecognized", androidFormat);
+        break;
+    }
+    return oboeFormat;
+}
+
+oboe_size_bytes_t OboeConvert_framesToBytes(oboe_size_frames_t numFrames,
+                                            oboe_size_bytes_t bytesPerFrame,
+                                            oboe_size_bytes_t *sizeInBytes) {
+    // TODO implement more elegantly
+    const int32_t maxChannels = 256; // ridiculously large
+    const oboe_size_frames_t maxBytesPerFrame = maxChannels * sizeof(float);
+    // Prevent overflow by limiting multiplicands.
+    if (bytesPerFrame > maxBytesPerFrame || numFrames > (0x3FFFFFFF / maxBytesPerFrame)) {
+        ALOGE("size overflow, numFrames = %d, frameSize = %zd", numFrames, bytesPerFrame);
+        return OBOE_ERROR_OUT_OF_RANGE;
+    }
+    *sizeInBytes = numFrames * bytesPerFrame;
+    return OBOE_OK;
+}
diff --git a/media/liboboe/src/utility/OboeUtilities.h b/media/liboboe/src/utility/OboeUtilities.h
new file mode 100644
index 0000000..974ccf6
--- /dev/null
+++ b/media/liboboe/src/utility/OboeUtilities.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UTILITY_OBOEUTILITIES_H
+#define UTILITY_OBOEUTILITIES_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <hardware/audio.h>
+
+#include "oboe/OboeDefinitions.h"
+
+oboe_result_t OboeConvert_androidToOboeError(android::status_t error);
+
+void OboeConvert_floatToPcm16(const float *source, int32_t numSamples, int16_t *destination);
+
+void OboeConvert_pcm16ToFloat(const int16_t *source, int32_t numSamples, float *destination);
+
+/**
+ * Calculate the number of bytes and prevent numeric overflow.
+ * @param numFrames frame count
+ * @param bytesPerFrame size of a frame in bytes
+ * @param sizeInBytes total size in bytes
+ * @return OBOE_OK or negative error, eg. OBOE_ERROR_OUT_OF_RANGE
+ */
+oboe_size_bytes_t OboeConvert_framesToBytes(oboe_size_frames_t numFrames,
+                                            oboe_size_bytes_t bytesPerFrame,
+                                            oboe_size_bytes_t *sizeInBytes);
+
+audio_format_t OboeConvert_oboeToAndroidDataFormat(oboe_audio_format_t oboe_format);
+
+oboe_audio_format_t OboeConvert_androidToOboeDataFormat(audio_format_t format);
+
+/**
+ * @return the size of a sample of the given format in bytes or OBOE_ERROR_ILLEGAL_ARGUMENT
+ */
+oboe_size_bytes_t OboeConvert_formatToSizeInBytes(oboe_audio_format_t format);
+
+#endif //UTILITY_OBOEUTILITIES_H
diff --git a/media/liboboe/src/utility/README.md b/media/liboboe/src/utility/README.md
new file mode 100644
index 0000000..9db926a
--- /dev/null
+++ b/media/liboboe/src/utility/README.md
@@ -0,0 +1,3 @@
+The utility folder contains things that may be shared between the Oboe client and server.
+They might also be handy outside Oboe.
+They generally do not depend on Oboe functionality.
diff --git a/media/liboboe/tests/Android.mk b/media/liboboe/tests/Android.mk
new file mode 100644
index 0000000..f2c65d9
--- /dev/null
+++ b/media/liboboe/tests/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/liboboe/include \
+    frameworks/av/media/liboboe/src/core \
+    frameworks/av/media/liboboe/src/utility
+LOCAL_SRC_FILES:= test_oboe_api.cpp
+LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \
+                          libbinder libcutils libutils \
+                          libaudioclient liblog
+LOCAL_STATIC_LIBRARIES := liboboe
+LOCAL_MODULE := test_oboe_api
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/liboboe/include \
+    frameworks/av/media/liboboe/src/core \
+    frameworks/av/media/liboboe/src/utility
+LOCAL_SRC_FILES:= test_handle_tracker.cpp
+LOCAL_SHARED_LIBRARIES := libbinder libcutils libutils liblog
+LOCAL_STATIC_LIBRARIES := liboboe
+LOCAL_MODULE := test_handle_tracker
+include $(BUILD_NATIVE_TEST)
diff --git a/media/liboboe/tests/test_handle_tracker.cpp b/media/liboboe/tests/test_handle_tracker.cpp
new file mode 100644
index 0000000..ae7384e
--- /dev/null
+++ b/media/liboboe/tests/test_handle_tracker.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit tests for Oboe Handle Tracker
+
+#include <stdlib.h>
+#include <math.h>
+
+#include <gtest/gtest.h>
+
+#include <oboe/OboeDefinitions.h>
+#include "HandleTracker.h"
+
+// Test adding one address.
+TEST(test_handle_tracker, oboe_handle_tracker) {
+    const int MAX_HANDLES = 4;
+    HandleTracker tracker(MAX_HANDLES);
+    handle_tracker_type_t type = 3; // arbitrary generic type
+    int data; // something that has an address we can use
+    handle_tracker_address_t found;
+
+    // repeat the test several times to see if it breaks
+    const int SEVERAL = 5; // arbitrary
+    for (int i = 0; i < SEVERAL; i++) {
+        // should fail to find a bogus handle
+        found = tracker.get(type, 0);  // bad handle
+        EXPECT_EQ(nullptr, found);
+
+        // create a valid handle and use it to lookup the object again
+        oboe_handle_t dataHandle = tracker.put(type, &data);
+        ASSERT_TRUE(dataHandle > 0);
+        found = tracker.get(type, dataHandle);
+        EXPECT_EQ(&data, found);
+        found = tracker.get(type, 0); // bad handle
+        EXPECT_EQ(nullptr, found);
+
+        // wrong type
+        found = tracker.get(type+1, dataHandle);
+        EXPECT_EQ(nullptr, found);
+
+        // remove from storage
+        found = tracker.remove(type, dataHandle);
+        EXPECT_EQ(&data, found);
+        // should fail the second time
+        found = tracker.remove(type, dataHandle);
+        EXPECT_EQ(NULL, found);
+    }
+}
+
+// Test filling the tracker.
+TEST(test_handle_tracker, oboe_full_up) {
+    const int MAX_HANDLES = 5;
+    HandleTracker tracker(MAX_HANDLES);
+    handle_tracker_type_t type = 4; // arbitrary generic type
+    int data[MAX_HANDLES];
+    oboe_handle_t handles[MAX_HANDLES];
+    handle_tracker_address_t found;
+
+    // repeat the test several times to see if it breaks
+    const int SEVERAL = 5; // arbitrary
+    for (int i = 0; i < SEVERAL; i++) {
+        for (int i = 0; i < MAX_HANDLES; i++) {
+            // add a handle
+            handles[i] = tracker.put(type, &data[i]);
+            ASSERT_TRUE(handles[i] > 0);
+            found = tracker.get(type, handles[i]);
+            EXPECT_EQ(&data[i], found);
+        }
+
+        // Now that it is full, try to add one more.
+        oboe_handle_t handle = tracker.put(type, &data[0]);
+        EXPECT_TRUE(handle < 0);
+
+        for (int i = 0; i < MAX_HANDLES; i++) {
+            // look up each handle
+            found = tracker.get(type, handles[i]);
+            EXPECT_EQ(&data[i], found);
+        }
+
+        // remove one from storage
+        found = tracker.remove(type, handles[2]);
+        EXPECT_EQ(&data[2], found);
+        // now try to look up the same handle and fail
+        found = tracker.get(type, handles[2]);
+        EXPECT_EQ(nullptr, found);
+
+        // add that same one back
+        handle = tracker.put(type, &data[2]);
+        ASSERT_TRUE(handle > 0);
+        found = tracker.get(type, handle);
+        EXPECT_EQ(&data[2], found);
+        // now use a stale handle again with a valid index and fail
+        found = tracker.get(type, handles[2]);
+        EXPECT_EQ(nullptr, found);
+
+        // remove them all
+        handles[2] = handle;
+        for (int i = 0; i < MAX_HANDLES; i++) {
+            // look up each handle
+            found = tracker.remove(type, handles[i]);
+            EXPECT_EQ(&data[i], found);
+        }
+    }
+}
diff --git a/media/liboboe/tests/test_oboe_api.cpp b/media/liboboe/tests/test_oboe_api.cpp
new file mode 100644
index 0000000..acf3000
--- /dev/null
+++ b/media/liboboe/tests/test_oboe_api.cpp
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Unit tests for Oboe 'C' API.
+
+#include <stdlib.h>
+#include <math.h>
+
+#include <gtest/gtest.h>
+
+#include <oboe/OboeDefinitions.h>
+#include <oboe/OboeAudio.h>
+#include "OboeUtilities.h"
+
+#define DEFAULT_STATE_TIMEOUT  (500 * OBOE_NANOS_PER_MILLISECOND)
+
+// Test OboeStreamBuilder
+TEST(test_oboe_api, oboe_stream_builder) {
+    const oboe_sample_rate_t requestedSampleRate1 = 48000;
+    const oboe_sample_rate_t requestedSampleRate2 = 44100;
+    const int32_t requestedSamplesPerFrame = 2;
+    const oboe_audio_format_t requestedDataFormat = OBOE_AUDIO_DATATYPE_INT16;
+
+    oboe_sample_rate_t sampleRate = 0;
+    int32_t samplesPerFrame = 0;
+    oboe_audio_format_t actualDataFormat;
+    OboeStreamBuilder oboeBuilder1;
+    OboeStreamBuilder oboeBuilder2;
+
+    oboe_result_t result = OBOE_OK;
+
+    // Use an OboeStreamBuilder to define the stream.
+    result = Oboe_createStreamBuilder(&oboeBuilder1);
+    ASSERT_EQ(OBOE_OK, result);
+
+    // Request stream properties.
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_setSampleRate(oboeBuilder1, requestedSampleRate1));
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_setSamplesPerFrame(oboeBuilder1, requestedSamplesPerFrame));
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_setFormat(oboeBuilder1, requestedDataFormat));
+
+    // Check to make sure builder saved the properties.
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_getSampleRate(oboeBuilder1, &sampleRate));
+    EXPECT_EQ(requestedSampleRate1, sampleRate);
+
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_getSamplesPerFrame(oboeBuilder1, &samplesPerFrame));
+    EXPECT_EQ(requestedSamplesPerFrame, samplesPerFrame);
+
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_getFormat(oboeBuilder1, &actualDataFormat));
+    EXPECT_EQ(requestedDataFormat, actualDataFormat);
+
+    result = OboeStreamBuilder_getSampleRate(0x0BADCAFE, &sampleRate); // ridiculous token
+    EXPECT_EQ(OBOE_ERROR_INVALID_HANDLE, result);
+
+    // Create a second builder and make sure they do not collide.
+    ASSERT_EQ(OBOE_OK, Oboe_createStreamBuilder(&oboeBuilder2));
+    ASSERT_NE(oboeBuilder1, oboeBuilder2);
+
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_setSampleRate(oboeBuilder2, requestedSampleRate2));
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_getSampleRate(oboeBuilder1, &sampleRate));
+    EXPECT_EQ(requestedSampleRate1, sampleRate);
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_getSampleRate(oboeBuilder2, &sampleRate));
+    EXPECT_EQ(requestedSampleRate2, sampleRate);
+
+    // Delete the builder.
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_delete(oboeBuilder1));
+
+    // Now it should no longer be valid.
+    // Note that test assumes we are using the HandleTracker. If we use plain pointers
+    // then it will be difficult to detect this kind of error.
+    result = OboeStreamBuilder_getSampleRate(oboeBuilder1, &sampleRate); // stale token
+    EXPECT_EQ(OBOE_ERROR_INVALID_HANDLE, result);
+
+    // Second builder should still be valid.
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_getSampleRate(oboeBuilder2, &sampleRate));
+    EXPECT_EQ(requestedSampleRate2, sampleRate);
+
+    // Delete the second builder.
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_delete(oboeBuilder2));
+
+    // Now it should no longer be valid. Assumes HandlerTracker used.
+    EXPECT_EQ(OBOE_ERROR_INVALID_HANDLE, OboeStreamBuilder_getSampleRate(oboeBuilder2, &sampleRate));
+}
+
+
+// Test creating a default stream with everything unspecified.
+TEST(test_oboe_api, oboe_stream_unspecified) {
+    OboeStreamBuilder oboeBuilder;
+    OboeStream oboeStream;
+    oboe_result_t result = OBOE_OK;
+
+    // Use an OboeStreamBuilder to define the stream.
+    result = Oboe_createStreamBuilder(&oboeBuilder);
+    ASSERT_EQ(OBOE_OK, result);
+
+    // Create an OboeStream using the Builder.
+    ASSERT_EQ(OBOE_OK, OboeStreamBuilder_openStream(oboeBuilder, &oboeStream));
+
+    // Cleanup
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_delete(oboeBuilder));
+    EXPECT_EQ(OBOE_OK, OboeStream_close(oboeStream));
+}
+
+// Test Writing to an OboeStream
+TEST(test_oboe_api, oboe_stream) {
+    const oboe_sample_rate_t requestedSampleRate = 48000;
+    const oboe_sample_rate_t requestedSamplesPerFrame = 2;
+    const oboe_audio_format_t requestedDataFormat = OBOE_AUDIO_DATATYPE_INT16;
+    //const oboe_sharing_mode_t requestedSharingMode = OBOE_SHARING_MODE_EXCLUSIVE; // MMAP NOIRQ
+    const oboe_sharing_mode_t requestedSharingMode = OBOE_SHARING_MODE_LEGACY; // AudioTrack
+
+    oboe_sample_rate_t actualSampleRate = -1;
+    int32_t actualSamplesPerFrame = -1;
+    oboe_audio_format_t actualDataFormat = OBOE_AUDIO_FORMAT_PCM824;
+    oboe_sharing_mode_t actualSharingMode;
+    oboe_size_frames_t framesPerBurst = -1;
+
+    oboe_size_frames_t framesWritten = 0;
+    oboe_size_frames_t framesPrimed = 0;
+    oboe_position_frames_t framesTotal = 0;
+    oboe_position_frames_t oboeFramesRead = 0;
+    oboe_position_frames_t oboeFramesRead1 = 0;
+    oboe_position_frames_t oboeFramesRead2 = 0;
+    oboe_position_frames_t oboeFramesWritten = 0;
+
+    oboe_nanoseconds_t timeoutNanos;
+
+    oboe_stream_state_t state = OBOE_STREAM_STATE_UNINITIALIZED;
+    OboeStreamBuilder oboeBuilder;
+    OboeStream oboeStream;
+
+    oboe_result_t result = OBOE_OK;
+
+    // Use an OboeStreamBuilder to define the stream.
+    result = Oboe_createStreamBuilder(&oboeBuilder);
+    ASSERT_EQ(OBOE_OK, result);
+
+    // Request stream properties.
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_setSampleRate(oboeBuilder, requestedSampleRate));
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_setSamplesPerFrame(oboeBuilder, requestedSamplesPerFrame));
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_setFormat(oboeBuilder, requestedDataFormat));
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_setSharingMode(oboeBuilder, requestedSharingMode));
+
+    // Create an OboeStream using the Builder.
+    ASSERT_EQ(OBOE_OK, OboeStreamBuilder_openStream(oboeBuilder, &oboeStream));
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_delete(oboeBuilder));
+
+    EXPECT_EQ(OBOE_OK, OboeStream_getState(oboeStream, &state));
+    EXPECT_EQ(OBOE_STREAM_STATE_OPEN, state);
+
+    // Check to see what kind of stream we actually got.
+    EXPECT_EQ(OBOE_OK, OboeStream_getSampleRate(oboeStream, &actualSampleRate));
+    EXPECT_TRUE(actualSampleRate >= 44100 && actualSampleRate <= 96000);  // TODO what is range?
+
+    EXPECT_EQ(OBOE_OK, OboeStream_getSamplesPerFrame(oboeStream, &actualSamplesPerFrame));
+    EXPECT_TRUE(actualSamplesPerFrame >= 1 && actualSamplesPerFrame <= 16); // TODO what is max?
+
+    EXPECT_EQ(OBOE_OK, OboeStream_getSharingMode(oboeStream, &actualSharingMode));
+    EXPECT_TRUE(actualSharingMode == OBOE_SHARING_MODE_EXCLUSIVE
+            || actualSharingMode == OBOE_SHARING_MODE_LEGACY);
+
+    EXPECT_EQ(OBOE_OK, OboeStream_getFramesPerBurst(oboeStream, &framesPerBurst));
+    EXPECT_TRUE(framesPerBurst >= 16 && framesPerBurst <= 1024); // TODO what is min/max?
+
+    // Allocate a buffer for the audio data.
+    int16_t *data = new int16_t[framesPerBurst * actualSamplesPerFrame];
+    ASSERT_TRUE(NULL != data);
+
+    timeoutNanos = 0;
+    do {
+        framesWritten = OboeStream_write(oboeStream, data, framesPerBurst, timeoutNanos);
+        // There should be some room for priming the buffer.
+        framesTotal += framesWritten;
+        ASSERT_GE(framesWritten, 0);
+        ASSERT_LE(framesWritten, framesPerBurst);
+    } while(framesWritten > 0);
+    ASSERT_TRUE(framesTotal > 0);
+
+    // Start and wait for server to respond.
+    ASSERT_EQ(OBOE_OK, OboeStream_requestStart(oboeStream));
+    ASSERT_EQ(OBOE_OK, OboeStream_waitForStateChange(oboeStream,
+                                                     OBOE_STREAM_STATE_STARTING,
+                                                     &state,
+                                                     DEFAULT_STATE_TIMEOUT));
+    EXPECT_EQ(OBOE_STREAM_STATE_STARTED, state);
+
+    // Write some data while we are running. Read counter should be advancing.
+    int loops = 1 * actualSampleRate / framesPerBurst; // 1 second
+    ASSERT_LT(2, loops); // detect absurdly high framesPerBurst
+    timeoutNanos = 10 * OBOE_NANOS_PER_SECOND * framesPerBurst / actualSampleRate; // bursts
+    framesWritten = 1;
+    ASSERT_EQ(OBOE_OK, OboeStream_getFramesRead(oboeStream, &oboeFramesRead));
+    oboeFramesRead1 = oboeFramesRead;
+    oboe_nanoseconds_t beginTime = Oboe_getNanoseconds(OBOE_CLOCK_MONOTONIC);
+    do {
+        framesWritten = OboeStream_write(oboeStream, data, framesPerBurst, timeoutNanos);
+        ASSERT_GE(framesWritten, 0);
+        ASSERT_LE(framesWritten, framesPerBurst);
+
+        framesTotal += framesWritten;
+        EXPECT_EQ(OBOE_OK, OboeStream_getFramesWritten(oboeStream, &oboeFramesWritten));
+        EXPECT_EQ(framesTotal, oboeFramesWritten);
+
+        // Try to get a more accurate measure of the sample rate.
+        if (beginTime == 0) {
+            EXPECT_EQ(OBOE_OK, OboeStream_getFramesRead(oboeStream, &oboeFramesRead));
+            if (oboeFramesRead > oboeFramesRead1) { // is read pointer advancing
+                beginTime = Oboe_getNanoseconds(OBOE_CLOCK_MONOTONIC);
+                oboeFramesRead1 = oboeFramesRead;
+            }
+        }
+    } while (framesWritten > 0 && loops-- > 0);
+
+    EXPECT_EQ(OBOE_OK, OboeStream_getFramesRead(oboeStream, &oboeFramesRead2));
+    oboe_nanoseconds_t endTime = Oboe_getNanoseconds(OBOE_CLOCK_MONOTONIC);
+    ASSERT_GT(oboeFramesRead2, 0);
+    ASSERT_GT(oboeFramesRead2, oboeFramesRead1);
+    ASSERT_LE(oboeFramesRead2, oboeFramesWritten);
+
+    // TODO why is legacy so inaccurate?
+    const double rateTolerance = 200.0; // arbitrary tolerance for sample rate
+    if (requestedSharingMode != OBOE_SHARING_MODE_LEGACY) {
+        // Calculate approximate sample rate and compare with stream rate.
+        double seconds = (endTime - beginTime) / (double) OBOE_NANOS_PER_SECOND;
+        double measuredRate = (oboeFramesRead2 - oboeFramesRead1) / seconds;
+        ASSERT_NEAR(actualSampleRate, measuredRate, rateTolerance);
+    }
+
+    // Request async pause and wait for server to say that it has completed the pause.
+    ASSERT_EQ(OBOE_OK, OboeStream_requestPause(oboeStream));
+    EXPECT_EQ(OBOE_OK, OboeStream_waitForStateChange(oboeStream,
+                                            OBOE_STREAM_STATE_PAUSING,
+                                            &state,
+                                            DEFAULT_STATE_TIMEOUT));
+    EXPECT_EQ(OBOE_STREAM_STATE_PAUSED, state);
+
+    // Make sure the read counter is not advancing when we are paused.
+    ASSERT_EQ(OBOE_OK, OboeStream_getFramesRead(oboeStream, &oboeFramesRead));
+    ASSERT_GE(oboeFramesRead, oboeFramesRead2); // monotonic increase
+
+    // Use this to sleep by waiting for something that won't happen.
+    OboeStream_waitForStateChange(oboeStream, OBOE_STREAM_STATE_PAUSED, &state, timeoutNanos);
+    ASSERT_EQ(OBOE_OK, OboeStream_getFramesRead(oboeStream, &oboeFramesRead2));
+    EXPECT_EQ(oboeFramesRead, oboeFramesRead2);
+
+    // Fill up the buffer.
+    timeoutNanos = 0;
+    loops = 100;
+    do {
+        framesWritten = OboeStream_write(oboeStream, data, framesPerBurst, timeoutNanos);
+        framesTotal += framesWritten;
+    } while (framesWritten > 0 && loops-- > 0);
+    EXPECT_EQ(0, framesWritten);
+
+    // Flush and wait for server to respond.
+    ASSERT_EQ(OBOE_OK, OboeStream_requestFlush(oboeStream));
+    EXPECT_EQ(OBOE_OK, OboeStream_waitForStateChange(oboeStream,
+                                                     OBOE_STREAM_STATE_FLUSHING,
+                                                     &state,
+                                                     DEFAULT_STATE_TIMEOUT));
+    EXPECT_EQ(OBOE_STREAM_STATE_FLUSHED, state);
+
+    // After a flush, the read counter should be caught up with the write counter.
+    EXPECT_EQ(OBOE_OK, OboeStream_getFramesWritten(oboeStream, &oboeFramesWritten));
+    EXPECT_EQ(framesTotal, oboeFramesWritten);
+    EXPECT_EQ(OBOE_OK, OboeStream_getFramesRead(oboeStream, &oboeFramesRead));
+    EXPECT_EQ(oboeFramesRead, oboeFramesWritten);
+
+    // The buffer should be empty after a flush so we should be able to write.
+    framesWritten = OboeStream_write(oboeStream, data, framesPerBurst, timeoutNanos);
+    // There should be some room for priming the buffer.
+    ASSERT_TRUE(framesWritten > 0 && framesWritten <= framesPerBurst);
+
+    EXPECT_EQ(OBOE_OK, OboeStream_close(oboeStream));
+}
+
+#define OBOE_THREAD_ANSWER          1826375
+#define OBOE_THREAD_DURATION_MSEC       500
+
+static void *TestOboeStreamThreadProc(void *arg) {
+    OboeStream oboeStream = (OboeStream) reinterpret_cast<size_t>(arg);
+    oboe_stream_state_t state;
+
+    // Use this to sleep by waiting for something that won't happen.
+    EXPECT_EQ(OBOE_OK, OboeStream_getState(oboeStream, &state));
+    OboeStream_waitForStateChange(oboeStream, OBOE_STREAM_STATE_PAUSED, &state,
+            OBOE_THREAD_DURATION_MSEC * OBOE_NANOS_PER_MILLISECOND);
+    return reinterpret_cast<void *>(OBOE_THREAD_ANSWER);
+}
+
+// Test creating a stream related thread.
+TEST(test_oboe_api, oboe_stream_thread_basic) {
+    OboeStreamBuilder oboeBuilder;
+    OboeStream oboeStream;
+    oboe_result_t result = OBOE_OK;
+    void *threadResult;
+
+    // Use an OboeStreamBuilder to define the stream.
+    result = Oboe_createStreamBuilder(&oboeBuilder);
+    ASSERT_EQ(OBOE_OK, result);
+
+    // Create an OboeStream using the Builder.
+    ASSERT_EQ(OBOE_OK, OboeStreamBuilder_openStream(oboeBuilder, &oboeStream));
+
+    // Start a thread.
+    ASSERT_EQ(OBOE_OK, OboeStream_createThread(oboeStream,
+            10 * OBOE_NANOS_PER_MILLISECOND,
+            TestOboeStreamThreadProc,
+            reinterpret_cast<void *>(oboeStream)));
+    // Thread already started.
+    ASSERT_NE(OBOE_OK, OboeStream_createThread(oboeStream,   // should fail!
+            10 * OBOE_NANOS_PER_MILLISECOND,
+            TestOboeStreamThreadProc,
+            reinterpret_cast<void *>(oboeStream)));
+
+    // Wait for the thread to finish.
+    ASSERT_EQ(OBOE_OK, OboeStream_joinThread(oboeStream,
+            &threadResult, 2 * OBOE_THREAD_DURATION_MSEC * OBOE_NANOS_PER_MILLISECOND));
+    // The thread returns a special answer.
+    ASSERT_EQ(OBOE_THREAD_ANSWER, (int)reinterpret_cast<size_t>(threadResult));
+
+    // Thread should already be joined.
+    ASSERT_NE(OBOE_OK, OboeStream_joinThread(oboeStream,  // should fail!
+            &threadResult, 2 * OBOE_THREAD_DURATION_MSEC * OBOE_NANOS_PER_MILLISECOND));
+
+    // Cleanup
+    EXPECT_EQ(OBOE_OK, OboeStreamBuilder_delete(oboeBuilder));
+    EXPECT_EQ(OBOE_OK, OboeStream_close(oboeStream));
+}
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index bd837ae..f3d622b 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -108,9 +108,9 @@
         libstagefright_mpeg2ts \
         libstagefright_id3 \
         libFLAC \
-        libmedia_helper \
 
 LOCAL_SHARED_LIBRARIES += \
+        libmedia_helper \
         libstagefright_foundation \
         libdl \
         libRScpp \
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index d36ac65..8ba36d5 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -244,7 +244,6 @@
       mDecryptHandle(NULL),
       mDrmManagerClient(NULL) {
     mOriginalExtractor = MediaExtractor::Create(source, mime);
-    mOriginalExtractor->setDrmFlag(true);
     mOriginalExtractor->getMetaData()->setInt32(kKeyIsDRM, 1);
 
     source->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index aeaead5..49f480d 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -160,6 +160,8 @@
             if (!strncmp(drmMime, "drm+es_based+", 13)) {
                 // DRMExtractor sets container metadata kKeyIsDRM to 1
                 return new DRMExtractor(source, drmMime + 14);
+            } else {
+                mime = drmMime + 20; // get real mimetype after "drm+container_based+" prefix
             }
         }
 
@@ -201,28 +203,6 @@
              mime, confidence);
     }
 
-    bool isDrm = false;
-    // DRM MIME type syntax is "drm+type+original" where
-    // type is "es_based" or "container_based" and
-    // original is the content's cleartext MIME type
-    if (!strncmp(mime, "drm+", 4)) {
-        const char *originalMime = strchr(mime+4, '+');
-        if (originalMime == NULL) {
-            // second + not found
-            return NULL;
-        }
-        ++originalMime;
-        if (!strncmp(mime, "drm+es_based+", 13)) {
-            // DRMExtractor sets container metadata kKeyIsDRM to 1
-            return new DRMExtractor(source, originalMime);
-        } else if (!strncmp(mime, "drm+container_based+", 20)) {
-            mime = originalMime;
-            isDrm = true;
-        } else {
-            return NULL;
-        }
-    }
-
     MediaExtractor *ret = NULL;
     if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
             || !strcasecmp(mime, "audio/mp4")) {
@@ -250,14 +230,6 @@
         ret = new MidiExtractor(source);
     }
 
-    if (ret != NULL) {
-       if (isDrm) {
-           ret->setDrmFlag(true);
-       } else {
-           ret->setDrmFlag(false);
-       }
-    }
-
     return ret;
 }
 
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 6f8220f..d25ce6c 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -82,14 +82,6 @@
         return ERROR_UNSUPPORTED;
     }
 
-    sp<MetaData> fileMeta = mImpl->getMetaData();
-    if (mImpl->getDrmFlag()) {
-        // Don't expose decrypted content to Java application
-        mImpl.clear();
-        mImpl = NULL;
-        return ERROR_UNSUPPORTED;
-    }
-
     status_t err = updateDurationAndBitrate();
     if (err == OK) {
         mDataSource = dataSource;
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index 4c4d93e..ea7d5af 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -18,6 +18,7 @@
 
 #include <media/ICrypto.h>
 #include <media/MediaCodecBuffer.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
@@ -74,7 +75,10 @@
                 err = codec->getOutputFormat(&format);
             }
             if (err == OK) {
-                return new SimpleDecodingSource(codec, source, looper, surface != NULL, format);
+                return new SimpleDecodingSource(codec, source, looper,
+                        surface != NULL,
+                        strcmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS) == 0,
+                        format);
             }
 
             ALOGD("Failed to configure codec '%s'", componentName.c_str());
@@ -90,11 +94,12 @@
 
 SimpleDecodingSource::SimpleDecodingSource(
         const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
-        bool usingSurface, const sp<AMessage> &format)
+        bool usingSurface, bool isVorbis, const sp<AMessage> &format)
     : mCodec(codec),
       mSource(source),
       mLooper(looper),
       mUsingSurface(usingSurface),
+      mIsVorbis(isVorbis),
       mProtectedState(format) {
     mCodec->getName(&mComponentName);
 }
@@ -280,16 +285,25 @@
             if (in_buf != NULL) {
                 int64_t timestampUs = 0;
                 CHECK(in_buf->meta_data()->findInt64(kKeyTime, &timestampUs));
-                if (in_buf->range_length() > in_buffer->capacity()) {
+                if (in_buf->range_length() + (mIsVorbis ? 4 : 0) > in_buffer->capacity()) {
                     ALOGW("'%s' received %zu input bytes for buffer of size %zu",
                             mComponentName.c_str(),
-                            in_buf->range_length(), in_buffer->capacity());
+                            in_buf->range_length() + (mIsVorbis ? 4 : 0), in_buffer->capacity());
                 }
+                size_t cpLen = min(in_buf->range_length(), in_buffer->capacity());
                 memcpy(in_buffer->base(), (uint8_t *)in_buf->data() + in_buf->range_offset(),
-                       min(in_buf->range_length(), in_buffer->capacity()));
+                        cpLen );
+
+                if (mIsVorbis) {
+                    int32_t numPageSamples;
+                    if (!in_buf->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
+                        numPageSamples = -1;
+                    }
+                    memcpy(in_buffer->base() + cpLen, &numPageSamples, sizeof(numPageSamples));
+                }
 
                 res = mCodec->queueInputBuffer(
-                        in_ix, 0 /* offset */, in_buf->range_length(),
+                        in_ix, 0 /* offset */, in_buf->range_length() + (mIsVorbis ? 4 : 0),
                         timestampUs, 0 /* flags */);
                 if (res != OK) {
                     ALOGI("[%s] failed to queue input buffer #%zu", mComponentName.c_str(), in_ix);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 5e00c44..883a4dd 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -783,11 +783,6 @@
             }
         }
     }
-
-    // To check whether the media file is drm-protected
-    if (mExtractor->getDrmFlag()) {
-        mMetaData.add(METADATA_KEY_IS_DRM, String8("1"));
-    }
 }
 
 void StagefrightMetadataRetriever::clearMetadata() {
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
index cb7e4aa..58753ff 100644
--- a/media/mtp/Android.mk
+++ b/media/mtp/Android.mk
@@ -19,26 +19,31 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=                                       \
+                  AsyncIO.cpp                           \
                   MtpDataPacket.cpp                     \
                   MtpDebug.cpp                          \
+                  MtpDevHandle.cpp                      \
                   MtpDevice.cpp                         \
-                  MtpEventPacket.cpp                    \
                   MtpDeviceInfo.cpp                     \
+                  MtpEventPacket.cpp                    \
+                  MtpFfsHandle.cpp                      \
                   MtpObjectInfo.cpp                     \
                   MtpPacket.cpp                         \
                   MtpProperty.cpp                       \
                   MtpRequestPacket.cpp                  \
                   MtpResponsePacket.cpp                 \
                   MtpServer.cpp                         \
+                  MtpStorage.cpp                        \
                   MtpStorageInfo.cpp                    \
                   MtpStringBuffer.cpp                   \
-                  MtpStorage.cpp                        \
                   MtpUtils.cpp                          \
 
 LOCAL_MODULE:= libmtp
 
 LOCAL_CFLAGS := -DMTP_DEVICE -DMTP_HOST -Wall -Wextra -Werror
 
-LOCAL_SHARED_LIBRARIES := libutils libcutils liblog libusbhost libbinder
+LOCAL_SHARED_LIBRARIES := libbase libutils libcutils liblog libusbhost libbinder
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/mtp/AsyncIO.cpp b/media/mtp/AsyncIO.cpp
new file mode 100644
index 0000000..a1a98ab
--- /dev/null
+++ b/media/mtp/AsyncIO.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <queue>
+
+#include "AsyncIO.h"
+
+namespace {
+
+void read_func(struct aiocb *aiocbp) {
+    aiocbp->ret = TEMP_FAILURE_RETRY(pread(aiocbp->aio_fildes,
+                aiocbp->aio_buf, aiocbp->aio_nbytes, aiocbp->aio_offset));
+    if (aiocbp->ret == -1) aiocbp->error = errno;
+}
+
+void write_func(struct aiocb *aiocbp) {
+    aiocbp->ret = TEMP_FAILURE_RETRY(pwrite(aiocbp->aio_fildes,
+                aiocbp->aio_buf, aiocbp->aio_nbytes, aiocbp->aio_offset));
+    if (aiocbp->ret == -1) aiocbp->error = errno;
+}
+
+void splice_read_func(struct aiocb *aiocbp) {
+    aiocbp->ret = TEMP_FAILURE_RETRY(splice(aiocbp->aio_fildes,
+                (off64_t*) &aiocbp->aio_offset, aiocbp->aio_sink,
+                NULL, aiocbp->aio_nbytes, 0));
+    if (aiocbp->ret == -1) aiocbp->error = errno;
+}
+
+void splice_write_func(struct aiocb *aiocbp) {
+    aiocbp->ret = TEMP_FAILURE_RETRY(splice(aiocbp->aio_fildes, NULL,
+                aiocbp->aio_sink, (off64_t*) &aiocbp->aio_offset,
+                aiocbp->aio_nbytes, 0));
+    if (aiocbp->ret == -1) aiocbp->error = errno;
+}
+
+std::queue<std::unique_ptr<struct aiocb>> queue;
+std::mutex queue_lock;
+std::condition_variable queue_cond;
+std::condition_variable write_cond;
+int done = 1;
+void splice_write_pool_func(int) {
+    while(1) {
+        std::unique_lock<std::mutex> lk(queue_lock);
+        queue_cond.wait(lk, []{return !queue.empty() || done;});
+        if (queue.empty() && done) {
+            return;
+        }
+        std::unique_ptr<struct aiocb> aiocbp = std::move(queue.front());
+        queue.pop();
+        lk.unlock();
+        write_cond.notify_one();
+        splice_write_func(aiocbp.get());
+        close(aiocbp->aio_fildes);
+    }
+}
+
+void write_pool_func(int) {
+    while(1) {
+        std::unique_lock<std::mutex> lk(queue_lock);
+        queue_cond.wait(lk, []{return !queue.empty() || done;});
+        if (queue.empty() && done) {
+            return;
+        }
+        std::unique_ptr<struct aiocb> aiocbp = std::move(queue.front());
+        queue.pop();
+        lk.unlock();
+        write_cond.notify_one();
+        aiocbp->ret = TEMP_FAILURE_RETRY(pwrite(aiocbp->aio_fildes,
+                    aiocbp->aio_pool_buf.get(), aiocbp->aio_nbytes, aiocbp->aio_offset));
+        if (aiocbp->ret == -1) aiocbp->error = errno;
+    }
+}
+
+constexpr int NUM_THREADS = 1;
+constexpr int MAX_QUEUE_SIZE = 10;
+std::thread pool[NUM_THREADS];
+
+} // end anonymous namespace
+
+void aio_pool_init(void(f)(int)) {
+    CHECK(done == 1);
+    done = 0;
+    for (int i = 0; i < NUM_THREADS; i++) {
+        pool[i] = std::thread(f, i);
+    }
+}
+
+void aio_pool_splice_init() {
+    aio_pool_init(splice_write_pool_func);
+}
+
+void aio_pool_write_init() {
+    aio_pool_init(write_pool_func);
+}
+
+void aio_pool_end() {
+    done = 1;
+    for (int i = 0; i < NUM_THREADS; i++) {
+        std::unique_lock<std::mutex> lk(queue_lock);
+        lk.unlock();
+        queue_cond.notify_one();
+    }
+
+    for (int i = 0; i < NUM_THREADS; i++) {
+        pool[i].join();
+    }
+}
+
+// used for both writes and splices depending on which init was used before.
+int aio_pool_write(struct aiocb *aiocbp) {
+    std::unique_lock<std::mutex> lk(queue_lock);
+    write_cond.wait(lk, []{return queue.size() < MAX_QUEUE_SIZE;});
+    queue.push(std::unique_ptr<struct aiocb>(aiocbp));
+    lk.unlock();
+    queue_cond.notify_one();
+    return 0;
+}
+
+int aio_read(struct aiocb *aiocbp) {
+    aiocbp->thread = std::thread(read_func, aiocbp);
+    return 0;
+}
+
+int aio_write(struct aiocb *aiocbp) {
+    aiocbp->thread = std::thread(write_func, aiocbp);
+    return 0;
+}
+
+int aio_splice_read(struct aiocb *aiocbp) {
+    aiocbp->thread = std::thread(splice_read_func, aiocbp);
+    return 0;
+}
+
+int aio_splice_write(struct aiocb *aiocbp) {
+    aiocbp->thread = std::thread(splice_write_func, aiocbp);
+    return 0;
+}
+
+int aio_error(const struct aiocb *aiocbp) {
+    return aiocbp->error;
+}
+
+ssize_t aio_return(struct aiocb *aiocbp) {
+    return aiocbp->ret;
+}
+
+int aio_suspend(struct aiocb *aiocbp[], int n,
+        const struct timespec *) {
+    for (int i = 0; i < n; i++) {
+        aiocbp[i]->thread.join();
+    }
+    return 0;
+}
+
+int aio_cancel(int, struct aiocb *) {
+    // Not implemented
+    return -1;
+}
+
diff --git a/media/mtp/AsyncIO.h b/media/mtp/AsyncIO.h
new file mode 100644
index 0000000..f7515a2
--- /dev/null
+++ b/media/mtp/AsyncIO.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ASYNCIO_H
+#define _ASYNCIO_H
+
+#include <fcntl.h>
+#include <linux/aio_abi.h>
+#include <memory>
+#include <signal.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <time.h>
+#include <thread>
+#include <unistd.h>
+
+/**
+ * Provides a subset of POSIX aio operations, as well
+ * as similar operations with splice and threadpools.
+ */
+
+struct aiocb {
+    int aio_fildes;     // Assumed to be the source for splices
+    void *aio_buf;      // Unused for splices
+
+    // Used for threadpool operations only, freed automatically
+    std::unique_ptr<char[]> aio_pool_buf;
+
+    off_t aio_offset;
+    size_t aio_nbytes;
+
+    int aio_sink;       // Unused for non splice r/w
+
+    // Used internally
+    std::thread thread;
+    ssize_t ret;
+    int error;
+};
+
+// Submit a request for IO to be completed
+int aio_read(struct aiocb *);
+int aio_write(struct aiocb *);
+int aio_splice_read(struct aiocb *);
+int aio_splice_write(struct aiocb *);
+
+// Suspend current thread until given IO is complete, at which point
+// its return value and any errors can be accessed
+int aio_suspend(struct aiocb *[], int, const struct timespec *);
+int aio_error(const struct aiocb *);
+ssize_t aio_return(struct aiocb *);
+int aio_cancel(int, struct aiocb *);
+
+// Initialize a threadpool to perform IO. Only one pool can be
+// running at a time.
+void aio_pool_write_init();
+void aio_pool_splice_init();
+// Suspend current thread until all queued work is complete, then ends the threadpool
+void aio_pool_end();
+// Submit IO work for the threadpool to complete. Memory associated with the work is
+// freed automatically when the work is complete.
+int aio_pool_write(struct aiocb *);
+
+#endif // ASYNCIO_H
+
diff --git a/media/mtp/IMtpHandle.h b/media/mtp/IMtpHandle.h
new file mode 100644
index 0000000..9185255
--- /dev/null
+++ b/media/mtp/IMtpHandle.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _IMTP_HANDLE_H
+#define _IMTP_HANDLE_H
+
+#include <linux/usb/f_mtp.h>
+
+constexpr char FFS_MTP_EP0[] = "/dev/usb-ffs/mtp/ep0";
+
+class IMtpHandle {
+public:
+    // Return number of bytes read/written, or -1 and errno is set
+    virtual int read(void *data, int len) = 0;
+    virtual int write(const void *data, int len) = 0;
+
+    // Return 0 if send/receive is successful, or -1 and errno is set
+    virtual int receiveFile(mtp_file_range mfr) = 0;
+    virtual int sendFile(mtp_file_range mfr) = 0;
+    virtual int sendEvent(mtp_event me) = 0;
+
+    // Return 0 if operation is successful, or -1 else
+    virtual int start() = 0;
+    virtual int configure(bool ptp) = 0;
+
+    virtual void close() = 0;
+
+    virtual ~IMtpHandle() {}
+};
+
+IMtpHandle *get_ffs_handle();
+IMtpHandle *get_mtp_handle();
+
+#endif // _IMTP_HANDLE_H
+
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 0356753..d1c71d7 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -24,6 +24,7 @@
 #include <sys/types.h>
 #include <usbhost/usbhost.h>
 #include "MtpStringBuffer.h"
+#include "IMtpHandle.h"
 
 namespace android {
 
@@ -438,9 +439,9 @@
         putUInt16(0);
 }
 
-#ifdef MTP_DEVICE 
-int MtpDataPacket::read(int fd) {
-    int ret = ::read(fd, mBuffer, MTP_BUFFER_SIZE);
+#ifdef MTP_DEVICE
+int MtpDataPacket::read(IMtpHandle *h) {
+    int ret = h->read(mBuffer, MTP_BUFFER_SIZE);
     if (ret < MTP_CONTAINER_HEADER_SIZE)
         return -1;
     mPacketSize = ret;
@@ -448,20 +449,20 @@
     return ret;
 }
 
-int MtpDataPacket::write(int fd) {
+int MtpDataPacket::write(IMtpHandle *h) {
     MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
     MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
-    int ret = ::write(fd, mBuffer, mPacketSize);
+    int ret = h->write(mBuffer, mPacketSize);
     return (ret < 0 ? ret : 0);
 }
 
-int MtpDataPacket::writeData(int fd, void* data, uint32_t length) {
+int MtpDataPacket::writeData(IMtpHandle *h, void* data, uint32_t length) {
     allocate(length + MTP_CONTAINER_HEADER_SIZE);
     memcpy(mBuffer + MTP_CONTAINER_HEADER_SIZE, data, length);
     length += MTP_CONTAINER_HEADER_SIZE;
     MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
     MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
-    int ret = ::write(fd, mBuffer, length);
+    int ret = h->write(mBuffer, length);
     return (ret < 0 ? ret : 0);
 }
 
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 82e0ee4..a449d6f 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -20,6 +20,7 @@
 #include "MtpPacket.h"
 #include "mtp.h"
 
+class IMtpHandle;
 struct usb_device;
 struct usb_request;
 
@@ -94,12 +95,12 @@
     inline void         putEmptyArray() { putUInt32(0); }
 
 #ifdef MTP_DEVICE
-    // fill our buffer with data from the given file descriptor
-    int                 read(int fd);
+    // fill our buffer with data from the given usb handle
+    int                 read(IMtpHandle *h);
 
-    // write our data to the given file descriptor
-    int                 write(int fd);
-    int                 writeData(int fd, void* data, uint32_t length);
+    // write our data to the given usb handle
+    int                 write(IMtpHandle *h);
+    int                 writeData(IMtpHandle *h, void* data, uint32_t length);
 #endif
 
 #ifdef MTP_HOST
diff --git a/media/mtp/MtpDevHandle.cpp b/media/mtp/MtpDevHandle.cpp
new file mode 100644
index 0000000..afc0525
--- /dev/null
+++ b/media/mtp/MtpDevHandle.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or         implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/Log.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <cutils/properties.h>
+#include <dirent.h>
+#include <errno.h>
+#include <linux/usb/ch9.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include "IMtpHandle.h"
+
+constexpr char mtp_dev_path[] = "/dev/mtp_usb";
+
+class MtpDevHandle : public IMtpHandle {
+private:
+    android::base::unique_fd mFd;
+
+public:
+    MtpDevHandle();
+    ~MtpDevHandle();
+    int read(void *data, int len);
+    int write(const void *data, int len);
+
+    int receiveFile(mtp_file_range mfr);
+    int sendFile(mtp_file_range mfr);
+    int sendEvent(mtp_event me);
+
+    int start();
+    void close();
+
+    int configure(bool ptp);
+};
+
+MtpDevHandle::MtpDevHandle()
+    : mFd(-1) {};
+
+MtpDevHandle::~MtpDevHandle() {}
+
+int MtpDevHandle::read(void *data, int len) {
+    return ::read(mFd, data, len);
+}
+
+int MtpDevHandle::write(const void *data, int len) {
+    return ::write(mFd, data, len);
+}
+
+int MtpDevHandle::receiveFile(mtp_file_range mfr) {
+    return ioctl(mFd, MTP_RECEIVE_FILE, reinterpret_cast<unsigned long>(&mfr));
+}
+
+int MtpDevHandle::sendFile(mtp_file_range mfr) {
+    return ioctl(mFd, MTP_SEND_FILE_WITH_HEADER, reinterpret_cast<unsigned long>(&mfr));
+}
+
+int MtpDevHandle::sendEvent(mtp_event me) {
+    return ioctl(mFd, MTP_SEND_EVENT, reinterpret_cast<unsigned long>(&me));
+}
+
+int MtpDevHandle::start() {
+    mFd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(mtp_dev_path, O_RDWR)));
+    if (mFd == -1) return -1;
+    return 0;
+}
+
+void MtpDevHandle::close() {
+    mFd.reset();
+}
+
+int MtpDevHandle::configure(bool) {
+    // Nothing to do, driver can configure itself
+    return 0;
+}
+
+IMtpHandle *get_mtp_handle() {
+    return new MtpDevHandle();
+}
diff --git a/media/mtp/MtpEventPacket.cpp b/media/mtp/MtpEventPacket.cpp
index d9ef311..921ecbd 100644
--- a/media/mtp/MtpEventPacket.cpp
+++ b/media/mtp/MtpEventPacket.cpp
@@ -19,12 +19,8 @@
 #include <stdio.h>
 #include <sys/types.h>
 #include <fcntl.h>
-#include <sys/ioctl.h>
 
-#ifdef MTP_DEVICE
-#include <linux/usb/f_mtp.h>
-#endif
-
+#include "IMtpHandle.h"
 #include "MtpEventPacket.h"
 
 #include <usbhost/usbhost.h>
@@ -40,7 +36,7 @@
 }
 
 #ifdef MTP_DEVICE
-int MtpEventPacket::write(int fd) {
+int MtpEventPacket::write(IMtpHandle *h) {
     struct mtp_event    event;
 
     putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
@@ -48,7 +44,7 @@
 
     event.data = mBuffer;
     event.length = mPacketSize;
-    int ret = ::ioctl(fd, MTP_SEND_EVENT, (unsigned long)&event);
+    int ret = h->sendEvent(event);
     return (ret < 0 ? ret : 0);
 }
 #endif
diff --git a/media/mtp/MtpEventPacket.h b/media/mtp/MtpEventPacket.h
index a8779fd..3f3b6a3 100644
--- a/media/mtp/MtpEventPacket.h
+++ b/media/mtp/MtpEventPacket.h
@@ -20,6 +20,8 @@
 #include "MtpPacket.h"
 #include "mtp.h"
 
+class IMtpHandle;
+
 namespace android {
 
 class MtpEventPacket : public MtpPacket {
@@ -29,8 +31,8 @@
     virtual             ~MtpEventPacket();
 
 #ifdef MTP_DEVICE
-    // write our data to the given file descriptor
-    int                 write(int fd);
+    // write our data to the given usb handle
+    int                 write(IMtpHandle *h);
 #endif
 
 #ifdef MTP_HOST
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
new file mode 100644
index 0000000..10314e9
--- /dev/null
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -0,0 +1,670 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+#include <mutex>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/endian.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <vector>
+
+#include "AsyncIO.h"
+#include "MtpFfsHandle.h"
+
+#define cpu_to_le16(x)  htole16(x)
+#define cpu_to_le32(x)  htole32(x)
+
+namespace {
+
+constexpr char FFS_MTP_EP_IN[] = "/dev/usb-ffs/mtp/ep1";
+constexpr char FFS_MTP_EP_OUT[] = "/dev/usb-ffs/mtp/ep2";
+constexpr char FFS_MTP_EP_INTR[] = "/dev/usb-ffs/mtp/ep3";
+
+constexpr int MAX_PACKET_SIZE_FS = 64;
+constexpr int MAX_PACKET_SIZE_HS = 512;
+constexpr int MAX_PACKET_SIZE_SS = 1024;
+
+// Must be divisible by all max packet size values
+constexpr int MAX_FILE_CHUNK_SIZE = 3145728;
+
+// Safe values since some devices cannot handle large DMAs
+// To get good performance, override these with
+// higher values per device using the properties
+// sys.usb.ffs.max_read and sys.usb.ffs.max_write
+constexpr int USB_FFS_MAX_WRITE = 32768;
+constexpr int USB_FFS_MAX_READ = 32768;
+
+constexpr unsigned int MAX_MTP_FILE_SIZE = 0xFFFFFFFF;
+
+struct func_desc {
+    struct usb_interface_descriptor intf;
+    struct usb_endpoint_descriptor_no_audio sink;
+    struct usb_endpoint_descriptor_no_audio source;
+    struct usb_endpoint_descriptor_no_audio intr;
+} __attribute__((packed));
+
+struct ss_func_desc {
+    struct usb_interface_descriptor intf;
+    struct usb_endpoint_descriptor_no_audio sink;
+    struct usb_ss_ep_comp_descriptor sink_comp;
+    struct usb_endpoint_descriptor_no_audio source;
+    struct usb_ss_ep_comp_descriptor source_comp;
+    struct usb_endpoint_descriptor_no_audio intr;
+    struct usb_ss_ep_comp_descriptor intr_comp;
+} __attribute__((packed));
+
+struct desc_v1 {
+    struct usb_functionfs_descs_head_v1 {
+        __le32 magic;
+        __le32 length;
+        __le32 fs_count;
+        __le32 hs_count;
+    } __attribute__((packed)) header;
+    struct func_desc fs_descs, hs_descs;
+} __attribute__((packed));
+
+struct desc_v2 {
+    struct usb_functionfs_descs_head_v2 header;
+    // The rest of the structure depends on the flags in the header.
+    __le32 fs_count;
+    __le32 hs_count;
+    __le32 ss_count;
+    struct func_desc fs_descs, hs_descs;
+    struct ss_func_desc ss_descs;
+} __attribute__((packed));
+
+const struct usb_interface_descriptor mtp_interface_desc = {
+    .bLength = USB_DT_INTERFACE_SIZE,
+    .bDescriptorType = USB_DT_INTERFACE,
+    .bInterfaceNumber = 0,
+    .bNumEndpoints = 3,
+    .bInterfaceClass = USB_CLASS_STILL_IMAGE,
+    .bInterfaceSubClass = 1,
+    .bInterfaceProtocol = 1,
+};
+
+const struct usb_interface_descriptor ptp_interface_desc = {
+    .bLength = USB_DT_INTERFACE_SIZE,
+    .bDescriptorType = USB_DT_INTERFACE,
+    .bInterfaceNumber = 0,
+    .bNumEndpoints = 3,
+    .bInterfaceClass = USB_CLASS_STILL_IMAGE,
+    .bInterfaceSubClass = 1,
+    .bInterfaceProtocol = 1,
+};
+
+const struct usb_endpoint_descriptor_no_audio fs_sink = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 1 | USB_DIR_IN,
+    .bmAttributes = USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+};
+
+const struct usb_endpoint_descriptor_no_audio fs_source = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 2 | USB_DIR_OUT,
+    .bmAttributes = USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+};
+
+const struct usb_endpoint_descriptor_no_audio fs_intr = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 3 | USB_DIR_IN,
+    .bmAttributes = USB_ENDPOINT_XFER_INT,
+    .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+    .bInterval = 6,
+};
+
+const struct usb_endpoint_descriptor_no_audio hs_sink = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 1 | USB_DIR_IN,
+    .bmAttributes = USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+};
+
+const struct usb_endpoint_descriptor_no_audio hs_source = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 2 | USB_DIR_OUT,
+    .bmAttributes = USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+};
+
+const struct usb_endpoint_descriptor_no_audio hs_intr = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 3 | USB_DIR_IN,
+    .bmAttributes = USB_ENDPOINT_XFER_INT,
+    .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+    .bInterval = 6,
+};
+
+const struct usb_endpoint_descriptor_no_audio ss_sink = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 1 | USB_DIR_IN,
+    .bmAttributes = USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+};
+
+const struct usb_endpoint_descriptor_no_audio ss_source = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 2 | USB_DIR_OUT,
+    .bmAttributes = USB_ENDPOINT_XFER_BULK,
+    .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+};
+
+const struct usb_endpoint_descriptor_no_audio ss_intr = {
+    .bLength = USB_DT_ENDPOINT_SIZE,
+    .bDescriptorType = USB_DT_ENDPOINT,
+    .bEndpointAddress = 3 | USB_DIR_IN,
+    .bmAttributes = USB_ENDPOINT_XFER_INT,
+    .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+    .bInterval = 6,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
+    .bLength = sizeof(ss_sink_comp),
+    .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+    .bMaxBurst = 2,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_source_comp = {
+    .bLength = sizeof(ss_source_comp),
+    .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+    .bMaxBurst = 2,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
+    .bLength = sizeof(ss_intr_comp),
+    .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+const struct func_desc mtp_fs_descriptors = {
+    .intf = mtp_interface_desc,
+    .sink = fs_sink,
+    .source = fs_source,
+    .intr = fs_intr,
+};
+
+const struct func_desc mtp_hs_descriptors = {
+    .intf = mtp_interface_desc,
+    .sink = hs_sink,
+    .source = hs_source,
+    .intr = hs_intr,
+};
+
+const struct ss_func_desc mtp_ss_descriptors = {
+    .intf = mtp_interface_desc,
+    .sink = ss_sink,
+    .sink_comp = ss_sink_comp,
+    .source = ss_source,
+    .source_comp = ss_source_comp,
+    .intr = ss_intr,
+    .intr_comp = ss_intr_comp,
+};
+
+const struct func_desc ptp_fs_descriptors = {
+    .intf = ptp_interface_desc,
+    .sink = fs_sink,
+    .source = fs_source,
+    .intr = fs_intr,
+};
+
+const struct func_desc ptp_hs_descriptors = {
+    .intf = ptp_interface_desc,
+    .sink = hs_sink,
+    .source = hs_source,
+    .intr = hs_intr,
+};
+
+const struct ss_func_desc ptp_ss_descriptors = {
+    .intf = ptp_interface_desc,
+    .sink = ss_sink,
+    .sink_comp = ss_sink_comp,
+    .source = ss_source,
+    .source_comp = ss_source_comp,
+    .intr = ss_intr,
+    .intr_comp = ss_intr_comp,
+};
+
+const struct {
+    struct usb_functionfs_strings_head header;
+} __attribute__((packed)) strings = {
+    .header = {
+        .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
+        .length = cpu_to_le32(sizeof(strings)),
+        .str_count = cpu_to_le32(0),
+        .lang_count = cpu_to_le32(0),
+    },
+};
+
+} // anonymous namespace
+
+namespace android {
+
+MtpFfsHandle::MtpFfsHandle() :
+    mMaxWrite(USB_FFS_MAX_WRITE),
+    mMaxRead(USB_FFS_MAX_READ) {}
+
+MtpFfsHandle::~MtpFfsHandle() {}
+
+void MtpFfsHandle::closeEndpoints() {
+    mIntr.reset();
+    mBulkIn.reset();
+    mBulkOut.reset();
+}
+
+bool MtpFfsHandle::initFunctionfs() {
+    ssize_t ret;
+    struct desc_v1 v1_descriptor;
+    struct desc_v2 v2_descriptor;
+
+    v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
+    v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor));
+    v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+                                 FUNCTIONFS_HAS_SS_DESC;
+    v2_descriptor.fs_count = 4;
+    v2_descriptor.hs_count = 4;
+    v2_descriptor.ss_count = 7;
+    v2_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
+    v2_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
+    v2_descriptor.ss_descs = mPtp ? ptp_ss_descriptors : mtp_ss_descriptors;
+
+    if (mControl < 0) { // might have already done this before
+        mControl.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP0, O_RDWR)));
+        if (mControl < 0) {
+            PLOG(ERROR) << FFS_MTP_EP0 << ": cannot open control endpoint";
+            goto err;
+        }
+
+        ret = TEMP_FAILURE_RETRY(::write(mControl, &v2_descriptor, sizeof(v2_descriptor)));
+        if (ret < 0) {
+            v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
+            v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor));
+            v1_descriptor.header.fs_count = 4;
+            v1_descriptor.header.hs_count = 4;
+            v1_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
+            v1_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
+            PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
+            ret = TEMP_FAILURE_RETRY(::write(mControl, &v1_descriptor, sizeof(v1_descriptor)));
+            if (ret < 0) {
+                PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
+                goto err;
+            }
+        }
+        ret = TEMP_FAILURE_RETRY(::write(mControl, &strings, sizeof(strings)));
+        if (ret < 0) {
+            PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
+            goto err;
+        }
+    }
+    if (mBulkIn > -1 || mBulkOut > -1 || mIntr > -1)
+        LOG(WARNING) << "Endpoints were not closed before configure!";
+
+    mBulkIn.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_IN, O_RDWR)));
+    if (mBulkIn < 0) {
+        PLOG(ERROR) << FFS_MTP_EP_IN << ": cannot open bulk in ep";
+        goto err;
+    }
+
+    mBulkOut.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_OUT, O_RDWR)));
+    if (mBulkOut < 0) {
+        PLOG(ERROR) << FFS_MTP_EP_OUT << ": cannot open bulk out ep";
+        goto err;
+    }
+
+    mIntr.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_INTR, O_RDWR)));
+    if (mIntr < 0) {
+        PLOG(ERROR) << FFS_MTP_EP0 << ": cannot open intr ep";
+        goto err;
+    }
+
+    return true;
+
+err:
+    closeEndpoints();
+    closeConfig();
+    return false;
+}
+
+void MtpFfsHandle::closeConfig() {
+    mControl.reset();
+}
+
+int MtpFfsHandle::writeHandle(int fd, const void* data, int len) {
+    LOG(VERBOSE) << "MTP about to write fd = " << fd << ", len=" << len;
+    int ret = 0;
+    const char* buf = static_cast<const char*>(data);
+    while (len > 0) {
+        int write_len = std::min(mMaxWrite, len);
+        int n = TEMP_FAILURE_RETRY(::write(fd, buf, write_len));
+
+        if (n < 0) {
+            PLOG(ERROR) << "write ERROR: fd = " << fd << ", n = " << n;
+            return -1;
+        } else if (n < write_len) {
+            errno = EIO;
+            PLOG(ERROR) << "less written than expected";
+            return -1;
+        }
+        buf += n;
+        len -= n;
+        ret += n;
+    }
+    return ret;
+}
+
+int MtpFfsHandle::readHandle(int fd, void* data, int len) {
+    LOG(VERBOSE) << "MTP about to read fd = " << fd << ", len=" << len;
+    int ret = 0;
+    char* buf = static_cast<char*>(data);
+    while (len > 0) {
+        int read_len = std::min(mMaxRead, len);
+        int n = TEMP_FAILURE_RETRY(::read(fd, buf, read_len));
+        if (n < 0) {
+            PLOG(ERROR) << "read ERROR: fd = " << fd << ", n = " << n;
+            return -1;
+        }
+        ret += n;
+        if (n < read_len) // done reading early
+            break;
+        buf += n;
+        len -= n;
+    }
+    return ret;
+}
+
+int MtpFfsHandle::spliceReadHandle(int fd, int pipe_out, int len) {
+    LOG(VERBOSE) << "MTP about to splice read fd = " << fd << ", len=" << len;
+    int ret = 0;
+    loff_t dummyoff;
+    while (len > 0) {
+        int read_len = std::min(mMaxRead, len);
+        dummyoff = 0;
+        int n = TEMP_FAILURE_RETRY(splice(fd, &dummyoff, pipe_out, nullptr, read_len, 0));
+        if (n < 0) {
+            PLOG(ERROR) << "splice read ERROR: fd = " << fd << ", n = " << n;
+            return -1;
+        }
+        ret += n;
+        if (n < read_len) // done reading early
+            break;
+        len -= n;
+    }
+    return ret;
+}
+
+int MtpFfsHandle::read(void* data, int len) {
+    return readHandle(mBulkOut, data, len);
+}
+
+int MtpFfsHandle::write(const void* data, int len) {
+    return writeHandle(mBulkIn, data, len);
+}
+
+int MtpFfsHandle::start() {
+    mLock.lock();
+    return 0;
+}
+
+int MtpFfsHandle::configure(bool usePtp) {
+    // Wait till previous server invocation has closed
+    std::lock_guard<std::mutex> lk(mLock);
+
+    // If ptp is changed, the configuration must be rewritten
+    if (mPtp != usePtp) {
+        closeEndpoints();
+        closeConfig();
+    }
+    mPtp = usePtp;
+
+    if (!initFunctionfs()) {
+        return -1;
+    }
+
+    // Get device specific r/w size
+    mMaxWrite = android::base::GetIntProperty("sys.usb.ffs.max_write", 0);
+    mMaxRead = android::base::GetIntProperty("sys.usb.ffs.max_read", 0);
+    if (!mMaxWrite)
+        mMaxWrite = USB_FFS_MAX_WRITE;
+    if (!mMaxRead)
+        mMaxRead = USB_FFS_MAX_READ;
+    return 0;
+}
+
+void MtpFfsHandle::close() {
+    closeEndpoints();
+    mLock.unlock();
+}
+
+/* Read from USB and write to a local file. */
+int MtpFfsHandle::receiveFile(mtp_file_range mfr) {
+    // When receiving files, the incoming length is given in 32 bits.
+    // A >4G file is given as 0xFFFFFFFF
+    uint32_t file_length = mfr.length;
+    uint64_t offset = lseek(mfr.fd, 0, SEEK_CUR);
+
+    int buf1_len = std::min(static_cast<uint32_t>(MAX_FILE_CHUNK_SIZE), file_length);
+    std::vector<char> buf1(buf1_len);
+    char* data = buf1.data();
+
+    // If necessary, allocate a second buffer for background r/w
+    int buf2_len = std::min(static_cast<uint32_t>(MAX_FILE_CHUNK_SIZE),
+            file_length - MAX_FILE_CHUNK_SIZE);
+    std::vector<char> buf2(std::max(0, buf2_len));
+    char *data2 = buf2.data();
+
+    struct aiocb aio;
+    aio.aio_fildes = mfr.fd;
+    aio.aio_buf = nullptr;
+    struct aiocb *aiol[] = {&aio};
+    int ret;
+    size_t length;
+    bool read = false;
+    bool write = false;
+
+    posix_fadvise(mfr.fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
+
+    // Break down the file into pieces that fit in buffers
+    while (file_length > 0 || write) {
+        if (file_length > 0) {
+            length = std::min(static_cast<uint32_t>(MAX_FILE_CHUNK_SIZE), file_length);
+
+            // Read data from USB
+            if ((ret = readHandle(mBulkOut, data, length)) == -1) {
+                return -1;
+            }
+
+            if (file_length != MAX_MTP_FILE_SIZE && ret < static_cast<int>(length)) {
+                errno = EIO;
+                return -1;
+            }
+            read = true;
+        }
+
+        if (write) {
+            // get the return status of the last write request
+            aio_suspend(aiol, 1, nullptr);
+
+            int written = aio_return(&aio);
+            if (written == -1) {
+                errno = aio_error(&aio);
+                return -1;
+            }
+            if (static_cast<size_t>(written) < aio.aio_nbytes) {
+                errno = EIO;
+                return -1;
+            }
+            write = false;
+        }
+
+        if (read) {
+            // Enqueue a new write request
+            aio.aio_buf = data;
+            aio.aio_sink = mfr.fd;
+            aio.aio_offset = offset;
+            aio.aio_nbytes = ret;
+            aio_write(&aio);
+
+            if (file_length == MAX_MTP_FILE_SIZE) {
+                // For larger files, receive until a short packet is received.
+                if (static_cast<size_t>(ret) < length) {
+                    file_length = 0;
+                }
+            } else {
+                file_length -= ret;
+            }
+
+            offset += ret;
+            std::swap(data, data2);
+
+            write = true;
+            read = false;
+        }
+    }
+    return 0;
+}
+
+/* Read from a local file and send over USB. */
+int MtpFfsHandle::sendFile(mtp_file_range mfr) {
+    uint64_t file_length = mfr.length;
+    uint32_t given_length = std::min(static_cast<uint64_t>(MAX_MTP_FILE_SIZE),
+            file_length + sizeof(mtp_data_header));
+    uint64_t offset = 0;
+    struct usb_endpoint_descriptor mBulkIn_desc;
+    int packet_size;
+
+    if (ioctl(mBulkIn, FUNCTIONFS_ENDPOINT_DESC, reinterpret_cast<unsigned long>(&mBulkIn_desc))) {
+        PLOG(ERROR) << "Could not get FFS bulk-in descriptor";
+        packet_size = MAX_PACKET_SIZE_HS;
+    } else {
+        packet_size = mBulkIn_desc.wMaxPacketSize;
+    }
+
+    posix_fadvise(mfr.fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
+
+    int init_read_len = packet_size - sizeof(mtp_data_header);
+    int buf1_len = std::max(static_cast<uint64_t>(packet_size), std::min(
+                  static_cast<uint64_t>(MAX_FILE_CHUNK_SIZE), file_length - init_read_len));
+    std::vector<char> buf1(buf1_len);
+    char *data = buf1.data();
+
+    // If necessary, allocate a second buffer for background r/w
+    int buf2_len = std::min(static_cast<uint64_t>(MAX_FILE_CHUNK_SIZE),
+            file_length - MAX_FILE_CHUNK_SIZE - init_read_len);
+    std::vector<char> buf2(std::max(0, buf2_len));
+    char *data2 = buf2.data();
+
+    struct aiocb aio;
+    aio.aio_fildes = mfr.fd;
+    struct aiocb *aiol[] = {&aio};
+    int ret, length;
+    bool read = false;
+    bool write = false;
+
+    // Send the header data
+    mtp_data_header *header = reinterpret_cast<mtp_data_header*>(data);
+    header->length = __cpu_to_le32(given_length);
+    header->type = __cpu_to_le16(2); /* data packet */
+    header->command = __cpu_to_le16(mfr.command);
+    header->transaction_id = __cpu_to_le32(mfr.transaction_id);
+
+    // Some hosts don't support header/data separation even though MTP allows it
+    // Handle by filling first packet with initial file data
+    if (TEMP_FAILURE_RETRY(pread(mfr.fd, reinterpret_cast<char*>(data) +
+                    sizeof(mtp_data_header), init_read_len, offset))
+            != init_read_len) return -1;
+    file_length -= init_read_len;
+    offset += init_read_len;
+    if (writeHandle(mBulkIn, data, packet_size) == -1) return -1;
+    if (file_length == 0) return 0;
+
+    // Break down the file into pieces that fit in buffers
+    while(file_length > 0) {
+        if (read) {
+            // Wait for the previous read to finish
+            aio_suspend(aiol, 1, nullptr);
+            ret = aio_return(&aio);
+            if (ret == -1) {
+                errno = aio_error(&aio);
+                return -1;
+            }
+            if (static_cast<size_t>(ret) < aio.aio_nbytes) {
+                errno = EIO;
+                return -1;
+            }
+
+            file_length -= ret;
+            offset += ret;
+            std::swap(data, data2);
+            read = false;
+            write = true;
+        }
+
+        if (file_length > 0) {
+            length = std::min((uint64_t) MAX_FILE_CHUNK_SIZE, file_length);
+            // Queue up another read
+            aio.aio_buf = data;
+            aio.aio_offset = offset;
+            aio.aio_nbytes = length;
+            aio_read(&aio);
+            read = true;
+        }
+
+        if (write) {
+            if (writeHandle(mBulkIn, data2, ret) == -1)
+                return -1;
+            write = false;
+        }
+    }
+
+    if (given_length == MAX_MTP_FILE_SIZE && ret % packet_size == 0) {
+        // If the last packet wasn't short, send a final empty packet
+        if (writeHandle(mBulkIn, data, 0) == -1) return -1;
+    }
+
+    return 0;
+}
+
+int MtpFfsHandle::sendEvent(mtp_event me) {
+    unsigned length = me.length;
+    int ret = writeHandle(mIntr, me.data, length);
+    return static_cast<unsigned>(ret) == length ? 0 : -1;
+}
+
+} // namespace android
+
+IMtpHandle *get_ffs_handle() {
+    return new android::MtpFfsHandle();
+}
+
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
new file mode 100644
index 0000000..9cd4dcf
--- /dev/null
+++ b/media/mtp/MtpFfsHandle.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _MTP_FFS_HANDLE_H
+#define _MTP_FFS_HANDLE_H
+
+#include <android-base/unique_fd.h>
+#include <IMtpHandle.h>
+
+namespace android {
+
+class MtpFfsHandleTest;
+
+class MtpFfsHandle : public IMtpHandle {
+    friend class android::MtpFfsHandleTest;
+private:
+    int writeHandle(int fd, const void *data, int len);
+    int readHandle(int fd, void *data, int len);
+    int spliceReadHandle(int fd, int fd_out, int len);
+    bool initFunctionfs();
+    void closeConfig();
+    void closeEndpoints();
+
+    bool mPtp;
+
+    std::mutex mLock;
+
+    android::base::unique_fd mControl;
+    // "in" from the host's perspective => sink for mtp server
+    android::base::unique_fd mBulkIn;
+    // "out" from the host's perspective => source for mtp server
+    android::base::unique_fd mBulkOut;
+    android::base::unique_fd mIntr;
+
+    int mMaxWrite;
+    int mMaxRead;
+
+public:
+    int read(void *data, int len);
+    int write(const void *data, int len);
+
+    int receiveFile(mtp_file_range mfr);
+    int sendFile(mtp_file_range mfr);
+    int sendEvent(mtp_event me);
+
+    int start();
+    void close();
+
+    int configure(bool ptp);
+
+    MtpFfsHandle();
+    ~MtpFfsHandle();
+};
+
+struct mtp_data_header {
+    /* length of packet, including this header */
+    __le32 length;
+    /* container type (2 for data packet) */
+    __le16 type;
+    /* MTP command code */
+    __le16 command;
+    /* MTP transaction ID */
+    __le32 transaction_id;
+};
+
+} // namespace android
+
+#endif // _MTP_FF_HANDLE_H
+
diff --git a/media/mtp/MtpPacket.h b/media/mtp/MtpPacket.h
index 4da53bf..d47c91d 100644
--- a/media/mtp/MtpPacket.h
+++ b/media/mtp/MtpPacket.h
@@ -17,6 +17,8 @@
 #ifndef _MTP_PACKET_H
 #define _MTP_PACKET_H
 
+#include <android-base/macros.h>
+
 #include "MtpTypes.h"
 
 struct usb_device;
@@ -66,6 +68,8 @@
     uint32_t            getUInt32(int offset) const;
     void                putUInt16(int offset, uint16_t value);
     void                putUInt32(int offset, uint32_t value);
+
+    DISALLOW_COPY_AND_ASSIGN(MtpPacket);
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpRequestPacket.cpp b/media/mtp/MtpRequestPacket.cpp
index 471967f..e0e86a9 100644
--- a/media/mtp/MtpRequestPacket.cpp
+++ b/media/mtp/MtpRequestPacket.cpp
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 #include <fcntl.h>
 
+#include "IMtpHandle.h"
 #include "MtpRequestPacket.h"
 
 #include <usbhost/usbhost.h>
@@ -36,8 +37,8 @@
 }
 
 #ifdef MTP_DEVICE
-int MtpRequestPacket::read(int fd) {
-    int ret = ::read(fd, mBuffer, mBufferSize);
+int MtpRequestPacket::read(IMtpHandle *h) {
+    int ret = h->read(mBuffer, mBufferSize);
     if (ret < 0) {
         // file read error
         return ret;
diff --git a/media/mtp/MtpRequestPacket.h b/media/mtp/MtpRequestPacket.h
index 79b798d..d1dc0ff 100644
--- a/media/mtp/MtpRequestPacket.h
+++ b/media/mtp/MtpRequestPacket.h
@@ -20,6 +20,7 @@
 #include "MtpPacket.h"
 #include "mtp.h"
 
+class IMtpHandle;
 struct usb_request;
 
 namespace android {
@@ -31,8 +32,8 @@
     virtual             ~MtpRequestPacket();
 
 #ifdef MTP_DEVICE
-    // fill our buffer with data from the given file descriptor
-    int                 read(int fd);
+    // fill our buffer with data from the given usb handle
+    int                 read(IMtpHandle *h);
 #endif
 
 #ifdef MTP_HOST
diff --git a/media/mtp/MtpResponsePacket.cpp b/media/mtp/MtpResponsePacket.cpp
index c2b41e4..f186b37 100644
--- a/media/mtp/MtpResponsePacket.cpp
+++ b/media/mtp/MtpResponsePacket.cpp
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 #include <fcntl.h>
 
+#include "IMtpHandle.h"
 #include "MtpResponsePacket.h"
 
 #include <usbhost/usbhost.h>
@@ -35,10 +36,10 @@
 }
 
 #ifdef MTP_DEVICE
-int MtpResponsePacket::write(int fd) {
+int MtpResponsePacket::write(IMtpHandle *h) {
     putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
     putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_RESPONSE);
-    int ret = ::write(fd, mBuffer, mPacketSize);
+    int ret = h->write(mBuffer, mPacketSize);
     return (ret < 0 ? ret : 0);
 }
 #endif
diff --git a/media/mtp/MtpResponsePacket.h b/media/mtp/MtpResponsePacket.h
index 592ad4a..29a72ba 100644
--- a/media/mtp/MtpResponsePacket.h
+++ b/media/mtp/MtpResponsePacket.h
@@ -20,6 +20,8 @@
 #include "MtpPacket.h"
 #include "mtp.h"
 
+class IMtpHandle;
+
 namespace android {
 
 class MtpResponsePacket : public MtpPacket {
@@ -29,8 +31,8 @@
     virtual             ~MtpResponsePacket();
 
 #ifdef MTP_DEVICE
-    // write our data to the given file descriptor
-    int                 write(int fd);
+    // write our data to the given usb handle
+    int                 write(IMtpHandle *h);
 #endif
 
 #ifdef MTP_HOST
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index e39dcdd..2a96ac9 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
+#include <android-base/properties.h>
+#include <chrono>
+#include <cutils/properties.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
-#include <sys/ioctl.h>
 #include <sys/stat.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <errno.h>
 #include <sys/stat.h>
-#include <dirent.h>
-
-#include <cutils/properties.h>
 
 #define LOG_TAG "MtpServer"
 
@@ -37,8 +37,6 @@
 #include "MtpStorage.h"
 #include "MtpStringBuffer.h"
 
-#include <linux/usb/f_mtp.h>
-
 namespace android {
 
 static const MtpOperationCode kSupportedOperationCodes[] = {
@@ -97,10 +95,9 @@
     MTP_EVENT_DEVICE_PROP_CHANGED,
 };
 
-MtpServer::MtpServer(int fd, MtpDatabase* database, bool ptp,
+MtpServer::MtpServer(MtpDatabase* database, bool ptp,
                     int fileGroup, int filePerm, int directoryPerm)
-    :   mFD(fd),
-        mDatabase(database),
+    :   mDatabase(database),
         mPtp(ptp),
         mFileGroup(fileGroup),
         mFilePermission(filePerm),
@@ -116,6 +113,21 @@
 MtpServer::~MtpServer() {
 }
 
+IMtpHandle* MtpServer::sHandle = nullptr;
+
+int MtpServer::configure(bool usePtp) {
+    if (sHandle == nullptr) {
+        bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
+        sHandle = ffs_ok ? get_ffs_handle() : get_mtp_handle();
+    }
+
+    int ret = sHandle->configure(usePtp);
+    if (ret) ALOGE("Failed to configure MTP driver!");
+    else android::base::SetProperty("sys.usb.ffs.mtp.ready", "1");
+
+    return ret;
+}
+
 void MtpServer::addStorage(MtpStorage* storage) {
     Mutex::Autolock autoLock(mMutex);
 
@@ -143,24 +155,30 @@
         if (storage->getStorageID() == id)
             return storage;
     }
-    return NULL;
+    return nullptr;
 }
 
 bool MtpServer::hasStorage(MtpStorageID id) {
     if (id == 0 || id == 0xFFFFFFFF)
         return mStorages.size() > 0;
-    return (getStorage(id) != NULL);
+    return (getStorage(id) != nullptr);
 }
 
 void MtpServer::run() {
-    int fd = mFD;
+    if (!sHandle) {
+        ALOGE("MtpServer was never configured!");
+        return;
+    }
 
-    ALOGV("MtpServer::run fd: %d\n", fd);
+    if (sHandle->start()) {
+        ALOGE("Failed to start usb driver!");
+        return;
+    }
 
     while (1) {
-        int ret = mRequest.read(fd);
+        int ret = mRequest.read(sHandle);
         if (ret < 0) {
-            ALOGV("request read returned %d, errno: %d", ret, errno);
+            ALOGE("request read returned %d, errno: %d", ret, errno);
             if (errno == ECANCELED) {
                 // return to top of loop and wait for next command
                 continue;
@@ -171,15 +189,13 @@
         MtpTransactionID transaction = mRequest.getTransactionID();
 
         ALOGV("operation: %s", MtpDebug::getOperationCodeName(operation));
-        mRequest.dump();
-
         // FIXME need to generalize this
         bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
                     || operation == MTP_OPERATION_SET_OBJECT_REFERENCES
                     || operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
                     || operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
         if (dataIn) {
-            int ret = mData.read(fd);
+            int ret = mData.read(sHandle);
             if (ret < 0) {
                 ALOGE("data read returned %d, errno: %d", ret, errno);
                 if (errno == ECANCELED) {
@@ -189,7 +205,6 @@
                 break;
             }
             ALOGV("received data:");
-            mData.dump();
         } else {
             mData.reset();
         }
@@ -199,8 +214,7 @@
                 mData.setOperationCode(operation);
                 mData.setTransactionID(transaction);
                 ALOGV("sending data:");
-                mData.dump();
-                ret = mData.write(fd);
+                ret = mData.write(sHandle);
                 if (ret < 0) {
                     ALOGE("request write returned %d, errno: %d", ret, errno);
                     if (errno == ECANCELED) {
@@ -213,9 +227,8 @@
 
             mResponse.setTransactionID(transaction);
             ALOGV("sending response %04X", mResponse.getResponseCode());
-            ret = mResponse.write(fd);
+            ret = mResponse.write(sHandle);
             const int savedErrno = errno;
-            mResponse.dump();
             if (ret < 0) {
                 ALOGE("request write returned %d, errno: %d", ret, errno);
                 if (savedErrno == ECANCELED) {
@@ -240,8 +253,8 @@
 
     if (mSessionOpen)
         mDatabase->sessionEnded();
-    close(fd);
-    mFD = -1;
+
+    sHandle->close();
 }
 
 void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
@@ -274,8 +287,8 @@
         mEvent.setEventCode(code);
         mEvent.setTransactionID(mRequest.getTransactionID());
         mEvent.setParameter(1, param1);
-        int ret = mEvent.write(mFD);
-        ALOGV("mEvent.write returned %d\n", ret);
+        if (mEvent.write(sHandle))
+            ALOGE("Mtp send event failed: %s", strerror(errno));
     }
 }
 
@@ -291,7 +304,7 @@
         ObjectEdit* edit = mObjectEditList[i];
         if (edit->mHandle == handle) return edit;
     }
-    return NULL;
+    return nullptr;
 }
 
 void MtpServer::removeEditObject(MtpObjectHandle handle) {
@@ -775,6 +788,8 @@
     if (result != MTP_RESPONSE_OK)
         return result;
 
+    auto start = std::chrono::steady_clock::now();
+
     const char* filePath = (const char *)pathBuf;
     mtp_file_range  mfr;
     mfr.fd = open(filePath, O_RDONLY);
@@ -787,8 +802,9 @@
     mfr.transaction_id = mRequest.getTransactionID();
 
     // then transfer the file
-    int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
+    int ret = sHandle->sendFile(mfr);
     if (ret < 0) {
+        ALOGE("Mtp send file got error %s", strerror(errno));
         if (errno == ECANCELED) {
             result = MTP_RESPONSE_TRANSACTION_CANCELLED;
         } else {
@@ -798,7 +814,13 @@
         result = MTP_RESPONSE_OK;
     }
 
-    ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
+    auto end = std::chrono::steady_clock::now();
+    std::chrono::duration<double> diff = end - start;
+    struct stat sstat;
+    fstat(mfr.fd, &sstat);
+    uint64_t finalsize = sstat.st_size;
+    ALOGV("Sent a file over MTP. Time: %f s, Size: %" PRIu64 ", Rate: %f bytes/s",
+            diff.count(), finalsize, ((double) finalsize) / diff.count());
     close(mfr.fd);
     return result;
 }
@@ -813,7 +835,7 @@
         // send data
         mData.setOperationCode(mRequest.getOperationCode());
         mData.setTransactionID(mRequest.getTransactionID());
-        mData.writeData(mFD, thumb, thumbSize);
+        mData.writeData(sHandle, thumb, thumbSize);
         free(thumb);
         return MTP_RESPONSE_OK;
     } else {
@@ -867,7 +889,7 @@
     mResponse.setParameter(1, length);
 
     // transfer the file
-    int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
+    int ret = sHandle->sendFile(mfr);
     ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
     result = MTP_RESPONSE_OK;
     if (ret < 0) {
@@ -995,6 +1017,8 @@
     int ret, initialData;
     bool isCanceled = false;
 
+    auto start = std::chrono::steady_clock::now();
+
     if (mSendObjectHandle == kInvalidObjectHandle) {
         ALOGE("Expected SendObjectInfo before SendObject");
         result = MTP_RESPONSE_NO_VALID_OBJECT_INFO;
@@ -1002,7 +1026,7 @@
     }
 
     // read the header, and possibly some data
-    ret = mData.read(mFD);
+    ret = mData.read(sHandle);
     if (ret < MTP_CONTAINER_HEADER_SIZE) {
         result = MTP_RESPONSE_GENERAL_ERROR;
         goto done;
@@ -1038,19 +1062,19 @@
                 mfr.length = mSendObjectFileSize - initialData;
             }
 
-            ALOGV("receiving %s\n", (const char *)mSendObjectFilePath);
             // transfer the file
-            ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+            ret = sHandle->receiveFile(mfr);
             if ((ret < 0) && (errno == ECANCELED)) {
                 isCanceled = true;
             }
-
-            ALOGV("MTP_RECEIVE_FILE returned %d\n", ret);
         }
     }
+    struct stat sstat;
+    fstat(mfr.fd, &sstat);
     close(mfr.fd);
 
     if (ret < 0) {
+        ALOGE("Mtp receive file got error %s", strerror(errno));
         unlink(mSendObjectFilePath);
         if (isCanceled)
             result = MTP_RESPONSE_TRANSACTION_CANCELLED;
@@ -1066,6 +1090,12 @@
             result == MTP_RESPONSE_OK);
     mSendObjectHandle = kInvalidObjectHandle;
     mSendObjectFormat = 0;
+
+    auto end = std::chrono::steady_clock::now();
+    std::chrono::duration<double> diff = end - start;
+    uint64_t finalsize = sstat.st_size;
+    ALOGV("Got a file over MTP. Time: %fs, Size: %" PRIu64 ", Rate: %f bytes/s",
+            diff.count(), finalsize, ((double) finalsize) / diff.count());
     return result;
 }
 
@@ -1209,7 +1239,7 @@
     ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
 
     // read the header, and possibly some data
-    int ret = mData.read(mFD);
+    int ret = mData.read(sHandle);
     if (ret < MTP_CONTAINER_HEADER_SIZE)
         return MTP_RESPONSE_GENERAL_ERROR;
     int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
@@ -1231,11 +1261,10 @@
             mfr.length = length;
 
             // transfer the file
-            ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+            ret = sHandle->receiveFile(mfr);
             if ((ret < 0) && (errno == ECANCELED)) {
                 isCanceled = true;
             }
-            ALOGV("MTP_RECEIVE_FILE returned %d", ret);
         }
     }
     if (ret < 0) {
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index b3a11e0..c80e6a8 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -23,8 +23,12 @@
 #include "MtpEventPacket.h"
 #include "mtp.h"
 #include "MtpUtils.h"
+#include "IMtpHandle.h"
 
 #include <utils/threads.h>
+#include <queue>
+#include <memory>
+#include <mutex>
 
 namespace android {
 
@@ -34,9 +38,6 @@
 class MtpServer {
 
 private:
-    // file descriptor for MTP kernel driver
-    int                 mFD;
-
     MtpDatabase*        mDatabase;
 
     // appear as a PTP device
@@ -56,10 +57,13 @@
     MtpRequestPacket    mRequest;
     MtpDataPacket       mData;
     MtpResponsePacket   mResponse;
+
     MtpEventPacket      mEvent;
 
     MtpStorageList      mStorages;
 
+    static IMtpHandle*  sHandle;
+
     // handle for new object, set by SendObjectInfo and used by SendObject
     MtpObjectHandle     mSendObjectHandle;
     MtpObjectFormat     mSendObjectFormat;
@@ -90,7 +94,7 @@
     Vector<ObjectEdit*>  mObjectEditList;
 
 public:
-                        MtpServer(int fd, MtpDatabase* database, bool ptp,
+                        MtpServer(MtpDatabase* database, bool ptp,
                                     int fileGroup, int filePerm, int directoryPerm);
     virtual             ~MtpServer();
 
@@ -100,6 +104,7 @@
     void                addStorage(MtpStorage* storage);
     void                removeStorage(MtpStorage* storage);
 
+    static int          configure(bool usePtp);
     void                run();
 
     void                sendObjectAdded(MtpObjectHandle handle);
diff --git a/media/mtp/tests/Android.mk b/media/mtp/tests/Android.mk
new file mode 100644
index 0000000..ace0d40
--- /dev/null
+++ b/media/mtp/tests/Android.mk
@@ -0,0 +1,51 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_MODULE := mtp_ffs_handle_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+	MtpFfsHandle_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+	libbase \
+	libcutils \
+	libmedia \
+	libmtp \
+	libutils \
+	liblog
+
+LOCAL_C_INCLUDES := \
+	frameworks/av/media/mtp \
+
+LOCAL_CFLAGS += -Werror -Wall
+
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_MODULE := async_io_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+	AsyncIO_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+	libbase \
+	libcutils \
+	libmedia \
+	libmtp \
+	libutils \
+	liblog
+
+LOCAL_C_INCLUDES := \
+	frameworks/av/media/mtp \
+
+LOCAL_CFLAGS += -Werror -Wall
+
+include $(BUILD_NATIVE_TEST)
diff --git a/media/mtp/tests/AsyncIO_test.cpp b/media/mtp/tests/AsyncIO_test.cpp
new file mode 100644
index 0000000..b5f4538
--- /dev/null
+++ b/media/mtp/tests/AsyncIO_test.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "AsyncIO_test.cpp"
+
+#include <android-base/test_utils.h>
+#include <fcntl.h>
+#include <gtest/gtest.h>
+#include <string>
+#include <unistd.h>
+#include <utils/Log.h>
+
+#include "AsyncIO.h"
+
+namespace android {
+
+constexpr int TEST_PACKET_SIZE = 512;
+constexpr int POOL_COUNT = 10;
+
+static const std::string dummyDataStr =
+    "/*\n * Copyright 2015 The Android Open Source Project\n *\n * Licensed un"
+    "der the Apache License, Version 2.0 (the \"License\");\n * you may not us"
+    "e this file except in compliance with the License.\n * You may obtain a c"
+    "opy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE"
+    "-2.0\n *\n * Unless required by applicable law or agreed to in writing, s"
+    "oftware\n * distributed under the License is distributed on an \"AS IS\" "
+    "BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express o"
+    "r implied.\n * Se";
+
+
+class AsyncIOTest : public ::testing::Test {
+protected:
+    TemporaryFile dummy_file;
+
+    AsyncIOTest() {}
+    ~AsyncIOTest() {}
+};
+
+TEST_F(AsyncIOTest, testRead) {
+    char buf[TEST_PACKET_SIZE + 1];
+    buf[TEST_PACKET_SIZE] = '\0';
+    EXPECT_EQ(write(dummy_file.fd, dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
+    struct aiocb aio;
+    struct aiocb *aiol[] = {&aio};
+    aio.aio_fildes = dummy_file.fd;
+    aio.aio_buf = buf;
+    aio.aio_offset = 0;
+    aio.aio_nbytes = TEST_PACKET_SIZE;
+
+    EXPECT_EQ(aio_read(&aio), 0);
+    EXPECT_EQ(aio_suspend(aiol, 1, nullptr), 0);
+    EXPECT_EQ(aio_return(&aio), TEST_PACKET_SIZE);
+    EXPECT_STREQ(buf, dummyDataStr.c_str());
+}
+
+TEST_F(AsyncIOTest, testWrite) {
+    char buf[TEST_PACKET_SIZE + 1];
+    buf[TEST_PACKET_SIZE] = '\0';
+    struct aiocb aio;
+    struct aiocb *aiol[] = {&aio};
+    aio.aio_fildes = dummy_file.fd;
+    aio.aio_buf = const_cast<char*>(dummyDataStr.c_str());
+    aio.aio_offset = 0;
+    aio.aio_nbytes = TEST_PACKET_SIZE;
+
+    EXPECT_EQ(aio_write(&aio), 0);
+    EXPECT_EQ(aio_suspend(aiol, 1, nullptr), 0);
+    EXPECT_EQ(aio_return(&aio), TEST_PACKET_SIZE);
+    EXPECT_EQ(read(dummy_file.fd, buf, TEST_PACKET_SIZE), TEST_PACKET_SIZE);
+    EXPECT_STREQ(buf, dummyDataStr.c_str());
+}
+
+TEST_F(AsyncIOTest, testError) {
+    char buf[TEST_PACKET_SIZE + 1];
+    buf[TEST_PACKET_SIZE] = '\0';
+    struct aiocb aio;
+    struct aiocb *aiol[] = {&aio};
+    aio.aio_fildes = -1;
+    aio.aio_buf = const_cast<char*>(dummyDataStr.c_str());
+    aio.aio_offset = 0;
+    aio.aio_nbytes = TEST_PACKET_SIZE;
+
+    EXPECT_EQ(aio_write(&aio), 0);
+    EXPECT_EQ(aio_suspend(aiol, 1, nullptr), 0);
+    EXPECT_EQ(aio_return(&aio), -1);
+    EXPECT_EQ(aio_error(&aio), EBADF);
+}
+
+TEST_F(AsyncIOTest, testSpliceRead) {
+    char buf[TEST_PACKET_SIZE + 1];
+    buf[TEST_PACKET_SIZE] = '\0';
+    int pipeFd[2];
+    EXPECT_EQ(pipe(pipeFd), 0);
+    EXPECT_EQ(write(dummy_file.fd, dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
+    struct aiocb aio;
+    struct aiocb *aiol[] = {&aio};
+    aio.aio_fildes = dummy_file.fd;
+    aio.aio_sink = pipeFd[1];
+    aio.aio_offset = 0;
+    aio.aio_nbytes = TEST_PACKET_SIZE;
+
+    EXPECT_EQ(aio_splice_read(&aio), 0);
+    EXPECT_EQ(aio_suspend(aiol, 1, nullptr), 0);
+    EXPECT_EQ(aio_return(&aio), TEST_PACKET_SIZE);
+
+    EXPECT_EQ(read(pipeFd[0], buf, TEST_PACKET_SIZE), TEST_PACKET_SIZE);
+    EXPECT_STREQ(buf, dummyDataStr.c_str());
+}
+
+TEST_F(AsyncIOTest, testSpliceWrite) {
+    char buf[TEST_PACKET_SIZE + 1];
+    buf[TEST_PACKET_SIZE] = '\0';
+    int pipeFd[2];
+    EXPECT_EQ(pipe(pipeFd), 0);
+    EXPECT_EQ(write(pipeFd[1], dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
+    struct aiocb aio;
+    struct aiocb *aiol[] = {&aio};
+    aio.aio_fildes = pipeFd[0];
+    aio.aio_sink = dummy_file.fd;
+    aio.aio_offset = 0;
+    aio.aio_nbytes = TEST_PACKET_SIZE;
+
+    EXPECT_EQ(aio_splice_write(&aio), 0);
+    EXPECT_EQ(aio_suspend(aiol, 1, nullptr), 0);
+    EXPECT_EQ(aio_return(&aio), TEST_PACKET_SIZE);
+    EXPECT_EQ(read(dummy_file.fd, buf, TEST_PACKET_SIZE), TEST_PACKET_SIZE);
+    EXPECT_STREQ(buf, dummyDataStr.c_str());
+}
+
+TEST_F(AsyncIOTest, testPoolWrite) {
+    aio_pool_write_init();
+    char buf[TEST_PACKET_SIZE * POOL_COUNT + 1];
+    buf[TEST_PACKET_SIZE * POOL_COUNT] = '\0';
+
+    for (int i = 0; i < POOL_COUNT; i++) {
+        struct aiocb *aiop = new struct aiocb;
+        aiop->aio_fildes = dummy_file.fd;
+        aiop->aio_pool_buf = std::unique_ptr<char[]>(new char[TEST_PACKET_SIZE]);
+        memcpy(aiop->aio_pool_buf.get(), dummyDataStr.c_str(), TEST_PACKET_SIZE);
+        aiop->aio_offset = i * TEST_PACKET_SIZE;
+        aiop->aio_nbytes = TEST_PACKET_SIZE;
+        EXPECT_EQ(aio_pool_write(aiop), 0);
+    }
+    aio_pool_end();
+    EXPECT_EQ(read(dummy_file.fd, buf, TEST_PACKET_SIZE * POOL_COUNT), TEST_PACKET_SIZE * POOL_COUNT);
+
+    std::stringstream ss;
+    for (int i = 0; i < POOL_COUNT; i++)
+        ss << dummyDataStr;
+
+    EXPECT_STREQ(buf, ss.str().c_str());
+}
+
+TEST_F(AsyncIOTest, testSplicePoolWrite) {
+    aio_pool_splice_init();
+    char buf[TEST_PACKET_SIZE * POOL_COUNT + 1];
+    buf[TEST_PACKET_SIZE * POOL_COUNT] = '\0';
+
+    for (int i = 0; i < POOL_COUNT; i++) {
+        int pipeFd[2];
+        EXPECT_EQ(pipe(pipeFd), 0);
+        EXPECT_EQ(write(pipeFd[1], dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
+        struct aiocb *aiop = new struct aiocb;
+        aiop->aio_fildes = pipeFd[0];
+        aiop->aio_sink = dummy_file.fd;
+        aiop->aio_offset = i * TEST_PACKET_SIZE;
+        aiop->aio_nbytes = TEST_PACKET_SIZE;
+        EXPECT_EQ(aio_pool_write(aiop), 0);
+    }
+    aio_pool_end();
+    EXPECT_EQ(read(dummy_file.fd, buf, TEST_PACKET_SIZE * POOL_COUNT), TEST_PACKET_SIZE * POOL_COUNT);
+
+    std::stringstream ss;
+    for (int i = 0; i < POOL_COUNT; i++)
+        ss << dummyDataStr;
+
+    EXPECT_STREQ(buf, ss.str().c_str());
+}
+
+} // namespace android
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandle_test.cpp
new file mode 100644
index 0000000..b511041
--- /dev/null
+++ b/media/mtp/tests/MtpFfsHandle_test.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "MtpFfsHandle_test.cpp"
+
+#include <android-base/unique_fd.h>
+#include <android-base/test_utils.h>
+#include <fcntl.h>
+#include <gtest/gtest.h>
+#include <memory>
+#include <string>
+#include <unistd.h>
+#include <utils/Log.h>
+
+#include "MtpFfsHandle.h"
+
+namespace android {
+
+constexpr int TEST_PACKET_SIZE = 512;
+constexpr int SMALL_MULT = 30;
+constexpr int MED_MULT = 510;
+
+static const std::string dummyDataStr =
+    "/*\n * Copyright 2015 The Android Open Source Project\n *\n * Licensed un"
+    "der the Apache License, Version 2.0 (the \"License\");\n * you may not us"
+    "e this file except in compliance with the License.\n * You may obtain a c"
+    "opy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE"
+    "-2.0\n *\n * Unless required by applicable law or agreed to in writing, s"
+    "oftware\n * distributed under the License is distributed on an \"AS IS\" "
+    "BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express o"
+    "r implied.\n * Se";
+
+class MtpFfsHandleTest : public ::testing::Test {
+protected:
+    std::unique_ptr<IMtpHandle> handle;
+
+    // Pipes for reading endpoint data
+    android::base::unique_fd bulk_in;
+    android::base::unique_fd bulk_out;
+    android::base::unique_fd intr;
+
+    TemporaryFile dummy_file;
+
+    MtpFfsHandleTest() {
+        int fd[2];
+        handle = std::unique_ptr<IMtpHandle>(get_ffs_handle());
+        MtpFfsHandle *ffs_handle = static_cast<MtpFfsHandle*>(handle.get());
+        EXPECT_TRUE(ffs_handle != NULL);
+
+        EXPECT_EQ(pipe(fd), 0);
+        EXPECT_EQ(fcntl(fd[0], F_SETPIPE_SZ, 1048576), 1048576);
+        bulk_in.reset(fd[0]);
+        ffs_handle->mBulkIn.reset(fd[1]);
+
+        EXPECT_EQ(pipe(fd), 0);
+        EXPECT_EQ(fcntl(fd[0], F_SETPIPE_SZ, 1048576), 1048576);
+        bulk_out.reset(fd[1]);
+        ffs_handle->mBulkOut.reset(fd[0]);
+
+        EXPECT_EQ(pipe(fd), 0);
+        intr.reset(fd[0]);
+        ffs_handle->mIntr.reset(fd[1]);
+    }
+
+    ~MtpFfsHandleTest() {}
+};
+
+TEST_F(MtpFfsHandleTest, testRead) {
+    EXPECT_EQ(write(bulk_out, dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
+    char buf[TEST_PACKET_SIZE + 1];
+    buf[TEST_PACKET_SIZE] = '\0';
+    EXPECT_EQ(handle->read(buf, TEST_PACKET_SIZE), TEST_PACKET_SIZE);
+    EXPECT_STREQ(buf, dummyDataStr.c_str());
+}
+
+TEST_F(MtpFfsHandleTest, testWrite) {
+    char buf[TEST_PACKET_SIZE + 1];
+    buf[TEST_PACKET_SIZE] = '\0';
+    EXPECT_EQ(handle->write(dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
+    EXPECT_EQ(read(bulk_in, buf, TEST_PACKET_SIZE), TEST_PACKET_SIZE);
+    EXPECT_STREQ(buf, dummyDataStr.c_str());
+}
+
+TEST_F(MtpFfsHandleTest, testReceiveFileSmall) {
+    std::stringstream ss;
+    mtp_file_range mfr;
+    int size = TEST_PACKET_SIZE * SMALL_MULT;
+    char buf[size + 1];
+    buf[size] = '\0';
+
+    mfr.length = size;
+    mfr.fd = dummy_file.fd;
+    for (int i = 0; i < SMALL_MULT; i++)
+        ss << dummyDataStr;
+
+    EXPECT_EQ(write(bulk_out, ss.str().c_str(), size), size);
+    EXPECT_EQ(handle->receiveFile(mfr), 0);
+
+    EXPECT_EQ(read(dummy_file.fd, buf, size), size);
+
+    EXPECT_STREQ(buf, ss.str().c_str());
+}
+
+TEST_F(MtpFfsHandleTest, testReceiveFileMed) {
+    std::stringstream ss;
+    mtp_file_range mfr;
+    int size = TEST_PACKET_SIZE * MED_MULT;
+    char buf[size + 1];
+    buf[size] = '\0';
+
+    mfr.length = size;
+    mfr.fd = dummy_file.fd;
+    for (int i = 0; i < MED_MULT; i++)
+        ss << dummyDataStr;
+
+    EXPECT_EQ(write(bulk_out, ss.str().c_str(), size), size);
+    EXPECT_EQ(handle->receiveFile(mfr), 0);
+
+    EXPECT_EQ(read(dummy_file.fd, buf, size), size);
+
+    EXPECT_STREQ(buf, ss.str().c_str());
+}
+
+TEST_F(MtpFfsHandleTest, testSendFileSmall) {
+    std::stringstream ss;
+    mtp_file_range mfr;
+    mfr.command = 42;
+    mfr.transaction_id = 1337;
+    int size = TEST_PACKET_SIZE * SMALL_MULT;
+    char buf[size + sizeof(mtp_data_header) + 1];
+    buf[size + sizeof(mtp_data_header)] = '\0';
+
+    mfr.length = size;
+    mfr.fd = dummy_file.fd;
+    for (int i = 0; i < SMALL_MULT; i++)
+        ss << dummyDataStr;
+
+    EXPECT_EQ(write(dummy_file.fd, ss.str().c_str(), size), size);
+    EXPECT_EQ(handle->sendFile(mfr), 0);
+
+    EXPECT_EQ(read(bulk_in, buf, size + sizeof(mtp_data_header)),
+            static_cast<long>(size + sizeof(mtp_data_header)));
+
+    struct mtp_data_header *header = reinterpret_cast<struct mtp_data_header*>(buf);
+    EXPECT_STREQ(buf + sizeof(mtp_data_header), ss.str().c_str());
+    EXPECT_EQ(header->length, static_cast<unsigned int>(size + sizeof(mtp_data_header)));
+    EXPECT_EQ(header->type, static_cast<unsigned int>(2));
+    EXPECT_EQ(header->command, static_cast<unsigned int>(42));
+    EXPECT_EQ(header->transaction_id, static_cast<unsigned int>(1337));
+}
+
+TEST_F(MtpFfsHandleTest, testSendFileMed) {
+    std::stringstream ss;
+    mtp_file_range mfr;
+    mfr.command = 42;
+    mfr.transaction_id = 1337;
+    int size = TEST_PACKET_SIZE * MED_MULT;
+    char buf[size + sizeof(mtp_data_header) + 1];
+    buf[size + sizeof(mtp_data_header)] = '\0';
+
+    mfr.length = size;
+    mfr.fd = dummy_file.fd;
+    for (int i = 0; i < MED_MULT; i++)
+        ss << dummyDataStr;
+
+    EXPECT_EQ(write(dummy_file.fd, ss.str().c_str(), size), size);
+    EXPECT_EQ(handle->sendFile(mfr), 0);
+
+    EXPECT_EQ(read(bulk_in, buf, size + sizeof(mtp_data_header)),
+            static_cast<long>(size + sizeof(mtp_data_header)));
+
+    struct mtp_data_header *header = reinterpret_cast<struct mtp_data_header*>(buf);
+    EXPECT_STREQ(buf + sizeof(mtp_data_header), ss.str().c_str());
+    EXPECT_EQ(header->length, static_cast<unsigned int>(size + sizeof(mtp_data_header)));
+    EXPECT_EQ(header->type, static_cast<unsigned int>(2));
+    EXPECT_EQ(header->command, static_cast<unsigned int>(42));
+    EXPECT_EQ(header->transaction_id, static_cast<unsigned int>(1337));
+}
+
+TEST_F(MtpFfsHandleTest, testSendEvent) {
+    struct mtp_event event;
+    event.length = TEST_PACKET_SIZE;
+    event.data = const_cast<char*>(dummyDataStr.c_str());
+    char buf[TEST_PACKET_SIZE + 1];
+    buf[TEST_PACKET_SIZE] = '\0';
+
+    handle->sendEvent(event);
+    read(intr, buf, TEST_PACKET_SIZE);
+    EXPECT_STREQ(buf, dummyDataStr.c_str());
+}
+
+} // namespace android
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 89f2d9c..805eafb 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -86,7 +86,6 @@
     jobject service = NULL;
     if (env == NULL) {
         ALOGE("setDataSource(path) must be called from Java thread");
-        env->ExceptionClear();
         return AMEDIA_ERROR_UNSUPPORTED;
     }
 
diff --git a/media/utils/BatteryNotifier.cpp b/media/utils/BatteryNotifier.cpp
index 7a7321f..09bc042 100644
--- a/media/utils/BatteryNotifier.cpp
+++ b/media/utils/BatteryNotifier.cpp
@@ -38,7 +38,7 @@
     }
 }
 
-void BatteryNotifier::noteStartVideo(int uid) {
+void BatteryNotifier::noteStartVideo(uid_t uid) {
     Mutex::Autolock _l(mLock);
     sp<IBatteryStats> batteryService = getBatteryService_l();
     if (mVideoRefCounts[uid] == 0 && batteryService != nullptr) {
@@ -47,7 +47,7 @@
     mVideoRefCounts[uid]++;
 }
 
-void BatteryNotifier::noteStopVideo(int uid) {
+void BatteryNotifier::noteStopVideo(uid_t uid) {
     Mutex::Autolock _l(mLock);
     if (mVideoRefCounts.find(uid) == mVideoRefCounts.end()) {
         ALOGW("%s: video refcount is broken for uid(%d).", __FUNCTION__, (int)uid);
@@ -74,7 +74,7 @@
     }
 }
 
-void BatteryNotifier::noteStartAudio(int uid) {
+void BatteryNotifier::noteStartAudio(uid_t uid) {
     Mutex::Autolock _l(mLock);
     sp<IBatteryStats> batteryService = getBatteryService_l();
     if (mAudioRefCounts[uid] == 0 && batteryService != nullptr) {
@@ -83,7 +83,7 @@
     mAudioRefCounts[uid]++;
 }
 
-void BatteryNotifier::noteStopAudio(int uid) {
+void BatteryNotifier::noteStopAudio(uid_t uid) {
     Mutex::Autolock _l(mLock);
     if (mAudioRefCounts.find(uid) == mAudioRefCounts.end()) {
         ALOGW("%s: audio refcount is broken for uid(%d).", __FUNCTION__, (int)uid);
@@ -110,11 +110,11 @@
     }
 }
 
-void BatteryNotifier::noteFlashlightOn(const String8& id, int uid) {
+void BatteryNotifier::noteFlashlightOn(const String8& id, uid_t uid) {
     Mutex::Autolock _l(mLock);
     sp<IBatteryStats> batteryService = getBatteryService_l();
 
-    std::pair<String8, int> k = std::make_pair(id, uid);
+    std::pair<String8, uid_t> k = std::make_pair(id, uid);
     if (!mFlashlightState[k]) {
         mFlashlightState[k] = true;
         if (batteryService != nullptr) {
@@ -123,11 +123,11 @@
     }
 }
 
-void BatteryNotifier::noteFlashlightOff(const String8& id, int uid) {
+void BatteryNotifier::noteFlashlightOff(const String8& id, uid_t uid) {
     Mutex::Autolock _l(mLock);
     sp<IBatteryStats> batteryService = getBatteryService_l();
 
-    std::pair<String8, int> k = std::make_pair(id, uid);
+    std::pair<String8, uid_t> k = std::make_pair(id, uid);
     if (mFlashlightState[k]) {
         mFlashlightState[k] = false;
         if (batteryService != nullptr) {
@@ -145,10 +145,10 @@
     }
 }
 
-void BatteryNotifier::noteStartCamera(const String8& id, int uid) {
+void BatteryNotifier::noteStartCamera(const String8& id, uid_t uid) {
     Mutex::Autolock _l(mLock);
     sp<IBatteryStats> batteryService = getBatteryService_l();
-    std::pair<String8, int> k = std::make_pair(id, uid);
+    std::pair<String8, uid_t> k = std::make_pair(id, uid);
     if (!mCameraState[k]) {
         mCameraState[k] = true;
         if (batteryService != nullptr) {
@@ -157,10 +157,10 @@
     }
 }
 
-void BatteryNotifier::noteStopCamera(const String8& id, int uid) {
+void BatteryNotifier::noteStopCamera(const String8& id, uid_t uid) {
     Mutex::Autolock _l(mLock);
     sp<IBatteryStats> batteryService = getBatteryService_l();
-    std::pair<String8, int> k = std::make_pair(id, uid);
+    std::pair<String8, uid_t> k = std::make_pair(id, uid);
     if (mCameraState[k]) {
         mCameraState[k] = false;
         if (batteryService != nullptr) {
@@ -211,7 +211,7 @@
         // Notify start now if mediaserver or audioserver is already started.
         // 1) mediaserver and audioserver is started before batterystats service
         // 2) batterystats server may have crashed.
-        std::map<int, int>::iterator it = mVideoRefCounts.begin();
+        std::map<uid_t, int>::iterator it = mVideoRefCounts.begin();
         for (; it != mVideoRefCounts.end(); ++it) {
             mBatteryStatService->noteStartVideo(it->first);
         }
diff --git a/media/utils/include/mediautils/BatteryNotifier.h b/media/utils/include/mediautils/BatteryNotifier.h
index 2ba4c76..a4e42ad 100644
--- a/media/utils/include/mediautils/BatteryNotifier.h
+++ b/media/utils/include/mediautils/BatteryNotifier.h
@@ -37,17 +37,17 @@
 public:
     ~BatteryNotifier();
 
-    void noteStartVideo(int uid);
-    void noteStopVideo(int uid);
+    void noteStartVideo(uid_t uid);
+    void noteStopVideo(uid_t uid);
     void noteResetVideo();
-    void noteStartAudio(int uid);
-    void noteStopAudio(int uid);
+    void noteStartAudio(uid_t uid);
+    void noteStopAudio(uid_t uid);
     void noteResetAudio();
-    void noteFlashlightOn(const String8& id, int uid);
-    void noteFlashlightOff(const String8& id, int uid);
+    void noteFlashlightOn(const String8& id, uid_t uid);
+    void noteFlashlightOff(const String8& id, uid_t uid);
     void noteResetFlashlight();
-    void noteStartCamera(const String8& id, int uid);
-    void noteStopCamera(const String8& id, int uid);
+    void noteStartCamera(const String8& id, uid_t uid);
+    void noteStopCamera(const String8& id, uid_t uid);
     void noteResetCamera();
 
 private:
@@ -58,10 +58,10 @@
     };
 
     Mutex mLock;
-    std::map<int, int> mVideoRefCounts;
-    std::map<int, int> mAudioRefCounts;
-    std::map<std::pair<String8, int>, bool> mFlashlightState;
-    std::map<std::pair<String8, int>, bool> mCameraState;
+    std::map<uid_t, int> mVideoRefCounts;
+    std::map<uid_t, int> mAudioRefCounts;
+    std::map<std::pair<String8, uid_t>, bool> mFlashlightState;
+    std::map<std::pair<String8, uid_t>, bool> mCameraState;
     sp<IBatteryStats> mBatteryStatService;
     sp<DeathNotifier> mDeathNotifier;
 
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index e2a93ad..51d785a 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -57,11 +57,11 @@
     libserviceutility \
     libsonic \
     libmediautils \
-    libmemunreachable
+    libmemunreachable \
+    libmedia_helper
 
 LOCAL_STATIC_LIBRARIES := \
     libcpustats \
-    libmedia_helper
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8917c26..d08309b 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2609,6 +2609,7 @@
         audio_io_handle_t io,
         audio_session_t sessionId,
         const String16& opPackageName,
+        pid_t pid,
         status_t *status,
         int *id,
         int *enabled)
@@ -2617,7 +2618,15 @@
     sp<EffectHandle> handle;
     effect_descriptor_t desc;
 
-    pid_t pid = IPCThreadState::self()->getCallingPid();
+    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+    if (pid == -1 || !isTrustedCallingUid(callingUid)) {
+        const pid_t callingPid = IPCThreadState::self()->getCallingPid();
+        ALOGW_IF(pid != -1 && pid != callingPid,
+                 "%s uid %d pid %d tried to pass itself off as pid %d",
+                 __func__, callingUid, callingPid, pid);
+        pid = callingPid;
+    }
+
     ALOGV("createEffect pid %d, effectClient %p, priority %d, sessionId %d, io %d, factory %p",
             pid, effectClient.get(), priority, sessionId, io, mEffectsFactoryHal.get());
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index b046ab5..08d94c4 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -226,6 +226,7 @@
                         audio_io_handle_t io,
                         audio_session_t sessionId,
                         const String16& opPackageName,
+                        pid_t pid,
                         status_t *status /*non-NULL*/,
                         int *id,
                         int *enabled);
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index 9f3488d..a1420ff 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -23,10 +23,10 @@
     libaudioclient \
     libhardware_legacy \
     libserviceutility \
-    libaudiopolicymanager
+    libaudiopolicymanager \
+    libmedia_helper
 
 LOCAL_STATIC_LIBRARIES := \
-    libmedia_helper \
     libaudiopolicycomponents
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
@@ -76,7 +76,7 @@
 LOCAL_STATIC_LIBRARIES := \
     libaudiopolicycomponents
 
-LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
+LOCAL_SHARED_LIBRARIES += libmedia_helper
 
 ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
 LOCAL_STATIC_LIBRARIES += libxml2
diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk
index 08c677e..341357c 100644
--- a/services/audiopolicy/engineconfigurable/Android.mk
+++ b/services/audiopolicy/engineconfigurable/Android.mk
@@ -40,8 +40,6 @@
 LOCAL_MODULE := libaudiopolicyengineconfigurable
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
-
 LOCAL_STATIC_LIBRARIES := \
     libaudiopolicypfwwrapper \
     libaudiopolicycomponents \
@@ -53,7 +51,8 @@
     libutils \
     liblog \
     libaudioutils \
-    libparameter
+    libparameter \
+    libmedia_helper
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.mk b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
index d031bc3..066ee0d 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.mk
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
@@ -14,10 +14,9 @@
 
 LOCAL_SRC_FILES:= ParameterManagerWrapper.cpp
 
-LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
-
 LOCAL_SHARED_LIBRARIES := \
     libparameter \
+    libmedia_helper
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
index c1bb3fb..47dc545 100644
--- a/services/audiopolicy/enginedefault/Android.mk
+++ b/services/audiopolicy/enginedefault/Android.mk
@@ -34,8 +34,6 @@
 LOCAL_MODULE := libaudiopolicyenginedefault
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
-
 LOCAL_STATIC_LIBRARIES := \
     libaudiopolicycomponents \
     libxml2
@@ -44,5 +42,6 @@
     liblog \
     libcutils \
     libutils \
+    libmedia_helper
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index c2b282e..2f25020 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -341,7 +341,7 @@
     DeviceVector deviceList;
     uint32_t muteWaitMs = 0;
 
-    if(!hasPrimaryOutput()) {
+    if(!hasPrimaryOutput() || mPrimaryOutput->device() == AUDIO_DEVICE_OUT_STUB) {
         return muteWaitMs;
     }
     audio_devices_t txDevice = getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 6586bea..654465d 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -27,6 +27,7 @@
 #include <utils/Vector.h>
 #include <utils/SortedVector.h>
 #include <cutils/config_utils.h>
+#include <binder/IPCThreadState.h>
 #include "AudioPolicyEffects.h"
 #include "ServiceUtilities.h"
 
@@ -105,6 +106,7 @@
 
     ALOGV("addInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
     if (sessionDesc->mRefCount == 1) {
+        int64_t token = IPCThreadState::self()->clearCallingIdentity();
         Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
         for (size_t i = 0; i < effects.size(); i++) {
             EffectDesc *effect = effects[i];
@@ -125,6 +127,7 @@
             sessionDesc->mEffects.add(fx);
         }
         sessionDesc->setProcessorEnabled(true);
+        IPCThreadState::self()->restoreCallingIdentity(token);
     }
     return status;
 }
@@ -251,6 +254,8 @@
     ALOGV("addOutputSessionEffects(): session: %d, refCount: %d",
           audioSession, procDesc->mRefCount);
     if (procDesc->mRefCount == 1) {
+        // make sure effects are associated to audio server even if we are executing a binder call
+        int64_t token = IPCThreadState::self()->clearCallingIdentity();
         Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
         for (size_t i = 0; i < effects.size(); i++) {
             EffectDesc *effect = effects[i];
@@ -269,6 +274,7 @@
         }
 
         procDesc->setProcessorEnabled(true);
+        IPCThreadState::self()->restoreCallingIdentity(token);
     }
     return status;
 }
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 7feed6b..ef2e8d9 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -67,7 +67,8 @@
     libhardware \
     libcamera_metadata \
     libjpeg \
-    libmemunreachable
+    libmemunreachable \
+    android.hardware.camera.common@1.0
 
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 85faac6..1d9ccb1 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -69,7 +69,11 @@
 namespace android {
 
 using binder::Status;
-using namespace hardware;
+using hardware::ICamera;
+using hardware::ICameraClient;
+using hardware::ICameraServiceListener;
+using hardware::camera::common::V1_0::CameraDeviceStatus;
+using hardware::camera::common::V1_0::TorchModeStatus;
 
 // ----------------------------------------------------------------------------
 // Logging support -- this is for debugging only
@@ -103,9 +107,24 @@
         int new_status) {
     sp<CameraService> cs = const_cast<CameraService*>(
             static_cast<const CameraService*>(callbacks));
+    String8 id = String8::format("%d", camera_id);
 
-    cs->onDeviceStatusChanged(camera_id,
-            static_cast<camera_device_status_t>(new_status));
+    CameraDeviceStatus newStatus{CameraDeviceStatus::NOT_PRESENT};
+    switch (new_status) {
+        case CAMERA_DEVICE_STATUS_NOT_PRESENT:
+            newStatus = CameraDeviceStatus::NOT_PRESENT;
+            break;
+        case CAMERA_DEVICE_STATUS_PRESENT:
+            newStatus = CameraDeviceStatus::PRESENT;
+            break;
+        case CAMERA_DEVICE_STATUS_ENUMERATING:
+            newStatus = CameraDeviceStatus::ENUMERATING;
+            break;
+        default:
+            ALOGW("Unknown device status change to %d", new_status);
+            break;
+    }
+    cs->onDeviceStatusChanged(id, newStatus);
 }
 
 static void torch_mode_status_change(
@@ -119,16 +138,16 @@
     sp<CameraService> cs = const_cast<CameraService*>(
                                 static_cast<const CameraService*>(callbacks));
 
-    int32_t status;
+    TorchModeStatus status;
     switch (new_status) {
         case TORCH_MODE_STATUS_NOT_AVAILABLE:
-            status = ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
+            status = TorchModeStatus::NOT_AVAILABLE;
             break;
         case TORCH_MODE_STATUS_AVAILABLE_OFF:
-            status = ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF;
+            status = TorchModeStatus::AVAILABLE_OFF;
             break;
         case TORCH_MODE_STATUS_AVAILABLE_ON:
-            status = ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON;
+            status = TorchModeStatus::AVAILABLE_ON;
             break;
         default:
             ALOGE("Unknown torch status %d", new_status);
@@ -261,7 +280,7 @@
 
         if (mFlashlight->hasFlashUnit(cameraId)) {
             mTorchStatusMap.add(cameraId,
-                    ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF);
+                    TorchModeStatus::AVAILABLE_OFF);
         }
     }
 
@@ -276,7 +295,10 @@
     sp<ICameraServiceProxy> proxyBinder = nullptr;
 #ifndef __BRILLO__
     sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("media.camera.proxy"));
+    // Use checkService because cameraserver normally starts before the
+    // system server and the proxy service. So the long timeout that getService
+    // has before giving up is inappropriate.
+    sp<IBinder> binder = sm->checkService(String16("media.camera.proxy"));
     if (binder != nullptr) {
         proxyBinder = interface_cast<ICameraServiceProxy>(binder);
     }
@@ -299,27 +321,28 @@
     gCameraService = nullptr;
 }
 
-void CameraService::onDeviceStatusChanged(int  cameraId,
-        camera_device_status_t newStatus) {
-    ALOGI("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__,
-          cameraId, newStatus);
+void CameraService::onDeviceStatusChanged(const String8& id,
+        CameraDeviceStatus newHalStatus) {
+    ALOGI("%s: Status changed for cameraId=%s, newStatus=%d", __FUNCTION__,
+            id.string(), newHalStatus);
 
-    String8 id = String8::format("%d", cameraId);
+    StatusInternal newStatus = mapToInternal(newHalStatus);
+
     std::shared_ptr<CameraState> state = getCameraState(id);
 
     if (state == nullptr) {
-        ALOGE("%s: Bad camera ID %d", __FUNCTION__, cameraId);
+        ALOGE("%s: Bad camera ID %s", __FUNCTION__, id.string());
         return;
     }
 
-    int32_t oldStatus = state->getStatus();
+    StatusInternal oldStatus = state->getStatus();
 
-    if (oldStatus == static_cast<int32_t>(newStatus)) {
+    if (oldStatus == newStatus) {
         ALOGE("%s: State transition to the same status %#x not allowed", __FUNCTION__, newStatus);
         return;
     }
 
-    if (newStatus == CAMERA_DEVICE_STATUS_NOT_PRESENT) {
+    if (newStatus == StatusInternal::NOT_PRESENT) {
         logDeviceRemoved(id, String8::format("Device status changed from %d to %d", oldStatus,
                 newStatus));
         sp<BasicClient> clientToDisconnect;
@@ -329,7 +352,7 @@
 
             // Set the device status to NOT_PRESENT, clients will no longer be able to connect
             // to this device until the status changes
-            updateStatus(ICameraServiceListener::STATUS_NOT_PRESENT, id);
+            updateStatus(StatusInternal::NOT_PRESENT, id);
 
             // Remove cached shim parameters
             state->setShimParams(CameraParameters());
@@ -355,27 +378,27 @@
         }
 
     } else {
-        if (oldStatus == ICameraServiceListener::STATUS_NOT_PRESENT) {
+        if (oldStatus == StatusInternal::NOT_PRESENT) {
             logDeviceAdded(id, String8::format("Device status changed from %d to %d", oldStatus,
                     newStatus));
         }
-        updateStatus(static_cast<int32_t>(newStatus), id);
+        updateStatus(newStatus, id);
     }
 
 }
 
 void CameraService::onTorchStatusChanged(const String8& cameraId,
-        int32_t newStatus) {
+        TorchModeStatus newStatus) {
     Mutex::Autolock al(mTorchStatusMutex);
     onTorchStatusChangedLocked(cameraId, newStatus);
 }
 
 void CameraService::onTorchStatusChangedLocked(const String8& cameraId,
-        int32_t newStatus) {
+        TorchModeStatus newStatus) {
     ALOGI("%s: Torch status changed for cameraId=%s, newStatus=%d",
             __FUNCTION__, cameraId.string(), newStatus);
 
-    int32_t status;
+    TorchModeStatus status;
     status_t res = getTorchStatusLocked(cameraId, &status);
     if (res) {
         ALOGE("%s: cannot get torch status of camera %s: %s (%d)",
@@ -403,16 +426,16 @@
             BatteryNotifier& notifier(BatteryNotifier::getInstance());
             if (oldUid != newUid) {
                 // If the UID has changed, log the status and update current UID in mTorchUidMap
-                if (status == ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON) {
+                if (status == TorchModeStatus::AVAILABLE_ON) {
                     notifier.noteFlashlightOff(cameraId, oldUid);
                 }
-                if (newStatus == ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON) {
+                if (newStatus == TorchModeStatus::AVAILABLE_ON) {
                     notifier.noteFlashlightOn(cameraId, newUid);
                 }
                 iter->second.second = newUid;
             } else {
                 // If the UID has not changed, log the status
-                if (newStatus == ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON) {
+                if (newStatus == TorchModeStatus::AVAILABLE_ON) {
                     notifier.noteFlashlightOn(cameraId, oldUid);
                 } else {
                     notifier.noteFlashlightOff(cameraId, oldUid);
@@ -424,7 +447,7 @@
     {
         Mutex::Autolock lock(mStatusListenerLock);
         for (auto& i : mListenerList) {
-            i->onTorchStatusChanged(newStatus, String16{cameraId});
+            i->onTorchStatusChanged(mapToInterface(newStatus), String16{cameraId});
         }
     }
 }
@@ -487,101 +510,8 @@
     return ret;
 }
 
-Status CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata* cameraInfo) {
-    ATRACE_CALL();
-
-    Status ret = Status::ok();
-
-    struct CameraInfo info;
-    if (!(ret = getCameraInfo(cameraId, &info)).isOk()) {
-        return ret;
-    }
-
-    CameraMetadata shimInfo;
-    int32_t orientation = static_cast<int32_t>(info.orientation);
-    status_t rc;
-    if ((rc = shimInfo.update(ANDROID_SENSOR_ORIENTATION, &orientation, 1)) != OK) {
-        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
-                "Error updating metadata: %d (%s)", rc, strerror(-rc));
-    }
-
-    uint8_t facing = (info.facing == CAMERA_FACING_FRONT) ?
-            ANDROID_LENS_FACING_FRONT : ANDROID_LENS_FACING_BACK;
-    if ((rc = shimInfo.update(ANDROID_LENS_FACING, &facing, 1)) != OK) {
-        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
-                "Error updating metadata: %d (%s)", rc, strerror(-rc));
-    }
-
-    CameraParameters shimParams;
-    if (!(ret = getLegacyParametersLazy(cameraId, /*out*/&shimParams)).isOk()) {
-        // Error logged by callee
-        return ret;
-    }
-
-    Vector<Size> sizes;
-    Vector<Size> jpegSizes;
-    Vector<int32_t> formats;
-    {
-        shimParams.getSupportedPreviewSizes(/*out*/sizes);
-        shimParams.getSupportedPreviewFormats(/*out*/formats);
-        shimParams.getSupportedPictureSizes(/*out*/jpegSizes);
-    }
-
-    // Always include IMPLEMENTATION_DEFINED
-    formats.add(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
-
-    const size_t INTS_PER_CONFIG = 4;
-
-    // Build available stream configurations metadata
-    size_t streamConfigSize = (sizes.size() * formats.size() + jpegSizes.size()) * INTS_PER_CONFIG;
-
-    Vector<int32_t> streamConfigs;
-    streamConfigs.setCapacity(streamConfigSize);
-
-    for (size_t i = 0; i < formats.size(); ++i) {
-        for (size_t j = 0; j < sizes.size(); ++j) {
-            streamConfigs.add(formats[i]);
-            streamConfigs.add(sizes[j].width);
-            streamConfigs.add(sizes[j].height);
-            streamConfigs.add(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
-        }
-    }
-
-    for (size_t i = 0; i < jpegSizes.size(); ++i) {
-        streamConfigs.add(HAL_PIXEL_FORMAT_BLOB);
-        streamConfigs.add(jpegSizes[i].width);
-        streamConfigs.add(jpegSizes[i].height);
-        streamConfigs.add(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
-    }
-
-    if ((rc = shimInfo.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
-            streamConfigs.array(), streamConfigSize)) != OK) {
-        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
-                "Error updating metadata: %d (%s)", rc, strerror(-rc));
-    }
-
-    int64_t fakeMinFrames[0];
-    // TODO: Fixme, don't fake min frame durations.
-    if ((rc = shimInfo.update(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
-            fakeMinFrames, 0)) != OK) {
-        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
-                "Error updating metadata: %d (%s)", rc, strerror(-rc));
-    }
-
-    int64_t fakeStalls[0];
-    // TODO: Fixme, don't fake stall durations.
-    if ((rc = shimInfo.update(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
-            fakeStalls, 0)) != OK) {
-        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
-                "Error updating metadata: %d (%s)", rc, strerror(-rc));
-    }
-
-    *cameraInfo = shimInfo;
-    return ret;
-}
-
-Status CameraService::getCameraCharacteristics(int cameraId,
-                                                CameraMetadata* cameraInfo) {
+Status CameraService::getCameraCharacteristics(const String16& id,
+        CameraMetadata* cameraInfo) {
     ATRACE_CALL();
     if (!cameraInfo) {
         ALOGE("%s: cameraInfo is NULL", __FUNCTION__);
@@ -594,6 +524,8 @@
                 "Camera subsystem is not available");;
     }
 
+    int cameraId = cameraIdToInt(String8(id));
+
     if (cameraId < 0 || cameraId >= mNumberOfCameras) {
         ALOGE("%s: Invalid camera id: %d", __FUNCTION__, cameraId);
         return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
@@ -604,26 +536,14 @@
     Status ret;
     if (mModule->getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_0 ||
             getDeviceVersion(cameraId, &facing) < CAMERA_DEVICE_API_VERSION_3_0) {
-        /**
-         * Backwards compatibility mode for old HALs:
-         * - Convert CameraInfo into static CameraMetadata properties.
-         * - Retrieve cached CameraParameters for this camera.  If none exist,
-         *   attempt to open CameraClient and retrieve the CameraParameters.
-         * - Convert cached CameraParameters into static CameraMetadata
-         *   properties.
-         */
-        ALOGI("%s: Switching to HAL1 shim implementation...", __FUNCTION__);
-
-        ret = generateShimMetadata(cameraId, cameraInfo);
-    } else {
-        /**
-         * Normal HAL 2.1+ codepath.
-         */
-        struct camera_info info;
-        ret = filterGetInfoErrorCode(mModule->getCameraInfo(cameraId, &info));
-        if (ret.isOk()) {
-            *cameraInfo = info.static_camera_characteristics;
-        }
+        return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "Can't get camera characteristics"
+                " for devices with HAL version < 3.0, %d is version %x", cameraId,
+                getDeviceVersion(cameraId, &facing));
+    }
+    struct camera_info info;
+    ret = filterGetInfoErrorCode(mModule->getCameraInfo(cameraId, &info));
+    if (ret.isOk()) {
+        *cameraInfo = info.static_camera_characteristics;
     }
 
     return ret;
@@ -700,10 +620,10 @@
     switch(err) {
         case NO_ERROR:
             return Status::ok();
-        case -EINVAL:
+        case BAD_VALUE:
             return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT,
                     "CameraId is not valid for HAL module");
-        case -ENODEV:
+        case NO_INIT:
             return STATUS_ERROR(ERROR_DISCONNECTED,
                     "Camera device not available");
         default:
@@ -831,6 +751,66 @@
     return s;
 }
 
+int32_t CameraService::mapToInterface(TorchModeStatus status) {
+    int32_t serviceStatus = ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
+    switch (status) {
+        case TorchModeStatus::NOT_AVAILABLE:
+            serviceStatus = ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
+            break;
+        case TorchModeStatus::AVAILABLE_OFF:
+            serviceStatus = ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF;
+            break;
+        case TorchModeStatus::AVAILABLE_ON:
+            serviceStatus = ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON;
+            break;
+        default:
+            ALOGW("Unknown new flash status: %d", status);
+    }
+    return serviceStatus;
+}
+
+CameraService::StatusInternal CameraService::mapToInternal(CameraDeviceStatus status) {
+    StatusInternal serviceStatus = StatusInternal::NOT_PRESENT;
+    switch (status) {
+        case CameraDeviceStatus::NOT_PRESENT:
+            serviceStatus = StatusInternal::NOT_PRESENT;
+            break;
+        case CameraDeviceStatus::PRESENT:
+            serviceStatus = StatusInternal::PRESENT;
+            break;
+        case CameraDeviceStatus::ENUMERATING:
+            serviceStatus = StatusInternal::ENUMERATING;
+            break;
+        default:
+            ALOGW("Unknown new HAL device status: %d", status);
+    }
+    return serviceStatus;
+}
+
+int32_t CameraService::mapToInterface(StatusInternal status) {
+    int32_t serviceStatus = ICameraServiceListener::STATUS_NOT_PRESENT;
+    switch (status) {
+        case StatusInternal::NOT_PRESENT:
+            serviceStatus = ICameraServiceListener::STATUS_NOT_PRESENT;
+            break;
+        case StatusInternal::PRESENT:
+            serviceStatus = ICameraServiceListener::STATUS_PRESENT;
+            break;
+        case StatusInternal::ENUMERATING:
+            serviceStatus = ICameraServiceListener::STATUS_ENUMERATING;
+            break;
+        case StatusInternal::NOT_AVAILABLE:
+            serviceStatus = ICameraServiceListener::STATUS_NOT_AVAILABLE;
+            break;
+        case StatusInternal::UNKNOWN:
+            serviceStatus = ICameraServiceListener::STATUS_UNKNOWN;
+            break;
+        default:
+            ALOGW("Unknown new internal device status: %d", status);
+    }
+    return serviceStatus;
+}
+
 Status CameraService::initializeShimMetadata(int cameraId) {
     int uid = getCallingUid();
 
@@ -1042,12 +1022,12 @@
         return -ENODEV;
     }
 
-    int32_t currentStatus = cameraState->getStatus();
-    if (currentStatus == ICameraServiceListener::STATUS_NOT_PRESENT) {
+    StatusInternal currentStatus = cameraState->getStatus();
+    if (currentStatus == StatusInternal::NOT_PRESENT) {
         ALOGE("CameraService::connect X (PID %d) rejected (camera %s is not connected)",
                 callingPid, cameraId.string());
         return -ENODEV;
-    } else if (currentStatus == ICameraServiceListener::STATUS_ENUMERATING) {
+    } else if (currentStatus == StatusInternal::ENUMERATING) {
         ALOGE("CameraService::connect X (PID %d) rejected, (camera %s is initializing)",
                 callingPid, cameraId.string());
         return -EBUSY;
@@ -1345,7 +1325,7 @@
 
 Status CameraService::connectDevice(
         const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
-        int cameraId,
+        const String16& cameraId,
         const String16& clientPackageName,
         int clientUid,
         /*out*/
@@ -1353,7 +1333,7 @@
 
     ATRACE_CALL();
     Status ret = Status::ok();
-    String8 id = String8::format("%d", cameraId);
+    String8 id = String8(cameraId);
     sp<CameraDeviceClient> client = nullptr;
     ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
             CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
@@ -1371,6 +1351,166 @@
     return ret;
 }
 
+template<class CALLBACK, class CLIENT>
+Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
+        int halVersion, const String16& clientPackageName, int clientUid, int clientPid,
+        apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
+        /*out*/sp<CLIENT>& device) {
+    binder::Status ret = binder::Status::ok();
+
+    String8 clientName8(clientPackageName);
+
+    int originalClientPid = 0;
+
+    ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) for HAL version %s and "
+            "Camera API version %d", clientPid, clientName8.string(), cameraId.string(),
+            (halVersion == -1) ? "default" : std::to_string(halVersion).c_str(),
+            static_cast<int>(effectiveApiLevel));
+
+    sp<CLIENT> client = nullptr;
+    {
+        // Acquire mServiceLock and prevent other clients from connecting
+        std::unique_ptr<AutoConditionLock> lock =
+                AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);
+
+        if (lock == nullptr) {
+            ALOGE("CameraService::connect (PID %d) rejected (too many other clients connecting)."
+                    , clientPid);
+            return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
+                    "Cannot open camera %s for \"%s\" (PID %d): Too many other clients connecting",
+                    cameraId.string(), clientName8.string(), clientPid);
+        }
+
+        // Enforce client permissions and do basic sanity checks
+        if(!(ret = validateConnectLocked(cameraId, clientName8,
+                /*inout*/clientUid, /*inout*/clientPid, /*out*/originalClientPid)).isOk()) {
+            return ret;
+        }
+
+        // Check the shim parameters after acquiring lock, if they have already been updated and
+        // we were doing a shim update, return immediately
+        if (shimUpdateOnly) {
+            auto cameraState = getCameraState(cameraId);
+            if (cameraState != nullptr) {
+                if (!cameraState->getShimParams().isEmpty()) return ret;
+            }
+        }
+
+        status_t err;
+
+        sp<BasicClient> clientTmp = nullptr;
+        std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;
+        if ((err = handleEvictionsLocked(cameraId, originalClientPid, effectiveApiLevel,
+                IInterface::asBinder(cameraCb), clientName8, /*out*/&clientTmp,
+                /*out*/&partial)) != NO_ERROR) {
+            switch (err) {
+                case -ENODEV:
+                    return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
+                            "No camera device with ID \"%s\" currently available",
+                            cameraId.string());
+                case -EBUSY:
+                    return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
+                            "Higher-priority client using camera, ID \"%s\" currently unavailable",
+                            cameraId.string());
+                default:
+                    return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
+                            "Unexpected error %s (%d) opening camera \"%s\"",
+                            strerror(-err), err, cameraId.string());
+            }
+        }
+
+        if (clientTmp.get() != nullptr) {
+            // Handle special case for API1 MediaRecorder where the existing client is returned
+            device = static_cast<CLIENT*>(clientTmp.get());
+            return ret;
+        }
+
+        // give flashlight a chance to close devices if necessary.
+        mFlashlight->prepareDeviceOpen(cameraId);
+
+        // TODO: Update getDeviceVersion + HAL interface to use strings for Camera IDs
+        int id = cameraIdToInt(cameraId);
+        if (id == -1) {
+            ALOGE("%s: Invalid camera ID %s, cannot get device version from HAL.", __FUNCTION__,
+                    cameraId.string());
+            return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
+                    "Bad camera ID \"%s\" passed to camera open", cameraId.string());
+        }
+
+        int facing = -1;
+        int deviceVersion = getDeviceVersion(id, /*out*/&facing);
+        sp<BasicClient> tmp = nullptr;
+        if(!(ret = makeClient(this, cameraCb, clientPackageName, id, facing, clientPid,
+                clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel,
+                /*out*/&tmp)).isOk()) {
+            return ret;
+        }
+        client = static_cast<CLIENT*>(tmp.get());
+
+        LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
+                __FUNCTION__);
+
+        if ((err = client->initialize(mModule)) != OK) {
+            ALOGE("%s: Could not initialize client from HAL module.", __FUNCTION__);
+            // Errors could be from the HAL module open call or from AppOpsManager
+            switch(err) {
+                case BAD_VALUE:
+                    return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
+                            "Illegal argument to HAL module for camera \"%s\"", cameraId.string());
+                case -EBUSY:
+                    return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
+                            "Camera \"%s\" is already open", cameraId.string());
+                case -EUSERS:
+                    return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
+                            "Too many cameras already open, cannot open camera \"%s\"",
+                            cameraId.string());
+                case PERMISSION_DENIED:
+                    return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
+                            "No permission to open camera \"%s\"", cameraId.string());
+                case -EACCES:
+                    return STATUS_ERROR_FMT(ERROR_DISABLED,
+                            "Camera \"%s\" disabled by policy", cameraId.string());
+                case -ENODEV:
+                default:
+                    return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
+                            "Failed to initialize camera \"%s\": %s (%d)", cameraId.string(),
+                            strerror(-err), err);
+            }
+        }
+
+        // Update shim paremeters for legacy clients
+        if (effectiveApiLevel == API_1) {
+            // Assume we have always received a Client subclass for API1
+            sp<Client> shimClient = reinterpret_cast<Client*>(client.get());
+            String8 rawParams = shimClient->getParameters();
+            CameraParameters params(rawParams);
+
+            auto cameraState = getCameraState(cameraId);
+            if (cameraState != nullptr) {
+                cameraState->setShimParams(params);
+            } else {
+                ALOGE("%s: Cannot update shim parameters for camera %s, no such device exists.",
+                        __FUNCTION__, cameraId.string());
+            }
+        }
+
+        if (shimUpdateOnly) {
+            // If only updating legacy shim parameters, immediately disconnect client
+            mServiceLock.unlock();
+            client->disconnect();
+            mServiceLock.lock();
+        } else {
+            // Otherwise, add client to active clients list
+            finishConnectLocked(client, partial);
+        }
+    } // lock is destroyed, allow further connect calls
+
+    // Important: release the mutex here so the client can call back into the service from its
+    // destructor (can be at the end of the call)
+    device = client;
+    return ret;
+}
+
 Status CameraService::setTorchMode(const String16& cameraId, bool enabled,
         const sp<IBinder>& clientBinder) {
 
@@ -1392,9 +1532,9 @@
                 "Camera ID \"%s\" is a not valid camera ID", id.string());
     }
 
-    int32_t cameraStatus = state->getStatus();
-    if (cameraStatus != ICameraServiceListener::STATUS_PRESENT &&
-            cameraStatus != ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+    StatusInternal cameraStatus = state->getStatus();
+    if (cameraStatus != StatusInternal::PRESENT &&
+            cameraStatus != StatusInternal::NOT_PRESENT) {
         ALOGE("%s: camera id is invalid %s", __FUNCTION__, id.string());
         return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
                 "Camera ID \"%s\" is a not valid camera ID", id.string());
@@ -1402,7 +1542,7 @@
 
     {
         Mutex::Autolock al(mTorchStatusMutex);
-        int32_t status;
+        TorchModeStatus status;
         status_t err = getTorchStatusLocked(id, &status);
         if (err != OK) {
             if (err == NAME_NOT_FOUND) {
@@ -1416,8 +1556,8 @@
                     strerror(-err), err);
         }
 
-        if (status == ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE) {
-            if (cameraStatus == ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+        if (status == TorchModeStatus::NOT_AVAILABLE) {
+            if (cameraStatus == StatusInternal::NOT_PRESENT) {
                 ALOGE("%s: torch mode of camera %s is not available because "
                         "camera is in use", __FUNCTION__, id.string());
                 return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
@@ -1506,7 +1646,9 @@
     return Status::ok();
 }
 
-Status CameraService::addListener(const sp<ICameraServiceListener>& listener) {
+Status CameraService::addListener(const sp<ICameraServiceListener>& listener,
+        /*out*/
+        std::vector<hardware::CameraStatus> *cameraStatuses) {
     ATRACE_CALL();
 
     ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
@@ -1531,25 +1673,23 @@
         mListenerList.push_back(listener);
     }
 
-
-    /* Immediately signal current status to this listener only */
+    /* Collect current devices and status */
     {
         Mutex::Autolock lock(mCameraStatesLock);
         for (auto& i : mCameraStates) {
-            // TODO: Update binder to use String16 for camera IDs and remove;
-            int id = cameraIdToInt(i.first);
-            if (id == -1) continue;
-
-            listener->onStatusChanged(i.second->getStatus(), id);
+            cameraStatuses->emplace_back(i.first, mapToInterface(i.second->getStatus()));
         }
     }
 
-    /* Immediately signal current torch status to this listener only */
+    /*
+     * Immediately signal current torch status to this listener only
+     * This may be a subset of all the devices, so don't include it in the response directly
+     */
     {
         Mutex::Autolock al(mTorchStatusMutex);
         for (size_t i = 0; i < mTorchStatusMap.size(); i++ ) {
             String16 id = String16(mTorchStatusMap.keyAt(i).string());
-            listener->onTorchStatusChanged(mTorchStatusMap.valueAt(i), id);
+            listener->onTorchStatusChanged(mapToInterface(mTorchStatusMap.valueAt(i)), id);
         }
     }
 
@@ -1610,10 +1750,11 @@
     return ret;
 }
 
-Status CameraService::supportsCameraApi(int cameraId, int apiVersion, bool *isSupported) {
+Status CameraService::supportsCameraApi(const String16& cameraId, int apiVersion,
+        /*out*/ bool *isSupported) {
     ATRACE_CALL();
 
-    ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId);
+    ALOGV("%s: for camera ID = %s", __FUNCTION__, String8(cameraId).string());
 
     switch (apiVersion) {
         case API_VERSION_1:
@@ -1626,7 +1767,9 @@
     }
 
     int facing = -1;
-    int deviceVersion = getDeviceVersion(cameraId, &facing);
+
+    int id = cameraIdToInt(String8(cameraId));
+    int deviceVersion = getDeviceVersion(id, &facing);
 
     switch(deviceVersion) {
         case CAMERA_DEVICE_API_VERSION_1_0:
@@ -1634,11 +1777,11 @@
         case CAMERA_DEVICE_API_VERSION_3_1:
             if (apiVersion == API_VERSION_2) {
                 ALOGV("%s: Camera id %d uses HAL version %d <3.2, doesn't support api2 without shim",
-                        __FUNCTION__, cameraId, deviceVersion);
+                        __FUNCTION__, id, deviceVersion);
                 *isSupported = false;
             } else { // if (apiVersion == API_VERSION_1) {
                 ALOGV("%s: Camera id %d uses older HAL before 3.2, but api1 is always supported",
-                        __FUNCTION__, cameraId);
+                        __FUNCTION__, id);
                 *isSupported = true;
             }
             break;
@@ -1646,17 +1789,17 @@
         case CAMERA_DEVICE_API_VERSION_3_3:
         case CAMERA_DEVICE_API_VERSION_3_4:
             ALOGV("%s: Camera id %d uses HAL3.2 or newer, supports api1/api2 directly",
-                    __FUNCTION__, cameraId);
+                    __FUNCTION__, id);
             *isSupported = true;
             break;
         case -1: {
-            String8 msg = String8::format("Unknown camera ID %d", cameraId);
+            String8 msg = String8::format("Unknown camera ID %d", id);
             ALOGE("%s: %s", __FUNCTION__, msg.string());
             return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
         }
         default: {
             String8 msg = String8::format("Unknown device version %d for device %d",
-                    deviceVersion, cameraId);
+                    deviceVersion, id);
             ALOGE("%s: %s", __FUNCTION__, msg.string());
             return STATUS_ERROR(ERROR_INVALID_OPERATION, msg.string());
         }
@@ -2212,7 +2355,7 @@
     mOpsActive = true;
 
     // Transition device availability listeners from PRESENT -> NOT_AVAILABLE
-    mCameraService->updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
+    mCameraService->updateStatus(StatusInternal::NOT_AVAILABLE,
             String8::format("%d", mCameraId));
 
     // Transition device state to OPEN
@@ -2232,11 +2375,11 @@
                 mClientPackageName);
         mOpsActive = false;
 
-        std::initializer_list<int32_t> rejected = {ICameraServiceListener::STATUS_NOT_PRESENT,
-                ICameraServiceListener::STATUS_ENUMERATING};
+        std::initializer_list<StatusInternal> rejected = {StatusInternal::PRESENT,
+                StatusInternal::ENUMERATING};
 
         // Transition to PRESENT if the camera is not in either of the rejected states
-        mCameraService->updateStatus(ICameraServiceListener::STATUS_PRESENT,
+        mCameraService->updateStatus(StatusInternal::PRESENT,
                 String8::format("%d", mCameraId), rejected);
 
         // Transition device state to CLOSED
@@ -2336,11 +2479,11 @@
 
 CameraService::CameraState::CameraState(const String8& id, int cost,
         const std::set<String8>& conflicting) : mId(id),
-        mStatus(ICameraServiceListener::STATUS_PRESENT), mCost(cost), mConflicting(conflicting) {}
+        mStatus(StatusInternal::PRESENT), mCost(cost), mConflicting(conflicting) {}
 
 CameraService::CameraState::~CameraState() {}
 
-int32_t CameraService::CameraState::getStatus() const {
+CameraService::StatusInternal CameraService::CameraState::getStatus() const {
     Mutex::Autolock lock(mStatusLock);
     return mStatus;
 }
@@ -2719,12 +2862,12 @@
             __FUNCTION__);
 }
 
-void CameraService::updateStatus(int32_t status, const String8& cameraId) {
+void CameraService::updateStatus(StatusInternal status, const String8& cameraId) {
     updateStatus(status, cameraId, {});
 }
 
-void CameraService::updateStatus(int32_t status, const String8& cameraId,
-        std::initializer_list<int32_t> rejectSourceStates) {
+void CameraService::updateStatus(StatusInternal status, const String8& cameraId,
+        std::initializer_list<StatusInternal> rejectSourceStates) {
     // Do not lock mServiceLock here or can get into a deadlock from
     // connect() -> disconnect -> updateStatus
 
@@ -2739,18 +2882,18 @@
     // Update the status for this camera state, then send the onStatusChangedCallbacks to each
     // of the listeners with both the mStatusStatus and mStatusListenerLock held
     state->updateStatus(status, cameraId, rejectSourceStates, [this]
-            (const String8& cameraId, int32_t status) {
+            (const String8& cameraId, StatusInternal status) {
 
-            if (status != ICameraServiceListener::STATUS_ENUMERATING) {
+            if (status != StatusInternal::ENUMERATING) {
                 // Update torch status if it has a flash unit.
                 Mutex::Autolock al(mTorchStatusMutex);
-                int32_t torchStatus;
+                TorchModeStatus torchStatus;
                 if (getTorchStatusLocked(cameraId, &torchStatus) !=
                         NAME_NOT_FOUND) {
-                    int32_t newTorchStatus =
-                            status == ICameraServiceListener::STATUS_PRESENT ?
-                            ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF :
-                            ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
+                    TorchModeStatus newTorchStatus =
+                            status == StatusInternal::PRESENT ?
+                            TorchModeStatus::AVAILABLE_OFF :
+                            TorchModeStatus::NOT_AVAILABLE;
                     if (torchStatus != newTorchStatus) {
                         onTorchStatusChangedLocked(cameraId, newTorchStatus);
                     }
@@ -2760,13 +2903,54 @@
             Mutex::Autolock lock(mStatusListenerLock);
 
             for (auto& listener : mListenerList) {
-                // TODO: Refactor status listeners to use strings for Camera IDs and remove this.
-                int id = cameraIdToInt(cameraId);
-                if (id != -1) listener->onStatusChanged(status, id);
+                listener->onStatusChanged(mapToInterface(status), String16(cameraId));
             }
         });
 }
 
+template<class Func>
+void CameraService::CameraState::updateStatus(StatusInternal status,
+        const String8& cameraId,
+        std::initializer_list<StatusInternal> rejectSourceStates,
+        Func onStatusUpdatedLocked) {
+    Mutex::Autolock lock(mStatusLock);
+    StatusInternal oldStatus = mStatus;
+    mStatus = status;
+
+    if (oldStatus == status) {
+        return;
+    }
+
+    ALOGV("%s: Status has changed for camera ID %s from %#x to %#x", __FUNCTION__,
+            cameraId.string(), oldStatus, status);
+
+    if (oldStatus == StatusInternal::NOT_PRESENT &&
+            (status != StatusInternal::PRESENT &&
+             status != StatusInternal::ENUMERATING)) {
+
+        ALOGW("%s: From NOT_PRESENT can only transition into PRESENT or ENUMERATING",
+                __FUNCTION__);
+        mStatus = oldStatus;
+        return;
+    }
+
+    /**
+     * Sometimes we want to conditionally do a transition.
+     * For example if a client disconnects, we want to go to PRESENT
+     * only if we weren't already in NOT_PRESENT or ENUMERATING.
+     */
+    for (auto& rejectStatus : rejectSourceStates) {
+        if (oldStatus == rejectStatus) {
+            ALOGV("%s: Rejecting status transition for Camera ID %s,  since the source "
+                    "state was was in one of the bad states.", __FUNCTION__, cameraId.string());
+            mStatus = oldStatus;
+            return;
+        }
+    }
+
+    onStatusUpdatedLocked(cameraId, status);
+}
+
 void CameraService::updateProxyDeviceState(ICameraServiceProxy::CameraState newState,
         const String8& cameraId) {
     sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
@@ -2777,7 +2961,7 @@
 
 status_t CameraService::getTorchStatusLocked(
         const String8& cameraId,
-        int32_t *status) const {
+        TorchModeStatus *status) const {
     if (!status) {
         return BAD_VALUE;
     }
@@ -2792,14 +2976,12 @@
 }
 
 status_t CameraService::setTorchStatusLocked(const String8& cameraId,
-        int32_t status) {
+        TorchModeStatus status) {
     ssize_t index = mTorchStatusMap.indexOfKey(cameraId);
     if (index == NAME_NOT_FOUND) {
         return BAD_VALUE;
     }
-    int32_t& item =
-            mTorchStatusMap.editValueAt(index);
-    item = status;
+    mTorchStatusMap.editValueAt(index) = status;
 
     return OK;
 }
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index b35f35c..a6c2fa8 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -29,6 +29,8 @@
 #include <camera/ICameraServiceProxy.h>
 #include <hardware/camera.h>
 
+#include <android/hardware/camera/common/1.0/types.h>
+
 #include <camera/VendorTagDescriptor.h>
 #include <camera/CaptureResult.h>
 #include <camera/CameraParameters.h>
@@ -95,10 +97,10 @@
 
     /////////////////////////////////////////////////////////////////////
     // HAL Callbacks
-    virtual void        onDeviceStatusChanged(int cameraId,
-                                              camera_device_status_t newStatus);
+    virtual void        onDeviceStatusChanged(const String8 &cameraId,
+            hardware::camera::common::V1_0::CameraDeviceStatus newHalStatus);
     virtual void        onTorchStatusChanged(const String8& cameraId,
-                                             int32_t newStatus);
+            hardware::camera::common::V1_0::TorchModeStatus newStatus);
 
     /////////////////////////////////////////////////////////////////////
     // ICameraService
@@ -106,7 +108,7 @@
 
     virtual binder::Status     getCameraInfo(int cameraId,
             hardware::CameraInfo* cameraInfo);
-    virtual binder::Status     getCameraCharacteristics(int cameraId,
+    virtual binder::Status     getCameraCharacteristics(const String16& id,
             CameraMetadata* cameraInfo);
     virtual binder::Status     getCameraVendorTagDescriptor(
             /*out*/
@@ -125,12 +127,14 @@
             sp<hardware::ICamera>* device);
 
     virtual binder::Status     connectDevice(
-            const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb, int32_t cameraId,
+            const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb, const String16& cameraId,
             const String16& clientPackageName, int32_t clientUid,
             /*out*/
             sp<hardware::camera2::ICameraDeviceUser>* device);
 
-    virtual binder::Status    addListener(const sp<hardware::ICameraServiceListener>& listener);
+    virtual binder::Status    addListener(const sp<hardware::ICameraServiceListener>& listener,
+            /*out*/
+            std::vector<hardware::CameraStatus>* cameraStatuses);
     virtual binder::Status    removeListener(
             const sp<hardware::ICameraServiceListener>& listener);
 
@@ -147,7 +151,7 @@
 
     // OK = supports api of that version, -EOPNOTSUPP = does not support
     virtual binder::Status    supportsCameraApi(
-            int32_t cameraId, int32_t apiVersion,
+            const String16& cameraId, int32_t apiVersion,
             /*out*/
             bool *isSupported);
 
@@ -409,6 +413,20 @@
 
 private:
 
+    typedef hardware::camera::common::V1_0::CameraDeviceStatus CameraDeviceStatus;
+
+    /**
+     * Typesafe version of device status, containing both the HAL-layer and the service interface-
+     * layer values.
+     */
+    enum class StatusInternal : int32_t {
+        NOT_PRESENT = static_cast<int32_t>(CameraDeviceStatus::NOT_PRESENT),
+        PRESENT = static_cast<int32_t>(CameraDeviceStatus::PRESENT),
+        ENUMERATING = static_cast<int32_t>(CameraDeviceStatus::ENUMERATING),
+        NOT_AVAILABLE = static_cast<int32_t>(hardware::ICameraServiceListener::STATUS_NOT_AVAILABLE),
+        UNKNOWN = static_cast<int32_t>(hardware::ICameraServiceListener::STATUS_UNKNOWN)
+    };
+
     /**
      * Container class for the state of each logical camera device, including: ID, status, and
      * dependencies on other devices.  The mapping of camera ID -> state saved in mCameraStates
@@ -432,7 +450,7 @@
          *
          * This method acquires mStatusLock.
          */
-        int32_t getStatus() const;
+        StatusInternal getStatus() const;
 
         /**
          * This function updates the status for this camera device, unless the given status
@@ -445,8 +463,9 @@
          * This method aquires mStatusLock.
          */
         template<class Func>
-        void updateStatus(int32_t status, const String8& cameraId,
-                std::initializer_list<int32_t> rejectSourceStates,
+        void updateStatus(StatusInternal status,
+                const String8& cameraId,
+                std::initializer_list<StatusInternal> rejectSourceStates,
                 Func onStatusUpdatedLocked);
 
         /**
@@ -477,7 +496,7 @@
 
     private:
         const String8 mId;
-        int32_t mStatus; // protected by mStatusLock
+        StatusInternal mStatus; // protected by mStatusLock
         const int mCost;
         std::set<String8> mConflicting;
         mutable Mutex mStatusLock;
@@ -671,9 +690,12 @@
      * This method must be idempotent.
      * This method acquires mStatusLock and mStatusListenerLock.
      */
-    void updateStatus(int32_t status, const String8& cameraId,
-            std::initializer_list<int32_t> rejectedSourceStates);
-    void updateStatus(int32_t status, const String8& cameraId);
+    void updateStatus(StatusInternal status,
+            const String8& cameraId,
+            std::initializer_list<StatusInternal>
+                rejectedSourceStates);
+    void updateStatus(StatusInternal status,
+            const String8& cameraId);
 
     // flashlight control
     sp<CameraFlashlight> mFlashlight;
@@ -684,7 +706,8 @@
     // guard mTorchUidMap
     Mutex                mTorchUidMapMutex;
     // camera id -> torch status
-    KeyedVector<String8, int32_t> mTorchStatusMap;
+    KeyedVector<String8, hardware::camera::common::V1_0::TorchModeStatus>
+            mTorchStatusMap;
     // camera id -> torch client binder
     // only store the last client that turns on each camera's torch mode
     KeyedVector<String8, sp<IBinder>> mTorchClientMap;
@@ -697,15 +720,15 @@
     // handle torch mode status change and invoke callbacks. mTorchStatusMutex
     // should be locked.
     void onTorchStatusChangedLocked(const String8& cameraId,
-            int32_t newStatus);
+            hardware::camera::common::V1_0::TorchModeStatus newStatus);
 
     // get a camera's torch status. mTorchStatusMutex should be locked.
     status_t getTorchStatusLocked(const String8 &cameraId,
-            int32_t *status) const;
+             hardware::camera::common::V1_0::TorchModeStatus *status) const;
 
     // set a camera's torch status. mTorchStatusMutex should be locked.
     status_t setTorchStatusLocked(const String8 &cameraId,
-            int32_t status);
+            hardware::camera::common::V1_0::TorchModeStatus status);
 
     // IBinder::DeathRecipient implementation
     virtual void        binderDied(const wp<IBinder> &who);
@@ -729,14 +752,6 @@
      */
     binder::Status      getLegacyParametersLazy(int cameraId, /*out*/CameraParameters* parameters);
 
-    /**
-     * Generate the CameraCharacteristics metadata required by the Camera2 API
-     * from the available HAL1 CameraParameters and CameraInfo.
-     *
-     * Sets Status to a service-specific error on failure
-     */
-    binder::Status      generateShimMetadata(int cameraId, /*out*/CameraMetadata* cameraInfo);
-
     static int getCallingPid();
 
     static int getCallingUid();
@@ -760,227 +775,15 @@
     status_t checkCameraAccess(const String16& opPackageName);
 
     static String8 toString(std::set<userid_t> intSet);
+    static int32_t mapToInterface(hardware::camera::common::V1_0::TorchModeStatus status);
+    static StatusInternal mapToInternal(hardware::camera::common::V1_0::CameraDeviceStatus status);
+    static int32_t mapToInterface(StatusInternal status);
 
     static sp<ICameraServiceProxy> getCameraServiceProxy();
     static void pingCameraServiceProxy();
 
 };
 
-template<class Func>
-void CameraService::CameraState::updateStatus(int32_t status,
-        const String8& cameraId,
-        std::initializer_list<int32_t> rejectSourceStates,
-        Func onStatusUpdatedLocked) {
-    Mutex::Autolock lock(mStatusLock);
-    int32_t oldStatus = mStatus;
-    mStatus = status;
-
-    if (oldStatus == status) {
-        return;
-    }
-
-    ALOGV("%s: Status has changed for camera ID %s from %#x to %#x", __FUNCTION__,
-            cameraId.string(), oldStatus, status);
-
-    if (oldStatus == hardware::ICameraServiceListener::STATUS_NOT_PRESENT &&
-            (status != hardware::ICameraServiceListener::STATUS_PRESENT &&
-             status != hardware::ICameraServiceListener::STATUS_ENUMERATING)) {
-
-        ALOGW("%s: From NOT_PRESENT can only transition into PRESENT or ENUMERATING",
-                __FUNCTION__);
-        mStatus = oldStatus;
-        return;
-    }
-
-    /**
-     * Sometimes we want to conditionally do a transition.
-     * For example if a client disconnects, we want to go to PRESENT
-     * only if we weren't already in NOT_PRESENT or ENUMERATING.
-     */
-    for (auto& rejectStatus : rejectSourceStates) {
-        if (oldStatus == rejectStatus) {
-            ALOGV("%s: Rejecting status transition for Camera ID %s,  since the source "
-                    "state was was in one of the bad states.", __FUNCTION__, cameraId.string());
-            mStatus = oldStatus;
-            return;
-        }
-    }
-
-    onStatusUpdatedLocked(cameraId, status);
-}
-
-#define STATUS_ERROR(errorCode, errorString) \
-    binder::Status::fromServiceSpecificError(errorCode, \
-            String8::format("%s:%d: %s", __FUNCTION__, __LINE__, errorString))
-
-#define STATUS_ERROR_FMT(errorCode, errorString, ...) \
-    binder::Status::fromServiceSpecificError(errorCode, \
-            String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, __VA_ARGS__))
-
-
-template<class CALLBACK, class CLIENT>
-binder::Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
-        int halVersion, const String16& clientPackageName, int clientUid, int clientPid,
-        apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
-        /*out*/sp<CLIENT>& device) {
-    binder::Status ret = binder::Status::ok();
-
-    String8 clientName8(clientPackageName);
-
-    int originalClientPid = 0;
-
-    ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) for HAL version %s and "
-            "Camera API version %d", clientPid, clientName8.string(), cameraId.string(),
-            (halVersion == -1) ? "default" : std::to_string(halVersion).c_str(),
-            static_cast<int>(effectiveApiLevel));
-
-    sp<CLIENT> client = nullptr;
-    {
-        // Acquire mServiceLock and prevent other clients from connecting
-        std::unique_ptr<AutoConditionLock> lock =
-                AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);
-
-        if (lock == nullptr) {
-            ALOGE("CameraService::connect (PID %d) rejected (too many other clients connecting)."
-                    , clientPid);
-            return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
-                    "Cannot open camera %s for \"%s\" (PID %d): Too many other clients connecting",
-                    cameraId.string(), clientName8.string(), clientPid);
-        }
-
-        // Enforce client permissions and do basic sanity checks
-        if(!(ret = validateConnectLocked(cameraId, clientName8,
-                /*inout*/clientUid, /*inout*/clientPid, /*out*/originalClientPid)).isOk()) {
-            return ret;
-        }
-
-        // Check the shim parameters after acquiring lock, if they have already been updated and
-        // we were doing a shim update, return immediately
-        if (shimUpdateOnly) {
-            auto cameraState = getCameraState(cameraId);
-            if (cameraState != nullptr) {
-                if (!cameraState->getShimParams().isEmpty()) return ret;
-            }
-        }
-
-        status_t err;
-
-        sp<BasicClient> clientTmp = nullptr;
-        std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;
-        if ((err = handleEvictionsLocked(cameraId, originalClientPid, effectiveApiLevel,
-                IInterface::asBinder(cameraCb), clientName8, /*out*/&clientTmp,
-                /*out*/&partial)) != NO_ERROR) {
-            switch (err) {
-                case -ENODEV:
-                    return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
-                            "No camera device with ID \"%s\" currently available",
-                            cameraId.string());
-                case -EBUSY:
-                    return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
-                            "Higher-priority client using camera, ID \"%s\" currently unavailable",
-                            cameraId.string());
-                default:
-                    return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
-                            "Unexpected error %s (%d) opening camera \"%s\"",
-                            strerror(-err), err, cameraId.string());
-            }
-        }
-
-        if (clientTmp.get() != nullptr) {
-            // Handle special case for API1 MediaRecorder where the existing client is returned
-            device = static_cast<CLIENT*>(clientTmp.get());
-            return ret;
-        }
-
-        // give flashlight a chance to close devices if necessary.
-        mFlashlight->prepareDeviceOpen(cameraId);
-
-        // TODO: Update getDeviceVersion + HAL interface to use strings for Camera IDs
-        int id = cameraIdToInt(cameraId);
-        if (id == -1) {
-            ALOGE("%s: Invalid camera ID %s, cannot get device version from HAL.", __FUNCTION__,
-                    cameraId.string());
-            return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
-                    "Bad camera ID \"%s\" passed to camera open", cameraId.string());
-        }
-
-        int facing = -1;
-        int deviceVersion = getDeviceVersion(id, /*out*/&facing);
-        sp<BasicClient> tmp = nullptr;
-        if(!(ret = makeClient(this, cameraCb, clientPackageName, id, facing, clientPid,
-                clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel,
-                /*out*/&tmp)).isOk()) {
-            return ret;
-        }
-        client = static_cast<CLIENT*>(tmp.get());
-
-        LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
-                __FUNCTION__);
-
-        if ((err = client->initialize(mModule)) != OK) {
-            ALOGE("%s: Could not initialize client from HAL module.", __FUNCTION__);
-            // Errors could be from the HAL module open call or from AppOpsManager
-            switch(err) {
-                case BAD_VALUE:
-                    return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
-                            "Illegal argument to HAL module for camera \"%s\"", cameraId.string());
-                case -EBUSY:
-                    return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
-                            "Camera \"%s\" is already open", cameraId.string());
-                case -EUSERS:
-                    return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
-                            "Too many cameras already open, cannot open camera \"%s\"",
-                            cameraId.string());
-                case PERMISSION_DENIED:
-                    return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
-                            "No permission to open camera \"%s\"", cameraId.string());
-                case -EACCES:
-                    return STATUS_ERROR_FMT(ERROR_DISABLED,
-                            "Camera \"%s\" disabled by policy", cameraId.string());
-                case -ENODEV:
-                default:
-                    return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
-                            "Failed to initialize camera \"%s\": %s (%d)", cameraId.string(),
-                            strerror(-err), err);
-            }
-        }
-
-        // Update shim paremeters for legacy clients
-        if (effectiveApiLevel == API_1) {
-            // Assume we have always received a Client subclass for API1
-            sp<Client> shimClient = reinterpret_cast<Client*>(client.get());
-            String8 rawParams = shimClient->getParameters();
-            CameraParameters params(rawParams);
-
-            auto cameraState = getCameraState(cameraId);
-            if (cameraState != nullptr) {
-                cameraState->setShimParams(params);
-            } else {
-                ALOGE("%s: Cannot update shim parameters for camera %s, no such device exists.",
-                        __FUNCTION__, cameraId.string());
-            }
-        }
-
-        if (shimUpdateOnly) {
-            // If only updating legacy shim parameters, immediately disconnect client
-            mServiceLock.unlock();
-            client->disconnect();
-            mServiceLock.lock();
-        } else {
-            // Otherwise, add client to active clients list
-            finishConnectLocked(client, partial);
-        }
-    } // lock is destroyed, allow further connect calls
-
-    // Important: release the mutex here so the client can call back into the service from its
-    // destructor (can be at the end of the call)
-    device = client;
-    return ret;
-}
-
-#undef STATUS_ERROR_FMT
-#undef STATUS_ERROR
-
 } // namespace android
 
 #endif
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm64.policy b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm64.policy
index ae6ac05..7e7b858 100644
--- a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm64.policy
+++ b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm64.policy
@@ -28,6 +28,8 @@
 getrlimit: 1
 
 # for attaching to debuggerd on process crash
+tgkill: 1
+rt_sigprocmask: 1
 rt_sigaction: 1
 # socket: arg0 == AF_LOCAL
 socket: arg0 == 1
diff --git a/services/radio/RadioHalHidl.cpp b/services/radio/RadioHalHidl.cpp
index 07cb4d5..c7a899a 100644
--- a/services/radio/RadioHalHidl.cpp
+++ b/services/radio/RadioHalHidl.cpp
@@ -39,6 +39,11 @@
     return new RadioHalHidl(classId);
 }
 
+void RadioHalHidl::crashIfHalIsDead(const Status& status) {
+    LOG_ALWAYS_FATAL_IF(
+            status.transactionError() == DEAD_OBJECT, "HAL server crashed, need to restart");
+}
+
 int RadioHalHidl::getProperties(radio_hal_properties_t *properties)
 {
     ALOGV("%s IN", __FUNCTION__);
@@ -56,10 +61,7 @@
                     }
                 });
 
-    if (hidlReturn.getStatus().transactionError() == DEAD_OBJECT) {
-        clearService();
-        return -EPIPE;
-    }
+    crashIfHalIsDead(hidlReturn.getStatus());
     if (halResult == Result::OK) {
         HidlUtils::convertPropertiesFromHal(properties, &halProperties);
     }
@@ -91,10 +93,7 @@
                     }
                 });
 
-    if (hidlReturn.getStatus().transactionError() == DEAD_OBJECT) {
-        clearService();
-        return -EPIPE;
-    }
+    crashIfHalIsDead(hidlReturn.getStatus());
     if (halResult == Result::OK) {
         tunerImpl->setHalTuner(halTuner);
         tuner = tunerImpl;
@@ -375,6 +374,7 @@
     if (status == DEAD_OBJECT) {
         handleHwFailure();
     }
+    RadioHalHidl::crashIfHalIsDead(hidlStatus);
     return status;
 }
 
diff --git a/services/radio/RadioHalHidl.h b/services/radio/RadioHalHidl.h
index 5211ee2..1657a40 100644
--- a/services/radio/RadioHalHidl.h
+++ b/services/radio/RadioHalHidl.h
@@ -45,6 +45,8 @@
 public:
                     RadioHalHidl(radio_class_t classId);
 
+        static void crashIfHalIsDead(const Status& status);
+
                     // RadioInterface
         virtual int getProperties(radio_hal_properties_t *properties);
         virtual int openTuner(const radio_hal_band_config_t *config,
diff --git a/services/soundtrigger/SoundTriggerHalHidl.cpp b/services/soundtrigger/SoundTriggerHalHidl.cpp
index ecbdec4..c027799 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.cpp
+++ b/services/soundtrigger/SoundTriggerHalHidl.cpp
@@ -59,9 +59,7 @@
         }
     } else {
         ret = (int)hidlReturn.getStatus().transactionError();
-        if (ret == -EPIPE) {
-            clearService();
-        }
+        crashIfHalIsDead(ret);
     }
     ALOGI("getProperties ret %d", ret);
     return ret;
@@ -135,9 +133,7 @@
     } else {
         ret = (int)hidlReturn.getStatus().transactionError();
         ALOGE("loadSoundModel error %d", ret);
-        if (ret == -EPIPE) {
-            clearService();
-        }
+        crashIfHalIsDead(ret);
     }
 
 
@@ -164,9 +160,7 @@
     }
     int ret = (int)hidlReturn.getStatus().transactionError();
     ALOGE_IF(ret != 0, "unloadSoundModel error %d", ret);
-    if (ret == -EPIPE) {
-        clearService();
-    }
+    crashIfHalIsDead(ret);
     if (ret == 0) {
         ret = hidlReturn;
     }
@@ -205,9 +199,7 @@
 
     int ret = (int)hidlReturn.getStatus().transactionError();
     ALOGE_IF(ret != 0, "startRecognition error %d", ret);
-    if (ret == -EPIPE) {
-        clearService();
-    }
+    crashIfHalIsDead(ret);
     if (ret == 0) {
         ret = hidlReturn;
     }
@@ -235,9 +227,7 @@
 
     int ret = (int)hidlReturn.getStatus().transactionError();
     ALOGE_IF(ret != 0, "stopRecognition error %d", ret);
-    if (ret == -EPIPE) {
-        clearService();
-    }
+    crashIfHalIsDead(ret);
     if (ret == 0) {
         ret = hidlReturn;
     }
@@ -259,9 +249,7 @@
 
     int ret = (int)hidlReturn.getStatus().transactionError();
     ALOGE_IF(ret != 0, "stopAllRecognitions error %d", ret);
-    if (ret == -EPIPE) {
-        clearService();
-    }
+    crashIfHalIsDead(ret);
     if (ret == 0) {
         ret = hidlReturn;
     }
@@ -291,10 +279,9 @@
     return mISoundTrigger;
 }
 
-void SoundTriggerHalHidl::clearService()
+void SoundTriggerHalHidl::crashIfHalIsDead(int ret)
 {
-    AutoMutex lock(mLock);
-    mISoundTrigger = 0;
+    LOG_ALWAYS_FATAL_IF(ret == -EPIPE, "HAL server crashed, need to restart");
 }
 
 sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::getModel(sound_model_handle_t handle)
diff --git a/services/soundtrigger/SoundTriggerHalHidl.h b/services/soundtrigger/SoundTriggerHalHidl.h
index e578dda..b235e1c 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.h
+++ b/services/soundtrigger/SoundTriggerHalHidl.h
@@ -143,7 +143,7 @@
 
         uint32_t nextUniqueId();
         sp<ISoundTriggerHw> getService();
-        void clearService();
+        void crashIfHalIsDead(int ret);
         sp<SoundModel> getModel(sound_model_handle_t handle);
         sp<SoundModel> removeModel(sound_model_handle_t handle);