Merge "Fix vts-hal-auto test"
diff --git a/audio/core/all-versions/vts/functional/5.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/5.0/AudioPrimaryHidlHalTest.cpp
new file mode 100644
index 0000000..bdb17cd
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/5.0/AudioPrimaryHidlHalTest.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 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 <math.h>
+
+// pull in all the <= 4.0 tests
+#include "4.0/AudioPrimaryHidlHalTest.cpp"
+
+TEST_P(InputStreamTest, SetMicrophoneDirection) {
+    doc::test("Make sure setMicrophoneDirection correctly handles valid & invalid arguments");
+
+    // MicrophoneDirection dir = MicrophoneDirection::FRONT;
+    for (MicrophoneDirection dir : android::hardware::hidl_enum_range<MicrophoneDirection>()) {
+        ASSERT_RESULT(okOrNotSupported, stream->setMicrophoneDirection(dir));
+    }
+
+    // Bogus values
+    for (auto dir : {42, -1, 4}) {
+        ASSERT_RESULT(invalidArgsOrNotSupported,
+                      stream->setMicrophoneDirection(MicrophoneDirection(dir)));
+    }
+}
+
+TEST_P(InputStreamTest, SetMicrophoneFieldDimension) {
+    doc::test("Make sure setMicrophoneFieldDimension correctly handles valid & invalid arguments");
+
+    // Valid zoom values -1.0 -> 1.0
+    float incr = 0.1f;
+    for (float val = -1.0f; val <= 1.0; val += incr) {
+        ASSERT_RESULT(okOrNotSupported, stream->setMicrophoneFieldDimension(val));
+    }
+
+    // Bogus values
+    for (float val = 1.0f + incr; val <= 10.0f; val += incr) {
+        ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(val));
+        ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(-val));
+    }
+    // Some extremes
+    ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(NAN));
+    ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(-NAN));
+    ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(INFINITY));
+    ASSERT_RESULT(invalidArgsOrNotSupported, stream->setMicrophoneFieldDimension(-INFINITY));
+}
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index 6498289..f434e42 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -73,8 +73,7 @@
     name: "VtsHalAudioV5_0TargetTest",
     defaults: ["VtsHalAudioTargetTest_defaults"],
     srcs: [
-        // for now the tests are the same as V4
-        "4.0/AudioPrimaryHidlHalTest.cpp",
+        "5.0/AudioPrimaryHidlHalTest.cpp",
     ],
     static_libs: [
         "android.hardware.audio@5.0",
diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp
index fd785df..f2d7a47 100644
--- a/camera/device/3.2/default/CameraDeviceSession.cpp
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -44,13 +44,15 @@
 static constexpr int METADATA_SHRINK_REL_THRESHOLD = 2;
 
 HandleImporter CameraDeviceSession::sHandleImporter;
+buffer_handle_t CameraDeviceSession::sEmptyBuffer = nullptr;
+
 const int CameraDeviceSession::ResultBatcher::NOT_BATCHED;
 
 CameraDeviceSession::CameraDeviceSession(
     camera3_device_t* device,
     const camera_metadata_t* deviceInfo,
     const sp<ICameraDeviceCallback>& callback) :
-        camera3_callback_ops({&sProcessCaptureResult, &sNotify}),
+        camera3_callback_ops({&sProcessCaptureResult, &sNotify, nullptr, nullptr}),
         mDevice(device),
         mDeviceVersion(device->common.version),
         mFreeBufEarly(shouldFreeBufEarly()),
@@ -246,10 +248,50 @@
     }
 }
 
+Status CameraDeviceSession::importBuffer(int32_t streamId,
+        uint64_t bufId, buffer_handle_t buf,
+        /*out*/buffer_handle_t** outBufPtr,
+        bool allowEmptyBuf) {
+
+    if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
+        if (allowEmptyBuf) {
+            *outBufPtr = &sEmptyBuffer;
+            return Status::OK;
+        } else {
+            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+            return Status::ILLEGAL_ARGUMENT;
+        }
+    }
+
+    Mutex::Autolock _l(mInflightLock);
+    CirculatingBuffers& cbs = mCirculatingBuffers[streamId];
+    if (cbs.count(bufId) == 0) {
+        // Register a newly seen buffer
+        buffer_handle_t importedBuf = buf;
+        sHandleImporter.importBuffer(importedBuf);
+        if (importedBuf == nullptr) {
+            ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
+            return Status::INTERNAL_ERROR;
+        } else {
+            cbs[bufId] = importedBuf;
+        }
+    }
+    *outBufPtr = &cbs[bufId];
+    return Status::OK;
+}
+
 Status CameraDeviceSession::importRequest(
         const CaptureRequest& request,
         hidl_vec<buffer_handle_t*>& allBufPtrs,
         hidl_vec<int>& allFences) {
+    return importRequestImpl(request, allBufPtrs, allFences);
+}
+
+Status CameraDeviceSession::importRequestImpl(
+        const CaptureRequest& request,
+        hidl_vec<buffer_handle_t*>& allBufPtrs,
+        hidl_vec<int>& allFences,
+        bool allowEmptyBuf) {
     bool hasInputBuf = (request.inputBuffer.streamId != -1 &&
             request.inputBuffer.bufferId != 0);
     size_t numOutputBufs = request.outputBuffers.size();
@@ -277,25 +319,15 @@
     }
 
     for (size_t i = 0; i < numBufs; i++) {
-        buffer_handle_t buf = allBufs[i];
-        uint64_t bufId = allBufIds[i];
-        CirculatingBuffers& cbs = mCirculatingBuffers[streamIds[i]];
-        if (cbs.count(bufId) == 0) {
-            if (buf == nullptr) {
-                ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
-                return Status::ILLEGAL_ARGUMENT;
-            }
-            // Register a newly seen buffer
-            buffer_handle_t importedBuf = buf;
-            sHandleImporter.importBuffer(importedBuf);
-            if (importedBuf == nullptr) {
-                ALOGE("%s: output buffer %zu is invalid!", __FUNCTION__, i);
-                return Status::INTERNAL_ERROR;
-            } else {
-                cbs[bufId] = importedBuf;
-            }
+        Status st = importBuffer(
+                streamIds[i], allBufIds[i], allBufs[i], &allBufPtrs[i],
+                // Disallow empty buf for input stream, otherwise follow
+                // the allowEmptyBuf argument.
+                (hasInputBuf && i == numOutputBufs) ? false : allowEmptyBuf);
+        if (st != Status::OK) {
+            // Detailed error logs printed in importBuffer
+            return st;
         }
-        allBufPtrs[i] = &cbs[bufId];
     }
 
     // All buffers are imported. Now validate output buffer acquire fences
@@ -1271,18 +1303,26 @@
         ATRACE_END();
 
         // free all imported buffers
+        Mutex::Autolock _l(mInflightLock);
         for(auto& pair : mCirculatingBuffers) {
             CirculatingBuffers& buffers = pair.second;
             for (auto& p2 : buffers) {
                 sHandleImporter.freeBuffer(p2.second);
             }
+            buffers.clear();
         }
+        mCirculatingBuffers.clear();
 
         mClosed = true;
     }
     return Void();
 }
 
+uint64_t CameraDeviceSession::getCapResultBufferId(const buffer_handle_t&, int) {
+    // No need to fill in bufferId by default
+    return BUFFER_ID_NO_BUFFER;
+}
+
 status_t CameraDeviceSession::constructCaptureResult(CaptureResult& result,
                                                  const camera3_capture_result *hal_result) {
     uint32_t frameNumber = hal_result->frame_number;
@@ -1396,6 +1436,14 @@
         result.outputBuffers[i].streamId =
                 static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
         result.outputBuffers[i].buffer = nullptr;
+        if (hal_result->output_buffers[i].buffer != nullptr) {
+            result.outputBuffers[i].bufferId = getCapResultBufferId(
+                    *(hal_result->output_buffers[i].buffer),
+                    result.outputBuffers[i].streamId);
+        } else {
+            result.outputBuffers[i].bufferId = 0;
+        }
+
         result.outputBuffers[i].status = (BufferStatus) hal_result->output_buffers[i].status;
         // skip acquire fence since it's of no use to camera service
         if (hal_result->output_buffers[i].release_fence != -1) {
diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h
index bcee259..a96c245 100644
--- a/camera/device/3.2/default/CameraDeviceSession.h
+++ b/camera/device/3.2/default/CameraDeviceSession.h
@@ -161,6 +161,7 @@
     std::map<uint32_t, bool> mInflightRawBoostPresent;
     ::android::hardware::camera::common::V1_0::helper::CameraMetadata mOverridenRequest;
 
+    static const uint64_t BUFFER_ID_NO_BUFFER = 0;
     // buffers currently ciculating between HAL and camera service
     // key: bufferId sent via HIDL interface
     // value: imported buffer_handle_t
@@ -171,6 +172,7 @@
     std::map<int, CirculatingBuffers> mCirculatingBuffers;
 
     static HandleImporter sHandleImporter;
+    static buffer_handle_t sEmptyBuffer;
 
     bool mInitFail;
     bool mFirstRequest = false;
@@ -301,11 +303,23 @@
     Status initStatus() const;
 
     // Validate and import request's input buffer and acquire fence
-    Status importRequest(
+    virtual Status importRequest(
             const CaptureRequest& request,
             hidl_vec<buffer_handle_t*>& allBufPtrs,
             hidl_vec<int>& allFences);
 
+    Status importRequestImpl(
+            const CaptureRequest& request,
+            hidl_vec<buffer_handle_t*>& allBufPtrs,
+            hidl_vec<int>& allFences,
+            // Optional argument for ICameraDeviceSession@3.5 impl
+            bool allowEmptyBuf = false);
+
+    Status importBuffer(int32_t streamId,
+            uint64_t bufId, buffer_handle_t buf,
+            /*out*/buffer_handle_t** outBufPtr,
+            bool allowEmptyBuf);
+
     static void cleanupInflightFences(
             hidl_vec<int>& allFences, size_t numFences);
 
@@ -332,6 +346,11 @@
     static callbacks_process_capture_result_t sProcessCaptureResult;
     static callbacks_notify_t sNotify;
 
+    // By default camera service uses frameNumber/streamId pair to retrieve the buffer that
+    // was sent to HAL. Override this implementation if HAL is using buffers from buffer management
+    // APIs to send output buffer.
+    virtual uint64_t getCapResultBufferId(const buffer_handle_t& buf, int streamId);
+
     status_t constructCaptureResult(CaptureResult& result,
                                 const camera3_capture_result *hal_result);
 
diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp
index f2e031c..e52577c 100644
--- a/camera/device/3.4/default/CameraDeviceSession.cpp
+++ b/camera/device/3.4/default/CameraDeviceSession.cpp
@@ -87,6 +87,14 @@
 Return<void> CameraDeviceSession::configureStreams_3_4(
         const StreamConfiguration& requestedConfiguration,
         ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb)  {
+    configureStreams_3_4_Impl(requestedConfiguration, _hidl_cb);
+    return Void();
+}
+
+void CameraDeviceSession::configureStreams_3_4_Impl(
+        const StreamConfiguration& requestedConfiguration,
+        ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb,
+        uint32_t streamConfigCounter)  {
     Status status = initStatus();
     HalStreamConfiguration outStreams;
 
@@ -97,7 +105,7 @@
                 ALOGE("%s: trying to configureStreams with physical camera id with V3.2 callback",
                         __FUNCTION__);
                 _hidl_cb(Status::INTERNAL_ERROR, outStreams);
-                return Void();
+                return;
             }
         }
     }
@@ -109,7 +117,7 @@
         ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!",
                 __FUNCTION__, mInflightBuffers.size());
         _hidl_cb(Status::INTERNAL_ERROR, outStreams);
-        return Void();
+        return;
     }
 
     if (!mInflightAETriggerOverrides.empty()) {
@@ -117,7 +125,7 @@
                 " trigger overrides!", __FUNCTION__,
                 mInflightAETriggerOverrides.size());
         _hidl_cb(Status::INTERNAL_ERROR, outStreams);
-        return Void();
+        return;
     }
 
     if (!mInflightRawBoostPresent.empty()) {
@@ -125,12 +133,12 @@
                 " boost overrides!", __FUNCTION__,
                 mInflightRawBoostPresent.size());
         _hidl_cb(Status::INTERNAL_ERROR, outStreams);
-        return Void();
+        return;
     }
 
     if (status != Status::OK) {
         _hidl_cb(status, outStreams);
-        return Void();
+        return;
     }
 
     const camera_metadata_t *paramBuffer = nullptr;
@@ -139,11 +147,12 @@
     }
 
     camera3_stream_configuration_t stream_list{};
+    stream_list.stream_configuration_counter = streamConfigCounter;
     hidl_vec<camera3_stream_t*> streams;
     stream_list.session_parameters = paramBuffer;
     if (!preProcessConfigurationLocked_3_4(requestedConfiguration, &stream_list, &streams)) {
         _hidl_cb(Status::INTERNAL_ERROR, outStreams);
-        return Void();
+        return;
     }
 
     ATRACE_BEGIN("camera3->configure_streams");
@@ -168,7 +177,7 @@
     }
 
     _hidl_cb(status, outStreams);
-    return Void();
+    return;
 }
 
 bool CameraDeviceSession::preProcessConfigurationLocked_3_4(
diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
index fdc8a5a..00500b1 100644
--- a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
+++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
@@ -87,6 +87,12 @@
     void postProcessConfigurationFailureLocked_3_4(
             const StreamConfiguration& requestedConfiguration);
 
+    void configureStreams_3_4_Impl(
+            const StreamConfiguration& requestedConfiguration,
+            ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb,
+            // Optional argument for ICameraDeviceSession@3.5 impl
+            uint32_t streamConfigCounter = 0);
+
     Return<void> processCaptureRequest_3_4(
             const hidl_vec<V3_4::CaptureRequest>& requests,
             const hidl_vec<V3_2::BufferCache>& cachesToRemove,
diff --git a/camera/device/3.5/default/CameraDeviceSession.cpp b/camera/device/3.5/default/CameraDeviceSession.cpp
index 963893a..0770f04 100644
--- a/camera/device/3.5/default/CameraDeviceSession.cpp
+++ b/camera/device/3.5/default/CameraDeviceSession.cpp
@@ -15,8 +15,10 @@
  */
 
 #define LOG_TAG "CamDevSession@3.5-impl"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
 #include <android/log.h>
 
+#include <vector>
 #include <utils/Trace.h>
 #include "CameraDeviceSession.h"
 
@@ -33,13 +35,26 @@
     const sp<V3_2::ICameraDeviceCallback>& callback) :
         V3_4::implementation::CameraDeviceSession(device, deviceInfo, callback) {
 
-    mHasCallback_3_5 = false;
+    mCallback_3_5 = nullptr;
 
     auto castResult = ICameraDeviceCallback::castFrom(callback);
     if (castResult.isOk()) {
         sp<ICameraDeviceCallback> callback3_5 = castResult;
         if (callback3_5 != nullptr) {
-            mHasCallback_3_5 = true;
+            mCallback_3_5 = callback3_5;
+        }
+    }
+
+    if (mCallback_3_5 != nullptr) {
+        camera_metadata_entry bufMgrVersion = mDeviceInfo.find(
+                ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION);
+        if (bufMgrVersion.count > 0) {
+            mSupportBufMgr = (bufMgrVersion.data.u8[0] ==
+                    ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+            if (mSupportBufMgr) {
+                request_stream_buffers = sRequestStreamBuffers;
+                return_stream_buffers = sReturnStreamBuffers;
+            }
         }
     }
 }
@@ -50,14 +65,297 @@
 Return<void> CameraDeviceSession::configureStreams_3_5(
         const StreamConfiguration& requestedConfiguration,
         ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb)  {
-    return configureStreams_3_4(requestedConfiguration.v3_4, _hidl_cb);
+    configureStreams_3_4_Impl(requestedConfiguration.v3_4, _hidl_cb,
+            requestedConfiguration.streamConfigCounter);
+    return Void();
 }
 
 Return<void> CameraDeviceSession::signalStreamFlush(
-        const hidl_vec<int32_t>& /*requests*/, uint32_t /*streamConfigCounter*/) {
+        const hidl_vec<int32_t>& streamIds, uint32_t streamConfigCounter) {
+    std::vector<camera3_stream_t*> streams(streamIds.size());
+    {
+        Mutex::Autolock _l(mInflightLock);
+        for (size_t i = 0; i < streamIds.size(); i++) {
+            int32_t id = streamIds[i];
+            if (mStreamMap.count(id) == 0) {
+                ALOGE("%s: unknown streamId %d", __FUNCTION__, id);
+                return Void();
+            }
+            streams[i] = &mStreamMap[id];
+        }
+    }
+    if (mDevice->ops->signal_stream_flush != nullptr) {
+        mDevice->ops->signal_stream_flush(mDevice,
+                streamConfigCounter, streams.size(), streams.data());
+    }
     return Void();
 }
 
+Status CameraDeviceSession::importRequest(
+        const CaptureRequest& request,
+        hidl_vec<buffer_handle_t*>& allBufPtrs,
+        hidl_vec<int>& allFences) {
+    if (mSupportBufMgr) {
+        return importRequestImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ true);
+    }
+    return importRequestImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ false);
+}
+
+void CameraDeviceSession::pushBufferId(
+        const buffer_handle_t& buf, uint64_t bufferId, int streamId) {
+    std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+
+    // emplace will return existing entry if there is one.
+    auto pair = mBufferIdMaps.emplace(streamId, BufferIdMap{});
+    BufferIdMap& bIdMap = pair.first->second;
+    bIdMap[buf] = bufferId;
+}
+
+uint64_t CameraDeviceSession::popBufferId(
+        const buffer_handle_t& buf, int streamId) {
+    std::lock_guard<std::mutex> lock(mBufferIdMapLock);
+
+    auto streamIt = mBufferIdMaps.find(streamId);
+    if (streamIt == mBufferIdMaps.end()) {
+        return BUFFER_ID_NO_BUFFER;
+    }
+    BufferIdMap& bIdMap = streamIt->second;
+    auto it = bIdMap.find(buf);
+    if (it == bIdMap.end()) {
+        return BUFFER_ID_NO_BUFFER;
+    }
+    uint64_t bufId = it->second;
+    bIdMap.erase(it);
+    if (bIdMap.empty()) {
+        mBufferIdMaps.erase(streamIt);
+    }
+    return bufId;
+}
+
+uint64_t CameraDeviceSession::getCapResultBufferId(const buffer_handle_t& buf, int streamId) {
+    if (mSupportBufMgr) {
+        return popBufferId(buf, streamId);
+    }
+    return BUFFER_ID_NO_BUFFER;
+}
+
+Camera3Stream* CameraDeviceSession::getStreamPointer(int32_t streamId) {
+    Mutex::Autolock _l(mInflightLock);
+    if (mStreamMap.count(streamId) == 0) {
+        ALOGE("%s: unknown streamId %d", __FUNCTION__, streamId);
+        return nullptr;
+    }
+    return &mStreamMap[streamId];
+}
+
+void CameraDeviceSession::cleanupInflightBufferFences(
+        std::vector<int>& fences, std::vector<std::pair<buffer_handle_t, int>>& bufs) {
+    hidl_vec<int> hFences = fences;
+    cleanupInflightFences(hFences, fences.size());
+    for (auto& p : bufs) {
+        popBufferId(p.first, p.second);
+    }
+}
+
+camera3_buffer_request_status_t CameraDeviceSession::requestStreamBuffers(
+        uint32_t num_buffer_reqs,
+        const camera3_buffer_request_t *buffer_reqs,
+        /*out*/uint32_t *num_returned_buf_reqs,
+        /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs) {
+    ATRACE_CALL();
+    *num_returned_buf_reqs = 0;
+    hidl_vec<BufferRequest> hBufReqs(num_buffer_reqs);
+    for (size_t i = 0; i < num_buffer_reqs; i++) {
+        hBufReqs[i].streamId =
+                static_cast<Camera3Stream*>(buffer_reqs[i].stream)->mId;
+        hBufReqs[i].numBuffersRequested = buffer_reqs[i].num_buffers_requested;
+    }
+
+    ATRACE_BEGIN("HIDL requestStreamBuffers");
+    BufferRequestStatus status;
+    hidl_vec<StreamBufferRet> bufRets;
+    auto err = mCallback_3_5->requestStreamBuffers(hBufReqs,
+            [&status, &bufRets]
+            (BufferRequestStatus s, const hidl_vec<StreamBufferRet>& rets) {
+                status = s;
+                bufRets = std::move(rets);
+            });
+    if (!err.isOk()) {
+        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+        return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+    }
+    ATRACE_END();
+
+    if (status == BufferRequestStatus::OK || status == BufferRequestStatus::FAILED_PARTIAL) {
+        if (bufRets.size() != num_buffer_reqs) {
+            ALOGE("%s: expect %d buffer requests returned, only got %zu",
+                    __FUNCTION__, num_buffer_reqs, bufRets.size());
+            return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+        }
+
+        for (size_t i = 0; i < num_buffer_reqs; i++) {
+            // maybe we can query all streams in one call to avoid frequent locking device here?
+            Camera3Stream* stream = getStreamPointer(bufRets[i].streamId);
+            if (stream == nullptr) {
+                ALOGE("%s: unknown streamId %d", __FUNCTION__, bufRets[i].streamId);
+                return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+            }
+            returned_buf_reqs[i].stream = stream;
+        }
+
+        std::vector<int> importedFences;
+        std::vector<std::pair<buffer_handle_t, int>> importedBuffers;
+        for (size_t i = 0; i < num_buffer_reqs; i++) {
+            int streamId = bufRets[i].streamId;
+            switch (bufRets[i].val.getDiscriminator()) {
+                case StreamBuffersVal::hidl_discriminator::error:
+                    returned_buf_reqs[i].num_output_buffers = 0;
+                    switch (bufRets[i].val.error()) {
+                        case StreamBufferRequestError::NO_BUFFER_AVAILABLE:
+                            returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_NO_BUFFER_AVAILABLE;
+                            break;
+                        case StreamBufferRequestError::MAX_BUFFER_EXCEEDED:
+                            returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_MAX_BUFFER_EXCEEDED;
+                            break;
+                        case StreamBufferRequestError::STREAM_DISCONNECTED:
+                            returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_STREAM_DISCONNECTED;
+                            break;
+                        case StreamBufferRequestError::UNKNOWN_ERROR:
+                            returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_UNKNOWN_ERROR;
+                            break;
+                        default:
+                            ALOGE("%s: Unknown StreamBufferRequestError %d",
+                                    __FUNCTION__, bufRets[i].val.error());
+                            cleanupInflightBufferFences(importedFences, importedBuffers);
+                            return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+                    }
+                    break;
+                case StreamBuffersVal::hidl_discriminator::buffers: {
+                    const hidl_vec<StreamBuffer>& hBufs = bufRets[i].val.buffers();
+                    camera3_stream_buffer_t* outBufs = returned_buf_reqs[i].output_buffers;
+                    for (size_t b = 0; b < hBufs.size(); b++) {
+                        const StreamBuffer& hBuf = hBufs[b];
+                        camera3_stream_buffer_t& outBuf = outBufs[b];
+                        // maybe add importBuffers API to avoid frequent locking device?
+                        Status s = importBuffer(streamId,
+                                hBuf.bufferId, hBuf.buffer.getNativeHandle(),
+                                /*out*/&(outBuf.buffer),
+                                /*allowEmptyBuf*/false);
+                        if (s != Status::OK) {
+                            ALOGE("%s: import stream %d bufferId %" PRIu64 " failed!",
+                                    __FUNCTION__, streamId, hBuf.bufferId);
+                            cleanupInflightBufferFences(importedFences, importedBuffers);
+                            // Buffer import should never fail - restart HAL since something is very
+                            // wrong.
+                            assert(false);
+                            return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+                        }
+
+                        pushBufferId(*(outBuf.buffer), hBuf.bufferId, streamId);
+                        importedBuffers.push_back(std::make_pair(*(outBuf.buffer), streamId));
+
+                        if (!sHandleImporter.importFence(
+                                hBuf.acquireFence,
+                                outBuf.acquire_fence)) {
+                            ALOGE("%s: stream %d bufferId %" PRIu64 "acquire fence is invalid",
+                                    __FUNCTION__, streamId, hBuf.bufferId);
+                            cleanupInflightBufferFences(importedFences, importedBuffers);
+                            return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+                        }
+                        importedFences.push_back(outBuf.acquire_fence);
+                        outBuf.stream = returned_buf_reqs[i].stream;
+                        outBuf.status = CAMERA3_BUFFER_STATUS_OK;
+                        outBuf.release_fence = -1;
+                    }
+                    returned_buf_reqs[i].status = CAMERA3_PS_BUF_REQ_OK;
+                } break;
+                default:
+                    ALOGE("%s: unknown StreamBuffersVal discrimator!", __FUNCTION__);
+                    cleanupInflightBufferFences(importedFences, importedBuffers);
+                    return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+            }
+        }
+
+        *num_returned_buf_reqs = num_buffer_reqs;
+
+        return (status == BufferRequestStatus::OK) ?
+                CAMERA3_BUF_REQ_OK : CAMERA3_BUF_REQ_FAILED_PARTIAL;
+    }
+
+    switch (status) {
+        case BufferRequestStatus::FAILED_CONFIGURING:
+            return CAMERA3_BUF_REQ_FAILED_CONFIGURING;
+        case BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS:
+            return CAMERA3_BUF_REQ_FAILED_ILLEGAL_ARGUMENTS;
+        case BufferRequestStatus::FAILED_UNKNOWN:
+        default:
+            return CAMERA3_BUF_REQ_FAILED_UNKNOWN;
+    }
+}
+
+void CameraDeviceSession::returnStreamBuffers(
+        uint32_t num_buffers,
+        const camera3_stream_buffer_t* const* buffers) {
+    ATRACE_CALL();
+    hidl_vec<StreamBuffer> hBufs(num_buffers);
+
+    for (size_t i = 0; i < num_buffers; i++) {
+        hBufs[i].streamId =
+                static_cast<Camera3Stream*>(buffers[i]->stream)->mId;
+        hBufs[i].buffer = nullptr; // use bufferId
+        hBufs[i].bufferId = popBufferId(*(buffers[i]->buffer), hBufs[i].streamId);
+        if (hBufs[i].bufferId == BUFFER_ID_NO_BUFFER) {
+            ALOGE("%s: unknown buffer is returned to stream %d",
+                    __FUNCTION__, hBufs[i].streamId);
+        }
+        // ERROR since the buffer is not for application to consume
+        hBufs[i].status = BufferStatus::ERROR;
+        // skip acquire fence since it's of no use to camera service
+        if (buffers[i]->release_fence != -1) {
+            native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+            handle->data[0] = buffers[i]->release_fence;
+            hBufs[i].releaseFence.setTo(handle, /*shouldOwn*/true);
+        }
+    }
+
+    mCallback_3_5->returnStreamBuffers(hBufs);
+    return;
+}
+
+/**
+ * Static callback forwarding methods from HAL to instance
+ */
+camera3_buffer_request_status_t CameraDeviceSession::sRequestStreamBuffers(
+        const struct camera3_callback_ops *cb,
+        uint32_t num_buffer_reqs,
+        const camera3_buffer_request_t *buffer_reqs,
+        /*out*/uint32_t *num_returned_buf_reqs,
+        /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs) {
+    CameraDeviceSession *d =
+            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+
+    if (num_buffer_reqs == 0 || buffer_reqs == nullptr || num_returned_buf_reqs == nullptr ||
+            returned_buf_reqs == nullptr) {
+        ALOGE("%s: bad argument: numBufReq %d, bufReqs %p, numRetBufReq %p, retBufReqs %p",
+                __FUNCTION__, num_buffer_reqs, buffer_reqs,
+                num_returned_buf_reqs, returned_buf_reqs);
+        return CAMERA3_BUF_REQ_FAILED_ILLEGAL_ARGUMENTS;
+    }
+
+    return d->requestStreamBuffers(num_buffer_reqs, buffer_reqs,
+            num_returned_buf_reqs, returned_buf_reqs);
+}
+
+void CameraDeviceSession::sReturnStreamBuffers(
+        const struct camera3_callback_ops *cb,
+        uint32_t num_buffers,
+        const camera3_stream_buffer_t* const* buffers) {
+    CameraDeviceSession *d =
+            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+
+    d->returnStreamBuffers(num_buffers, buffers);
+}
+
 } // namespace implementation
 }  // namespace V3_5
 }  // namespace device
