Merge "AudioFlinger: Associate audio time with client uid"
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/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/AudioRecord.h b/include/media/AudioRecord.h
index f7eb397..1c8746f 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -650,6 +650,8 @@
     //  a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing.
     audio_port_handle_t    mSelectedDeviceId;
     sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+    audio_port_handle_t    mPortId;  // unique ID allocated by audio policy
+
 };
 
 }; // namespace android
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 0533ba6..0e9960f 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -217,12 +217,10 @@
                                      audio_session_t session,
                                      audio_stream_type_t *stream,
                                      uid_t uid,
-                                     uint32_t samplingRate = 0,
-                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                     audio_channel_mask_t channelMask = AUDIO_CHANNEL_OUT_STEREO,
-                                     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
-                                     audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
-                                     const audio_offload_info_t *offloadInfo = NULL);
+                                     const audio_config_t *config,
+                                     audio_output_flags_t flags,
+                                     audio_port_handle_t selectedDeviceId,
+                                     audio_port_handle_t *portId);
     static status_t startOutput(audio_io_handle_t output,
                                 audio_stream_type_t stream,
                                 audio_session_t session);
@@ -240,11 +238,10 @@
                                     audio_session_t session,
                                     pid_t pid,
                                     uid_t uid,
-                                    uint32_t samplingRate,
-                                    audio_format_t format,
-                                    audio_channel_mask_t channelMask,
+                                    const audio_config_base_t *config,
                                     audio_input_flags_t flags,
-                                    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
+                                    audio_port_handle_t selectedDeviceId,
+                                    audio_port_handle_t *portId);
 
     static status_t startInput(audio_io_handle_t input,
                                audio_session_t session);
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 7c5686a..cd33a44 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -1134,6 +1134,7 @@
     pid_t                   mClientPid;
 
     sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+    audio_port_handle_t     mPortId;  // unique ID allocated by audio policy
 };
 
 }; // namespace android
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 8feb8c5..8c5e61a 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -66,7 +66,8 @@
                                 pid_t tid,  // -1 means unused, otherwise must be valid non-0
                                 audio_session_t *sessionId,
                                 int clientUid,
-                                status_t *status) = 0;
+                                status_t *status,
+                                audio_port_handle_t portId) = 0;
 
     virtual sp<IAudioRecord> openRecord(
                                 // On successful return, AudioFlinger takes over the handle
@@ -86,7 +87,8 @@
                                 size_t *notificationFrames,
                                 sp<IMemory>& cblk,
                                 sp<IMemory>& buffers,   // return value 0 means it follows cblk
-                                status_t *status) = 0;
+                                status_t *status,
+                                audio_port_handle_t portId) = 0;
 
     // FIXME Surprisingly, format/latency don't work for input handles
 
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 5637dd5..e8db4b1 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -63,12 +63,10 @@
                                       audio_session_t session,
                                       audio_stream_type_t *stream,
                                       uid_t uid,
-                                      uint32_t samplingRate = 0,
-                                      audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                      audio_channel_mask_t channelMask = 0,
-                                      audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
-                                      audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
-                                      const audio_offload_info_t *offloadInfo = NULL) = 0;
+                                      const audio_config_t *config,
+                                      audio_output_flags_t flags,
+                                      audio_port_handle_t selectedDeviceId,
+                                      audio_port_handle_t *portId) = 0;
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
                                  audio_session_t session) = 0;
@@ -83,11 +81,10 @@
                               audio_session_t session,
                               pid_t pid,
                               uid_t uid,
-                              uint32_t samplingRate,
-                              audio_format_t format,
-                              audio_channel_mask_t channelMask,
+                              const audio_config_base_t *config,
                               audio_input_flags_t flags,
-                              audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE) = 0;
+                              audio_port_handle_t selectedDeviceId,
+                              audio_port_handle_t *portId) = 0;
     virtual status_t startInput(audio_io_handle_t input,
                                 audio_session_t session) = 0;
     virtual status_t stopInput(audio_io_handle_t input,
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/OMXBuffer.h b/include/media/OMXBuffer.h
index 89b709c..aeb1765 100644
--- a/include/media/OMXBuffer.h
+++ b/include/media/OMXBuffer.h
@@ -24,12 +24,27 @@
 
 namespace android {
 
+class OMXBuffer;
+
+// This is needed temporarily for the OMX HIDL transition.
+namespace hardware { namespace media { namespace omx {
+namespace V1_0 {
+    struct CodecBuffer;
+namespace implementation {
+    inline bool wrapAs(::android::hardware::media::omx::V1_0::CodecBuffer* t,
+            ::android::OMXBuffer const& l);
+    inline bool convertTo(::android::OMXBuffer* l,
+            ::android::hardware::media::omx::V1_0::CodecBuffer const& t);
+}}}}}
+
 class GraphicBuffer;
 class IMemory;
 class MediaCodecBuffer;
 class NativeHandle;
-class OMXNodeInstance;
+struct OMXNodeInstance;
 
+// TODO: After complete HIDL transition, this class would be replaced by
+// CodecBuffer.
 class OMXBuffer {
 public:
     // sPreset is used in places where we are referring to a pre-registered
@@ -43,6 +58,10 @@
     // |codecBuffer|'s size (or 0 if |codecBuffer| is NULL).
     OMXBuffer(const sp<MediaCodecBuffer> &codecBuffer);
 
+    // Constructs a buffer of type kBufferTypePreset with a specified
+    // mRangeLength.
+    explicit OMXBuffer(OMX_U32 rangeLength);
+
     // Constructs a buffer of type kBufferTypeSharedMem.
     OMXBuffer(const sp<IMemory> &mem);
 
@@ -59,7 +78,15 @@
     ~OMXBuffer();
 
 private:
-    friend class OMXNodeInstance;
+    friend struct OMXNodeInstance;
+
+    // This is needed temporarily for OMX HIDL transition.
+    friend inline bool (::android::hardware::media::omx::V1_0::implementation::
+            wrapAs)(::android::hardware::media::omx::V1_0::CodecBuffer* t,
+            OMXBuffer const& l);
+    friend inline bool (::android::hardware::media::omx::V1_0::implementation::
+            convertTo)(OMXBuffer* l,
+            ::android::hardware::media::omx::V1_0::CodecBuffer const& t);
 
     enum BufferType {
         kBufferTypeInvalid = 0,
@@ -85,8 +112,12 @@
     // kBufferTypeNativeHandle
     sp<NativeHandle> mNativeHandle;
 
-    OMXBuffer(const OMXBuffer &);
-    OMXBuffer &operator=(const OMXBuffer &);
+    // Move assignment
+    OMXBuffer &operator=(OMXBuffer&&);
+
+    // Deleted copy constructor and assignment.
+    OMXBuffer(const OMXBuffer&) = delete;
+    OMXBuffer& operator=(const OMXBuffer&) = delete;
 };
 
 }  // namespace android
diff --git a/include/media/OMXFenceParcelable.h b/include/media/OMXFenceParcelable.h
index c9da301..f529301 100644
--- a/include/media/OMXFenceParcelable.h
+++ b/include/media/OMXFenceParcelable.h
@@ -21,6 +21,18 @@
 
 namespace android {
 
+struct OMXFenceParcelable;
+
+// This is needed temporarily for the OMX HIDL transition.
+namespace hardware {
+    struct hidl_handle;
+namespace media { namespace omx { namespace V1_0 { namespace implementation {
+    void wrapAs(::android::OMXFenceParcelable* l,
+            ::android::hardware::hidl_handle const& t);
+    bool convertTo(::android::OMXFenceParcelable* l,
+            ::android::hardware::hidl_handle const& t);
+}}}}}
+
 struct OMXFenceParcelable : public Parcelable {
     OMXFenceParcelable() : mFenceFd(-1) {}
     OMXFenceParcelable(int fenceFd) : mFenceFd(fenceFd) {}
@@ -36,6 +48,14 @@
     OMXFenceParcelable &operator=(const OMXFenceParcelable &);
 
     int mFenceFd;
+
+    // This is needed temporarily for OMX HIDL transition.
+    friend void (::android::hardware::media::omx::V1_0::implementation::
+            wrapAs)(OMXFenceParcelable* l,
+            ::android::hardware::hidl_handle const& t);
+    friend bool (::android::hardware::media::omx::V1_0::implementation::
+            convertTo)(OMXFenceParcelable* l,
+            ::android::hardware::hidl_handle const& t);
 };
 
 inline status_t OMXFenceParcelable::readFromParcel(const Parcel* parcel) {
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 4de1521..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,10 +59,10 @@
     virtual uint32_t flags() const;
 
     // for DRM
-    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/audioserver/Android.mk b/media/audioserver/Android.mk
index c620e7c..7dc4e1d 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -14,7 +14,8 @@
 	libmedialogservice \
 	libradioservice \
 	libsoundtriggerservice \
-	libutils
+	libutils \
+	libhwbinder
 
 LOCAL_C_INCLUDES := \
 	frameworks/av/services/audioflinger \
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
index 4a7a988..bcd0342 100644
--- a/media/audioserver/main_audioserver.cpp
+++ b/media/audioserver/main_audioserver.cpp
@@ -27,6 +27,10 @@
 #include <binder/IServiceManager.h>
 #include <utils/Log.h>
 
+// FIXME: remove when BUG 31748996 is fixed
+#include <hwbinder/IPCThreadState.h>
+#include <hwbinder/ProcessState.h>
+
 // from LOCAL_C_INCLUDES
 #include "AudioFlinger.h"
 #include "AudioPolicyService.h"
@@ -130,6 +134,10 @@
         RadioService::instantiate();
         SoundTriggerHwService::instantiate();
         ProcessState::self()->startThreadPool();
+
+// FIXME: remove when BUG 31748996 is fixed
+        android::hardware::ProcessState::self()->startThreadPool();
+
         IPCThreadState::self()->joinThreadPool();
     }
 }
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 778540c..4c1fbd7 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -68,7 +68,7 @@
 AudioRecord::AudioRecord(const String16 &opPackageName)
     : mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName), mSessionId(AUDIO_SESSION_ALLOCATE),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mPortId(AUDIO_PORT_HANDLE_NONE)
 {
 }
 
@@ -95,7 +95,8 @@
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mProxy(NULL),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mPortId(AUDIO_PORT_HANDLE_NONE)
 {
     mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
             notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
@@ -529,14 +530,18 @@
     // The sp<> references will be dropped when re-entering scope.
     // The lack of indentation is deliberate, to reduce code churn and ease merges.
     for (;;) {
-
+    audio_config_base_t config  = {
+            .sample_rate = mSampleRate,
+            .channel_mask = mChannelMask,
+            .format = mFormat
+        };
     status = AudioSystem::getInputForAttr(&mAttributes, &input,
                                         mSessionId,
                                         // FIXME compare to AudioTrack
                                         mClientPid,
                                         mClientUid,
-                                        mSampleRate, mFormat, mChannelMask,
-                                        mFlags, mSelectedDeviceId);
+                                        &config,
+                                        mFlags, mSelectedDeviceId, &mPortId);
 
     if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE) {
         ALOGE("Could not get audio input for session %d, record source %d, sample rate %u, "
@@ -622,7 +627,8 @@
                                                        &notificationFrames,
                                                        iMem,
                                                        bufferMem,
-                                                       &status);
+                                                       &status,
+                                                       mPortId);
     ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId,
             "session ID changed from %d to %d", originalSessionId, mSessionId);
 
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index d45b12f..f7ba757 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -792,18 +792,16 @@
                                         audio_session_t session,
                                         audio_stream_type_t *stream,
                                         uid_t uid,
-                                        uint32_t samplingRate,
-                                        audio_format_t format,
-                                        audio_channel_mask_t channelMask,
+                                        const audio_config_t *config,
                                         audio_output_flags_t flags,
                                         audio_port_handle_t selectedDeviceId,
-                                        const audio_offload_info_t *offloadInfo)
+                                        audio_port_handle_t *portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return NO_INIT;
     return aps->getOutputForAttr(attr, output, session, stream, uid,
-                                 samplingRate, format, channelMask,
-                                 flags, selectedDeviceId, offloadInfo);
+                                 config,
+                                 flags, selectedDeviceId, portId);
 }
 
 status_t AudioSystem::startOutput(audio_io_handle_t output,
@@ -838,17 +836,16 @@
                                 audio_session_t session,
                                 pid_t pid,
                                 uid_t uid,
-                                uint32_t samplingRate,
-                                audio_format_t format,
-                                audio_channel_mask_t channelMask,
+                                const audio_config_base_t *config,
                                 audio_input_flags_t flags,
-                                audio_port_handle_t selectedDeviceId)
+                                audio_port_handle_t selectedDeviceId,
+                                audio_port_handle_t *portId)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return NO_INIT;
     return aps->getInputForAttr(
             attr, input, session, pid, uid,
-            samplingRate, format, channelMask, flags, selectedDeviceId);
+            config, flags, selectedDeviceId, portId);
 }
 
 status_t AudioSystem::startInput(audio_io_handle_t input,
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index aef7dfb..f9ab208 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -183,7 +183,8 @@
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mPortId(AUDIO_PORT_HANDLE_NONE)
 {
     mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
     mAttributes.usage = AUDIO_USAGE_UNKNOWN;
@@ -214,7 +215,8 @@
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mPortId(AUDIO_PORT_HANDLE_NONE)
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
@@ -245,7 +247,8 @@
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mPortId(AUDIO_PORT_HANDLE_NONE)
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             0 /*frameCount*/, flags, cbf, user, notificationFrames,
@@ -452,6 +455,7 @@
         mOffloadInfo = &mOffloadInfoCopy;
     } else {
         mOffloadInfo = NULL;
+        memset(&mOffloadInfoCopy, 0, sizeof(audio_offload_info_t));
     }
 
     mVolume[AUDIO_INTERLEAVE_LEFT] = 1.0f;
@@ -1255,10 +1259,15 @@
     // After fast request is denied, we will request again if IAudioTrack is re-created.
 
     status_t status;
+    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+    config.sample_rate = mSampleRate;
+    config.channel_mask = mChannelMask;
+    config.format = mFormat;
+    config.offload_info = mOffloadInfoCopy;
     status = AudioSystem::getOutputForAttr(attr, &output,
                                            mSessionId, &streamType, mClientUid,
-                                           mSampleRate, mFormat, mChannelMask,
-                                           mFlags, mSelectedDeviceId, mOffloadInfo);
+                                           &config,
+                                           mFlags, mSelectedDeviceId, &mPortId);
 
     if (status != NO_ERROR || output == AUDIO_IO_HANDLE_NONE) {
         ALOGE("Could not get audio output for session %d, stream type %d, usage %d, sample rate %u, format %#x,"
@@ -1416,7 +1425,8 @@
                                                       tid,
                                                       &mSessionId,
                                                       mClientUid,
-                                                      &status);
+                                                      &status,
+                                                      mPortId);
     ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId,
             "session ID changed from %d to %d", originalSessionId, mSessionId);
 
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 31a18a4..255e350 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -108,7 +108,8 @@
                                 pid_t tid,
                                 audio_session_t *sessionId,
                                 int clientUid,
-                                status_t *status)
+                                status_t *status,
+                                audio_port_handle_t portId)
     {
         Parcel data, reply;
         sp<IAudioTrack> track;
@@ -137,6 +138,7 @@
         }
         data.writeInt32(lSessionId);
         data.writeInt32(clientUid);
+        data.writeInt32(portId);
         status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
         if (lStatus != NO_ERROR) {
             ALOGE("createTrack error: %s", strerror(-lStatus));
@@ -188,7 +190,8 @@
                                 size_t *notificationFrames,
                                 sp<IMemory>& cblk,
                                 sp<IMemory>& buffers,
-                                status_t *status)
+                                status_t *status,
+                                audio_port_handle_t portId)
     {
         Parcel data, reply;
         sp<IAudioRecord> record;
@@ -211,6 +214,7 @@
         }
         data.writeInt32(lSessionId);
         data.writeInt64(notificationFrames != NULL ? *notificationFrames : 0);
+        data.writeInt32(portId);
         cblk.clear();
         buffers.clear();
         status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply);
@@ -960,6 +964,7 @@
             pid_t tid = (pid_t) data.readInt32();
             audio_session_t sessionId = (audio_session_t) data.readInt32();
             int clientUid = data.readInt32();
+            audio_port_handle_t portId = (audio_port_handle_t) data.readInt32();
             status_t status = NO_ERROR;
             sp<IAudioTrack> track;
             if ((haveSharedBuffer && (buffer == 0)) ||
@@ -970,7 +975,7 @@
                 track = createTrack(
                         (audio_stream_type_t) streamType, sampleRate, format,
                         channelMask, &frameCount, &flags, buffer, output, pid, tid,
-                        &sessionId, clientUid, &status);
+                        &sessionId, clientUid, &status, portId);
                 LOG_ALWAYS_FATAL_IF((track != 0) != (status == NO_ERROR));
             }
             reply->writeInt64(frameCount);
@@ -994,13 +999,14 @@
             int clientUid = data.readInt32();
             audio_session_t sessionId = (audio_session_t) data.readInt32();
             size_t notificationFrames = data.readInt64();
