Merge "transcoding: use NDK methods for permission and binder"
diff --git a/apex/Android.bp b/apex/Android.bp
index fac3831..6ba9cb9 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -31,11 +31,12 @@
                 "libmpeg2extractor",
                 "liboggextractor",
                 "libwavextractor",
-                // JNI
-                "libmediaparser-jni"
             ],
         },
     },
+    // JNI
+    native_shared_libs: ["libmediaparser-jni"],
+    compile_multilib: "both",
     prebuilts: [
         "mediaextractor.policy",
         "code_coverage.policy",
diff --git a/camera/Android.bp b/camera/Android.bp
index b777d74..a9e00d0 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -35,6 +35,7 @@
         "CameraParameters.cpp",
         "CaptureResult.cpp",
         "CameraParameters2.cpp",
+        "CameraSessionStats.cpp",
         "ICamera.cpp",
         "ICameraClient.cpp",
         "ICameraRecordingProxy.cpp",
diff --git a/camera/CameraSessionStats.cpp b/camera/CameraSessionStats.cpp
new file mode 100644
index 0000000..4c23982
--- /dev/null
+++ b/camera/CameraSessionStats.cpp
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2020 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 "CameraSessionStats"
+#include <utils/Log.h>
+#include <utils/String16.h>
+
+#include <camera/CameraSessionStats.h>
+
+#include <binder/Parcel.h>
+
+namespace android {
+namespace hardware {
+
+status_t CameraStreamStats::readFromParcel(const android::Parcel* parcel) {
+    if (parcel == NULL) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    status_t err = OK;
+
+    int width = 0;
+    if ((err = parcel->readInt32(&width)) != OK) {
+        ALOGE("%s: Failed to read width from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int height = 0;
+    if ((err = parcel->readInt32(&height)) != OK) {
+        ALOGE("%s: Failed to read height from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int format = 0;
+    if ((err = parcel->readInt32(&format)) != OK) {
+        ALOGE("%s: Failed to read format from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int dataSpace = 0;
+    if ((err = parcel->readInt32(&dataSpace)) != OK) {
+        ALOGE("%s: Failed to read dataSpace from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int64_t usage = 0;
+    if ((err = parcel->readInt64(&usage)) != OK) {
+        ALOGE("%s: Failed to read usage from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int64_t requestCount = 0;
+    if ((err = parcel->readInt64(&requestCount)) != OK) {
+        ALOGE("%s: Failed to read request count from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int64_t errorCount = 0;
+    if ((err = parcel->readInt64(&errorCount)) != OK) {
+        ALOGE("%s: Failed to read error count from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int startLatencyMs = 0;
+    if ((err = parcel->readInt32(&startLatencyMs)) != OK) {
+        ALOGE("%s: Failed to read start latency from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int maxHalBuffers = 0;
+    if ((err = parcel->readInt32(&maxHalBuffers)) != OK) {
+        ALOGE("%s: Failed to read max Hal buffers from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int maxAppBuffers = 0;
+    if ((err = parcel->readInt32(&maxAppBuffers)) != OK) {
+        ALOGE("%s: Failed to read max app buffers from parcel", __FUNCTION__);
+        return err;
+    }
+
+    mWidth = width;
+    mHeight = height;
+    mFormat = format;
+    mDataSpace = dataSpace;
+    mUsage = usage;
+    mRequestCount = requestCount;
+    mErrorCount = errorCount;
+    mStartLatencyMs = startLatencyMs;
+    mMaxHalBuffers = maxHalBuffers;
+    mMaxAppBuffers = maxAppBuffers;
+
+    return OK;
+}
+
+status_t CameraStreamStats::writeToParcel(android::Parcel* parcel) const {
+    if (parcel == NULL) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    status_t err = OK;
+
+    if ((err = parcel->writeInt32(mWidth)) != OK) {
+        ALOGE("%s: Failed to write stream width!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt32(mHeight)) != OK) {
+        ALOGE("%s: Failed to write stream height!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt32(mFormat)) != OK) {
+        ALOGE("%s: Failed to write stream format!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt32(mDataSpace)) != OK) {
+        ALOGE("%s: Failed to write stream dataSpace!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt64(mUsage)) != OK) {
+        ALOGE("%s: Failed to write stream usage!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt64(mRequestCount)) != OK) {
+        ALOGE("%s: Failed to write stream request count!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt64(mErrorCount)) != OK) {
+        ALOGE("%s: Failed to write stream error count!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt32(mStartLatencyMs)) != OK) {
+        ALOGE("%s: Failed to write stream start latency!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt32(mMaxHalBuffers)) != OK) {
+        ALOGE("%s: Failed to write max hal buffers", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt32(mMaxAppBuffers)) != OK) {
+        ALOGE("%s: Failed to write max app buffers", __FUNCTION__);
+        return err;
+    }
+
+    return OK;
+}
+
+CameraSessionStats::CameraSessionStats() :
+        mFacing(CAMERA_FACING_BACK),
+        mNewCameraState(CAMERA_STATE_CLOSED),
+        mApiLevel(0),
+        mIsNdk(false),
+        mLatencyMs(-1),
+        mSessionType(0),
+        mInternalReconfigure(0),
+        mRequestCount(0),
+        mResultErrorCount(0),
+        mDeviceError(false) {}
+
+CameraSessionStats::CameraSessionStats(const String16& cameraId,
+        int facing, int newCameraState, const String16& clientName,
+        int apiLevel, bool isNdk, int32_t latencyMs) :
+                mCameraId(cameraId),
+                mFacing(facing),
+                mNewCameraState(newCameraState),
+                mClientName(clientName),
+                mApiLevel(apiLevel),
+                mIsNdk(isNdk),
+                mLatencyMs(latencyMs),
+                mSessionType(0),
+                mInternalReconfigure(0),
+                mRequestCount(0),
+                mResultErrorCount(0),
+                mDeviceError(0) {}
+
+status_t CameraSessionStats::readFromParcel(const android::Parcel* parcel) {
+    if (parcel == NULL) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    status_t err = OK;
+
+    String16 id;
+    if ((err = parcel->readString16(&id)) != OK) {
+        ALOGE("%s: Failed to read camera id!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    int facing = 0;
+    if ((err = parcel->readInt32(&facing)) != OK) {
+        ALOGE("%s: Failed to read camera facing from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int32_t newCameraState;
+    if ((err = parcel->readInt32(&newCameraState)) != OK) {
+        ALOGE("%s: Failed to read new camera state from parcel", __FUNCTION__);
+        return err;
+    }
+
+    String16 clientName;
+    if ((err = parcel->readString16(&clientName)) != OK) {
+        ALOGE("%s: Failed to read client name!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    int32_t apiLevel;
+    if ((err = parcel->readInt32(&apiLevel)) != OK) {
+        ALOGE("%s: Failed to read api level from parcel", __FUNCTION__);
+        return err;
+    }
+
+    bool isNdk;
+    if ((err = parcel->readBool(&isNdk)) != OK) {
+        ALOGE("%s: Failed to read isNdk flag from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int32_t latencyMs;
+    if ((err = parcel->readInt32(&latencyMs)) != OK) {
+        ALOGE("%s: Failed to read latencyMs from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int32_t sessionType;
+    if ((err = parcel->readInt32(&sessionType)) != OK) {
+        ALOGE("%s: Failed to read session type from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int32_t internalReconfigure;
+    if ((err = parcel->readInt32(&internalReconfigure)) != OK) {
+        ALOGE("%s: Failed to read internal reconfigure count from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int64_t requestCount;
+    if ((err = parcel->readInt64(&requestCount)) != OK) {
+        ALOGE("%s: Failed to read request count from parcel", __FUNCTION__);
+        return err;
+    }
+
+    int64_t resultErrorCount;
+    if ((err = parcel->readInt64(&resultErrorCount)) != OK) {
+        ALOGE("%s: Failed to read result error count from parcel", __FUNCTION__);
+        return err;
+    }
+
+    bool deviceError;
+    if ((err = parcel->readBool(&deviceError)) != OK) {
+        ALOGE("%s: Failed to read device error flag from parcel", __FUNCTION__);
+        return err;
+    }
+
+    std::vector<CameraStreamStats> streamStats;
+    if ((err = parcel->readParcelableVector(&streamStats)) != OK) {
+        ALOGE("%s: Failed to read stream state from parcel", __FUNCTION__);
+        return err;
+    }
+
+    mCameraId = id;
+    mFacing = facing;
+    mNewCameraState = newCameraState;
+    mClientName = clientName;
+    mApiLevel = apiLevel;
+    mIsNdk = isNdk;
+    mLatencyMs = latencyMs;
+    mSessionType = sessionType;
+    mInternalReconfigure = internalReconfigure;
+    mRequestCount = requestCount;
+    mResultErrorCount = resultErrorCount;
+    mDeviceError = deviceError;
+    mStreamStats = std::move(streamStats);
+
+    return OK;
+}
+
+status_t CameraSessionStats::writeToParcel(android::Parcel* parcel) const {
+    if (parcel == NULL) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    status_t err = OK;
+
+    if ((err = parcel->writeString16(mCameraId)) != OK) {
+        ALOGE("%s: Failed to write camera id!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt32(mFacing)) != OK) {
+        ALOGE("%s: Failed to write camera facing!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt32(mNewCameraState)) != OK) {
+        ALOGE("%s: Failed to write new camera state!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeString16(mClientName)) != OK) {
+        ALOGE("%s: Failed to write client name!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt32(mApiLevel)) != OK) {
+        ALOGE("%s: Failed to write api level!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeBool(mIsNdk)) != OK) {
+        ALOGE("%s: Failed to write isNdk flag!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt32(mLatencyMs)) != OK) {
+        ALOGE("%s: Failed to write latency in Ms!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt32(mSessionType)) != OK) {
+        ALOGE("%s: Failed to write session type!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt32(mInternalReconfigure)) != OK) {
+        ALOGE("%s: Failed to write internal reconfigure count!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt64(mRequestCount)) != OK) {
+        ALOGE("%s: Failed to write request count!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeInt64(mResultErrorCount)) != OK) {
+        ALOGE("%s: Failed to write result error count!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeBool(mDeviceError)) != OK) {
+        ALOGE("%s: Failed to write device error flag!", __FUNCTION__);
+        return err;
+    }
+
+    if ((err = parcel->writeParcelableVector(mStreamStats)) != OK) {
+        ALOGE("%s: Failed to write stream states!", __FUNCTION__);
+        return err;
+    }
+
+    return OK;
+}
+
+} // namespace hardware
+} // namesmpace android
diff --git a/camera/aidl/android/hardware/CameraSessionStats.aidl b/camera/aidl/android/hardware/CameraSessionStats.aidl
new file mode 100644
index 0000000..a8e6774
--- /dev/null
+++ b/camera/aidl/android/hardware/CameraSessionStats.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+/** @hide */
+parcelable CameraSessionStats cpp_header "camera/CameraSessionStats.h";
diff --git a/camera/aidl/android/hardware/ICameraServiceProxy.aidl b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
index 7575948..d428b4e 100644
--- a/camera/aidl/android/hardware/ICameraServiceProxy.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
@@ -16,11 +16,11 @@
 
 package android.hardware;
 
+import android.hardware.CameraSessionStats;
+
 /**
  * Binder interface for the camera service proxy running in system_server.
  *
- * Keep in sync with frameworks/av/include/camera/ICameraServiceProxy.h
- *
  * @hide
  */
 interface ICameraServiceProxy
@@ -30,30 +30,9 @@
      */
     oneway void pingForUserUpdate();
 
-    /**
-     * Values for notifyCameraState newCameraState
-     */
-    const int CAMERA_STATE_OPEN = 0;
-    const int CAMERA_STATE_ACTIVE = 1;
-    const int CAMERA_STATE_IDLE = 2;
-    const int CAMERA_STATE_CLOSED = 3;
-
-    /**
-     * Values for notifyCameraState facing
-     */
-    const int CAMERA_FACING_BACK = 0;
-    const int CAMERA_FACING_FRONT = 1;
-    const int CAMERA_FACING_EXTERNAL = 2;
-
-    /**
-     * Values for notifyCameraState api level
-     */
-     const int CAMERA_API_LEVEL_1 = 1;
-     const int CAMERA_API_LEVEL_2 = 2;
 
     /**
      * Update the status of a camera device.
      */
-    oneway void notifyCameraState(String cameraId, int facing, int newCameraState,
-            String clientName, int apiLevel);
+    oneway void notifyCameraState(in CameraSessionStats cameraSessionStats);
 }
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index b183ccc..28a57bd 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -83,9 +83,11 @@
      * @param operatingMode The kind of session to create; either NORMAL_MODE or
      *     CONSTRAINED_HIGH_SPEED_MODE. Must be a non-negative value.
      * @param sessionParams Session wide camera parameters
+     * @param startTimeMs The timestamp of session creation start, measured by
+     *                    SystemClock.uptimeMillis.
      * @return a list of stream ids that can be used in offline mode via "switchToOffline"
      */
-    int[] endConfigure(int operatingMode, in CameraMetadataNative sessionParams);
+    int[] endConfigure(int operatingMode, in CameraMetadataNative sessionParams, long startTimeMs);
 
     /**
       * Check whether a particular session configuration has camera device
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index 09a333b..a354189 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -48,6 +48,6 @@
     init_rc: ["cameraserver.rc"],
 
     vintf_fragments: [
-        "manifest_android.frameworks.cameraservice.service@2.1.xml",
+        "manifest_android.frameworks.cameraservice.service@2.2.xml",
     ],
 }
diff --git a/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.1.xml b/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.2.xml
similarity index 90%
rename from camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.1.xml
rename to camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.2.xml
index 5a15b35..eeafc91 100644
--- a/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.1.xml
+++ b/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.2.xml
@@ -2,7 +2,7 @@
     <hal>
         <name>android.frameworks.cameraservice.service</name>
         <transport>hwbinder</transport>
-        <version>2.1</version>
+        <version>2.2</version>
         <interface>
             <name>ICameraService</name>
             <instance>default</instance>
diff --git a/camera/include/camera/CameraSessionStats.h b/camera/include/camera/CameraSessionStats.h
new file mode 100644
index 0000000..57c2645
--- /dev/null
+++ b/camera/include/camera/CameraSessionStats.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 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_CAMERA_SERVICE_SESSION_STATS_H
+#define ANDROID_HARDWARE_CAMERA_SERVICE_SESSION_STATS_H
+
+#include <binder/Parcelable.h>
+
+namespace android {
+namespace hardware {
+
+/**
+ * Camera stream info and statistics
+ */
+class CameraStreamStats : public android::Parcelable {
+public:
+    int mWidth;
+    int mHeight;
+    int mFormat;
+    int mDataSpace;
+    int64_t mUsage;
+
+    // The number of requested buffers
+    int64_t mRequestCount;
+    // The number of buffer errors
+    int64_t mErrorCount;
+
+    // The capture latency of 1st request for this stream
+    int32_t mStartLatencyMs;
+
+    // Buffer count info
+    int mMaxHalBuffers;
+    int mMaxAppBuffers;
+
+    CameraStreamStats() :
+            mWidth(0), mHeight(0), mFormat(0), mDataSpace(0), mUsage(0),
+            mRequestCount(0), mErrorCount(0), mStartLatencyMs(0),
+            mMaxHalBuffers(0), mMaxAppBuffers(0) {}
+    CameraStreamStats(int width, int height, int format, int dataSpace, int64_t usage,
+            int maxHalBuffers, int maxAppBuffers)
+            : mWidth(width), mHeight(height), mFormat(format), mDataSpace(dataSpace),
+              mUsage(usage), mRequestCount(0), mErrorCount(0), mStartLatencyMs(0),
+              mMaxHalBuffers(maxHalBuffers), mMaxAppBuffers(maxAppBuffers) {}
+
+    virtual status_t readFromParcel(const android::Parcel* parcel) override;
+    virtual status_t writeToParcel(android::Parcel* parcel) const override;
+};
+
+/**
+ * Camera session statistics
+ *
+ * This includes session wide info and stream statistics.
+ */
+class CameraSessionStats : public android::Parcelable {
+public:
+    /**
+     * Values for notifyCameraState newCameraState
+     */
+    static const int CAMERA_STATE_OPEN = 0;
+    static const int CAMERA_STATE_ACTIVE = 1;
+    static const int CAMERA_STATE_IDLE = 2;
+    static const int CAMERA_STATE_CLOSED = 3;
+
+    /**
+     * Values for notifyCameraState facing
+     */
+    static const int CAMERA_FACING_BACK = 0;
+    static const int CAMERA_FACING_FRONT = 1;
+    static const int CAMERA_FACING_EXTERNAL = 2;
+
+    /**
+     * Values for notifyCameraState api level
+     */
+    static const int CAMERA_API_LEVEL_1 = 1;
+    static const int CAMERA_API_LEVEL_2 = 2;
+
+    String16 mCameraId;
+    int mFacing;
+    int mNewCameraState;
+    String16 mClientName;
+    int mApiLevel;
+    bool mIsNdk;
+    // latency in ms for camera open, close, or session creation.
+    int mLatencyMs;
+
+    // Session info and statistics
+    int mSessionType;
+    int mInternalReconfigure;
+    // The number of capture requests
+    int64_t mRequestCount;
+    // The number of result error
+    int64_t mResultErrorCount;
+    // Whether the device runs into an error state
+    bool mDeviceError;
+    std::vector<CameraStreamStats> mStreamStats;
+
+    // Constructors
+    CameraSessionStats();
+    CameraSessionStats(const String16& cameraId, int facing, int newCameraState,
+            const String16& clientName, int apiLevel, bool isNdk, int32_t latencyMs);
+
+    virtual status_t readFromParcel(const android::Parcel* parcel) override;
+    virtual status_t writeToParcel(android::Parcel* parcel) const override;
+};
+
+}; // namespace hardware
+}; // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_SERVICE_SESSION_STATS_H
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 7ba82c1..3cf94d0 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -121,9 +121,11 @@
         "libcamera_metadata",
         "libmediandk",
         "android.frameworks.cameraservice.device@2.0",
+        "android.frameworks.cameraservice.device@2.1",
         "android.frameworks.cameraservice.common@2.0",
         "android.frameworks.cameraservice.service@2.0",
         "android.frameworks.cameraservice.service@2.1",
+        "android.frameworks.cameraservice.service@2.2",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index c15c5a5..08c88ce 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -186,6 +186,7 @@
         const ACaptureRequest* sessionParameters,
         const ACameraCaptureSession_stateCallbacks* callbacks,
         /*out*/ACameraCaptureSession** session) {
+    nsecs_t startTimeNs = systemTime();
     sp<ACameraCaptureSession> currentSession = mCurrentSession.promote();
     Mutex::Autolock _l(mDeviceLock);
     camera_status_t ret = checkCameraClosedOrErrorLocked();
@@ -199,7 +200,7 @@
     }
 
     // Create new session
-    ret = configureStreamsLocked(outputs, sessionParameters);
+    ret = configureStreamsLocked(outputs, sessionParameters, startTimeNs);
     if (ret != ACAMERA_OK) {
         ALOGE("Fail to create new session. cannot configure streams");
         return ret;
@@ -450,7 +451,11 @@
     }
 
     // No new session, unconfigure now
-    camera_status_t ret = configureStreamsLocked(nullptr, nullptr);
+    // Note: The unconfiguration of session won't be accounted for session
+    // latency because a stream configuration with 0 streams won't ever become
+    // active.
+    nsecs_t startTimeNs = systemTime();
+    camera_status_t ret = configureStreamsLocked(nullptr, nullptr, startTimeNs);
     if (ret != ACAMERA_OK) {
         ALOGE("Unconfigure stream failed. Device might still be configured! ret %d", ret);
     }
@@ -609,7 +614,7 @@
 
 camera_status_t
 CameraDevice::configureStreamsLocked(const ACaptureSessionOutputContainer* outputs,
-        const ACaptureRequest* sessionParameters) {
+        const ACaptureRequest* sessionParameters, nsecs_t startTimeNs) {
     ACaptureSessionOutputContainer emptyOutput;
     if (outputs == nullptr) {
         outputs = &emptyOutput;
@@ -711,7 +716,8 @@
         params.append(sessionParameters->settings->getInternalData());
     }
     std::vector<int> offlineStreamIds;
-    remoteRet = mRemote->endConfigure(/*isConstrainedHighSpeed*/ false, params, &offlineStreamIds);
+    remoteRet = mRemote->endConfigure(/*isConstrainedHighSpeed*/ false, params,
+            ns2ms(startTimeNs), &offlineStreamIds);
     if (remoteRet.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_ILLEGAL_ARGUMENT) {
         ALOGE("Camera device %s cannnot support app output configuration: %s", getId(),
                 remoteRet.toString8().string());
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index d937865..125e6e3 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -167,7 +167,7 @@
     void notifySessionEndOfLifeLocked(ACameraCaptureSession* session);
 
     camera_status_t configureStreamsLocked(const ACaptureSessionOutputContainer* outputs,
-           const ACaptureRequest* sessionParameters);
+           const ACaptureRequest* sessionParameters, nsecs_t startTimeNs);
 
     // Input message will be posted and cleared after this returns
     void postSessionMsgAndCleanup(sp<AMessage>& msg);
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 0fcb700..9f63099 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -180,6 +180,7 @@
         const ACaptureRequest* sessionParameters,
         const ACameraCaptureSession_stateCallbacks* callbacks,
         /*out*/ACameraCaptureSession** session) {
+    nsecs_t startTimeNs = systemTime();
     sp<ACameraCaptureSession> currentSession = mCurrentSession.promote();
     Mutex::Autolock _l(mDeviceLock);
     camera_status_t ret = checkCameraClosedOrErrorLocked();
@@ -193,7 +194,7 @@
     }
 
     // Create new session
-    ret = configureStreamsLocked(outputs, sessionParameters);
+    ret = configureStreamsLocked(outputs, sessionParameters, startTimeNs);
     if (ret != ACAMERA_OK) {
         ALOGE("Fail to create new session. cannot configure streams");
         return ret;
@@ -472,7 +473,11 @@
     }
 
     // No new session, unconfigure now
-    camera_status_t ret = configureStreamsLocked(nullptr, nullptr);
+    // Note: The unconfiguration of session won't be accounted for session
+    // latency because a stream configuration with 0 streams won't ever become
+    // active.
+    nsecs_t startTimeNs = systemTime();
+    camera_status_t ret = configureStreamsLocked(nullptr, nullptr, startTimeNs);
     if (ret != ACAMERA_OK) {
         ALOGE("Unconfigure stream failed. Device might still be configured! ret %d", ret);
     }
@@ -598,7 +603,7 @@
 
 camera_status_t
 CameraDevice::configureStreamsLocked(const ACaptureSessionOutputContainer* outputs,
-        const ACaptureRequest* sessionParameters) {
+        const ACaptureRequest* sessionParameters, nsecs_t startTimeNs) {
     ACaptureSessionOutputContainer emptyOutput;
     if (outputs == nullptr) {
         outputs = &emptyOutput;
@@ -697,7 +702,8 @@
         utils::convertToHidl(params_metadata, &hidlParams);
         params.unlock(params_metadata);
     }
-    remoteRet = mRemote->endConfigure(StreamConfigurationMode::NORMAL_MODE, hidlParams);
+    remoteRet = mRemote->endConfigure_2_1(StreamConfigurationMode::NORMAL_MODE,
+                                          hidlParams, startTimeNs);
     CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "endConfigure()")
     return ACAMERA_OK;
 }
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 7fc699e..0b6c7c8 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -26,7 +26,7 @@
 #include <utils/Mutex.h>
 #include <utils/List.h>
 #include <utils/Vector.h>
-#include <android/frameworks/cameraservice/device/2.0/ICameraDeviceUser.h>
+#include <android/frameworks/cameraservice/device/2.1/ICameraDeviceUser.h>
 #include <android/frameworks/cameraservice/device/2.0/ICameraDeviceCallback.h>
 #include <android/frameworks/cameraservice/device/2.0/types.h>
 #include <fmq/MessageQueue.h>
@@ -44,7 +44,8 @@
 namespace acam {
 
 using ICameraDeviceCallback = frameworks::cameraservice::device::V2_0::ICameraDeviceCallback;
-using ICameraDeviceUser = frameworks::cameraservice::device::V2_0::ICameraDeviceUser;
+using ICameraDeviceUser_2_0 = frameworks::cameraservice::device::V2_0::ICameraDeviceUser;
+using ICameraDeviceUser = frameworks::cameraservice::device::V2_1::ICameraDeviceUser;
 using CaptureResultExtras = frameworks::cameraservice::device::V2_0::CaptureResultExtras;
 using PhysicalCaptureResultInfo = frameworks::cameraservice::device::V2_0::PhysicalCaptureResultInfo;
 using PhysicalCameraSettings = frameworks::cameraservice::device::V2_0::PhysicalCameraSettings;
@@ -201,7 +202,7 @@
     void notifySessionEndOfLifeLocked(ACameraCaptureSession* session);
 
     camera_status_t configureStreamsLocked(const ACaptureSessionOutputContainer* outputs,
-           const ACaptureRequest* sessionParameters);
+           const ACaptureRequest* sessionParameters, nsecs_t startTimeNs);
 
     // Input message will be posted and cleared after this returns
     void postSessionMsgAndCleanup(sp<AMessage>& msg);
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index 5aa9c46..77c934a 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -764,15 +764,15 @@
     }
 
     sp<ICameraDeviceCallback> callbacks = device->getServiceCallback();
-    sp<ICameraDeviceUser> deviceRemote;
+    sp<ICameraDeviceUser_2_0> deviceRemote_2_0;
 
     // No way to get package name from native.
     // Send a zero length package name and let camera service figure it out from UID
     Status status = Status::NO_ERROR;
     auto serviceRet = cs->connectDevice(
-            callbacks, cameraId, [&status, &deviceRemote](auto s, auto &device) {
+            callbacks, cameraId, [&status, &deviceRemote_2_0](auto s, auto &device) {
                                      status = s;
-                                     deviceRemote = device;
+                                     deviceRemote_2_0 = device;
                                  });
 
     if (!serviceRet.isOk() || status != Status::NO_ERROR) {
@@ -780,11 +780,18 @@
         delete device;
         return utils::convertFromHidl(status);
     }
-    if (deviceRemote == nullptr) {
+    if (deviceRemote_2_0 == nullptr) {
         ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
         delete device;
         return ACAMERA_ERROR_CAMERA_DISCONNECTED;
     }
+    auto castResult = ICameraDeviceUser::castFrom(deviceRemote_2_0);
+    if (!castResult.isOk()) {
+        ALOGE("%s: failed to cast remote device to version 2.1", __FUNCTION__);
+        delete device;
+        return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+    }
+    sp<ICameraDeviceUser> deviceRemote = castResult;
     device->setRemoteDevice(deviceRemote);
     device->setDeviceMetadataQueues();
     *outDevice = device;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index 85da3e9..8359bb1 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -22,6 +22,7 @@
 #include <android-base/parseint.h>
 #include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
 #include <android/frameworks/cameraservice/service/2.1/ICameraService.h>
+#include <android/frameworks/cameraservice/service/2.2/ICameraService.h>
 #include <android/frameworks/cameraservice/service/2.1/ICameraServiceListener.h>
 
 #include <CameraMetadata.h>
@@ -38,7 +39,7 @@
 namespace android {
 namespace acam {
 
-using ICameraService = frameworks::cameraservice::service::V2_1::ICameraService;
+using ICameraService = frameworks::cameraservice::service::V2_2::ICameraService;
 using CameraDeviceStatus = frameworks::cameraservice::service::V2_0::CameraDeviceStatus;
 using ICameraServiceListener = frameworks::cameraservice::service::V2_1::ICameraServiceListener;
 using PhysicalCameraStatusAndId = frameworks::cameraservice::service::V2_1::PhysicalCameraStatusAndId;
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index eee05ff..0cf390f 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -517,7 +517,7 @@
         CameraMetadata sessionParams;
         std::vector<int> offlineStreamIds;
         res = device->endConfigure(/*isConstrainedHighSpeed*/ false, sessionParams,
-                &offlineStreamIds);
+                ns2ms(systemTime()), &offlineStreamIds);
         EXPECT_TRUE(res.isOk()) << res;
         EXPECT_FALSE(callbacks->hadError());
 
@@ -629,7 +629,7 @@
         res = device->deleteStream(streamId);
         EXPECT_TRUE(res.isOk()) << res;
         res = device->endConfigure(/*isConstrainedHighSpeed*/ false, sessionParams,
-                &offlineStreamIds);
+                ns2ms(systemTime()), &offlineStreamIds);
         EXPECT_TRUE(res.isOk()) << res;
 
         sleep(/*second*/1); // allow some time for errors to show up, if any
diff --git a/include/media/MicrophoneInfo.h b/include/media/MicrophoneInfo.h
index 2287aca..0a24b02 100644
--- a/include/media/MicrophoneInfo.h
+++ b/include/media/MicrophoneInfo.h
@@ -205,11 +205,11 @@
 private:
     status_t readFloatVector(
             const Parcel* parcel, Vector<float> *vectorPtr, size_t defaultLength) {
-        std::unique_ptr<std::vector<float>> v;
+        std::optional<std::vector<float>> v;
         status_t result = parcel->readFloatVector(&v);
         if (result != OK) return result;
         vectorPtr->clear();
-        if (v.get() != nullptr) {
+        if (v) {
             for (const auto& iter : *v) {
                 vectorPtr->push_back(iter);
             }
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index c7588e9..dd1f485 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -25,6 +25,7 @@
 #include <C2AllocatorGralloc.h>
 #include <C2BlockInternal.h>
 #include <C2Component.h>
+#include <C2Config.h>
 #include <C2PlatformSupport.h>
 
 #include <OMX_Component.h>
@@ -44,6 +45,8 @@
 
 namespace {
 
+constexpr OMX_U32 kPortIndexInput = 0;
+
 class Buffer2D : public C2Buffer {
 public:
     explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {}
@@ -200,11 +203,27 @@
                 return BAD_VALUE;
             }
             OMX_PARAM_PORTDEFINITIONTYPE *pDef = (OMX_PARAM_PORTDEFINITIONTYPE *)params;
-            // TODO: read these from intf()
+            if (pDef->nPortIndex != kPortIndexInput) {
+                break;
+            }
+
             pDef->nBufferCountActual = 16;
+
+            std::shared_ptr<Codec2Client::Component> comp = mComp.lock();
+            C2PortActualDelayTuning::input inputDelay(0);
+            C2ActualPipelineDelayTuning pipelineDelay(0);
+            c2_status_t c2err = comp->query(
+                    {&inputDelay, &pipelineDelay}, {}, C2_DONT_BLOCK, nullptr);
+            if (c2err == C2_OK || c2err == C2_BAD_INDEX) {
+                pDef->nBufferCountActual = 4;
+                pDef->nBufferCountActual += (inputDelay ? inputDelay.value : 0u);
+                pDef->nBufferCountActual += (pipelineDelay ? pipelineDelay.value : 0u);
+            }
+
             pDef->eDomain = OMX_PortDomainVideo;
             pDef->format.video.nFrameWidth = mWidth;
             pDef->format.video.nFrameHeight = mHeight;
+            pDef->format.video.eColorFormat = OMX_COLOR_FormatAndroidOpaque;
             err = OK;
             break;
         }
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 6666788..eeba10c 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -65,7 +65,7 @@
 
     /**
      * This format uses the int16_t data type.
-     * The maximum range of the data is -32768 to 32767.
+     * The maximum range of the data is -32768 (0x8000) to 32767 (0x7FFF).
      */
     AAUDIO_FORMAT_PCM_I16,
 
@@ -77,7 +77,31 @@
      * See also 'floatData' at
      * https://developer.android.com/reference/android/media/AudioTrack#write(float[],%20int,%20int,%20int)
      */
-    AAUDIO_FORMAT_PCM_FLOAT
+    AAUDIO_FORMAT_PCM_FLOAT,
+
+    /**
+     * This format uses 24-bit samples packed into 3 bytes.
+     * The bytes are in the native endian order.
+     * The maximum range of the data is -8388608 (0x800000)
+     * to 8388607 (0x7FFFFF).
+     *
+     * Note that the lower precision bits may be ignored by the device.
+     *
+     * Available since API level 31.
+     */
+    AAUDIO_FORMAT_PCM_I24_PACKED,
+
+    /**
+     * This format uses 32-bit samples stored in an int32_t data type.
+     * The maximum range of the data is -2147483648 (0x80000000)
+     * to 2147483647 (0x7FFFFFFF).
+     *
+     * Note that the lower precision bits may be ignored by the device.
+     *
+     * Available since API level 31.
+     */
+    AAUDIO_FORMAT_PCM_I32
+
 };
 typedef int32_t aaudio_format_t;
 
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index aafcccc..d02d1b6 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -130,9 +130,11 @@
         "flowgraph/SinkFloat.cpp",
         "flowgraph/SinkI16.cpp",
         "flowgraph/SinkI24.cpp",
+        "flowgraph/SinkI32.cpp",
         "flowgraph/SourceFloat.cpp",
         "flowgraph/SourceI16.cpp",
         "flowgraph/SourceI24.cpp",
+        "flowgraph/SourceI32.cpp",
     ],
     sanitize: {
         integer_overflow: true,
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.cpp b/media/libaaudio/src/client/AAudioFlowGraph.cpp
index 8f2c488..61b50f3 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.cpp
+++ b/media/libaaudio/src/client/AAudioFlowGraph.cpp
@@ -26,9 +26,11 @@
 #include <flowgraph/SinkFloat.h>
 #include <flowgraph/SinkI16.h>
 #include <flowgraph/SinkI24.h>
+#include <flowgraph/SinkI32.h>
 #include <flowgraph/SourceFloat.h>
 #include <flowgraph/SourceI16.h>
 #include <flowgraph/SourceI24.h>
+#include <flowgraph/SourceI32.h>
 
 using namespace flowgraph;
 
@@ -38,7 +40,8 @@
                           int32_t sinkChannelCount) {
     AudioFloatOutputPort *lastOutput = nullptr;
 
-    ALOGV("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d",
+    // TODO change back to ALOGD
+    ALOGI("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d",
           __func__, sourceFormat, sourceChannelCount, sinkFormat, sinkChannelCount);
 
     switch (sourceFormat) {
@@ -51,7 +54,10 @@
         case AUDIO_FORMAT_PCM_24_BIT_PACKED:
             mSource = std::make_unique<SourceI24>(sourceChannelCount);
             break;
-        default: // TODO add I32
+        case AUDIO_FORMAT_PCM_32_BIT:
+            mSource = std::make_unique<SourceI32>(sourceChannelCount);
+            break;
+        default:
             ALOGE("%s() Unsupported source format = %d", __func__, sourceFormat);
             return AAUDIO_ERROR_UNIMPLEMENTED;
     }
@@ -90,7 +96,10 @@
         case AUDIO_FORMAT_PCM_24_BIT_PACKED:
             mSink = std::make_unique<SinkI24>(sinkChannelCount);
             break;
-        default: // TODO add I32
+        case AUDIO_FORMAT_PCM_32_BIT:
+            mSink = std::make_unique<SinkI32>(sinkChannelCount);
+            break;
+        default:
             ALOGE("%s() Unsupported sink format = %d", __func__, sinkFormat);
             return AAUDIO_ERROR_UNIMPLEMENTED;
     }
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 809c76e..2815c6a 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -104,7 +104,7 @@
     if (getFormat() == AUDIO_FORMAT_DEFAULT) {
         setFormat(AUDIO_FORMAT_PCM_FLOAT);
     }
-    // Request FLOAT for the shared mixer.
+    // Request FLOAT for the shared mixer or the device.
     request.getConfiguration().setFormat(AUDIO_FORMAT_PCM_FLOAT);
 
     // Build the request to send to the server.
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 5f45261..2c81c91 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -54,7 +54,9 @@
     switch (format) {
         case AUDIO_FORMAT_DEFAULT:
         case AUDIO_FORMAT_PCM_16_BIT:
+        case AUDIO_FORMAT_PCM_32_BIT:
         case AUDIO_FORMAT_PCM_FLOAT:
+        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
             break; // valid
         default:
             ALOGD("audioFormat not valid, audio_format_t = 0x%08x", format);
diff --git a/media/libaaudio/src/core/AudioGlobal.cpp b/media/libaaudio/src/core/AudioGlobal.cpp
index 7f5d8d5..0e5b8be 100644
--- a/media/libaaudio/src/core/AudioGlobal.cpp
+++ b/media/libaaudio/src/core/AudioGlobal.cpp
@@ -80,6 +80,8 @@
         AAUDIO_CASE_ENUM(AAUDIO_FORMAT_INVALID);
         AAUDIO_CASE_ENUM(AAUDIO_FORMAT_PCM_I16);
         AAUDIO_CASE_ENUM(AAUDIO_FORMAT_PCM_FLOAT);
+        AAUDIO_CASE_ENUM(AAUDIO_FORMAT_PCM_I24_PACKED);
+        AAUDIO_CASE_ENUM(AAUDIO_FORMAT_PCM_I32);
     }
     return "Unrecognized";
 }
diff --git a/media/libaaudio/src/flowgraph/FlowgraphUtilities.h b/media/libaaudio/src/flowgraph/FlowgraphUtilities.h
new file mode 100644
index 0000000..b750410
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/FlowgraphUtilities.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020 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 FLOWGRAPH_UTILITIES_H
+#define FLOWGRAPH_UTILITIES_H
+
+#include <unistd.h>
+
+using namespace flowgraph;
+
+class FlowgraphUtilities {
+public:
+// This was copied from audio_utils/primitives.h
+/**
+ * Convert a single-precision floating point value to a Q0.31 integer value.
+ * Rounds to nearest, ties away from 0.
+ *
+ * Values outside the range [-1.0, 1.0) are properly clamped to -2147483648 and 2147483647,
+ * including -Inf and +Inf. NaN values are considered undefined, and behavior may change
+ * depending on hardware and future implementation of this function.
+ */
+static int32_t clamp32FromFloat(float f)
+{
+    static const float scale = (float)(1UL << 31);
+    static const float limpos = 1.;
+    static const float limneg = -1.;
+
+    if (f <= limneg) {
+        return -0x80000000; /* or 0x80000000 */
+    } else if (f >= limpos) {
+        return 0x7fffffff;
+    }
+    f *= scale;
+    /* integer conversion is through truncation (though int to float is not).
+     * ensure that we round to nearest, ties away from 0.
+     */
+    return f > 0 ? f + 0.5 : f - 0.5;
+}
+
+};
+
+#endif // FLOWGRAPH_UTILITIES_H
diff --git a/media/libaaudio/src/flowgraph/SinkI24.cpp b/media/libaaudio/src/flowgraph/SinkI24.cpp
index 6592828..0cb077d 100644
--- a/media/libaaudio/src/flowgraph/SinkI24.cpp
+++ b/media/libaaudio/src/flowgraph/SinkI24.cpp
@@ -15,7 +15,7 @@
  */
 
 #include <algorithm>
-#include <unistd.h>
+#include <stdint.h>
 
 #ifdef __ANDROID__
 #include <audio_utils/primitives.h>
@@ -26,7 +26,6 @@
 
 using namespace flowgraph;
 
-
 SinkI24::SinkI24(int32_t channelCount)
         : AudioSink(channelCount) {}
 
diff --git a/media/libaaudio/src/flowgraph/SinkI32.cpp b/media/libaaudio/src/flowgraph/SinkI32.cpp
new file mode 100644
index 0000000..eab863d
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SinkI32.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#ifdef __ANDROID__
+#include <audio_utils/primitives.h>
+#endif
+
+#include "AudioProcessorBase.h"
+#include "FlowgraphUtilities.h"
+#include "SinkI32.h"
+
+using namespace flowgraph;
+
+SinkI32::SinkI32(int32_t channelCount)
+        : AudioSink(channelCount) {}
+
+int32_t SinkI32::read(void *data, int32_t numFrames) {
+    int32_t *intData = (int32_t *) data;
+    const int32_t channelCount = input.getSamplesPerFrame();
+
+    int32_t framesLeft = numFrames;
+    while (framesLeft > 0) {
+        // Run the graph and pull data through the input port.
+        int32_t framesRead = pull(framesLeft);
+        if (framesRead <= 0) {
+            break;
+        }
+        const float *signal = input.getBlock();
+        int32_t numSamples = framesRead * channelCount;
+#ifdef __ANDROID__
+        memcpy_to_i32_from_float(intData, signal, numSamples);
+        intData += numSamples;
+        signal += numSamples;
+#else
+        for (int i = 0; i < numSamples; i++) {
+            *intData++ = FlowgraphUtilities::clamp32FromFloat(*signal++);
+        }
+#endif
+        framesLeft -= framesRead;
+    }
+    return numFrames - framesLeft;
+}
diff --git a/media/libaaudio/src/flowgraph/SinkI32.h b/media/libaaudio/src/flowgraph/SinkI32.h
new file mode 100644
index 0000000..09d23b7
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SinkI32.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 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 FLOWGRAPH_SINK_I32_H
+#define FLOWGRAPH_SINK_I32_H
+
+#include <stdint.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+class SinkI32 : public AudioSink {
+public:
+    explicit SinkI32(int32_t channelCount);
+    ~SinkI32() override = default;
+
+    int32_t read(void *data, int32_t numFrames) override;
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SINK_I32_H
diff --git a/media/libaaudio/src/flowgraph/SourceI24.cpp b/media/libaaudio/src/flowgraph/SourceI24.cpp
index f319880..097954e 100644
--- a/media/libaaudio/src/flowgraph/SourceI24.cpp
+++ b/media/libaaudio/src/flowgraph/SourceI24.cpp
@@ -15,7 +15,7 @@
  */
 
 #include <algorithm>
-#include <unistd.h>
+#include <stdint.h>
 
 #ifdef __ANDROID__
 #include <audio_utils/primitives.h>
diff --git a/media/libaaudio/src/flowgraph/SourceI24.h b/media/libaaudio/src/flowgraph/SourceI24.h
index 39f14da..2ed6f18 100644
--- a/media/libaaudio/src/flowgraph/SourceI24.h
+++ b/media/libaaudio/src/flowgraph/SourceI24.h
@@ -17,8 +17,7 @@
 #ifndef FLOWGRAPH_SOURCE_I24_H
 #define FLOWGRAPH_SOURCE_I24_H
 
-#include <unistd.h>
-#include <sys/types.h>
+#include <stdint.h>
 
 #include "AudioProcessorBase.h"
 
diff --git a/media/libaaudio/src/flowgraph/SourceI32.cpp b/media/libaaudio/src/flowgraph/SourceI32.cpp
new file mode 100644
index 0000000..e8177ad
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SourceI32.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 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 <algorithm>
+#include <unistd.h>
+
+#ifdef __ANDROID__
+#include <audio_utils/primitives.h>
+#endif
+
+#include "AudioProcessorBase.h"
+#include "SourceI32.h"
+
+using namespace flowgraph;
+
+SourceI32::SourceI32(int32_t channelCount)
+        : AudioSource(channelCount) {
+}
+
+int32_t SourceI32::onProcess(int64_t framePosition, int32_t numFrames) {
+    float *floatData = output.getBlock();
+    int32_t channelCount = output.getSamplesPerFrame();
+
+    int32_t framesLeft = mSizeInFrames - mFrameIndex;
+    int32_t framesToProcess = std::min(numFrames, framesLeft);
+    int32_t numSamples = framesToProcess * channelCount;
+
+    const int32_t *intBase = static_cast<const int32_t *>(mData);
+    const int32_t *intData = &intBase[mFrameIndex * channelCount];
+
+#ifdef __ANDROID__
+    memcpy_to_float_from_i32(floatData, intData, numSamples);
+#else
+    for (int i = 0; i < numSamples; i++) {
+        *floatData++ = *intData++ * kScale;
+    }
+#endif
+
+    mFrameIndex += framesToProcess;
+    return framesToProcess;
+}
diff --git a/media/libaaudio/src/flowgraph/SourceI32.h b/media/libaaudio/src/flowgraph/SourceI32.h
new file mode 100644
index 0000000..e50f9be
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SourceI32.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef FLOWGRAPH_SOURCE_I32_H
+#define FLOWGRAPH_SOURCE_I32_H
+
+#include <stdint.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+class SourceI32 : public AudioSource {
+public:
+    explicit SourceI32(int32_t channelCount);
+    ~SourceI32() override = default;
+
+    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+
+private:
+    static constexpr float kScale = 1.0 / (1UL << 31);
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SOURCE_I32_H
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index 3dfb801..d795725 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -134,6 +134,12 @@
     case AAUDIO_FORMAT_PCM_FLOAT:
         androidFormat = AUDIO_FORMAT_PCM_FLOAT;
         break;
+    case AAUDIO_FORMAT_PCM_I24_PACKED:
+        androidFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+        break;
+    case AAUDIO_FORMAT_PCM_I32:
+        androidFormat = AUDIO_FORMAT_PCM_32_BIT;
+        break;
     default:
         androidFormat = AUDIO_FORMAT_INVALID;
         ALOGE("%s() 0x%08X unrecognized", __func__, aaudioFormat);
@@ -154,6 +160,12 @@
     case AUDIO_FORMAT_PCM_FLOAT:
         aaudioFormat = AAUDIO_FORMAT_PCM_FLOAT;
         break;
+    case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+        aaudioFormat = AAUDIO_FORMAT_PCM_I24_PACKED;
+        break;
+    case AUDIO_FORMAT_PCM_32_BIT:
+        aaudioFormat = AAUDIO_FORMAT_PCM_I32;
+        break;
     default:
         aaudioFormat = AAUDIO_FORMAT_INVALID;
         ALOGE("%s() 0x%08X unrecognized", __func__, androidFormat);
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index 050ad65..ee78a2d 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -853,6 +853,11 @@
                       { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
           .repeatCnt = ToneGenerator::TONEGEN_INF,
           .repeatSegment = 0 },                               // TONE_INDIA_RINGTONE
+        { .segments = { { .duration = 1000, .waveFreq = { 440, 480, 0 }, 0, 0 },
+                        { .duration = 2000, .waveFreq = { 0 }, 0, 0 },
+                        { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+          .repeatCnt = ToneGenerator::TONEGEN_INF,
+          .repeatSegment = 0 },                               // TONE_TW_RINGTONE
 };
 
 // Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type
@@ -937,6 +942,16 @@
             TONE_SUP_ERROR,              // TONE_SUP_ERROR
             TONE_INDIA_CALL_WAITING,     // TONE_SUP_CALL_WAITING
             TONE_INDIA_RINGTONE          // TONE_SUP_RINGTONE
+        },
+        {   // TAIWAN
+            TONE_SUP_DIAL,               // TONE_SUP_DIAL
+            TONE_SUP_BUSY,               // TONE_SUP_BUSY
+            TONE_SUP_CONGESTION,         // TONE_SUP_CONGESTION
+            TONE_SUP_RADIO_ACK,          // TONE_SUP_RADIO_ACK
+            TONE_SUP_RADIO_NOTAVAIL,     // TONE_SUP_RADIO_NOTAVAIL
+            TONE_SUP_ERROR,              // TONE_SUP_ERROR
+            TONE_SUP_CALL_WAITING,       // TONE_SUP_CALL_WAITING
+            TONE_TW_RINGTONE             // TONE_SUP_RINGTONE
         }
 };
 
@@ -1010,6 +1025,8 @@
         mRegion = IRELAND;
     } else if (strstr(value, "in") != NULL) {
         mRegion = INDIA;
+    } else if (strstr(value, "tw") != NULL) {
+        mRegion = TAIWAN;
     } else {
         mRegion = CEPT;
     }
diff --git a/media/libaudioclient/include/media/ToneGenerator.h b/media/libaudioclient/include/media/ToneGenerator.h
index 5b0689a..04357a8 100644
--- a/media/libaudioclient/include/media/ToneGenerator.h
+++ b/media/libaudioclient/include/media/ToneGenerator.h
@@ -218,6 +218,7 @@
         TONE_INDIA_CONGESTION,      // Congestion tone: 400 Hz, 250ms ON, 250ms OFF...
         TONE_INDIA_CALL_WAITING,    // Call waiting tone: 400 Hz, tone repeated in a 0.2s on, 0.1s off, 0.2s on, 7.5s off pattern.
         TONE_INDIA_RINGTONE,        // Ring tone: 400 Hz tone modulated with 25Hz, 0.4 on 0.2 off 0.4 on 2..0 off
+        TONE_TW_RINGTONE,           // Ring Tone: 440 Hz + 480 Hz repeated with pattern 1s on, 3s off.
         NUM_ALTERNATE_TONES
     };
 
@@ -230,6 +231,7 @@
         HONGKONG,
         IRELAND,
         INDIA,
+        TAIWAN,
         CEPT,
         NUM_REGIONS
     };
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 4a36865..8cb40e0 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -69,11 +69,13 @@
         "hidl/Convert.cpp",
         "hidl/HidlCameraDeviceUser.cpp",
         "hidl/HidlCameraService.cpp",
+        "utils/CameraServiceProxyWrapper.cpp",
         "utils/CameraThreadState.cpp",
         "utils/CameraTraces.cpp",
         "utils/AutoConditionLock.cpp",
         "utils/ExifUtils.cpp",
         "utils/SessionConfigurationUtils.cpp",
+        "utils/SessionStatsBuilder.cpp",
         "utils/TagMonitor.cpp",
         "utils/LatencyHistogram.cpp",
     ],
@@ -115,7 +117,9 @@
         "android.frameworks.cameraservice.common@2.0",
         "android.frameworks.cameraservice.service@2.0",
         "android.frameworks.cameraservice.service@2.1",
+        "android.frameworks.cameraservice.service@2.2",
         "android.frameworks.cameraservice.device@2.0",
+        "android.frameworks.cameraservice.device@2.1",
         "android.hardware.camera.common@1.0",
         "android.hardware.camera.provider@2.4",
         "android.hardware.camera.provider@2.5",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 138e429..8400dae 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -37,7 +37,6 @@
 #include <binder/ActivityManager.h>
 #include <binder/AppOpsManager.h>
 #include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
 #include <binder/MemoryBase.h>
 #include <binder/MemoryHeapBase.h>
 #include <binder/PermissionController.h>
@@ -75,6 +74,7 @@
 #include "utils/CameraTraces.h"
 #include "utils/TagMonitor.h"
 #include "utils/CameraThreadState.h"
+#include "utils/CameraServiceProxyWrapper.h"
 
 namespace {
     const char* kPermissionServiceName = "permission";
@@ -87,7 +87,6 @@
 using frameworks::cameraservice::service::V2_0::implementation::HidlCameraService;
 using hardware::ICamera;
 using hardware::ICameraClient;
-using hardware::ICameraServiceProxy;
 using hardware::ICameraServiceListener;
 using hardware::camera::common::V1_0::CameraDeviceStatus;
 using hardware::camera::common::V1_0::TorchModeStatus;
@@ -134,9 +133,6 @@
 static constexpr int32_t kVendorClientState = 1;
 const String8 CameraService::kOfflineDevice("offline-");
 
-Mutex CameraService::sProxyMutex;
-sp<hardware::ICameraServiceProxy> CameraService::sCameraServiceProxy;
-
 CameraService::CameraService() :
         mEventLog(DEFAULT_EVENT_LOG_LENGTH),
         mNumberOfCameras(0),
@@ -178,7 +174,7 @@
 
     // This needs to be last call in this function, so that it's as close to
     // ServiceManager::addService() as possible.
-    CameraService::pingCameraServiceProxy();
+    CameraServiceProxyWrapper::pingCameraServiceProxy();
     ALOGI("CameraService pinged cameraservice proxy");
 }
 
@@ -228,29 +224,6 @@
     return OK;
 }
 
-sp<ICameraServiceProxy> CameraService::getCameraServiceProxy() {
-#ifndef __BRILLO__
-    Mutex::Autolock al(sProxyMutex);
-    if (sCameraServiceProxy == nullptr) {
-        sp<IServiceManager> sm = defaultServiceManager();
-        // Use checkService because cameraserver normally starts before the
-        // system server and the proxy service. So the long timeout that getService
-        // has before giving up is inappropriate.
-        sp<IBinder> binder = sm->checkService(String16("media.camera.proxy"));
-        if (binder != nullptr) {
-            sCameraServiceProxy = interface_cast<ICameraServiceProxy>(binder);
-        }
-    }
-#endif
-    return sCameraServiceProxy;
-}
-
-void CameraService::pingCameraServiceProxy() {
-    sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
-    if (proxyBinder == nullptr) return;
-    proxyBinder->pingForUserUpdate();
-}
-
 void CameraService::broadcastTorchModeStatus(const String8& cameraId, TorchModeStatus status) {
     Mutex::Autolock lock(mStatusListenerLock);
 
@@ -1573,7 +1546,11 @@
             "Camera API version %d", clientPid, clientName8.string(), cameraId.string(),
             static_cast<int>(effectiveApiLevel));
 
+    nsecs_t openTimeNs = systemTime();
+
     sp<CLIENT> client = nullptr;
+    int facing = -1;
+    bool isNdk = (clientPackageName.size() == 0);
     {
         // Acquire mServiceLock and prevent other clients from connecting
         std::unique_ptr<AutoConditionLock> lock =
@@ -1638,7 +1615,6 @@
         // give flashlight a chance to close devices if necessary.
         mFlashlight->prepareDeviceOpen(cameraId);
 
-        int facing = -1;
         int deviceVersion = getDeviceVersion(cameraId, /*out*/&facing);
         if (facing == -1) {
             ALOGE("%s: Unable to get camera device \"%s\"  facing", __FUNCTION__, cameraId.string());
@@ -1723,6 +1699,11 @@
     // Important: release the mutex here so the client can call back into the service from its
     // destructor (can be at the end of the call)
     device = client;
+
+    int32_t openLatencyMs = ns2ms(systemTime() - openTimeNs);
+    CameraServiceProxyWrapper::logOpen(cameraId, facing, clientPackageName,
+            effectiveApiLevel, isNdk, openLatencyMs);
+
     return ret;
 }
 
@@ -2880,14 +2861,6 @@
     // Transition device availability listeners from PRESENT -> NOT_AVAILABLE
     sCameraService->updateStatus(StatusInternal::NOT_AVAILABLE, mCameraIdStr);
 
-    int apiLevel = hardware::ICameraServiceProxy::CAMERA_API_LEVEL_1;
-    if (canCastToApiClient(API_2)) {
-        apiLevel = hardware::ICameraServiceProxy::CAMERA_API_LEVEL_2;
-    }
-    // Transition device state to OPEN
-    sCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_OPEN,
-            mCameraIdStr, mCameraFacing, mClientPackageName, apiLevel);
-
     sCameraService->mUidPolicy->registerMonitorUid(mClientUid);
 
     // Notify listeners of camera open/close status
@@ -2916,14 +2889,6 @@
         // Transition to PRESENT if the camera is not in either of the rejected states
         sCameraService->updateStatus(StatusInternal::PRESENT,
                 mCameraIdStr, rejected);
-
-        int apiLevel = hardware::ICameraServiceProxy::CAMERA_API_LEVEL_1;
-        if (canCastToApiClient(API_2)) {
-            apiLevel = hardware::ICameraServiceProxy::CAMERA_API_LEVEL_2;
-        }
-        // Transition device state to CLOSED
-        sCameraService->updateProxyDeviceState(ICameraServiceProxy::CAMERA_STATE_CLOSED,
-                mCameraIdStr, mCameraFacing, mClientPackageName, apiLevel);
     }
     // Always stop watching, even if no camera op is active
     if (mOpsCallback != nullptr && mAppOpsManager != nullptr) {
@@ -3803,14 +3768,6 @@
     onStatusUpdatedLocked(cameraId, status);
 }
 
-void CameraService::updateProxyDeviceState(int newState,
-        const String8& cameraId, int facing, const String16& clientName, int apiLevel) {
-    sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
-    if (proxyBinder == nullptr) return;
-    String16 id(cameraId);
-    proxyBinder->notifyCameraState(id, newState, facing, clientName, apiLevel);
-}
-
 status_t CameraService::getTorchStatusLocked(
         const String8& cameraId,
         TorchModeStatus *status) const {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 6f37e9f..d26c62d 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -20,7 +20,6 @@
 #include <android/hardware/BnCameraService.h>
 #include <android/hardware/BnSensorPrivacyListener.h>
 #include <android/hardware/ICameraServiceListener.h>
-#include <android/hardware/ICameraServiceProxy.h>
 
 #include <cutils/multiuser.h>
 #include <utils/Vector.h>
@@ -211,16 +210,6 @@
     void                loadSoundLocked(sound_kind kind);
     void                decreaseSoundRef();
     void                increaseSoundRef();
-    /**
-     * Update the state of a given camera device (open/close/active/idle) with
-     * the camera proxy service in the system service
-     */
-    static void         updateProxyDeviceState(
-            int newState,
-            const String8& cameraId,
-            int facing,
-            const String16& clientName,
-            int apiLevel);
 
     /////////////////////////////////////////////////////////////////////
     // CameraDeviceFactory functionality
@@ -1069,13 +1058,6 @@
     static StatusInternal mapToInternal(hardware::camera::common::V1_0::CameraDeviceStatus status);
     static int32_t mapToInterface(StatusInternal status);
 
-    // Guard mCameraServiceProxy
-    static Mutex sProxyMutex;
-    // Cached interface to the camera service proxy in system service
-    static sp<hardware::ICameraServiceProxy> sCameraServiceProxy;
-
-    static sp<hardware::ICameraServiceProxy> getCameraServiceProxy();
-    static void pingCameraServiceProxy();
 
     void broadcastTorchModeStatus(const String8& cameraId,
             hardware::camera::common::V1_0::TorchModeStatus status);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 09e2c3f..662b58f 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -34,6 +34,7 @@
 #include "api1/client2/CallbackProcessor.h"
 #include "api1/client2/ZslProcessor.h"
 #include "utils/CameraThreadState.h"
+#include "utils/CameraServiceProxyWrapper.h"
 
 #define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
 #define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
@@ -396,6 +397,7 @@
 
 binder::Status Camera2Client::disconnect() {
     ATRACE_CALL();
+    nsecs_t startTime = systemTime();
     Mutex::Autolock icl(mBinderSerializationLock);
 
     binder::Status res = binder::Status::ok();
@@ -457,6 +459,9 @@
 
     CameraService::Client::disconnect();
 
+    int32_t closeLatencyMs = ns2ms(systemTime() - startTime);
+    CameraServiceProxyWrapper::logClose(mCameraIdStr, closeLatencyMs);
+
     return res;
 }
 
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index e80838b..66eda5d 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -31,6 +31,7 @@
 #include "device3/Camera3Device.h"
 #include "device3/Camera3OutputStream.h"
 #include "api2/CameraDeviceClient.h"
+#include "utils/CameraServiceProxyWrapper.h"
 
 #include <camera_metadata_hidden.h>
 
@@ -471,7 +472,7 @@
 }
 
 binder::Status CameraDeviceClient::endConfigure(int operatingMode,
-        const hardware::camera2::impl::CameraMetadataNative& sessionParams,
+        const hardware::camera2::impl::CameraMetadataNative& sessionParams, int64_t startTimeMs,
         std::vector<int>* offlineStreamIds /*out*/) {
     ATRACE_CALL();
     ALOGV("%s: ending configure (%d input stream, %zu output surfaces)",
@@ -547,6 +548,11 @@
         for (const auto& offlineStreamId : *offlineStreamIds) {
             mStreamInfoMap[offlineStreamId].supportsOffline = true;
         }
+
+        nsecs_t configureEnd = systemTime();
+        int32_t configureDurationMs = ns2ms(configureEnd) - startTimeMs;
+        CameraServiceProxyWrapper::logStreamConfigured(mCameraIdStr, operatingMode,
+                false /*internalReconfig*/, configureDurationMs);
     }
 
     return res;
@@ -1708,14 +1714,16 @@
     mStreamingRequestId = REQUEST_ID_NONE;
 }
 
-void CameraDeviceClient::notifyIdle() {
+void CameraDeviceClient::notifyIdle(
+        int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+        const std::vector<hardware::CameraStreamStats>& streamStats) {
     // Thread safe. Don't bother locking.
     sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
 
     if (remoteCb != 0) {
         remoteCb->onDeviceIdle();
     }
-    Camera2ClientBase::notifyIdle();
+    Camera2ClientBase::notifyIdle(requestCount, resultErrorCount, deviceError, streamStats);
 }
 
 void CameraDeviceClient::notifyShutter(const CaptureResultExtras& resultExtras,
@@ -1751,6 +1759,7 @@
 void CameraDeviceClient::detachDevice() {
     if (mDevice == 0) return;
 
+    nsecs_t startTime = systemTime();
     ALOGV("Camera %s: Stopping processors", mCameraIdStr.string());
 
     mFrameProcessor->removeListener(camera2::FrameProcessorBase::FRAME_PROCESSOR_LISTENER_MIN_ID,
@@ -1785,6 +1794,9 @@
     mCompositeStreamMap.clear();
 
     Camera2ClientBase::detachDevice();
+
+    int32_t closeLatencyMs = ns2ms(systemTime() - startTime);
+    CameraServiceProxyWrapper::logClose(mCameraIdStr, closeLatencyMs);
 }
 
 /** Device-related methods */
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 2807aee..5d40b82 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -95,6 +95,7 @@
 
     virtual binder::Status endConfigure(int operatingMode,
             const hardware::camera2::impl::CameraMetadataNative& sessionParams,
+            int64_t startTimeMs,
             /*out*/
             std::vector<int>* offlineStreamIds) override;
 
@@ -196,7 +197,8 @@
      * Device listener interface
      */
 
-    virtual void notifyIdle();
+    virtual void notifyIdle(int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+                            const std::vector<hardware::CameraStreamStats>& streamStats);
     virtual void notifyError(int32_t errorCode,
                              const CaptureResultExtras& resultExtras);
     virtual void notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp);
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index 237c24b..62b5479 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -265,7 +265,9 @@
     }
 }
 
-void CameraOfflineSessionClient::notifyIdle() {
+void CameraOfflineSessionClient::notifyIdle(
+        int64_t /*requestCount*/, int64_t /*resultErrorCount*/, bool /*deviceError*/,
+        const std::vector<hardware::CameraStreamStats>& /*streamStats*/) {
     if (mRemoteCallback.get() != nullptr) {
         mRemoteCallback->onDeviceIdle();
     }
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index 03621c8..839c435 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -86,7 +86,8 @@
     // NotificationListener API
     void notifyError(int32_t errorCode, const CaptureResultExtras& resultExtras) override;
     void notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) override;
-    void notifyIdle() override;
+    void notifyIdle(int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+            const std::vector<hardware::CameraStreamStats>& streamStats) override;
     void notifyAutoFocus(uint8_t newState, int triggerId) override;
     void notifyAutoExposure(uint8_t newState, int triggerId) override;
     void notifyAutoWhitebalance(uint8_t newState, int triggerId) override;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 609698c..6fd8d45 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -27,12 +27,15 @@
 #include <gui/Surface.h>
 #include <gui/Surface.h>
 
+#include <camera/CameraSessionStats.h>
+
 #include "common/Camera2ClientBase.h"
 
 #include "api2/CameraDeviceClient.h"
 
 #include "device3/Camera3Device.h"
 #include "utils/CameraThreadState.h"
+#include "utils/CameraServiceProxyWrapper.h"
 
 namespace android {
 using namespace camera2;
@@ -194,7 +197,7 @@
 
     CameraService::BasicClient::disconnect();
 
-    ALOGV("Camera %s: Shut down complete complete", TClientBase::mCameraIdStr.string());
+    ALOGV("Camera %s: Shut down complete", TClientBase::mCameraIdStr.string());
 
     return res;
 }
@@ -245,13 +248,12 @@
 }
 
 template <typename TClientBase>
-void Camera2ClientBase<TClientBase>::notifyIdle() {
+void Camera2ClientBase<TClientBase>::notifyIdle(
+        int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+        const std::vector<hardware::CameraStreamStats>& streamStats) {
     if (mDeviceActive) {
-        getCameraService()->updateProxyDeviceState(
-            hardware::ICameraServiceProxy::CAMERA_STATE_IDLE, TClientBase::mCameraIdStr,
-            TClientBase::mCameraFacing, TClientBase::mClientPackageName,
-            ((mApi1CameraId < 0) ? hardware::ICameraServiceProxy::CAMERA_API_LEVEL_2 :
-             hardware::ICameraServiceProxy::CAMERA_API_LEVEL_1));
+        CameraServiceProxyWrapper::logIdle(TClientBase::mCameraIdStr,
+                requestCount, resultErrorCount, deviceError, streamStats);
     }
     mDeviceActive = false;
 
@@ -265,11 +267,7 @@
     (void)timestamp;
 
     if (!mDeviceActive) {
-        getCameraService()->updateProxyDeviceState(
-            hardware::ICameraServiceProxy::CAMERA_STATE_ACTIVE, TClientBase::mCameraIdStr,
-            TClientBase::mCameraFacing, TClientBase::mClientPackageName,
-            ((mApi1CameraId < 0) ? hardware::ICameraServiceProxy::CAMERA_API_LEVEL_2 :
-             hardware::ICameraServiceProxy::CAMERA_API_LEVEL_1));
+        CameraServiceProxyWrapper::logActive(TClientBase::mCameraIdStr);
     }
     mDeviceActive = true;
 
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index d7506af..1ce4393 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -66,7 +66,9 @@
 
     virtual void          notifyError(int32_t errorCode,
                                       const CaptureResultExtras& resultExtras);
-    virtual void          notifyIdle();
+    virtual void          notifyIdle(int64_t requestCount, int64_t resultErrorCount,
+                                     bool deviceError,
+                                     const std::vector<hardware::CameraStreamStats>& streamStats);
     virtual void          notifyShutter(const CaptureResultExtras& resultExtras,
                                         nsecs_t timestamp);
     virtual void          notifyAutoFocus(uint8_t newState, int triggerId);
diff --git a/services/camera/libcameraservice/common/CameraOfflineSessionBase.h b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
index 1f835a9..e02e146 100644
--- a/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
+++ b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
@@ -17,11 +17,14 @@
 #ifndef ANDROID_SERVERS_CAMERA_CAMERAOFFLINESESSIONBASE_H
 #define ANDROID_SERVERS_CAMERA_CAMERAOFFLINESESSIONBASE_H
 
+#include <vector>
+
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 #include <utils/Timers.h>
 
 #include "camera/CaptureResult.h"
+#include "camera/CameraSessionStats.h"
 #include "FrameProducer.h"
 
 namespace android {
@@ -39,7 +42,8 @@
                              const CaptureResultExtras &resultExtras) = 0;
 
     // Required only for API2
-    virtual void notifyIdle() = 0;
+    virtual void notifyIdle(int64_t requestCount, int64_t resultError, bool deviceError,
+            const std::vector<hardware::CameraStreamStats>& streamStats) = 0;
     virtual void notifyShutter(const CaptureResultExtras &resultExtras,
             nsecs_t timestamp) = 0;
     virtual void notifyPrepared(int streamId) = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index d27f11f..50ef953 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -61,6 +61,7 @@
 #include "CameraService.h"
 #include "utils/CameraThreadState.h"
 #include "utils/TraceHFR.h"
+#include "utils/CameraServiceProxyWrapper.h"
 
 #include <algorithm>
 #include <tuple>
@@ -867,7 +868,7 @@
 status_t Camera3Device::convertMetadataListToRequestListLocked(
         const List<const PhysicalCameraSettingsList> &metadataList,
         const std::list<const SurfaceMap> &surfaceMaps,
-        bool repeating,
+        bool repeating, nsecs_t requestTimeNs,
         RequestList *requestList) {
     if (requestList == NULL) {
         CLOGE("requestList cannot be NULL.");
@@ -886,6 +887,7 @@
         }
 
         newRequest->mRepeating = repeating;
+        newRequest->mRequestTimeNs = requestTimeNs;
 
         // Setup burst Id and request Id
         newRequest->mResultExtras.burstId = burstId++;
@@ -953,6 +955,8 @@
         /*out*/
         int64_t *lastFrameNumber) {
     ATRACE_CALL();
+    nsecs_t requestTimeNs = systemTime();
+
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
 
@@ -965,7 +969,7 @@
     RequestList requestList;
 
     res = convertMetadataListToRequestListLocked(requests, surfaceMaps,
-            repeating, /*out*/&requestList);
+            repeating, requestTimeNs, /*out*/&requestList);
     if (res != OK) {
         // error logged by previous call
         return res;
@@ -997,7 +1001,7 @@
         const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
         requestStreamBuffers_cb _hidl_cb) {
     RequestBufferStates states {
-        mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams,
+        mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
         *this, *mInterface, *this};
     camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
     return hardware::Void();
@@ -1006,7 +1010,7 @@
 hardware::Return<void> Camera3Device::returnStreamBuffers(
         const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
     ReturnBufferStates states {
-        mId, mUseHalBufManager, mOutputStreams, *mInterface};
+        mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, *mInterface};
     camera3::returnStreamBuffers(states, buffers);
     return hardware::Void();
 }
@@ -1054,7 +1058,8 @@
         mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
         mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
         mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
-        mTagMonitor, mInputStream, mOutputStreams, listener, *this, *this, *mInterface
+        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+        *mInterface
     };
 
     for (const auto& result : results) {
@@ -1112,7 +1117,8 @@
         mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
         mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
         mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
-        mTagMonitor, mInputStream, mOutputStreams, listener, *this, *this, *mInterface
+        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+        *mInterface
     };
 
     for (const auto& result : results) {
@@ -1152,7 +1158,8 @@
         mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
         mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
         mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
-        mTagMonitor, mInputStream, mOutputStreams, listener, *this, *this, *mInterface
+        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+        *mInterface
     };
     for (const auto& msg : msgs) {
         camera3::notify(states, msg);
@@ -1455,6 +1462,8 @@
         return res;
     }
 
+    mSessionStatsBuilder.addStream(mNextStreamId);
+
     *id = mNextStreamId++;
     mNeedConfig = true;
 
@@ -1578,6 +1587,7 @@
             CLOGE("Stream %d does not exist", id);
             return BAD_VALUE;
         }
+        mSessionStatsBuilder.removeStream(id);
     }
 
     // Delete output stream or the output part of a bi-directional stream.
@@ -2010,6 +2020,9 @@
         }
 
         mRequestThread->clear(/*out*/frameNumber);
+
+        // Stop session and stream counter
+        mSessionStatsBuilder.stopCounter();
     }
 
     return mRequestThread->flush();
@@ -2087,6 +2100,9 @@
 
 void Camera3Device::notifyStatus(bool idle) {
     ATRACE_CALL();
+    std::vector<int> streamIds;
+    std::vector<hardware::CameraStreamStats> streamStats;
+
     {
         // Need mLock to safely update state and synchronize to current
         // state of methods in flight.
@@ -2104,6 +2120,24 @@
         // Skip notifying listener if we're doing some user-transparent
         // state changes
         if (mPauseStateNotify) return;
+
+        // Populate stream statistics in case of Idle
+        if (idle) {
+            for (size_t i = 0; i < mOutputStreams.size(); i++) {
+                auto stream = mOutputStreams[i];
+                if (stream.get() == nullptr) continue;
+                streamIds.push_back(stream->getId());
+                Camera3Stream* camera3Stream = Camera3Stream::cast(stream->asHalStream());
+                int64_t usage = 0LL;
+                if (camera3Stream != nullptr) {
+                    usage = camera3Stream->getUsage();
+                }
+                streamStats.emplace_back(stream->getWidth(), stream->getHeight(),
+                    stream->getFormat(), stream->getDataSpace(), usage,
+                    stream->getMaxHalBuffers(),
+                    stream->getMaxTotalBuffers() - stream->getMaxHalBuffers());
+            }
+        }
     }
 
     sp<NotificationListener> listener;
@@ -2112,7 +2146,22 @@
         listener = mListener.promote();
     }
     if (idle && listener != NULL) {
-        listener->notifyIdle();
+        // Get session stats from the builder, and notify the listener.
+        int64_t requestCount, resultErrorCount;
+        bool deviceError;
+        std::map<int, StreamStats> streamStatsMap;
+        mSessionStatsBuilder.buildAndReset(&requestCount, &resultErrorCount,
+                &deviceError, &streamStatsMap);
+        for (size_t i = 0; i < streamIds.size(); i++) {
+            int streamId = streamIds[i];
+            auto stats = streamStatsMap.find(streamId);
+            if (stats != streamStatsMap.end()) {
+                streamStats[i].mRequestCount = stats->second.mRequestedFrameCount;
+                streamStats[i].mErrorCount = stats->second.mDroppedFrameCount;
+                streamStats[i].mStartLatencyMs = stats->second.mStartLatencyMs;
+            }
+        }
+        listener->notifyIdle(requestCount, resultErrorCount, deviceError, streamStats);
     }
 }
 
@@ -2222,6 +2271,12 @@
         ALOGE("%s: Stream %d is not found.", __FUNCTION__, streamId);
         return BAD_VALUE;
     }
+
+    if (dropping) {
+        mSessionStatsBuilder.stopCounter(streamId);
+    } else {
+        mSessionStatsBuilder.startCounter(streamId);
+    }
     return stream->dropBuffers(dropping);
 }
 
@@ -2376,6 +2431,8 @@
     ATRACE_CALL();
     bool ret = false;
 
+    nsecs_t startTime = systemTime();
+
     Mutex::Autolock il(mInterfaceLock);
     nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
 
@@ -2423,6 +2480,9 @@
         ALOGE("%s: Failed to pause streaming: %d", __FUNCTION__, rc);
     }
 
+    CameraServiceProxyWrapper::logStreamConfigured(mId, mOperatingMode, true /*internalReconfig*/,
+        ns2ms(systemTime() - startTime));
+
     if (markClientActive) {
         mStatusTracker->markComponentActive(clientStatusId);
     }
@@ -2776,6 +2836,7 @@
     if (listener != NULL) {
         listener->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
                 CaptureResultExtras());
+        mSessionStatsBuilder.onDeviceError();
     }
 
     // Save stack trace. View by dumping it later.
@@ -2792,14 +2853,14 @@
         bool hasAppCallback, nsecs_t maxExpectedDuration,
         std::set<String8>& physicalCameraIds, bool isStillCapture,
         bool isZslCapture, bool rotateAndCropAuto, const std::set<std::string>& cameraIdsWithZoom,
-        const SurfaceMap& outputSurfaces) {
+        const SurfaceMap& outputSurfaces, nsecs_t requestTimeNs) {
     ATRACE_CALL();
     std::lock_guard<std::mutex> l(mInFlightLock);
 
     ssize_t res;
     res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras, hasInput,
             hasAppCallback, maxExpectedDuration, physicalCameraIds, isStillCapture, isZslCapture,
-            rotateAndCropAuto, cameraIdsWithZoom, outputSurfaces));
+            rotateAndCropAuto, cameraIdsWithZoom, requestTimeNs, outputSurfaces));
     if (res < 0) return res;
 
     if (mInFlightMap.size() == 1) {
@@ -2869,7 +2930,7 @@
 
     FlushInflightReqStates states {
         mId, mInFlightLock, mInFlightMap, mUseHalBufManager,
-        listener, *this, *mInterface, *this};
+        listener, *this, *mInterface, *this, mSessionStatsBuilder};
 
     camera3::flushInflightRequests(states);
 }
@@ -3778,6 +3839,7 @@
         mInterface(interface),
         mListener(nullptr),
         mId(getId(parent)),
+        mFirstRepeating(false),
         mReconfigured(false),
         mDoPause(false),
         mPaused(true),
@@ -3908,6 +3970,7 @@
         *lastFrameNumber = mRepeatingLastFrameNumber;
     }
     mRepeatingRequests.clear();
+    mFirstRepeating = true;
     mRepeatingRequests.insert(mRepeatingRequests.begin(),
             requests.begin(), requests.end());
 
@@ -4697,7 +4760,7 @@
                 requestedPhysicalCameras, isStillCapture, isZslCapture,
                 captureRequest->mRotateAndCropAuto, mPrevCameraIdsWithZoom,
                 (mUseHalBufManager) ? uniqueSurfaceIdMap :
-                                      SurfaceMap{});
+                                      SurfaceMap{}, captureRequest->mRequestTimeNs);
         ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
                ", burstId = %" PRId32 ".",
                 __FUNCTION__,
@@ -5019,6 +5082,17 @@
             // list. Guarantees a complete in-sequence set of captures to
             // application.
             const RequestList &requests = mRepeatingRequests;
+            if (mFirstRepeating) {
+                mFirstRepeating = false;
+            } else {
+                for (auto& request : requests) {
+                    // For repeating requests, override timestamp request using
+                    // the time a request is inserted into the request queue,
+                    // because the original repeating request will have an old
+                    // fixed timestamp.
+                    request->mRequestTimeNs = systemTime();
+                }
+            }
             RequestList::const_iterator firstRequest =
                     requests.begin();
             nextRequest = *firstRequest;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index c579071..de7df81 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -471,6 +471,8 @@
 
     camera3::StreamSet         mOutputStreams;
     sp<camera3::Camera3Stream> mInputStream;
+    SessionStatsBuilder        mSessionStatsBuilder;
+
     int                        mNextStreamId;
     bool                       mNeedConfig;
 
@@ -520,6 +522,8 @@
         // Whether this capture request has its zoom ratio set to 1.0x before
         // the framework overrides it for camera HAL consumption.
         bool                                mZoomRatioIs1x;
+        // The systemTime timestamp when the request is created.
+        nsecs_t                             mRequestTimeNs;
 
 
         // Whether this capture request's distortion correction update has
@@ -538,7 +542,7 @@
     status_t convertMetadataListToRequestListLocked(
             const List<const PhysicalCameraSettingsList> &metadataList,
             const std::list<const SurfaceMap> &surfaceMaps,
-            bool repeating,
+            bool repeating, nsecs_t requestTimeNs,
             /*out*/
             RequestList *requestList);
 
@@ -961,6 +965,7 @@
         Condition          mRequestSubmittedSignal;
         RequestList        mRequestQueue;
         RequestList        mRepeatingRequests;
+        bool               mFirstRepeating;
         // The next batch of requests being prepped for submission to the HAL, no longer
         // on the request queue. Read-only even with mRequestLock held, outside
         // of threadLoop
@@ -1035,7 +1040,8 @@
             int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
             bool callback, nsecs_t maxExpectedDuration, std::set<String8>& physicalCameraIds,
             bool isStillCapture, bool isZslCapture, bool rotateAndCropAuto,
-            const std::set<std::string>& cameraIdsWithZoom, const SurfaceMap& outputSurfaces);
+            const std::set<std::string>& cameraIdsWithZoom, const SurfaceMap& outputSurfaces,
+            nsecs_t requestTimeNs);
 
     /**
      * Tracking for idle detection
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index 448379c..ca62239 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -48,6 +48,7 @@
 
     virtual void     dump(int fd, const Vector<String16> &args) const;
 
+    int              getMaxTotalBuffers() const { return mTotalBufferCount; }
   protected:
     size_t            mTotalBufferCount;
     // sum of input and output buffers that are currently acquired by HAL
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
index 95f9633..a7e64ce 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
@@ -176,7 +176,7 @@
 
     FlushInflightReqStates states {
         mId, mOfflineReqsLock, mOfflineReqs, mUseHalBufManager,
-        listener, *this, mBufferRecords, *this};
+        listener, *this, mBufferRecords, *this, mSessionStatsBuilder};
 
     camera3::flushInflightRequests(states);
 
@@ -260,7 +260,8 @@
         mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
         mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
         mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
-        mTagMonitor, mInputStream, mOutputStreams, listener, *this, *this, mBufferRecords
+        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+        mBufferRecords
     };
 
     std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -299,7 +300,8 @@
         mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
         mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
         mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
-        mTagMonitor, mInputStream, mOutputStreams, listener, *this, *this, mBufferRecords
+        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+        mBufferRecords
     };
 
     std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -333,7 +335,8 @@
         mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
         mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
         mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
-        mTagMonitor, mInputStream, mOutputStreams, listener, *this, *this, mBufferRecords
+        mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+        mBufferRecords
     };
     for (const auto& msg : msgs) {
         camera3::notify(states, msg);
@@ -353,7 +356,7 @@
     }
 
     RequestBufferStates states {
-        mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams,
+        mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
         *this, mBufferRecords, *this};
     camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
     return hardware::Void();
@@ -370,7 +373,7 @@
     }
 
     ReturnBufferStates states {
-        mId, mUseHalBufManager, mOutputStreams, mBufferRecords};
+        mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, mBufferRecords};
     camera3::returnStreamBuffers(states, buffers);
     return hardware::Void();
 }
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.h b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
index ee9ed25..5581964 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.h
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
@@ -208,6 +208,7 @@
     sp<camera3::Camera3Stream> mInputStream;
     camera3::StreamSet mOutputStreams;
     camera3::BufferRecords mBufferRecords;
+    SessionStatsBuilder mSessionStatsBuilder;
 
     std::mutex mOfflineReqsLock;
     camera3::InFlightRequestMap mOfflineReqs;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 90f6216..f88b062 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -423,6 +423,7 @@
     InFlightRequestMap& inflightMap = states.inflightMap;
     const InFlightRequest &request = inflightMap.valueAt(idx);
     const uint32_t frameNumber = inflightMap.keyAt(idx);
+    SessionStatsBuilder& sessionStatsBuilder = states.sessionStatsBuilder;
 
     nsecs_t sensorTimestamp = request.sensorTimestamp;
     nsecs_t shutterTimestamp = request.shutterTimestamp;
@@ -459,7 +460,9 @@
         returnOutputBuffers(
             states.useHalBufManager, states.listener,
             request.pendingOutputBuffers.array(),
-            request.pendingOutputBuffers.size(), 0, /*timestampIncreasing*/true,
+            request.pendingOutputBuffers.size(), 0,
+            /*requested*/true, request.requestTimeNs, states.sessionStatsBuilder,
+            /*timestampIncreasing*/true,
             request.outputSurfaces, request.resultExtras,
             request.errorBufStrategy);
 
@@ -472,6 +475,8 @@
             states.lastCompletedRegularFrameNumber = frameNumber;
         }
 
+        sessionStatsBuilder.incResultCounter(request.skipResultMetadata);
+
         removeInFlightMapEntryLocked(states, idx);
         ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
     }
@@ -628,7 +633,7 @@
         if (shutterTimestamp != 0) {
             returnAndRemovePendingOutputBuffers(
                 states.useHalBufManager, states.listener,
-                request);
+                request, states.sessionStatsBuilder);
         }
 
         if (result->result != NULL && !isPartialResult) {
@@ -825,7 +830,8 @@
         bool useHalBufManager,
         sp<NotificationListener> listener,
         const camera3_stream_buffer_t *outputBuffers, size_t numBuffers,
-        nsecs_t timestamp, bool timestampIncreasing,
+        nsecs_t timestamp, bool requested, nsecs_t requestTimeNs,
+        SessionStatsBuilder& sessionStatsBuilder, bool timestampIncreasing,
         const SurfaceMap& outputSurfaces,
         const CaptureResultExtras &inResultExtras,
         ERROR_BUF_STRATEGY errorBufStrategy) {
@@ -853,6 +859,10 @@
                 // has not got a output buffer handle filled yet. This is though illegal if HAL
                 // buffer management API is not being used.
                 ALOGE("%s: cannot return a null buffer!", __FUNCTION__);
+            } else {
+                if (requested) {
+                    sessionStatsBuilder.incCounter(streamId, /*dropped*/true, 0);
+                }
             }
             continue;
         }
@@ -876,10 +886,22 @@
         }
         // Note: stream may be deallocated at this point, if this buffer was
         // the last reference to it.
+        bool dropped = false;
         if (res == NO_INIT || res == DEAD_OBJECT) {
             ALOGV("Can't return buffer to its stream: %s (%d)", strerror(-res), res);
+            sessionStatsBuilder.stopCounter(streamId);
         } else if (res != OK) {
             ALOGE("Can't return buffer to its stream: %s (%d)", strerror(-res), res);
+            dropped = true;
+        } else {
+            if (outputBuffers[i].status == CAMERA3_BUFFER_STATUS_ERROR || timestamp == 0) {
+                dropped = true;
+            }
+        }
+        if (requested) {
+            nsecs_t bufferTimeNs = systemTime();
+            int32_t captureLatencyMs = ns2ms(bufferTimeNs - requestTimeNs);
+            sessionStatsBuilder.incCounter(streamId, dropped, captureLatencyMs);
         }
 
         // Long processing consumers can cause returnBuffer timeout for shared stream
@@ -889,7 +911,8 @@
             // cancel the buffer
             camera3_stream_buffer_t sb = outputBuffers[i];
             sb.status = CAMERA3_BUFFER_STATUS_ERROR;
-            stream->returnBuffer(sb, /*timestamp*/0, timestampIncreasing, std::vector<size_t> (),
+            stream->returnBuffer(sb, /*timestamp*/0,
+                    timestampIncreasing, std::vector<size_t> (),
                     inResultExtras.frameNumber);
 
             if (listener != nullptr) {
@@ -904,12 +927,14 @@
 }
 
 void returnAndRemovePendingOutputBuffers(bool useHalBufManager,
-        sp<NotificationListener> listener, InFlightRequest& request) {
+        sp<NotificationListener> listener, InFlightRequest& request,
+        SessionStatsBuilder& sessionStatsBuilder) {
     bool timestampIncreasing = !(request.zslCapture || request.hasInputBuffer);
     returnOutputBuffers(useHalBufManager, listener,
             request.pendingOutputBuffers.array(),
             request.pendingOutputBuffers.size(),
-            request.shutterTimestamp, timestampIncreasing,
+            request.shutterTimestamp, /*requested*/true,
+            request.requestTimeNs, sessionStatsBuilder, timestampIncreasing,
             request.outputSurfaces, request.resultExtras,
             request.errorBufStrategy);
 
@@ -992,7 +1017,7 @@
                     r.rotateAndCropAuto, r.cameraIdsWithZoom, r.physicalMetadatas);
             }
             returnAndRemovePendingOutputBuffers(
-                    states.useHalBufManager, states.listener, r);
+                    states.useHalBufManager, states.listener, r, states.sessionStatsBuilder);
 
             removeInFlightRequestIfReadyLocked(states, idx);
         }
@@ -1281,6 +1306,7 @@
                     ALOGV("%s: Can't get output buffer for stream %d: %s (%d)",
                             __FUNCTION__, streamId, strerror(-res), res);
                     bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
+                    states.sessionStatsBuilder.stopCounter(streamId);
                 } else {
                     ALOGE("%s: Can't get output buffer for stream %d: %s (%d)",
                             __FUNCTION__, streamId, strerror(-res), res);
@@ -1346,7 +1372,8 @@
                 sb.status = CAMERA3_BUFFER_STATUS_ERROR;
             }
             returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
-                    streamBuffers.data(), numAllocatedBuffers, 0);
+                    streamBuffers.data(), numAllocatedBuffers, 0, /*requested*/false,
+                    /*requestTimeNs*/0, states.sessionStatsBuilder);
         }
     }
 
@@ -1403,22 +1430,23 @@
         }
         streamBuffer.stream = stream->asHalStream();
         returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
-                &streamBuffer, /*size*/1, /*timestamp*/ 0);
+                &streamBuffer, /*size*/1, /*timestamp*/ 0, /*requested*/false,
+                /*requestTimeNs*/0, states.sessionStatsBuilder);
     }
 }
 
 void flushInflightRequests(FlushInflightReqStates& states) {
     ATRACE_CALL();
-    { // First return buffers cached in mInFlightMap
+    { // First return buffers cached in inFlightMap
         std::lock_guard<std::mutex> l(states.inflightLock);
         for (size_t idx = 0; idx < states.inflightMap.size(); idx++) {
             const InFlightRequest &request = states.inflightMap.valueAt(idx);
             returnOutputBuffers(
                 states.useHalBufManager, states.listener,
                 request.pendingOutputBuffers.array(),
-                request.pendingOutputBuffers.size(), 0,
-                /*timestampIncreasing*/true, request.outputSurfaces,
-                request.resultExtras, request.errorBufStrategy);
+                request.pendingOutputBuffers.size(), 0, /*requested*/true,
+                request.requestTimeNs, states.sessionStatsBuilder, /*timestampIncreasing*/true,
+                request.outputSurfaces, request.resultExtras, request.errorBufStrategy);
             ALOGW("%s: Frame %d |  Timestamp: %" PRId64 ", metadata"
                     " arrived: %s, buffers left: %d.\n", __FUNCTION__,
                     states.inflightMap.keyAt(idx), request.shutterTimestamp,
@@ -1490,7 +1518,8 @@
                 switch (halStream->stream_type) {
                     case CAMERA3_STREAM_OUTPUT:
                         res = stream->returnBuffer(streamBuffer, /*timestamp*/ 0,
-                                /*timestampIncreasing*/true, std::vector<size_t> (), frameNumber);
+                                /*timestampIncreasing*/true,
+                                std::vector<size_t> (), frameNumber);
                         if (res != OK) {
                             ALOGE("%s: Can't return output buffer for frame %d to"
                                   " stream %d: %s (%d)",  __FUNCTION__,
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index 3ebbc17..45c8a43 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -33,6 +33,7 @@
 #include "device3/InFlightRequest.h"
 #include "device3/Camera3Stream.h"
 #include "device3/Camera3OutputStreamInterface.h"
+#include "utils/SessionStatsBuilder.h"
 #include "utils/TagMonitor.h"
 
 namespace android {
@@ -51,7 +52,8 @@
             bool useHalBufManager,
             sp<NotificationListener> listener, // Only needed when outputSurfaces is not empty
             const camera3_stream_buffer_t *outputBuffers,
-            size_t numBuffers, nsecs_t timestamp, bool timestampIncreasing = true,
+            size_t numBuffers, nsecs_t timestamp, bool requested, nsecs_t requestTimeNs,
+            SessionStatsBuilder& sessionStatsBuilder, bool timestampIncreasing = true,
             // The following arguments are only meant for surface sharing use case
             const SurfaceMap& outputSurfaces = SurfaceMap{},
             // Used to send buffer error callback when failing to return buffer
@@ -64,7 +66,7 @@
     void returnAndRemovePendingOutputBuffers(
             bool useHalBufManager,
             sp<NotificationListener> listener, // Only needed when outputSurfaces is not empty
-            InFlightRequest& request);
+            InFlightRequest& request, SessionStatsBuilder& sessionStatsBuilder);
 
     // Camera3Device/Camera3OfflineSession internal states used in notify/processCaptureResult
     // callbacks
@@ -98,6 +100,7 @@
         TagMonitor& tagMonitor;
         sp<Camera3Stream> inputStream;
         StreamSet& outputStreams;
+        SessionStatsBuilder& sessionStatsBuilder;
         sp<NotificationListener> listener;
         SetErrorInterface& setErrIntf;
         InflightRequestUpdateInterface& inflightIntf;
@@ -121,6 +124,7 @@
         std::mutex& reqBufferLock; // lock to serialize request buffer calls
         const bool useHalBufManager;
         StreamSet& outputStreams;
+        SessionStatsBuilder& sessionStatsBuilder;
         SetErrorInterface& setErrIntf;
         BufferRecordsInterface& bufferRecordsIntf;
         RequestBufferInterface& reqBufferIntf;
@@ -134,6 +138,7 @@
         const String8& cameraId;
         const bool useHalBufManager;
         StreamSet& outputStreams;
+        SessionStatsBuilder& sessionStatsBuilder;
         BufferRecordsInterface& bufferRecordsIntf;
     };
 
@@ -149,6 +154,7 @@
         InflightRequestUpdateInterface& inflightIntf;
         BufferRecordsInterface& bufferRecordsIntf;
         FlushBufferInterface& flushBufferIntf;
+        SessionStatsBuilder& sessionStatsBuilder;
     };
 
     void flushInflightRequests(FlushInflightReqStates& states);
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index f208561..9a8f6fe 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -152,6 +152,10 @@
     return mPhysicalCameraId;
 }
 
+int Camera3Stream::getMaxHalBuffers() const {
+    return camera3_stream::max_buffers;
+}
+
 void Camera3Stream::setOfflineProcessingSupport(bool support) {
     mSupportOfflineProcessing = support;
 }
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index d768d3d..3654f89 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -165,6 +165,7 @@
     void              setDataSpaceOverride(bool dataSpaceOverriden);
     bool              isDataSpaceOverridden() const;
     android_dataspace getOriginalDataSpace() const;
+    int               getMaxHalBuffers() const;
     const String8&    physicalCameraId() const;
 
     void              setOfflineProcessingSupport(bool) override;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 667e3bb..a053262 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -99,6 +99,8 @@
     virtual void setDataSpaceOverride(bool dataSpaceOverriden) = 0;
     virtual bool isDataSpaceOverridden() const = 0;
     virtual android_dataspace getOriginalDataSpace() const = 0;
+    virtual int getMaxHalBuffers() const = 0;
+    virtual int getMaxTotalBuffers() const = 0;
 
     /**
      * Offline processing
diff --git a/services/camera/libcameraservice/device3/InFlightRequest.h b/services/camera/libcameraservice/device3/InFlightRequest.h
index da4f228..c7b7475 100644
--- a/services/camera/libcameraservice/device3/InFlightRequest.h
+++ b/services/camera/libcameraservice/device3/InFlightRequest.h
@@ -115,6 +115,9 @@
     // Requested camera ids (both logical and physical) with zoomRatio != 1.0f
     std::set<std::string> cameraIdsWithZoom;
 
+    // Time of capture request (from systemTime) in Ns
+    nsecs_t requestTimeNs;
+
     // What shared surfaces an output should go to
     SurfaceMap outputSurfaces;
 
@@ -135,14 +138,15 @@
             errorBufStrategy(ERROR_BUF_CACHE),
             stillCapture(false),
             zslCapture(false),
-            rotateAndCropAuto(false) {
+            rotateAndCropAuto(false),
+            requestTimeNs(0) {
     }
 
     InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
             bool hasAppCallback, nsecs_t maxDuration,
             const std::set<String8>& physicalCameraIdSet, bool isStillCapture,
             bool isZslCapture, bool rotateAndCropAuto, const std::set<std::string>& idsWithZoom,
-            const SurfaceMap& outSurfaces = SurfaceMap{}) :
+            nsecs_t requestNs, const SurfaceMap& outSurfaces = SurfaceMap{}) :
             shutterTimestamp(0),
             sensorTimestamp(0),
             requestStatus(OK),
@@ -159,6 +163,7 @@
             zslCapture(isZslCapture),
             rotateAndCropAuto(rotateAndCropAuto),
             cameraIdsWithZoom(idsWithZoom),
+            requestTimeNs(requestNs),
             outputSurfaces(outSurfaces) {
     }
 };
diff --git a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
index bf89ca5..2509e6c 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
@@ -28,7 +28,7 @@
 namespace frameworks {
 namespace cameraservice {
 namespace device {
-namespace V2_0 {
+namespace V2_1 {
 namespace implementation {
 
 using hardware::cameraservice::utils::conversion::convertToHidl;
@@ -115,7 +115,7 @@
         // is guaranteed to be called serially by the client if it decides to
         // use fmq.
         if (e.settings.getDiscriminator() ==
-            FmqSizeOrMetadata::hidl_discriminator::fmqMetadataSize) {
+            V2_0::FmqSizeOrMetadata::hidl_discriminator::fmqMetadataSize) {
             /**
              * Get settings from the fmq.
              */
@@ -196,6 +196,12 @@
 
 Return<HStatus> HidlCameraDeviceUser::endConfigure(StreamConfigurationMode operatingMode,
                                                    const hidl_vec<uint8_t>& sessionParams) {
+    return endConfigure_2_1(operatingMode, sessionParams, systemTime());
+}
+
+Return<HStatus> HidlCameraDeviceUser::endConfigure_2_1(StreamConfigurationMode operatingMode,
+                                                   const hidl_vec<uint8_t>& sessionParams,
+                                                   nsecs_t startTimeNs) {
     android::CameraMetadata cameraMetadata;
     if (!convertFromHidl(sessionParams, &cameraMetadata)) {
         return HStatus::ILLEGAL_ARGUMENT;
@@ -203,7 +209,8 @@
 
     std::vector<int> offlineStreamIds;
     binder::Status ret = mDeviceRemote->endConfigure(convertFromHidl(operatingMode),
-                                                     cameraMetadata, &offlineStreamIds);
+                                                     cameraMetadata, ns2ms(startTimeNs),
+                                                     &offlineStreamIds);
     return B2HStatus(ret);
 }
 
diff --git a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.h b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.h
index c3a80fe..0e2ab3d 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.h
+++ b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.h
@@ -24,6 +24,7 @@
 #include <android/frameworks/cameraservice/common/2.0/types.h>
 #include <android/frameworks/cameraservice/service/2.0/types.h>
 #include <android/frameworks/cameraservice/device/2.0/ICameraDeviceUser.h>
+#include <android/frameworks/cameraservice/device/2.1/ICameraDeviceUser.h>
 #include <android/frameworks/cameraservice/device/2.0/types.h>
 #include <android/hardware/camera2/ICameraDeviceCallbacks.h>
 #include <fmq/MessageQueue.h>
@@ -36,7 +37,7 @@
 namespace frameworks {
 namespace cameraservice {
 namespace device {
-namespace V2_0 {
+namespace V2_1 {
 namespace implementation {
 
 using frameworks::cameraservice::device::V2_0::StreamConfigurationMode;
@@ -50,7 +51,7 @@
 using CaptureRequestMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
 using TemplateId = frameworks::cameraservice::device::V2_0::TemplateId;
 
-using HCameraDeviceUser = device::V2_0::ICameraDeviceUser;
+using HCameraDeviceUser = device::V2_1::ICameraDeviceUser;
 using HCameraMetadata = cameraservice::service::V2_0::CameraMetadata;
 using HCaptureRequest = device::V2_0::CaptureRequest;
 using HSessionConfiguration = frameworks::cameraservice::device::V2_0::SessionConfiguration;
@@ -83,6 +84,10 @@
     virtual Return<HStatus> endConfigure(StreamConfigurationMode operatingMode,
                                          const hidl_vec<uint8_t>& sessionParams);
 
+    virtual Return<HStatus> endConfigure_2_1(StreamConfigurationMode operatingMode,
+                                         const hidl_vec<uint8_t>& sessionParams,
+                                         nsecs_t startTimeNs);
+
     virtual Return<HStatus> deleteStream(int32_t streamId) override;
 
     virtual Return<void> createStream(const HOutputConfiguration& outputConfiguration,
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 9ea9526..aa1e95a 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -38,7 +38,7 @@
 using hardware::Void;
 
 using device::V2_0::implementation::H2BCameraDeviceCallbacks;
-using device::V2_0::implementation::HidlCameraDeviceUser;
+using device::V2_1::implementation::HidlCameraDeviceUser;
 using service::V2_0::implementation::H2BCameraServiceListener;
 using HCameraMetadataType = frameworks::cameraservice::common::V2_0::CameraMetadataType;
 using HVendorTag = frameworks::cameraservice::common::V2_0::VendorTag;
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.h b/services/camera/libcameraservice/hidl/HidlCameraService.h
index 097f4c5..86a7cec 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.h
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.h
@@ -21,7 +21,7 @@
 #include <thread>
 
 #include <android/frameworks/cameraservice/common/2.0/types.h>
-#include <android/frameworks/cameraservice/service/2.1/ICameraService.h>
+#include <android/frameworks/cameraservice/service/2.2/ICameraService.h>
 #include <android/frameworks/cameraservice/service/2.0/types.h>
 #include <android/frameworks/cameraservice/device/2.0/types.h>
 
@@ -42,7 +42,7 @@
 
 using HCameraDeviceCallback = frameworks::cameraservice::device::V2_0::ICameraDeviceCallback;
 using HCameraMetadata = frameworks::cameraservice::service::V2_0::CameraMetadata;
-using HCameraService = frameworks::cameraservice::service::V2_1::ICameraService;
+using HCameraService = frameworks::cameraservice::service::V2_2::ICameraService;
 using HCameraServiceListener = frameworks::cameraservice::service::V2_0::ICameraServiceListener;
 using HCameraServiceListener2_1 = frameworks::cameraservice::service::V2_1::ICameraServiceListener;
 using HStatus = frameworks::cameraservice::common::V2_0::Status;
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
new file mode 100644
index 0000000..0557fcc
--- /dev/null
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CameraServiceProxyWrapper"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <inttypes.h>
+#include <utils/Log.h>
+#include <binder/IServiceManager.h>
+
+#include "CameraServiceProxyWrapper.h"
+
+namespace android {
+
+using hardware::ICameraServiceProxy;
+using hardware::CameraSessionStats;
+
+Mutex CameraServiceProxyWrapper::sProxyMutex;
+sp<hardware::ICameraServiceProxy> CameraServiceProxyWrapper::sCameraServiceProxy;
+
+Mutex CameraServiceProxyWrapper::mLock;
+std::map<String8, std::shared_ptr<CameraServiceProxyWrapper::CameraSessionStatsWrapper>>
+        CameraServiceProxyWrapper::mSessionStatsMap;
+
+/**
+ * CameraSessionStatsWrapper functions
+ */
+
+void CameraServiceProxyWrapper::CameraSessionStatsWrapper::onOpen() {
+    Mutex::Autolock l(mLock);
+
+    updateProxyDeviceState(mSessionStats);
+}
+
+void CameraServiceProxyWrapper::CameraSessionStatsWrapper::onClose(int32_t latencyMs) {
+    Mutex::Autolock l(mLock);
+
+    mSessionStats.mNewCameraState = CameraSessionStats::CAMERA_STATE_CLOSED;
+    mSessionStats.mLatencyMs = latencyMs;
+    updateProxyDeviceState(mSessionStats);
+}
+
+void CameraServiceProxyWrapper::CameraSessionStatsWrapper::onStreamConfigured(
+        int operatingMode, bool internalReconfig, int32_t latencyMs) {
+    Mutex::Autolock l(mLock);
+
+    if (internalReconfig) {
+        mSessionStats.mInternalReconfigure++;
+    } else {
+        mSessionStats.mLatencyMs = latencyMs;
+        mSessionStats.mSessionType = operatingMode;
+    }
+}
+
+void CameraServiceProxyWrapper::CameraSessionStatsWrapper::onActive() {
+    Mutex::Autolock l(mLock);
+
+    mSessionStats.mNewCameraState = CameraSessionStats::CAMERA_STATE_ACTIVE;
+    updateProxyDeviceState(mSessionStats);
+
+    // Reset mCreationDuration to -1 to distinguish between 1st session
+    // after configuration, and all other sessions after configuration.
+    mSessionStats.mLatencyMs = -1;
+}
+
+void CameraServiceProxyWrapper::CameraSessionStatsWrapper::onIdle(
+        int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+        const std::vector<hardware::CameraStreamStats>& streamStats) {
+    Mutex::Autolock l(mLock);
+
+    mSessionStats.mNewCameraState = CameraSessionStats::CAMERA_STATE_IDLE;
+    mSessionStats.mRequestCount = requestCount;
+    mSessionStats.mResultErrorCount = resultErrorCount;
+    mSessionStats.mDeviceError = deviceError;
+    mSessionStats.mStreamStats = streamStats;
+    updateProxyDeviceState(mSessionStats);
+
+    mSessionStats.mInternalReconfigure = 0;
+    mSessionStats.mStreamStats.clear();
+}
+
+/**
+ * CameraServiceProxyWrapper functions
+ */
+
+sp<ICameraServiceProxy> CameraServiceProxyWrapper::getCameraServiceProxy() {
+#ifndef __BRILLO__
+    Mutex::Autolock al(sProxyMutex);
+    if (sCameraServiceProxy == nullptr) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        // Use checkService because cameraserver normally starts before the
+        // system server and the proxy service. So the long timeout that getService
+        // has before giving up is inappropriate.
+        sp<IBinder> binder = sm->checkService(String16("media.camera.proxy"));
+        if (binder != nullptr) {
+            sCameraServiceProxy = interface_cast<ICameraServiceProxy>(binder);
+        }
+    }
+#endif
+    return sCameraServiceProxy;
+}
+
+void CameraServiceProxyWrapper::pingCameraServiceProxy() {
+    sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
+    if (proxyBinder == nullptr) return;
+    proxyBinder->pingForUserUpdate();
+}
+
+void CameraServiceProxyWrapper::updateProxyDeviceState(const CameraSessionStats& sessionStats) {
+    sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
+    if (proxyBinder == nullptr) return;
+    proxyBinder->notifyCameraState(sessionStats);
+}
+
+void CameraServiceProxyWrapper::logStreamConfigured(const String8& id,
+        int operatingMode, bool internalConfig, int32_t latencyMs) {
+    std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
+    {
+        Mutex::Autolock l(mLock);
+        sessionStats = mSessionStatsMap[id];
+        if (sessionStats == nullptr) {
+            ALOGE("%s: SessionStatsMap should contain camera %s",
+                    __FUNCTION__, id.c_str());
+            return;
+        }
+    }
+
+    ALOGV("%s: id %s, operatingMode %d, internalConfig %d, latencyMs %d",
+            __FUNCTION__, id.c_str(), operatingMode, internalConfig, latencyMs);
+    sessionStats->onStreamConfigured(operatingMode, internalConfig, latencyMs);
+}
+
+void CameraServiceProxyWrapper::logActive(const String8& id) {
+    std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
+    {
+        Mutex::Autolock l(mLock);
+        sessionStats = mSessionStatsMap[id];
+        if (sessionStats == nullptr) {
+            ALOGE("%s: SessionStatsMap should contain camera %s when logActive is called",
+                    __FUNCTION__, id.c_str());
+            return;
+        }
+    }
+
+    ALOGV("%s: id %s", __FUNCTION__, id.c_str());
+    sessionStats->onActive();
+}
+
+void CameraServiceProxyWrapper::logIdle(const String8& id,
+        int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+        const std::vector<hardware::CameraStreamStats>& streamStats) {
+    std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
+    {
+        Mutex::Autolock l(mLock);
+        sessionStats = mSessionStatsMap[id];
+    }
+
+    if (sessionStats == nullptr) {
+        ALOGE("%s: SessionStatsMap should contain camera %s when logIdle is called",
+                __FUNCTION__, id.c_str());
+        return;
+    }
+
+    ALOGV("%s: id %s, requestCount %" PRId64 ", resultErrorCount %" PRId64 ", deviceError %d",
+            __FUNCTION__, id.c_str(), requestCount, resultErrorCount, deviceError);
+    for (size_t i = 0; i < streamStats.size(); i++) {
+        ALOGV("%s: streamStats[%zu]: w %d h %d, requestedCount %" PRId64 ", dropCount %"
+                PRId64 ", startTimeMs %d" ,
+                __FUNCTION__, i, streamStats[i].mWidth, streamStats[i].mHeight,
+                streamStats[i].mRequestCount, streamStats[i].mErrorCount,
+                streamStats[i].mStartLatencyMs);
+    }
+
+    sessionStats->onIdle(requestCount, resultErrorCount, deviceError, streamStats);
+}
+
+void CameraServiceProxyWrapper::logOpen(const String8& id, int facing,
+            const String16& clientPackageName, int effectiveApiLevel, bool isNdk,
+            int32_t latencyMs) {
+    std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
+    {
+        Mutex::Autolock l(mLock);
+        if (mSessionStatsMap.count(id) > 0) {
+            ALOGE("%s: SessionStatsMap shouldn't contain camera %s",
+                    __FUNCTION__, id.c_str());
+            return;
+        }
+
+        int apiLevel = CameraSessionStats::CAMERA_API_LEVEL_1;
+        if (effectiveApiLevel == 2) {
+            apiLevel = CameraSessionStats::CAMERA_API_LEVEL_2;
+        }
+
+        sessionStats = std::make_shared<CameraSessionStatsWrapper>(String16(id), facing,
+                CameraSessionStats::CAMERA_STATE_OPEN, clientPackageName,
+                apiLevel, isNdk, latencyMs);
+        mSessionStatsMap.emplace(id, sessionStats);
+        ALOGV("%s: Adding id %s", __FUNCTION__, id.c_str());
+    }
+
+    ALOGV("%s: id %s, facing %d, effectiveApiLevel %d, isNdk %d, latencyMs %d",
+            __FUNCTION__, id.c_str(), facing, effectiveApiLevel, isNdk, latencyMs);
+    sessionStats->onOpen();
+}
+
+void CameraServiceProxyWrapper::logClose(const String8& id, int32_t latencyMs) {
+    std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
+    {
+        Mutex::Autolock l(mLock);
+        if (mSessionStatsMap.count(id) == 0) {
+            ALOGE("%s: SessionStatsMap should contain camera %s before it's closed",
+                    __FUNCTION__, id.c_str());
+            return;
+        }
+
+        sessionStats = mSessionStatsMap[id];
+        if (sessionStats == nullptr) {
+            ALOGE("%s: SessionStatsMap should contain camera %s",
+                    __FUNCTION__, id.c_str());
+            return;
+        }
+        mSessionStatsMap.erase(id);
+        ALOGV("%s: Erasing id %s", __FUNCTION__, id.c_str());
+    }
+
+    ALOGV("%s: id %s, latencyMs %d", __FUNCTION__, id.c_str(), latencyMs);
+    sessionStats->onClose(latencyMs);
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
new file mode 100644
index 0000000..9525935
--- /dev/null
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 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_SERVERS_CAMERA_SERVICE_PROXY_WRAPPER_H_
+#define ANDROID_SERVERS_CAMERA_SERVICE_PROXY_WRAPPER_H_
+
+#include <android/hardware/ICameraServiceProxy.h>
+
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
+
+#include <camera/CameraSessionStats.h>
+
+namespace android {
+
+class CameraServiceProxyWrapper {
+private:
+    // Guard mCameraServiceProxy
+    static Mutex sProxyMutex;
+    // Cached interface to the camera service proxy in system service
+    static sp<hardware::ICameraServiceProxy> sCameraServiceProxy;
+
+    struct CameraSessionStatsWrapper {
+        hardware::CameraSessionStats mSessionStats;
+        Mutex mLock; // lock for per camera session stats
+
+        CameraSessionStatsWrapper(const String16& cameraId, int facing, int newCameraState,
+                const String16& clientName, int apiLevel, bool isNdk, int32_t latencyMs) :
+            mSessionStats(cameraId, facing, newCameraState, clientName, apiLevel, isNdk, latencyMs)
+            {}
+
+        void onOpen();
+        void onClose(int32_t latencyMs);
+        void onStreamConfigured(int operatingMode, bool internalReconfig, int32_t latencyMs);
+        void onActive();
+        void onIdle(int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+                const std::vector<hardware::CameraStreamStats>& streamStats);
+    };
+
+    // Lock for camera session stats map
+    static Mutex mLock;
+    // Map from camera id to the camera's session statistics
+    static std::map<String8, std::shared_ptr<CameraSessionStatsWrapper>> mSessionStatsMap;
+
+    /**
+     * Update the session stats of a given camera device (open/close/active/idle) with
+     * the camera proxy service in the system service
+     */
+    static void updateProxyDeviceState(
+            const hardware::CameraSessionStats& sessionStats);
+
+    static sp<hardware::ICameraServiceProxy> getCameraServiceProxy();
+
+public:
+    // Open
+    static void logOpen(const String8& id, int facing,
+            const String16& clientPackageName, int apiLevel, bool isNdk,
+            int32_t latencyMs);
+
+    // Close
+    static void logClose(const String8& id, int32_t latencyMs);
+
+    // Stream configuration
+    static void logStreamConfigured(const String8& id, int operatingMode, bool internalReconfig,
+            int32_t latencyMs);
+
+    // Session state becomes active
+    static void logActive(const String8& id);
+
+    // Session state becomes idle
+    static void logIdle(const String8& id,
+            int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+            const std::vector<hardware::CameraStreamStats>& streamStats);
+
+    // Ping camera service proxy for user update
+    static void pingCameraServiceProxy();
+};
+
+} // android
+
+#endif // ANDROID_SERVERS_CAMERA_SERVICE_PROXY_WRAPPER_H_
diff --git a/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp b/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
new file mode 100644
index 0000000..83965c4
--- /dev/null
+++ b/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CameraSessionStatsBuilder"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include "SessionStatsBuilder.h"
+
+namespace android {
+
+status_t SessionStatsBuilder::addStream(int id) {
+    std::lock_guard<std::mutex> l(mLock);
+    StreamStats stats;
+    mStatsMap.emplace(id, stats);
+    return OK;
+}
+
+status_t SessionStatsBuilder::removeStream(int id) {
+    std::lock_guard<std::mutex> l(mLock);
+    mStatsMap.erase(id);
+    return OK;
+}
+
+void SessionStatsBuilder::buildAndReset(int64_t* requestCount,
+        int64_t* errorResultCount, bool* deviceError,
+        std::map<int, StreamStats> *statsMap) {
+    std::lock_guard<std::mutex> l(mLock);
+    *requestCount = mRequestCount;
+    *errorResultCount = mErrorResultCount;
+    *deviceError = mDeviceError;
+    *statsMap = mStatsMap;
+
+    // Reset internal states
+    mRequestCount = 0;
+    mErrorResultCount = 0;
+    mCounterStopped = false;
+    mDeviceError = false;
+    for (auto& streamStats : mStatsMap) {
+        streamStats.second.mRequestedFrameCount = 0;
+        streamStats.second.mDroppedFrameCount = 0;
+        streamStats.second.mCounterStopped = false;
+        streamStats.second.mStartLatencyMs = 0;
+    }
+}
+
+void SessionStatsBuilder::startCounter(int id) {
+    std::lock_guard<std::mutex> l(mLock);
+    mStatsMap[id].mCounterStopped = false;
+}
+
+void SessionStatsBuilder::stopCounter(int id) {
+    std::lock_guard<std::mutex> l(mLock);
+    mStatsMap[id].mCounterStopped = true;
+}
+
+void SessionStatsBuilder::incCounter(int id, bool dropped, int32_t captureLatencyMs) {
+    std::lock_guard<std::mutex> l(mLock);
+    auto it = mStatsMap.find(id);
+    if (it != mStatsMap.end()) {
+         if (!it->second.mCounterStopped) {
+             it->second.mRequestedFrameCount++;
+             if (dropped) {
+                 it->second.mDroppedFrameCount++;
+             } else if (it->second.mRequestedFrameCount == 1) {
+                 // The capture latency for the first request.
+                 it->second.mStartLatencyMs = captureLatencyMs;
+             }
+         }
+    }
+}
+
+void SessionStatsBuilder::stopCounter() {
+    std::lock_guard<std::mutex> l(mLock);
+    mCounterStopped = true;
+    for (auto& streamStats : mStatsMap) {
+        streamStats.second.mCounterStopped = true;
+    }
+}
+
+void SessionStatsBuilder::incResultCounter(bool dropped) {
+    std::lock_guard<std::mutex> l(mLock);
+    if (!mCounterStopped) {
+        mRequestCount ++;
+        if (dropped) mErrorResultCount++;
+    }
+}
+
+void SessionStatsBuilder::onDeviceError() {
+    std::lock_guard<std::mutex> l(mLock);
+    mDeviceError = true;
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/utils/SessionStatsBuilder.h b/services/camera/libcameraservice/utils/SessionStatsBuilder.h
new file mode 100644
index 0000000..7943637
--- /dev/null
+++ b/services/camera/libcameraservice/utils/SessionStatsBuilder.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 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_SERVICE_UTILS_SESSION_STATS_BUILDER_H
+#define ANDROID_SERVICE_UTILS_SESSION_STATS_BUILDER_H
+
+#include <utils/Errors.h>
+
+#include <mutex>
+#include <map>
+
+namespace android {
+
+// Helper class to build stream stats
+struct StreamStats {
+    int64_t mRequestedFrameCount;
+    int64_t mDroppedFrameCount;
+    bool mCounterStopped;
+    int32_t mStartLatencyMs;
+
+    StreamStats() : mRequestedFrameCount(0),
+                     mDroppedFrameCount(0),
+                     mCounterStopped(false),
+                     mStartLatencyMs(0) {}
+};
+
+// Helper class to build session stats
+class SessionStatsBuilder {
+public:
+
+    status_t addStream(int streamId);
+    status_t removeStream(int streamId);
+
+    // Return the session statistics and reset the internal states.
+    void buildAndReset(/*out*/int64_t* requestCount,
+            /*out*/int64_t* errorResultCount,
+            /*out*/bool* deviceError,
+            /*out*/std::map<int, StreamStats> *statsMap);
+
+    // Stream specific counter
+    void startCounter(int streamId);
+    void stopCounter(int streamId);
+    void incCounter(int streamId, bool dropped, int32_t captureLatencyMs);
+
+    // Session specific counter
+    void stopCounter();
+    void incResultCounter(bool dropped);
+    void onDeviceError();
+
+    SessionStatsBuilder() : mRequestCount(0), mErrorResultCount(0),
+             mCounterStopped(false), mDeviceError(false) {}
+private:
+    std::mutex mLock;
+    int64_t mRequestCount;
+    int64_t mErrorResultCount;
+    bool mCounterStopped;
+    bool mDeviceError;
+    // Map from stream id to stream statistics
+    std::map<int, StreamStats> mStatsMap;
+};
+
+}; // namespace android
+
+#endif // ANDROID_SERVICE_UTILS_SESSION_STATS_BUILDER_H
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 5bccfd5..85b2057 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -72,24 +72,46 @@
 
 aaudio_result_t AAudioServiceEndpointMMAP::open(const aaudio::AAudioStreamRequest &request) {
     aaudio_result_t result = AAUDIO_OK;
-    audio_config_base_t config;
-    audio_port_handle_t deviceId;
-
     copyFrom(request.getConstantConfiguration());
-
-    const audio_attributes_t attributes = getAudioAttributesFrom(this);
-
     mMmapClient.clientUid = request.getUserId();
     mMmapClient.clientPid = request.getProcessId();
     mMmapClient.packageName.setTo(String16(""));
 
+    audio_format_t audioFormat = getFormat();
+
+    // FLOAT is not directly supported by the HAL so ask for a 24-bit.
+    bool isHighResRequested = audioFormat == AUDIO_FORMAT_PCM_FLOAT
+            || audioFormat == AUDIO_FORMAT_PCM_32_BIT;
+    if (isHighResRequested) {
+        // TODO remove these logs when finished debugging.
+        ALOGD("%s() change format from %d to 24_BIT_PACKED", __func__, audioFormat);
+        audioFormat = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+    }
+
+    result = openWithFormat(audioFormat);
+    if (result == AAUDIO_OK) return result;
+
+    // TODO The HAL and AudioFlinger should be recommending a format if the open fails.
+    //      But that recommendation is not propagating back from the HAL.
+    //      So for now just try something very likely to work.
+    if (result == AAUDIO_ERROR_UNAVAILABLE && audioFormat == AUDIO_FORMAT_PCM_24_BIT_PACKED) {
+        ALOGD("%s() 24_BIT failed, perhaps due to format. Try again with 16_BIT", __func__);
+        audioFormat = AUDIO_FORMAT_PCM_16_BIT;
+        result = openWithFormat(audioFormat);
+    }
+    return result;
+}
+
+aaudio_result_t AAudioServiceEndpointMMAP::openWithFormat(audio_format_t audioFormat) {
+    aaudio_result_t result = AAUDIO_OK;
+    audio_config_base_t config;
+    audio_port_handle_t deviceId;
+
+    const audio_attributes_t attributes = getAudioAttributesFrom(this);
+
     mRequestedDeviceId = deviceId = getDeviceId();
 
     // Fill in config
-    audio_format_t audioFormat = getFormat();
-    if (audioFormat == AUDIO_FORMAT_DEFAULT || audioFormat == AUDIO_FORMAT_PCM_FLOAT) {
-        audioFormat = AUDIO_FORMAT_PCM_16_BIT;
-    }
     config.format = audioFormat;
 
     int32_t aaudioSampleRate = getSampleRate();
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
index a2a0922..24b161d 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -88,6 +88,9 @@
     aaudio_result_t getExternalPosition(uint64_t *positionFrames, int64_t *timeNanos);
 
 private:
+
+    aaudio_result_t openWithFormat(audio_format_t audioFormat);
+
     MonotonicCounter                          mFramesTransferred;
 
     // Interface to the AudioFlinger MMAP support.
diff --git a/services/tuner/Android.bp b/services/tuner/Android.bp
index 0562b45..6078e54 100644
--- a/services/tuner/Android.bp
+++ b/services/tuner/Android.bp
@@ -2,6 +2,17 @@
     name: "tv_tuner_aidl",
     srcs: [
         "aidl/android/media/tv/tuner/ITunerService.aidl",
+        "aidl/android/media/tv/tuner/TunerFrontendAnalogCapabilities.aidl",
+        "aidl/android/media/tv/tuner/TunerFrontendAtscCapabilities.aidl",
+        "aidl/android/media/tv/tuner/TunerFrontendAtsc3Capabilities.aidl",
+        "aidl/android/media/tv/tuner/TunerFrontendCableCapabilities.aidl",
+        "aidl/android/media/tv/tuner/TunerFrontendCapabilities.aidl",
+        "aidl/android/media/tv/tuner/TunerFrontendDvbsCapabilities.aidl",
+        "aidl/android/media/tv/tuner/TunerFrontendDvbtCapabilities.aidl",
+        "aidl/android/media/tv/tuner/TunerFrontendIsdbsCapabilities.aidl",
+        "aidl/android/media/tv/tuner/TunerFrontendIsdbs3Capabilities.aidl",
+        "aidl/android/media/tv/tuner/TunerFrontendIsdbtCapabilities.aidl",
+        "aidl/android/media/tv/tuner/TunerServiceFrontendInfo.aidl",
     ],
     path: "aidl",
 }
diff --git a/services/tuner/TunerService.cpp b/services/tuner/TunerService.cpp
index 92008a9..77250aa 100644
--- a/services/tuner/TunerService.cpp
+++ b/services/tuner/TunerService.cpp
@@ -20,8 +20,19 @@
 #include <utils/Log.h>
 #include "TunerService.h"
 
+using ::aidl::android::media::tv::tuner::TunerFrontendAnalogCapabilities;
+using ::aidl::android::media::tv::tuner::TunerFrontendAtsc3Capabilities;
+using ::aidl::android::media::tv::tuner::TunerFrontendAtscCapabilities;
+using ::aidl::android::media::tv::tuner::TunerFrontendCableCapabilities;
+using ::aidl::android::media::tv::tuner::TunerFrontendCapabilities;
+using ::aidl::android::media::tv::tuner::TunerFrontendDvbsCapabilities;
+using ::aidl::android::media::tv::tuner::TunerFrontendDvbtCapabilities;
+using ::aidl::android::media::tv::tuner::TunerFrontendIsdbs3Capabilities;
+using ::aidl::android::media::tv::tuner::TunerFrontendIsdbsCapabilities;
+using ::aidl::android::media::tv::tuner::TunerFrontendIsdbtCapabilities;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::tv::tuner::V1_0::FrontendId;
+using ::android::hardware::tv::tuner::V1_0::FrontendType;
 using ::android::hardware::tv::tuner::V1_0::Result;
 
 namespace android {
@@ -62,4 +73,147 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
+Status TunerService::getFrontendInfo(
+        int32_t frontendHandle, TunerServiceFrontendInfo* _aidl_return) {
+    if (mTuner == nullptr) {
+        // TODO: create a method for init.
+        mTuner = ITuner::getService();
+        if (mTuner == nullptr) {
+            ALOGE("Failed to get ITuner service.");
+            return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                    static_cast<int32_t>(Result::UNAVAILABLE));
+        }
+    }
+
+    Result res;
+    FrontendInfo info;
+    int feId = getResourceIdFromHandle(frontendHandle);
+    mTuner->getFrontendInfo(feId, [&](Result r, const FrontendInfo& feInfo) {
+        info = feInfo;
+        res = r;
+    });
+    if (res != Result::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    TunerServiceFrontendInfo tunerInfo = convertToAidlFrontendInfo(feId, info);
+    *_aidl_return = tunerInfo;
+    return ::ndk::ScopedAStatus::ok();
+}
+
+TunerServiceFrontendInfo TunerService::convertToAidlFrontendInfo(int feId, FrontendInfo halInfo) {
+    TunerServiceFrontendInfo info{
+        .id = feId,
+        .type = (int)halInfo.type,
+        .minFrequency = (int)halInfo.minFrequency,
+        .maxFrequency = (int)halInfo.maxFrequency,
+        .minSymbolRate = (int)halInfo.minSymbolRate,
+        .maxSymbolRate = (int)halInfo.maxSymbolRate,
+        .acquireRange = (int)halInfo.acquireRange,
+        .exclusiveGroupId = (int)halInfo.exclusiveGroupId,
+    };
+    for (int i = 0; i < halInfo.statusCaps.size(); i++) {
+        info.statusCaps.push_back((int)halInfo.statusCaps[i]);
+    }
+
+    TunerFrontendCapabilities caps;
+    switch (halInfo.type) {
+        case FrontendType::ANALOG: {
+            TunerFrontendAnalogCapabilities analogCaps{
+                .typeCap = (int)halInfo.frontendCaps.analogCaps().typeCap,
+                .sifStandardCap = (int)halInfo.frontendCaps.analogCaps().sifStandardCap,
+            };
+            caps.set<TunerFrontendCapabilities::analogCaps>(analogCaps);
+            break;
+        }
+        case FrontendType::ATSC: {
+            TunerFrontendAtscCapabilities atscCaps{
+                .modulationCap = (int)halInfo.frontendCaps.atscCaps().modulationCap,
+            };
+            caps.set<TunerFrontendCapabilities::atscCaps>(atscCaps);
+            break;
+        }
+        case FrontendType::ATSC3: {
+            TunerFrontendAtsc3Capabilities atsc3Caps{
+                .bandwidthCap = (int)halInfo.frontendCaps.atsc3Caps().bandwidthCap,
+                .modulationCap = (int)halInfo.frontendCaps.atsc3Caps().modulationCap,
+                .timeInterleaveModeCap =
+                        (int)halInfo.frontendCaps.atsc3Caps().timeInterleaveModeCap,
+                .codeRateCap = (int)halInfo.frontendCaps.atsc3Caps().codeRateCap,
+                .demodOutputFormatCap = (int)halInfo.frontendCaps.atsc3Caps().demodOutputFormatCap,
+                .fecCap = (int)halInfo.frontendCaps.atsc3Caps().fecCap,
+            };
+            caps.set<TunerFrontendCapabilities::atsc3Caps>(atsc3Caps);
+            break;
+        }
+        case FrontendType::DVBC: {
+            TunerFrontendCableCapabilities cableCaps{
+                .modulationCap = (int)halInfo.frontendCaps.dvbcCaps().modulationCap,
+                .codeRateCap = (int)halInfo.frontendCaps.dvbcCaps().fecCap,
+                .annexCap = (int)halInfo.frontendCaps.dvbcCaps().annexCap,
+            };
+            caps.set<TunerFrontendCapabilities::cableCaps>(cableCaps);
+            break;
+        }
+        case FrontendType::DVBS: {
+            TunerFrontendDvbsCapabilities dvbsCaps{
+                .modulationCap = (int)halInfo.frontendCaps.dvbsCaps().modulationCap,
+                .codeRateCap = (long)halInfo.frontendCaps.dvbsCaps().innerfecCap,
+                .standard = (int)halInfo.frontendCaps.dvbsCaps().standard,
+            };
+            caps.set<TunerFrontendCapabilities::dvbsCaps>(dvbsCaps);
+            break;
+        }
+        case FrontendType::DVBT: {
+            TunerFrontendDvbtCapabilities dvbtCaps{
+                .transmissionModeCap = (int)halInfo.frontendCaps.dvbtCaps().transmissionModeCap,
+                .bandwidthCap = (int)halInfo.frontendCaps.dvbtCaps().bandwidthCap,
+                .constellationCap = (int)halInfo.frontendCaps.dvbtCaps().constellationCap,
+                .codeRateCap = (int)halInfo.frontendCaps.dvbtCaps().coderateCap,
+                .hierarchyCap = (int)halInfo.frontendCaps.dvbtCaps().hierarchyCap,
+                .guardIntervalCap = (int)halInfo.frontendCaps.dvbtCaps().guardIntervalCap,
+                .isT2Supported = (bool)halInfo.frontendCaps.dvbtCaps().isT2Supported,
+                .isMisoSupported = (bool)halInfo.frontendCaps.dvbtCaps().isMisoSupported,
+            };
+            caps.set<TunerFrontendCapabilities::dvbtCaps>(dvbtCaps);
+            break;
+        }
+        case FrontendType::ISDBS: {
+            TunerFrontendIsdbsCapabilities isdbsCaps{
+                .modulationCap = (int)halInfo.frontendCaps.isdbsCaps().modulationCap,
+                .codeRateCap = (int)halInfo.frontendCaps.isdbsCaps().coderateCap,
+            };
+            caps.set<TunerFrontendCapabilities::isdbsCaps>(isdbsCaps);
+            break;
+        }
+        case FrontendType::ISDBS3: {
+            TunerFrontendIsdbs3Capabilities isdbs3Caps{
+                .modulationCap = (int)halInfo.frontendCaps.isdbs3Caps().modulationCap,
+                .codeRateCap = (int)halInfo.frontendCaps.isdbs3Caps().coderateCap,
+            };
+            caps.set<TunerFrontendCapabilities::isdbs3Caps>(isdbs3Caps);
+            break;
+        }
+        case FrontendType::ISDBT: {
+            TunerFrontendIsdbtCapabilities isdbtCaps{
+                .modeCap = (int)halInfo.frontendCaps.isdbtCaps().modeCap,
+                .bandwidthCap = (int)halInfo.frontendCaps.isdbtCaps().bandwidthCap,
+                .modulationCap = (int)halInfo.frontendCaps.isdbtCaps().modulationCap,
+                .codeRateCap = (int)halInfo.frontendCaps.isdbtCaps().coderateCap,
+                .guardIntervalCap = (int)halInfo.frontendCaps.isdbtCaps().guardIntervalCap,
+            };
+            caps.set<TunerFrontendCapabilities::isdbtCaps>(isdbtCaps);
+            break;
+        }
+        default:
+            break;
+    }
+
+    info.caps = caps;
+    return info;
+}
+
+int TunerService::getResourceIdFromHandle(int resourceHandle) {
+    return (resourceHandle & 0x00ff0000) >> 16;
+}
 } // namespace android
diff --git a/services/tuner/TunerService.h b/services/tuner/TunerService.h
index bda6c65..f3d5ff7 100644
--- a/services/tuner/TunerService.h
+++ b/services/tuner/TunerService.h
@@ -18,10 +18,13 @@
 #define ANDROID_MEDIA_TUNERSERVICE_H
 
 #include <aidl/android/media/tv/tuner/BnTunerService.h>
+#include <aidl/android/media/tv/tuner/TunerServiceFrontendInfo.h>
 #include <android/hardware/tv/tuner/1.0/ITuner.h>
 
 using Status = ::ndk::ScopedAStatus;
 using ::aidl::android::media::tv::tuner::BnTunerService;
+using ::aidl::android::media::tv::tuner::TunerServiceFrontendInfo;
+using ::android::hardware::tv::tuner::V1_0::FrontendInfo;
 using ::android::hardware::tv::tuner::V1_0::ITuner;
 
 namespace android {
@@ -34,9 +37,13 @@
     TunerService();
     virtual ~TunerService();
     Status getFrontendIds(std::vector<int32_t>* ids, int32_t* _aidl_return) override;
+    Status getFrontendInfo(int32_t frontendHandle, TunerServiceFrontendInfo* _aidl_return) override;
 
 private:
     static sp<ITuner> mTuner;
+
+    int getResourceIdFromHandle(int resourceHandle);
+    TunerServiceFrontendInfo convertToAidlFrontendInfo(int feId, FrontendInfo halInfo);
 };
 
 } // namespace android
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
index 53cd90d..1d3671d 100644
--- a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
@@ -16,6 +16,8 @@
 
 package android.media.tv.tuner;
 
+import android.media.tv.tuner.TunerServiceFrontendInfo;
+
 /**
  * TunerService interface handles tuner related operations.
  *
@@ -29,4 +31,12 @@
      * @return the result code of the operation.
      */
     int getFrontendIds(out int[] ids);
+
+    /**
+     * Retrieve the frontend's information.
+     *
+     * @param frontendHandle the handle of the frontend granted by TRM.
+     * @return the information for the frontend.
+     */
+    TunerServiceFrontendInfo getFrontendInfo(in int frontendHandle);
 }
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendAnalogCapabilities.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendAnalogCapabilities.aidl
new file mode 100644
index 0000000..74bf04e
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendAnalogCapabilities.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2020, 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.media.tv.tuner;
+
+/**
+ * Analog Frontend Capabilities interface.
+ *
+ * {@hide}
+ */
+parcelable TunerFrontendAnalogCapabilities {
+	/**
+     * Signal Type capability
+     */
+    int typeCap;
+
+    /**
+     * Standard Interchange Format (SIF) capability
+     */
+    int sifStandardCap;
+}
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendAtsc3Capabilities.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendAtsc3Capabilities.aidl
new file mode 100644
index 0000000..6c9be77
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendAtsc3Capabilities.aidl
@@ -0,0 +1,54 @@
+/**
+ * Copyright 2020, 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.media.tv.tuner;
+
+/**
+ * ATSC3 Frontend Capabilities interface.
+ *
+ * {@hide}
+ */
+parcelable TunerFrontendAtsc3Capabilities {
+    /**
+     * Bandwidth capability
+     */
+    int bandwidthCap;
+
+    /**
+     * Modulation capability
+     */
+    int modulationCap;
+
+    /**
+     * TimeInterleaveMode capability
+     */
+    int timeInterleaveModeCap;
+
+    /**
+     * CodeRate capability
+     */
+    int codeRateCap;
+
+    /**
+     * FEC capability
+     */
+    int fecCap;
+
+    /**
+     * Demodulator Output Format capability
+     */
+    int demodOutputFormatCap;
+}
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendAtscCapabilities.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendAtscCapabilities.aidl
new file mode 100644
index 0000000..2b6c2fc
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendAtscCapabilities.aidl
@@ -0,0 +1,29 @@
+/**
+ * Copyright 2020, 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.media.tv.tuner;
+
+/**
+ * ATSC Frontend Capabilities interface.
+ *
+ * {@hide}
+ */
+parcelable TunerFrontendAtscCapabilities {
+    /**
+     * Modulation capability
+     */
+    int modulationCap;
+}
\ No newline at end of file
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendCableCapabilities.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendCableCapabilities.aidl
new file mode 100644
index 0000000..7df452a
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendCableCapabilities.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright 2020, 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.media.tv.tuner;
+
+/**
+ * Cable(DVBC) Frontend Capabilities interface.
+ *
+ * {@hide}
+ */
+parcelable TunerFrontendCableCapabilities {
+    /**
+     * Modulation capability
+     */
+    int modulationCap;
+
+    /**
+     * Code Rate capability
+     */
+    int codeRateCap; // inner FEC will converge to codeRate
+
+    /**
+     * Annex capability
+     */
+    int annexCap;
+}
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendCapabilities.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendCapabilities.aidl
new file mode 100644
index 0000000..19f31f1
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendCapabilities.aidl
@@ -0,0 +1,85 @@
+/**
+ * Copyright 2020, 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.media.tv.tuner;
+
+import android.media.tv.tuner.TunerFrontendAnalogCapabilities;
+import android.media.tv.tuner.TunerFrontendAtscCapabilities;
+import android.media.tv.tuner.TunerFrontendAtsc3Capabilities;
+import android.media.tv.tuner.TunerFrontendCableCapabilities;
+import android.media.tv.tuner.TunerFrontendDvbsCapabilities;
+import android.media.tv.tuner.TunerFrontendDvbtCapabilities;
+import android.media.tv.tuner.TunerFrontendIsdbsCapabilities;
+import android.media.tv.tuner.TunerFrontendIsdbs3Capabilities;
+import android.media.tv.tuner.TunerFrontendIsdbtCapabilities;
+
+/**
+ * Frontend Capabilities interface.
+ *
+ * Use a group of vectors as the workaround for Union structure that is not fully supported
+ * in AIDL currently.
+ *
+ * Client may use FrontendInfo.type as the discriminar to check the corresponding vector. If
+ * the vector is not null, it contains valid value.
+ *
+ * {@hide}
+ */
+union TunerFrontendCapabilities {
+    /**
+     * Analog Frontend Capabilities
+     */
+    TunerFrontendAnalogCapabilities analogCaps;
+
+    /**
+     * ATSC Frontend Capabilities
+     */
+    TunerFrontendAtscCapabilities atscCaps;
+
+    /**
+     * ATSC3 Frontend Capabilities
+     */
+    TunerFrontendAtsc3Capabilities atsc3Caps;
+
+    /**
+     * Cable Frontend Capabilities
+     */
+    TunerFrontendCableCapabilities cableCaps;
+
+    /**
+     * DVBS Frontend Capabilities
+     */
+    TunerFrontendDvbsCapabilities dvbsCaps;
+
+    /**
+     * DVBT Frontend Capabilities
+     */
+    TunerFrontendDvbtCapabilities dvbtCaps;
+
+    /**
+     * ISDB-S Frontend Capabilities
+     */
+    TunerFrontendIsdbsCapabilities isdbsCaps;
+
+    /**
+     * ISDB-S3 Frontend Capabilities
+     */
+    TunerFrontendIsdbs3Capabilities isdbs3Caps;
+
+    /**
+     * ISDB-T Frontend Capabilities
+     */
+    TunerFrontendIsdbtCapabilities isdbtCaps;
+}
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendDvbsCapabilities.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendDvbsCapabilities.aidl
new file mode 100644
index 0000000..5e4322c
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendDvbsCapabilities.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright 2020, 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.media.tv.tuner;
+
+/**
+ * DVBS Frontend Capabilities interface.
+ *
+ * {@hide}
+ */
+parcelable TunerFrontendDvbsCapabilities {
+    /**
+     * Modulation capability
+     */
+    int modulationCap;
+
+    /**
+     * Code Rate capability
+     */
+    long codeRateCap;  // inner FEC will converge to codeRate
+
+    /**
+     * Sub standards capability
+     */
+    int standard;
+}
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendDvbtCapabilities.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendDvbtCapabilities.aidl
new file mode 100644
index 0000000..73f16dd
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendDvbtCapabilities.aidl
@@ -0,0 +1,64 @@
+/**
+ * Copyright 2020, 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.media.tv.tuner;
+
+/**
+ * DVBT Frontend Capabilities interface.
+ *
+ * {@hide}
+ */
+parcelable TunerFrontendDvbtCapabilities {
+    /**
+     * Transmission Mode capability
+     */
+    int transmissionModeCap;
+
+    /**
+     * Bandwidth capability
+     */
+    int bandwidthCap;
+
+    /**
+     * Constellation capability
+     */
+    int constellationCap;
+
+    /**
+     * Code Rate capability
+     */
+    int codeRateCap;
+
+    /**
+     * Hierarchy Type capability
+     */
+    int hierarchyCap;
+
+    /**
+     * Guard Interval capability
+     */
+    int guardIntervalCap;
+
+    /**
+     * T2 Support capability
+     */
+    boolean isT2Supported;
+
+    /**
+     * Miso Support capability
+     */
+    boolean isMisoSupported;
+}
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbs3Capabilities.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbs3Capabilities.aidl
new file mode 100644
index 0000000..84dd67a
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbs3Capabilities.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2020, 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.media.tv.tuner;
+
+/**
+ * ISDB-S3 Frontend Capabilities interface.
+ *
+ * {@hide}
+ */
+parcelable TunerFrontendIsdbs3Capabilities {
+    /**
+     * Modulation capability
+     */
+    int modulationCap;
+
+    /**
+     * Code Rate capability
+     */
+    int codeRateCap;
+}
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbsCapabilities.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbsCapabilities.aidl
new file mode 100644
index 0000000..15dfdf7
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbsCapabilities.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2020, 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.media.tv.tuner;
+
+/**
+ * ISDB-S Frontend Capabilities interface.
+ *
+ * {@hide}
+ */
+parcelable TunerFrontendIsdbsCapabilities {
+    /**
+     * Modulation capability
+     */
+    int modulationCap;
+
+    /**
+     * Code Rate capability
+     */
+    int codeRateCap;
+}
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbtCapabilities.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbtCapabilities.aidl
new file mode 100644
index 0000000..c9295d8
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbtCapabilities.aidl
@@ -0,0 +1,49 @@
+/**
+ * Copyright 2020, 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.media.tv.tuner;
+
+/**
+ * ISDB-T Frontend Capabilities interface.
+ *
+ * {@hide}
+ */
+parcelable TunerFrontendIsdbtCapabilities {
+    /**
+     * ISDB-T Mode capability
+     */
+    int modeCap;
+
+    /**
+     * Bandwidth capability
+     */
+    int bandwidthCap;
+
+    /**
+     * Modulation capability
+     */
+    int modulationCap;
+
+    /**
+     * Code Rate capability
+     */
+    int codeRateCap;
+
+    /**
+     * Guard Interval capability
+     */
+    int guardIntervalCap;
+}
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerServiceFrontendInfo.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerServiceFrontendInfo.aidl
new file mode 100644
index 0000000..ddcbcdc
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerServiceFrontendInfo.aidl
@@ -0,0 +1,77 @@
+/**
+ * Copyright 2020, 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.media.tv.tuner;
+
+import android.media.tv.tuner.TunerFrontendCapabilities;
+
+/**
+ * FrontendInfo interface that carries tuner frontend information.
+ *
+ * {@hide}
+ */
+parcelable TunerServiceFrontendInfo {
+    /**
+     * Frontend Id
+     */
+    int id;
+
+    /**
+     * Frontend Type
+     */
+    int type;
+
+    /**
+     * Minimum Frequency in Hertz
+     */
+    int minFrequency;
+
+    /**
+     * Maximum Frequency in Hertz
+     */
+    int maxFrequency;
+
+    /**
+     * Minimum symbols per second
+     */
+    int minSymbolRate;
+
+    /**
+     * Maximum symbols per second
+     */
+    int maxSymbolRate;
+
+    /**
+     * Range in Hertz
+     */
+    int acquireRange;
+
+    /**
+     * Frontends are assigned with the same exclusiveGroupId if they can't
+     * function at same time. For instance, they share same hardware module.
+     */
+    int exclusiveGroupId;
+
+    /**
+     * A list of supported status types which client can inquiry
+     */
+    int[] statusCaps;
+
+    /**
+     * Frontend Capabilities
+     */
+    TunerFrontendCapabilities caps;
+}