diff --git a/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h b/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h
index ec34769..4f7284c 100644
--- a/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h
+++ b/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h
@@ -21,6 +21,7 @@
 #include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
 #include <../../3.4/default/include/device_v3_4_impl/CameraDeviceSession.h>
+#include <unordered_map>
 
 namespace android {
 namespace hardware {
@@ -30,11 +31,14 @@
 namespace implementation {
 
 using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::device::V3_2::BufferStatus;
 using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::StreamBuffer;
 using ::android::hardware::camera::device::V3_5::StreamConfiguration;
 using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
 using ::android::hardware::camera::device::V3_5::ICameraDeviceSession;
 using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::implementation::Camera3Stream;
 using ::android::hardware::camera::common::V1_0::Status;
 using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
 using ::android::hardware::Return;
@@ -44,6 +48,25 @@
 using ::android::sp;
 using ::android::Mutex;
 
+
+/**
+ * Function pointer types with C calling convention to
+ * use for HAL callback functions.
+ */
+extern "C" {
+    typedef camera3_buffer_request_status_t (callbacks_request_stream_buffer_t)(
+            const struct camera3_callback_ops *,
+            uint32_t num_buffer_reqs,
+            const camera3_buffer_request_t *buffer_reqs,
+            /*out*/uint32_t *num_returned_buf_reqs,
+            /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs);
+
+    typedef void (callbacks_return_stream_buffer_t)(
+            const struct camera3_callback_ops *,
+            uint32_t num_buffers,
+            const camera3_stream_buffer_t* const* buffers);
+}
+
 struct CameraDeviceSession : public V3_4::implementation::CameraDeviceSession {
 
     CameraDeviceSession(camera3_device_t*,
@@ -62,12 +85,85 @@
             ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb);
 
     Return<void> signalStreamFlush(
-            const hidl_vec<int32_t>& requests,
+            const hidl_vec<int32_t>& streamIds,
             uint32_t streamConfigCounter);
 
+    virtual Status importRequest(
+            const CaptureRequest& request,
+            hidl_vec<buffer_handle_t*>& allBufPtrs,
+            hidl_vec<int>& allFences) override;
 
-    // Whether this camera device session is created with version 3.5 callback.
-    bool mHasCallback_3_5;
+    /**
+     * Static callback forwarding methods from HAL to instance
+     */
+    static callbacks_request_stream_buffer_t sRequestStreamBuffers;
+    static callbacks_return_stream_buffer_t sReturnStreamBuffers;
+
+    camera3_buffer_request_status_t requestStreamBuffers(
+            uint32_t num_buffer_reqs,
+            const camera3_buffer_request_t *buffer_reqs,
+            /*out*/uint32_t *num_returned_buf_reqs,
+            /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs);
+
+    void returnStreamBuffers(
+            uint32_t num_buffers,
+            const camera3_stream_buffer_t* const* buffers);
+
+    struct BufferHasher {
+        size_t operator()(const buffer_handle_t& buf) const {
+            if (buf == nullptr)
+                return 0;
+
+            size_t result = 1;
+            result = 31 * result + buf->numFds;
+            for (int i = 0; i < buf->numFds; i++) {
+                result = 31 * result + buf->data[i];
+            }
+            return result;
+        }
+    };
+
+    struct BufferComparator {
+        bool operator()(const buffer_handle_t& buf1, const buffer_handle_t& buf2) const {
+            if (buf1->numFds == buf2->numFds) {
+                for (int i = 0; i < buf1->numFds; i++) {
+                    if (buf1->data[i] != buf2->data[i]) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+            return false;
+        }
+    };
+
+    Camera3Stream* getStreamPointer(int32_t streamId);
+
+    // Register buffer to mBufferIdMaps so we can find corresponding bufferId
+    // when the buffer is returned to camera service
+    void pushBufferId(const buffer_handle_t& buf, uint64_t bufferId, int streamId);
+
+    // Method to pop buffer's bufferId from mBufferIdMaps
+    // BUFFER_ID_NO_BUFFER is returned if no matching buffer is found
+    uint64_t popBufferId(const buffer_handle_t& buf, int streamId);
+
+    // Method to cleanup imported buffer/fences if requestStreamBuffers fails half way
+    void cleanupInflightBufferFences(
+            std::vector<int>& fences, std::vector<std::pair<buffer_handle_t, int>>& bufs);
+
+    // Overrides the default constructCaptureResult behavior for buffer management APIs
+    virtual uint64_t getCapResultBufferId(const buffer_handle_t& buf, int streamId) override;
+
+    std::mutex mBufferIdMapLock; // protecting mBufferIdMaps and mNextBufferId
+    typedef std::unordered_map<const buffer_handle_t, uint64_t,
+            BufferHasher, BufferComparator> BufferIdMap;
+    // stream ID -> per stream buffer ID map for buffers coming from requestStreamBuffers API
+    // Entries are created during requestStreamBuffers when a stream first request a buffer, and
+    // deleted in returnStreamBuffers/processCaptureResult* when all buffers are returned
+    std::unordered_map<int, BufferIdMap> mBufferIdMaps;
+
+    sp<ICameraDeviceCallback> mCallback_3_5;
+    bool mSupportBufMgr;
 
 private:
 
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp
index f143dd7..e02cc7e 100644
--- a/camera/provider/2.4/default/CameraProvider.cpp
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -41,11 +41,8 @@
 const char *kExternalProviderName = "external/0";
 // "device@<version>/legacy/<id>"
 const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/legacy/(.+)");
-const char *kHAL3_2 = "3.2";
-const char *kHAL3_3 = "3.3";
 const char *kHAL3_4 = "3.4";
 const char *kHAL3_5 = "3.5";
-const char *kHAL1_0 = "1.0";
 const int kMaxCameraDeviceNameLen = 128;
 const int kMaxCameraIdLen = 16;
 
@@ -226,22 +223,6 @@
     return cameraId;
 }
 
-int CameraProvider::getCameraDeviceVersion(const hidl_string& deviceName) {
-    std::string deviceVersion;
-    bool match = matchDeviceName(deviceName, &deviceVersion, nullptr);
-    if (!match) {
-        return -1;
-    }
-    if (deviceVersion == kHAL3_3) {
-        return CAMERA_DEVICE_API_VERSION_3_3;
-    } else if (deviceVersion == kHAL3_2) {
-        return CAMERA_DEVICE_API_VERSION_3_2;
-    } else if (deviceVersion == kHAL1_0) {
-        return CAMERA_DEVICE_API_VERSION_1_0;
-    }
-    return 0;
-}
-
 std::string CameraProvider::getHidlDeviceName(
         std::string cameraId, int deviceVersion) {
     // Maybe consider create a version check method and SortedVec to speed up?
@@ -249,9 +230,16 @@
             deviceVersion != CAMERA_DEVICE_API_VERSION_3_2 &&
             deviceVersion != CAMERA_DEVICE_API_VERSION_3_3 &&
             deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 &&
-            deviceVersion != CAMERA_DEVICE_API_VERSION_3_5) {
+            deviceVersion != CAMERA_DEVICE_API_VERSION_3_5 &&
+            deviceVersion != CAMERA_DEVICE_API_VERSION_3_6) {
         return hidl_string("");
     }
+
+    // Supported combinations:
+    // CAMERA_DEVICE_API_VERSION_1_0 -> ICameraDevice@1.0
+    // CAMERA_DEVICE_API_VERSION_3_[2-4] -> ICameraDevice@[3.2|3.3]
+    // CAMERA_DEVICE_API_VERSION_3_5 + CAMERA_MODULE_API_VERSION_2_4 -> ICameraDevice@3.4
+    // CAMERA_DEVICE_API_VERSION_3_[5-6] + CAMERA_MODULE_API_VERSION_2_5 -> ICameraDevice@3.5
     bool isV1 = deviceVersion == CAMERA_DEVICE_API_VERSION_1_0;
     int versionMajor = isV1 ? 1 : 3;
     int versionMinor = isV1 ? 0 : mPreferredHal3MinorVersion;
@@ -261,6 +249,8 @@
         } else {
             versionMinor = 4;
         }
+    } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_6) {
+        versionMinor = 5;
     }
     char deviceName[kMaxCameraDeviceNameLen];
     snprintf(deviceName, sizeof(deviceName), "device@%d.%d/legacy/%s",
@@ -360,7 +350,8 @@
 
     // device_version undefined in CAMERA_MODULE_API_VERSION_1_0,
     // All CAMERA_MODULE_API_VERSION_1_0 devices are backward-compatible
-    if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0) {
+    uint16_t moduleVersion = mModule->getModuleApiVersion();
+    if (moduleVersion >= CAMERA_MODULE_API_VERSION_2_0) {
         // Verify the device version is in the supported range
         switch (info.device_version) {
             case CAMERA_DEVICE_API_VERSION_1_0:
@@ -370,6 +361,20 @@
             case CAMERA_DEVICE_API_VERSION_3_5:
                 // in support
                 break;
+            case CAMERA_DEVICE_API_VERSION_3_6:
+                /**
+                 * ICameraDevice@3.5 contains APIs from both
+                 * CAMERA_DEVICE_API_VERSION_3_6 and CAMERA_MODULE_API_VERSION_2_5
+                 * so we require HALs to uprev both for simplified supported combinations.
+                 * HAL can still opt in individual new APIs indepedently.
+                 */
+                if (moduleVersion < CAMERA_MODULE_API_VERSION_2_5) {
+                    ALOGE("%s: Device %d has unsupported version combination:"
+                            "HAL version %x and module version %x",
+                            __FUNCTION__, id, info.device_version, moduleVersion);
+                    return NO_INIT;
+                }
+                break;
             case CAMERA_DEVICE_API_VERSION_2_0:
             case CAMERA_DEVICE_API_VERSION_2_1:
             case CAMERA_DEVICE_API_VERSION_3_0:
@@ -575,10 +580,11 @@
         return Void();
     }
 
-    // ICameraDevice 3.4 or upper
     sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl;
+
+    // ICameraDevice 3.4 or upper
     if (deviceVersion >= kHAL3_4) {
-        ALOGV("Constructing v3.4 camera device");
+        ALOGV("Constructing v3.4+ camera device");
         if (deviceVersion == kHAL3_4) {
             deviceImpl = new android::hardware::camera::device::V3_4::implementation::CameraDevice(
                     mModule, cameraId, mCameraDeviceNames);
diff --git a/camera/provider/2.4/default/CameraProvider.h b/camera/provider/2.4/default/CameraProvider.h
index 0f0959f..10e9b0d 100644
--- a/camera/provider/2.4/default/CameraProvider.h
+++ b/camera/provider/2.4/default/CameraProvider.h
@@ -98,7 +98,6 @@
 
     // extract legacy camera ID/device version from a HIDL device name
     static std::string getLegacyCameraId(const hidl_string& deviceName);
-    static int getCameraDeviceVersion(const hidl_string& deviceName);
 
     // convert conventional HAL status to HIDL Status
     static Status getHidlStatus(int);
diff --git a/cas/1.1/Android.bp b/cas/1.1/Android.bp
new file mode 100644
index 0000000..bb0edb9
--- /dev/null
+++ b/cas/1.1/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.cas@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "ICas.hal",
+        "ICasListener.hal",
+        "IMediaCasService.hal",
+    ],
+    interfaces: [
+        "android.hardware.cas@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
+
diff --git a/cas/1.1/ICas.hal b/cas/1.1/ICas.hal
new file mode 100644
index 0000000..027968e
--- /dev/null
+++ b/cas/1.1/ICas.hal
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 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.cas@1.1;
+
+import @1.0::HidlCasSessionId;
+import @1.0::ICas;
+import @1.0::Status;
+
+/**
+ * ICas is the API to control the cas system and is accessible from both
+ * Java and native level. It is used to manage sessions, provision/refresh
+ * the cas system, and process the EMM/ECM messages. It also allows bi-directional,
+ * scheme-specific communications between the client and the cas system.
+ */
+
+interface ICas extends @1.0::ICas {
+   /**
+     * Send an scheme-specific session event to the CasPlugin.
+     *
+     * @param sessionId the id of an opened session.
+     * @param event an integer denoting a scheme-specific event to be sent.
+     * @param arg a scheme-specific integer argument for the event.
+     * @param data a byte array containing scheme-specific data for the event.
+     * @return status the status of the call.
+     */
+    sendSessionEvent(HidlCasSessionId sessionId, int32_t event, int32_t arg,
+                     vec<uint8_t> eventData)
+          generates (Status status);
+};
diff --git a/cas/1.1/ICasListener.hal b/cas/1.1/ICasListener.hal
new file mode 100644
index 0000000..5ec1154
--- /dev/null
+++ b/cas/1.1/ICasListener.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 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.cas@1.1;
+
+import @1.0::ICasListener;
+import @1.0::HidlCasSessionId;
+
+interface ICasListener extends @1.0::ICasListener{
+    /**
+      * Notify the listener of a scheme-specific session event from CA system.
+      *
+      * @param sessionId the id of an opened session.
+      * @param event an integer whose meaning is scheme-specific.
+      * @param arg an integer whose meaning is scheme-specific.
+      * @param data a byte array of data whose format and meaning are
+      * scheme-specific.
+      */
+    onSessionEvent(HidlCasSessionId sessionId, int32_t event, int32_t arg,
+                   vec<uint8_t> data);
+};
diff --git a/cas/1.1/IMediaCasService.hal b/cas/1.1/IMediaCasService.hal
new file mode 100644
index 0000000..e82b54c
--- /dev/null
+++ b/cas/1.1/IMediaCasService.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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.cas@1.1;
+
+import @1.1::ICas;
+import @1.1::ICasListener;
+import @1.0::IMediaCasService;
+
+/**
+ * IMediaCasService is the main entry point for interacting with a vendor's
+ * cas HAL to create cas and descrambler plugin instances. A cas plugin instance
+ * opens cas sessions which are used to obtain keys for a descrambler session,
+ * which can in turn be used to descramble protected video content.
+ */
+
+interface IMediaCasService extends @1.0::IMediaCasService {
+    /**
+     * Construct a new instance of a @1.1 ICAS CasPlugin given a CA_system_id.
+     *
+     * @param caSystemId the id of the CA system.
+     * @param listener the event listener to receive events coming from the CasPlugin.
+     * @return cas the newly created CasPlugin interface.
+     */
+    createPluginExt(int32_t caSystemId, ICasListener listener) generates (ICas cas);
+};
diff --git a/cas/1.1/default/Android.bp b/cas/1.1/default/Android.bp
new file mode 100644
index 0000000..68a49cf
--- /dev/null
+++ b/cas/1.1/default/Android.bp
@@ -0,0 +1,49 @@
+cc_defaults {
+    name: "cas_service_defaults@1.1",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+      "CasImpl.cpp",
+      "DescramblerImpl.cpp",
+      "MediaCasService.cpp",
+      "service.cpp",
+      "SharedLibrary.cpp",
+      "TypeConvert.cpp",
+    ],
+
+    compile_multilib: "32",
+
+    shared_libs: [
+      "android.hardware.cas@1.0",
+      "android.hardware.cas@1.1",
+      "android.hardware.cas.native@1.0",
+      "android.hidl.memory@1.0",
+      "libbinder",
+      "libhidlbase",
+      "libhidlmemory",
+      "libhidltransport",
+      "liblog",
+      "libutils",
+    ],
+    header_libs: [
+      "libstagefright_foundation_headers",
+      "media_plugin_headers",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.cas@1.1-service",
+    vintf_fragments: ["android.hardware.cas@1.1-service.xml"],
+    defaults: ["cas_service_defaults@1.1"],
+    init_rc: ["android.hardware.cas@1.1-service.rc"],
+}
+
+cc_binary {
+    name: "android.hardware.cas@1.1-service-lazy",
+    vintf_fragments: ["android.hardware.cas@1.1-service-lazy.xml"],
+    overrides: ["android.hardware.cas@1.1-service"],
+    defaults: ["cas_service_defaults@1.1"],
+    init_rc: ["android.hardware.cas@1.1-service-lazy.rc"],
+    cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/cas/1.1/default/CasImpl.cpp b/cas/1.1/default/CasImpl.cpp
new file mode 100644
index 0000000..4cc6017
--- /dev/null
+++ b/cas/1.1/default/CasImpl.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2019 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-CasImpl"
+
+#include <android/hardware/cas/1.1/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "SharedLibrary.h"
+#include "TypeConvert.h"
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+CasImpl::CasImpl(const sp<ICasListener>& listener) : mListener(listener) {
+    ALOGV("CTOR");
+}
+
+CasImpl::~CasImpl() {
+    ALOGV("DTOR");
+    release();
+}
+
+// static
+void CasImpl::OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl* casImpl = static_cast<CasImpl*>(appData);
+    casImpl->onEvent(event, arg, data, size);
+}
+
+// static
+void CasImpl::CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+                          const CasSessionId* sessionId) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl* casImpl = static_cast<CasImpl*>(appData);
+    casImpl->onEvent(sessionId, event, arg, data, size);
+}
+
+void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin* plugin) {
+    mLibrary = library;
+    std::shared_ptr<CasPlugin> holder(plugin);
+    std::atomic_store(&mPluginHolder, holder);
+}
+
+void CasImpl::onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size) {
+    if (mListener == NULL) {
+        return;
+    }
+
+    HidlCasData eventData;
+    if (data != NULL) {
+        eventData.setToExternal(data, size);
+    }
+
+    mListener->onEvent(event, arg, eventData);
+}
+
+void CasImpl::onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+                      size_t size) {
+    if (mListener == NULL) {
+        return;
+    }
+
+    HidlCasData eventData;
+    if (data != NULL) {
+        eventData.setToExternal(data, size);
+    }
+
+    if (sessionId != NULL) {
+        mListener->onSessionEvent(*sessionId, event, arg, eventData);
+    } else {
+        mListener->onEvent(event, arg, eventData);
+    }
+}
+
+Return<Status> CasImpl::setPrivateData(const HidlCasData& pvtData) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->setPrivateData(pvtData));
+}
+
+Return<void> CasImpl::openSession(openSession_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+    CasSessionId sessionId;
+
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    status_t err = INVALID_OPERATION;
+    if (holder.get() != nullptr) {
+        err = holder->openSession(&sessionId);
+        holder.reset();
+    }
+
+    _hidl_cb(toStatus(err), sessionId);
+
+    return Void();
+}
+
+Return<Status> CasImpl::setSessionPrivateData(const HidlCasSessionId& sessionId,
+                                              const HidlCasData& pvtData) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->setSessionPrivateData(sessionId, pvtData));
+}
+
+Return<Status> CasImpl::closeSession(const HidlCasSessionId& sessionId) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->closeSession(sessionId));
+}
+
+Return<Status> CasImpl::processEcm(const HidlCasSessionId& sessionId, const HidlCasData& ecm) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->processEcm(sessionId, ecm));
+}
+
+Return<Status> CasImpl::processEmm(const HidlCasData& emm) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->processEmm(emm));
+}
+
+Return<Status> CasImpl::sendEvent(int32_t event, int32_t arg, const HidlCasData& eventData) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->sendEvent(event, arg, eventData);
+    return toStatus(err);
+}
+
+Return<Status> CasImpl::sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event,
+                                         int32_t arg, const HidlCasData& eventData) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->sendSessionEvent(sessionId, event, arg, eventData);
+    return toStatus(err);
+}
+
+Return<Status> CasImpl::provision(const hidl_string& provisionString) {
+    ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str());
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->provision(String8(provisionString.c_str())));
+}
+
+Return<Status> CasImpl::refreshEntitlements(int32_t refreshType, const HidlCasData& refreshData) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->refreshEntitlements(refreshType, refreshData);
+    return toStatus(err);
+}
+
+Return<Status> CasImpl::release() {
+    ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+    std::shared_ptr<CasPlugin> holder(nullptr);
+    std::atomic_store(&mPluginHolder, holder);
+
+    return Status::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.1/default/CasImpl.h b/cas/1.1/default/CasImpl.h
new file mode 100644
index 0000000..18aee9e
--- /dev/null
+++ b/cas/1.1/default/CasImpl.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_
+#define ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_
+
+#include <android/hardware/cas/1.1/ICas.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+struct CasPlugin;
+
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+struct ICasListener;
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasData;
+using ::android::hardware::cas::V1_0::HidlCasSessionId;
+using ::android::hardware::cas::V1_0::Status;
+
+class SharedLibrary;
+
+class CasImpl : public ICas {
+   public:
+    CasImpl(const sp<ICasListener>& listener);
+    virtual ~CasImpl();
+
+    static void OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+    static void CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+                            const CasSessionId* sessionId);
+
+    void init(const sp<SharedLibrary>& library, CasPlugin* plugin);
+    void onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+    void onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+                 size_t size);
+
+    // ICas inherits
+
+    virtual Return<Status> setPrivateData(const HidlCasData& pvtData) override;
+
+    virtual Return<void> openSession(openSession_cb _hidl_cb) override;
+
+    virtual Return<Status> closeSession(const HidlCasSessionId& sessionId) override;
+
+    virtual Return<Status> setSessionPrivateData(const HidlCasSessionId& sessionId,
+                                                 const HidlCasData& pvtData) override;
+
+    virtual Return<Status> processEcm(const HidlCasSessionId& sessionId,
+                                      const HidlCasData& ecm) override;
+
+    virtual Return<Status> processEmm(const HidlCasData& emm) override;
+
+    virtual Return<Status> sendEvent(int32_t event, int32_t arg,
+                                     const HidlCasData& eventData) override;
+
+    virtual Return<Status> sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event,
+                                            int32_t arg, const HidlCasData& eventData) override;
+
+    virtual Return<Status> provision(const hidl_string& provisionString) override;
+
+    virtual Return<Status> refreshEntitlements(int32_t refreshType,
+                                               const HidlCasData& refreshData) override;
+
+    virtual Return<Status> release() override;
+
+   private:
+    struct PluginHolder;
+    sp<SharedLibrary> mLibrary;
+    std::shared_ptr<CasPlugin> mPluginHolder;
+    sp<ICasListener> mListener;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_
diff --git a/cas/1.1/default/DescramblerImpl.cpp b/cas/1.1/default/DescramblerImpl.cpp
new file mode 100644
index 0000000..36dc1a5
--- /dev/null
+++ b/cas/1.1/default/DescramblerImpl.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2019 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-DescramblerImpl"
+
+#include <hidlmemory/mapping.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <utils/Log.h>
+
+#include "DescramblerImpl.h"
+#include "SharedLibrary.h"
+#include "TypeConvert.h"
+
+namespace android {
+using hidl::memory::V1_0::IMemory;
+
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+#define CHECK_SUBSAMPLE_DEF(type)                                                                 \
+    static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \
+    static_assert(offsetof(SubSample, numBytesOfClearData) ==                                     \
+                          offsetof(type::SubSample, mNumBytesOfClearData),                        \
+                  "SubSample: numBytesOfClearData offset doesn't match");                         \
+    static_assert(offsetof(SubSample, numBytesOfEncryptedData) ==                                 \
+                          offsetof(type::SubSample, mNumBytesOfEncryptedData),                    \
+                  "SubSample: numBytesOfEncryptedData offset doesn't match")
+
+CHECK_SUBSAMPLE_DEF(DescramblerPlugin);
+CHECK_SUBSAMPLE_DEF(CryptoPlugin);
+
+DescramblerImpl::DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin* plugin)
+    : mLibrary(library), mPluginHolder(plugin) {
+    ALOGV("CTOR: plugin=%p", mPluginHolder.get());
+}
+
+DescramblerImpl::~DescramblerImpl() {
+    ALOGV("DTOR: plugin=%p", mPluginHolder.get());
+    release();
+}
+
+Return<Status> DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+
+    std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->setMediaCasSession(sessionId));
+}
+
+Return<bool> DescramblerImpl::requiresSecureDecoderComponent(const hidl_string& mime) {
+    std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return false;
+    }
+
+    return holder->requiresSecureDecoderComponent(String8(mime.c_str()));
+}
+
+static inline bool validateRangeForSize(uint64_t offset, uint64_t length, uint64_t size) {
+    return isInRange<uint64_t, uint64_t>(0, size, offset, length);
+}
+
+Return<void> DescramblerImpl::descramble(ScramblingControl scramblingControl,
+                                         const hidl_vec<SubSample>& subSamples,
+                                         const SharedBuffer& srcBuffer, uint64_t srcOffset,
+                                         const DestinationBuffer& dstBuffer, uint64_t dstOffset,
+                                         descramble_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    // hidl_memory's size is stored in uint64_t, but mapMemory's mmap will map
+    // size in size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed
+    // but the mapped memory's actual size will be smaller than the reported size.
+    if (srcBuffer.heapBase.size() > SIZE_MAX) {
+        ALOGE("Invalid hidl_memory size: %llu", srcBuffer.heapBase.size());
+        android_errorWriteLog(0x534e4554, "79376389");
+        _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+        return Void();
+    }
+
+    sp<IMemory> srcMem = mapMemory(srcBuffer.heapBase);
+
+    // Validate if the offset and size in the SharedBuffer is consistent with the
+    // mapped ashmem, since the offset and size is controlled by client.
+    if (srcMem == NULL) {
+        ALOGE("Failed to map src buffer.");
+        _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+        return Void();
+    }
+    if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize())) {
+        ALOGE("Invalid src buffer range: offset %llu, size %llu, srcMem size %llu",
+              srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize());
+        android_errorWriteLog(0x534e4554, "67962232");
+        _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+        return Void();
+    }
+
+    // use 64-bit here to catch bad subsample size that might be overflowing.
+    uint64_t totalBytesInSubSamples = 0;
+    for (size_t i = 0; i < subSamples.size(); i++) {
+        totalBytesInSubSamples +=
+                (uint64_t)subSamples[i].numBytesOfClearData + subSamples[i].numBytesOfEncryptedData;
+    }
+    // Further validate if the specified srcOffset and requested total subsample size
+    // is consistent with the source shared buffer size.
+    if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) {
+        ALOGE("Invalid srcOffset and subsample size: "
+              "srcOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
+              srcOffset, totalBytesInSubSamples, srcBuffer.size);
+        android_errorWriteLog(0x534e4554, "67962232");
+        _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+        return Void();
+    }
+
+    void* srcPtr = (uint8_t*)(void*)srcMem->getPointer() + srcBuffer.offset;
+    void* dstPtr = NULL;
+    if (dstBuffer.type == BufferType::SHARED_MEMORY) {
+        // When using shared memory, src buffer is also used as dst,
+        // we don't map it again here.
+        dstPtr = srcPtr;
+
+        // In this case the dst and src would be the same buffer, need to validate
+        // dstOffset against the buffer size too.
+        if (!validateRangeForSize(dstOffset, totalBytesInSubSamples, srcBuffer.size)) {
+            ALOGE("Invalid dstOffset and subsample size: "
+                  "dstOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
+                  dstOffset, totalBytesInSubSamples, srcBuffer.size);
+            android_errorWriteLog(0x534e4554, "67962232");
+            _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+            return Void();
+        }
+    } else {
+        native_handle_t* handle =
+                const_cast<native_handle_t*>(dstBuffer.secureMemory.getNativeHandle());
+        dstPtr = static_cast<void*>(handle);
+    }
+
+    // Get a local copy of the shared_ptr for the plugin. Note that before
+    // calling the HIDL callback, this shared_ptr must be manually reset,
+    // since the client side could proceed as soon as the callback is called
+    // without waiting for this method to go out of scope.
+    std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        _hidl_cb(toStatus(INVALID_OPERATION), 0, NULL);
+        return Void();
+    }
+
+    // Casting hidl SubSample to DescramblerPlugin::SubSample, but need
+    // to ensure structs are actually idential
+
+    int32_t result =
+            holder->descramble(dstBuffer.type != BufferType::SHARED_MEMORY,
+                               (DescramblerPlugin::ScramblingControl)scramblingControl,
+                               subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(),
+                               srcPtr, srcOffset, dstPtr, dstOffset, NULL);
+
+    holder.reset();
+    _hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL);
+    return Void();
+}
+
+Return<Status> DescramblerImpl::release() {
+    ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+    std::shared_ptr<DescramblerPlugin> holder(nullptr);
+    std::atomic_store(&mPluginHolder, holder);
+
+    return Status::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.1/default/DescramblerImpl.h b/cas/1.1/default/DescramblerImpl.h
new file mode 100644
index 0000000..a1f66ae
--- /dev/null
+++ b/cas/1.1/default/DescramblerImpl.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_
+#define ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_
+
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+struct DescramblerPlugin;
+using namespace hardware::cas::native::V1_0;
+
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasSessionId;
+using ::android::hardware::cas::V1_0::Status;
+
+class SharedLibrary;
+
+class DescramblerImpl : public IDescrambler {
+   public:
+    DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin* plugin);
+    virtual ~DescramblerImpl();
+
+    virtual Return<Status> setMediaCasSession(const HidlCasSessionId& sessionId) override;
+
+    virtual Return<bool> requiresSecureDecoderComponent(const hidl_string& mime) override;
+
+    virtual Return<void> descramble(ScramblingControl scramblingControl,
+                                    const hidl_vec<SubSample>& subSamples,
+                                    const SharedBuffer& srcBuffer, uint64_t srcOffset,
+                                    const DestinationBuffer& dstBuffer, uint64_t dstOffset,
+                                    descramble_cb _hidl_cb) override;
+
+    virtual Return<Status> release() override;
+
+   private:
+    sp<SharedLibrary> mLibrary;
+    std::shared_ptr<DescramblerPlugin> mPluginHolder;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_
diff --git a/cas/1.1/default/FactoryLoader.h b/cas/1.1/default/FactoryLoader.h
new file mode 100644
index 0000000..c4a48e2
--- /dev/null
+++ b/cas/1.1/default/FactoryLoader.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
+#define ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/cas/CasAPI.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+#include "SharedLibrary.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor;
+
+template <class T>
+class FactoryLoader {
+   public:
+    FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
+
+    virtual ~FactoryLoader() { closeFactory(); }
+
+    bool findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library = NULL,
+                              T** factory = NULL);
+
+    bool enumeratePlugins(vector<HidlCasPluginDescriptor>* results);
+
+   private:
+    typedef T* (*CreateFactoryFunc)();
+
+    Mutex mMapLock;
+    T* mFactory;
+    const char* mCreateFactoryFuncName;
+    sp<SharedLibrary> mLibrary;
+    KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
+    KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
+
+    bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+                                      sp<SharedLibrary>* library, T** factory);
+
+    bool queryPluginsFromPath(const String8& path, vector<HidlCasPluginDescriptor>* results);
+
+    bool openFactory(const String8& path);
+    void closeFactory();
+};
+
+template <class T>
+bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library,
+                                            T** factory) {
+    if (library != NULL) {
+        library->clear();
+    }
+    if (factory != NULL) {
+        *factory = NULL;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    // first check cache
+    ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
+    if (index >= 0) {
+        return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
+                                            library, factory);
+    }
+
+    // no luck, have to search
+    String8 dirPath("/vendor/lib/mediacas");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
+                mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
+                closedir(pDir);
+
+                return true;
+            }
+        }
+    }
+
+    closedir(pDir);
+
+    ALOGE("Failed to find plugin");
+    return false;
+}
+
+template <class T>
+bool FactoryLoader<T>::enumeratePlugins(vector<HidlCasPluginDescriptor>* results) {
+    ALOGI("enumeratePlugins");
+
+    results->clear();
+
+    String8 dirPath("/vendor/lib/mediacas");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            queryPluginsFromPath(pluginPath, results);
+        }
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+                                                    sp<SharedLibrary>* library, T** factory) {
+    closeFactory();
+
+    if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
+        closeFactory();
+        return false;
+    }
+
+    if (library != NULL) {
+        *library = mLibrary;
+    }
+    if (factory != NULL) {
+        *factory = mFactory;
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
+                                            vector<HidlCasPluginDescriptor>* results) {
+    closeFactory();
+
+    vector<CasPluginDescriptor> descriptors;
+    if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
+        closeFactory();
+        return false;
+    }
+
+    for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
+        results->push_back(
+                HidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::openFactory(const String8& path) {
+    // get strong pointer to open shared library
+    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+    if (index >= 0) {
+        mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
+    } else {
+        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+    }
+
+    if (!mLibrary.get()) {
+        mLibrary = new SharedLibrary(path);
+        if (!*mLibrary) {
+            return false;
+        }
+
+        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+    }
+
+    CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
+    if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
+        return false;
+    }
+    return true;
+}
+
+template <class T>
+void FactoryLoader<T>::closeFactory() {
+    delete mFactory;
+    mFactory = NULL;
+    mLibrary.clear();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
diff --git a/cas/1.1/default/MediaCasService.cpp b/cas/1.1/default/MediaCasService.cpp
new file mode 100644
index 0000000..e2d3357
--- /dev/null
+++ b/cas/1.1/default/MediaCasService.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2019 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-MediaCasService"
+
+#include <android/hardware/cas/1.1/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "DescramblerImpl.h"
+#include "MediaCasService.h"
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+MediaCasService::MediaCasService()
+    : mCasLoader("createCasFactory"), mDescramblerLoader("createDescramblerFactory") {}
+
+MediaCasService::~MediaCasService() {}
+
+Return<void> MediaCasService::enumeratePlugins(enumeratePlugins_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    vector<HidlCasPluginDescriptor> results;
+    mCasLoader.enumeratePlugins(&results);
+
+    _hidl_cb(results);
+    return Void();
+}
+
+Return<bool> MediaCasService::isSystemIdSupported(int32_t CA_system_id) {
+    ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
+
+    return mCasLoader.findFactoryForScheme(CA_system_id);
+}
+
+Return<sp<V1_0::ICas>> MediaCasService::createPlugin(int32_t /* CA_system_id */,
+                                                     const sp<V1_0::ICasListener>& /* listener */) {
+    ALOGE("%s:Use createPluginExt to create plugin with cas@1.1", __FUNCTION__);
+
+    sp<V1_0::ICas> result;
+    /*
+        CasFactory *factory;
+        sp<SharedLibrary> library;
+        if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+            CasPlugin *plugin = NULL;
+            sp<CasImpl> casImpl = new CasImpl(listener);
+            if (factory->createPlugin(CA_system_id, casImpl.get(),
+                    CasImpl::OnEvent, &plugin) == OK && plugin != NULL) {
+                casImpl->init(library, plugin);
+                result = casImpl;
+            }
+        }
+    */
+    return result;
+}
+
+Return<sp<ICas>> MediaCasService::createPluginExt(int32_t CA_system_id,
+                                                  const sp<ICasListener>& listener) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+    sp<ICas> result;
+
+    CasFactory* factory;
+    sp<SharedLibrary> library;
+    if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+        CasPlugin* plugin = NULL;
+        sp<CasImpl> casImpl = new CasImpl(listener);
+        if (factory->createPlugin(CA_system_id, casImpl.get(), &CasImpl::CallBackExt, &plugin) ==
+                    OK &&
+            plugin != NULL) {
+            casImpl->init(library, plugin);
+            result = casImpl;
+        }
+    }
+
+    return result;
+}
+
+Return<bool> MediaCasService::isDescramblerSupported(int32_t CA_system_id) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+    return mDescramblerLoader.findFactoryForScheme(CA_system_id);
+}
+
+Return<sp<IDescramblerBase>> MediaCasService::createDescrambler(int32_t CA_system_id) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+    sp<IDescrambler> result;
+
+    DescramblerFactory* factory;
+    sp<SharedLibrary> library;
+    if (mDescramblerLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+        DescramblerPlugin* plugin = NULL;
+        if (factory->createPlugin(CA_system_id, &plugin) == OK && plugin != NULL) {
+            result = new DescramblerImpl(library, plugin);
+        }
+    }
+
+    return result;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.1/default/MediaCasService.h b/cas/1.1/default/MediaCasService.h
new file mode 100644
index 0000000..ec5a86d
--- /dev/null
+++ b/cas/1.1/default/MediaCasService.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_
+#define ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_
+
+#include <android/hardware/cas/1.1/IMediaCasService.h>
+
+#include "FactoryLoader.h"
+
+namespace android {
+struct CasFactory;
+struct DescramblerFactory;
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor;
+using ::android::hardware::cas::V1_0::IDescramblerBase;
+
+class MediaCasService : public IMediaCasService {
+   public:
+    MediaCasService();
+
+    virtual Return<void> enumeratePlugins(enumeratePlugins_cb _hidl_cb) override;
+
+    virtual Return<bool> isSystemIdSupported(int32_t CA_system_id) override;
+
+    virtual Return<sp<V1_0::ICas>> createPlugin(int32_t CA_system_id,
+                                                const sp<V1_0::ICasListener>& listener) override;
+
+    virtual Return<sp<ICas>> createPluginExt(int32_t CA_system_id,
+                                             const sp<ICasListener>& listener) override;
+
+    virtual Return<bool> isDescramblerSupported(int32_t CA_system_id) override;
+
+    virtual Return<sp<IDescramblerBase>> createDescrambler(int32_t CA_system_id) override;
+
+   private:
+    FactoryLoader<CasFactory> mCasLoader;
+    FactoryLoader<DescramblerFactory> mDescramblerLoader;
+
+    virtual ~MediaCasService();
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_
diff --git a/cas/1.1/default/SharedLibrary.cpp b/cas/1.1/default/SharedLibrary.cpp
new file mode 100644
index 0000000..ffe4bb9
--- /dev/null
+++ b/cas/1.1/default/SharedLibrary.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-SharedLibrary"
+
+#include "SharedLibrary.h"
+#include <dlfcn.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+SharedLibrary::SharedLibrary(const String8& path) {
+    mLibHandle = dlopen(path.string(), RTLD_NOW);
+}
+
+SharedLibrary::~SharedLibrary() {
+    if (mLibHandle != NULL) {
+        dlclose(mLibHandle);
+        mLibHandle = NULL;
+    }
+}
+
+bool SharedLibrary::operator!() const {
+    return mLibHandle == NULL;
+}
+
+void* SharedLibrary::lookup(const char* symbol) const {
+    if (!mLibHandle) {
+        return NULL;
+    }
+    // Clear last error before we load the symbol again,
+    // in case the caller didn't retrieve it.
+    (void)dlerror();
+    return dlsym(mLibHandle, symbol);
+}
+
+const char* SharedLibrary::lastError() const {
+    const char* error = dlerror();
+    return error ? error : "No errors or unknown error";
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.1/default/SharedLibrary.h b/cas/1.1/default/SharedLibrary.h
new file mode 100644
index 0000000..f4d2ff6
--- /dev/null
+++ b/cas/1.1/default/SharedLibrary.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_
+#define ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+class SharedLibrary : public RefBase {
+   public:
+    explicit SharedLibrary(const String8& path);
+    ~SharedLibrary();
+
+    bool operator!() const;
+    void* lookup(const char* symbol) const;
+    const char* lastError() const;
+
+   private:
+    void* mLibHandle;
+    DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_
diff --git a/cas/1.1/default/TypeConvert.cpp b/cas/1.1/default/TypeConvert.cpp
new file mode 100644
index 0000000..09ef41a
--- /dev/null
+++ b/cas/1.1/default/TypeConvert.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-TypeConvert"
+
+#include "TypeConvert.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+Status toStatus(status_t legacyStatus) {
+    Status status;
+    switch (legacyStatus) {
+        case android::OK:
+            status = Status::OK;
+            break;
+        case android::ERROR_CAS_NO_LICENSE:
+            status = Status::ERROR_CAS_NO_LICENSE;
+            break;
+        case android::ERROR_CAS_LICENSE_EXPIRED:
+            status = Status::ERROR_CAS_LICENSE_EXPIRED;
+            break;
+        case android::ERROR_CAS_SESSION_NOT_OPENED:
+            status = Status::ERROR_CAS_SESSION_NOT_OPENED;
+            break;
+        case android::ERROR_CAS_CANNOT_HANDLE:
+            status = Status::ERROR_CAS_CANNOT_HANDLE;
+            break;
+        case android::ERROR_CAS_TAMPER_DETECTED:
+            status = Status::ERROR_CAS_INVALID_STATE;
+            break;
+        case android::BAD_VALUE:
+            status = Status::BAD_VALUE;
+            break;
+        case android::ERROR_CAS_NOT_PROVISIONED:
+            status = Status::ERROR_CAS_NOT_PROVISIONED;
+            break;
+        case android::ERROR_CAS_RESOURCE_BUSY:
+            status = Status::ERROR_CAS_RESOURCE_BUSY;
+            break;
+        case android::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
+            status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION;
+            break;
+        case android::ERROR_CAS_DEVICE_REVOKED:
+            status = Status::ERROR_CAS_DEVICE_REVOKED;
+            break;
+        case android::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED:
+            status = Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
+            break;
+        case android::ERROR_CAS_DECRYPT:
+            status = Status::ERROR_CAS_DECRYPT;
+            break;
+        default:
+            ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", legacyStatus);
+            status = Status::ERROR_CAS_UNKNOWN;
+            break;
+    }
+    return status;
+}
+
+String8 sessionIdToString(const CasSessionId& sessionId) {
+    String8 result;
+    for (size_t i = 0; i < sessionId.size(); i++) {
+        result.appendFormat("%02x ", sessionId[i]);
+    }
+    if (result.isEmpty()) {
+        result.append("(null)");
+    }
+    return result;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.1/default/TypeConvert.h b/cas/1.1/default/TypeConvert.h
new file mode 100644
index 0000000..c4a0119
--- /dev/null
+++ b/cas/1.1/default/TypeConvert.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H
+#define ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H
+
+#include <android/hardware/cas/1.0/types.h>
+#include <media/cas/CasAPI.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::Status;
+
+Status toStatus(status_t legacyStatus);
+
+String8 sessionIdToString(const CasSessionId& sessionId);
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
new file mode 100644
index 0000000..9227b6f
--- /dev/null
+++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
@@ -0,0 +1,9 @@
+service vendor.cas-hal-1-1 /vendor/bin/hw/android.hardware.cas@1.1-service-lazy
+    interface android.hardware.cas@1.1::IMediaCasService default
+    oneshot
+    disabled
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml
new file mode 100644
index 0000000..c9f13ba
--- /dev/null
+++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.cas</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service.rc b/cas/1.1/default/android.hardware.cas@1.1-service.rc
new file mode 100644
index 0000000..4081fe1
--- /dev/null
+++ b/cas/1.1/default/android.hardware.cas@1.1-service.rc
@@ -0,0 +1,6 @@
+service vendor.cas-hal-1-1 /vendor/bin/hw/android.hardware.cas@1.1-service
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service.xml b/cas/1.1/default/android.hardware.cas@1.1-service.xml
new file mode 100644
index 0000000..c9f13ba
--- /dev/null
+++ b/cas/1.1/default/android.hardware.cas@1.1-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.cas</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/cas/1.1/default/service.cpp b/cas/1.1/default/service.cpp
new file mode 100644
index 0000000..9625303
--- /dev/null
+++ b/cas/1.1/default/service.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 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_NDEBUG 0
+#ifdef LAZY_SERVICE
+#define LOG_TAG "android.hardware.cas@1.1-service-lazy"
+#else
+#define LOG_TAG "android.hardware.cas@1.1-service"
+#endif
+
+#include <binder/ProcessState.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+
+#include "MediaCasService.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::LazyServiceRegistrar;
+using android::hardware::cas::V1_1::IMediaCasService;
+using android::hardware::cas::V1_1::implementation::MediaCasService;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main() {
+    configureRpcThreadpool(8, true /* callerWillJoin */);
+
+    // Setup hwbinder service
+    android::sp<IMediaCasService> service = new MediaCasService();
+    android::status_t status;
+    if (kLazyService) {
+        auto serviceRegistrar = std::make_shared<LazyServiceRegistrar>();
+        status = serviceRegistrar->registerService(service);
+    } else {
+        status = service->registerAsService();
+    }
+    LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering cas service: %d", status);
+
+    joinRpcThreadpool();
+    return 0;
+}
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 94ffe80..89855a0 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -121,7 +121,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.cas</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IMediaCasService</name>
             <instance>default</instance>
diff --git a/current.txt b/current.txt
index 3b87306..478cbc5 100644
--- a/current.txt
+++ b/current.txt
@@ -399,8 +399,9 @@
 417ab60fe1ef786778047e4486f3d868ebce570d91addd8fe4251515213072de android.hardware.neuralnetworks@1.0::types
 e22e8135d061d0e9c4c1a70c25c19fdba10f4d3cda9795ef25b6392fc520317c android.hardware.neuralnetworks@1.1::types
 1d4a5776614c08b5d794a5ec5ab04697260cbd4b3441d5935cd53ee71d19da02 android.hardware.radio@1.0::IRadioResponse
-271187e261b30c01a33011aea257c07a2d2f05b72943ebee89e973e997849973 android.hardware.radio@1.0::types
+ed9da80ec0c96991fd03f0a46107815d0e50f764656e49dba4980fa5c31d5bc3 android.hardware.radio@1.0::types
 1d19720d4fd38b1095f0f555a4bd92b3b12c9b1d0f560b0e9a474cd6dcc20db6 android.hardware.radio@1.2::IRadio
+cd1757867a5e3a3faa362e785239515870d1a3c9ce756c6f0cf0f0fd8aac2547 android.hardware.radio@1.2::types
 e78cf871f9fd1c072874e481e06e18e2681763cf2aa38c1fd777d53bab4eb69b android.hardware.sensors@1.0::types
 3d01e29e8129186f7567c4f9c8bee7480a0768e587b1be9b28adb0a6cbec6bf2 android.hardware.tv.cec@1.0::types
 1722ad002317b1fae1400de709e90f442d94ef22864e05f7a12af48c32e8edc8 android.hardware.usb@1.1::types
diff --git a/gnss/measurement_corrections/1.0/types.hal b/gnss/measurement_corrections/1.0/types.hal
index 5f20734..edf26bf 100644
--- a/gnss/measurement_corrections/1.0/types.hal
+++ b/gnss/measurement_corrections/1.0/types.hal
@@ -79,18 +79,35 @@
  * toaGpsNanosecondsOfWeek
  */
 struct MeasurementCorrections {
-    /** Represents latitude in degrees. */
+    /** Represents latitude in degrees at which the corrections are computed.. */
     double latitudeDegrees;
 
-    /** Represents longitude in degrees. */
+    /** Represents longitude in degrees at which the corrections are computed.. */
     double longitudeDegrees;
 
     /**
-     * Represents altitude in meters above the WGS 84 reference ellipsoid.
+     * Represents altitude in meters above the WGS 84 reference ellipsoid at which the corrections
+     * are computed.
      */
     double altitudeMeters;
 
-    /** Time Of Applicability, GPS time of week */
+    /**
+     * Represents the horizontal uncertainty (68% confidence) in meters on the device position at
+     * which the corrections are provided.
+     *
+     * This value is useful for example to judge how accurate the provided corrections are.
+     */
+    double horizontalPositionUncertaintyMeters;
+
+    /**
+     * Represents the vertical uncertainty (68% confidence) in meters on the device position at
+     * which the corrections are provided.
+     *
+     * This value is useful for example to judge how accurate the provided corrections are.
+     */
+    double verticalPositionUncertaintyMeters;
+
+    /** Time Of Applicability, GPS time of week in nanoseconds. */
     uint64_t toaGpsNanosecondsOfWeek;
 
     /**
diff --git a/media/c2/1.0/Android.bp b/media/c2/1.0/Android.bp
index c37c22b..56c78b2 100644
--- a/media/c2/1.0/Android.bp
+++ b/media/c2/1.0/Android.bp
@@ -13,6 +13,7 @@
         "IComponentListener.hal",
         "IComponentStore.hal",
         "IConfigurable.hal",
+        "IInputSink.hal",
         "IInputSurface.hal",
         "IInputSurfaceConnection.hal",
     ],
diff --git a/media/c2/1.0/IComponent.hal b/media/c2/1.0/IComponent.hal
index deb9255..7fd551f 100644
--- a/media/c2/1.0/IComponent.hal
+++ b/media/c2/1.0/IComponent.hal
@@ -22,13 +22,19 @@
 import IConfigurable;
 import IComponentInterface;
 import IComponentListener;
+import IInputSurface;
+import IInputSurfaceConnection;
 
 /**
- * Interface for a Codec 2.0 component corresponding to API level 1.0 or
- * below. Components have two states: stopped and running. The running
- * state has three sub-states: executing, tripped and error.
+ * Interface for a Codec2 component corresponding to API level 1.0 or below.
+ * Components have two states: stopped and running. The running state has three
+ * sub-states: executing, tripped and error.
+ *
+ * All methods in `IComponent` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status.
  */
-interface IComponent extends IComponentInterface {
+interface IComponent {
 
     // METHODS AVAILABLE WHEN RUNNING
     // =========================================================================
@@ -38,44 +44,42 @@
      *
      * This method must be supported in running (including tripped) states.
      *
-     * This method must return within 1ms
+     * It is acceptable for this method to return `OK` and return an error value
+     * using the IComponentListener::onWorkDone() callback.
      *
-     * It is acceptable for this method to return OK and return an error value
-     * using the onWorkDone() callback.
-     *
-     * @param workBundle WorkBundle object containing Works to queue to the
-     * component.
+     * @param workBundle `WorkBundle` object containing a list of `Work` objects
+     *     to queue to the component.
      * @return status Status of the call, which may be
-     *   - OK        - Works in \p workBundle were successfully queued.
-     *   - BAD_INDEX - Some component(s) in some Work do(es) not exist.
-     *   - CANNOT_DO - The components are not tunneled.
-     *   - NO_MEMORY - Not enough memory to queue \p workBundle.
-     *   - CORRUPTED - Some unknown error prevented queuing the Works.
-     *                 (unexpected).
+     *   - `OK`        - Works in @p workBundle were successfully queued.
+     *   - `BAD_INDEX` - Some component id in some `Worklet` is not valid.
+     *   - `CANNOT_DO` - The components are not tunneled but some `Work` object
+     *                   contains tunneling information.
+     *   - `NO_MEMORY` - Not enough memory to queue @p workBundle.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
      */
     queue(WorkBundle workBundle) generates (Status status);
 
     /**
-     * Discards and abandons any pending work for the component.
+     * Discards and abandons any pending `Work` items for the component.
      *
      * This method must be supported in running (including tripped) states.
      *
-     * This method must return within 5ms.
+     * `Work` that could be immediately abandoned/discarded must be returned in
+     * @p flushedWorkBundle. The order in which queued `Work` items are
+     * discarded can be arbitrary.
      *
-     * Work that could be immediately abandoned/discarded must be returned in
-     * \p flushedWorks; this can be done in an arbitrary order.
-     *
-     * Work that could not be abandoned or discarded immediately must be marked
-     * to be discarded at the earliest opportunity, and must be returned via
-     * the onWorkDone() callback. This must be completed within 500ms.
+     * `Work` that could not be abandoned or discarded immediately must be
+     * marked to be discarded at the earliest opportunity, and must be returned
+     * via IComponentListener::onWorkDone(). This must be completed within
+     * 500ms.
      *
      * @return status Status of the call, which may be
-     *   - OK        - The component has been successfully flushed.
-     *   - TIMED_OUT - The flush could not be completed within the time limit.
-     *                 (unexpected)
-     *   - CORRUPTED - Some unknown error prevented flushing from
-     *                 completion. (unexpected)
-     * @return flushedWorkBundle WorkBundle object containing flushed Works.
+     *   - `OK`        - The component has been successfully flushed.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return flushedWorkBundle `WorkBundle` object containing flushed `Work`
+     *     items.
      */
     flush(
         ) generates (
@@ -87,42 +91,39 @@
      * Drains the component, and optionally downstream components. This is a
      * signalling method; as such it does not wait for any work completion.
      *
-     * Marks last work item as "drain-till-here", so component is notified not
-     * to wait for further work before it processes work already queued. This
-     * method can also be used to set the end-of-stream flag after work has been
-     * queued. Client can continue to queue further work immediately after this
-     * method returns.
+     * The last `Work` item is marked as "drain-till-here", so the component is
+     * notified not to wait for further `Work` before it processes what is
+     * already queued. This method can also be used to set the end-of-stream
+     * flag after `Work` has been queued. Client can continue to queue further
+     * `Work` immediately after this method returns.
      *
      * This method must be supported in running (including tripped) states.
      *
-     * This method must return within 1ms.
-     *
-     * Work that is completed must be returned via the onWorkDone() callback.
+     * `Work` that is completed must be returned via
+     * IComponentListener::onWorkDone().
      *
      * @param withEos Whether to drain the component with marking end-of-stream.
      * @return status Status of the call, which may be
-     *   - OK        - The drain request has been successfully recorded.
-     *   - TIMED_OUT - The flush could not be completed within the time limit.
-     *                 (unexpected)
-     *   - CORRUPTED - Some unknown error prevented flushing from completion.
-     *                 (unexpected)
+     *   - `OK`        - The drain request has been successfully recorded.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
      */
     drain(bool withEos) generates (Status status);
 
     /**
      * Starts using a surface for output.
      *
-     * @param blockPoolId The id of the BlockPool to be associated with the
-     * output surface.
-     * @param surface A surface to use for codec output.
+     * This method must not block.
+     *
+     * @param blockPoolId Id of the `C2BlockPool` to be associated with the
+     *     output surface.
+     * @param surface Output surface.
      * @return status Status of the call, which may be
-     *   - OK        - The operation completed successfully.
-     *   - CANNOT_DO - The component does not support an output surface.
-     *   - REFUSED   - The output surface cannot be accessed.
-     *   - TIMED_OUT - The component could not be connected within the time
-     *                 limit. (unexpected)
-     *   - CORRUPTED - Some unknown error prevented connecting the component.
-     *                 (unexpected)
+     *   - `OK`        - The operation completed successfully.
+     *   - `CANNOT_DO` - The component does not support an output surface.
+     *   - `REFUSED`   - The output surface cannot be accessed.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
      */
     setOutputSurface(
             uint64_t blockPoolId,
@@ -132,65 +133,101 @@
         );
 
     /**
-     * Starts using a persistent OMX input surface for a component.
+     * Starts using an input surface.
      *
      * The component must be in running state.
      *
-     * @param producer Producer component of an OMX persistent input surface.
-     * @param source Source component of an OMX persistent input surface.
+     * @param inputSurface Input surface to connect to.
      * @return status Status of the call, which may be
-     *   - OK        - The operation completed successfully.
-     *   - CANNOT_DO - The component does not support an input surface.
-     *   - BAD_STATE - Component is not in running state.
-     *   - DUPLICATE - The component is already connected to an input surface.
-     *   - REFUSED   - The input surface is already in use.
-     *   - NO_MEMORY - Not enough memory to start the component.
-     *   - TIMED_OUT - The component could not be connected within the time
-     *                 limit. (unexpected)
-     *   - CORRUPTED - Some unknown error prevented connecting the component.
-     *                 (unexpected)
+     *   - `OK`        - The operation completed successfully.
+     *   - `CANNOT_DO` - The component does not support an input surface.
+     *   - `BAD_STATE` - The component is not in running state.
+     *   - `DUPLICATE` - The component is already connected to an input surface.
+     *   - `REFUSED`   - The input surface is already in use.
+     *   - `NO_MEMORY` - Not enough memory to start the component.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return connection `IInputSurfaceConnection` object, which can be used to
+     *     query and configure properties of the connection. This cannot be
+     *     null.
+     */
+    connectToInputSurface(
+            IInputSurface inputSurface
+        ) generates (
+            Status status,
+            IInputSurfaceConnection connection
+        );
+
+    /**
+     * Starts using an OMX input surface.
+     *
+     * The component must be in running state.
+     *
+     * This method is similar to connectToInputSurface(), but it takes an OMX
+     * input surface (as a pair of `IGraphicBufferProducer` and
+     * `IGraphicBufferSource`) instead of Codec2's own `IInputSurface`.
+     *
+     * @param producer Producer component of an OMX input surface.
+     * @param source Source component of an OMX input surface.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation completed successfully.
+     *   - `CANNOT_DO` - The component does not support an OMX input surface.
+     *   - `BAD_STATE` - The component is not in running state.
+     *   - `DUPLICATE` - The component is already connected to an input surface.
+     *   - `REFUSED`   - The input surface is already in use.
+     *   - `NO_MEMORY` - Not enough memory to start the component.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return connection `IInputSurfaceConnection` object, which can be used to
+     *     query and configure properties of the connection. This cannot be
+     *     null.
      */
     connectToOmxInputSurface(
             IGraphicBufferProducer producer,
             IGraphicBufferSource source
-        ) generates (Status status);
+        ) generates (
+            Status status,
+            IInputSurfaceConnection connection
+        );
 
     /**
      * Stops using an input surface.
      *
-     * This call is used for both Codec 2.0 and OMX input surfaces.
-     *
      * The component must be in running state.
      *
      * @return status Status of the call, which may be
-     *   - OK        - The operation completed successfully.
-     *   - CANNOT_DO - The component does not support an input surface.
-     *   - BAD_STATE - Component is not in running state.
-     *   - NOT_FOUND - The component is not connected to an input surface.
-     *   - TIMED_OUT - The component could not be connected within the time
-     *                 limit. (unexpected)
-     *   - CORRUPTED - Some unknown error prevented connecting the component.
-     *                 (unexpected)
+     *   - `OK`        - The operation completed successfully.
+     *   - `CANNOT_DO` - The component does not support an input surface.
+     *   - `BAD_STATE` - The component is not in running state.
+     *   - `NOT_FOUND` - The component is not connected to an input surface.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
      */
     disconnectFromInputSurface() generates (Status Status);
 
     /**
-     * Creates a local block pool backed by the given allocator and returns its
-     * identifier.
+     * Creates a local `C2BlockPool` backed by the given allocator and returns
+     * its id.
      *
-     * This call must return within 100 msec.
+     * The returned @p blockPoolId is the only way the client can refer to a
+     * `C2BlockPool` object in the component. The id can be passed to
+     * setOutputSurface() or used in some C2Param objects later.
      *
-     * @param allocatorId The Codec 2.0 allocator ID
+     * The created `C2BlockPool` object can be destroyed by calling
+     * destroyBlockPool(), reset() or release(). reset() and release() must
+     * destroy all `C2BlockPool` objects that have been created.
+     *
+     * @param allocatorId Id of a `C2Allocator`.
      * @return status Status of the call, which may be
-     *   - OK        - The operation completed successfully.
-     *   - NO_MEMORY - Not enough memory to create the pool.
-     *   - BAD_VALUE - Invalid allocator.
-     *   - TIMED_OUT - The pool could not be created within the time
-     *                 limit. (unexpected)
-     *   - CORRUPTED - Some unknown error prevented creating the pool.
-     *                 (unexpected)
-     * @return blockPoolId The Codec 2.0 blockpool ID for the created pool.
-     * @return configurable Configuration interface for the created pool.
+     *   - `OK`        - The operation completed successfully.
+     *   - `NO_MEMORY` - Not enough memory to create the pool.
+     *   - `BAD_VALUE` - @p allocatorId is not recognized.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return blockPoolId Id of the created C2BlockPool object. This may be
+     *     used in setOutputSurface() if the allocator
+     * @return configurable Configuration interface for the created pool. This
+     *     must not be null.
      */
     createBlockPool(uint32_t allocatorId) generates (
         Status status,
@@ -201,17 +238,13 @@
     /**
      * Destroys a local block pool previously created by createBlockPool().
      *
-     * This call must return within 100 msec.
-     *
-     * @param blockPoolId The block pool id previously returned by
+     * @param blockPoolId Id of a `C2BlockPool` that was previously returned by
      *      createBlockPool().
      * @return status Status of the call, which may be
-     *   - OK        - The operation completed successfully.
-     *   - NOT_FOUND - The supplied blockPoolId is not valid.
-     *   - TIMED_OUT - The pool could not be destroyedwithin the time limit.
-     *                 (unexpected)
-     *   - CORRUPTED - Some unknown error prevented destruction of the pool.
-     *                 (unexpected)
+     *   - `OK`        - The operation completed successfully.
+     *   - `NOT_FOUND` - The supplied blockPoolId is not valid.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
      */
     destroyBlockPool(uint64_t blockPoolId) generates (Status status);
 
@@ -223,28 +256,24 @@
      *
      * This method must be supported in stopped state as well as tripped state.
      *
-     * If the return value is OK, the component must be in the running state.
-     * If the return value is BAD_STATE or DUPLICATE, no state change is
-     * expected as a response to this call.
-     * Otherwise, the component must be in the stopped state.
+     * If the return value is `OK`, the component must be in the running state.
+     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+     * expected as a response to this call. Otherwise, the component must be in
+     * the stopped state.
      *
      * If a component is in the tripped state and start() is called while the
-     * component configuration still results in a trip, start must succeed and
-     * a new onTripped callback must be used to communicate the configuration
+     * component configuration still results in a trip, start() must succeed and
+     * a new onTripped() callback must be used to communicate the configuration
      * conflict that results in the new trip.
      *
-     * This method must return within 500ms.
-     *
      * @return status Status of the call, which may be
-     *   - OK        - The component has started successfully.
-     *   - BAD_STATE - Component is not in stopped or tripped state.
-     *   - DUPLICATE - When called during another start call from another
-     *                 thread.
-     *   - NO_MEMORY - Not enough memory to start the component.
-     *   - TIMED_OUT - The component could not be started within the time limit.
-     *                 (unexpected)
-     *   - CORRUPTED - Some unknown error prevented starting the component.
-     *                 (unexpected)
+     *   - `OK`        - The component has started successfully.
+     *   - `BAD_STATE` - Component is not in stopped or tripped state.
+     *   - `DUPLICATE` - When called during another start call from another
+     *                   thread.
+     *   - `NO_MEMORY` - Not enough memory to start the component.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
      */
     start() generates (Status status);
 
@@ -255,22 +284,22 @@
      *
      * This method must return withing 500ms.
      *
-     * Upon this call, all pending work must be abandoned.
-     * If the return value is BAD_STATE or DUPLICATE, no state change is
-     * expected as a response to this call.
-     * For all other return values, the component must be in the stopped state.
+     * Upon this call, all pending `Work` must be abandoned.
+     *
+     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+     * expected as a response to this call. For all other return values, the
+     * component must be in the stopped state.
      *
      * This does not alter any settings and tunings that may have resulted in a
      * tripped state.
      *
      * @return status Status of the call, which may be
-     *   - OK        - The component has stopped successfully.
-     *   - BAD_STATE - Component is not in running state.
-     *   - DUPLICATE - When called during another stop call from another thread.
-     *   - TIMED_OUT - The component could not be stopped within the time limit.
-     *                 (unexpected)
-     *   - CORRUPTED - Some unknown error prevented starting the component.
-     *                 (unexpected)
+     *   - `OK`        - The component has stopped successfully.
+     *   - `BAD_STATE` - Component is not in running state.
+     *   - `DUPLICATE` - When called during another stop call from another
+     *                   thread.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
      */
     stop() generates (Status status);
 
@@ -284,25 +313,24 @@
      *
      * This method must return withing 500ms.
      *
-     * After this call returns all work must have been abandoned, all references
-     * must have been released.
+     * When this call returns, if @p status is `OK`, all `Work` items must
+     * have been abandoned, and all resources (including `C2BlockPool` objects
+     * previously created by createBlockPool()) must have been released.
      *
-     * If the return value is BAD_STATE or DUPLICATE, no state change is
-     * expected as a response to this call.
-     * For all other return values, the component shall be in the stopped state.
+     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+     * expected as a response to this call. For all other return values, the
+     * component must be in the stopped state.
      *
-     * This brings settings back to their default - "guaranteeing" no tripped
+     * This brings settings back to their default, "guaranteeing" no tripped
      * state.
      *
      * @return status Status of the call, which may be
-     *   - OK        - The component has been reset.
-     *   - BAD_STATE - Component is in released state.
-     *   - DUPLICATE - When called during another reset call from another
-     *                 thread.
-     *   - TIMED_OUT - The component could not be reset within the time limit.
-     *                 (unexpected)
-     *   - CORRUPTED - Some unknown error prevented resetting the component.
-     *                 (unexpected)
+     *   - `OK`        - The component has been reset.
+     *   - `BAD_STATE` - Component is in released state.
+     *   - `DUPLICATE` - When called during another reset call from another
+     *                   thread.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
      */
     reset() generates (Status status);
 
@@ -311,19 +339,27 @@
      *
      * This method must be supported in stopped state.
      *
-     * This method must return withing 500ms. Upon return all references must
-     * be abandoned.
+     * This method destroys the component. Upon return, if @p status is `OK` or
+     * `DUPLICATE`, all resources must have been released.
      *
      * @return status Status of the call, which may be
-     *   - OK        - The component has been released.
-     *   - BAD_STATE - The component is running.
-     *   - DUPLICATE - The component is already released.
-     *   - TIMED_OUT - The component could not be released within the time
-     *                 limit. (unexpected)
-     *   - CORRUPTED - Some unknown error prevented releasing the component.
-     *                 (unexpected)
+     *   - `OK`        - The component has been released.
+     *   - `BAD_STATE` - The component is running.
+     *   - `DUPLICATE` - The component is already released.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
      */
     release() generates (Status status);
 
+    /**
+     * Returns the @ref IComponentInterface instance associated to this
+     * component.
+     *
+     * An @p IConfigurable instance for the component can be obtained by calling
+     * IComponentInterface::getConfigurable() on the returned @p intf.
+     *
+     * @return intf `IComponentInterface` instance. This must not be null.
+     */
+    getInterface() generates (IComponentInterface intf);
 };
 
diff --git a/media/c2/1.0/IComponentInterface.hal b/media/c2/1.0/IComponentInterface.hal
index d4b30b1..a007d02 100644
--- a/media/c2/1.0/IComponentInterface.hal
+++ b/media/c2/1.0/IComponentInterface.hal
@@ -19,21 +19,20 @@
 import IConfigurable;
 
 /**
- * Component interface object. This object contains all of the configuration of
+ * Component interface object. This object contains all of the configurations of
  * a potential or actual component. It can be created and used independently of
- * an actual Codec 2.0 component instance to query support and parameters for
- * various component settings and configurations for a potential component.
- * Actual components also expose this interface.
+ * an actual Codec2 component to query supported parameters for various
+ * component settings, and configurations for a potential component.
+ *
+ * An actual component exposes this interface via IComponent::getInterface().
  */
-interface IComponentInterface extends IConfigurable {
-    /*
-     * There are no additional methods to IConfigurable interface.
+interface IComponentInterface {
+    /**
+     * Returns the @ref IConfigurable instance associated to this component
+     * interface.
      *
-     * Component interfaces have no states.
-     *
-     * The name of the component or component interface object is a unique name
-     * for that component or component interface 'class'; however, multiple
-     * instances of that component must have the same name.
+     * @return configurable `IConfigurable` instance. This must not be null.
      */
+    getConfigurable() generates (IConfigurable configurable);
 };
 
diff --git a/media/c2/1.0/IComponentListener.hal b/media/c2/1.0/IComponentListener.hal
index eb71ecb..70d5fb2 100644
--- a/media/c2/1.0/IComponentListener.hal
+++ b/media/c2/1.0/IComponentListener.hal
@@ -17,54 +17,112 @@
 package android.hardware.media.c2@1.0;
 
 /**
- * This callback interface is used for handling notifications from IComponent.
+ * Callback interface for handling notifications from @ref IComponent.
  */
 interface IComponentListener {
 
     /**
-     * Notify the listener that some works have been completed.
+     * Notify the listener that some `Work` items have been completed.
+     *
+     * All the input buffers in the returned `Work` objects must not be used by
+     * the component after onWorkDone() is called.
+     *
+     * @param workBundle List of completed `Work` objects.
      */
     oneway onWorkDone(WorkBundle workBundle);
 
     /**
      * Notify the listener that the component is tripped.
+     *
+     * @param settingResults List of failures.
      */
     oneway onTripped(vec<SettingResult> settingResults);
 
     /**
      * Notify the listener of an error.
      *
-     * @param status Error type. \p status may be `OK`, which means that an
-     *     error has occurred, but the error type is unknown.
-     * @param errorCode Additional error code. The framework may not recognize
-     *     this.
+     * @param status Error type. @p status may be `OK`, which means that an
+     *     error has occurred, but the error type does not fit into the type
+     *     `Status`. In this case, additional information is provided by
+     *     @p errorCode.
+     * @param errorCode Additional error information. The framework may not
+     *     recognize the meaning of this value.
      */
     oneway onError(Status status, uint32_t errorCode);
 
     /**
-     * Information about rendering of a frame.
+     * Information about rendering of a frame to a `Surface`.
      */
     struct RenderedFrame {
         /**
-         * Id of the buffer queue containing the rendered buffer.
+         * Id of the `BufferQueue` containing the rendered buffer.
+         *
+         * This value must have been obtained by an earlier call to
+         * IGraphicBufferProducer::getUniqueId().
          */
         uint64_t bufferQueueId;
         /**
          * Id of the slot of the rendered buffer.
+         *
+         * This value must have been obtained by an earlier call to
+         * IGraphicBufferProducer::dequeueBuffer() or
+         * IGraphicBufferProducer::attachBuffer().
          */
         int32_t slotId;
         /**
-         * Timestamp of the rendering (consistent with timestamps in
-         * the associated BufferQueue).
+         * Timestamp the rendering happened.
+         *
+         * The reference point for the timestamp is determined by the
+         * `BufferQueue` that performed the rendering.
          */
         int64_t timestampNs;
     };
 
     /**
-     * Notify the listener that frames are rendered.
+     * Notify the listener that frames have been rendered.
      *
-     * @param renderedFrames List of information about renderings of frames.
+     * @param renderedFrames List of @ref RenderedFrame objects.
      */
     oneway onFramesRendered(vec<RenderedFrame> renderedFrames);
+
+    /**
+     * Identifying information for an input buffer previously queued to the
+     * component via IComponent::queue().
+     */
+    struct InputBuffer {
+        /**
+         * This value comes from `Work::input.ordinal.frameIndex` in a `Work`
+         * object that was previously queued.
+         */
+        uint64_t frameIndex;
+        /**
+         * This value is an index into `Work::input.buffers` (which is an array)
+         * in a `Work` object that was previously queued.
+         */
+        uint32_t arrayIndex;
+    };
+
+    /**
+     * Notify the listener that some input buffers are no longer needed by the
+     * component, and hence can be released or reused by the client.
+     *
+     * Input buffers that are contained in a `Work` object returned by an
+     * earlier onWorkDone() call are assumed released, so they must not appear
+     * in any onInputBuffersReleased() calls. That means
+     * onInputBuffersReleased() must only report input buffers that are released
+     * before the output in the same `Work` item is produced. However, it is
+     * possible for an input buffer to be returned by onWorkDone() after it has
+     * been reported by onInputBuffersReleased().
+     *
+     * @note onWorkDone() and onInputBuffersReleased() both notify the client
+     * that input buffers are no longer needed. However, in order to minimize
+     * IPC calls, onInputBuffersReleased() should be called only when
+     * onWorkDone() cannot be called, e.g., the component needs more input
+     * before an output can be produced.
+     *
+     * @param inputBuffers List of `InputBuffer` objects, identifying input
+     * buffers that are no longer needed by the component.
+     */
+    oneway onInputBuffersReleased(vec<InputBuffer> inputBuffers);
 };
 
diff --git a/media/c2/1.0/IComponentStore.hal b/media/c2/1.0/IComponentStore.hal
index 4bfa170..2aa6a70 100644
--- a/media/c2/1.0/IComponentStore.hal
+++ b/media/c2/1.0/IComponentStore.hal
@@ -23,27 +23,33 @@
 import IConfigurable;
 import IInputSurface;
 
-interface IComponentStore extends IConfigurable {
+/**
+ * Entry point for Codec2 HAL.
+ *
+ * All methods in `IComponentStore` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status. The only exceptions are getPoolClientManager() and getConfigurable(),
+ * which must always return immediately.
+ */
+interface IComponentStore {
 
     /**
      * Creates a component by name.
      *
-     * This method must return within 100ms.
-     *
-     * @param name Name of the component to create. This should match one of the
+     * @param name Name of the component to create. This must match one of the
      *     names returned by listComponents().
-     * @param listener The component listener to use for the component.
-     * @param pool The buffer pool client manager of the component listener.
-     *     This must be null if the listener process does not own a buffer pool.
+     * @param listener Callback receiver.
+     * @param pool `IClientManager` object of the BufferPool in the client
+     *     process. This may be null if the client does not own a BufferPool.
      * @return status Status of the call, which may be
-     *   - OK        - The component was created successfully.
-     *   - NOT_FOUND - There is no component with the given name.
-     *   - NO_MEMORY - Not enough memory to create the component.
-     *   - TIMED_OUT - The component could not be created within the time limit.
-     *                 (unexpected)
-     *   - CORRUPTED - Some unknown error prevented the creation of the
-     *                 component. (unexpected)
-     * @return comp The created component if `Status = OK`.
+     *   - `OK`        - The component was created successfully.
+     *   - `NOT_FOUND` - There is no component with the given name.
+     *   - `NO_MEMORY` - Not enough memory to create the component.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return comp The created component if @p status is `OK`.
+     *
+     * @sa IComponentListener.
      */
     createComponent(
             string name,
@@ -57,19 +63,15 @@
     /**
      * Creates a component interface by name.
      *
-     * This method must return within 100ms.
-     *
      * @param name Name of the component interface to create. This should match
      *     one of the names returned by listComponents().
      * @return status Status of the call, which may be
-     *   - OK        - The component interface was created successfully.
-     *   - NOT_FOUND - There is no component interface with the given name.
-     *   - NO_MEMORY - Not enough memory to create the component interface.
-     *   - TIMED_OUT - The component interface could not be created within the
-     *                 time limit. (unexpected)
-     *   - CORRUPTED - Some unknown error prevented the creation of the
-     *                 component interface. (unexpected)
-     * @return compIntf The created component interface if `Status = OK`.
+     *   - `OK`        - The component interface was created successfully.
+     *   - `NOT_FOUND` - There is no component interface with the given name.
+     *   - `NO_MEMORY` - Not enough memory to create the component interface.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return compIntf The created component interface if @p status is `OK`.
      */
     createInterface(
             string name
@@ -83,57 +85,49 @@
      */
     struct ComponentTraits {
         /**
-         * Name of the component.
+         * Name of the component. This must be unique for each component.
+         *
+         * This name is use to identify the component to create in
+         * createComponent() and createComponentInterface().
          */
         string name;
 
         enum Domain : uint32_t {
-            AUDIO,
+            OTHER = 0,
             VIDEO,
-            OTHER = 0xffffffff,
+            AUDIO,
+            IMAGE,
         };
         /**
-         * Component domain. The framework may not recognize `OTHER`.
+         * Component domain.
          */
         Domain domain;
-        /**
-         * If #domain is `OTHER`, #domainOther can be used to provide additional
-         * information. Otherwise, #domainOther is ignored. The framework may
-         * not inspect this value.
-         */
-        uint32_t domainOther;
 
         enum Kind : uint32_t {
+            OTHER = 0,
             DECODER,
             ENCODER,
-            OTHER = 0xffffffff,
         };
         /**
-         * Component kind. The framework may not recognize `OTHER`.
+         * Component kind.
          */
         Kind kind;
-        /**
-         * If #kind is `OTHER`, #kindOther can be used to provide additional
-         * information. Otherwise, #kindOther is ignored. The framework may not
-         * inspect this value.
-         */
-        uint32_t kindOther;
 
         /**
-         * Rank used by MediaCodecList to determine component ordering. Lower
+         * Rank used by `MediaCodecList` to determine component ordering. Lower
          * value means higher priority.
          */
         uint32_t rank;
 
         /**
-         * Media type.
+         * MIME type.
          */
         string mediaType;
 
         /**
          * Aliases for component name for backward compatibility.
          *
-         * \note Multiple components can have the same alias (but not the same
+         * Multiple components can have the same alias (but not the same
          * component name) as long as their media types differ.
          */
         vec<string> aliases;
@@ -142,36 +136,51 @@
     /**
      * Returns the list of components supported by this component store.
      *
-     * This method must return within 500ms.
-     *
-     * @return traits List of component traits for all components supported by this store in no
-     * particular order.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation was successful.
+     *   - `NO_MEMORY` - Not enough memory to complete this method.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return traits List of component traits for all components supported by
+     *     this store (in no particular order).
      */
-    listComponents() generates (vec<ComponentTraits> traits);
+    listComponents() generates (
+            Status status,
+            vec<ComponentTraits> traits
+        );
 
     /**
      * Creates a persistent input surface that can be used as an input surface
      * for any IComponent instance
      *
-     * This method must return within 100ms.
-     *
-     * @return surface A persistent input surface
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation was successful.
+     *   - `NO_MEMORY` - Not enough memory to complete this method.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return surface A persistent input surface. This may be null to indicate
+     *     an error.
      */
-    createInputSurface() generates (IInputSurface surface);
+    createInputSurface() generates (
+            Status status,
+            IInputSurface surface
+        );
 
     /**
-     * Returns a list of StructDescriptor object for a set of requested
-     * structures that this store is aware of.
+     * Returns a list of `StructDescriptor` objects for a set of requested
+     * C2Param structure indices that this store is aware of.
      *
      * This operation must be performed at best effort, e.g. the component
      * store must simply ignore all struct indices that it is not aware of.
      *
-     * @param indices struct indices to return des
+     * @param indices Indices of C2Param structures to describe.
      * @return status Status of the call, which may be
-     *   - OK        - The operation completed successfully.
-     *   - NOT_FOUND - Some indices were not known.
-     *   - NO_MEMORY - Not enough memory to complete this method.
-     * @return structs List of StructDescriptor objects.
+     *   - `OK`        - The operation completed successfully.
+     *   - `NOT_FOUND` - Some indices were not known.
+     *   - `NO_MEMORY` - Not enough memory to complete this method.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return structs List of `StructDescriptor` objects.
      */
     getStructDescriptors(
             vec<ParamIndex> indices
@@ -181,33 +190,35 @@
         );
 
     /**
-     * Returns information required for using BufferPool API in buffer passing.
-     * If the returned pool is not null, the client can call registerSender() to
-     * register its IAccessor instance, hence allowing the client to send
-     * buffers to components hosted by this process.
-     *
-     * @return pool If the component store supports receiving buffers via
-     *     BufferPool API, \p pool must be a valid `IClientManager` instance.
-     *     Otherwise, \p pool must be null.
-     */
-    getPoolClientManager(
-        ) generates (
-            IClientManager pool
-        );
-
-    /**
-     * The store must copy the contents of \p src into \p dst without changing
-     * the format of \p dst.
+     * Copies the contents of @p src into @p dst without changing the format of
+     * @p dst.
      *
      * @param src Source buffer.
      * @param dst Destination buffer.
      * @return status Status of the call, which may be
-     *   - OK        - The copy is successful.
-     *   - CANNOT_DO - \p src and \p dst are not compatible.
-     *   - REFUSED   - No permission to copy.
-     *   - CORRUPTED - The copy cannot be done. (unexpected)
+     *   - `OK`        - The copy is successful.
+     *   - `CANNOT_DO` - @p src and @p dst are not compatible.
+     *   - `REFUSED`   - No permission to copy.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
      */
     copyBuffer(Buffer src, Buffer dst) generates (Status status);
 
+    /**
+     * Returns the `IClientManager` object for the component's BufferPool.
+     *
+     * @return pool If the component store supports receiving buffers via
+     *     BufferPool API, @p pool must be a valid `IClientManager` instance.
+     *     Otherwise, @p pool must be null.
+     */
+    getPoolClientManager() generates (IClientManager pool);
+
+    /**
+     * Returns the @ref IConfigurable instance associated to this component
+     * store.
+     *
+     * @return configurable `IConfigurable` instance. This must not be null.
+     */
+    getConfigurable() generates (IConfigurable configurable);
 };
 
diff --git a/media/c2/1.0/IConfigurable.hal b/media/c2/1.0/IConfigurable.hal
index cd4dd10..31dc4d3 100644
--- a/media/c2/1.0/IConfigurable.hal
+++ b/media/c2/1.0/IConfigurable.hal
@@ -17,43 +17,78 @@
 package android.hardware.media.c2@1.0;
 
 /**
- * Generic configuration interface used by all configurable Codec 2.0
- * components.
+ * Generic configuration interface presented by all configurable Codec2 objects.
  *
- * This interface must be supported in all states of the inheriting
- * object, and must not change the state of the inheriting object.
+ * This interface must be supported in all states of the owning object, and must
+ * not change the state of the owning object.
  */
 interface IConfigurable {
     /**
-     * Returns the name of this object. This must match the name that was
-     * supplied during the creation of the object.
+     * Returns the id of the object. This must be unique among all objects of
+     * the same type hosted by the same store.
      *
-     * @return name Name of this object.
+     * @return id Id of the object.
+     */
+    getId() generates (uint32_t id);
+
+    /**
+     * Returns the name of the object.
+     *
+     * This must match the name that was supplied during the creation of the
+     * object.
+     *
+     * @return name Name of the object.
      */
     getName() generates (string name);
 
     /**
-     * Queries a set of parameters from the object. Querying is performed at
-     * best effort: the object must query all supported parameters and skip
-     * unsupported ones, or parameters that could not be allocated. Any errors
-     * are communicated in the return value.
+     * Queries a set of parameters from the object.
      *
-     * \note Parameter values do not depend on the order of query.
+     * Querying is performed at best effort: the object must query all supported
+     * parameters and skip unsupported ones (which may include parameters that
+     * could not be allocated). Any errors are communicated in the return value.
      *
-     * This method must return within 1ms if \p mayBlock is DONT_BLOCK, and
-     * within 5ms otherwise.
+     * If @p mayBlock is false, this method must not block. All parameter
+     * queries that require blocking must be skipped.
      *
-     * @param indices List of param indices for params to be queried.
+     * If @p mayBlock is true, a query may block, but the whole method call
+     * has to complete in a timely manner, or `status = TIMED_OUT` is returned.
+     *
+     * If @p mayBlock is false, this method must not block. Otherwise, this
+     * method is allowed to block for a certain period of time before completing
+     * the operation. If the operation is not completed in a timely manner,
+     * `status = TIMED_OUT` is returned.
+     *
+     * @note The order of C2Param objects in @p param does not depend on the
+     *     order of C2Param structure indices in @p indices.
+     *
+     * \par For IComponent
+     *
+     * When the object type is @ref IComponent, this method must be supported in
+     * any state except released. This call must not change the state nor the
+     * internal configuration of the component.
+     *
+     * The blocking behavior of this method differs among states:
+     *   - In the stopped state, this must be non-blocking. @p mayBlock is
+     *     ignored. (The method operates as if @p mayBlock was false.)
+     *   - In any of the running states, this method may block momentarily if
+     *     @p mayBlock is true. However, if the call cannot be completed in a
+     *     timely manner, `status = TIMED_OUT` is returned.
+     *
+     * @param indices List of C2Param structure indices to query.
      * @param mayBlock Whether this call may block or not.
      * @return status Status of the call, which may be
-     *   - OK        - All parameters could be queried.
-     *   - BAD_INDEX - All supported parameters could be queried, but some
-     *                 parameters were not supported.
-     *   - NO_MEMORY - Could not allocate memory for a supported parameter.
-     *   - BLOCKING  - Querying some parameters requires blocking.
-     *   - CORRUPTED - Some unknown error prevented the querying of the
-     *                 parameters. (unexpected)
-     * @return params List of params queried corresponding to \p indices.
+     *   - `OK`        - All parameters could be queried.
+     *   - `BAD_INDEX` - All supported parameters could be queried, but some
+     *                   parameters were not supported.
+     *   - `NO_MEMORY` - Could not allocate memory for a supported parameter.
+     *   - `BLOCKING`  - Querying some parameters requires blocking, but
+     *                   @p mayBlock is false.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return params Flattened representation of C2Param objects.
+     *
+     * @sa Params.
      */
     query(
             vec<ParamIndex> indices,
@@ -64,31 +99,60 @@
         );
 
     /**
-     * Sets a set of parameters for the object. Tuning is performed at best
-     * effort: the object must update all supported configuration at best
-     * effort and skip unsupported parameters. Any errors are communicated in
-     * the return value and in \p failures.
+     * Sets a set of parameters for the object.
      *
-     * \note Parameter tuning DOES depend on the order of the tuning parameters.
-     * E.g. some parameter update may allow some subsequent parameter update.
+     * Tuning is performed at best effort: the object must update all supported
+     * configurations at best effort and skip unsupported parameters. Any errors
+     * are communicated in the return value and in @p failures.
      *
-     * This method must return within 1ms if \p mayBlock is false, and within
-     * 5ms otherwise.
+     * A non-strict parameter update with an unsupported value shall cause an
+     * update to the closest supported value. A strict parameter update with an
+     * unsupported value shall be skipped and a failure shall be returned.
+     *
+     * If @p mayBlock is false, this method must not block. An update that
+     * requires blocking shall be skipped and a failure shall be returned.
+     *
+     * If @p mayBlock is true, an update may block, but the whole method call
+     * has to complete in a timely manner, or `status = TIMED_OUT` is returned.
+     *
+     * The final values for all parameters set are propagated back to the caller
+     * in @p params.
+     *
+     * \par For IComponent
+     *
+     * When the object type is @ref IComponent, this method must be supported in
+     * any state except released.
+     *
+     * The blocking behavior of this method differs among states:
+     *   - In the stopped state, this must be non-blocking. @p mayBlock is
+     *     ignored. (The method operates as if @p mayBlock was false.)
+     *   - In any of the running states, this method may block momentarily if
+     *     @p mayBlock is true. However, if the call cannot be completed in a
+     *     timely manner, `status = TIMED_OUT` is returned.
+     *
+     * @note Parameter tuning @e does depend on the order of the tuning
+     * parameters, e.g., some parameter update may enable some subsequent
+     * parameter update.
      *
      * @param inParams Requested parameter updates.
      * @param mayBlock Whether this call may block or not.
      * @return status Status of the call, which may be
-     *   - OK        - All parameters could be updated successfully.
-     *   - BAD_INDEX - All supported parameters could be updated successfully,
-     *                 but some parameters were not supported.
-     *   - NO_MEMORY - Some supported parameters could not be updated
-     *                 successfully because they contained unsupported values.
-     *                 These are returned in \p failures.
-     *   - BLOCKING  - Setting some parameters requires blocking.
-     *   - CORRUPTED - Some unknown error prevented the update of the
-     *                 parameters. (unexpected)
-     * @return failures List of parameter failures.
-     * @return outParams Resulting values for the configured parameters.
+     *   - `OK`        - All parameters could be updated successfully.
+     *   - `BAD_INDEX` - All supported parameters could be updated successfully,
+     *                   but some parameters were not supported.
+     *   - `NO_MEMORY` - Some supported parameters could not be updated
+     *                   successfully because they contained unsupported values.
+     *                   These are returned in @p failures.
+     *   - `BLOCKING`  - Setting some parameters requires blocking, but
+     *                   @p mayBlock is false.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return failures List of update failures.
+     * @return outParams Flattened representation of configured parameters. The
+     *     order of parameters in @p outParams is based on the order of
+     *     requested updates in @p inParams.
+     *
+     * @sa SettingResult.
      */
     config(
             Params inParams,
@@ -103,22 +167,19 @@
     // =========================================================================
 
     /**
-     * Returns a selected range of the set of supported parameters.
+     * Returns a list of supported parameters within a selected range of C2Param
+     * structure indices.
      *
-     * The set of supported parameters are represented in a vector with a
-     * start index of 0, and the selected range are indices into this vector.
-     * Fewer than \p count parameters are returned if the selected range is
-     * not fully/not at all part of the available vector indices.
-     *
-     * This method must return within 1ms.
-     *
-     * @param start start index of selected range
-     * @param count size of the selected
+     * @param start The first index of the selected range.
+     * @param count The length of the selected range.
      * @return status Status of the call, which may be
-     *   - OK        - The operation completed successfully.
-     *   - NO_MEMORY - Not enough memory to complete this method.
-     * @return params Vector containing the selected range of supported
-     *     parameters.
+     *   - `OK`        - The operation completed successfully.
+     *   - `NO_MEMORY` - Not enough memory to complete this method.
+     * @return params List of supported parameters in the selected range. This
+     *     list may have fewer than @p count elements if some indices in the
+     *     range are not supported.
+     *
+     * @sa ParamDescriptor.
      */
     querySupportedParams(
             uint32_t start,
@@ -131,23 +192,42 @@
     /**
      * Retrieves the supported values for the queried fields.
      *
-     * Upon return the object must fill in the supported
-     * values for the fields listed as well as a status for each field.
-     * Object shall process all fields queried even if some queries fail.
+     * The object must process all fields queried even if some queries fail.
      *
-     * This method must return within 1ms if \p mayBlock is false, and within
-     * 5ms otherwise.
+     * If @p mayBlock is false, this method must not block. Otherwise, this
+     * method is allowed to block for a certain period of time before completing
+     * the operation. If the operation cannot be completed in a timely manner,
+     * `status = TIMED_OUT` is returned.
      *
-     * @param inFields Vector of field queries.
+     * \par For IComponent
+     *
+     * When the object type is @ref IComponent, this method must be supported in
+     * any state except released.
+     *
+     * The blocking behavior of this method differs among states:
+     *   - In the stopped state, this must be non-blocking. @p mayBlock is
+     *     ignored. (The method operates as if @p mayBlock was false.)
+     *   - In any of the running states, this method may block momentarily if
+     *     @p mayBlock is true. However, if the call cannot be completed in a
+     *     timely manner, `status = TIMED_OUT` is returned.
+     *
+     * @param inFields List of field queries.
      * @param mayBlock Whether this call may block or not.
      * @return status Status of the call, which may be
-     *   - OK        - The operation completed successfully.
-     *   - BLOCKING  - Querying some parameters requires blocking.
-     *   - NO_MEMORY - Not enough memory to complete this method.
-     *   - BAD_INDEX - At least one field was not recognized as a component
-     *                 field.
-     * @return outFields Vector containing supported values and query result
-     *     for the selected fields.
+     *   - `OK`        - The operation completed successfully.
+     *   - `BLOCKING`  - Querying some parameters requires blocking, but
+     *                   @p mayBlock is false.
+     *   - `NO_MEMORY` - Not enough memory to complete this method.
+     *   - `BAD_INDEX` - At least one field was not recognized as a component
+     *                   field.
+     *   - `BLOCKING`  - Querying some fields requires blocking, but @p mayblock
+     *                   is false.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return outFields List of supported values and results for the
+     *     supplied queries.
+     *
+     * @sa FieldSupportedValuesQuery, FieldSupportedValuesQueryResult.
      */
     querySupportedValues(
             vec<FieldSupportedValuesQuery> inFields,
diff --git a/media/c2/1.0/IInputSink.hal b/media/c2/1.0/IInputSink.hal
new file mode 100644
index 0000000..809c27a
--- /dev/null
+++ b/media/c2/1.0/IInputSink.hal
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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.media.c2@1.0;
+
+import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer;
+
+import IConfigurable;
+
+/**
+ * An `IInputSink` is a receiver of work items.
+ *
+ * An @ref IComponent instance can present itself as an `IInputSink` via a thin
+ * wrapper.
+ *
+ * @sa IInputSurface, IComponent.
+ */
+interface IInputSink {
+    /**
+     * Feeds work to the sink.
+     *
+     * @param workBundle `WorkBundle` object containing a list of `Work` objects
+     *     to queue to the component.
+     * @return status Status of the call, which may be
+     *   - `OK`        - Works in @p workBundle were successfully queued.
+     *   - `BAD_INDEX` - Some component id in some `Worklet` is not valid.
+     *   - `CANNOT_DO` - Tunneling has not been set up for this sink, but some
+     *                   `Work` object contains tunneling information.
+     *   - `NO_MEMORY` - Not enough memory to queue @p workBundle.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     */
+    queue(WorkBundle workBundle) generates (Status status);
+
+    /**
+     * Returns the @ref IConfigurable instance associated to this sink.
+     *
+     * @return configurable `IConfigurable` instance. This must not be null.
+     */
+    getConfigurable() generates (IConfigurable configurable);
+};
+
diff --git a/media/c2/1.0/IInputSurface.hal b/media/c2/1.0/IInputSurface.hal
index c083a21..d11ce15 100644
--- a/media/c2/1.0/IInputSurface.hal
+++ b/media/c2/1.0/IInputSurface.hal
@@ -19,43 +19,57 @@
 import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer;
 
 import IConfigurable;
-import IComponent;
+import IInputSink;
 import IInputSurfaceConnection;
 
 /**
- * Input surface that can be configured for the IComponent.
+ * Input surface for a Codec2 component.
+ *
+ * An <em>input surface</em> is an instance of `IInputSurface`, which may be
+ * created by calling IComponentStore::createInputSurface(). Once created, the
+ * client may
+ *   1. write data to it via the `IGraphicBufferProducer` interface; and
+ *   2. use it as input to a Codec2 encoder.
+ *
+ * @sa IInputSurfaceConnection, IComponentStore::createInputSurface(),
+ *     IComponent::connectToInputSurface().
  */
-interface IInputSurface extends IGraphicBufferProducer {
+interface IInputSurface {
+    /**
+     * Returns the producer interface into the internal buffer queue.
+     *
+     * @return producer `IGraphicBufferProducer` instance. This must not be
+     * null.
+     */
+    getGraphicBufferProducer() generates (IGraphicBufferProducer producer);
 
     /**
-     * Connects this input surface to a component.
+     * Returns the @ref IConfigurable instance associated to this input surface.
      *
-     * This call must return within 100 ms.
-     *
-     * @param component The component to connect to. This must have type
-     *     IComponent.
-     * @return status Status of the call, which may be
-     *   - OK        - The operation succeeded.
-     *   - BAD_STATE - The component is in running state.
-     *   - DUPLICATE - The surface is already connected to a component.
-     *   - NO_MEMORY - Could not allocate memory to connect to the component.
-     *   - CORRUPTED - Some unknown error prevented the connection. (unexpected)
-     * @return connection Connection object that is used to disconnect
-     *     from the component.
+     * @return configurable `IConfigurable` instance. This must not be null.
      */
-    connectToComponent(
-            IComponent component
+    getConfigurable() generates (IConfigurable configurable);
+
+    /**
+     * Connects the input surface to an input sink.
+     *
+     * This function is generally called from inside the implementation of
+     * IComponent::connectToInputSurface(), where @p sink is a thin wrapper of
+     * the component that consumes buffers from this surface.
+     *
+     * @param sink Input sink. See `IInputSink` for more information.
+     * @return status Status of the call, which may be
+     *   - `OK`        - Configuration successful.
+     *   - `BAD_VALUE` - @p sink is invalid.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return connection `IInputSurfaceConnection` object. This must not be
+     *     null if @p status is `OK`.
+     */
+    connect(
+            IInputSink sink
         ) generates (
             Status status,
             IInputSurfaceConnection connection
         );
-
-    /**
-     * Returns the Codec 2.0 configuration object for this surface.
-     *
-     * @return configurable The configuration object for this surface.
-     */
-    getConfigurable() generates (IConfigurable configurable);
-
 };
 
diff --git a/media/c2/1.0/IInputSurfaceConnection.hal b/media/c2/1.0/IInputSurfaceConnection.hal
index 500091d..035b115 100644
--- a/media/c2/1.0/IInputSurfaceConnection.hal
+++ b/media/c2/1.0/IInputSurfaceConnection.hal
@@ -16,20 +16,33 @@
 
 package android.hardware.media.c2@1.0;
 
-interface IInputSurfaceConnection {
+import IConfigurable;
 
+/**
+ * Connection between a component and an input surface.
+ *
+ * An instance of `IInputSurfaceConnection` contains an `IConfigurable`
+ * interface for querying and configuring properties of the connection.
+ */
+interface IInputSurfaceConnection {
     /**
-     * Disconnects this input surface from the component.
-     *
-     * This call must return within 100 ms.
+     * Destroys the connection between an input surface and a component.
      *
      * @return status Status of the call, which may be
-     *   - OK        - The operation succeeded.
-     *   - BAD_STATE - The component is not in running state.
-     *   - NOT_FOUND - The surface is not connected to a component.
-     *   - CORRUPTED - Some unknown error prevented the connection. (unexpected)
+     *   - `OK`        - The disconnection succeeded.
+     *   - `BAD_STATE` - The component is not in running state.
+     *   - `NOT_FOUND` - The surface is not connected to a component.
+     *   - `CORRUPTED` - Some unknown error occurred.
      */
     disconnect() generates (Status status);
 
+    /**
+     * Returns the @ref IConfigurable instance associated to this connection.
+     *
+     * This can be used to customize the connection.
+     *
+     * @return configurable `IConfigurable` instance. This must not be null.
+     */
+    getConfigurable() generates (IConfigurable configurable);
 };
 
diff --git a/media/c2/1.0/types.hal b/media/c2/1.0/types.hal
index 252d781..ec422b1 100644
--- a/media/c2/1.0/types.hal
+++ b/media/c2/1.0/types.hal
@@ -18,220 +18,278 @@
 
 import android.hardware.media.bufferpool@2.0::BufferStatusMessage;
 
+/**
+ * Common return values for Codec2 operations.
+ */
 enum Status : int32_t {
-    /** operation completed successfully */
+    /** Operation completed successfully. */
     OK        = 0,
 
     // bad input
 
-    /** argument has invalid value (user error) */
+    /** Argument has invalid value (user error). */
     BAD_VALUE = -22,
-    /** argument uses invalid index (user error) */
+    /** Argument uses invalid index (user error). */
     BAD_INDEX = -75,
-    /** argument/index is valid but not possible */
+    /** Argument/Index is valid but not possible. */
     CANNOT_DO = -2147483646,
 
     // bad sequencing of events
 
-    /** object already exists */
+    /** Object already exists. */
     DUPLICATE = -17,
-    /** object not found */
+    /** Object not found. */
     NOT_FOUND = -2,
-    /** operation is not permitted in the current state */
+    /** Operation is not permitted in the current state. */
     BAD_STATE = -38,
-    /** operation would block but blocking is not permitted */
+    /** Operation would block but blocking is not permitted. */
     BLOCKING  = -9930,
 
     // bad environment
 
-    /** not enough memory to complete operation */
+    /** Not enough memory to complete operation. */
     NO_MEMORY = -12,
-    /** missing permission to complete operation */
+    /** Missing permission to complete operation. */
     REFUSED   = -1,
 
-    /** operation did not complete within timeout */
+    /** Operation did not complete within timeout. */
     TIMED_OUT = -110,
 
     // missing functionality
 
-    /** operation is not implemented/supported (optional only) */
+    /** Operation is not implemented/supported (optional only). */
     OMITTED   = -74,
 
     // unknown fatal
 
-    /** some unexpected error prevented the operation */
+    /** Some unexpected error prevented the operation. */
     CORRUPTED = -2147483648,
 
     // uninitialized
 
-    /** status has not been initialized */
+    /** Status has not been initialized. */
     NO_INIT   = -19,
 };
 
 /**
- * Codec 2.0 parameter index
+ * C2Param structure index.
+ *
+ * This is a number that is unique for each C2Param structure type.
+ *
+ * @sa Codec 2.0 standard.
  */
 typedef uint32_t ParamIndex;
 
 /**
- * Codec 2.0 parameter structure
+ * Flattened representation of C2Param objects.
  *
- * The description of a Params is provided by supplying a ParamIndex to
- * IComponentStore::getStructDescriptors().
+ * The `Params` type is an array of bytes made up by concatenating a list of
+ * C2Param objects. The start index (offset into @ref Params) of each C2Param
+ * object in the list is divisible by 8. Up to 7 padding bytes may be added
+ * after each C2Param object to achieve this 64-bit alignment.
+ *
+ * Each C2Param object has the following layout:
+ * - 4 bytes: C2Param structure index (of type @ref ParamIndex) identifying the
+ *   type of the C2Param object.
+ * - 4 bytes: size of the C2Param object (unsigned 4-byte integer).
+ * - (size - 8) bytes: data of the C2Param object.
+ *
+ * In order to interpret each C2Param object correctly, its structure must be
+ * described by IComponentStore::getStructDescriptors().
+ *
+ * @note Please refer to the Codec 2.0 standard for the list of standard
+ * parameter structures.
+ *
+ * @sa Codec 2.0 standard.
  */
 typedef vec<uint8_t> Params;
 
 /**
- * Struct uniquely specifying a field in an arbitrary parameter structure.
+ * Identifying information of a field relative to a known C2Param structure.
+ *
+ * Within a given C2Param structure, each field is uniquely identified by @ref
+ * FieldId.
  */
 struct FieldId {
-    /** Offset of the field in bytes */
+    /** Offset of the field in bytes. */
     uint32_t offset;
-    /** Size of the field in bytes */
+    /** Size of the field in bytes. */
     uint32_t size;
 };
 
 /**
- * Struct representing a location of a field in a parameter with a given index.
+ * Reference to a field in a C2Param structure.
  */
 struct ParamField {
-    /** Index of the parameter */
+    /** Index of the C2Param structure. */
     ParamIndex index;
-    /** Field identifier */
+    /** Identifier of the field inside the C2Param structure. */
     FieldId fieldId;
 };
 
 /**
- * Struct describing basic properties of a parameter with a given index.
+ * Usage description of a C2Param structure.
+ *
+ * @ref ParamDescriptor is returned by IConfigurable::querySupportedParams().
  */
 struct ParamDescriptor {
-    /** Parameter index */
+    /**
+     * Index of the C2Param structure being described.
+     */
     ParamIndex index;
 
     enum Attrib : uint32_t {
         /**
-         * Parameter is required to be specified.
+         * The parameter is required to be specified.
          */
         REQUIRED   = 1u << 0,
         /**
-         * Parameter retains its value.
+         * The parameter retains its value.
          */
         PERSISTENT = 1u << 1,
         /**
-         * Parameter is strict.
+         * The parameter is strict.
          */
         STRICT     = 1u << 2,
         /**
-         * Parameter is publicly read-only.
+         * The parameter is publicly read-only.
          */
         READ_ONLY  = 1u << 3,
         /**
-         * Parameter must not be visible to clients.
+         * The parameter must not be visible to clients.
          */
         HIDDEN     = 1u << 4,
         /**
-         * Parameter must not be used by framework (other than testing).
+         * The parameter must not be used by framework (other than testing).
          */
         INTERNAL   = 1u << 5,
         /**
-         * Parameter is publicly constant (hence read-only).
+         * The parameter is publicly constant (hence read-only).
          */
         CONST      = 1u << 6,
     };
-    /** Parameter attributes */
     bitfield<Attrib> attrib;
 
-    /** Parameter name */
+    /**
+     * Name of the structure. This must be unique for each structure.
+     */
     string name;
 
-    /** index of other parameters that this parameter depends on */
+    /**
+     * Indices of other C2Param structures that this C2Param structure depends
+     * on.
+     */
     vec<ParamIndex> dependencies;
 };
 
-// Generic way to describe supported numeric values for Codec 2.0 interfaces.
+// Generic way to describe supported numeric values for Codec2 interfaces.
 
 /**
- * An untyped value that can fit on 64 bits - the type of which is communicated
- * via a separate channel (FieldType).
+ * An untyped value that can fit in 64 bits, the type of which is communicated
+ * via a separate channel (@ref FieldSupportedValues.type).
  */
 typedef uint64_t PrimitiveValue;
 
 /*
- * Generic supported values for a field.
+ * Description of supported values for a field.
  *
- * This can be either a range or a set of values. The range can be linear or
- * geometric with clear minimum and maximum values, and can have an optional
- * step size or geometric ratio. Values can optionally represent flags.
+ * This can be a continuous range or a discrete set of values.
  */
 struct FieldSupportedValues {
+    /**
+     * Used if #type is `RANGE`.
+     *
+     * If the `step` member is 0, and `num` and `denom` are both 1, the `Range`
+     * structure represents a closed interval bounded by `min` and `max`.
+     *
+     * Otherwise, the #Range structure represents a finite sequence of numbers
+     * produced from the following recurrence relation:
+     *
+     * @code
+     * v[0] = min
+     * v[i] = v[i - 1] * num / denom + step ; i >= 1
+     * @endcode
+     *
+     * Both the ratio `num / denom` and the value `step` must be positive. The
+     * last number in the sequence described by this #Range structure is the
+     * largest number in the sequence that is smaller than or equal to `max`.
+     *
+     * @note
+     * The division in the formula may truncate the result if the data type of
+     * these values is an integral type.
+     */
     struct Range {
+        /**
+         * Lower end of the range (inclusive).
+         */
         PrimitiveValue min;
+        /**
+         * Upper end of the range (inclusive).
+         */
         PrimitiveValue max;
+        /**
+         * The non-homogeneous term in the recurrence relation.
+         */
         PrimitiveValue step;
+        /**
+         * The numerator of the scale coefficient in the recurrence relation.
+         */
         PrimitiveValue num;
+        /**
+         * The denominator of the scale coefficient in the recurrence relation.
+         */
         PrimitiveValue denom;
     };
 
     enum Type : int32_t {
         /** No supported values */
-        EMPTY,
-        /** Numeric range that can be continuous or discrete */
+        EMPTY = 0,
+        /** Numeric range, described in a #Range structure */
         RANGE,
         /** List of values */
         VALUES,
         /** List of flags that can be OR-ed */
         FLAGS,
-        /** Other representations */
-        OTHER = 0xffffffff,
     };
     /**
-     * Type of the supported values. The framework may not recognize `OTHER`.
+     * Type of the supported values.
      */
     Type type;
-    /**
-     * Codec2.0 type code of the supported values.
-     *   * If #type is `OTHER`, #typeOther can be used to give more information.
-     *     In this case, the interpretation of this structure is
-     *     implementation-defined.
-     *   * For all other values of #type, #typeOther is not used.
-     * The framework may not inspect this value.
-     */
-    int32_t typeOther;
-
-    /*
-     * If #type = EMPTY, #range and #value are unused.
-     */
 
     /**
-     * If #type = RANGE, #range will specify the range of possible values.
+     * When #type is #Type.RANGE, #range shall specify the range of possible
+     * values.
      *
-     * The intended type of members of #range will be clear in the context where
-     * FieldSupportedValues is used.
+     * The intended type of members of #range shall be clear in the context
+     * where `FieldSupportedValues` is used.
      */
     Range range;
 
     /**
-     * If #type is `VALUES` or `FLAGS`, #value will list supported values.
+     * When #type is #Type.VALUES or #Type.FLAGS, #value shall list supported
+     * values/flags.
      *
-     * The intended type of components of #value will be clear in the context
-     * where FieldSupportedValues is used.
+     * The intended type of components of #value shall be clear in the context
+     * where `FieldSupportedValues` is used.
      */
     vec<PrimitiveValue> values;
 };
 
 /**
- * Supported values for a specific field.
+ * Supported values for a field.
  *
  * This is a pair of the field specifier together with an optional supported
  * values object. This structure is used when reporting parameter configuration
  * failures and conflicts.
  */
 struct ParamFieldValues {
-    /** the field or parameter */
+    /**
+     * Reference to a field or a C2Param structure.
+     */
     ParamField paramOrField;
 
     /**
-     * optional supported values for the field if paramOrField specifies an
+     * Optional supported values for the field if #paramOrField specifies an
      * actual field that is numeric (non struct, blob or string). Supported
      * values for arrays (including string and blobs) describe the supported
      * values for each element (character for string, and bytes for blobs). It
@@ -241,18 +299,18 @@
 };
 
 /**
- * Field descriptor.
+ * Description of a field inside a C2Param structure.
  */
 struct FieldDescriptor {
 
-    /** Field id */
+    /** Location of the field in the C2Param structure */
     FieldId fieldId;
 
     /**
-     * Possible types of a field.
+     * Possible types of the field.
      */
     enum Type : uint32_t {
-        NO_INIT,
+        NO_INIT = 0,
         INT32,
         UINT32,
         CNTR32,
@@ -261,186 +319,227 @@
         CNTR64,
         FLOAT,
         /**
-         * Fixed-size string (POD)
+         * Fixed-size string (POD).
          */
         STRING = 0x100,
         /**
-         * blobs have no sub-elements and can be thought of as byte arrays.
-         * However, bytes cannot be individually addressed by clients.
+         * A blob has no sub-elements and can be thought of as an array of
+         * bytes. However, bytes cannot be individually addressed by clients.
          */
         BLOB,
         /**
-         * Structs. Marked with this flag in addition to their coreIndex.
+         * The field is a structure that may contain other fields.
          */
-        STRUCT_FLAG = 0x20000,
+        STRUCT = 0x20000,
     };
     /**
      * Type of the field.
      */
     bitfield<Type> type;
 
-    /** Extent of the field */
-    uint32_t length;
-    /*
-     * Note: the last member of a param struct can be of arbitrary length (e.g.
-     * if it is T[] array, which extends to the last byte of the parameter.)
-     * This is marked with extent 0.
+    /**
+     * If #type is #Type.STRUCT, #structIndex is the C2Param structure index;
+     * otherwise, #structIndex is not used.
      */
+    ParamIndex structIndex;
 
-    /** Name of the field */
+    /**
+     * Extent of the field.
+     * - For a non-array field, #extent is 1.
+     * - For a fixed-length array field, #extent is the length. An array field
+     *   of length 1 is indistinguishable from a non-array field.
+     * - For a variable-length array field, #extent is 0. This can only occur as
+     *   the last member of a C2Param structure.
+     */
+    uint32_t extent;
+
+    /**
+     * Name of the field. This must be unique for each field in the same
+     * structure.
+     */
     string name;
-    /** Named value type */
+
+    /**
+     * Named value type. This is used for defining an enum value for a numeric
+     * type.
+     */
     struct NamedValue {
+        /**
+         * Name of the enum value. This must be unique for each enum value in
+         * the same field.
+         */
         string name;
+        /**
+         * Underlying value of the enum value. Multiple enum names may have the
+         * same underlying value.
+         */
         PrimitiveValue value;
     };
-    /** Named values for the field */
+    /**
+     * List of enum values. This is not used when #type is not one of the
+     * numeric types.
+     */
     vec<NamedValue> namedValues;
 };
 
 /**
- * Struct descriptor.
+ * Description of a C2Param structure. It consists of an index and a list of
+ * `FieldDescriptor`s.
  */
 struct StructDescriptor {
-    /** Struct type */
+    /**
+     * Index of the structure.
+     */
     ParamIndex type;
-    /** Field descriptors for each field */
+    /**
+     * List of fields in the structure.
+     *
+     * Fields are ordered by their offsets. A field that is a structure is
+     * ordered before its members.
+     */
     vec<FieldDescriptor> fields;
 };
 
 /**
- * Information describing the reason a parameter settings may fail, or
- * may be overriden.
+ * Information describing the reason the parameter settings may fail, or may be
+ * overridden.
  */
 struct SettingResult {
-    /** Failure code (of Codec 2.0 SettingResult failure type) */
+    /** Failure code */
     enum Failure : uint32_t {
-        /** Parameter is read-only and cannot be set. */
-        READ_ONLY,
-        /** Parameter mismatches input data. */
-        MISMATCH,
-        /** Parameter does not accept value. */
-        BAD_VALUE,
         /** Parameter is not supported. */
         BAD_TYPE,
         /** Parameter is not supported on the specific port. */
         BAD_PORT,
         /** Parameter is not supported on the specific stream. */
         BAD_INDEX,
-        /** Parameter is in conflict with an/other setting(s). */
+        /** Parameter is read-only and cannot be set. */
+        READ_ONLY,
+        /** Parameter mismatches input data. */
+        MISMATCH,
+        /** Strict parameter does not accept value for the field at all. */
+        BAD_VALUE,
+        /**
+         * Strict parameter field value is in conflict with an/other
+         * setting(s).
+         */
         CONFLICT,
         /**
-         * Parameter is out of range due to other settings. (This failure mode
-         * can only be used for strict parameters.)
+         * Parameter field is out of range due to other settings. (This failure
+         * mode can only be used for strict calculated parameters.)
          */
         UNSUPPORTED,
         /**
+         * Field does not access the requested parameter value at all. It has
+         * been corrected to the closest supported value. This failure mode is
+         * provided to give guidance as to what are the currently supported
+         * values for this field (which may be a subset of the at-all-potential
+         * values).
+         */
+        INFO_BAD_VALUE,
+        /**
          * Requested parameter value is in conflict with an/other setting(s)
          * and has been corrected to the closest supported value. This failure
-         * mode is given to provide suggestion to the client as to how to enable
-         * the requested parameter value. */
-        INFO_CONFLICT,
-        /**
-         * This failure mode is reported when all the above failure modes do not
-         * apply.
+         * mode is given to provide guidance as to what are the currently
+         * supported values as well as to optionally provide suggestion to the
+         * client as to how to enable the requested parameter value.
          */
-        OTHER = 0xffffffff,
+        INFO_CONFLICT,
     };
-    /**
-     * The failure type. The framework might not recognize `OTHER`.
-     */
     Failure failure;
-    /**
-     * The failure code.
-     *   * If #failure is `OTHER`, #failureOther can be used to give more
-     *     information.
-     *   * For all other values of #failure, #failureOther is not used.
-     * The framework may not inspect this value.
-     */
-    uint32_t failureOther;
 
     /**
-     * Failing (or corrected) field. Currently supported values for the field.
-     * This is set if different from the globally supported values (e.g. due to
-     * restrictions by another param or input data)
+     * Failing (or corrected) field or parameter and optionally, currently
+     * supported values for the field. Values must only be set for field
+     * failures other than `BAD_VALUE`, and only if they are different from the
+     * globally supported values (e.g. due to restrictions by another parameter
+     * or input data).
      */
     ParamFieldValues field;
 
     /**
-     * Conflicting parameters or fields with
-     * (optional) suggested values for any conflicting fields to avoid the conflict.
+     * Conflicting parameters or fields with (optional) suggested values for any
+     * conflicting fields to avoid the conflict. Values must only be set for
+     * `CONFLICT`, `UNSUPPORTED` or `INFO_CONFLICT` failure code.
      */
     vec<ParamFieldValues> conflicts;
 };
 
 /**
- * Data structure for ordering Work objects. Each member is used for comparing
- * urgency in the same fashion: a smaller value indicates that the associated
- * Work object is more urgent.
+ * Ordering information of @ref FrameData objects. Each member is used for
+ * comparing urgency: a smaller difference from a reference value indicates that
+ * the associated Work object is more urgent. The reference value for each
+ * member is initialized the first time it is communicated between the client
+ * and the codec, and it may be updated to later values that are communicated.
+ *
+ * Each member of `WorkOrdinal` is stored as an unsigned integer, but the actual
+ * order it represents is derived by subtracting the reference value, then
+ * interpreting the result as a signed number with the same storage size (using
+ * two's complement).
+ *
+ * @note `WorkOrdinal` is the HIDL counterpart of `C2WorkOrdinalStruct` in the
+ * Codec 2.0 standard.
  */
 struct WorkOrdinal {
     /**
-     * Timestamp in microseconds - can wrap around.
+     * Timestamp in microseconds.
      */
     uint64_t timestampUs;
     /**
-     * Frame index - can wrap around.
+     * Frame index.
      */
     uint64_t frameIndex;
     /**
-     * Component specific frame ordinal - can wrap around.
+     * Component specific frame ordinal.
      */
     uint64_t customOrdinal;
 };
 
 /**
- * A structure that holds information of a Block. There are two types of Blocks:
- * NATIVE and POOLED. Each type has its own way of identifying blocks.
+ * Storage type for `BaseBlock`.
+ *
+ * A `BaseBlock` is a representation of a codec memory block. Coded data,
+ * decoded data, codec-specific data, and other codec-related data are all sent
+ * in the form of BaseBlocks.
  */
-struct BaseBlock {
-    enum Type : int32_t {
-        NATIVE,
-        POOLED,
-    };
+safe_union BaseBlock {
     /**
-     * There are two types of blocks: NATIVE and POOLED.
-     */
-    Type type;
-
-    /**
-     * A "NATIVE" block is represented by a native handle.
+     * #nativeBlock is the opaque representation of a buffer.
      */
     handle nativeBlock;
-
-    /*
-     * A "POOLED" block is represented by `BufferStatusMessage`.
+    /**
+     * #pooledBlock is a reference to a buffer handled by a BufferPool.
      */
     BufferStatusMessage pooledBlock;
 };
 
 /**
- * A Block in transfer consists of an index into an array of BaseBlock plus some
- * extra information. One BaseBlock may occur in multiple blocks in one
- * `WorkBundle`.
+ * Reference to a @ref BaseBlock within a @ref WorkBundle.
+ *
+ * `Block` contains additional attributes that `BaseBlock` does not. These
+ * attributes may differ among `Block` objects that refer to the same
+ * `BaseBlock` in the same `WorkBundle`.
  */
 struct Block {
     /**
-     * Identity of the BaseBlock within a WorkBundle. This is an index into the
-     * `baseBlocks` array of a `WorkBundle` object.
+     * Identity of a `BaseBlock` within a `WorkBundle`. This is an index into
+     * #WorkBundle.baseBlocks.
      */
     uint32_t index;
     /**
-     * Metadata associated with the block.
+     * Metadata associated with this `Block`.
      */
     Params meta;
     /**
-     * Fence for synchronizing block access.
+     * Fence for synchronizing `Block` access.
      */
     handle fence;
 };
 
 /**
- * Type of buffers processed by a component.
+ * A codec buffer, which is a collection of @ref Block objects and metadata.
+ *
+ * This is a part of @ref FrameData.
  */
 struct Buffer {
     /**
@@ -454,23 +553,37 @@
 };
 
 /**
- * An extension of Buffer that also contains an index.
+ * An extension of @ref Buffer that also contains a C2Param structure index.
+ *
+ * This is a part of @ref FrameData.
  */
 struct InfoBuffer {
+    /**
+     * A C2Param structure index.
+     */
     ParamIndex index;
+    /**
+     * Associated @ref Buffer object.
+     */
     Buffer buffer;
 };
 
 /**
- * This structure represents a frame with its metadata. A frame consists of an
- * ordered set of buffers, configuration changes, and info buffers along with
- * some non-configuration metadata.
+ * Data for an input frame or an output frame.
+ *
+ * This structure represents a @e frame with its metadata. A @e frame consists
+ * of an ordered set of buffers, configuration changes, and info buffers along
+ * with some non-configuration metadata.
+ *
+ * @note `FrameData` is the HIDL counterpart of `C2FrameData` in the Codec 2.0
+ * standard.
  */
 struct FrameData {
     enum Flags : uint32_t {
         /**
-         * For input frames: no output frame will be generated when processing
+         * For input frames: no output frame shall be generated when processing
          * this frame, but metadata must still be processed.
+         *
          * For output frames: this frame must be discarded but metadata is still
          * valid.
          */
@@ -482,92 +595,178 @@
         END_OF_STREAM = (1 << 1),
         /**
          * This frame must be discarded with its metadata.
-         * This flag is only set by components - e.g. as a response to the flush
+         *
+         * This flag is only set by components, e.g. as a response to the flush
          * command.
          */
         DISCARD_FRAME = (1 << 2),
         /**
+         * This frame is not the last frame produced for the input.
+         *
+         * This flag is normally set by the component - e.g. when an input frame
+         * results in multiple output frames, this flag is set on all but the
+         * last output frame.
+         *
+         * Also, when components are chained, this flag should be propagated
+         * down the work chain. That is, if set on an earlier frame of a
+         * work-chain, it should be propagated to all later frames in that
+         * chain. Additionally, components down the chain could set this flag
+         * even if not set earlier, e.g. if multiple output frames are generated
+         * at that component for the input frame.
+         */
+        FLAG_INCOMPLETE = (1 << 3),
+        /**
          * This frame contains only codec-specific configuration data, and no
          * actual access unit.
          *
-         * \deprecated Pass codec configuration with the codec-specific
+         * @deprecated Pass codec configuration with the codec-specific
          * configuration info together with the access unit.
          */
         CODEC_CONFIG  = (1u << 31),
     };
 
     /**
-     * Frame flags.
+     * Frame flags, as described in #Flags.
      */
     bitfield<Flags> flags;
 
     /**
-     * Ordinal of the frame.
+     * @ref WorkOrdinal of the frame.
      */
     WorkOrdinal ordinal;
 
     /**
-     * Frame buffers.
+     * List of frame buffers.
      */
     vec<Buffer> buffers;
 
     /**
-     * Params determining a configuration update.
+     * List of configuration updates.
      */
     Params configUpdate;
 
     /**
-     * Info buffers.
+     * List of info buffers.
      */
     vec<InfoBuffer> infoBuffers;
 };
 
 /**
- * Struct for
+ * In/out structure containing some instructions for and results from output
+ * processing.
+ *
+ * This is a part of @ref Work. One `Worklet` corresponds to one output
+ * @ref FrameData. The client must construct an original `Worklet` object inside
+ * a @ref Work object for each expected output before calling
+ * IComponent::queue().
  */
 struct Worklet {
     /**
-     * List of Params describing tunings.
+     * Component id. (Input)
+     *
+     * This is used only when tunneling is enabled.
+     *
+     * When used, this must match the return value from IConfigurable::getId().
      */
-    vec<Params> tunings;
+    uint32_t componentId;
 
     /**
-     * List of failures.
+     * List of C2Param objects describing tunings to be applied before
+     * processing this `Worklet`. (Input)
+     */
+    Params tunings;
+
+    /**
+     * List of failures. (Output)
      */
     vec<SettingResult> failures;
 
     /**
-     * Output frame data.
+     * Output frame data. (Output)
      */
     FrameData output;
-
-    /* Note: Component id is not necessary as tunneling is not supported. */
 };
 
 /**
- * This structure holds information about a single work item. It must be passed
- * by the client to the component.
+ * A collection of input data to and output data from the component.
+ *
+ * A `Work` object holds information about a single work item. It is created by
+ * the client and passed to the component via IComponent::queue(). The component
+ * has two ways of returning a `Work` object to the client:
+ *   1. If the queued `Work` object has been successfully processed,
+ *      IComponentListener::onWorkDone() shall be called to notify the listener,
+ *      and the output shall be included in the returned `Work` object.
+ *   2. If the client calls IComponent::flush(), a `Work` object that has not
+ *      been processed shall be returned.
+ *
+ * `Work` is a part of @ref WorkBundle.
  */
 struct Work {
     /**
-     * FrameData for the input. Indices of Blocks inside #input refer to
-     * BaseBlocks in the member `blocks` of the containing `WorkBundle`.
+     * Additional work chain info not part of this work.
+     */
+    Params chainInfo;
+
+    /**
+     * @ref FrameData for the input.
      */
     FrameData input;
+
     /**
-     * Worklet. Indices of Blocks inside `worklet.output` refer to
-     * BaseBlocks in the member `blocks` of the containing `WorkBundle`.
+     * The chain of `Worklet`s.
+     *
+     * The length of #worklets is 1 when tunneling is not enabled.
+     *
+     * If #worklets has more than a single element, the tunnels between
+     * successive components of the work chain must have been successfully
+     * pre-registered at the time that the `Work` is submitted. Allocating the
+     * output buffers in the `Worklet`s is the responsibility of each component
+     * in the chain.
+     *
+     * Upon `Work` submission, #worklets must be an appropriately sized vector
+     * containing `Worklet`s with @ref Worklet.hasOutput set to `false`. After a
+     * successful processing, all but the final `Worklet` in the returned
+     * #worklets must have @ref Worklet.hasOutput set to `false`.
      */
-    Worklet worklet;
+    vec<Worklet> worklets;
+
     /**
-     * Whether the worklet was processed or not.
+     * The number of `Worklet`s successfully processed in this chain.
+     *
+     * This must be initialized to 0 by the client when the `Work` is submitted,
+     * and it must contain the number of `Worklet`s that were successfully
+     * processed when the `Work` is returned to the client.
+     *
+     * #workletsProcessed cannot exceed the length of #worklets. If
+     * #workletsProcessed is smaller than the length of #worklets, #result
+     * cannot be `OK`.
      */
-    bool workletProcessed;
+    uint32_t workletsProcessed;
+
+    /**
+     * The final outcome of the `Work` (corresponding to #workletsProcessed).
+     *
+     * The value of @ref Status.OK implies that all `Worklet`s have been
+     * successfully processed.
+     */
     Status result;
 };
 
 /**
- * This structure holds a list of Work objects and a list of BaseBlocks.
+ * List of `Work` objects.
+ *
+ * `WorkBundle` is used in IComponent::queue(), IComponent::flush() and
+ * IComponentListener::onWorkDone(). A `WorkBundle` object consists of a list of
+ * `Work` objects and a list of `BaseBlock` objects. Bundling multiple `Work`
+ * objects together provides two benefits:
+ *   1. Batching of `Work` objects can reduce the number of IPC calls.
+ *   2. If multiple `Work` objects contain `Block`s that refer to the same
+ *      `BaseBlock`, the number of `BaseBlock`s that is sent between processes
+ *      is also reduced.
+ *
+ * @note `WorkBundle` is the HIDL counterpart of the vector of `C2Work` in the
+ * Codec 2.0 standard. The presence of #baseBlocks helps with minimizing the
+ * data transferred over an IPC.
  */
 struct WorkBundle {
     /**
@@ -581,27 +780,48 @@
 };
 
 /**
- * This structure describes a query for supported values of a field. This is
- * used as input to IConfigurable::queryFieldSupportedValues().
+ * Query information for supported values of a field. This is used as input to
+ * IConfigurable::querySupportedValues().
  */
 struct FieldSupportedValuesQuery {
+    /**
+     * Identity of the field to query.
+     */
+    ParamField field;
+
     enum Type : uint32_t {
-        /** Query all possible values regardless of other settings */
+        /** Query all possible values regardless of other settings. */
         POSSIBLE,
-        /** Query currently possible values given dependent settings */
+        /** Query currently possible values given dependent settings. */
         CURRENT,
     };
-
-    ParamField field;
+    /**
+     * Type of the query. See #Type for more information.
+     */
     Type type;
 };
 
 /**
  * This structure is used to hold the result from
- * IConfigurable::queryFieldSupportedValues().
+ * IConfigurable::querySupportedValues().
  */
 struct FieldSupportedValuesQueryResult {
+    /**
+     * Result of the query. Possible values are
+     * - `OK`: The query was successful.
+     * - `BAD_STATE`: The query was requested when the `IConfigurable` instance
+     *   was in a bad state.
+     * - `BAD_INDEX`: The requested field was not recognized.
+     * - `TIMED_OUT`: The query could not be completed in a timely manner.
+     * - `BLOCKING`: The query must block, but the parameter `mayBlock` in the
+     *   call to `querySupportedValues()` was `false`.
+     * - `CORRUPTED`: Some unknown error occurred.
+     */
     Status status;
+
+    /**
+     * Supported values. This is meaningful only when #status is `OK`.
+     */
     FieldSupportedValues values;
 };
 
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index 9e7d8f0..2e48ba0 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -47,7 +47,7 @@
      * used to convert the 16 bit number to a real value in the following way:
      * realValue = integerValue * scale.
      *
-     * scale is a 32 bit floating point with value greater then zero.
+     * scale is a 32 bit floating point with value greater than zero.
      */
     TENSOR_QUANT16_SYMM = 7,
     /** A tensor of IEEE 754 16 bit floating point values. */
@@ -97,6 +97,16 @@
      * real_value = (integer_value - zeroPoint) * scale.
      */
     TENSOR_QUANT16_ASYMM = 12,
+    /**
+     * A tensor of 8 bit signed integers that represent real numbers.
+     *
+     * Attached to this tensor is a number representing real value scale that is
+     * used to convert the 8 bit number to a real value in the following way:
+     * realValue = integerValue * scale.
+     *
+     * scale is a 32 bit floating point with value greater than zero.
+     */
+    TENSOR_QUANT8_SYMM = 13,
     /* ADDING A NEW FUNDAMENTAL TYPE REQUIRES UPDATING THE VALUE OF
      * OperandTypeRange::FUNDAMENTAL_MAX.
      */
@@ -111,7 +121,7 @@
 enum OperandTypeRange : uint32_t {
     BASE_MIN        = 0,
     FUNDAMENTAL_MIN = 0,
-    FUNDAMENTAL_MAX = 12,
+    FUNDAMENTAL_MAX = 13,
     OEM_MIN         = 10000,
     OEM_MAX         = 10001,
     BASE_MAX        = 0xFFFF,
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index 1bbb203..a0f11eb 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -161,6 +161,7 @@
         case OperandType::TENSOR_FLOAT32:
         case OperandType::TENSOR_INT32:
         case OperandType::TENSOR_QUANT8_ASYMM:
+        case OperandType::TENSOR_QUANT8_SYMM:
         case OperandType::TENSOR_QUANT16_ASYMM:
         case OperandType::TENSOR_QUANT16_SYMM:
         case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
@@ -199,6 +200,7 @@
             return 1.0f;
         case OperandType::TENSOR_INT32:
             return -1.0f;
+        case OperandType::TENSOR_QUANT8_SYMM:
         case OperandType::TENSOR_QUANT8_ASYMM:
         case OperandType::TENSOR_QUANT16_ASYMM:
         case OperandType::TENSOR_QUANT16_SYMM:
@@ -235,6 +237,8 @@
             return {1};
         case OperandType::TENSOR_QUANT8_ASYMM:
             return {-1, 256};
+        case OperandType::TENSOR_QUANT8_SYMM:
+          return {-129, -1, 1, 128};
         case OperandType::TENSOR_QUANT16_ASYMM:
             return {-1, 65536};
         case OperandType::TENSOR_QUANT16_SYMM:
@@ -292,6 +296,7 @@
             newOperand.zeroPoint = 0;
             break;
         case OperandType::TENSOR_QUANT8_ASYMM:
+        case OperandType::TENSOR_QUANT8_SYMM:
         case OperandType::TENSOR_QUANT16_ASYMM:
         case OperandType::TENSOR_QUANT16_SYMM:
             newOperand.dimensions =
diff --git a/radio/1.0/types.hal b/radio/1.0/types.hal
index 17718e0..8393cf5 100644
--- a/radio/1.0/types.hal
+++ b/radio/1.0/types.hal
@@ -1230,85 +1230,108 @@
 
 struct GsmSignalStrength {
     uint32_t signalStrength;              // Valid values are (0-61, 99) as defined in
-                                          // TS 27.007 8.69
-    uint32_t bitErrorRate;                // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+                                          // TS 27.007 8.69; INT_MAX means invalid/unreported.
+    uint32_t bitErrorRate;                // bit error rate (0-7, 99) as defined in TS 27.007 8.5;
+                                          // INT_MAX means invalid/unreported.
     int32_t timingAdvance;                // Timing Advance in bit periods. 1 bit period = 48/13 us.
-                                          // INT_MAX denotes invalid value
+                                          // INT_MAX means invalid/unreported.
 };
 
 struct WcdmaSignalStrength{
     int32_t signalStrength;               // Valid values are (0-31, 99) as defined in
-                                          // TS 27.007 8.5
-    int32_t bitErrorRate;                 // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+                                          // TS 27.007 8.5; INT_MAX means unreported.
+    int32_t bitErrorRate;                 // bit error rate (0-7, 99) as defined in TS 27.007 8.5;
+                                          // INT_MAX means invalid/unreported.
 };
 
 struct CdmaSignalStrength {
     uint32_t dbm;                         // This value is the actual RSSI
                                           // value multiplied by -1. Example: If the
                                           // actual RSSI is -75, then this response value will
-                                          // be 75.
+                                          // be 75. INT_MAX means invalid/unreported.
     uint32_t ecio;                        // This value is the actual
                                           // Ec/Io multiplied by -10. Example: If the
                                           // actual Ec/Io is -12.5 dB, then this response value
-                                          // will be 125.
+                                          // will be 125. INT_MAX means invalid/unreported.
 };
 
 struct EvdoSignalStrength {
     uint32_t dbm;                         // This value is the actual
                                           // RSSI value multiplied by -1.
                                           // Example: If the actual RSSI is -75,
-                                          // then this response value will be 75.
+                                          // then this response value will be 75; INT_MAX means
+                                          // invalid/unreported.
     uint32_t ecio;                        // This value is the actual
                                           // Ec/Io multiplied by -10. Example: If the
                                           // actual Ec/Io is -12.5 dB, then this response value
-                                          // will be 125.
+                                          // will be 125; INT_MAX means invalid/unreported.
     uint32_t signalNoiseRatio;            // Valid values are 0-8. 8 is the highest signal to
-                                          // noise ratio.
+                                          // noise ratio; INT_MAX means invalid/unreported.
 };
 
 struct LteSignalStrength {
     uint32_t signalStrength;              // Valid values are (0-31, 99) as defined in
-                                          // TS 27.007 8.5
+                                          // TS 27.007 8.5; INT_MAX means invalid/unreported.
     uint32_t rsrp;                        // The current Reference Signal Receive Power in dBm
                                           // multipled by -1.
-                                          // Range: 44 to 140 dBm
-                                          // INT_MAX: 0x7FFFFFFF denotes invalid value.
+                                          // Range: 44 to 140 dBm;
+                                          // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
                                           // Reference: 3GPP TS 36.133 9.1.4
     uint32_t rsrq;                        // The current Reference Signal Receive Quality in dB
                                           // multiplied by -1.
-                                          // Range: 20 to 3 dB.
-                                          // INT_MAX: 0x7FFFFFFF denotes invalid value.
+                                          // Range: 20 to 3 dB;
+                                          // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
                                           // Reference: 3GPP TS 36.133 9.1.7
     int32_t rssnr;                        // The current reference signal signal-to-noise ratio in
                                           // 0.1 dB units.
                                           // Range: -200 to +300 (-200 = -20.0 dB, +300 = 30dB).
-                                          // INT_MAX : 0x7FFFFFFF denotes invalid value.
+                                          // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
                                           // Reference: 3GPP TS 36.101 8.1.1
     uint32_t cqi;                         // The current Channel Quality Indicator.
                                           // Range: 0 to 15.
-                                          // INT_MAX : 0x7FFFFFFF denotes invalid value.
+                                          // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
                                           // Reference: 3GPP TS 36.101 9.2, 9.3, A.4
     uint32_t timingAdvance;               // timing advance in micro seconds for a one way trip
                                           // from cell to device.
                                           // Approximate distance is calculated using
                                           // 300m/us * timingAdvance.
                                           // Range: 0 to 1282 inclusive.
-                                          // INT_MAX : 0x7FFFFFFF denotes unknown value.
+                                          // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
                                           // Reference: 3GPP 36.213 section 4.2.3
 };
 
 struct TdScdmaSignalStrength {
     uint32_t rscp;                        // The Received Signal Code Power in dBm multiplied by -1.
                                           // Range : 25 to 120
-                                          // INT_MAX: 0x7FFFFFFF denotes invalid value.
+                                          // INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
                                           // Reference: 3GPP TS 25.123, section 9.1.1.1
 };
 
 struct SignalStrength {
+    /**
+     * If GSM measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     GsmSignalStrength gw;
+    /**
+     * If CDMA measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     CdmaSignalStrength cdma;
+    /**
+     * If EvDO measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     EvdoSignalStrength evdo;
+    /**
+     * If LTE measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     LteSignalStrength lte;
+    /**
+     * If TD-SCDMA measurements are provided, this structure must contain valid measurements;
+     * otherwise all fields should be set to INT_MAX to mark them as invalid.
+     */
     TdScdmaSignalStrength tdScdma;
 };
 
diff --git a/radio/1.2/types.hal b/radio/1.2/types.hal
index 4715fac..2dceeb1 100644
--- a/radio/1.2/types.hal
+++ b/radio/1.2/types.hal
@@ -427,11 +427,13 @@
     /**
      * CPICH RSCP as defined in TS 25.215 5.1.1
      * Valid values are (0-96, 255) as defined in TS 27.007 8.69
+     * INT_MAX denotes that the value is invalid/unreported.
      */
     uint32_t rscp;
     /**
      * Ec/No value as defined in TS 25.215 5.1.5
      * Valid values are (0-49, 255) as defined in TS 27.007 8.69
+     * INT_MAX denotes that the value is invalid/unreported.
      */
     uint32_t ecno;
 
@@ -441,26 +443,53 @@
     /**
      * UTRA carrier RSSI as defined in TS 25.225 5.1.4
      * Valid values are (0-31, 99) as defined in TS 27.007 8.5
+     * INT_MAX denotes that the value is invalid/unreported.
      */
     uint32_t signalStrength;
     /**
      * Transport Channel BER as defined in TS 25.225 5.2.5
      * Valid values are (0-7, 99) as defined in TS 27.007 8.5
+     * INT_MAX denotes that the value is invalid/unreported.
      */
     uint32_t bitErrorRate;
     /**
      * P-CCPCH RSCP as defined in TS 25.225 5.1.1
      * Valid values are (0-96, 255) as defined in TS 27.007 8.69
+     * INT_MAX denotes that the value is invalid/unreported.
      */
     uint32_t rscp;
 };
 
 struct SignalStrength {
+    /**
+     * If GSM measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     GsmSignalStrength gsm;
+    /**
+     * If CDMA measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     CdmaSignalStrength cdma;
+    /**
+     * If EvDO measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     EvdoSignalStrength evdo;
+    /**
+     * If LTE measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     LteSignalStrength lte;
+    /**
+     * If TD-SCDMA measurements are provided, this structure must contain valid measurements;
+     * otherwise all fields should be set to INT_MAX to mark them as invalid.
+     */
     TdScdmaSignalStrength tdScdma;
+    /**
+     * If WCDMA measurements are provided, this structure must contain valid measurements; otherwise
+     * all fields should be set to INT_MAX to mark them as invalid.
+     */
     WcdmaSignalStrength wcdma;
 };
 
diff --git a/sensors/2.0/default/Sensor.cpp b/sensors/2.0/default/Sensor.cpp
index 373ab12..c09173f 100644
--- a/sensors/2.0/default/Sensor.cpp
+++ b/sensors/2.0/default/Sensor.cpp
@@ -18,6 +18,8 @@
 
 #include <utils/SystemClock.h>
 
+#include <cmath>
+
 namespace android {
 namespace hardware {
 namespace sensors {
@@ -28,6 +30,8 @@
 using ::android::hardware::sensors::V1_0::SensorFlagBits;
 using ::android::hardware::sensors::V1_0::SensorStatus;
 
+static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000;
+
 Sensor::Sensor(ISensorsEventCallback* callback)
     : mIsEnabled(false),
       mSamplingPeriodNs(0),
@@ -83,7 +87,7 @@
     // to the Event FMQ prior to writing the flush complete event.
     Event ev;
     ev.sensorHandle = mSensorInfo.sensorHandle;
-    ev.sensorType = SensorType::ADDITIONAL_INFO;
+    ev.sensorType = SensorType::META_DATA;
     ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
     std::vector<Event> evs{ev};
     mCallback->postEvents(evs, isWakeUpSensor());
@@ -202,7 +206,7 @@
     mSensorInfo.resolution = 1.52e-5;
     mSensorInfo.power = 0.001f;          // mA
     mSensorInfo.minDelay = 20 * 1000;    // microseconds
-    mSensorInfo.maxDelay = 1000 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
@@ -218,10 +222,10 @@
     mSensorInfo.type = SensorType::PRESSURE;
     mSensorInfo.typeAsString = "";
     mSensorInfo.maxRange = 1100.0f;   // hPa
-    mSensorInfo.resolution = 1.0f;    // hPa
+    mSensorInfo.resolution = 0.005f;  // hPa
     mSensorInfo.power = 0.001f;       // mA
-    mSensorInfo.minDelay = 28571.0f;  // microseconds
-    mSensorInfo.maxDelay = 0.0f;      // microseconds
+    mSensorInfo.minDelay = 100 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
@@ -236,11 +240,11 @@
     mSensorInfo.version = 1;
     mSensorInfo.type = SensorType::MAGNETIC_FIELD;
     mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 4911.0f;
-    mSensorInfo.resolution = 1.00f;
+    mSensorInfo.maxRange = 1300.0f;
+    mSensorInfo.resolution = 0.01f;
     mSensorInfo.power = 0.001f;       // mA
-    mSensorInfo.minDelay = 14284.0f;  // microseconds
-    mSensorInfo.maxDelay = 0.0f;      // microseconds
+    mSensorInfo.minDelay = 20 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
@@ -255,11 +259,11 @@
     mSensorInfo.version = 1;
     mSensorInfo.type = SensorType::LIGHT;
     mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 10000.0f;
+    mSensorInfo.maxRange = 43000.0f;
     mSensorInfo.resolution = 10.0f;
     mSensorInfo.power = 0.001f;           // mA
-    mSensorInfo.minDelay = 20.0f * 1000;  // microseconds
-    mSensorInfo.maxDelay = 0;             // microseconds
+    mSensorInfo.minDelay = 200 * 1000;    // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
@@ -277,8 +281,8 @@
     mSensorInfo.maxRange = 5.0f;
     mSensorInfo.resolution = 1.0f;
     mSensorInfo.power = 0.012f;  // mA
-    mSensorInfo.minDelay = 500;  // microseconds
-    mSensorInfo.maxDelay = 2 * mSensorInfo.minDelay;
+    mSensorInfo.minDelay = 200 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
@@ -293,11 +297,11 @@
     mSensorInfo.version = 1;
     mSensorInfo.type = SensorType::GYROSCOPE;
     mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 8.726639f;
-    mSensorInfo.resolution = 1.0f;
+    mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
+    mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
     mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 4444;  // microseonds
-    mSensorInfo.maxDelay = 0;     // microseconds
+    mSensorInfo.minDelay = 2.5f * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
@@ -313,10 +317,10 @@
     mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
     mSensorInfo.typeAsString = "";
     mSensorInfo.maxRange = 80.0f;
-    mSensorInfo.resolution = 1.0f;
+    mSensorInfo.resolution = 0.01f;
     mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 4444;  // microseonds
-    mSensorInfo.maxDelay = 0;     // microseconds
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
@@ -332,10 +336,10 @@
     mSensorInfo.type = SensorType::TEMPERATURE;
     mSensorInfo.typeAsString = "";
     mSensorInfo.maxRange = 80.0f;
-    mSensorInfo.resolution = 1.0f;
+    mSensorInfo.resolution = 0.01f;
     mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 4444;  // microseonds
-    mSensorInfo.maxDelay = 0;     // microseconds
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
@@ -352,10 +356,10 @@
     mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
     mSensorInfo.typeAsString = "";
     mSensorInfo.maxRange = 100.0f;
-    mSensorInfo.resolution = 1.0f;
+    mSensorInfo.resolution = 0.1f;
     mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 4444;  // microseonds
-    mSensorInfo.maxDelay = 0;     // microseconds
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
     mSensorInfo.requiredPermission = "";
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index 4a1f8f1..39053fe 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -51,7 +51,7 @@
     }
 
     void onEvent(const ::android::hardware::sensors::V1_0::Event& event) override {
-        if (event.sensorType == SensorType::ADDITIONAL_INFO &&
+        if (event.sensorType == SensorType::META_DATA &&
             event.u.meta.what == MetaDataEventType::META_DATA_FLUSH_COMPLETE) {
             std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
             mFlushMap[event.sensorHandle]++;