+            audio_port_handle_t portId = (audio_port_handle_t) data.readInt32();
             sp<IMemory> cblk;
             sp<IMemory> buffers;
             status_t status = NO_ERROR;
             sp<IAudioRecord> record = openRecord(input,
                     sampleRate, format, channelMask, opPackageName, &frameCount, &flags,
                     pid, tid, clientUid, &sessionId, &notificationFrames, cblk, buffers,
-                    &status);
+                    &status, portId);
             LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR));
             reply->writeInt64(frameCount);
             reply->writeInt32(flags);
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 2fb2da6..bc5502e 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -175,12 +175,10 @@
                                         audio_session_t session,
                                         audio_stream_type_t *stream,
                                         uid_t uid,
-                                        uint32_t samplingRate,
-                                        audio_format_t format,
-                                        audio_channel_mask_t channelMask,
+                                        const audio_config_t *config,
                                         audio_output_flags_t flags,
                                         audio_port_handle_t selectedDeviceId,
-                                        const audio_offload_info_t *offloadInfo)
+                                        audio_port_handle_t *portId)
         {
             Parcel data, reply;
             data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
@@ -198,6 +196,10 @@
                 ALOGE("getOutputForAttr NULL output - shouldn't happen");
                 return BAD_VALUE;
             }
+            if (portId == NULL) {
+                ALOGE("getOutputForAttr NULL portId - shouldn't happen");
+                return BAD_VALUE;
+            }
             if (attr == NULL) {
                 data.writeInt32(0);
             } else {
@@ -212,18 +214,10 @@
                 data.writeInt32(*stream);
             }
             data.writeInt32(uid);
-            data.writeInt32(samplingRate);
-            data.writeInt32(static_cast <uint32_t>(format));
-            data.writeInt32(channelMask);
+            data.write(config, sizeof(audio_config_t));
             data.writeInt32(static_cast <uint32_t>(flags));
             data.writeInt32(selectedDeviceId);
-            // hasOffloadInfo
-            if (offloadInfo == NULL) {
-                data.writeInt32(0);
-            } else {
-                data.writeInt32(1);
-                data.write(offloadInfo, sizeof(audio_offload_info_t));
-            }
+            data.writeInt32(*portId);
             status_t status = remote()->transact(GET_OUTPUT_FOR_ATTR, data, &reply);
             if (status != NO_ERROR) {
                 return status;
@@ -233,9 +227,11 @@
                 return status;
             }
             *output = (audio_io_handle_t)reply.readInt32();
+            audio_stream_type_t lStream = (audio_stream_type_t)reply.readInt32();
             if (stream != NULL) {
-                *stream = (audio_stream_type_t)reply.readInt32();
+                *stream = lStream;
             }
+            *portId = (audio_port_handle_t)reply.readInt32();
             return status;
         }
 
@@ -282,11 +278,10 @@
                                      audio_session_t session,
                                      pid_t pid,
                                      uid_t uid,
-                                     uint32_t samplingRate,
-                                     audio_format_t format,
-                                     audio_channel_mask_t channelMask,
+                                     const audio_config_base_t *config,
                                      audio_input_flags_t flags,
-                                     audio_port_handle_t selectedDeviceId)
+                                     audio_port_handle_t selectedDeviceId,
+                                     audio_port_handle_t *portId)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
@@ -298,15 +293,18 @@
             ALOGE("getInputForAttr NULL input - shouldn't happen");
             return BAD_VALUE;
         }
+        if (portId == NULL) {
+            ALOGE("getInputForAttr NULL portId - shouldn't happen");
+            return BAD_VALUE;
+        }
         data.write(attr, sizeof(audio_attributes_t));
         data.writeInt32(session);
         data.writeInt32(pid);
         data.writeInt32(uid);
-        data.writeInt32(samplingRate);
-        data.writeInt32(static_cast <uint32_t>(format));
-        data.writeInt32(channelMask);
+        data.write(config, sizeof(audio_config_base_t));
         data.writeInt32(flags);
         data.writeInt32(selectedDeviceId);
+        data.writeInt32(*portId);
         status_t status = remote()->transact(GET_INPUT_FOR_ATTR, data, &reply);
         if (status != NO_ERROR) {
             return status;
@@ -316,6 +314,7 @@
             return status;
         }
         *input = (audio_io_handle_t)reply.readInt32();
+        *portId = (audio_port_handle_t)reply.readInt32();
         return NO_ERROR;
     }
 
@@ -901,25 +900,22 @@
                 stream = (audio_stream_type_t)data.readInt32();
             }
             uid_t uid = (uid_t)data.readInt32();
-            uint32_t samplingRate = data.readInt32();
-            audio_format_t format = (audio_format_t) data.readInt32();
-            audio_channel_mask_t channelMask = data.readInt32();
+            audio_config_t config;
+            memset(&config, 0, sizeof(audio_config_t));
+            data.read(&config, sizeof(audio_config_t));
             audio_output_flags_t flags =
                     static_cast <audio_output_flags_t>(data.readInt32());
             audio_port_handle_t selectedDeviceId = data.readInt32();
-            bool hasOffloadInfo = data.readInt32() != 0;
-            audio_offload_info_t offloadInfo;
-            if (hasOffloadInfo) {
-                data.read(&offloadInfo, sizeof(audio_offload_info_t));
-            }
+            audio_port_handle_t portId = (audio_port_handle_t)data.readInt32();
             audio_io_handle_t output = 0;
             status_t status = getOutputForAttr(hasAttributes ? &attr : NULL,
                     &output, session, &stream, uid,
-                    samplingRate, format, channelMask,
-                    flags, selectedDeviceId, hasOffloadInfo ? &offloadInfo : NULL);
+                    &config,
+                    flags, selectedDeviceId, &portId);
             reply->writeInt32(status);
             reply->writeInt32(output);
             reply->writeInt32(stream);
+            reply->writeInt32(portId);
             return NO_ERROR;
         } break;
 
@@ -963,18 +959,20 @@
             audio_session_t session = (audio_session_t)data.readInt32();
             pid_t pid = (pid_t)data.readInt32();
             uid_t uid = (uid_t)data.readInt32();
-            uint32_t samplingRate = data.readInt32();
-            audio_format_t format = (audio_format_t) data.readInt32();
-            audio_channel_mask_t channelMask = data.readInt32();
+            audio_config_base_t config;
+            memset(&config, 0, sizeof(audio_config_base_t));
+            data.read(&config, sizeof(audio_config_base_t));
             audio_input_flags_t flags = (audio_input_flags_t) data.readInt32();
             audio_port_handle_t selectedDeviceId = (audio_port_handle_t) data.readInt32();
+            audio_port_handle_t portId = (audio_port_handle_t)data.readInt32();
             audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
             status_t status = getInputForAttr(&attr, &input, session, pid, uid,
-                                              samplingRate, format, channelMask,
-                                              flags, selectedDeviceId);
+                                              &config,
+                                              flags, selectedDeviceId, &portId);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
                 reply->writeInt32(input);
+                reply->writeInt32(portId);
             }
             return NO_ERROR;
         } break;
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 7776313..0f4f092 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -200,11 +200,16 @@
     for (size_t i = 0; i < tracks.size(); i++) {
         const String8 desc = trackDescriptions.itemAt(i);
         str.appendFormat("    track {%s} ", desc.string());
-        const sp<IMediaSource> source = tracks.itemAt(i).promote();
-        if (source == NULL) {
-            str.append(": deleted\n");
+        wp<IMediaSource> wSource = tracks.itemAt(i);
+        if (wSource == NULL) {
+            str.append(": null\n");
         } else {
-            str.appendFormat(": active\n");
+            const sp<IMediaSource> source = wSource.promote();
+            if (source == NULL) {
+                str.append(": deleted\n");
+            } else {
+                str.appendFormat(": active\n");
+            }
         }
     }
     return str;
@@ -223,9 +228,14 @@
         if (extractor != NULL && extractor == ex) {
             if (instance.tracks.size() > 5) {
                 instance.tracks.resize(5);
+                instance.trackDescriptions.resize(5);
             }
             instance.tracks.push_front(source);
-            instance.trackDescriptions.add(source->getFormat()->toString());
+            if (source != NULL) {
+                instance.trackDescriptions.push_front(source->getFormat()->toString());
+            } else {
+                instance.trackDescriptions.push_front(String8::empty());
+            }
             break;
         }
     }
diff --git a/media/libmedia/OMXBuffer.cpp b/media/libmedia/OMXBuffer.cpp
index 2834853..914cd5b 100644
--- a/media/libmedia/OMXBuffer.cpp
+++ b/media/libmedia/OMXBuffer.cpp
@@ -38,6 +38,11 @@
       mRangeLength(codecBuffer != NULL ? codecBuffer->size() : 0) {
 }
 
+OMXBuffer::OMXBuffer(OMX_U32 rangeLength)
+    : mBufferType(kBufferTypePreset),
+      mRangeLength(rangeLength) {
+}
+
 OMXBuffer::OMXBuffer(const sp<IMemory> &mem)
     : mBufferType(kBufferTypeSharedMem),
       mMem(mem) {
@@ -133,6 +138,15 @@
     return OK;
 }
 
+OMXBuffer& OMXBuffer::operator=(OMXBuffer&& source) {
+    mBufferType = std::move(source.mBufferType);
+    mRangeLength = std::move(source.mRangeLength);
+    mMem = std::move(source.mMem);
+    mGraphicBuffer = std::move(source.mGraphicBuffer);
+    mNativeHandle = std::move(source.mNativeHandle);
+    return *this;
+}
+
 } // namespace android
 
 
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/liboboe/src/core/OboeAudio.cpp b/media/liboboe/src/core/OboeAudio.cpp
index fc1b021..a02f226 100644
--- a/media/liboboe/src/core/OboeAudio.cpp
+++ b/media/liboboe/src/core/OboeAudio.cpp
@@ -405,7 +405,7 @@
     return audioStream->createThread(periodNanoseconds, startRoutine, arg);
 }
 
-OBOE_API oboe_result_t Oboe_joinThread(OboeStream stream,
+OBOE_API oboe_result_t OboeStream_joinThread(OboeStream stream,
                                    void **returnArg,
                                    oboe_nanoseconds_t timeoutNanoseconds)
 {
diff --git a/media/liboboe/tests/test_oboe_api.cpp b/media/liboboe/tests/test_oboe_api.cpp
index b3fb24b..acf3000 100644
--- a/media/liboboe/tests/test_oboe_api.cpp
+++ b/media/liboboe/tests/test_oboe_api.cpp
@@ -285,3 +285,57 @@
 
     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/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index 0df7da4..0434bab 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -51,7 +51,7 @@
 }
 
 ssize_t CallbackDataSource::readAt(off64_t offset, void* data, size_t size) {
-    if (mMemory == NULL) {
+    if (mMemory == NULL || data == NULL) {
         return -1;
     }
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index f9af5e1..87d7d3c 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -3992,7 +3992,12 @@
         return OK;
     }
     if (smplcnt > mCurrentSampleInfoAllocSize) {
-        mCurrentSampleInfoSizes = (uint8_t*) realloc(mCurrentSampleInfoSizes, smplcnt);
+        uint8_t * newPtr =  (uint8_t*) realloc(mCurrentSampleInfoSizes, smplcnt);
+        if (newPtr == NULL) {
+            ALOGE("failed to realloc %u -> %u", mCurrentSampleInfoAllocSize, smplcnt);
+            return NO_MEMORY;
+        }
+        mCurrentSampleInfoSizes = newPtr;
         mCurrentSampleInfoAllocSize = smplcnt;
     }
 
@@ -4031,6 +4036,7 @@
     if (entrycount > mCurrentSampleInfoOffsetsAllocSize) {
         uint64_t *newPtr = (uint64_t *)realloc(mCurrentSampleInfoOffsets, entrycount * 8);
         if (newPtr == NULL) {
+            ALOGE("failed to realloc %u -> %u", mCurrentSampleInfoOffsetsAllocSize, entrycount * 8);
             return NO_MEMORY;
         }
         mCurrentSampleInfoOffsets = newPtr;
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/omx/hal/1.0/Android.mk b/media/libstagefright/omx/hal/1.0/Android.mk
index b84d74b..1633486 100644
--- a/media/libstagefright/omx/hal/1.0/Android.mk
+++ b/media/libstagefright/omx/hal/1.0/Android.mk
@@ -4,19 +4,35 @@
 LOCAL_MODULE := android.hardware.media.omx@1.0-impl
 LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_SRC_FILES := \
-    GraphicBufferSource.cpp \
+    WGraphicBufferSource.cpp \
+    WOmx.cpp \
+    WOmxBufferSource.cpp \
+    WOmxNode.cpp \
+    WOmxObserver.cpp \
     Omx.cpp \
-    OmxBufferSource.cpp \
     OmxNode.cpp \
-    OmxObserver.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
+    libmedia \
+    libstagefright_foundation \
+    libstagefright_omx \
+    libui \
     libhidlbase \
     libhidltransport \
     libhwbinder \
     libutils \
+    libcutils \
+    libbinder \
     android.hardware.media.omx@1.0 \
     android.hardware.graphics.common@1.0 \
     android.hardware.media@1.0 \
+    android.hidl.base@1.0 \
+
+LOCAL_C_INCLUDES += \
+        $(TOP) \
+        $(TOP)/frameworks/av/include/media \
+        $(TOP)/frameworks/av/media/libstagefright/include \
+        $(TOP)/frameworks/native/include/media/hardware \
+        $(TOP)/frameworks/native/include/media/openmax
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/hal/1.0/Conversion.h b/media/libstagefright/omx/hal/1.0/Conversion.h
new file mode 100644
index 0000000..44d2c84
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/Conversion.h
@@ -0,0 +1,820 @@
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <unistd.h>
+#include <vector>
+#include <list>
+
+#include <frameworks/native/include/binder/Binder.h>
+#include <frameworks/native/include/binder/Status.h>
+
+#include <OMXFenceParcelable.h>
+#include <cutils/native_handle.h>
+
+#include <IOMX.h>
+#include <VideoAPI.h>
+#include <OMXBuffer.h>
+#include <android/IOMXBufferSource.h>
+#include <android/IGraphicBufferSource.h>
+
+#include <android/hardware/media/omx/1.0/types.h>
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+using ::android::hardware::hidl_handle;
+using ::android::String8;
+using ::android::OMXFenceParcelable;
+
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::omx_message;
+
+using ::android::hardware::media::omx::V1_0::ColorAspects;
+
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+
+using ::android::OMXBuffer;
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::IOMX;
+
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::IOMXNode;
+
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::IOMXObserver;
+
+using ::android::hardware::media::omx::V1_0::IOmxBufferSource;
+using ::android::IOMXBufferSource;
+
+// native_handle_t helper functions.
+
+/**
+ * \brief Take an fd and create a native handle containing only the given fd.
+ * The created handle will need to be deleted manually with
+ * `native_handle_delete()`.
+ *
+ * \param[in] fd The source file descriptor (of type `int`).
+ * \return The create `native_handle_t*` that contains the given \p fd. If the
+ * supplied \p fd is negative, the created native handle will contain no file
+ * descriptors.
+ *
+ * If the native handle cannot be created, the return value will be
+ * `nullptr`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+inline native_handle_t* native_handle_create_from_fd(int fd) {
+    if (fd < 0) {
+        return native_handle_create(0, 0);
+    }
+    native_handle_t* nh = native_handle_create(1, 0);
+    if (nh == nullptr) {
+        return nullptr;
+    }
+    nh->data[0] = fd;
+    return nh;
+}
+
+/**
+ * \brief Extract a file descriptor from a native handle.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \param[in] index The index of the file descriptor in \p nh to read from. This
+ * input has the default value of `0`.
+ * \return The `index`-th file descriptor in \p nh. If \p nh does not have
+ * enough file descriptors, the returned value will be `-1`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+inline int native_handle_read_fd(native_handle_t const* nh, int index = 0) {
+    return ((nh == nullptr) || (nh->numFds == 0) ||
+            (nh->numFds <= index) || (index < 0)) ?
+            -1 : nh->data[index];
+}
+
+/**
+ * Conversion functions
+ * ====================
+ *
+ * There are two main directions of conversion:
+ * - `inTargetType(...)`: Create a wrapper whose lifetime depends on the
+ *   input. The wrapper has type `TargetType`.
+ * - `toTargetType(...)`: Create a standalone object of type `TargetType` that
+ *   corresponds to the input. The lifetime of the output does not depend on the
+ *   lifetime of the input.
+ * - `wrapIn(TargetType*, ...)`: Same as `inTargetType()`, but for `TargetType`
+ *   that cannot be copied and/or moved efficiently, or when there are multiple
+ *   output arguments.
+ * - `convertTo(TargetType*, ...)`: Same as `toTargetType()`, but for
+ *   `TargetType` that cannot be copied and/or moved efficiently, or when there
+ *   are multiple output arguments.
+ *
+ * `wrapIn()` and `convertTo()` functions will take output arguments before
+ * input arguments. Some of these functions might return a value to indicate
+ * success or error.
+ *
+ * In converting or wrapping something as a Treble type that contains a
+ * `hidl_handle`, `native_handle_t*` will need to be created and returned as
+ * an additional output argument, hence only `wrapIn()` or `convertTo()` would
+ * be available. The caller must call `native_handle_delete()` to deallocate the
+ * returned native handle when it is no longer needed.
+ *
+ * For types that contain file descriptors, `inTargetType()` and `wrapAs()` do
+ * not perform duplication of file descriptors, while `toTargetType()` and
+ * `convertTo()` do.
+ */
+
+/**
+ * \brief Convert `binder::Status` to `hardware::Status`.
+ *
+ * \param[in] l The source `binder::Status`.
+ * \return The corresponding `hardware::Status`.
+ */
+// convert: ::android::binder::Status -> ::android::hardware::Status
+inline ::android::hardware::Status toHardwareStatus(
+        ::android::binder::Status const& l) {
+    if (l.exceptionCode() == ::android::binder::Status::EX_SERVICE_SPECIFIC) {
+        return ::android::hardware::Status::fromServiceSpecificError(
+                l.serviceSpecificErrorCode(),
+                l.exceptionMessage());
+    }
+    return ::android::hardware::Status::fromExceptionCode(
+            l.exceptionCode(),
+            l.exceptionMessage());
+}
+
+/**
+ * \brief Convert `hardware::Status` to `binder::Status`.
+ *
+ * \param[in] t The source `hardware::Status`.
+ * \return The corresponding `binder::Status`.
+ */
+// convert: ::android::hardware::Status -> ::android::binder::Status
+inline ::android::binder::Status toBinderStatus(
+        ::android::hardware::Status const& t) {
+    if (t.exceptionCode() == ::android::hardware::Status::EX_SERVICE_SPECIFIC) {
+        return ::android::binder::Status::fromServiceSpecificError(
+                t.serviceSpecificErrorCode(),
+                t.exceptionMessage());
+    }
+    return ::android::binder::Status::fromExceptionCode(
+            t.exceptionCode(),
+            t.exceptionMessage());
+}
+
+/**
+ * \brief Convert `hardware::Return<void>` to `binder::Status`.
+ *
+ * \param[in] t The source `hardware::Return<void>`.
+ * \return The corresponding `binder::Status`.
+ *
+ * This function simply calls `toBinderStatus(::android::hardware::Status
+ * const&)`.
+ */
+// convert: ::android::hardware::Return<void> -> ::android::binder::Status
+inline ::android::binder::Status toBinderStatus(Return<void> const& t) {
+    return toBinderStatus(t.getStatus());
+}
+
+/**
+ * \brief Convert `Return<Status>` to `status_t`. This is for legacy binder
+ * calls.
+ *
+ * \param[in] t The source `Return<Status>`.
+ * \return The corresponding `status_t`.
+ *
+ * This function first check if \p t has a transport error. If it does, then the
+ * return value is the transport error code. Otherwise, the return value is
+ * converted from `Status` contained inside \p t.
+ *
+ * Note:
+ * - This `Status` is omx-specific. It is defined in `types.hal`.
+ * - The name of this function is not `convert`.
+ */
+// convert: Status -> status_t
+inline status_t toStatusT(Return<Status> const& t) {
+    return t.isOk() ? static_cast<status_t>(static_cast<Status>(t)) :
+            t.getStatus().transactionError();
+}
+
+/**
+ * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `status_t`.
+ */
+// convert: Return<void> -> status_t
+inline status_t toStatusT(Return<void> const& t) {
+    return t.getStatus().transactionError();
+}
+
+/**
+ * \brief Convert `Status` to `status_t`. This is for legacy binder calls.
+ *
+ * \param[in] t The source `Status`.
+ * \return the corresponding `status_t`.
+ */
+// convert: Status -> status_t
+inline status_t toStatusT(Status const& t) {
+    return static_cast<status_t>(t);
+}
+
+/**
+ * \brief Convert `status_t` to `Status`.
+ *
+ * \param[in] l The source `status_t`.
+ * \return The corresponding `Status`.
+ */
+// convert: status_t -> Status
+inline Status toStatus(status_t l) {
+    return static_cast<Status>(l);
+}
+
+/**
+ * \brief Wrap `native_handle_t*` in `hidl_handle`.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \return The `hidl_handle` that points to \p nh.
+ */
+// wrap: native_handle_t* -> hidl_handle
+inline hidl_handle inHidlHandle(native_handle_t const* nh) {
+    return hidl_handle(nh);
+}
+
+/**
+ * \brief Wrap an `omx_message` and construct the corresponding `Message`.
+ *
+ * \param[out] t The wrapper of type `Message`.
+ * \param[out] nh The native_handle_t referred to by `t->fence`.
+ * \param[in] l The source `omx_message`.
+ * \return `true` if the wrapping is successful; `false` otherwise.
+ *
+ * Upon success, \p nh will be created to hold the file descriptor stored in
+ * `l.fenceFd`, and `t->fence` will point to \p nh. \p nh will need to be
+ * destroyed manually by `native_handle_delete()` when \p t is no longer needed.
+ *
+ * Upon failure, \p nh will not be created and will not need to be deleted. \p t
+ * will be invalid.
+ */
+// wrap, omx_message -> Message, native_handle_t*
+inline bool wrapAs(Message* t, native_handle_t** nh, omx_message const& l) {
+    *nh = native_handle_create_from_fd(l.fenceFd);
+    if (!*nh) {
+        return false;
+    }
+    t->fence = inHidlHandle(*nh);
+    switch (l.type) {
+        case omx_message::EVENT:
+            t->type = Message::Type::EVENT;
+            t->data.eventData.data1 = l.u.event_data.data1;
+            t->data.eventData.data2 = l.u.event_data.data2;
+            t->data.eventData.data3 = l.u.event_data.data3;
+            t->data.eventData.data4 = l.u.event_data.data4;
+            break;
+        case omx_message::EMPTY_BUFFER_DONE:
+            t->type = Message::Type::EMPTY_BUFFER_DONE;
+            t->data.bufferData.buffer = l.u.buffer_data.buffer;
+            break;
+        case omx_message::FILL_BUFFER_DONE:
+            t->type = Message::Type::FILL_BUFFER_DONE;
+            t->data.extendedBufferData.buffer = l.u.extended_buffer_data.buffer;
+            t->data.extendedBufferData.rangeOffset = l.u.extended_buffer_data.range_offset;
+            t->data.extendedBufferData.rangeLength = l.u.extended_buffer_data.range_length;
+            t->data.extendedBufferData.flags = l.u.extended_buffer_data.flags;
+            t->data.extendedBufferData.timestampUs = l.u.extended_buffer_data.timestamp;
+            break;
+        case omx_message::FRAME_RENDERED:
+            t->type = Message::Type::FRAME_RENDERED;
+            t->data.renderData.timestampUs = l.u.render_data.timestamp;
+            t->data.renderData.systemTimeNs = l.u.render_data.nanoTime;
+            break;
+        default:
+            native_handle_delete(*nh);
+            return false;
+    }
+    return true;
+}
+
+/**
+ * \brief Wrap a `Message` inside an `omx_message`.
+ *
+ * \param[out] l The wrapper of type `omx_message`.
+ * \param[in] t The source `Message`.
+ * \return `true` if the wrapping is successful; `false` otherwise.
+ */
+// wrap: Message -> omx_message
+inline bool wrapAs(omx_message* l, Message const& t) {
+    l->fenceFd = native_handle_read_fd(t.fence);
+    switch (t.type) {
+        case Message::Type::EVENT:
+            l->type = omx_message::EVENT;
+            l->u.event_data.data1 = t.data.eventData.data1;
+            l->u.event_data.data2 = t.data.eventData.data2;
+            l->u.event_data.data3 = t.data.eventData.data3;
+            l->u.event_data.data4 = t.data.eventData.data4;
+            break;
+        case Message::Type::EMPTY_BUFFER_DONE:
+            l->type = omx_message::EMPTY_BUFFER_DONE;
+            l->u.buffer_data.buffer = t.data.bufferData.buffer;
+            break;
+        case Message::Type::FILL_BUFFER_DONE:
+            l->type = omx_message::FILL_BUFFER_DONE;
+            l->u.extended_buffer_data.buffer = t.data.extendedBufferData.buffer;
+            l->u.extended_buffer_data.range_offset = t.data.extendedBufferData.rangeOffset;
+            l->u.extended_buffer_data.range_length = t.data.extendedBufferData.rangeLength;
+            l->u.extended_buffer_data.flags = t.data.extendedBufferData.flags;
+            l->u.extended_buffer_data.timestamp = t.data.extendedBufferData.timestampUs;
+            break;
+        case Message::Type::FRAME_RENDERED:
+            l->type = omx_message::FRAME_RENDERED;
+            l->u.render_data.timestamp = t.data.renderData.timestampUs;
+            l->u.render_data.nanoTime = t.data.renderData.systemTimeNs;
+            break;
+        default:
+            return false;
+    }
+    return true;
+}
+
+/**
+ * \brief Similar to `wrapTo(omx_message*, Message const&)`, but the output will
+ * have an extended lifetime.
+ *
+ * \param[out] l The output `omx_message`.
+ * \param[in] t The source `Message`.
+ * \return `true` if the conversion is successful; `false` otherwise.
+ *
+ * This function calls `wrapto()`, then attempts to clone the file descriptor
+ * for the fence if it is not `-1`. If the clone cannot be made, `false` will be
+ * returned.
+ */
+// convert: Message -> omx_message
+inline bool convertTo(omx_message* l, Message const& t) {
+    if (!wrapAs(l, t)) {
+        return false;
+    }
+    if (l->fenceFd == -1) {
+        return true;
+    }
+    l->fenceFd = dup(l->fenceFd);
+    return l->fenceFd != -1;
+}
+
+/**
+ * \brief Wrap an `OMXFenceParcelable` inside a `hidl_handle`.
+ *
+ * \param[out] t The wrapper of type `hidl_handle`.
+ * \param[out] nh The native handle created to hold the file descriptor inside
+ * \p l.
+ * \param[in] l The source `OMXFenceParcelable`, which essentially contains one
+ * file descriptor.
+ * \return `true` if \p t and \p nh are successfully created to wrap around \p
+ * l; `false` otherwise.
+ *
+ * On success, \p nh needs to be deleted by the caller with
+ * `native_handle_delete()` after \p t and \p nh are no longer needed.
+ *
+ * On failure, \p nh will not need to be deleted, and \p t will hold an invalid
+ * value.
+ */
+// wrap: OMXFenceParcelable -> hidl_handle, native_handle_t*
+inline bool wrapAs(hidl_handle* t, native_handle_t** nh,
+        OMXFenceParcelable const& l) {
+    *nh = native_handle_create_from_fd(l.get());
+    if (!*nh) {
+        return false;
+    }
+    *t = *nh;
+    return true;
+}
+
+/**
+ * \brief Wrap a `hidl_handle` inside an `OMXFenceParcelable`.
+ *
+ * \param[out] l The wrapper of type `OMXFenceParcelable`.
+ * \param[in] t The source `hidl_handle`.
+ */
+// wrap: hidl_handle -> OMXFenceParcelable
+inline void wrapAs(OMXFenceParcelable* l, hidl_handle const& t) {
+    l->mFenceFd = native_handle_read_fd(t);
+}
+
+/**
+ * \brief Convert a `hidl_handle` to `OMXFenceParcelable`. If `hidl_handle`
+ * contains file descriptors, the first file descriptor will be duplicated and
+ * stored in the output `OMXFenceParcelable`.
+ *
+ * \param[out] l The output `OMXFenceParcelable`.
+ * \param[in] t The input `hidl_handle`.
+ * \return `false` if \p t contains a valid file descriptor but duplication
+ * fails; `true` otherwise.
+ */
+// convert: hidl_handle -> OMXFenceParcelable
+inline bool convertTo(OMXFenceParcelable* l, hidl_handle const& t) {
+    int fd = native_handle_read_fd(t);
+    if (fd != -1) {
+        fd = dup(fd);
+        if (fd == -1) {
+            return false;
+        }
+    }
+    l->mFenceFd = fd;
+    return true;
+}
+
+/**
+ * \brief Convert `::android::ColorAspects` to `ColorAspects`.
+ *
+ * \param[in] l The source `::android::ColorAspects`.
+ * \return The corresponding `ColorAspects`.
+ */
+// convert: ::android::ColorAspects -> ColorAspects
+inline ColorAspects toHardwareColorAspects(::android::ColorAspects const& l) {
+    return ColorAspects{
+            static_cast<ColorAspects::Range>(l.mRange),
+            static_cast<ColorAspects::Primaries>(l.mPrimaries),
+            static_cast<ColorAspects::Transfer>(l.mTransfer),
+            static_cast<ColorAspects::MatrixCoeffs>(l.mMatrixCoeffs)};
+}
+
+/**
+ * \brief Convert `int32_t` to `ColorAspects`.
+ *
+ * \param[in] l The source `int32_t`.
+ * \return The corresponding `ColorAspects`.
+ */
+// convert: int32_t -> ColorAspects
+inline ColorAspects toHardwareColorAspects(int32_t l) {
+    return ColorAspects{
+            static_cast<ColorAspects::Range>((l >> 24) & 0xFF),
+            static_cast<ColorAspects::Primaries>((l >> 16) & 0xFF),
+            static_cast<ColorAspects::Transfer>(l & 0xFF),
+            static_cast<ColorAspects::MatrixCoeffs>((l >> 8) & 0xFF)};
+}
+
+/**
+ * \brief Convert `ColorAspects` to `::android::ColorAspects`.
+ *
+ * \param[in] t The source `ColorAspects`.
+ * \return The corresponding `::android::ColorAspects`.
+ */
+// convert: ColorAspects -> ::android::ColorAspects
+inline int32_t toCompactColorAspects(ColorAspects const& t) {
+    return static_cast<int32_t>(
+            (static_cast<uint32_t>(t.range) << 24) |
+            (static_cast<uint32_t>(t.primaries) << 16) |
+            (static_cast<uint32_t>(t.transfer)) |
+            (static_cast<uint32_t>(t.matrixCoeffs) << 8));
+}
+
+/**
+ * \brief Convert `int32_t` to `Dataspace`.
+ *
+ * \param[in] l The source `int32_t`.
+ * \result The corresponding `Dataspace`.
+ */
+// convert: int32_t -> Dataspace
+inline Dataspace toHardwareDataspace(int32_t l) {
+    return static_cast<Dataspace>(l);
+}
+
+/**
+ * \brief Convert `Dataspace` to `int32_t`.
+ *
+ * \param[in] t The source `Dataspace`.
+ * \result The corresponding `int32_t`.
+ */
+// convert: Dataspace -> int32_t
+inline int32_t toRawDataspace(Dataspace const& t) {
+    return static_cast<int32_t>(t);
+}
+
+/**
+ * \brief Wrap an opaque buffer inside a `hidl_vec<uint8_t>`.
+ *
+ * \param[in] l The pointer to the beginning of the opaque buffer.
+ * \param[in] size The size of the buffer.
+ * \return A `hidl_vec<uint8_t>` that points to the buffer.
+ */
+// wrap: void*, size_t -> hidl_vec<uint8_t>
+inline hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) {
+    hidl_vec<uint8_t> t;
+    t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false);
+    return t;
+}
+
+/**
+ * \brief Create a `hidl_vec<uint8_t>` that is a copy of an opaque buffer.
+ *
+ * \param[in] l The pointer to the beginning of the opaque buffer.
+ * \param[in] size The size of the buffer.
+ * \return A `hidl_vec<uint8_t>` that is a copy of the input buffer.
+ */
+// convert: void*, size_t -> hidl_vec<uint8_t>
+inline hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size) {
+    hidl_vec<uint8_t> t;
+    t.resize(size);
+    uint8_t const* src = static_cast<uint8_t const*>(l);
+    std::copy(src, src + size, t.data());
+    return t;
+}
+
+/**
+ * \brief Wrap `OMXBuffer` in `CodecBuffer`.
+ *
+ * \param[out] t The wrapper of type `CodecBuffer`.
+ * \param[in] l The source `OMXBuffer`.
+ * \return `true` if the wrapping is successful; `false` otherwise.
+ *
+ * TODO: Use HIDL's shared memory.
+ */
+// wrap: OMXBuffer -> CodecBuffer
+inline bool wrapAs(CodecBuffer* t, OMXBuffer const& l) {
+    switch (l.mBufferType) {
+        case OMXBuffer::kBufferTypeInvalid: {
+            t->type = CodecBuffer::Type::INVALID;
+            return true;
+        }
+        case OMXBuffer::kBufferTypePreset: {
+            t->type = CodecBuffer::Type::PRESET;
+            t->attr.preset.rangeLength = static_cast<uint32_t>(l.mRangeLength);
+            return true;
+        }
+        case OMXBuffer::kBufferTypeSharedMem: {
+            t->type = CodecBuffer::Type::SHARED_MEM;
+/* TODO: Use HIDL's shared memory.
+            ssize_t offset;
+            size_t size;
+            native_handle_t* handle;
+            sp<IMemoryHeap> memoryHeap = l.mMem->getMemory(&offset, &size);
+            t->attr.sharedMem.size = static_cast<uint32_t>(size);
+            t->attr.sharedMem.flags = static_cast<uint32_t>(memoryHeap->getFlags());
+            t->attr.sharedMem.offset = static_cast<uint32_t>(offset);
+            if (!convertFd2Handle(memoryHeap->getHeapID(), nh)) {
+                return false;
+            }
+            t->nativeHandle = hidl_handle(*nh);
+            return true;*/
+            return false;
+        }
+        case OMXBuffer::kBufferTypeANWBuffer: {
+            t->type = CodecBuffer::Type::ANW_BUFFER;
+            t->attr.anwBuffer.width = l.mGraphicBuffer->getWidth();
+            t->attr.anwBuffer.height = l.mGraphicBuffer->getHeight();
+            t->attr.anwBuffer.stride = l.mGraphicBuffer->getStride();
+            t->attr.anwBuffer.format = static_cast<PixelFormat>(l.mGraphicBuffer->getPixelFormat());
+            t->attr.anwBuffer.layerCount = l.mGraphicBuffer->getLayerCount();
+            t->attr.anwBuffer.usage = l.mGraphicBuffer->getUsage();
+            t->nativeHandle = hidl_handle(l.mGraphicBuffer->handle);
+            return true;
+        }
+        case OMXBuffer::kBufferTypeNativeHandle: {
+            t->type = CodecBuffer::Type::NATIVE_HANDLE;
+            t->nativeHandle = hidl_handle(l.mNativeHandle->handle());
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * \brief Convert `CodecBuffer` to `OMXBuffer`.
+ *
+ * \param[out] l The destination `OMXBuffer`.
+ * \param[in] t The source `CodecBuffer`.
+ * \return `true` if successful; `false` otherwise.
+ *
+ * TODO: Use HIDL's shared memory.
+ */
+// convert: CodecBuffer -> OMXBuffer
+inline bool convertTo(OMXBuffer* l, CodecBuffer const& t) {
+    switch (t.type) {
+        case CodecBuffer::Type::INVALID: {
+            *l = OMXBuffer();
+            return true;
+        }
+        case CodecBuffer::Type::PRESET: {
+            *l = OMXBuffer(t.attr.preset.rangeLength);
+            return true;
+        }
+        case CodecBuffer::Type::SHARED_MEM: {
+/* TODO: Use HIDL's memory.
+            *l = OMXBuffer();
+            return true;*/
+            return false;
+        }
+        case CodecBuffer::Type::ANW_BUFFER: {
+            *l = OMXBuffer(sp<GraphicBuffer>(new GraphicBuffer(
+                    t.attr.anwBuffer.width,
+                    t.attr.anwBuffer.height,
+                    static_cast<::android::PixelFormat>(
+                            t.attr.anwBuffer.format),
+                    t.attr.anwBuffer.layerCount,
+                    t.attr.anwBuffer.usage,
+                    t.attr.anwBuffer.stride,
+                    native_handle_clone(t.nativeHandle),
+                    true)));
+            return true;
+        }
+        case CodecBuffer::Type::NATIVE_HANDLE: {
+            *l = OMXBuffer(NativeHandle::create(
+                    native_handle_clone(t.nativeHandle), true));
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * \brief Convert `IOMX::ComponentInfo` to `IOmx::ComponentInfo`.
+ *
+ * \param[out] t The destination `IOmx::ComponentInfo`.
+ * \param[in] l The source `IOMX::ComponentInfo`.
+ */
+// convert: IOMX::ComponentInfo -> IOmx::ComponentInfo
+inline bool convertTo(IOmx::ComponentInfo* t, IOMX::ComponentInfo const& l) {
+    t->mName = l.mName.string();
+    t->mRoles.resize(l.mRoles.size());
+    size_t i = 0;
+    for (auto& role : l.mRoles) {
+        t->mRoles[i++] = role.string();
+    }
+    return true;
+}
+
+/**
+ * \brief Convert `IOmx::ComponentInfo` to `IOMX::ComponentInfo`.
+ *
+ * \param[out] l The destination `IOMX::ComponentInfo`.
+ * \param[in] t The source `IOmx::ComponentInfo`.
+ */
+// convert: IOmx::ComponentInfo -> IOMX::ComponentInfo
+inline bool convertTo(IOMX::ComponentInfo* l, IOmx::ComponentInfo const& t) {
+    l->mName = t.mName.c_str();
+    l->mRoles.clear();
+    for (size_t i = 0; i < t.mRoles.size(); ++i) {
+        l->mRoles.push_back(String8(t.mRoles[i].c_str()));
+    }
+    return true;
+}
+
+/**
+ * \brief Convert `OMX_BOOL` to `bool`.
+ *
+ * \param[in] l The source `OMX_BOOL`.
+ * \return The destination `bool`.
+ */
+// convert: OMX_BOOL -> bool
+inline bool toRawBool(OMX_BOOL l) {
+    return l == OMX_FALSE ? false : true;
+}
+
+/**
+ * \brief Convert `bool` to `OMX_BOOL`.
+ *
+ * \param[in] t The source `bool`.
+ * \return The destination `OMX_BOOL`.
+ */
+// convert: bool -> OMX_BOOL
+inline OMX_BOOL toEnumBool(bool t) {
+    return t ? OMX_TRUE : OMX_FALSE;
+}
+
+/**
+ * \brief Convert `OMX_COMMANDTYPE` to `uint32_t`.
+ *
+ * \param[in] l The source `OMX_COMMANDTYPE`.
+ * \return The underlying value of type `uint32_t`.
+ *
+ * `OMX_COMMANDTYPE` is an enum type whose underlying type is `uint32_t`.
+ */
+// convert: OMX_COMMANDTYPE -> uint32_t
+inline uint32_t toRawCommandType(OMX_COMMANDTYPE l) {
+    return static_cast<uint32_t>(l);
+}
+
+/**
+ * \brief Convert `uint32_t` to `OMX_COMMANDTYPE`.
+ *
+ * \param[in] t The source `uint32_t`.
+ * \return The corresponding enum value of type `OMX_COMMANDTYPE`.
+ *
+ * `OMX_COMMANDTYPE` is an enum type whose underlying type is `uint32_t`.
+ */
+// convert: uint32_t -> OMX_COMMANDTYPE
+inline OMX_COMMANDTYPE toEnumCommandType(uint32_t t) {
+    return static_cast<OMX_COMMANDTYPE>(t);
+}
+
+/**
+ * \brief Convert `OMX_INDEXTYPE` to `uint32_t`.
+ *
+ * \param[in] l The source `OMX_INDEXTYPE`.
+ * \return The underlying value of type `uint32_t`.
+ *
+ * `OMX_INDEXTYPE` is an enum type whose underlying type is `uint32_t`.
+ */
+// convert: OMX_INDEXTYPE -> uint32_t
+inline uint32_t toRawIndexType(OMX_INDEXTYPE l) {
+    return static_cast<uint32_t>(l);
+}
+
+/**
+ * \brief Convert `uint32_t` to `OMX_INDEXTYPE`.
+ *
+ * \param[in] t The source `uint32_t`.
+ * \return The corresponding enum value of type `OMX_INDEXTYPE`.
+ *
+ * `OMX_INDEXTYPE` is an enum type whose underlying type is `uint32_t`.
+ */
+// convert: uint32_t -> OMX_INDEXTYPE
+inline OMX_INDEXTYPE toEnumIndexType(uint32_t t) {
+    return static_cast<OMX_INDEXTYPE>(t);
+}
+
+/**
+ * \brief Convert `IOMX::PortMode` to `PortMode`.
+ *
+ * \param[in] l The source `IOMX::PortMode`.
+ * \return The destination `PortMode`.
+ */
+// convert: IOMX::PortMode -> PortMode
+inline PortMode toHardwarePortMode(IOMX::PortMode l) {
+    return static_cast<PortMode>(l);
+}
+
+/**
+ * \brief Convert `PortMode` to `IOMX::PortMode`.
+ *
+ * \param[in] t The source `PortMode`.
+ * \return The destination `IOMX::PortMode`.
+ */
+// convert: PortMode -> IOMX::PortMode
+inline IOMX::PortMode toIOMXPortMode(PortMode t) {
+    return static_cast<IOMX::PortMode>(t);
+}
+
+/**
+ * \brief Convert `OMX_TICKS` to `uint64_t`.
+ *
+ * \param[in] l The source `OMX_TICKS`.
+ * \return The destination `uint64_t`.
+ */
+// convert: OMX_TICKS -> uint64_t
+inline uint64_t toRawTicks(OMX_TICKS l) {
+#ifndef OMX_SKIP64BIT
+    return static_cast<uint64_t>(l);
+#else
+    return static_cast<uint64_t>(l.nLowPart) |
+            static_cast<uint64_t>(l.nHighPart << 32);
+#endif
+}
+
+/**
+ * \brief Convert 'uint64_t` to `OMX_TICKS`.
+ *
+ * \param[in] l The source `uint64_t`.
+ * \return The destination `OMX_TICKS`.
+ */
+// convert: uint64_t -> OMX_TICKS
+inline OMX_TICKS toOMXTicks(uint64_t t) {
+#ifndef OMX_SKIP64BIT
+    return static_cast<OMX_TICKS>(t);
+#else
+    return OMX_TICKS{
+            static_cast<uint32_t>(t & 0xFFFFFFFF),
+            static_cast<uint32_t>(t >> 32)};
+#endif
+}
+
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
diff --git a/media/libstagefright/omx/hal/1.0/GraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/GraphicBufferSource.cpp
deleted file mode 100644
index 6a43883..0000000
--- a/media/libstagefright/omx/hal/1.0/GraphicBufferSource.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "GraphicBufferSource.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
-
-// Methods from ::android::hardware::media::omx::V1_0::IGraphicBufferSource follow.
-Return<Status> GraphicBufferSource::configure(const sp<IOmxNode>& omxNode, Dataspace dataspace) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> GraphicBufferSource::setSuspend(bool suspend) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> GraphicBufferSource::setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> GraphicBufferSource::setMaxFps(float maxFps) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> GraphicBufferSource::setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> GraphicBufferSource::setStartTimeUs(int64_t startTimeUs) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> GraphicBufferSource::setColorAspects(const ColorAspects& aspects) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> GraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> GraphicBufferSource::signalEndOfInputStream() {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-
-IGraphicBufferSource* HIDL_FETCH_IGraphicBufferSource(const char* /* name */) {
-    return new GraphicBufferSource();
-}
-
-} // namespace implementation
-}  // namespace V1_0
-}  // namespace omx
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/GraphicBufferSource.h b/media/libstagefright/omx/hal/1.0/GraphicBufferSource.h
deleted file mode 100644
index fb8c89d..0000000
--- a/media/libstagefright/omx/hal/1.0/GraphicBufferSource.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__GRAPHICBUFFERSOURCE_H
-#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__GRAPHICBUFFERSOURCE_H
-
-#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::graphics::common::V1_0::Dataspace;
-using ::android::hardware::media::omx::V1_0::ColorAspects;
-using ::android::hardware::media::omx::V1_0::IGraphicBufferSource;
-using ::android::hardware::media::omx::V1_0::IOmxNode;
-using ::android::hardware::media::omx::V1_0::Status;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct GraphicBufferSource : public IGraphicBufferSource {
-    // Methods from ::android::hardware::media::omx::V1_0::IGraphicBufferSource follow.
-    Return<Status> configure(const sp<IOmxNode>& omxNode, Dataspace dataspace) override;
-    Return<Status> setSuspend(bool suspend) override;
-    Return<Status> setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
-    Return<Status> setMaxFps(float maxFps) override;
-    Return<Status> setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) override;
-    Return<Status> setStartTimeUs(int64_t startTimeUs) override;
-    Return<Status> setColorAspects(const ColorAspects& aspects) override;
-    Return<Status> setTimeOffsetUs(int64_t timeOffsetUs) override;
-    Return<Status> signalEndOfInputStream() override;
-
-};
-
-extern "C" IGraphicBufferSource* HIDL_FETCH_IGraphicBufferSource(const char* name);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace omx
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0__GRAPHICBUFFERSOURCE_H
diff --git a/media/libstagefright/omx/hal/1.0/Omx.cpp b/media/libstagefright/omx/hal/1.0/Omx.cpp
index 68040eb..cb23191 100644
--- a/media/libstagefright/omx/hal/1.0/Omx.cpp
+++ b/media/libstagefright/omx/hal/1.0/Omx.cpp
@@ -19,11 +19,13 @@
 }
 
 
+// Methods from ::android::hidl::base::V1_0::IBase follow.
+
 IOmx* HIDL_FETCH_IOmx(const char* /* name */) {
     return new Omx();
 }
 
-} // namespace implementation
+}  // namespace implementation
 }  // namespace V1_0
 }  // namespace omx
 }  // namespace media
diff --git a/media/libstagefright/omx/hal/1.0/Omx.h b/media/libstagefright/omx/hal/1.0/Omx.h
index 02a0a01..5d06444 100644
--- a/media/libstagefright/omx/hal/1.0/Omx.h
+++ b/media/libstagefright/omx/hal/1.0/Omx.h
@@ -1,10 +1,12 @@
-#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMX_H
-#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMX_H
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMX_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMX_H
 
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
+#include <IOMX.h>
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -16,7 +18,9 @@
 using ::android::hardware::media::omx::V1_0::IOmxNode;
 using ::android::hardware::media::omx::V1_0::IOmxObserver;
 using ::android::hardware::media::omx::V1_0::Status;
+using ::android::hidl::base::V1_0::IBase;
 using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
@@ -28,6 +32,8 @@
     Return<void> listNodes(listNodes_cb _hidl_cb) override;
     Return<void> allocateNode(const hidl_string& name, const sp<IOmxObserver>& observer, allocateNode_cb _hidl_cb) override;
 
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+
 };
 
 extern "C" IOmx* HIDL_FETCH_IOmx(const char* name);
@@ -39,4 +45,4 @@
 }  // namespace hardware
 }  // namespace android
 
-#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMX_H
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMX_H
diff --git a/media/libstagefright/omx/hal/1.0/OmxBufferSource.cpp b/media/libstagefright/omx/hal/1.0/OmxBufferSource.cpp
deleted file mode 100644
index 2885d0d..0000000
--- a/media/libstagefright/omx/hal/1.0/OmxBufferSource.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#include "OmxBufferSource.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
-
-// Methods from ::android::hardware::media::omx::V1_0::IOmxBufferSource follow.
-Return<void> OmxBufferSource::onOmxExecuting() {
-    // TODO implement
-    return Void();
-}
-
-Return<void> OmxBufferSource::onOmxIdle() {
-    // TODO implement
-    return Void();
-}
-
-Return<void> OmxBufferSource::onOmxLoaded() {
-    // TODO implement
-    return Void();
-}
-
-Return<void> OmxBufferSource::onInputBufferAdded(uint32_t buffer) {
-    // TODO implement
-    return Void();
-}
-
-Return<void> OmxBufferSource::onInputBufferEmptied(uint32_t buffer, const hidl_handle& fence) {
-    // TODO implement
-    return Void();
-}
-
-
-IOmxBufferSource* HIDL_FETCH_IOmxBufferSource(const char* /* name */) {
-    return new OmxBufferSource();
-}
-
-} // namespace implementation
-}  // namespace V1_0
-}  // namespace omx
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/OmxBufferSource.h b/media/libstagefright/omx/hal/1.0/OmxBufferSource.h
deleted file mode 100644
index 5e4855b..0000000
--- a/media/libstagefright/omx/hal/1.0/OmxBufferSource.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXBUFFERSOURCE_H
-#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXBUFFERSOURCE_H
-
-#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::media::omx::V1_0::IOmxBufferSource;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct OmxBufferSource : public IOmxBufferSource {
-    // Methods from ::android::hardware::media::omx::V1_0::IOmxBufferSource follow.
-    Return<void> onOmxExecuting() override;
-    Return<void> onOmxIdle() override;
-    Return<void> onOmxLoaded() override;
-    Return<void> onInputBufferAdded(uint32_t buffer) override;
-    Return<void> onInputBufferEmptied(uint32_t buffer, const hidl_handle& fence) override;
-
-};
-
-extern "C" IOmxBufferSource* HIDL_FETCH_IOmxBufferSource(const char* name);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace omx
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXBUFFERSOURCE_H
diff --git a/media/libstagefright/omx/hal/1.0/OmxNode.cpp b/media/libstagefright/omx/hal/1.0/OmxNode.cpp
index ba0e722..08d1cd7 100644
--- a/media/libstagefright/omx/hal/1.0/OmxNode.cpp
+++ b/media/libstagefright/omx/hal/1.0/OmxNode.cpp
@@ -1,4 +1,9 @@
+#include <IOMX.h>
+#include <OMXNodeInstance.h>
 #include "OmxNode.h"
+#include "WOmxNode.h"
+#include "WOmxObserver.h"
+#include "Conversion.h"
 
 namespace android {
 namespace hardware {
@@ -13,7 +18,7 @@
     return ::android::hardware::media::omx::V1_0::Status {};
 }
 
-Return<Status> OmxNode::sendCommand(uint32_t cmd, const hidl_vec<uint8_t>& info) {
+Return<Status> OmxNode::sendCommand(uint32_t cmd, int32_t param) {
     // TODO implement
     return ::android::hardware::media::omx::V1_0::Status {};
 }
@@ -98,12 +103,11 @@
     return ::android::hardware::media::omx::V1_0::Status {};
 }
 
-
-IOmxNode* HIDL_FETCH_IOmxNode(const char* /* name */) {
-    return new OmxNode();
+OmxNode::OmxNode(OmxNodeOwner* owner, sp<IOmxObserver> const& observer, char const* name) {
+    mLNode = new OMXNodeInstance(owner, new LWOmxObserver(observer), name);
 }
 
-} // namespace implementation
+}  // namespace implementation
 }  // namespace V1_0
 }  // namespace omx
 }  // namespace media
diff --git a/media/libstagefright/omx/hal/1.0/OmxNode.h b/media/libstagefright/omx/hal/1.0/OmxNode.h
index dd9e5b4..e05e107 100644
--- a/media/libstagefright/omx/hal/1.0/OmxNode.h
+++ b/media/libstagefright/omx/hal/1.0/OmxNode.h
@@ -1,10 +1,13 @@
-#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXNODE_H
-#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXNODE_H
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXNODE_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXNODE_H
 
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
+#include <OMXNodeInstance.h>
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -15,20 +18,34 @@
 using ::android::hardware::media::omx::V1_0::CodecBuffer;
 using ::android::hardware::media::omx::V1_0::IOmxBufferSource;
 using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
 using ::android::hardware::media::omx::V1_0::Message;
 using ::android::hardware::media::omx::V1_0::PortMode;
 using ::android::hardware::media::omx::V1_0::Status;
+using ::android::hidl::base::V1_0::IBase;
 using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::sp;
 
+using ::android::OMXNodeInstance;
+using ::android::OmxNodeOwner;
+
+/**
+ * Wrapper classes for conversion
+ * ==============================
+ *
+ * Naming convention:
+ * - LW = Legacy Wrapper --- It wraps a Treble object inside a legacy object.
+ * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
+ */
+
 struct OmxNode : public IOmxNode {
-    // Methods from ::android::hardware::media::omx::V1_0::IOmxNode follow.
     Return<Status> freeNode() override;
-    Return<Status> sendCommand(uint32_t cmd, const hidl_vec<uint8_t>& info) override;
+    Return<Status> sendCommand(uint32_t cmd, int32_t param) override;
     Return<void> getParameter(uint32_t index, const hidl_vec<uint8_t>& inParams, getParameter_cb _hidl_cb) override;
     Return<Status> setParameter(uint32_t index, const hidl_vec<uint8_t>& params) override;
     Return<void> getConfig(uint32_t index, const hidl_vec<uint8_t>& inConfig, getConfig_cb _hidl_cb) override;
@@ -46,10 +63,11 @@
     Return<void> getExtensionIndex(const hidl_string& parameterName, getExtensionIndex_cb _hidl_cb) override;
     Return<Status> dispatchMessage(const Message& msg) override;
 
+    OmxNode(OmxNodeOwner* owner, sp<IOmxObserver> const& observer, char const* name);
+protected:
+    sp<OMXNodeInstance> mLNode;
 };
 
-extern "C" IOmxNode* HIDL_FETCH_IOmxNode(const char* name);
-
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace omx
@@ -57,4 +75,4 @@
 }  // namespace hardware
 }  // namespace android
 
-#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXNODE_H
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXNODE_H
diff --git a/media/libstagefright/omx/hal/1.0/OmxObserver.cpp b/media/libstagefright/omx/hal/1.0/OmxObserver.cpp
deleted file mode 100644
index 4e946cd..0000000
--- a/media/libstagefright/omx/hal/1.0/OmxObserver.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-#include "OmxObserver.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
-
-// Methods from ::android::hardware::media::omx::V1_0::IOmxObserver follow.
-Return<void> OmxObserver::onMessages(const hidl_vec<Message>& messages) {
-    // TODO implement
-    return Void();
-}
-
-
-IOmxObserver* HIDL_FETCH_IOmxObserver(const char* /* name */) {
-    return new OmxObserver();
-}
-
-} // namespace implementation
-}  // namespace V1_0
-}  // namespace omx
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/OmxObserver.h b/media/libstagefright/omx/hal/1.0/OmxObserver.h
deleted file mode 100644
index 630cae3..0000000
--- a/media/libstagefright/omx/hal/1.0/OmxObserver.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXOBSERVER_H
-#define ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXOBSERVER_H
-
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::media::omx::V1_0::IOmxObserver;
-using ::android::hardware::media::omx::V1_0::Message;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct OmxObserver : public IOmxObserver {
-    // Methods from ::android::hardware::media::omx::V1_0::IOmxObserver follow.
-    Return<void> onMessages(const hidl_vec<Message>& messages) override;
-
-};
-
-extern "C" IOmxObserver* HIDL_FETCH_IOmxObserver(const char* name);
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace omx
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0__OMXOBSERVER_H
diff --git a/media/libstagefright/omx/hal/1.0/WGraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/WGraphicBufferSource.cpp
new file mode 100644
index 0000000..0ec31f2
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/WGraphicBufferSource.cpp
@@ -0,0 +1,124 @@
+#include "WGraphicBufferSource.h"
+#include "Conversion.h"
+#include "WOmxNode.h"
+#include <stagefright/foundation/ColorUtils.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using android::ColorUtils;
+
+// LWGraphicBufferSource
+LWGraphicBufferSource::LWGraphicBufferSource(
+        sp<TGraphicBufferSource> const& base) : mBase(base) {
+}
+
+::android::binder::Status LWGraphicBufferSource::configure(
+        const sp<IOMXNode>& omxNode, int32_t dataSpace) {
+    return toBinderStatus(mBase->configure(
+            new TWOmxNode(omxNode), toHardwareDataspace(dataSpace)));
+}
+
+::android::binder::Status LWGraphicBufferSource::setSuspend(bool suspend) {
+    return toBinderStatus(mBase->setSuspend(suspend));
+}
+
+::android::binder::Status LWGraphicBufferSource::setRepeatPreviousFrameDelayUs(
+        int64_t repeatAfterUs) {
+    return toBinderStatus(mBase->setRepeatPreviousFrameDelayUs(repeatAfterUs));
+}
+
+::android::binder::Status LWGraphicBufferSource::setMaxFps(float maxFps) {
+    return toBinderStatus(mBase->setMaxFps(maxFps));
+}
+
+::android::binder::Status LWGraphicBufferSource::setTimeLapseConfig(
+        int64_t timePerFrameUs, int64_t timePerCaptureUs) {
+    return toBinderStatus(mBase->setTimeLapseConfig(
+            timePerFrameUs, timePerCaptureUs));
+}
+
+::android::binder::Status LWGraphicBufferSource::setStartTimeUs(
+        int64_t startTimeUs) {
+    return toBinderStatus(mBase->setStartTimeUs(startTimeUs));
+}
+
+::android::binder::Status LWGraphicBufferSource::setColorAspects(
+        int32_t aspects) {
+    return toBinderStatus(mBase->setColorAspects(
+            toHardwareColorAspects(aspects)));
+}
+
+::android::binder::Status LWGraphicBufferSource::setTimeOffsetUs(
+        int64_t timeOffsetsUs) {
+    return toBinderStatus(mBase->setTimeOffsetUs(timeOffsetsUs));
+}
+
+::android::binder::Status LWGraphicBufferSource::signalEndOfInputStream() {
+    return toBinderStatus(mBase->signalEndOfInputStream());
+}
+
+::android::IBinder* LWGraphicBufferSource::onAsBinder() {
+    return nullptr;
+}
+
+// TWGraphicBufferSource
+TWGraphicBufferSource::TWGraphicBufferSource(
+        sp<LGraphicBufferSource> const& base) : mBase(base) {
+}
+
+Return<void> TWGraphicBufferSource::configure(
+        const sp<IOmxNode>& omxNode, Dataspace dataspace) {
+    return toHardwareStatus(mBase->configure(
+            new LWOmxNode(omxNode),
+            toRawDataspace(dataspace)));
+}
+
+Return<void> TWGraphicBufferSource::setSuspend(bool suspend) {
+    return toHardwareStatus(mBase->setSuspend(suspend));
+}
+
+Return<void> TWGraphicBufferSource::setRepeatPreviousFrameDelayUs(
+        int64_t repeatAfterUs) {
+    return toHardwareStatus(mBase->setRepeatPreviousFrameDelayUs(
+            repeatAfterUs));
+}
+
+Return<void> TWGraphicBufferSource::setMaxFps(float maxFps) {
+    return toHardwareStatus(mBase->setMaxFps(maxFps));
+}
+
+Return<void> TWGraphicBufferSource::setTimeLapseConfig(
+        int64_t timePerFrameUs, int64_t timePerCaptureUs) {
+    return toHardwareStatus(mBase->setTimeLapseConfig(
+            timePerFrameUs, timePerCaptureUs));
+}
+
+Return<void> TWGraphicBufferSource::setStartTimeUs(int64_t startTimeUs) {
+    return toHardwareStatus(mBase->setStartTimeUs(startTimeUs));
+}
+
+Return<void> TWGraphicBufferSource::setColorAspects(
+        const ColorAspects& aspects) {
+    return toHardwareStatus(mBase->setColorAspects(toCompactColorAspects(
+            aspects)));
+}
+
+Return<void> TWGraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
+    return toHardwareStatus(mBase->setTimeOffsetUs(timeOffsetUs));
+}
+
+Return<void> TWGraphicBufferSource::signalEndOfInputStream() {
+    return toHardwareStatus(mBase->signalEndOfInputStream());
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/WGraphicBufferSource.h b/media/libstagefright/omx/hal/1.0/WGraphicBufferSource.h
new file mode 100644
index 0000000..66977ad
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/WGraphicBufferSource.h
@@ -0,0 +1,92 @@
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
+
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <frameworks/native/include/binder/Binder.h>
+#include <IOMX.h>
+#include <android/IGraphicBufferSource.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+
+#include <android/hardware/graphics/common/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::media::omx::V1_0::ColorAspects;
+using ::android::hardware::media::omx::V1_0::IGraphicBufferSource;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+using ::android::IOMXNode;
+
+/**
+ * Wrapper classes for conversion
+ * ==============================
+ *
+ * Naming convention:
+ * - LW = Legacy Wrapper --- It wraps a Treble object inside a legacy object.
+ * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
+ */
+
+typedef ::android::IGraphicBufferSource LGraphicBufferSource;
+typedef ::android::hardware::media::omx::V1_0::IGraphicBufferSource
+        TGraphicBufferSource;
+
+struct LWGraphicBufferSource : public LGraphicBufferSource {
+    sp<TGraphicBufferSource> mBase;
+    LWGraphicBufferSource(sp<TGraphicBufferSource> const& base);
+    ::android::binder::Status configure(
+            const sp<IOMXNode>& omxNode, int32_t dataSpace) override;
+    ::android::binder::Status setSuspend(bool suspend) override;
+    ::android::binder::Status setRepeatPreviousFrameDelayUs(
+            int64_t repeatAfterUs) override;
+    ::android::binder::Status setMaxFps(float maxFps) override;
+    ::android::binder::Status setTimeLapseConfig(
+            int64_t timePerFrameUs, int64_t timePerCaptureUs) override;
+    ::android::binder::Status setStartTimeUs(int64_t startTimeUs) override;
+    ::android::binder::Status setColorAspects(int32_t aspects) override;
+    ::android::binder::Status setTimeOffsetUs(int64_t timeOffsetsUs) override;
+    ::android::binder::Status signalEndOfInputStream() override;
+protected:
+    ::android::IBinder* onAsBinder() override;
+};
+
+struct TWGraphicBufferSource : public TGraphicBufferSource {
+    sp<LGraphicBufferSource> mBase;
+    TWGraphicBufferSource(sp<LGraphicBufferSource> const& base);
+    Return<void> configure(
+            const sp<IOmxNode>& omxNode, Dataspace dataspace) override;
+    Return<void> setSuspend(bool suspend) override;
+    Return<void> setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
+    Return<void> setMaxFps(float maxFps) override;
+    Return<void> setTimeLapseConfig(
+            int64_t timePerFrameUs, int64_t timePerCaptureUs) override;
+    Return<void> setStartTimeUs(int64_t startTimeUs) override;
+    Return<void> setColorAspects(const ColorAspects& aspects) override;
+    Return<void> setTimeOffsetUs(int64_t timeOffsetUs) override;
+    Return<void> signalEndOfInputStream() override;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
diff --git a/media/libstagefright/omx/hal/1.0/WOmx.cpp b/media/libstagefright/omx/hal/1.0/WOmx.cpp
new file mode 100644
index 0000000..25bcfe9
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/WOmx.cpp
@@ -0,0 +1,95 @@
+#include "WOmx.h"
+#include "WOmxNode.h"
+#include "WOmxObserver.h"
+#include "Conversion.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+// LWOmx
+LWOmx::LWOmx(sp<IOmx> const& base) : mBase(base) {
+}
+
+status_t LWOmx::listNodes(List<IOMX::ComponentInfo>* list) {
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->listNodes(
+            [&fnStatus, list](
+                    Status status,
+                    hidl_vec<IOmx::ComponentInfo> const& nodeList) {
+                fnStatus = toStatusT(status);
+                list->clear();
+                for (size_t i = 0; i < nodeList.size(); ++i) {
+                    auto newInfo = list->insert(
+                            list->end(), IOMX::ComponentInfo());
+                    convertTo(&*newInfo, nodeList[i]);
+                }
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t LWOmx::allocateNode(
+        char const* name,
+        sp<IOMXObserver> const& observer,
+        sp<IOMXNode>* omxNode) {
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->allocateNode(
+            name, new TWOmxObserver(observer),
+            [&fnStatus, omxNode](Status status, sp<IOmxNode> const& node) {
+                fnStatus = toStatusT(status);
+                *omxNode = new LWOmxNode(node);
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t LWOmx::createInputSurface(
+        sp<::android::IGraphicBufferProducer>* /* bufferProducer */,
+        sp<::android::IGraphicBufferSource>* /* bufferSource */) {
+    // TODO: Implement.
+    return INVALID_OPERATION;
+}
+
+::android::IBinder* LWOmx::onAsBinder() {
+    return nullptr;
+}
+
+// TWOmx
+TWOmx::TWOmx(sp<IOMX> const& base) : mBase(base) {
+}
+
+Return<void> TWOmx::listNodes(listNodes_cb _hidl_cb) {
+    List<IOMX::ComponentInfo> lList;
+    Status status = toStatus(mBase->listNodes(&lList));
+
+    hidl_vec<IOmx::ComponentInfo> tList;
+    tList.resize(lList.size());
+    size_t i = 0;
+    for (auto const& lInfo : lList) {
+        convertTo(&(tList[i++]), lInfo);
+    }
+    _hidl_cb(status, tList);
+    return Void();
+}
+
+Return<void> TWOmx::allocateNode(
+        const hidl_string& name,
+        const sp<IOmxObserver>& observer,
+        allocateNode_cb _hidl_cb) {
+    sp<IOMXNode> omxNode;
+    Status status = toStatus(mBase->allocateNode(
+            name, new LWOmxObserver(observer), &omxNode));
+    _hidl_cb(status, new TWOmxNode(omxNode));
+    return Void();
+}
+
+// TODO: Add createInputSurface().
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/WOmx.h b/media/libstagefright/omx/hal/1.0/WOmx.h
new file mode 100644
index 0000000..b07c4f2
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/WOmx.h
@@ -0,0 +1,75 @@
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <IOMX.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::Status;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+using ::android::List;
+using ::android::IOMX;
+
+/**
+ * Wrapper classes for conversion
+ * ==============================
+ *
+ * Naming convention:
+ * - LW = Legacy Wrapper --- It wraps a Treble object inside a legacy object.
+ * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
+ */
+
+struct LWOmx : public IOMX {
+    sp<IOmx> mBase;
+    LWOmx(sp<IOmx> const& base);
+    status_t listNodes(List<IOMX::ComponentInfo>* list) override;
+    status_t allocateNode(
+            char const* name,
+            sp<IOMXObserver> const& observer,
+            sp<IOMXNode>* omxNode) override;
+    status_t createInputSurface(
+            sp<::android::IGraphicBufferProducer>* bufferProducer,
+            sp<::android::IGraphicBufferSource>* bufferSource) override;
+protected:
+    ::android::IBinder* onAsBinder() override;
+};
+
+struct TWOmx : public IOmx {
+    sp<IOMX> mBase;
+    TWOmx(sp<IOMX> const& base);
+    Return<void> listNodes(listNodes_cb _hidl_cb) override;
+    Return<void> allocateNode(
+            const hidl_string& name,
+            const sp<IOmxObserver>& observer,
+            allocateNode_cb _hidl_cb) override;
+
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
diff --git a/media/libstagefright/omx/hal/1.0/WOmxBufferSource.cpp b/media/libstagefright/omx/hal/1.0/WOmxBufferSource.cpp
new file mode 100644
index 0000000..79eb1be
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/WOmxBufferSource.cpp
@@ -0,0 +1,95 @@
+#include "WOmxBufferSource.h"
+#include "Conversion.h"
+#include <utils/String8.h>
+#include <cutils/native_handle.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+// LWOmxBufferSource
+LWOmxBufferSource::LWOmxBufferSource(sp<IOmxBufferSource> const& base) :
+    mBase(base) {
+}
+
+::android::binder::Status LWOmxBufferSource::onOmxExecuting() {
+    return toBinderStatus(mBase->onOmxExecuting());
+}
+
+::android::binder::Status LWOmxBufferSource::onOmxIdle() {
+    return toBinderStatus(mBase->onOmxIdle());
+}
+
+::android::binder::Status LWOmxBufferSource::onOmxLoaded() {
+    return toBinderStatus(mBase->onOmxLoaded());
+}
+
+::android::binder::Status LWOmxBufferSource::onInputBufferAdded(
+        int32_t bufferId) {
+    return toBinderStatus(mBase->onInputBufferAdded(
+            static_cast<uint32_t>(bufferId)));
+}
+
+::android::binder::Status LWOmxBufferSource::onInputBufferEmptied(
+        int32_t bufferId, OMXFenceParcelable const& fenceParcel) {
+    hidl_handle fence;
+    native_handle_t* fenceNh;
+    if (!wrapAs(&fence, &fenceNh, fenceParcel)) {
+        return ::android::binder::Status::fromExceptionCode(
+                ::android::binder::Status::EX_BAD_PARCELABLE,
+                "Invalid fence");
+    }
+    ::android::binder::Status status = toBinderStatus(
+            mBase->onInputBufferEmptied(
+            static_cast<uint32_t>(bufferId), fence));
+    if (native_handle_delete(fenceNh) != 0) {
+        return ::android::binder::Status::fromExceptionCode(
+                ::android::binder::Status::EX_NULL_POINTER,
+                "Cannot delete native handle");
+    }
+    return status;
+}
+
+::android::IBinder* LWOmxBufferSource::onAsBinder() {
+    return nullptr;
+}
+
+// TWOmxBufferSource
+TWOmxBufferSource::TWOmxBufferSource(sp<IOMXBufferSource> const& base) :
+    mBase(base) {
+}
+
+Return<void> TWOmxBufferSource::onOmxExecuting() {
+    return toHardwareStatus(mBase->onOmxExecuting());
+}
+
+Return<void> TWOmxBufferSource::onOmxIdle() {
+    return toHardwareStatus(mBase->onOmxIdle());
+}
+
+Return<void> TWOmxBufferSource::onOmxLoaded() {
+    return toHardwareStatus(mBase->onOmxLoaded());
+}
+
+Return<void> TWOmxBufferSource::onInputBufferAdded(uint32_t buffer) {
+    return toHardwareStatus(mBase->onInputBufferAdded(
+            static_cast<int32_t>(buffer)));
+}
+
+Return<void> TWOmxBufferSource::onInputBufferEmptied(
+        uint32_t buffer, hidl_handle const& fence) {
+    OMXFenceParcelable fenceParcelable;
+    wrapAs(&fenceParcelable, fence);
+    return toHardwareStatus(mBase->onInputBufferEmptied(
+            static_cast<int32_t>(buffer), fenceParcelable));
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/WOmxBufferSource.h b/media/libstagefright/omx/hal/1.0/WOmxBufferSource.h
new file mode 100644
index 0000000..3ba9453
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/WOmxBufferSource.h
@@ -0,0 +1,74 @@
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
+
+#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <frameworks/native/include/binder/Binder.h>
+#include <android/IOMXBufferSource.h>
+#include <OMXFenceParcelable.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::media::omx::V1_0::IOmxBufferSource;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+using ::android::OMXFenceParcelable;
+using ::android::IOMXBufferSource;
+
+/**
+ * Wrapper classes for conversion
+ * ==============================
+ *
+ * Naming convention:
+ * - LW = Legacy Wrapper --- It wraps a Treble object inside a legacy object.
+ * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
+ */
+
+struct LWOmxBufferSource : public IOMXBufferSource {
+    sp<IOmxBufferSource> mBase;
+    LWOmxBufferSource(sp<IOmxBufferSource> const& base);
+    ::android::binder::Status onOmxExecuting() override;
+    ::android::binder::Status onOmxIdle() override;
+    ::android::binder::Status onOmxLoaded() override;
+    ::android::binder::Status onInputBufferAdded(int32_t bufferID) override;
+    ::android::binder::Status onInputBufferEmptied(
+            int32_t bufferID, OMXFenceParcelable const& fenceParcel) override;
+protected:
+    ::android::IBinder* onAsBinder() override;
+};
+
+struct TWOmxBufferSource : public IOmxBufferSource {
+    sp<IOMXBufferSource> mBase;
+    TWOmxBufferSource(sp<IOMXBufferSource> const& base);
+    Return<void> onOmxExecuting() override;
+    Return<void> onOmxIdle() override;
+    Return<void> onOmxLoaded() override;
+    Return<void> onInputBufferAdded(uint32_t buffer) override;
+    Return<void> onInputBufferEmptied(
+            uint32_t buffer, hidl_handle const& fence) override;
+};
+
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
diff --git a/media/libstagefright/omx/hal/1.0/WOmxNode.cpp b/media/libstagefright/omx/hal/1.0/WOmxNode.cpp
new file mode 100644
index 0000000..0e781d8
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/WOmxNode.cpp
@@ -0,0 +1,421 @@
+#include <IOMX.h>
+#include <OMXNodeInstance.h>
+#include "WOmxNode.h"
+#include "WOmxBufferSource.h"
+#include "Conversion.h"
+
+#include <algorithm>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::Void;
+
+// LWOmxNode
+LWOmxNode::LWOmxNode(sp<IOmxNode> const& base) : mBase(base) {
+}
+
+status_t LWOmxNode::freeNode() {
+    return toStatusT(mBase->freeNode());
+}
+
+status_t LWOmxNode::sendCommand(
+        OMX_COMMANDTYPE cmd, OMX_S32 param) {
+    return toStatusT(mBase->sendCommand(
+            toRawCommandType(cmd), param));
+}
+
+status_t LWOmxNode::getParameter(
+        OMX_INDEXTYPE index, void *params, size_t size) {
+    hidl_vec<uint8_t> tParams = inHidlBytes(params, size);
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->getParameter(
+            toRawIndexType(index),
+            tParams,
+            [&fnStatus, params, size](
+                    Status status, hidl_vec<uint8_t> const& outParams) {
+                fnStatus = toStatusT(status);
+                std::copy(
+                        outParams.data(),
+                        outParams.data() + outParams.size(),
+                        static_cast<uint8_t*>(params));
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t LWOmxNode::setParameter(
+        OMX_INDEXTYPE index, const void *params, size_t size) {
+    hidl_vec<uint8_t> tParams = inHidlBytes(params, size);
+    tParams = inHidlBytes(params, size);
+    return toStatusT(mBase->setParameter(
+            toRawIndexType(index), tParams));
+}
+
+status_t LWOmxNode::getConfig(
+        OMX_INDEXTYPE index, void *params, size_t size) {
+    hidl_vec<uint8_t> tParams = inHidlBytes(params, size);
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->getConfig(
+            toRawIndexType(index),
+            tParams,
+            [&fnStatus, params, size](
+                    Status status, hidl_vec<uint8_t> const& outParams) {
+                fnStatus = toStatusT(status);
+                std::copy(
+                        outParams.data(),
+                        outParams.data() + size,
+                        static_cast<uint8_t*>(params));
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t LWOmxNode::setConfig(
+        OMX_INDEXTYPE index, const void *params, size_t size) {
+    hidl_vec<uint8_t> tParams = inHidlBytes(params, size);
+    return toStatusT(mBase->setConfig(toRawIndexType(index), tParams));
+}
+
+status_t LWOmxNode::setPortMode(
+        OMX_U32 port_index, IOMX::PortMode mode) {
+    return toStatusT(mBase->setPortMode(port_index, toHardwarePortMode(mode)));
+}
+
+status_t LWOmxNode::prepareForAdaptivePlayback(
+        OMX_U32 portIndex, OMX_BOOL enable,
+        OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
+    return toStatusT(mBase->prepareForAdaptivePlayback(
+            portIndex, toRawBool(enable), maxFrameWidth, maxFrameHeight));
+}
+
+status_t LWOmxNode::configureVideoTunnelMode(
+        OMX_U32 portIndex, OMX_BOOL tunneled,
+        OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->configureVideoTunnelMode(
+            portIndex,
+            toRawBool(tunneled),
+            audioHwSync,
+            [&fnStatus, sidebandHandle](
+                    Status status, hidl_handle const& outSidebandHandle) {
+                fnStatus = toStatusT(status);
+                *sidebandHandle = native_handle_clone(outSidebandHandle);
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t LWOmxNode::getGraphicBufferUsage(
+        OMX_U32 portIndex, OMX_U32* usage) {
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->getGraphicBufferUsage(
+            portIndex,
+            [&fnStatus, usage](
+                    Status status, uint32_t outUsage) {
+                fnStatus = toStatusT(status);
+                *usage = outUsage;
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t LWOmxNode::setInputSurface(
+        const sp<IOMXBufferSource> &bufferSource) {
+    return toStatusT(mBase->setInputSurface(
+            new TWOmxBufferSource(bufferSource)));
+}
+
+status_t LWOmxNode::allocateSecureBuffer(
+        OMX_U32 portIndex, size_t size, buffer_id *buffer,
+        void **buffer_data, sp<NativeHandle> *native_handle) {
+    *buffer_data = nullptr;
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->allocateSecureBuffer(
+            portIndex,
+            static_cast<uint64_t>(size),
+            [&fnStatus, buffer, buffer_data, native_handle](
+                    Status status,
+                    uint32_t outBuffer,
+                    hidl_handle const& outNativeHandle) {
+                fnStatus = toStatusT(status);
+                *buffer = outBuffer;
+                *native_handle = NativeHandle::create(
+                        native_handle_clone(outNativeHandle), true);
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t LWOmxNode::useBuffer(
+        OMX_U32 portIndex, const OMXBuffer &omxBuffer, buffer_id *buffer) {
+    CodecBuffer codecBuffer;
+    if (!wrapAs(&codecBuffer, omxBuffer)) {
+        return BAD_VALUE;
+    }
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->useBuffer(
+            portIndex,
+            codecBuffer,
+            [&fnStatus, buffer](Status status, uint32_t outBuffer) {
+                fnStatus = toStatusT(status);
+                *buffer = outBuffer;
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t LWOmxNode::freeBuffer(
+        OMX_U32 portIndex, buffer_id buffer) {
+    return toStatusT(mBase->freeBuffer(portIndex, buffer));
+}
+
+status_t LWOmxNode::fillBuffer(
+        buffer_id buffer, const OMXBuffer &omxBuffer, int fenceFd) {
+    CodecBuffer codecBuffer;
+    if (!wrapAs(&codecBuffer, omxBuffer)) {
+        return BAD_VALUE;
+    }
+    native_handle_t* fenceNh = native_handle_create_from_fd(fenceFd);
+    if (!fenceNh) {
+        return NO_MEMORY;
+    }
+    status_t status = toStatusT(mBase->fillBuffer(
+            buffer, codecBuffer, fenceNh));
+    native_handle_delete(fenceNh);
+    return status;
+}
+
+status_t LWOmxNode::emptyBuffer(
+        buffer_id buffer, const OMXBuffer &omxBuffer,
+        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
+    CodecBuffer codecBuffer;
+    if (!wrapAs(&codecBuffer, omxBuffer)) {
+        return BAD_VALUE;
+    }
+    native_handle_t* fenceNh = native_handle_create_from_fd(fenceFd);
+    if (!fenceNh) {
+        return NO_MEMORY;
+    }
+    status_t status = toStatusT(mBase->emptyBuffer(
+            buffer,
+            codecBuffer,
+            flags,
+            toRawTicks(timestamp),
+            fenceNh));
+    native_handle_delete(fenceNh);
+    return status;
+}
+status_t LWOmxNode::getExtensionIndex(
+        const char *parameter_name,
+        OMX_INDEXTYPE *index) {
+    status_t fnStatus;
+    status_t transStatus = toStatusT(mBase->getExtensionIndex(
+            hidl_string(parameter_name),
+            [&fnStatus, index](Status status, uint32_t outIndex) {
+                fnStatus = toStatusT(status);
+                *index = toEnumIndexType(outIndex);
+            }));
+    return transStatus == NO_ERROR ? fnStatus : transStatus;
+}
+
+status_t LWOmxNode::dispatchMessage(const omx_message &lMsg) {
+    Message tMsg;
+    native_handle_t* nh;
+    if (!wrapAs(&tMsg, &nh, lMsg)) {
+        return NO_MEMORY;
+    }
+    status_t status = toStatusT(mBase->dispatchMessage(tMsg));
+    native_handle_delete(nh);
+    return status;
+}
+
+// TODO: this is temporary, will be removed when quirks move to OMX side.
+status_t LWOmxNode::setQuirks(OMX_U32 /* quirks */) {
+    return NO_ERROR;
+}
+
+::android::IBinder* LWOmxNode::onAsBinder() {
+    return nullptr;
+}
+
+// TWOmxNode
+TWOmxNode::TWOmxNode(sp<IOMXNode> const& base) : mBase(base) {
+}
+
+Return<Status> TWOmxNode::freeNode() {
+    return toStatus(mBase->freeNode());
+}
+
+Return<Status> TWOmxNode::sendCommand(uint32_t cmd, int32_t param) {
+    return toStatus(mBase->sendCommand(toEnumCommandType(cmd), param));
+}
+
+Return<void> TWOmxNode::getParameter(
+        uint32_t index, hidl_vec<uint8_t> const& inParams,
+        getParameter_cb _hidl_cb) {
+    hidl_vec<uint8_t> params(inParams);
+    Status status = toStatus(mBase->getParameter(
+            toEnumIndexType(index),
+            static_cast<void*>(params.data()),
+            params.size()));
+    _hidl_cb(status, params);
+    return Void();
+}
+
+Return<Status> TWOmxNode::setParameter(
+        uint32_t index, hidl_vec<uint8_t> const& params) {
+    return toStatus(mBase->setParameter(
+            toEnumIndexType(index),
+            static_cast<void const*>(params.data()),
+            params.size()));
+}
+
+Return<void> TWOmxNode::getConfig(
+        uint32_t index, const hidl_vec<uint8_t>& inConfig,
+        getConfig_cb _hidl_cb) {
+    hidl_vec<uint8_t> config(inConfig);
+    Status status = toStatus(mBase->getConfig(
+            toEnumIndexType(index),
+            static_cast<void*>(config.data()),
+            config.size()));
+    _hidl_cb(status, config);
+    return Void();
+}
+
+Return<Status> TWOmxNode::setConfig(
+        uint32_t index, const hidl_vec<uint8_t>& config) {
+    return toStatus(mBase->setConfig(
+            toEnumIndexType(index),
+            static_cast<void const*>(config.data()),
+            config.size()));
+}
+
+Return<Status> TWOmxNode::setPortMode(uint32_t portIndex, PortMode mode) {
+    return toStatus(mBase->setPortMode(portIndex, toIOMXPortMode(mode)));
+}
+
+Return<Status> TWOmxNode::prepareForAdaptivePlayback(
+        uint32_t portIndex, bool enable,
+        uint32_t maxFrameWidth, uint32_t maxFrameHeight) {
+    return toStatus(mBase->prepareForAdaptivePlayback(
+            portIndex,
+            toEnumBool(enable),
+            maxFrameWidth,
+            maxFrameHeight));
+}
+
+Return<void> TWOmxNode::configureVideoTunnelMode(
+        uint32_t portIndex, bool tunneled, uint32_t audioHwSync,
+        configureVideoTunnelMode_cb _hidl_cb) {
+    native_handle_t* sidebandHandle;
+    Status status = toStatus(mBase->configureVideoTunnelMode(
+            portIndex,
+            toEnumBool(tunneled),
+            audioHwSync,
+            &sidebandHandle));
+    _hidl_cb(status, hidl_handle(sidebandHandle));
+    return Void();
+}
+
+Return<void> TWOmxNode::getGraphicBufferUsage(
+        uint32_t portIndex, getGraphicBufferUsage_cb _hidl_cb) {
+    OMX_U32 usage;
+    Status status = toStatus(mBase->getGraphicBufferUsage(
+            portIndex, &usage));
+    _hidl_cb(status, usage);
+    return Void();
+}
+
+Return<Status> TWOmxNode::setInputSurface(
+        const sp<IOmxBufferSource>& bufferSource) {
+    return toStatus(mBase->setInputSurface(new LWOmxBufferSource(
+            bufferSource)));
+}
+
+Return<void> TWOmxNode::allocateSecureBuffer(
+        uint32_t portIndex, uint64_t size,
+        allocateSecureBuffer_cb _hidl_cb) {
+    IOMX::buffer_id buffer;
+    void* bufferData;
+    sp<NativeHandle> nativeHandle;
+    Status status = toStatus(mBase->allocateSecureBuffer(
+            portIndex,
+            static_cast<size_t>(size),
+            &buffer,
+            &bufferData,
+            &nativeHandle));
+    _hidl_cb(status, buffer, nativeHandle->handle());
+    return Void();
+}
+
+Return<void> TWOmxNode::useBuffer(
+        uint32_t portIndex, const CodecBuffer& codecBuffer,
+        useBuffer_cb _hidl_cb) {
+    IOMX::buffer_id buffer;
+    OMXBuffer omxBuffer;
+    if (!convertTo(&omxBuffer, codecBuffer)) {
+        _hidl_cb(Status::BAD_VALUE, 0);
+        return Void();
+    }
+    Status status = toStatus(mBase->useBuffer(
+            portIndex, omxBuffer, &buffer));
+    _hidl_cb(status, buffer);
+    return Void();
+}
+
+Return<Status> TWOmxNode::freeBuffer(uint32_t portIndex, uint32_t buffer) {
+    return toStatus(mBase->freeBuffer(portIndex, buffer));
+}
+
+Return<Status> TWOmxNode::fillBuffer(
+        uint32_t buffer, const CodecBuffer& codecBuffer,
+        const hidl_handle& fence) {
+    OMXBuffer omxBuffer;
+    if (!convertTo(&omxBuffer, codecBuffer)) {
+        return Status::BAD_VALUE;
+    }
+    return toStatus(mBase->fillBuffer(
+            buffer,
+            omxBuffer,
+            native_handle_read_fd(fence)));
+}
+
+Return<Status> TWOmxNode::emptyBuffer(
+        uint32_t buffer, const CodecBuffer& codecBuffer, uint32_t flags,
+        uint64_t timestampUs, const hidl_handle& fence) {
+    OMXBuffer omxBuffer;
+    if (!convertTo(&omxBuffer, codecBuffer)) {
+        return Status::BAD_VALUE;
+    }
+    return toStatus(mBase->emptyBuffer(
+            buffer,
+            omxBuffer,
+            flags,
+            toOMXTicks(timestampUs),
+            native_handle_read_fd(fence)));
+}
+
+Return<void> TWOmxNode::getExtensionIndex(
+        const hidl_string& parameterName,
+        getExtensionIndex_cb _hidl_cb) {
+    OMX_INDEXTYPE index;
+    Status status = toStatus(mBase->getExtensionIndex(
+            parameterName, &index));
+    _hidl_cb(status, toRawIndexType(index));
+    return Void();
+}
+
+Return<Status> TWOmxNode::dispatchMessage(const Message& tMsg) {
+    omx_message lMsg;
+    if (!wrapAs(&lMsg, tMsg)) {
+        return Status::BAD_VALUE;
+    }
+    return toStatus(mBase->dispatchMessage(lMsg));
+}
+
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/WOmxNode.h b/media/libstagefright/omx/hal/1.0/WOmxNode.h
new file mode 100644
index 0000000..3a459d6
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/WOmxNode.h
@@ -0,0 +1,149 @@
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
+
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <utils/Errors.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::media::omx::V1_0::CodecBuffer;
+using ::android::hardware::media::omx::V1_0::IOmxBufferSource;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::media::omx::V1_0::PortMode;
+using ::android::hardware::media::omx::V1_0::Status;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+/**
+ * Wrapper classes for conversion
+ * ==============================
+ *
+ * Naming convention:
+ * - LW = Legacy Wrapper --- It wraps a Treble object inside a legacy object.
+ * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
+ */
+
+struct LWOmxNode : public IOMXNode {
+    sp<IOmxNode> mBase;
+    LWOmxNode(sp<IOmxNode> const& base);
+    status_t freeNode() override;
+    status_t sendCommand(
+            OMX_COMMANDTYPE cmd, OMX_S32 param) override;
+    status_t getParameter(
+            OMX_INDEXTYPE index, void *params, size_t size) override;
+    status_t setParameter(
+            OMX_INDEXTYPE index, const void *params, size_t size) override;
+    status_t getConfig(
+            OMX_INDEXTYPE index, void *params, size_t size) override;
+    status_t setConfig(
+            OMX_INDEXTYPE index, const void *params, size_t size) override;
+    status_t setPortMode(
+            OMX_U32 port_index, IOMX::PortMode mode) override;
+    status_t prepareForAdaptivePlayback(
+            OMX_U32 portIndex, OMX_BOOL enable,
+            OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) override;
+    status_t configureVideoTunnelMode(
+            OMX_U32 portIndex, OMX_BOOL tunneled,
+            OMX_U32 audioHwSync, native_handle_t **sidebandHandle) override;
+    status_t getGraphicBufferUsage(
+            OMX_U32 port_index, OMX_U32* usage) override;
+    status_t setInputSurface(
+            const sp<IOMXBufferSource> &bufferSource) override;
+    status_t allocateSecureBuffer(
+            OMX_U32 port_index, size_t size, buffer_id *buffer,
+            void **buffer_data, sp<NativeHandle> *native_handle) override;
+    status_t useBuffer(
+            OMX_U32 port_index, const OMXBuffer &omxBuf,
+            buffer_id *buffer) override;
+    status_t freeBuffer(
+            OMX_U32 port_index, buffer_id buffer) override;
+    status_t fillBuffer(
+            buffer_id buffer, const OMXBuffer &omxBuf,
+            int fenceFd = -1) override;
+    status_t emptyBuffer(
+            buffer_id buffer, const OMXBuffer &omxBuf,
+            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd = -1) override;
+    status_t getExtensionIndex(
+            const char *parameter_name,
+            OMX_INDEXTYPE *index) override;
+    status_t dispatchMessage(const omx_message &msg) override;
+
+    // TODO: this is temporary, will be removed when quirks move to OMX side.
+    status_t setQuirks(OMX_U32 quirks) override;
+protected:
+    ::android::IBinder* onAsBinder() override;
+};
+
+struct TWOmxNode : public IOmxNode {
+    sp<IOMXNode> mBase;
+    TWOmxNode(sp<IOMXNode> const& base);
+
+    Return<Status> freeNode() override;
+    Return<Status> sendCommand(uint32_t cmd, int32_t param) override;
+    Return<void> getParameter(
+            uint32_t index, hidl_vec<uint8_t> const& inParams,
+            getParameter_cb _hidl_cb) override;
+    Return<Status> setParameter(
+            uint32_t index, hidl_vec<uint8_t> const& params) override;
+    Return<void> getConfig(
+            uint32_t index, hidl_vec<uint8_t> const& inConfig,
+            getConfig_cb _hidl_cb) override;
+    Return<Status> setConfig(
+            uint32_t index, hidl_vec<uint8_t> const& config) override;
+    Return<Status> setPortMode(uint32_t portIndex, PortMode mode) override;
+    Return<Status> prepareForAdaptivePlayback(
+            uint32_t portIndex, bool enable,
+            uint32_t maxFrameWidth, uint32_t maxFrameHeight) override;
+    Return<void> configureVideoTunnelMode(
+            uint32_t portIndex, bool tunneled, uint32_t audioHwSync,
+            configureVideoTunnelMode_cb _hidl_cb) override;
+    Return<void> getGraphicBufferUsage(
+            uint32_t portIndex,
+            getGraphicBufferUsage_cb _hidl_cb) override;
+    Return<Status> setInputSurface(
+            sp<IOmxBufferSource> const& bufferSource) override;
+    Return<void> allocateSecureBuffer(
+            uint32_t portIndex, uint64_t size,
+            allocateSecureBuffer_cb _hidl_cb) override;
+    Return<void> useBuffer(
+            uint32_t portIndex, CodecBuffer const& codecBuffer,
+            useBuffer_cb _hidl_cb) override;
+    Return<Status> freeBuffer(uint32_t portIndex, uint32_t buffer) override;
+    Return<Status> fillBuffer(
+            uint32_t buffer, CodecBuffer const& codecBuffer,
+            const hidl_handle& fence) override;
+    Return<Status> emptyBuffer(
+            uint32_t buffer, CodecBuffer const& codecBuffer,
+            uint32_t flags, uint64_t timestampUs,
+            hidl_handle const& fence) override;
+    Return<void> getExtensionIndex(
+            hidl_string const& parameterName,
+            getExtensionIndex_cb _hidl_cb) override;
+    Return<Status> dispatchMessage(Message const& msg) override;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
diff --git a/media/libstagefright/omx/hal/1.0/WOmxObserver.cpp b/media/libstagefright/omx/hal/1.0/WOmxObserver.cpp
new file mode 100644
index 0000000..f3ad8d3
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/WOmxObserver.cpp
@@ -0,0 +1,59 @@
+#include "WOmxObserver.h"
+
+#include <vector>
+
+#include <cutils/native_handle.h>
+#include <frameworks/native/include/binder/Binder.h>
+
+#include "Conversion.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+// LWOmxObserver
+LWOmxObserver::LWOmxObserver(sp<IOmxObserver> const& base) : mBase(base) {
+}
+
+void LWOmxObserver::onMessages(std::list<omx_message> const& lMessages) {
+    hidl_vec<Message> tMessages;
+    std::vector<native_handle_t*> handles(lMessages.size());
+    tMessages.resize(lMessages.size());
+    size_t i = 0;
+    for (auto const& message : lMessages) {
+        wrapAs(&tMessages[i], &handles[i], message);
+        ++i;
+    }
+    mBase->onMessages(tMessages);
+    for (auto& handle : handles) {
+        native_handle_delete(handle);
+    }
+}
+
+::android::IBinder* LWOmxObserver::onAsBinder() {
+    return nullptr;
+}
+
+// TWOmxObserver
+TWOmxObserver::TWOmxObserver(sp<IOMXObserver> const& base) : mBase(base) {
+}
+
+Return<void> TWOmxObserver::onMessages(const hidl_vec<Message>& tMessages) {
+    std::list<omx_message> lMessages;
+    for (size_t i = 0; i < tMessages.size(); ++i) {
+        lMessages.push_back(omx_message{});
+        wrapAs(&lMessages.back(), tMessages[i]);
+    }
+    mBase->onMessages(lMessages);
+    return Return<void>();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/WOmxObserver.h b/media/libstagefright/omx/hal/1.0/WOmxObserver.h
new file mode 100644
index 0000000..c8ab296
--- /dev/null
+++ b/media/libstagefright/omx/hal/1.0/WOmxObserver.h
@@ -0,0 +1,62 @@
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
+
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <IOMX.h>
+#include <list>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+using ::android::IOMXObserver;
+using ::android::omx_message;
+
+/**
+ * Wrapper classes for conversion
+ * ==============================
+ *
+ * Naming convention:
+ * - LW = Legacy Wrapper --- It wraps a Treble object inside a legacy object.
+ * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
+ */
+
+struct LWOmxObserver : public IOMXObserver {
+    sp<IOmxObserver> mBase;
+    LWOmxObserver(sp<IOmxObserver> const& base);
+    void onMessages(std::list<omx_message> const& lMessages) override;
+protected:
+    ::android::IBinder* onAsBinder() override;
+};
+
+struct TWOmxObserver : public IOmxObserver {
+    sp<IOMXObserver> mBase;
+    TWOmxObserver(sp<IOMXObserver> const& base);
+    Return<void> onMessages(const hidl_vec<Message>& tMessages) override;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
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/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index cf30aa9..d08309b 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -547,7 +547,8 @@
         pid_t tid,
         audio_session_t *sessionId,
         int clientUid,
-        status_t *status)
+        status_t *status,
+        audio_port_handle_t portId)
 {
     sp<PlaybackThread::Track> track;
     sp<TrackHandle> trackHandle;
@@ -640,7 +641,8 @@
         ALOGV("createTrack() lSessionId: %d", lSessionId);
 
         track = thread->createTrack_l(client, streamType, sampleRate, format,
-                channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, clientUid, &lStatus);
+                channelMask, frameCount, sharedBuffer, lSessionId, flags, tid,
+                clientUid, &lStatus, portId);
         LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0));
         // we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
 
@@ -1445,7 +1447,8 @@
         size_t *notificationFrames,
         sp<IMemory>& cblk,
         sp<IMemory>& buffers,
-        status_t *status)
+        status_t *status,
+        audio_port_handle_t portId)
 {
     sp<RecordThread::RecordTrack> recordTrack;
     sp<RecordHandle> recordHandle;
@@ -1529,7 +1532,7 @@
 
         recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
                                                   frameCount, lSessionId, notificationFrames,
-                                                  clientUid, flags, tid, &lStatus);
+                                                  clientUid, flags, tid, &lStatus, portId);
         LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
 
         if (lStatus == NO_ERROR) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index aa8824e..ec58475 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -116,7 +116,8 @@
                                 pid_t tid,
                                 audio_session_t *sessionId,
                                 int clientUid,
-                                status_t *status /*non-NULL*/);
+                                status_t *status /*non-NULL*/,
+                                audio_port_handle_t portId);
 
     virtual sp<IAudioRecord> openRecord(
                                 audio_io_handle_t input,
@@ -133,7 +134,8 @@
                                 size_t *notificationFrames,
                                 sp<IMemory>& cblk,
                                 sp<IMemory>& buffers,
-                                status_t *status /*non-NULL*/);
+                                status_t *status /*non-NULL*/,
+                                audio_port_handle_t portId);
 
     virtual     uint32_t    sampleRate(audio_io_handle_t ioHandle) const;
     virtual     audio_format_t format(audio_io_handle_t output) const;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 128eaba..ff96b86 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1308,6 +1308,24 @@
     ALOGVV("command(), cmdCode: %d, mHasControl: %d, mEffect: %p",
             cmdCode, mHasControl, mEffect.unsafe_get());
 
+    if (cmdCode == EFFECT_CMD_ENABLE) {
+        if (*replySize < sizeof(int)) {
+            android_errorWriteLog(0x534e4554, "32095713");
+            return BAD_VALUE;
+        }
+        *(int *)pReplyData = NO_ERROR;
+        *replySize = sizeof(int);
+        return enable();
+    } else if (cmdCode == EFFECT_CMD_DISABLE) {
+        if (*replySize < sizeof(int)) {
+            android_errorWriteLog(0x534e4554, "32095713");
+            return BAD_VALUE;
+        }
+        *(int *)pReplyData = NO_ERROR;
+        *replySize = sizeof(int);
+        return disable();
+    }
+
     AutoMutex _l(mLock);
     sp<EffectModule> effect = mEffect.promote();
     if (effect == 0 || mDisconnected) {
@@ -1323,11 +1341,17 @@
 
     // handle commands that are not forwarded transparently to effect engine
     if (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) {
+        if (*replySize < sizeof(int)) {
+            android_errorWriteLog(0x534e4554, "32095713");
+            return BAD_VALUE;
+        }
+        *(int *)pReplyData = NO_ERROR;
+        *replySize = sizeof(int);
+
         // No need to trylock() here as this function is executed in the binder thread serving a
         // particular client process:  no risk to block the whole media server process or mixer
         // threads if we are stuck here
         Mutex::Autolock _l(mCblk->lock);
-
         // keep local copy of index in case of client corruption b/32220769
         const uint32_t clientIndex = mCblk->clientIndex;
         const uint32_t serverIndex = mCblk->serverIndex;
@@ -1390,12 +1414,6 @@
         mCblk->serverIndex = 0;
         mCblk->clientIndex = 0;
         return status;
-    } else if (cmdCode == EFFECT_CMD_ENABLE) {
-        *(int *)pReplyData = NO_ERROR;
-        return enable();
-    } else if (cmdCode == EFFECT_CMD_DISABLE) {
-        *(int *)pReplyData = NO_ERROR;
-        return disable();
     }
 
     return effect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 0bcb9a0..27e4627 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -34,7 +34,8 @@
                                 audio_session_t sessionId,
                                 uid_t uid,
                                 audio_output_flags_t flags,
-                                track_type type);
+                                track_type type,
+                                audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
     virtual             ~Track();
     virtual status_t    initCheck() const;
 
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 883ff6b..848e531 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -32,7 +32,8 @@
                                 audio_session_t sessionId,
                                 uid_t uid,
                                 audio_input_flags_t flags,
-                                track_type type);
+                                track_type type,
+                                audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
     virtual             ~RecordTrack();
     virtual status_t    initCheck() const;
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 16f86c2..a06eacf 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1808,7 +1808,8 @@
         audio_output_flags_t *flags,
         pid_t tid,
         uid_t uid,
-        status_t *status)
+        status_t *status,
+        audio_port_handle_t portId)
 {
     size_t frameCount = *pFrameCount;
     sp<Track> track;
@@ -1990,7 +1991,7 @@
 
         track = new Track(this, client, streamType, sampleRate, format,
                           channelMask, frameCount, NULL, sharedBuffer,
-                          sessionId, uid, *flags, TrackBase::TYPE_DEFAULT);
+                          sessionId, uid, *flags, TrackBase::TYPE_DEFAULT, portId);
 
         lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
         if (lStatus != NO_ERROR) {
@@ -6439,7 +6440,8 @@
         uid_t uid,
         audio_input_flags_t *flags,
         pid_t tid,
-        status_t *status)
+        status_t *status,
+        audio_port_handle_t portId)
 {
     size_t frameCount = *pFrameCount;
     sp<RecordTrack> track;
@@ -6547,7 +6549,7 @@
 
         track = new RecordTrack(this, client, sampleRate,
                       format, channelMask, frameCount, NULL, sessionId, uid,
-                      *flags, TrackBase::TYPE_DEFAULT);
+                      *flags, TrackBase::TYPE_DEFAULT, portId);
 
         lStatus = track->initCheck();
         if (lStatus != NO_ERROR) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8607815..547cfd1 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -679,7 +679,8 @@
                                 audio_output_flags_t *flags,
                                 pid_t tid,
                                 uid_t uid,
-                                status_t *status /*non-NULL*/);
+                                status_t *status /*non-NULL*/,
+                                audio_port_handle_t portId);
 
                 AudioStreamOut* getOutput() const;
                 AudioStreamOut* clearOutput();
@@ -1448,7 +1449,8 @@
                     uid_t uid,
                     audio_input_flags_t *flags,
                     pid_t tid,
-                    status_t *status /*non-NULL*/);
+                    status_t *status /*non-NULL*/,
+                    audio_port_handle_t portId);
 
             status_t    start(RecordTrack* recordTrack,
                               AudioSystem::sync_event_t event,
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 4fcb596..9ca2d63 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -65,7 +65,8 @@
                                 uid_t uid,
                                 bool isOut,
                                 alloc_type alloc = ALLOC_CBLK,
-                                track_type type = TYPE_DEFAULT);
+                                track_type type = TYPE_DEFAULT,
+                                audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
     virtual             ~TrackBase();
     virtual status_t    initCheck() const;
 
@@ -163,6 +164,7 @@
     bool                mTerminated;
     track_type          mType;      // must be one of TYPE_DEFAULT, TYPE_OUTPUT, TYPE_PATCH ...
     audio_io_handle_t   mThreadIoHandle; // I/O handle of the thread the track is attached to
+    audio_port_handle_t mPortId; // unique ID for this track used by audio policy
 };
 
 // PatchProxyBufferProvider interface is implemented by PatchTrack and PatchRecord.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index e8e27e4..9746075 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -75,7 +75,8 @@
             uid_t clientUid,
             bool isOut,
             alloc_type alloc,
-            track_type type)
+            track_type type,
+            audio_port_handle_t portId)
     :   RefBase(),
         mThread(thread),
         mClient(client),
@@ -96,7 +97,8 @@
         mId(android_atomic_inc(&nextTrackId)),
         mTerminated(false),
         mType(type),
-        mThreadIoHandle(thread->id())
+        mThreadIoHandle(thread->id()),
+        mPortId(portId)
 {
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
     if (!isTrustedCallingUid(callingUid) || clientUid == AUDIO_UID_INVALID) {
@@ -343,12 +345,13 @@
             audio_session_t sessionId,
             uid_t uid,
             audio_output_flags_t flags,
-            track_type type)
+            track_type type,
+            audio_port_handle_t portId)
     :   TrackBase(thread, client, sampleRate, format, channelMask, frameCount,
                   (sharedBuffer != 0) ? sharedBuffer->pointer() : buffer,
                   sessionId, uid, true /*isOut*/,
                   (type == TYPE_PATCH) ? ( buffer == NULL ? ALLOC_LOCAL : ALLOC_NONE) : ALLOC_CBLK,
-                  type),
+                  type, portId),
     mFillingUpStatus(FS_INVALID),
     // mRetryCount initialized later when needed
     mSharedBuffer(sharedBuffer),
@@ -1477,13 +1480,14 @@
             audio_session_t sessionId,
             uid_t uid,
             audio_input_flags_t flags,
-            track_type type)
+            track_type type,
+            audio_port_handle_t portId)
     :   TrackBase(thread, client, sampleRate, format,
                   channelMask, frameCount, buffer, sessionId, uid, false /*isOut*/,
                   (type == TYPE_DEFAULT) ?
                           ((flags & AUDIO_INPUT_FLAG_FAST) ? ALLOC_PIPE : ALLOC_CBLK) :
                           ((buffer == NULL) ? ALLOC_LOCAL : ALLOC_NONE),
-                  type),
+                  type, portId),
         mOverflow(false),
         mFramesToDrop(0),
         mResamplerBufferProvider(NULL), // initialize in case of early constructor exit
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index a1420ff..7cd2b81 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -79,9 +79,7 @@
 LOCAL_SHARED_LIBRARIES += libmedia_helper
 
 ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
-LOCAL_STATIC_LIBRARIES += libxml2
-
-LOCAL_SHARED_LIBRARIES += libicuuc
+LOCAL_SHARED_LIBRARIES += libicuuc libxml2
 
 LOCAL_CFLAGS += -DUSE_XML_AUDIO_POLICY_CONF
 endif #ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index c60b49a..ff9e44c 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -116,12 +116,10 @@
                                         audio_session_t session,
                                         audio_stream_type_t *stream,
                                         uid_t uid,
-                                        uint32_t samplingRate,
-                                        audio_format_t format,
-                                        audio_channel_mask_t channelMask,
+                                        const audio_config_t *config,
                                         audio_output_flags_t flags,
                                         int selectedDeviceId,
-                                        const audio_offload_info_t *offloadInfo) = 0;
+                                        audio_port_handle_t *portId) = 0;
     // indicates to the audio policy manager that the output starts being used by corresponding stream.
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
@@ -140,12 +138,11 @@
                                      audio_io_handle_t *input,
                                      audio_session_t session,
                                      uid_t uid,
-                                     uint32_t samplingRate,
-                                     audio_format_t format,
-                                     audio_channel_mask_t channelMask,
+                                     const audio_config_base_t *config,
                                      audio_input_flags_t flags,
                                      audio_port_handle_t selectedDeviceId,
-                                     input_type_t *inputType) = 0;
+                                     input_type_t *inputType,
+                                     audio_port_handle_t *portId) = 0;
     // indicates to the audio policy manager that the input starts being used.
     virtual status_t startInput(audio_io_handle_t input,
                                 audio_session_t session,
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 02118c4..7968103 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -41,9 +41,7 @@
 
 LOCAL_SRC_FILES += src/Serializer.cpp
 
-LOCAL_STATIC_LIBRARIES += libxml2
-
-LOCAL_SHARED_LIBRARIES += libicuuc
+LOCAL_SHARED_LIBRARIES += libicuuc libxml2
 
 LOCAL_C_INCLUDES += \
     $(TOPDIR)external/libxml2/include \
diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk
index 341357c..5b43347 100644
--- a/services/audiopolicy/engineconfigurable/Android.mk
+++ b/services/audiopolicy/engineconfigurable/Android.mk
@@ -42,8 +42,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libaudiopolicypfwwrapper \
-    libaudiopolicycomponents \
-    libxml2
+    libaudiopolicycomponents
 
 LOCAL_SHARED_LIBRARIES := \
     liblog \
@@ -52,7 +51,8 @@
     liblog \
     libaudioutils \
     libparameter \
-    libmedia_helper
+    libmedia_helper \
+    libxml2
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
index 47dc545..b37b379 100644
--- a/services/audiopolicy/enginedefault/Android.mk
+++ b/services/audiopolicy/enginedefault/Android.mk
@@ -36,7 +36,6 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libaudiopolicycomponents \
-    libxml2
 
 LOCAL_SHARED_LIBRARIES += \
     liblog \
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index a714041..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);
@@ -718,12 +718,10 @@
                                               audio_session_t session,
                                               audio_stream_type_t *stream,
                                               uid_t uid,
-                                              uint32_t samplingRate,
-                                              audio_format_t format,
-                                              audio_channel_mask_t channelMask,
+                                              const audio_config_t *config,
                                               audio_output_flags_t flags,
                                               audio_port_handle_t selectedDeviceId,
-                                              const audio_offload_info_t *offloadInfo)
+                                              audio_port_handle_t *portId)
 {
     audio_attributes_t attributes;
     if (attr != NULL) {
@@ -741,10 +739,16 @@
         }
         stream_type_to_audio_attributes(*stream, &attributes);
     }
+
+    // TODO: check for existing client for this port ID
+    if (*portId == AUDIO_PORT_HANDLE_NONE) {
+        *portId = AudioPort::getNextUniqueId();
+    }
+
     sp<SwAudioOutputDescriptor> desc;
     if (mPolicyMixes.getOutputForAttr(attributes, uid, desc) == NO_ERROR) {
         ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr");
-        if (!audio_has_proportional_frames(format)) {
+        if (!audio_has_proportional_frames(config->format)) {
             return BAD_VALUE;
         }
         *stream = streamTypefromAttributesInt(&attributes);
@@ -782,11 +786,11 @@
     }
 
     ALOGV("getOutputForAttr() device 0x%x, samplingRate %d, format %x, channelMask %x, flags %x",
-          device, samplingRate, format, channelMask, flags);
+          device, config->sample_rate, config->format, config->channel_mask, flags);
 
     *output = getOutputForDevice(device, session, *stream,
-                                 samplingRate, format, channelMask,
-                                 flags, offloadInfo);
+                                 config->sample_rate, config->format, config->channel_mask,
+                                 flags, &config->offload_info);
     if (*output == AUDIO_IO_HANDLE_NONE) {
         mOutputRoutes.removeRoute(session);
         return INVALID_OPERATION;
@@ -1411,16 +1415,15 @@
                                              audio_io_handle_t *input,
                                              audio_session_t session,
                                              uid_t uid,
-                                             uint32_t samplingRate,
-                                             audio_format_t format,
-                                             audio_channel_mask_t channelMask,
+                                             const audio_config_base_t *config,
                                              audio_input_flags_t flags,
                                              audio_port_handle_t selectedDeviceId,
-                                             input_type_t *inputType)
+                                             input_type_t *inputType,
+                                             audio_port_handle_t *portId)
 {
     ALOGV("getInputForAttr() source %d, samplingRate %d, format %d, channelMask %x,"
             "session %d, flags %#x",
-          attr->source, samplingRate, format, channelMask, session, flags);
+          attr->source, config->sample_rate, config->format, config->channel_mask, session, flags);
 
     *input = AUDIO_IO_HANDLE_NONE;
     *inputType = API_INPUT_INVALID;
@@ -1437,6 +1440,11 @@
     }
     halInputSource = inputSource;
 
+    // TODO: check for existing client for this port ID
+    if (*portId == AUDIO_PORT_HANDLE_NONE) {
+        *portId = AudioPort::getNextUniqueId();
+    }
+
     // Explicit routing?
     sp<DeviceDescriptor> deviceDesc;
     for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
@@ -1486,12 +1494,13 @@
     }
 
     *input = getInputForDevice(device, address, session, uid, inputSource,
-                               samplingRate, format, channelMask, flags,
+                               config->sample_rate, config->format, config->channel_mask, flags,
                                policyMix);
     if (*input == AUDIO_IO_HANDLE_NONE) {
         mInputRoutes.removeRoute(session);
         return INVALID_OPERATION;
     }
+
     ALOGV("getInputForAttr() returns input type = %d", *inputType);
     return NO_ERROR;
 }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 52fa082..f440c37 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -111,12 +111,10 @@
                                           audio_session_t session,
                                           audio_stream_type_t *stream,
                                           uid_t uid,
-                                          uint32_t samplingRate,
-                                          audio_format_t format,
-                                          audio_channel_mask_t channelMask,
+                                          const audio_config_t *config,
                                           audio_output_flags_t flags,
                                           audio_port_handle_t selectedDeviceId,
-                                          const audio_offload_info_t *offloadInfo);
+                                          audio_port_handle_t *portId);
         virtual status_t startOutput(audio_io_handle_t output,
                                      audio_stream_type_t stream,
                                      audio_session_t session);
@@ -130,12 +128,11 @@
                                          audio_io_handle_t *input,
                                          audio_session_t session,
                                          uid_t uid,
-                                         uint32_t samplingRate,
-                                         audio_format_t format,
-                                         audio_channel_mask_t channelMask,
+                                         const audio_config_base_t *config,
                                          audio_input_flags_t flags,
                                          audio_port_handle_t selectedDeviceId,
-                                         input_type_t *inputType);
+                                         input_type_t *inputType,
+                                         audio_port_handle_t *portId);
 
         // indicates to the audio policy manager that the input starts being used.
         virtual status_t startInput(audio_io_handle_t input,
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 0c23080..be86cfa 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -151,12 +151,10 @@
                                               audio_session_t session,
                                               audio_stream_type_t *stream,
                                               uid_t uid,
-                                              uint32_t samplingRate,
-                                              audio_format_t format,
-                                              audio_channel_mask_t channelMask,
+                                              const audio_config_t *config,
                                               audio_output_flags_t flags,
                                               audio_port_handle_t selectedDeviceId,
-                                              const audio_offload_info_t *offloadInfo)
+                                              audio_port_handle_t *portId)
 {
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
@@ -170,8 +168,9 @@
                 "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
         uid = callingUid;
     }
-    return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, samplingRate,
-                                    format, channelMask, flags, selectedDeviceId, offloadInfo);
+    return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid,
+                                                 config,
+                                                 flags, selectedDeviceId, portId);
 }
 
 status_t AudioPolicyService::startOutput(audio_io_handle_t output,
@@ -262,11 +261,10 @@
                                              audio_session_t session,
                                              pid_t pid,
                                              uid_t uid,
-                                             uint32_t samplingRate,
-                                             audio_format_t format,
-                                             audio_channel_mask_t channelMask,
+                                             const audio_config_base_t *config,
                                              audio_input_flags_t flags,
-                                             audio_port_handle_t selectedDeviceId)
+                                             audio_port_handle_t selectedDeviceId,
+                                             audio_port_handle_t *portId)
 {
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
@@ -305,9 +303,9 @@
         Mutex::Autolock _l(mLock);
         // the audio_in_acoustics_t parameter is ignored by get_input()
         status = mAudioPolicyManager->getInputForAttr(attr, input, session, uid,
-                                                     samplingRate, format, channelMask,
+                                                     config,
                                                      flags, selectedDeviceId,
-                                                     &inputType);
+                                                     &inputType, portId);
         audioPolicyEffects = mAudioPolicyEffects;
 
         if (status == NO_ERROR) {
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 8eb4f2d..d800743 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -77,12 +77,10 @@
                                       audio_session_t session,
                                       audio_stream_type_t *stream,
                                       uid_t uid,
-                                      uint32_t samplingRate = 0,
-                                      audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                      audio_channel_mask_t channelMask = 0,
-                                      audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
-                                      audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
-                                      const audio_offload_info_t *offloadInfo = NULL);
+                                      const audio_config_t *config,
+                                      audio_output_flags_t flags,
+                                      audio_port_handle_t selectedDeviceId,
+                                      audio_port_handle_t *portId);
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
                                  audio_session_t session);
@@ -97,11 +95,10 @@
                                      audio_session_t session,
                                      pid_t pid,
                                      uid_t uid,
-                                     uint32_t samplingRate,
-                                     audio_format_t format,
-                                     audio_channel_mask_t channelMask,
+                                     const audio_config_base_t *config,
                                      audio_input_flags_t flags,
-                                     audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
+                                     audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
+                                     audio_port_handle_t *portId = NULL);
     virtual status_t startInput(audio_io_handle_t input,
                                 audio_session_t session);
     virtual status_t stopInput(audio_io_handle_t input,
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 86c48a4..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);
         }
     }
 
@@ -302,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;
@@ -332,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());
@@ -358,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)",
@@ -406,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);
@@ -427,7 +447,7 @@
     {
         Mutex::Autolock lock(mStatusListenerLock);
         for (auto& i : mListenerList) {
-            i->onTorchStatusChanged(newStatus, String16{cameraId});
+            i->onTorchStatusChanged(mapToInterface(newStatus), String16{cameraId});
         }
     }
 }
@@ -490,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__);
@@ -597,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,
@@ -607,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;
@@ -703,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:
@@ -834,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();
 
@@ -1045,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;
@@ -1348,7 +1325,7 @@
 
 Status CameraService::connectDevice(
         const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
-        int cameraId,
+        const String16& cameraId,
         const String16& clientPackageName,
         int clientUid,
         /*out*/
@@ -1356,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,
@@ -1374,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) {
 
@@ -1395,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());
@@ -1405,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) {
@@ -1419,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,
@@ -1509,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());
@@ -1534,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);
         }
     }
 
@@ -1613,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:
@@ -1629,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:
@@ -1637,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;
@@ -1649,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());
         }
@@ -2215,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
@@ -2235,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
@@ -2339,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;
 }
@@ -2722,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
 
@@ -2742,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);
                     }
@@ -2763,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();
@@ -2780,7 +2961,7 @@
 
 status_t CameraService::getTorchStatusLocked(
         const String8& cameraId,
-        int32_t *status) const {
+        TorchModeStatus *status) const {
     if (!status) {
         return BAD_VALUE;
     }
@@ -2795,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