Merge "Log if intercepting tracks takes too long"
diff --git a/apex/Android.bp b/apex/Android.bp
index c077a77..9455290 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -12,9 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-apex {
-    name: "com.android.media",
-    manifest: "manifest.json",
+apex_defaults {
+    name: "com.android.media-defaults",
     java_libs: ["updatable-media"],
     compile_multilib: "both",
     multilib: {
@@ -42,16 +41,29 @@
         },
     },
     key: "com.android.media.key",
+    certificate: ":com.android.media.certificate",
 }
 
 apex {
-    name: "com.android.media.swcodec",
-    manifest: "manifest_codec.json",
+    name: "com.android.media",
+    manifest: "manifest.json",
+    defaults: ["com.android.media-defaults"],
+}
+
+apex_defaults {
+    name: "com.android.media.swcodec-defaults",
     native_shared_libs: [
         "libmedia_codecserviceregistrant",
     ],
     use_vendor: true,
     key: "com.android.media.swcodec.key",
+    certificate: ":com.android.media.swcodec.certificate",
+}
+
+apex {
+    name: "com.android.media.swcodec",
+    manifest: "manifest_codec.json",
+    defaults: ["com.android.media.swcodec-defaults"],
 }
 
 apex_key {
@@ -65,3 +77,13 @@
     public_key: "com.android.media.swcodec.avbpubkey",
     private_key: "com.android.media.swcodec.pem",
 }
+
+android_app_certificate {
+    name: "com.android.media.certificate",
+    certificate: "com.android.media",
+}
+
+android_app_certificate {
+    name: "com.android.media.swcodec.certificate",
+    certificate: "com.android.media.swcodec",
+}
diff --git a/apex/com.android.media.pk8 b/apex/com.android.media.pk8
new file mode 100644
index 0000000..6df741e
--- /dev/null
+++ b/apex/com.android.media.pk8
Binary files differ
diff --git a/apex/com.android.media.swcodec.pk8 b/apex/com.android.media.swcodec.pk8
new file mode 100644
index 0000000..05a4216
--- /dev/null
+++ b/apex/com.android.media.swcodec.pk8
Binary files differ
diff --git a/apex/com.android.media.swcodec.x509.pem b/apex/com.android.media.swcodec.x509.pem
new file mode 100644
index 0000000..67b9b4f
--- /dev/null
+++ b/apex/com.android.media.swcodec.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF3jCCA8agAwIBAgIJAIM72JpD4v6XMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4g
+VmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEiMCAGA1UE
+AwwZY29tLmFuZHJvaWQubWVkaWEuc3djb2RlYzAgFw0xOTAyMTEwMjExMTFaGA80
+NzU3MDEwNzAyMTExMVowgYIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9y
+bmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAw
+DgYDVQQLDAdBbmRyb2lkMSIwIAYDVQQDDBljb20uYW5kcm9pZC5tZWRpYS5zd2Nv
+ZGVjMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsqXE0AIWpLW9Tgq2
+nQGph7KZ6L2Q9oxviqCVHxIaPqfhM2SwTbycADIQeqrrlRxhddVkjLuMUkJa7mev
+fERmgpiOfnPIlGK6PTs2gljCkskZhF3bgfeyuHt0tsYO+UaN8MVoZD7/QdiE46w2
+OMDClG1UqgiqOBhLTEN/cHXObnUiiVXUYqN8aYZf6L6Fs3yQi2ZZgfbxTVFewqdv
+aLLOqCYnVYXZH+ZxbXESA0M+WXKgRKsYTj2GYs3eko1rFi4Y6uHVLx45yaoT5u/i
+SxPEkocyMCKvGJWu4XlSOd3EjSOMaqCOYVyGLxdlnQWQU7PZDqBSJ0SysWgpFHpB
+I15c2jhRdXOCfQ9ZtDfPZkE0a2A8kJDAoF1mzTp6IvBAWUsl5nHPw5CWkFpNad/h
+tqqGCScWbiKZuvrQ4/RQNm3f1K+mxX9TrjFigpqNO6d4pGAo1fa6sHR3xWPw/myq
+h5ZJjVnXU5Yq64S4xWOssfjpOg7RfNuvzuk3ok3MYs1mbx3vhZOj5km1f3qrgX9c
+mXjYnyXD0jJBm4uAJWXLdK9PlZvlXbztMCzYj832Io4pFLCtSxkzX75t1em36Nv0
+mNp6NtSSy6SFSq8l7IsXV2FNyUiyHWxS/UQm8pYg5Q5dWHvEEF78P6lV0wRa6FQl
+BBSgpqTAI092KIjDDtB7GQCgV5ECAwEAAaNTMFEwHQYDVR0OBBYEFAFIdFTDEDft
+ewSSAS7Fa3OZ5TXzMB8GA1UdIwQYMBaAFAFIdFTDEDftewSSAS7Fa3OZ5TXzMA8G
+A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAC5e3zXythJCGmz1FmAV
+8Y/UI+Glg6G0x/k04WaRG0DPLLjlJ1F0LM1/IReBSgXcYAL0CAgPycf/rGPOgMFm
+tQxYyjBUxKdjpIqU5DJoV1feanGveIRpto1YRKNgHuzG9rZGR4AgPnt6X4Yxlq04
+lI7QpWadXe1myARJhj3niSNY9+2wEInkx4ZuCO1LtIGqnbdc8jQ8YoVqIE5N4kuM
+ccyPYgsdABtopbjN92rueu8sfF8R6ROy+tNgb6OjpAAevtnBfZ2LXqfObKirHCK+
+k6w4WSB1UUoZ3Xgz8sJtXgokvYeInkN8tHuTagHYU2VQTcA0rdBGMN/1OljJpWlN
+0UUq4fAYU6cN4lHxr2LM9If4WvAzdLAWvaIZrDqaU4i/zYT9l6rR4lC2KW3EHWov
+nPXfgEJJ8AP1iRGibvew3i3SB6XTWFQYTUIBeJfDz/KDXQabP+yzXWISdZCUMUpx
+f+Raqsb5MoKaJdVgnSL0mBunjCyJDzzg34J7oGx6/BnwoiOrwLN4Qaz5U8jbrPSx
+p9LfleCcO7ZdeE8GKqx0X1T4d7tradtmxOS8Iwr4niskkHGRkzozvVvuyGKmoN2k
+162Vfjq+ddj7qEpSh3BS6hHU+vlMbC9L0trGxPxFEAHDrwu0KwGNduTkiu/3jvfB
+JTgH8P9mD1loYxRdo+vet8eQ
+-----END CERTIFICATE-----
diff --git a/apex/com.android.media.x509.pem b/apex/com.android.media.x509.pem
new file mode 100644
index 0000000..e7908fa
--- /dev/null
+++ b/apex/com.android.media.x509.pem
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFzDCCA7SgAwIBAgIJAO05DBBusaaLMA0GCSqGSIb3DQEBCwUAMHoxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
+aWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRyb2lkMRowGAYDVQQD
+DBFjb20uYW5kcm9pZC5tZWRpYTAgFw0xOTAxMjUxNzE3MTdaGA80NzU2MTIyMTE3
+MTcxN1owejELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNV
+BAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0FuZHJvaWQxEDAOBgNVBAsMB0Fu
+ZHJvaWQxGjAYBgNVBAMMEWNvbS5hbmRyb2lkLm1lZGlhMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAmNkVxUbp/bLbeGbvKqYXzwBycSDpmOhh///lNGYQ
+/AMUD0q6EaZzU2bd4aL0rOGqfoYlhKd0kMVmMUmfdE9ODAfKxleEeEaRl2GJS8a9
+ABi770l3GHbB2xMI2sEWeOD9xsPFF6+ByPZmoUuNhMr4pUbXsDpE3h8ljrgXHtIg
+bh7ofbvddruwBV0lS1k9OZ9jPVGhEKkJnhgQa67cwgdjizAMbI0Dcz9gtMMawsDj
+Z2aQd1r+vxgh1/XkI/NMmXCnG2ERytXcJeC5S4gEtHfTTPoP0FuVgSB6y6dalMuZ
+F0NBZw8Mvgdy3QJip0uNa36J63CMZKTJWbTdlFpPL2hk0PgaYvje8C5Xtk5282wT
+dMocc8n2zIXbzbnSXGvjcNZib3Pfu55YUnX6eTqZ1BxlJ0FHZAsC4quFFWXxYBYD
+LCRoNNFEtIDQpuvuHF2DuHNDULpAQjy2y6+7eot0KEsVoDmZ4H8BpuAVVu2SxYNb
+gYflR9SmM0tmYeAcRT48q3xrocGyEHMqvgQRUpPfvct/8l8xVcDzOI/sJVDqmYzM
+u0Cj3fkSypGDJOMF/esFSmVvoI01tS7kaNS5vvtKYib//xqKRC9f0dCsGfFLnuUK
+o4KYbYWYwMyJqEd/5/ZvXyKIPAEeJL174L9+wTkc3cQpoBwJN4t+2E5MnhOEq6do
+5L0CAwEAAaNTMFEwHQYDVR0OBBYEFHjNK/GZko1RdZp+8iavWXL5xz9wMB8GA1Ud
+IwQYMBaAFHjNK/GZko1RdZp+8iavWXL5xz9wMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQELBQADggIBACmPQMksuLrNV1vbI44S1f70I0FHdBxchFGB39zuLbcn
+SsYom/LPtYJiD0Dl4bB4eb+ZnxkQP2XeP6pycmUH2j1EWexFwvdUvlfe8Qz+wAec
+ap4AxiX4Z2Ke2ivYotIZFUHdZOLkX20js8Wex1mzY43MLQn5APl9gK1VZTxDggeR
+EObH1S+JVjGwQqYZj2e6gNZH34Q25NQ698RL85GDkYtSISAifJtaJsU/B3vKm82I
+k9xMiCooCH6bRdGHG1jze4SRpidjxEm8cxkiaQagfcuXeCLziXJr3qAMKYiEY6bp
+0+bAqCt3S8OrrN3RQZfQrnlwitsM1jJJ/+C+WoDg4eY5AFrXDLvNeKh1qO/f8xv+
+fCXkQPcVVphLfRH9oxNrSgOWBP5/qIDH4s1YUL9luGT6H+08dlue3RkbzDbBqsQu
+7fQ/BbrIG/GuVKgyEM+a7C9gv7zc86YlueVYJEyxKidnn7RxOqyDBqyyfXA3zvme
+Rro7xIrMHPL7Nu3AWjwjXzbp/w0z+tEFPsfVB+OOHKsWPcUG0HUTJGkyeO/uHRjN
+qPEkkf7BHHUO4V2gjOIdCsELxKwHf7vsZTOk40EV751fZ7FDHMr1eddQkgH4eqAb
+DB79uP+SLfUo+42n4q6eMmoqw8d76bBXRoUhIo/Ms4sebhV0sRtAS67OQioc9UUg
+-----END CERTIFICATE-----
diff --git a/apex/testing/Android.bp b/apex/testing/Android.bp
new file mode 100644
index 0000000..701ced7
--- /dev/null
+++ b/apex/testing/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+apex {
+    name: "test_com.android.media",
+    manifest: "test_manifest.json",
+    file_contexts: "com.android.media",
+    defaults: ["com.android.media-defaults"],
+    installable: false,
+}
+
+apex {
+    name: "test_com.android.media.swcodec",
+    manifest: "test_manifest_codec.json",
+    file_contexts: "com.android.media.swcodec",
+    defaults: ["com.android.media.swcodec-defaults"],
+    installable: false,
+}
diff --git a/apex/testing/test_manifest.json b/apex/testing/test_manifest.json
new file mode 100644
index 0000000..9f81f9f
--- /dev/null
+++ b/apex/testing/test_manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.media",
+  "version": 2
+}
diff --git a/apex/testing/test_manifest_codec.json b/apex/testing/test_manifest_codec.json
new file mode 100644
index 0000000..c956454
--- /dev/null
+++ b/apex/testing/test_manifest_codec.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.media.swcodec",
+  "version": 2
+}
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index c038314..0e969c7 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -162,6 +162,28 @@
      * Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
      */
     const int EVENT_NONE = 0;
-    const int EVENT_USER_SWITCHED = 1;
+    const int EVENT_USER_SWITCHED = 1; // The argument is the set of new foreground user IDs.
     oneway void notifySystemEvent(int eventId, in int[] args);
+
+    /**
+     * Notify the camera service of a device physical status change. May only be called from
+     * a privileged process.
+     *
+     * newState is a bitfield consisting of DEVICE_STATE_* values combined together. Valid state
+     * combinations are device-specific. At device startup, the camera service will assume the device
+     * state is NORMAL until otherwise notified.
+     *
+     * Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
+     */
+    oneway void notifyDeviceStateChange(long newState);
+
+    // Bitfield constants for notifyDeviceStateChange
+    // All bits >= 32 are for custom vendor states
+    // Written as ints since AIDL does not support long constants.
+    const int DEVICE_STATE_NORMAL = 0;
+    const int DEVICE_STATE_BACK_COVERED = 1;
+    const int DEVICE_STATE_FRONT_COVERED = 2;
+    const int DEVICE_STATE_FOLDED = 4;
+    const int DEVICE_STATE_LAST_FRAMEWORK_BIT = 0x80000000; // 1 << 31;
+
 }
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index b88a2c5..92b06c2 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -27,6 +27,7 @@
         "libhidltransport",
         "android.hardware.camera.common@1.0",
         "android.hardware.camera.provider@2.4",
+        "android.hardware.camera.provider@2.5",
         "android.hardware.camera.device@1.0",
         "android.hardware.camera.device@3.2",
         "android.hardware.camera.device@3.4",
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index 50ad7b2..de40990 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -36,6 +36,8 @@
         filterDurations(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS);
         filterDurations(ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS);
         filterDurations(ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
+        filterDurations(ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS);
+        filterDurations(ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS);
     }
     // TODO: filter request/result keys
 }
@@ -174,6 +176,16 @@
                     filteredDurations.push_back(duration);
                 }
                 break;
+            case ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS:
+            case ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS:
+                if (format == HAL_PIXEL_FORMAT_BLOB) {
+                    format = AIMAGE_FORMAT_HEIC;
+                    filteredDurations.push_back(format);
+                    filteredDurations.push_back(width);
+                    filteredDurations.push_back(height);
+                    filteredDurations.push_back(duration);
+                }
+                break;
             default:
                 // Should not reach here
                 ALOGE("%s: Unkown tag 0x%x", __FUNCTION__, tag);
@@ -247,6 +259,31 @@
         filteredDepthStreamConfigs.push_back(isInput);
     }
     mData.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, filteredDepthStreamConfigs);
+
+    entry = mData.find(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS);
+    Vector<int32_t> filteredHeicStreamConfigs;
+    filteredHeicStreamConfigs.setCapacity(entry.count);
+
+    for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+        int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+        int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+        int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+        int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+        if (isInput == ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_INPUT) {
+            // Hide input streams
+            continue;
+        }
+        // Translate HAL formats to NDK format
+        if (format == HAL_PIXEL_FORMAT_BLOB) {
+            format = AIMAGE_FORMAT_HEIC;
+        }
+
+        filteredHeicStreamConfigs.push_back(format);
+        filteredHeicStreamConfigs.push_back(width);
+        filteredHeicStreamConfigs.push_back(height);
+        filteredHeicStreamConfigs.push_back(isInput);
+    }
+    mData.update(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, filteredHeicStreamConfigs);
 }
 
 bool
@@ -485,6 +522,8 @@
     ANDROID_STATISTICS_INFO_SHARPNESS_MAP_SIZE,
     ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION,
     ANDROID_DEPTH_MAX_DEPTH_SAMPLES,
+    ANDROID_HEIC_INFO_SUPPORTED,
+    ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT,
 });
 
 /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 69b9e7e..8c19e1d 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -71,6 +71,8 @@
     ACAMERA_DEPTH,
     ACAMERA_LOGICAL_MULTI_CAMERA,
     ACAMERA_DISTORTION_CORRECTION,
+    ACAMERA_HEIC,
+    ACAMERA_HEIC_INFO,
     ACAMERA_SECTION_COUNT,
 
     ACAMERA_VENDOR = 0x8000
@@ -112,6 +114,8 @@
     ACAMERA_DISTORTION_CORRECTION_START
                                    = ACAMERA_DISTORTION_CORRECTION
                                                                 << 16,
+    ACAMERA_HEIC_START             = ACAMERA_HEIC              << 16,
+    ACAMERA_HEIC_INFO_START        = ACAMERA_HEIC_INFO         << 16,
     ACAMERA_VENDOR_START           = ACAMERA_VENDOR            << 16
 } acamera_metadata_section_start_t;
 
@@ -1912,6 +1916,7 @@
      *   <li>ACaptureRequest</li>
      * </ul></p>
      *
+     * <p>This tag is also used for HEIC image capture.</p>
      */
     ACAMERA_JPEG_GPS_COORDINATES =                              // double[3]
             ACAMERA_JPEG_START,
@@ -1927,6 +1932,7 @@
      *   <li>ACaptureRequest</li>
      * </ul></p>
      *
+     * <p>This tag is also used for HEIC image capture.</p>
      */
     ACAMERA_JPEG_GPS_PROCESSING_METHOD =                        // byte
             ACAMERA_JPEG_START + 1,
@@ -1942,6 +1948,7 @@
      *   <li>ACaptureRequest</li>
      * </ul></p>
      *
+     * <p>This tag is also used for HEIC image capture.</p>
      */
     ACAMERA_JPEG_GPS_TIMESTAMP =                                // int64
             ACAMERA_JPEG_START + 2,
@@ -1986,6 +1993,10 @@
      * </code></pre>
      * <p>For EXTERNAL cameras the sensor orientation will always be set to 0 and the facing will
      * also be set to EXTERNAL. The above code is not relevant in such case.</p>
+     * <p>This tag is also used to describe the orientation of the HEIC image capture, in which
+     * case the rotation is reflected by
+     * <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>, and not by
+     * rotating the image data itself.</p>
      *
      * @see ACAMERA_SENSOR_ORIENTATION
      */
@@ -2003,7 +2014,8 @@
      *   <li>ACaptureRequest</li>
      * </ul></p>
      *
-     * <p>85-95 is typical usage range.</p>
+     * <p>85-95 is typical usage range. This tag is also used to describe the quality
+     * of the HEIC image capture.</p>
      */
     ACAMERA_JPEG_QUALITY =                                      // byte
             ACAMERA_JPEG_START + 4,
@@ -2019,6 +2031,7 @@
      *   <li>ACaptureRequest</li>
      * </ul></p>
      *
+     * <p>This tag is also used to describe the quality of the HEIC image capture.</p>
      */
     ACAMERA_JPEG_THUMBNAIL_QUALITY =                            // byte
             ACAMERA_JPEG_START + 5,
@@ -2055,6 +2068,10 @@
      *   orientation is requested. LEGACY device will always report unrotated thumbnail
      *   size.</li>
      * </ul>
+     * <p>The tag is also used as thumbnail size for HEIC image format capture, in which case the
+     * the thumbnail rotation is reflected by
+     * <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>, and not by
+     * rotating the thumbnail data itself.</p>
      *
      * @see ACAMERA_JPEG_ORIENTATION
      */
@@ -2088,6 +2105,7 @@
      * and vice versa.</li>
      * <li>All non-<code>(0, 0)</code> sizes will have non-zero widths and heights.</li>
      * </ul>
+     * <p>This list is also used as supported thumbnail sizes for HEIC image format capture.</p>
      *
      * @see ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
      */
@@ -5757,6 +5775,80 @@
             ACAMERA_DISTORTION_CORRECTION_START + 1,
     ACAMERA_DISTORTION_CORRECTION_END,
 
+    /**
+     * <p>The available HEIC (ISO/IEC 23008-12) stream
+     * configurations that this camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     *
+     * <p>Type: int32[n*4] (acamera_metadata_enum_android_heic_available_heic_stream_configurations_t)</p>
+     *
+     * <p>This tag may appear in:
+     * <ul>
+     *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+     * </ul></p>
+     *
+     * <p>The configurations are listed as <code>(format, width, height, input?)</code> tuples.</p>
+     * <p>If the camera device supports HEIC image format, it will support identical set of stream
+     * combinations involving HEIC image format, compared to the combinations involving JPEG
+     * image format as required by the device's hardware level and capabilities.</p>
+     * <p>All the static, control, and dynamic metadata tags related to JPEG apply to HEIC formats.
+     * Configuring JPEG and HEIC streams at the same time is not supported.</p>
+     * <p>All the configuration tuples <code>(format, width, height, input?)</code> will contain
+     * AIMAGE_FORMAT_HEIC format as OUTPUT only.</p>
+     */
+    ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS =         // int32[n*4] (acamera_metadata_enum_android_heic_available_heic_stream_configurations_t)
+            ACAMERA_HEIC_START,
+    /**
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for HEIC output formats.</p>
+     *
+     * <p>Type: int64[4*n]</p>
+     *
+     * <p>This tag may appear in:
+     * <ul>
+     *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+     * </ul></p>
+     *
+     * <p>This should correspond to the frame duration when only that
+     * stream is active, with all processing (typically in android.*.mode)
+     * set to either OFF or FAST.</p>
+     * <p>When multiple streams are used in a request, the minimum frame
+     * duration will be max(individual stream min durations).</p>
+     * <p>See ACAMERA_SENSOR_FRAME_DURATION and
+     * ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS for more details about
+     * calculating the max frame rate.</p>
+     *
+     * @see ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS
+     * @see ACAMERA_SENSOR_FRAME_DURATION
+     */
+    ACAMERA_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS =           // int64[4*n]
+            ACAMERA_HEIC_START + 1,
+    /**
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination for HEIC streams.</p>
+     *
+     * <p>Type: int64[4*n]</p>
+     *
+     * <p>This tag may appear in:
+     * <ul>
+     *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+     * </ul></p>
+     *
+     * <p>A stall duration is how much extra time would get added
+     * to the normal minimum frame duration for a repeating request
+     * that has streams with non-zero stall.</p>
+     * <p>This functions similarly to
+     * ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS for HEIC
+     * streams.</p>
+     * <p>All HEIC output stream formats may have a nonzero stall
+     * duration.</p>
+     *
+     * @see ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS
+     */
+    ACAMERA_HEIC_AVAILABLE_HEIC_STALL_DURATIONS =               // int64[4*n]
+            ACAMERA_HEIC_START + 2,
+    ACAMERA_HEIC_END,
+
 } acamera_metadata_tag_t;
 
 /**
@@ -8373,6 +8465,16 @@
 } acamera_metadata_enum_android_distortion_correction_mode_t;
 
 
+// ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS
+typedef enum acamera_metadata_enum_acamera_heic_available_heic_stream_configurations {
+    ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_OUTPUT         = 0,
+
+    ACAMERA_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_INPUT          = 1,
+
+} acamera_metadata_enum_android_heic_available_heic_stream_configurations_t;
+
+
+
 #endif /* __ANDROID_API__ >= 24 */
 
 __END_DECLS
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index b8baec8..b158f8f 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -151,7 +151,7 @@
         c2_status_t status;
         do {
             status = mBase->fetchLinearBlock(capacity, usage, block);
-        } while (status == C2_TIMED_OUT);
+        } while (status == C2_BLOCKING);
         return status;
     }
 
@@ -162,7 +162,7 @@
         c2_status_t status;
         do {
             status = mBase->fetchCircularBlock(capacity, usage, block);
-        } while (status == C2_TIMED_OUT);
+        } while (status == C2_BLOCKING);
         return status;
     }
 
@@ -174,7 +174,7 @@
         do {
             status = mBase->fetchGraphicBlock(width, height, format, usage,
                                               block);
-        } while (status == C2_TIMED_OUT);
+        } while (status == C2_BLOCKING);
         return status;
     }
 
diff --git a/media/codec2/core/include/C2Buffer.h b/media/codec2/core/include/C2Buffer.h
index 2997f6e..c428122 100644
--- a/media/codec2/core/include/C2Buffer.h
+++ b/media/codec2/core/include/C2Buffer.h
@@ -888,6 +888,7 @@
      * \retval C2_OK        the operation was successful
      * \retval C2_NO_MEMORY not enough memory to complete any required allocation
      * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_BLOCKING  the operation is blocked
      * \retval C2_REFUSED   no permission to complete any required allocation
      * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
      * \retval C2_OMITTED   this pool does not support linear blocks
@@ -916,6 +917,7 @@
      * \retval C2_OK        the operation was successful
      * \retval C2_NO_MEMORY not enough memory to complete any required allocation
      * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_BLOCKING  the operation is blocked
      * \retval C2_REFUSED   no permission to complete any required allocation
      * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
      * \retval C2_OMITTED   this pool does not support circular blocks
@@ -946,6 +948,7 @@
      * \retval C2_OK        the operation was successful
      * \retval C2_NO_MEMORY not enough memory to complete any required allocation
      * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_BLOCKING  the operation is blocked
      * \retval C2_REFUSED   no permission to complete any required allocation
      * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller
      *                      error)
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 0357115..fb6edb6 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -597,6 +597,9 @@
     LEVEL_AVC_5,                                ///< AVC (H.264) Level 5
     LEVEL_AVC_5_1,                              ///< AVC (H.264) Level 5.1
     LEVEL_AVC_5_2,                              ///< AVC (H.264) Level 5.2
+    LEVEL_AVC_6,                                ///< AVC (H.264) Level 6
+    LEVEL_AVC_6_1,                              ///< AVC (H.264) Level 6.1
+    LEVEL_AVC_6_2,                              ///< AVC (H.264) Level 6.2
 
     // HEVC (H.265) tiers and levels
     LEVEL_HEVC_MAIN_1 = _C2_PL_HEVC_BASE,       ///< HEVC (H.265) Main Tier Level 1
diff --git a/media/codec2/hidl/1.0/utils/Configurable.cpp b/media/codec2/hidl/1.0/utils/Configurable.cpp
index a35b74c..ec9c170 100644
--- a/media/codec2/hidl/1.0/utils/Configurable.cpp
+++ b/media/codec2/hidl/1.0/utils/Configurable.cpp
@@ -171,17 +171,15 @@
             c2fields,
             mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK);
     hidl_vec<FieldSupportedValuesQueryResult> outFields(inFields.size());
-    {
-        size_t ix = 0;
-        for (const C2FieldSupportedValuesQuery &result : c2fields) {
-            if (!objcpy(&outFields[ix], result)) {
-                ++ix;
-            } else {
-                outFields.resize(ix);
-                c2res = C2_CORRUPTED;
-                LOG(WARNING) << "querySupportedValues -- invalid output params.";
-                break;
-            }
+    size_t dstIx = 0;
+    for (const C2FieldSupportedValuesQuery &result : c2fields) {
+        if (objcpy(&outFields[dstIx], result)) {
+            ++dstIx;
+        } else {
+            outFields.resize(dstIx);
+            c2res = C2_CORRUPTED;
+            LOG(WARNING) << "querySupportedValues -- invalid output params.";
+            break;
         }
     }
     _hidl_cb((Status)c2res, outFields);
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
index d4b973f..d3b37d7 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
@@ -272,7 +272,7 @@
 }
 
 // Set Default config param.
-void setupConfigParam(
+bool setupConfigParam(
     const std::shared_ptr<android::Codec2Client::Component>& component,
     int32_t* bitStreamInfo) {
     std::vector<std::unique_ptr<C2SettingResult>> failures;
@@ -282,8 +282,8 @@
     std::vector<C2Param*> configParam{&sampleRateInfo, &channelCountInfo};
     c2_status_t status =
         component->config(configParam, C2_DONT_BLOCK, &failures);
-    ASSERT_EQ(failures.size(), 0u);
-    ASSERT_EQ(status, C2_OK);
+    if (status == C2_OK && failures.size() == 0u) return true;
+    return false;
 }
 
 // In decoder components, often the input parameters get updated upon
@@ -557,7 +557,11 @@
         ASSERT_NO_FATAL_FAILURE(
             getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
     }
-    setupConfigParam(mComponent, bitStreamInfo);
+    if (!setupConfigParam(mComponent, bitStreamInfo)) {
+        std::cout << "[   WARN   ] Test Skipped \n";
+        return;
+    }
+    ASSERT_EQ(mComponent->start(), C2_OK);
     ALOGV("mURL : %s", mURL);
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
@@ -613,7 +617,6 @@
     description("Test Request for thumbnail");
     if (mDisableTest) return;
 
-    ASSERT_EQ(mComponent->start(), C2_OK);
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
@@ -642,7 +645,11 @@
         ASSERT_NO_FATAL_FAILURE(
             getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
     }
-    setupConfigParam(mComponent, bitStreamInfo);
+    if (!setupConfigParam(mComponent, bitStreamInfo)) {
+        std::cout << "[   WARN   ] Test Skipped \n";
+        return;
+    }
+    ASSERT_EQ(mComponent->start(), C2_OK);
     ALOGV("mURL : %s", mURL);
 
     // request EOS for thumbnail
@@ -711,7 +718,6 @@
     description("Tests Flush calls");
     if (mDisableTest) return;
     typedef std::unique_lock<std::mutex> ULock;
-    ASSERT_EQ(mComponent->start(), C2_OK);
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
@@ -741,7 +747,11 @@
         ASSERT_NO_FATAL_FAILURE(
             getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
     }
-    setupConfigParam(mComponent, bitStreamInfo);
+    if (!setupConfigParam(mComponent, bitStreamInfo)) {
+        std::cout << "[   WARN   ] Test Skipped \n";
+        return;
+    }
+    ASSERT_EQ(mComponent->start(), C2_OK);
     ALOGV("mURL : %s", mURL);
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
@@ -833,8 +843,6 @@
     description("Decode with multiple empty input frames");
     if (mDisableTest) return;
 
-    ASSERT_EQ(mComponent->start(), C2_OK);
-
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
@@ -868,7 +876,19 @@
         frameId++;
     }
     eleInfo.close();
-
+    int32_t bitStreamInfo[2] = {0};
+    if (mCompName == raw) {
+        bitStreamInfo[0] = 8000;
+        bitStreamInfo[1] = 1;
+    } else {
+        ASSERT_NO_FATAL_FAILURE(
+            getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+    }
+    if (!setupConfigParam(mComponent, bitStreamInfo)) {
+        std::cout << "[   WARN   ] Test Skipped \n";
+        return;
+    }
+    ASSERT_EQ(mComponent->start(), C2_OK);
     ALOGV("mURL : %s", mURL);
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
index 5d66ee5..a74d43e 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
@@ -219,7 +219,7 @@
 }
 
 // Set Default config param.
-void setupConfigParam(
+bool setupConfigParam(
     const std::shared_ptr<android::Codec2Client::Component>& component,
     int32_t nChannels, int32_t nSampleRate) {
     std::vector<std::unique_ptr<C2SettingResult>> failures;
@@ -229,8 +229,8 @@
     std::vector<C2Param*> configParam{&sampleRateInfo, &channelCountInfo};
     c2_status_t status =
         component->config(configParam, C2_DONT_BLOCK, &failures);
-    ASSERT_EQ(failures.size(), 0u);
-    ASSERT_EQ(status, C2_OK);
+    if (status == C2_OK && failures.size() == 0u) return true;
+    return false;
 }
 
 // LookUpTable of clips and metadata for component testing
@@ -358,7 +358,6 @@
 TEST_F(Codec2AudioEncHidlTest, EncodeTest) {
     ALOGV("EncodeTest");
     if (mDisableTest) return;
-    ASSERT_EQ(mComponent->start(), C2_OK);
     char mURL[512];
     strcpy(mURL, gEnv->getRes().c_str());
     GetURLForComponent(mCompName, mURL);
@@ -396,7 +395,11 @@
         default:
             ASSERT_TRUE(false);
     }
-    setupConfigParam(mComponent, nChannels, nSampleRate);
+    if (!setupConfigParam(mComponent, nChannels, nSampleRate)) {
+        std::cout << "[   WARN   ] Test Skipped \n";
+        return;
+    }
+    ASSERT_EQ(mComponent->start(), C2_OK);
     std::ifstream eleStream;
     uint32_t numFrames = 128;
     eleStream.open(mURL, std::ifstream::binary);
@@ -469,7 +472,6 @@
 TEST_F(Codec2AudioEncHidlTest, FlushTest) {
     description("Test Request for flush");
     if (mDisableTest) return;
-    ASSERT_EQ(mComponent->start(), C2_OK);
 
     typedef std::unique_lock<std::mutex> ULock;
     char mURL[512];
@@ -510,7 +512,13 @@
         default:
             ASSERT_TRUE(false);
     }
-    setupConfigParam(mComponent, nChannels, nSampleRate);
+
+    if (!setupConfigParam(mComponent, nChannels, nSampleRate)) {
+        std::cout << "[   WARN   ] Test Skipped \n";
+        return;
+    }
+    ASSERT_EQ(mComponent->start(), C2_OK);
+
     std::ifstream eleStream;
     uint32_t numFramesFlushed = 30;
     uint32_t numFrames = 128;
diff --git a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
index 64a458c..31da111 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
@@ -107,22 +107,24 @@
         component->config(configParam, C2_DONT_BLOCK, &failures);
         ASSERT_EQ(failures.size(), 0u);
     }
-    framesReceived++;
-    eos = (work->worklets.front()->output.flags &
-           C2FrameData::FLAG_END_OF_STREAM) != 0;
-    auto frameIndexIt = std::find(flushedIndices.begin(), flushedIndices.end(),
-                                  work->input.ordinal.frameIndex.peeku());
-    ALOGV("WorkDone: frameID received %d",
-          (int)work->worklets.front()->output.ordinal.frameIndex.peeku());
-    work->input.buffers.clear();
-    work->worklets.clear();
-    {
-        typedef std::unique_lock<std::mutex> ULock;
-        ULock l(queueLock);
-        workQueue.push_back(std::move(work));
-        if (!flushedIndices.empty()) {
-            flushedIndices.erase(frameIndexIt);
+    if (work->worklets.front()->output.flags != C2FrameData::FLAG_INCOMPLETE) {
+        framesReceived++;
+        eos = (work->worklets.front()->output.flags &
+               C2FrameData::FLAG_END_OF_STREAM) != 0;
+        auto frameIndexIt = std::find(flushedIndices.begin(), flushedIndices.end(),
+                                      work->input.ordinal.frameIndex.peeku());
+        ALOGV("WorkDone: frameID received %d",
+              (int)work->worklets.front()->output.ordinal.frameIndex.peeku());
+        work->input.buffers.clear();
+        work->worklets.clear();
+        {
+            typedef std::unique_lock<std::mutex> ULock;
+            ULock l(queueLock);
+            workQueue.push_back(std::move(work));
+            if (!flushedIndices.empty()) {
+                flushedIndices.erase(frameIndexIt);
+            }
+            queueCondition.notify_all();
         }
-        queueCondition.notify_all();
     }
 }
\ No newline at end of file
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
index 8585c87..95d1b72 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
@@ -118,7 +118,6 @@
         }
         mEos = false;
         mCsd = false;
-        mConfig = false;
         mFramesReceived = 0;
         mFailedWorkReceived = 0;
         if (mCompName == unknown_comp) mDisableTest = true;
@@ -134,7 +133,7 @@
         Super::TearDown();
     }
 
-    void setupConfigParam(int32_t nWidth, int32_t nHeight);
+    bool setupConfigParam(int32_t nWidth, int32_t nHeight);
 
     // callback function to process onWorkDone received by Listener
     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
@@ -228,14 +227,14 @@
 }
 
 // Set Default config param.
-void Codec2VideoEncHidlTest::setupConfigParam(int32_t nWidth, int32_t nHeight) {
+bool Codec2VideoEncHidlTest::setupConfigParam(int32_t nWidth, int32_t nHeight) {
     std::vector<std::unique_ptr<C2SettingResult>> failures;
     C2VideoSizeStreamTuning::input inputSize(0u, nWidth, nHeight);
     std::vector<C2Param*> configParam{&inputSize};
     c2_status_t status =
         mComponent->config(configParam, C2_DONT_BLOCK, &failures);
-    if (failures.size() == 0u ) mConfig = true;
-    ASSERT_EQ(status, C2_OK);
+    if (status == C2_OK && failures.size() == 0u) return true;
+    return false;
 }
 
 // LookUpTable of clips for component testing
@@ -360,8 +359,7 @@
     ASSERT_EQ(eleStream.is_open(), true) << mURL << " file not found";
     ALOGV("mURL : %s", mURL);
 
-    setupConfigParam(nWidth, nHeight);
-    if (!mConfig) {
+    if (!setupConfigParam(nWidth, nHeight)) {
         std::cout << "[   WARN   ] Test Skipped \n";
         return;
     }
@@ -439,7 +437,6 @@
 TEST_F(Codec2VideoEncHidlTest, FlushTest) {
     description("Test Request for flush");
     if (mDisableTest) return;
-    ASSERT_EQ(mComponent->start(), C2_OK);
 
     typedef std::unique_lock<std::mutex> ULock;
     char mURL[512];
@@ -447,7 +444,12 @@
     int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT;
     strcpy(mURL, gEnv->getRes().c_str());
     GetURLForComponent(mURL);
-    setupConfigParam(nWidth, nHeight);
+
+    if (!setupConfigParam(nWidth, nHeight)) {
+        std::cout << "[   WARN   ] Test Skipped \n";
+        return;
+    }
+    ASSERT_EQ(mComponent->start(), C2_OK);
 
     // Setting default configuration
     mFlushedIndices.clear();
@@ -522,12 +524,16 @@
 TEST_F(Codec2VideoEncHidlTest, InvalidBufferTest) {
     description("Tests feeding larger/smaller input buffer");
     if (mDisableTest) return;
-    ASSERT_EQ(mComponent->start(), C2_OK);
 
     std::ifstream eleStream;
     int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH / 2;
     int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT / 2;
-    setupConfigParam(nWidth, nHeight);
+
+    if (!setupConfigParam(nWidth, nHeight)) {
+        std::cout << "[   WARN   ] Test Skipped \n";
+        return;
+    }
+    ASSERT_EQ(mComponent->start(), C2_OK);
 
     ASSERT_NO_FATAL_FAILURE(
         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
@@ -579,10 +585,12 @@
     int32_t nWidth = GetParam().first;
     int32_t nHeight = GetParam().second;
     ALOGD("Trying encode for width %d height %d", nWidth, nHeight);
-    mConfig = false;
     mEos = false;
-    setupConfigParam(nWidth, nHeight);
-    if (!mConfig) return;
+
+    if (!setupConfigParam(nWidth, nHeight)) {
+        std::cout << "[   WARN   ] Test Skipped \n";
+        return;
+    }
     ASSERT_EQ(mComponent->start(), C2_OK);
 
     ASSERT_NO_FATAL_FAILURE(
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index bc22045..dce3222 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -772,8 +772,16 @@
         }
 
         std::vector<std::unique_ptr<C2Param>> configUpdate;
+        // NOTE: We used to ignore "video-bitrate" at configure; replicate
+        //       the behavior here.
+        sp<AMessage> sdkParams = msg;
+        int32_t videoBitrate;
+        if (sdkParams->findInt32(PARAMETER_KEY_VIDEO_BITRATE, &videoBitrate)) {
+            sdkParams = msg->dup();
+            sdkParams->removeEntryAt(sdkParams->findEntryByName(PARAMETER_KEY_VIDEO_BITRATE));
+        }
         status_t err = config->getConfigUpdateFromSdkParams(
-                comp, msg, Config::IS_CONFIG, C2_DONT_BLOCK, &configUpdate);
+                comp, sdkParams, Config::IS_CONFIG, C2_DONT_BLOCK, &configUpdate);
         if (err != OK) {
             ALOGW("failed to convert configuration to c2 params");
         }
@@ -1415,11 +1423,7 @@
     (void)mChannel->requestInitialInputBuffers();
 }
 
-void CCodec::signalSetParameters(const sp<AMessage> &params) {
-    setParameters(params);
-}
-
-void CCodec::setParameters(const sp<AMessage> &params) {
+void CCodec::signalSetParameters(const sp<AMessage> &msg) {
     std::shared_ptr<Codec2Client::Component> comp;
     auto checkState = [this, &comp] {
         Mutexed<State>::Locked state(mState);
@@ -1433,6 +1437,15 @@
         return;
     }
 
+    // NOTE: We used to ignore "bitrate" at setParameters; replicate
+    //       the behavior here.
+    sp<AMessage> params = msg;
+    int32_t bitrate;
+    if (params->findInt32(KEY_BIT_RATE, &bitrate)) {
+        params = msg->dup();
+        params->removeEntryAt(params->findEntryByName(KEY_BIT_RATE));
+    }
+
     Mutexed<Config>::Locked config(mConfig);
 
     /**
diff --git a/media/codec2/sfplugin/CCodec.h b/media/codec2/sfplugin/CCodec.h
index ba5f5f3..b0b3c4f 100644
--- a/media/codec2/sfplugin/CCodec.h
+++ b/media/codec2/sfplugin/CCodec.h
@@ -102,7 +102,6 @@
     void createInputSurface();
     void setInputSurface(const sp<PersistentSurface> &surface);
     status_t setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface);
-    void setParameters(const sp<AMessage> &params);
 
     void setDeadline(
             const TimePoint &now,
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 6842fa5..ff2419d 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -255,6 +255,34 @@
         mSkipCutBuffer = scb;
     }
 
+    void handleImageData(const sp<Codec2Buffer> &buffer) {
+        sp<ABuffer> imageDataCandidate = buffer->getImageData();
+        if (imageDataCandidate == nullptr) {
+            return;
+        }
+        sp<ABuffer> imageData;
+        if (!mFormat->findBuffer("image-data", &imageData)
+                || imageDataCandidate->size() != imageData->size()
+                || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
+            ALOGD("[%s] updating image-data", mName);
+            sp<AMessage> newFormat = dupFormat();
+            newFormat->setBuffer("image-data", imageDataCandidate);
+            MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
+            if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
+                int32_t stride = img->mPlane[0].mRowInc;
+                newFormat->setInt32(KEY_STRIDE, stride);
+                ALOGD("[%s] updating stride = %d", mName, stride);
+                if (img->mNumPlanes > 1 && stride > 0) {
+                    int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
+                    newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
+                    ALOGD("[%s] updating vstride = %d", mName, vstride);
+                }
+            }
+            setFormat(newFormat);
+            buffer->setFormat(newFormat);
+        }
+    }
+
 protected:
     sp<SkipCutBuffer> mSkipCutBuffer;
 
@@ -1152,6 +1180,7 @@
             return WOULD_BLOCK;
         }
         submit(c2Buffer);
+        handleImageData(c2Buffer);
         *clientBuffer = c2Buffer;
         ALOGV("[%s] grabbed buffer %zu", mName, *index);
         return OK;
@@ -1250,6 +1279,7 @@
         }
         newBuffer->setFormat(mFormat);
         *index = mImpl.assignSlot(newBuffer);
+        handleImageData(newBuffer);
         *clientBuffer = newBuffer;
         ALOGV("[%s] registered buffer %zu", mName, *index);
         return OK;
@@ -1557,6 +1587,7 @@
       mCCodecCallback(callback),
       mNumInputSlots(kSmoothnessFactor),
       mNumOutputSlots(kSmoothnessFactor),
+      mDelay(0),
       mFrameIndex(0u),
       mFirstValidFrameIndex(0u),
       mMetaMode(MODE_NONE),
@@ -2104,11 +2135,13 @@
         }
     }
 
-    mNumInputSlots =
-        (inputDelay ? inputDelay.value : 0) +
-        (pipelineDelay ? pipelineDelay.value : 0) +
-        kSmoothnessFactor;
-    mNumOutputSlots = (outputDelay ? outputDelay.value : 0) + kSmoothnessFactor;
+    uint32_t inputDelayValue = inputDelay ? inputDelay.value : 0;
+    uint32_t pipelineDelayValue = pipelineDelay ? pipelineDelay.value : 0;
+    uint32_t outputDelayValue = outputDelay ? outputDelay.value : 0;
+
+    mNumInputSlots = inputDelayValue + pipelineDelayValue + kSmoothnessFactor;
+    mNumOutputSlots = outputDelayValue + kSmoothnessFactor;
+    mDelay = inputDelayValue + pipelineDelayValue + outputDelayValue;
 
     // TODO: get this from input format
     bool secure = mComponent->getName().find(".secure") != std::string::npos;
@@ -2397,9 +2430,9 @@
 
     {
         Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
-        watcher->inputDelay(inputDelay ? inputDelay.value : 0)
-                .pipelineDelay(pipelineDelay ? pipelineDelay.value : 0)
-                .outputDelay(outputDelay ? outputDelay.value : 0)
+        watcher->inputDelay(inputDelayValue)
+                .pipelineDelay(pipelineDelayValue)
+                .outputDelay(outputDelayValue)
                 .smoothnessFactor(kSmoothnessFactor);
         watcher->flush();
     }
@@ -2816,7 +2849,11 @@
 }
 
 PipelineWatcher::Clock::duration CCodecBufferChannel::elapsed() {
-    return mPipelineWatcher.lock()->elapsed(PipelineWatcher::Clock::now());
+    // When client pushed EOS, we want all the work to be done quickly.
+    // Otherwise, component may have stalled work due to input starvation up to
+    // the sum of the delay in the pipeline.
+    size_t n = mInputMetEos ? 0 : mDelay;
+    return mPipelineWatcher.lock()->elapsed(PipelineWatcher::Clock::now(), n);
 }
 
 void CCodecBufferChannel::setMetaMode(MetaMode mode) {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 9dccab8..9ce886a 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -236,6 +236,7 @@
 
     size_t mNumInputSlots;
     size_t mNumOutputSlots;
+    size_t mDelay;
 
     Mutexed<std::unique_ptr<InputBuffers>> mInputBuffers;
     Mutexed<std::list<sp<ABuffer>>> mFlushedConfigs;
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 2dec42e..13b63c9 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -84,17 +84,7 @@
 }
 
 void Codec2Buffer::setImageData(const sp<ABuffer> &imageData) {
-    meta()->setBuffer("image-data", imageData);
-    format()->setBuffer("image-data", imageData);
-    MediaImage2 *img = (MediaImage2*)imageData->data();
-    if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
-        int32_t stride = img->mPlane[0].mRowInc;
-        format()->setInt32(KEY_STRIDE, stride);
-        if (img->mNumPlanes > 1 && stride > 0) {
-            int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
-            format()->setInt32(KEY_SLICE_HEIGHT, vstride);
-        }
-    }
+    mImageData = imageData;
 }
 
 // LocalLinearBuffer
@@ -546,7 +536,6 @@
     : Codec2Buffer(format, buffer),
       mView(view),
       mBlock(block),
-      mImageData(imageData),
       mWrapped(wrapped) {
     setImageData(imageData);
 }
@@ -683,9 +672,7 @@
       mView(std::move(view)),
       mBufferRef(buffer),
       mWrapped(wrapped) {
-    if (imageData != nullptr) {
-        setImageData(imageData);
-    }
+    setImageData(imageData);
 }
 
 std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
diff --git a/media/codec2/sfplugin/Codec2Buffer.h b/media/codec2/sfplugin/Codec2Buffer.h
index 481975f..dd618aa 100644
--- a/media/codec2/sfplugin/Codec2Buffer.h
+++ b/media/codec2/sfplugin/Codec2Buffer.h
@@ -23,6 +23,7 @@
 #include <android/hardware/cas/native/1.0/types.h>
 #include <binder/IMemory.h>
 #include <media/hardware/VideoAPI.h>
+#include <media/stagefright/foundation/ABuffer.h>
 #include <media/MediaCodecBuffer.h>
 #include <media/ICrypto.h>
 
@@ -85,6 +86,8 @@
         return false;
     }
 
+    sp<ABuffer> getImageData() const { return mImageData; }
+
 protected:
     /**
      * canCopy() implementation for linear buffers.
@@ -100,6 +103,8 @@
      * sets MediaImage data for flexible graphic buffers
      */
     void setImageData(const sp<ABuffer> &imageData);
+
+    sp<ABuffer> mImageData;
 };
 
 /**
@@ -239,7 +244,6 @@
 
     C2GraphicView mView;
     std::shared_ptr<C2GraphicBlock> mBlock;
-    sp<ABuffer> mImageData;
     const bool mWrapped;
 };
 
diff --git a/media/codec2/sfplugin/PipelineWatcher.cpp b/media/codec2/sfplugin/PipelineWatcher.cpp
index fe0a2c8..cdcc41b 100644
--- a/media/codec2/sfplugin/PipelineWatcher.cpp
+++ b/media/codec2/sfplugin/PipelineWatcher.cpp
@@ -127,19 +127,21 @@
 }
 
 PipelineWatcher::Clock::duration PipelineWatcher::elapsed(
-        const PipelineWatcher::Clock::time_point &now) const {
-    return std::accumulate(
-            mFramesInPipeline.begin(),
-            mFramesInPipeline.end(),
-            Clock::duration::zero(),
-            [&now](const Clock::duration &current,
-                   const decltype(mFramesInPipeline)::value_type &value) {
-                Clock::duration elapsed = now - value.second.queuedAt;
-                ALOGV("elapsed: frameIndex = %llu elapsed = %lldms",
-                      (unsigned long long)value.first,
-                      std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count());
-                return current > elapsed ? current : elapsed;
-            });
+        const PipelineWatcher::Clock::time_point &now, size_t n) const {
+    if (mFramesInPipeline.size() <= n) {
+        return Clock::duration::zero();
+    }
+    std::vector<Clock::duration> durations;
+    for (const decltype(mFramesInPipeline)::value_type &value : mFramesInPipeline) {
+        Clock::duration elapsed = now - value.second.queuedAt;
+        ALOGV("elapsed: frameIndex = %llu elapsed = %lldms",
+              (unsigned long long)value.first,
+              std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count());
+        durations.push_back(elapsed);
+    }
+    nth_element(durations.begin(), durations.end(), durations.begin() + n,
+                std::greater<Clock::duration>());
+    return durations[n];
 }
 
 }  // namespace android
diff --git a/media/codec2/sfplugin/PipelineWatcher.h b/media/codec2/sfplugin/PipelineWatcher.h
index ce82298..1c127e4 100644
--- a/media/codec2/sfplugin/PipelineWatcher.h
+++ b/media/codec2/sfplugin/PipelineWatcher.h
@@ -54,7 +54,7 @@
     void flush();
 
     bool pipelineFull() const;
-    Clock::duration elapsed(const Clock::time_point &now) const;
+    Clock::duration elapsed(const Clock::time_point &now, size_t n) const;
 
 private:
     uint32_t mInputDelay;
diff --git a/media/codec2/sfplugin/SkipCutBuffer.cpp b/media/codec2/sfplugin/SkipCutBuffer.cpp
index 5762440..8d1de65 100644
--- a/media/codec2/sfplugin/SkipCutBuffer.cpp
+++ b/media/codec2/sfplugin/SkipCutBuffer.cpp
@@ -20,7 +20,7 @@
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/SkipCutBuffer.h>
+#include "SkipCutBuffer.h"
 
 namespace android {
 
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index c369e16..0a6a717 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -65,7 +65,9 @@
     { C2Config::LEVEL_AVC_5,    AVCLevel5 },
     { C2Config::LEVEL_AVC_5_1,  AVCLevel51 },
     { C2Config::LEVEL_AVC_5_2,  AVCLevel52 },
-
+    { C2Config::LEVEL_AVC_6,    AVCLevel6 },
+    { C2Config::LEVEL_AVC_6_1,  AVCLevel61 },
+    { C2Config::LEVEL_AVC_6_2,  AVCLevel62 },
 };
 
 ALookup<C2Config::profile_t, int32_t> sAvcProfiles = {
diff --git a/media/codec2/vndk/C2Config.cpp b/media/codec2/vndk/C2Config.cpp
index 8a27088..34680a7 100644
--- a/media/codec2/vndk/C2Config.cpp
+++ b/media/codec2/vndk/C2Config.cpp
@@ -186,6 +186,9 @@
         { "avc-5", C2Config::LEVEL_AVC_5 },
         { "avc-5.1", C2Config::LEVEL_AVC_5_1 },
         { "avc-5.2", C2Config::LEVEL_AVC_5_2 },
+        { "avc-6", C2Config::LEVEL_AVC_6 },
+        { "avc-6.1", C2Config::LEVEL_AVC_6_1 },
+        { "avc-6.2", C2Config::LEVEL_AVC_6_2 },
         { "hevc-main-1", C2Config::LEVEL_HEVC_MAIN_1 },
         { "hevc-main-2", C2Config::LEVEL_HEVC_MAIN_2 },
         { "hevc-main-2.1", C2Config::LEVEL_HEVC_MAIN_2_1 },
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 7bf3d64..41a5b3f 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -207,12 +207,16 @@
         // dequeueBuffer returns flag.
         if (!transStatus.isOk() || status < android::OK) {
             ALOGD("cannot dequeue buffer %d", status);
-            if (transStatus.isOk() && status == android::INVALID_OPERATION) {
-              // Too many buffer dequeued. retrying after some time is required.
-              return C2_TIMED_OUT;
-            } else {
-              return C2_BAD_VALUE;
+            if (transStatus.isOk()) {
+                if (status == android::INVALID_OPERATION ||
+                    status == android::TIMED_OUT ||
+                    status == android::WOULD_BLOCK) {
+                    // Dequeue buffer is blocked temporarily. Retrying is
+                    // required.
+                    return C2_BLOCKING;
+                }
             }
+            return C2_BAD_VALUE;
         }
         ALOGV("dequeued a buffer successfully");
         native_handle_t* nh = nullptr;
@@ -227,7 +231,7 @@
             if (status == -ETIME) {
                 // fence is not signalled yet.
                 (void)mProducer->cancelBuffer(slot, fenceHandle).isOk();
-                return C2_TIMED_OUT;
+                return C2_BLOCKING;
             }
             if (status != android::NO_ERROR) {
                 ALOGD("buffer fence wait error %d", status);
@@ -353,14 +357,14 @@
                 return C2_OK;
             }
             c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block);
-            if (status == C2_TIMED_OUT) {
+            if (status == C2_BLOCKING) {
                 lock.unlock();
                 ::usleep(kMaxIgbpRetryDelayUs);
                 continue;
             }
             return status;
         }
-        return C2_TIMED_OUT;
+        return C2_BLOCKING;
     }
 
     void setRenderCallback(const OnRenderCallback &renderCallback) {
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index beddad0..9d183d4 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -150,6 +150,7 @@
 
     mMeta = AMediaFormat_new();
     MakeAACCodecSpecificData(mMeta, profile, sf_index, channel);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_AAC_PROFILE, profile + 1);
 
     off64_t streamSize, numFrames = 0;
     size_t frameSize = 0;
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index ac54116..4b4d767 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -2236,7 +2236,29 @@
             *offset += chunk_size;
             break;
         }
+        case FOURCC("av1C"):
+        {
+            auto buffer = heapbuffer<uint8_t>(chunk_data_size);
 
+            if (buffer.get() == NULL) {
+                ALOGE("b/28471206");
+                return NO_MEMORY;
+            }
+
+            if (mDataSource->readAt(
+                        data_offset, buffer.get(), chunk_data_size) < chunk_data_size) {
+                return ERROR_IO;
+            }
+
+            if (mLastTrack == NULL)
+                return ERROR_MALFORMED;
+
+            AMediaFormat_setBuffer(mLastTrack->meta,
+                   AMEDIAFORMAT_KEY_CSD_0, buffer.get(), chunk_data_size);
+
+            *offset += chunk_size;
+            break;
+        }
         case FOURCC("d263"):
         {
             *offset += chunk_size;
@@ -2663,19 +2685,40 @@
         case FOURCC("ac-3"):
         {
             *offset += chunk_size;
-            return parseAC3SpecificBox(data_offset);
+            // bypass ac-3 if parse fail
+            if (parseAC3SpecificBox(data_offset) != OK) {
+                if (mLastTrack != NULL) {
+                    ALOGW("Fail to parse ac-3");
+                    mLastTrack->skipTrack = true;
+                }
+            }
+            return OK;
         }
 
         case FOURCC("ec-3"):
         {
             *offset += chunk_size;
-            return parseEAC3SpecificBox(data_offset);
+            // bypass ec-3 if parse fail
+            if (parseEAC3SpecificBox(data_offset) != OK) {
+                if (mLastTrack != NULL) {
+                    ALOGW("Fail to parse ec-3");
+                    mLastTrack->skipTrack = true;
+                }
+            }
+            return OK;
         }
 
         case FOURCC("ac-4"):
         {
             *offset += chunk_size;
-            return parseAC4SpecificBox(data_offset);
+            // bypass ac-4 if parse fail
+            if (parseAC4SpecificBox(data_offset) != OK) {
+                if (mLastTrack != NULL) {
+                    ALOGW("Fail to parse ac-4");
+                    mLastTrack->skipTrack = true;
+                }
+            }
+            return OK;
         }
 
         case FOURCC("ftyp"):
@@ -3972,6 +4015,18 @@
         if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
             itemTable = mItemTable;
         }
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
+        void *data;
+        size_t size;
+        if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
+            return NULL;
+        }
+
+        const uint8_t *ptr = (const uint8_t *)data;
+
+        if (size < 5 || ptr[0] != 0x81) {  // configurationVersion == 1
+            return NULL;
+        }
     }
 
     if (track->has_elst and !strncasecmp("video/", mime, 6) and track->elst_media_time > 0) {
@@ -4005,6 +4060,10 @@
         if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_HEVC, &data, &size)) {
             return ERROR_MALFORMED;
         }
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
+        if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
+            return ERROR_MALFORMED;
+        }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
             || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2)
             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
@@ -5621,10 +5680,10 @@
             }
 
             if (isMalFormed) {
-                ALOGE("Video is malformed");
-                mBuffer->release();
-                mBuffer = NULL;
-                return AMEDIA_ERROR_MALFORMED;
+                //if nallength abnormal,ignore it.
+                ALOGW("abnormal nallength, ignore this NAL");
+                srcOffset = size;
+                break;
             }
 
             if (nalLength == 0) {
@@ -6214,6 +6273,7 @@
 
 static const char *extensions[] = {
     "3g2",
+    "3ga",
     "3gp",
     "3gpp",
     "3gpp2",
@@ -6222,6 +6282,7 @@
     "m4v",
     "mov",
     "mp4",
+    "qt",
     NULL
 };
 
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index ba40690..d99493d 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -364,7 +364,13 @@
             return OK;
         }
 
-        ++*pageOffset;
+        // see how far ahead to skip; avoid some fruitless comparisons
+        unsigned int i;
+        for (i = 1; i < 4 ; i++) {
+            if (signature[i] == 'O')
+                break;
+        }
+        *pageOffset += i;
     }
 }
 
@@ -1382,6 +1388,7 @@
 static const char *extensions[] = {
     "oga",
     "ogg",
+    "opus",
     NULL
 };
 
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 75d425f..6578156 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -36,8 +36,11 @@
 #include "LoopbackAnalyzer.h"
 #include "../../utils/AAudioExampleUtils.h"
 
-// V0.4.00 = rectify and low-pass filter the echos, use auto-correlation on entire echo
-#define APP_VERSION             "0.4.00"
+// V0.4.00 = rectify and low-pass filter the echos, auto-correlate entire echo
+// V0.4.01 = add -h hang option
+//           fix -n option to set output buffer for -tm
+//           plot first glitch
+#define APP_VERSION             "0.4.01"
 
 // Tag for machine readable results as property = value pairs
 #define RESULT_TAG              "RESULT: "
@@ -396,7 +399,7 @@
     int32_t               requestedInputCapacity     = AAUDIO_UNSPECIFIED;
     aaudio_performance_mode_t inputPerformanceLevel  = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
 
-    int32_t               outputFramesPerBurst = 0;
+    int32_t               outputFramesPerBurst       = 0;
 
     aaudio_format_t       actualOutputFormat         = AAUDIO_FORMAT_INVALID;
     int32_t               actualSampleRate           = 0;
@@ -476,6 +479,8 @@
     int32_t timeMillis = 0;
     int32_t recordingDuration = std::min(60 * 5, requestedDuration);
 
+    int32_t requestedOutputBursts = argParser.getNumberOfBursts();
+
     switch(testMode) {
         case TEST_SINE_MAGNITUDE:
             loopbackData.loopbackProcessor = &loopbackData.sineAnalyzer;
@@ -541,20 +546,19 @@
     }
     inputStream = loopbackData.inputStream = recorder.getStream();
 
-    argParser.compareWithStream(inputStream);
-
     {
         int32_t actualCapacity = AAudioStream_getBufferCapacityInFrames(inputStream);
         (void) AAudioStream_setBufferSizeInFrames(inputStream, actualCapacity);
 
-        if (testMode == TEST_SINE_MAGNITUDE) {
+        if (testMode == TEST_SINE_MAGNITUDE
+                && requestedOutputBursts == AAUDIO_UNSPECIFIED) {
             result = AAudioStream_setBufferSizeInFrames(outputStream, actualCapacity);
             if (result < 0) {
                 fprintf(stderr, "ERROR -  AAudioStream_setBufferSizeInFrames(output) returned %d\n",
                         result);
                 goto finish;
             } else {
-                printf("Output buffer size set to match input capacity = %d frames.\n", result);
+                printf("Output buffer size set to match input capacity = %d frames!\n", result);
             }
         }
 
@@ -565,6 +569,8 @@
         }
     }
 
+    argParser.compareWithStream(inputStream);
+
     // ------- Setup loopbackData -----------------------------
     loopbackData.actualInputFormat = AAudioStream_getFormat(inputStream);
 
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 1645986..4373fa9 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -32,8 +32,6 @@
 
 // Arbitrary period for glitches
 #define FORCED_UNDERRUN_PERIOD_FRAMES    (2 * 48000)
-// How long to sleep in a callback to cause an intentional glitch. For testing.
-#define FORCED_UNDERRUN_SLEEP_MICROS     (10 * 1000)
 
 #define MAX_TIMESTAMPS                   16
 
@@ -275,7 +273,7 @@
 
     int                scheduler = 0;
     bool               schedulerChecked = false;
-    bool               forceUnderruns = false;
+    int32_t            hangTimeMSec = 0;
 
     AAudioSimplePlayer simplePlayer;
     int32_t            callbackCount = 0;
@@ -327,10 +325,12 @@
         sineData->setupSineSweeps();
     }
 
-    if (sineData->forceUnderruns) {
+    if (sineData->hangTimeMSec > 0) {
         if (sineData->framesTotal > sineData->nextFrameToGlitch) {
-            usleep(FORCED_UNDERRUN_SLEEP_MICROS);
-            printf("Simulate glitch at %lld\n", (long long) sineData->framesTotal);
+            usleep(sineData->hangTimeMSec * 1000);
+            printf("Hang callback at %lld frames for %d msec\n",
+                    (long long) sineData->framesTotal,
+                   sineData->hangTimeMSec);
             sineData->nextFrameToGlitch += FORCED_UNDERRUN_PERIOD_FRAMES;
         }
     }
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index 7a48153..2b05f10 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -26,11 +26,14 @@
 #include <string.h>
 #include <time.h>
 #include <aaudio/AAudio.h>
+
 #include "AAudioExampleUtils.h"
 #include "AAudioSimplePlayer.h"
 #include "AAudioArgsParser.h"
 
-#define APP_VERSION  "0.1.5"
+#define APP_VERSION  "0.1.6"
+
+constexpr int32_t kDefaultHangTimeMSec = 10;
 
 /**
  * Open stream, play some sine waves, then close the stream.
@@ -41,7 +44,7 @@
 static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser,
                                          int32_t loopCount,
                                          int32_t prefixToneMsec,
-                                         bool forceUnderruns)
+                                         int32_t hangTimeMSec)
 {
     SineThreadedData_t myData;
     AAudioSimplePlayer &player = myData.simplePlayer;
@@ -53,10 +56,12 @@
     printf("----------------------- run complete test --------------------------\n");
     myData.schedulerChecked = false;
     myData.callbackCount = 0;
-    myData.forceUnderruns = forceUnderruns; // test AAudioStream_getXRunCount()
+    myData.hangTimeMSec = hangTimeMSec; // test AAudioStream_getXRunCount()
 
     result = player.open(argParser,
-                         SimplePlayerDataCallbackProc, SimplePlayerErrorCallbackProc, &myData);
+                         SimplePlayerDataCallbackProc,
+                         SimplePlayerErrorCallbackProc,
+                         &myData);
     if (result != AAUDIO_OK) {
         fprintf(stderr, "ERROR -  player.open() returned %s\n",
                 AAudio_convertResultToText(result));
@@ -115,12 +120,17 @@
             int64_t millis =
                     (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
             result = myData.waker.get();
+            const int32_t framesWritten = (int32_t) AAudioStream_getFramesWritten(player.getStream());
+            const int32_t framesRead = (int32_t) AAudioStream_getFramesRead(player.getStream());
+            const int32_t xruns = AAudioStream_getXRunCount(player.getStream());
             printf(" waker result = %d, at %6d millis"
-                           ", second = %3d, framesWritten = %8d, underruns = %d\n",
+                           ", second = %3d, frames written %8d - read %8d = %8d, underruns = %d\n",
                    result, (int) millis,
                    second,
-                   (int) AAudioStream_getFramesWritten(player.getStream()),
-                   (int) AAudioStream_getXRunCount(player.getStream()));
+                   framesWritten,
+                   framesRead,
+                   framesWritten - framesRead,
+                   xruns);
             if (result != AAUDIO_OK) {
                 disconnected = (result == AAUDIO_ERROR_DISCONNECTED);
                 bailOut = true;
@@ -210,7 +220,9 @@
     AAudioArgsParser::usage();
     printf("      -l{count} loopCount start/stop, every other one is silent\n");
     printf("      -t{msec}  play a high pitched tone at the beginning\n");
-    printf("      -z        force periodic underruns by sleeping in callback\n");
+    printf("      -h{msec}  force periodic underruns by hanging in callback\n");
+    printf("                If no value specified then %d used.\n",
+            kDefaultHangTimeMSec);
 }
 
 int main(int argc, const char **argv)
@@ -219,13 +231,14 @@
     aaudio_result_t    result;
     int32_t            loopCount = 1;
     int32_t            prefixToneMsec = 0;
-    bool               forceUnderruns = false;
+    int32_t            hangTimeMSec = 0;
 
     // Make printf print immediately so that debug info is not stuck
     // in a buffer if we hang or crash.
     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
 
-    printf("%s - Play a sine sweep using an AAudio callback V%s\n", argv[0], APP_VERSION);
+    printf("%s - Play a sine sweep using an AAudio callback V%s\n",
+        argv[0], APP_VERSION);
 
     for (int i = 1; i < argc; i++) {
         const char *arg = argv[i];
@@ -240,8 +253,10 @@
                     case 't':
                         prefixToneMsec = atoi(&arg[2]);
                         break;
-                    case 'z':
-                        forceUnderruns = true;  // Zzzzzzz
+                    case 'h':
+                        hangTimeMSec = (arg[2]) // value specified?
+                                ? atoi(&arg[2])
+                                : kDefaultHangTimeMSec;
                         break;
                     default:
                         usage();
@@ -257,7 +272,8 @@
     }
 
     // Keep looping until we can complete the test without disconnecting.
-    while((result = testOpenPlayClose(argParser, loopCount, prefixToneMsec, forceUnderruns))
+    while((result = testOpenPlayClose(argParser, loopCount,
+            prefixToneMsec, hangTimeMSec))
             == AAUDIO_ERROR_DISCONNECTED);
 
     return (result) ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index bd10d67..b111b78 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -74,6 +74,7 @@
         "libnblog",
         "libprocessgroup",
         "libutils",
+        "libvibrator",
     ],
     export_shared_lib_headers: ["libbinder"],
 
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 8afb1cc..baa1469 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1361,14 +1361,12 @@
         ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
         return BAD_VALUE;
     }
-    {
-        AutoMutex lock(mLock);
-        if (mDeviceCallback.unsafe_get() != callback.get()) {
-            ALOGW("%s(%d): removing different callback!", __func__, mPortId);
-            return INVALID_OPERATION;
-        }
-        mDeviceCallback.clear();
+    AutoMutex lock(mLock);
+    if (mDeviceCallback.unsafe_get() != callback.get()) {
+        ALOGW("%s(%d): removing different callback!", __func__, mPortId);
+        return INVALID_OPERATION;
     }
+    mDeviceCallback.clear();
     if (mInput != AUDIO_IO_HANDLE_NONE) {
         AudioSystem::removeAudioDeviceCallback(this, mInput);
     }
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 52ad5a6..01d9b3d 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -522,11 +522,12 @@
     if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;
 
     audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
-    AudioDeviceCallbacks callbacks;
-    bool deviceValidOrChanged = false;
-    Mutex::Autolock _l(mCallbacksLock);
+    Vector<sp<AudioDeviceCallback>> callbacksToCall;
     {
         Mutex::Autolock _l(mLock);
+        bool deviceValidOrChanged = false;
+        bool sendCallbacks = false;
+        ssize_t ioIndex = -1;
 
         switch (event) {
         case AUDIO_OUTPUT_OPENED:
@@ -544,17 +545,16 @@
             if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
                 deviceId = ioDesc->getDeviceId();
                 if (event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED) {
-                    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
+                    ioIndex = mAudioDeviceCallbackProxies.indexOfKey(ioDesc->mIoHandle);
                     if (ioIndex >= 0) {
-                        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+                        sendCallbacks = true;
                         deviceValidOrChanged = true;
                     }
                 }
                 if (event == AUDIO_OUTPUT_REGISTERED || event == AUDIO_INPUT_REGISTERED) {
-                    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
-                    if ((ioIndex >= 0) && !mAudioDeviceCallbacks.valueAt(ioIndex).notifiedOnce()) {
-                        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
-                    }
+                    ioIndex = mAudioDeviceCallbackProxies.indexOfKey(ioDesc->mIoHandle);
+                    sendCallbacks = (ioIndex >= 0)
+                            && !mAudioDeviceCallbackProxies.valueAt(ioIndex).notifiedOnce();
                 }
             }
             ALOGV("ioConfigChanged() new %s %s %d samplingRate %u, format %#x channel mask %#x "
@@ -577,7 +577,7 @@
                   event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle);
 
             mIoDescriptors.removeItem(ioDesc->mIoHandle);
-            mAudioDeviceCallbacks.removeItem(ioDesc->mIoHandle);
+            mAudioDeviceCallbackProxies.removeItem(ioDesc->mIoHandle);
             } break;
 
         case AUDIO_OUTPUT_CONFIG_CHANGED:
@@ -594,10 +594,8 @@
             if (deviceId != ioDesc->getDeviceId()) {
                 deviceValidOrChanged = true;
                 deviceId = ioDesc->getDeviceId();
-                ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
-                if (ioIndex >= 0) {
-                    callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
-                }
+                ioIndex = mAudioDeviceCallbackProxies.indexOfKey(ioDesc->mIoHandle);
+                sendCallbacks = ioIndex >= 0;
             }
             ALOGV("ioConfigChanged() new config for %s %d samplingRate %u, format %#x "
                     "channel mask %#x frameCount %zu frameCountHAL %zu deviceId %d",
@@ -608,30 +606,34 @@
 
         } break;
         }
-    }
-    // callbacks.size() != 0 =>  ioDesc->mIoHandle and deviceId are valid
-    if (callbacks.size() != 0) {
-        for (size_t i = 0; i < callbacks.size(); ) {
-            sp<AudioDeviceCallback> callback = callbacks[i].promote();
-            if (callback.get() != nullptr) {
-                // Call the callback only if the device actually changed, the input or output was
-                // opened or closed or the client was newly registered and the callback was never
-                // called
-                if (!callback->notifiedOnce() || deviceValidOrChanged) {
-                    // Must be called without mLock held. May lead to dead lock if calling for
-                    // example getRoutedDevice that updates the device and tries to acquire mLock.
-                    callback->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
-                    callback->setNotifiedOnce();
+
+        // sendCallbacks true =>  ioDesc->mIoHandle and deviceId are valid
+        if (sendCallbacks) {
+            AudioDeviceCallbackProxies &callbackProxies =
+                mAudioDeviceCallbackProxies.editValueAt(ioIndex);
+            for (size_t i = 0; i < callbackProxies.size(); ) {
+                sp<AudioDeviceCallback> callback = callbackProxies[i]->callback();
+                if (callback.get() != nullptr) {
+                    // Call the callback only if the device actually changed, the input or output
+                    // was opened or closed or the client was newly registered and the callback
+                    // was never called
+                    if (!callbackProxies[i]->notifiedOnce() || deviceValidOrChanged) {
+                        callbacksToCall.add(callback);
+                        callbackProxies[i]->setNotifiedOnce();
+                    }
+                    i++;
+                } else {
+                    callbackProxies.removeAt(i);
                 }
-                i++;
-            } else {
-                callbacks.removeAt(i);
             }
+            callbackProxies.setNotifiedOnce();
         }
-        callbacks.setNotifiedOnce();
-        // clean up callback list while we are here if some clients have disappeared without
-        // unregistering their callback, or if cb was served for the first time since registered
-        mAudioDeviceCallbacks.replaceValueFor(ioDesc->mIoHandle, callbacks);
+    }
+
+    // Callbacks must be called without mLock held. May lead to dead lock if calling for
+    // example getRoutedDevice that updates the device and tries to acquire mLock.
+    for (size_t i = 0; i < callbacksToCall.size(); i++) {
+        callbacksToCall[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
     }
 }
 
@@ -686,48 +688,49 @@
 status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
         const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
-    Mutex::Autolock _l(mCallbacksLock);
-    AudioDeviceCallbacks callbacks;
-    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
+    Mutex::Autolock _l(mLock);
+    AudioDeviceCallbackProxies callbackProxies;
+    ssize_t ioIndex = mAudioDeviceCallbackProxies.indexOfKey(audioIo);
     if (ioIndex >= 0) {
-        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+        callbackProxies = mAudioDeviceCallbackProxies.valueAt(ioIndex);
     }
 
-    for (size_t cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
-        if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
+    for (size_t cbIndex = 0; cbIndex < callbackProxies.size(); cbIndex++) {
+        sp<AudioDeviceCallback> cbk = callbackProxies[cbIndex]->callback();
+        if (cbk.get() == callback.unsafe_get()) {
             return INVALID_OPERATION;
         }
     }
-    callbacks.add(callback);
-    callbacks.resetNotifiedOnce();
-    mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks);
+    callbackProxies.add(new AudioDeviceCallbackProxy(callback));
+    callbackProxies.resetNotifiedOnce();
+    mAudioDeviceCallbackProxies.replaceValueFor(audioIo, callbackProxies);
     return NO_ERROR;
 }
 
 status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
         const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
-    Mutex::Autolock _l(mCallbacksLock);
-    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
+    Mutex::Autolock _l(mLock);
+    ssize_t ioIndex = mAudioDeviceCallbackProxies.indexOfKey(audioIo);
     if (ioIndex < 0) {
         return INVALID_OPERATION;
     }
-    AudioDeviceCallbacks callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
-
+    AudioDeviceCallbackProxies callbackProxies = mAudioDeviceCallbackProxies.valueAt(ioIndex);
     size_t cbIndex;
-    for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
-        if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
+    for (cbIndex = 0; cbIndex < callbackProxies.size(); cbIndex++) {
+        sp<AudioDeviceCallback> cbk = callbackProxies[cbIndex]->callback();
+        if (cbk.get() == callback.unsafe_get()) {
             break;
         }
     }
-    if (cbIndex == callbacks.size()) {
+    if (cbIndex == callbackProxies.size()) {
         return INVALID_OPERATION;
     }
-    callbacks.removeAt(cbIndex);
-    if (callbacks.size() != 0) {
-        mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks);
+    callbackProxies.removeAt(cbIndex);
+    if (callbackProxies.size() != 0) {
+        mAudioDeviceCallbackProxies.replaceValueFor(audioIo, callbackProxies);
     } else {
-        mAudioDeviceCallbacks.removeItem(audioIo);
+        mAudioDeviceCallbackProxies.removeItem(audioIo);
     }
     return NO_ERROR;
 }
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index b5a7ebe..7881bb8 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -2959,14 +2959,12 @@
         ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
         return BAD_VALUE;
     }
-    {
-        AutoMutex lock(mLock);
-        if (mDeviceCallback.unsafe_get() != callback.get()) {
-            ALOGW("%s removing different callback!", __FUNCTION__);
-            return INVALID_OPERATION;
-        }
-        mDeviceCallback.clear();
+    AutoMutex lock(mLock);
+    if (mDeviceCallback.unsafe_get() != callback.get()) {
+        ALOGW("%s removing different callback!", __FUNCTION__);
+        return INVALID_OPERATION;
     }
+    mDeviceCallback.clear();
     if (mOutput != AUDIO_IO_HANDLE_NONE) {
         AudioSystem::removeAudioDeviceCallback(this, mOutput);
     }
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index fbbbd11..41b425f 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -26,6 +26,7 @@
 #include <unordered_map>
 #include <vector>
 
+#include <android/os/IExternalVibratorService.h>
 #include <media/AudioBufferProvider.h>
 #include <media/AudioResampler.h>
 #include <media/AudioResamplerPublic.h>
@@ -103,20 +104,21 @@
                                   // parameter 'value' is a pointer to the new playback rate.
     };
 
-    enum { // Haptic intensity, should keep consistent with VibratorService
-        HAPTIC_SCALE_VERY_LOW = -2,
-        HAPTIC_SCALE_LOW = -1,
-        HAPTIC_SCALE_NONE = 0,
-        HAPTIC_SCALE_HIGH = 1,
-        HAPTIC_SCALE_VERY_HIGH = 2,
-    };
-    typedef int32_t haptic_intensity_t;
-    static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2 / 3;
-    static constexpr float HAPTIC_SCALE_LOW_RATIO = 3 / 4;
-    static const CONSTEXPR float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f;
+    typedef enum { // Haptic intensity, should keep consistent with VibratorService
+        HAPTIC_SCALE_MUTE = os::IExternalVibratorService::SCALE_MUTE,
+        HAPTIC_SCALE_VERY_LOW = os::IExternalVibratorService::SCALE_VERY_LOW,
+        HAPTIC_SCALE_LOW = os::IExternalVibratorService::SCALE_LOW,
+        HAPTIC_SCALE_NONE = os::IExternalVibratorService::SCALE_NONE,
+        HAPTIC_SCALE_HIGH = os::IExternalVibratorService::SCALE_HIGH,
+        HAPTIC_SCALE_VERY_HIGH = os::IExternalVibratorService::SCALE_VERY_HIGH,
+    } haptic_intensity_t;
+    static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2.0f / 3.0f;
+    static constexpr float HAPTIC_SCALE_LOW_RATIO = 3.0f / 4.0f;
+    static const constexpr float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f;
 
     static inline bool isValidHapticIntensity(haptic_intensity_t hapticIntensity) {
         switch (hapticIntensity) {
+        case HAPTIC_SCALE_MUTE:
         case HAPTIC_SCALE_VERY_LOW:
         case HAPTIC_SCALE_LOW:
         case HAPTIC_SCALE_NONE:
@@ -428,8 +430,9 @@
         case HAPTIC_SCALE_NONE:
         case HAPTIC_SCALE_HIGH:
         case HAPTIC_SCALE_VERY_HIGH:
-        default:
             return 1.0f;
+        default:
+            return 0.0f;
         }
         }
 
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 3df49e6..b9ee24a 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -399,15 +399,28 @@
 
         virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
                                          audio_port_handle_t deviceId) = 0;
-                bool notifiedOnce() const { return mNotifiedOnce; }
-                void setNotifiedOnce() { mNotifiedOnce = true; }
+    };
+
+    class AudioDeviceCallbackProxy : public RefBase
+    {
+    public:
+
+          AudioDeviceCallbackProxy(wp<AudioDeviceCallback> callback)
+              : mCallback(callback) {}
+          ~AudioDeviceCallbackProxy() override {}
+
+          sp<AudioDeviceCallback> callback() const { return mCallback.promote(); };
+
+          bool notifiedOnce() const { return mNotifiedOnce; }
+          void setNotifiedOnce() { mNotifiedOnce = true; }
     private:
-                /**
-                 * @brief mNotifiedOnce it forces the callback to be called at least once when
-                 * registered with a VALID AudioDevice, and allows not to flood other listeners
-                 * on this iohandle that already know the valid device.
-                 */
-                bool mNotifiedOnce = false;
+        /**
+         * @brief mNotifiedOnce it forces the callback to be called at least once when
+         * registered with a VALID AudioDevice, and allows not to flood other listeners
+         * on this iohandle that already know the valid device.
+         */
+         bool mNotifiedOnce = false;
+         wp<AudioDeviceCallback> mCallback;
     };
 
     static status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
@@ -454,7 +467,7 @@
         Mutex                               mLock;
         DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> >   mIoDescriptors;
 
-        class AudioDeviceCallbacks : public Vector<wp<AudioDeviceCallback>>
+        class AudioDeviceCallbackProxies : public Vector<sp<AudioDeviceCallbackProxy>>
         {
         public:
             /**
@@ -472,8 +485,8 @@
              */
             bool mNotifiedOnce = false;
         };
-        Mutex                               mCallbacksLock; // prevents race on Callbacks
-        DefaultKeyedVector<audio_io_handle_t, AudioDeviceCallbacks> mAudioDeviceCallbacks;
+        DefaultKeyedVector<audio_io_handle_t, AudioDeviceCallbackProxies>
+                mAudioDeviceCallbackProxies;
         // cached values for recording getInputBufferSize() queries
         size_t                              mInBuffSize;    // zero indicates cache is invalid
         uint32_t                            mInSamplingRate;
diff --git a/media/libaudioprocessing/Android.bp b/media/libaudioprocessing/Android.bp
index 817fb0b..cb78063 100644
--- a/media/libaudioprocessing/Android.bp
+++ b/media/libaudioprocessing/Android.bp
@@ -12,6 +12,11 @@
         "libnblog",
         "libsonic",
         "libutils",
+        "libvibrator",
+    ],
+
+    header_libs: [
+        "libbase_headers",
     ],
 
     cflags: [
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index 86777d6..2c57db7 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -113,10 +113,10 @@
         // Integer volume.
         // Currently integer volume is kept for the legacy integer mixer.
         // Will be removed when the legacy mixer path is removed.
-        t->volume[0] = UNITY_GAIN_INT;
-        t->volume[1] = UNITY_GAIN_INT;
-        t->prevVolume[0] = UNITY_GAIN_INT << 16;
-        t->prevVolume[1] = UNITY_GAIN_INT << 16;
+        t->volume[0] = 0;
+        t->volume[1] = 0;
+        t->prevVolume[0] = 0 << 16;
+        t->prevVolume[1] = 0 << 16;
         t->volumeInc[0] = 0;
         t->volumeInc[1] = 0;
         t->auxLevel = 0;
@@ -124,10 +124,10 @@
         t->prevAuxLevel = 0;
 
         // Floating point volume.
-        t->mVolume[0] = UNITY_GAIN_FLOAT;
-        t->mVolume[1] = UNITY_GAIN_FLOAT;
-        t->mPrevVolume[0] = UNITY_GAIN_FLOAT;
-        t->mPrevVolume[1] = UNITY_GAIN_FLOAT;
+        t->mVolume[0] = 0.f;
+        t->mVolume[1] = 0.f;
+        t->mPrevVolume[0] = 0.f;
+        t->mPrevVolume[1] = 0.f;
         t->mVolumeInc[0] = 0.;
         t->mVolumeInc[1] = 0.;
         t->mAuxLevel = 0.;
diff --git a/media/libaudioprocessing/tests/Android.bp b/media/libaudioprocessing/tests/Android.bp
index 811c16b..0c8e5bb 100644
--- a/media/libaudioprocessing/tests/Android.bp
+++ b/media/libaudioprocessing/tests/Android.bp
@@ -10,6 +10,7 @@
         "libcutils",
         "liblog",
         "libutils",
+        "libvibrator",
     ],
 
     cflags: [
diff --git a/media/libeffects/downmix/tests/Android.bp b/media/libeffects/downmix/tests/Android.bp
new file mode 100644
index 0000000..e2e7dbd
--- /dev/null
+++ b/media/libeffects/downmix/tests/Android.bp
@@ -0,0 +1,31 @@
+// Build testbench for downmix module.
+cc_test {
+    name:"downmixtest",
+    host_supported: false,
+    proprietary: true,
+    include_dirs: [
+        "frameworks/av/media/libeffects/downmix",
+    ],
+
+    header_libs: [
+        "libaudioeffects",
+    ],
+
+    shared_libs: [
+        "libaudioutils",
+        "libdownmix",
+        "liblog",
+    ],
+
+    relative_install_path: "soundfx",
+
+    srcs: [
+        "downmixtest.cpp",
+    ],
+
+    cflags: [
+        "-v",
+        "-Werror",
+        "-Wextra",
+    ],
+}
diff --git a/media/libeffects/downmix/tests/build_and_run_all_unit_tests.sh b/media/libeffects/downmix/tests/build_and_run_all_unit_tests.sh
new file mode 100755
index 0000000..d0faebe
--- /dev/null
+++ b/media/libeffects/downmix/tests/build_and_run_all_unit_tests.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+#
+#Run tests in this directory.
+#
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+    echo "Android build environment not set"
+    exit -1
+fi
+#ensure we have mm
+. $ANDROID_BUILD_TOP/build/envsetup.sh
+
+mm -j
+
+echo "waiting for device"
+
+adb root && adb wait-for-device remount
+
+#location of test files
+testdir="/data/local/tmp/downmixtest"
+
+fs_arr=(
+    8000
+    11025
+    12000
+    16000
+    22050
+    24000
+    32000
+    44100
+    48000
+    88200
+    96000
+    176400
+    192000
+)
+
+echo "========================================"
+echo "testing Downmix"
+adb shell mkdir $testdir
+
+adb push $ANDROID_BUILD_TOP/cts/tests/tests/media/res/raw/sinesweepraw.raw \
+$testdir
+adb push $OUT/testcases/downmixtest/arm64/downmixtest $testdir
+
+#run the downmix test application for test.
+for fs in ${fs_arr[*]}
+do
+    for f_ch in {1..8}
+    do
+        for ch_fmt in {0..4}
+        do
+            adb shell  LD_LIBRARY_PATH=/vendor/lib64/soundfx \
+            $testdir/downmixtest $testdir/sinesweepraw.raw \
+            $testdir/sinesweep_fmt_$((ch_fmt))_fch_$((f_ch))_$((fs)).raw \
+            -ch_fmt:$ch_fmt -fch:$f_ch -fs:$fs
+
+            # Implementation dependent test:
+            # check that higher frequencies match 8 kHz result.
+            if [ $fs != 8000 ]
+            then
+                adb shell cmp \
+                $testdir/sinesweep_fmt_$((ch_fmt))_fch_$((f_ch))_8000.raw \
+                $testdir/sinesweep_fmt_$((ch_fmt))_fch_$((f_ch))_$((fs)).raw
+            fi
+        done
+    done
+done
+adb shell rm -r $testdir
diff --git a/media/libeffects/downmix/tests/downmixtest.cpp b/media/libeffects/downmix/tests/downmixtest.cpp
new file mode 100644
index 0000000..71f83e5
--- /dev/null
+++ b/media/libeffects/downmix/tests/downmixtest.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vector>
+
+#include <audio_effects/effect_downmix.h>
+#include <audio_utils/channels.h>
+#include <audio_utils/primitives.h>
+#include <log/log.h>
+#include <system/audio.h>
+
+#include "EffectDownmix.h"
+#define FRAME_LENGTH 256
+#define MAX_NUM_CHANNELS 8
+
+struct downmix_cntxt_s {
+  effect_descriptor_t desc;
+  effect_handle_t handle;
+  effect_config_t config;
+
+  int numFileChannels;
+  int numProcessChannels;
+};
+
+extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
+
+void printUsage() {
+  printf("\nUsage:");
+  printf("\n     downmixtest <input_file> <out_file> [options]\n");
+  printf("\nwhere,");
+  printf("\n     <input_file>  is the input file name");
+  printf("\n                  on which LVM effects are applied");
+  printf("\n     <output_file> processed output file");
+  printf("\n     and options are mentioned below");
+  printf("\n");
+  printf("\n      -h");
+  printf("\n           Prints this usage information");
+  printf("\n");
+  printf("\n     -ch_fmt:<format_of_input_audio>");
+  printf("\n         0:AUDIO_CHANNEL_OUT_7POINT1(default)");
+  printf("\n         1:AUDIO_CHANNEL_OUT_5POINT1_SIDE");
+  printf("\n         2:AUDIO_CHANNEL_OUT_5POINT1_BACK");
+  printf("\n         3:AUDIO_CHANNEL_OUT_QUAD_SIDE");
+  printf("\n         4:AUDIO_CHANNEL_OUT_QUAD_BACK");
+  printf("\n");
+  printf("\n     -fch:<file_channels> (1 through 8)");
+  printf("\n");
+}
+
+int32_t DownmixDefaultConfig(effect_config_t *pConfig) {
+  pConfig->inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+  pConfig->inputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+  pConfig->inputCfg.channels = AUDIO_CHANNEL_OUT_7POINT1;
+  pConfig->inputCfg.bufferProvider.getBuffer = nullptr;
+  pConfig->inputCfg.bufferProvider.releaseBuffer = nullptr;
+  pConfig->inputCfg.bufferProvider.cookie = nullptr;
+  pConfig->inputCfg.mask = EFFECT_CONFIG_ALL;
+
+  pConfig->inputCfg.samplingRate = 44100;
+  pConfig->outputCfg.samplingRate = pConfig->inputCfg.samplingRate;
+
+  // set a default value for the access mode, but should be overwritten by caller
+  pConfig->outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
+  pConfig->outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+  pConfig->outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+  pConfig->outputCfg.bufferProvider.getBuffer = nullptr;
+  pConfig->outputCfg.bufferProvider.releaseBuffer = nullptr;
+  pConfig->outputCfg.bufferProvider.cookie = nullptr;
+  pConfig->outputCfg.mask = EFFECT_CONFIG_ALL;
+
+  return 0;
+}
+
+int32_t DownmixConfiureAndEnable(downmix_cntxt_s *pDescriptor) {
+  effect_handle_t *effectHandle = &pDescriptor->handle;
+  downmix_module_t *downmixEffectHandle = (downmix_module_t *)*effectHandle;
+  const struct effect_interface_s *Downmix_api = downmixEffectHandle->itfe;
+  int32_t err = 0;
+  uint32_t replySize = (uint32_t)sizeof(err);
+
+  err = (Downmix_api->command)(*effectHandle, EFFECT_CMD_SET_CONFIG,
+                               sizeof(effect_config_t), &(pDescriptor->config),
+                               &replySize, &err);
+  if (err != 0) {
+    ALOGE("Downmix command to configure returned an error %d", err);
+    return err;
+  }
+
+  err = ((Downmix_api->command))(*effectHandle, EFFECT_CMD_ENABLE, 0, nullptr,
+                                 &replySize, &err);
+  if (err != 0) {
+    ALOGE("Downmix command to enable effect returned an error %d", err);
+    return err;
+  }
+  return 0;
+}
+
+int32_t DownmixExecute(downmix_cntxt_s *pDescriptor, FILE *finp,
+                       FILE *fout) {
+  effect_handle_t *effectHandle = &pDescriptor->handle;
+  downmix_module_t *downmixEffectHandle = (downmix_module_t *)*effectHandle;
+  const struct effect_interface_s *Downmix_api = downmixEffectHandle->itfe;
+
+  const int numFileChannels = pDescriptor->numFileChannels;
+  const int numProcessChannels = pDescriptor->numProcessChannels;
+  const int fileFrameSize = numFileChannels * sizeof(short);
+  const unsigned int outputChannels =
+      audio_channel_count_from_out_mask(AUDIO_CHANNEL_OUT_STEREO);
+
+  std::vector<float> outFloat(FRAME_LENGTH * MAX_NUM_CHANNELS);
+  std::vector<float> inFloat(FRAME_LENGTH * MAX_NUM_CHANNELS);
+
+  audio_buffer_t inbuffer, outbuffer;
+  inbuffer.f32 = inFloat.data();
+  outbuffer.f32 = outFloat.data();
+  inbuffer.frameCount = FRAME_LENGTH;
+  outbuffer.frameCount = FRAME_LENGTH;
+
+  audio_buffer_t *pinbuf, *poutbuf;
+  pinbuf = &inbuffer;
+  poutbuf = &outbuffer;
+
+  int frameCounter = 0;
+  std::vector<short> inS16(FRAME_LENGTH * MAX_NUM_CHANNELS);
+  std::vector<short> outS16(FRAME_LENGTH * MAX_NUM_CHANNELS);
+
+  while (fread(inS16.data(), fileFrameSize, FRAME_LENGTH, finp) ==
+         FRAME_LENGTH) {
+    if (numFileChannels != numProcessChannels) {
+      adjust_channels(inS16.data(), numFileChannels, inS16.data(),
+                      numProcessChannels, sizeof(short),
+                      FRAME_LENGTH * fileFrameSize);
+    }
+
+    memcpy_to_float_from_i16(inFloat.data(), inS16.data(),
+                             FRAME_LENGTH * numProcessChannels);
+
+    const int32_t err = (Downmix_api->process)(*effectHandle, pinbuf, poutbuf);
+    if (err != 0) {
+      ALOGE("DownmixProcess returned an error %d", err);
+      return -1;
+    }
+
+    memcpy_to_i16_from_float(outS16.data(), outFloat.data(),
+                             FRAME_LENGTH * outputChannels);
+    fwrite(outS16.data(), sizeof(short), (FRAME_LENGTH * outputChannels),
+           fout);
+    frameCounter++;
+  }
+  printf("frameCounter: [%d]\n", frameCounter);
+  return 0;
+}
+
+int32_t DowmixMainProcess(downmix_cntxt_s *pDescriptor, FILE *finp,
+                          FILE *fout) {
+  effect_handle_t *effectHandle = &pDescriptor->handle;
+  int32_t sessionId = 0, ioId = 0;
+  const effect_uuid_t downmix_uuid = {
+      0x93f04452, 0xe4fe, 0x41cc, 0x91f9, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}};
+
+  int32_t err = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(
+      &downmix_uuid, sessionId, ioId,
+      effectHandle);
+  if (err != 0) {
+    ALOGE("DownmixLib_Create returned an error %d", err);
+    return -1;
+  }
+
+  // Passing the init config for time being.
+  err = DownmixConfiureAndEnable(pDescriptor);
+  if (err != 0) {
+    ALOGE("DownmixConfigureAndEnable returned an error %d", err);
+    return -1;
+  }
+  // execute call for downmix.
+  err = DownmixExecute(pDescriptor, finp, fout);
+  if (err != 0) {
+    ALOGE("DownmixExecute returned an error %d", err);
+    return -1;
+  }
+  // Release the library function.
+  err = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(*effectHandle);
+  if (err != 0) {
+    ALOGE("DownmixRelease returned an error %d", err);
+    return -1;
+  }
+  return 0;
+}
+
+int main(int argc, const char *argv[]) {
+  int numFileChannels = 1, numProcessChannels = 8;
+  downmix_cntxt_s descriptor = {};
+  DownmixDefaultConfig(&(descriptor.config));
+
+  const char *infile = nullptr;
+  const char *outfile = nullptr;
+  for (int i = 1; i < argc; i++) {
+    printf("%s ", argv[i]);
+    if (argv[i][0] != '-') {
+      if (infile == nullptr) {
+        infile = argv[i];
+      } else if (outfile == nullptr) {
+        outfile = argv[i];
+      } else {
+        printUsage();
+        return -1;
+      }
+    } else if (!strncmp(argv[i], "-fs:", 4)) {
+      // Add a check for all the supported streams.
+      const int samplingFreq = atoi(argv[i] + 4);
+      if (samplingFreq != 8000 && samplingFreq != 11025 &&
+          samplingFreq != 12000 && samplingFreq != 16000 &&
+          samplingFreq != 22050 && samplingFreq != 24000 &&
+          samplingFreq != 32000 && samplingFreq != 44100 &&
+          samplingFreq != 48000 && samplingFreq != 88200 &&
+          samplingFreq != 96000 && samplingFreq != 176400 &&
+          samplingFreq != 192000) {
+        printf("Unsupported Sampling Frequency : %d", samplingFreq);
+        printUsage();
+        return -1;
+      }
+
+      descriptor.config.inputCfg.samplingRate = samplingFreq;
+      descriptor.config.outputCfg.samplingRate = samplingFreq;
+    } else if (!strncmp(argv[i], "-ch_fmt:", 8)) {
+      const int format = atoi(argv[i] + 8);
+      uint32_t *audioType = &descriptor.config.inputCfg.channels;
+      switch (format) {
+        case 0:
+          *audioType = AUDIO_CHANNEL_OUT_7POINT1;
+          break;
+        case 1:
+          *audioType = AUDIO_CHANNEL_OUT_5POINT1_SIDE;
+          break;
+        case 2:
+          *audioType = AUDIO_CHANNEL_OUT_5POINT1_BACK;
+          break;
+        case 3:
+          *audioType = AUDIO_CHANNEL_OUT_QUAD_SIDE;
+          break;
+        case 4:
+          *audioType = AUDIO_CHANNEL_OUT_QUAD_BACK;
+          break;
+        default:
+          *audioType = AUDIO_CHANNEL_OUT_7POINT1;
+          break;
+      }
+      descriptor.numProcessChannels =
+          audio_channel_count_from_out_mask(*audioType);
+    } else if (!strncmp(argv[i], "-fch:", 5)) {
+      const int fChannels = atoi(argv[i] + 5);
+      if (fChannels > 8 || fChannels < 1) {
+        printf("Unsupported number of file channels : %d", fChannels);
+        printUsage();
+        return -1;
+      }
+      descriptor.numFileChannels = fChannels;
+
+    } else if (!strncmp(argv[i], "-h", 2)) {
+      printUsage();
+      return 0;
+    }
+  }
+
+  if (/*infile == nullptr || */ outfile == nullptr) {
+    printUsage();
+    return -1;
+  }
+
+  FILE *finp = fopen(infile, "rb");
+  if (finp == nullptr) {
+    printf("Cannot open input file %s", infile);
+    return -1;
+  }
+  FILE *fout = fopen(outfile, "wb");
+  if (fout == nullptr) {
+    printf("Cannot open output file %s", outfile);
+    fclose(finp);
+    return -1;
+  }
+
+  const int err = DowmixMainProcess(&descriptor, finp, fout);
+  // close input and output files.
+  fclose(finp);
+  fclose(fout);
+  if (err != 0) {
+    printf("Error: %d\n", err);
+  }
+  return err;
+}
diff --git a/media/libeffects/lvm/lib/Common/src/Copy_16.c b/media/libeffects/lvm/lib/Common/src/Copy_16.c
index 1f9f659..3858450 100644
--- a/media/libeffects/lvm/lib/Common/src/Copy_16.c
+++ b/media/libeffects/lvm/lib/Common/src/Copy_16.c
@@ -132,8 +132,8 @@
     src += NrChannels * (NrFrames - 1);
     for (ii = NrFrames; ii != 0; ii--)
     {
-        dst[0] = src_st[0];
         dst[1] = src_st[1];
+        dst[0] = src_st[0]; // copy 1 before 0 is required for NrChannels == 3.
         for (jj = 2; jj < NrChannels; jj++)
         {
             dst[jj] = src[jj];
diff --git a/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh b/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
index 41a4f04..1a874a3 100755
--- a/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
+++ b/media/libeffects/lvm/tests/build_and_run_all_unit_tests.sh
@@ -54,21 +54,13 @@
     192000
 )
 
-ch_arr=(
-    1
-    2
-    4
-    6
-    8
-)
-
 # run multichannel effects at different configs, saving only the stereo channel
 # pair.
 for flags in "${flags_arr[@]}"
 do
     for fs in ${fs_arr[*]}
     do
-        for ch in ${ch_arr[*]}
+        for ch in {1..8}
         do
             adb shell $testdir/lvmtest -i:$testdir/sinesweepraw.raw \
                 -o:$testdir/sinesweep_$((ch))_$((fs)).raw -ch:$ch -fs:$fs $flags
diff --git a/media/libeffects/lvm/tests/lvmtest.cpp b/media/libeffects/lvm/tests/lvmtest.cpp
index 43271d2..fe47d0b 100644
--- a/media/libeffects/lvm/tests/lvmtest.cpp
+++ b/media/libeffects/lvm/tests/lvmtest.cpp
@@ -571,17 +571,12 @@
                   0);                      /* Audio Time */
 }
 
-int lvmMainProcess(lvmConfigParams_t *plvmConfigParams, FILE *finp, FILE *fout) {
-  struct EffectContext context;
-  LVM_ControlParams_t params;
-
-  int errCode = lvmCreate(&context, plvmConfigParams, &params);
-  if (errCode) {
-    ALOGE("Error: lvmCreate returned with %d\n", errCode);
-    return errCode;
-  }
-
-  errCode = lvmControl(&context, plvmConfigParams, &params);
+int lvmMainProcess(EffectContext *pContext,
+                   LVM_ControlParams_t *pParams,
+                   lvmConfigParams_t *plvmConfigParams,
+                   FILE *finp,
+                   FILE *fout) {
+  int errCode = lvmControl(pContext, plvmConfigParams, pParams);
   if (errCode) {
     ALOGE("Error: lvmControl returned with %d\n", errCode);
     return errCode;
@@ -625,7 +620,7 @@
         }
     }
 #if 1
-    errCode = lvmExecute(floatIn.data(), floatOut.data(), &context, plvmConfigParams);
+    errCode = lvmExecute(floatIn.data(), floatOut.data(), pContext, plvmConfigParams);
     if (errCode) {
       printf("\nError: lvmExecute returned with %d\n", errCode);
       return errCode;
@@ -654,14 +649,15 @@
   }
 
   lvmConfigParams_t lvmConfigParams{}; // default initialize
-  FILE *finp = nullptr, *fout = nullptr;
+  const char *infile = nullptr;
+  const char *outfile = nullptr;
 
   for (int i = 1; i < argc; i++) {
     printf("%s ", argv[i]);
     if (!strncmp(argv[i], "-i:", 3)) {
-      finp = fopen(argv[i] + 3, "rb");
+      infile = argv[i] + 3;
     } else if (!strncmp(argv[i], "-o:", 3)) {
-      fout = fopen(argv[i] + 3, "wb");
+      outfile = argv[i] + 3;
     } else if (!strncmp(argv[i], "-fs:", 4)) {
       const int samplingFreq = atoi(argv[i] + 4);
       if (samplingFreq != 8000 && samplingFreq != 11025 &&
@@ -671,21 +667,21 @@
           samplingFreq != 48000 && samplingFreq != 88200 &&
           samplingFreq != 96000 && samplingFreq != 176400 &&
           samplingFreq != 192000) {
-        ALOGE("\nError: Unsupported Sampling Frequency : %d\n", samplingFreq);
+        printf("Error: Unsupported Sampling Frequency : %d\n", samplingFreq);
         return -1;
       }
       lvmConfigParams.samplingFreq = samplingFreq;
     } else if (!strncmp(argv[i], "-ch:", 4)) {
       const int nrChannels = atoi(argv[i] + 4);
       if (nrChannels > 8 || nrChannels < 1) {
-        ALOGE("\nError: Unsupported number of channels : %d\n", nrChannels);
+        printf("Error: Unsupported number of channels : %d\n", nrChannels);
         return -1;
       }
       lvmConfigParams.nrChannels = nrChannels;
     } else if (!strncmp(argv[i], "-fch:", 5)) {
       const int fChannels = atoi(argv[i] + 5);
       if (fChannels > 8 || fChannels < 1) {
-             ALOGE("\nError: Unsupported number of file channels : %d\n", fChannels);
+             printf("Error: Unsupported number of file channels : %d\n", fChannels);
              return -1;
            }
            lvmConfigParams.fChannels = fChannels;
@@ -694,7 +690,7 @@
     } else if (!strncmp(argv[i], "-basslvl:", 9)) {
       const int bassEffectLevel = atoi(argv[i] + 9);
       if (bassEffectLevel > 15 || bassEffectLevel < 0) {
-        ALOGE("\nError: Unsupported Bass Effect Level : %d\n",
+        printf("Error: Unsupported Bass Effect Level : %d\n",
                bassEffectLevel);
         printUsage();
         return -1;
@@ -703,7 +699,7 @@
     } else if (!strncmp(argv[i], "-eqPreset:", 10)) {
       const int eqPresetLevel = atoi(argv[i] + 10);
       if (eqPresetLevel > 9 || eqPresetLevel < 0) {
-        ALOGE("\nError: Unsupported Equalizer Preset : %d\n", eqPresetLevel);
+        printf("Error: Unsupported Equalizer Preset : %d\n", eqPresetLevel);
         printUsage();
         return -1;
       }
@@ -722,19 +718,47 @@
     }
   }
 
-  if (finp == nullptr || fout == nullptr) {
-    ALOGE("\nError: missing input/output files\n");
+  if (infile == nullptr || outfile == nullptr) {
+    printf("Error: missing input/output files\n");
     printUsage();
-    // ok not to close.
     return -1;
   }
 
-  const int errCode = lvmMainProcess(&lvmConfigParams, finp, fout);
+  FILE *finp = fopen(infile, "rb");
+  if (finp == nullptr) {
+    printf("Cannot open input file %s", infile);
+    return -1;
+  }
+
+  FILE *fout = fopen(outfile, "wb");
+  if (fout == nullptr) {
+    printf("Cannot open output file %s", outfile);
+    fclose(finp);
+    return -1;
+  }
+
+  EffectContext context;
+  LVM_ControlParams_t params;
+  int errCode = lvmCreate(&context, &lvmConfigParams, &params);
+  if (errCode == 0) {
+    errCode = lvmMainProcess(&context, &params, &lvmConfigParams, finp, fout);
+    if (errCode != 0) {
+      printf("Error: lvmMainProcess returned with the error: %d",errCode);
+    }
+  } else {
+    printf("Error: lvmCreate returned with the error: %d", errCode);
+  }
   fclose(finp);
   fclose(fout);
+  /* Free the allocated buffers */
+  if (context.pBundledContext != nullptr) {
+    if (context.pBundledContext->hInstance != nullptr) {
+      LvmEffect_free(&context);
+    }
+    free(context.pBundledContext);
+  }
 
   if (errCode) {
-    ALOGE("Error: lvmMainProcess returns with the error: %d \n", errCode);
     return -1;
   }
   return 0;
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 9a1ac53..5853e4b 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -21,6 +21,7 @@
     vndk: {
         enabled: true,
     },
+    double_loadable: true,
     srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
     cflags: [
         "-Werror",
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
index aa77cd3..8dac91a 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmedia/TypeConverter.cpp
@@ -228,6 +228,9 @@
     MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_2POINT1),
     MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_2POINT0POINT2),
     MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_2POINT1POINT2),
+    MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_TRI),
+    MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_TRI_BACK),
+    MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_3POINT1),
     MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_3POINT0POINT2),
     MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_3POINT1POINT2),
     MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_QUAD),
@@ -388,6 +391,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_FLAG_BYPASS_MUTE),
     MAKE_STRING_FROM_ENUM(AUDIO_FLAG_LOW_LATENCY),
     MAKE_STRING_FROM_ENUM(AUDIO_FLAG_DEEP_BUFFER),
+    MAKE_STRING_FROM_ENUM(AUDIO_FLAG_NO_CAPTURE),
     TERMINATOR
 };
 
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 5da6e24..d608d4a 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -1289,6 +1289,7 @@
             } else if (what == DecoderBase::kWhatShutdownCompleted) {
                 ALOGV("%s shutdown completed", audio ? "audio" : "video");
                 if (audio) {
+                    Mutex::Autolock autoLock(mDecoderLock);
                     mAudioDecoder.clear();
                     mAudioDecoderError = false;
                     ++mAudioDecoderGeneration;
@@ -1296,6 +1297,7 @@
                     CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
                     mFlushingAudio = SHUT_DOWN;
                 } else {
+                    Mutex::Autolock autoLock(mDecoderLock);
                     mVideoDecoder.clear();
                     mVideoDecoderError = false;
                     ++mVideoDecoderGeneration;
@@ -1967,6 +1969,7 @@
         int64_t currentPositionUs, bool forceNonOffload, bool needsToCreateAudioDecoder) {
     if (mAudioDecoder != NULL) {
         mAudioDecoder->pause();
+        Mutex::Autolock autoLock(mDecoderLock);
         mAudioDecoder.clear();
         mAudioDecoderError = false;
         ++mAudioDecoderGeneration;
@@ -1988,11 +1991,21 @@
     closeAudioSink();
     mRenderer->flush(true /* audio */, false /* notifyComplete */);
     if (mVideoDecoder != NULL) {
-        mRenderer->flush(false /* audio */, false /* notifyComplete */);
+        mDeferredActions.push_back(
+                new FlushDecoderAction(FLUSH_CMD_NONE /* audio */,
+                                       FLUSH_CMD_FLUSH /* video */));
+        mDeferredActions.push_back(
+                new SeekAction(currentPositionUs,
+                MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */));
+        // After a flush without shutdown, decoder is paused.
+        // Don't resume it until source seek is done, otherwise it could
+        // start pulling stale data too soon.
+        mDeferredActions.push_back(new ResumeDecoderAction(false));
+        processDeferredActions();
+    } else {
+        performSeek(currentPositionUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */);
     }
 
-    performSeek(currentPositionUs, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */);
-
     if (forceNonOffload) {
         mRenderer->signalDisableOffloadAudio();
         mOffloadAudio = false;
@@ -2085,6 +2098,8 @@
         }
     }
 
+    Mutex::Autolock autoLock(mDecoderLock);
+
     if (audio) {
         sp<AMessage> notify = new AMessage(kWhatAudioNotify, this);
         ++mAudioDecoderGeneration;
@@ -2395,6 +2410,8 @@
     CHECK(mTrackStats != NULL);
 
     mTrackStats->clear();
+
+    Mutex::Autolock autoLock(mDecoderLock);
     if (mVideoDecoder != NULL) {
         mTrackStats->push_back(mVideoDecoder->getStats());
     }
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index 798c725..b8fb988 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -197,6 +197,7 @@
     sp<DecoderBase> mVideoDecoder;
     bool mOffloadAudio;
     sp<DecoderBase> mAudioDecoder;
+    Mutex mDecoderLock;  // guard |mAudioDecoder| and |mVideoDecoder|.
     sp<CCDecoder> mCCDecoder;
     sp<Renderer> mRenderer;
     sp<ALooper> mRendererLooper;
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
index 9729d86..66bfae5 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
@@ -109,7 +109,10 @@
     mStats->setInt64("frames-dropped-output", mNumOutputFramesDropped);
     mStats->setFloat("frame-rate-total", mFrameRateTotal);
 
-    return mStats;
+    // i'm mutexed right now.
+    // make our own copy, so we aren't victim to any later changes.
+    sp<AMessage> copiedStats = mStats->dup();
+    return copiedStats;
 }
 
 status_t NuPlayer2::Decoder::setVideoSurface(const sp<ANativeWindowWrapper> &nww) {
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index 1b661f2..1876496 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -81,7 +81,7 @@
 };
 
 // key for media statistics
-static const char *kKeyPlayer = "nuplayer";
+static const char *kKeyPlayer = "nuplayer2";
 // attrs for media statistics
     // NB: these are matched with public Java API constants defined
     // in frameworks/base/media/java/android/media/MediaPlayer2.java
@@ -108,6 +108,8 @@
 static const char *kPlayerRebufferingCount = "android.media.mediaplayer.rebuffers";
 static const char *kPlayerRebufferingAtExit = "android.media.mediaplayer.rebufferExit";
 
+static const char *kPlayerVersion = "android.media.mediaplayer.version";
+
 
 NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid, const sp<JObjectHolder> &context)
     : mState(STATE_IDLE),
@@ -127,6 +129,7 @@
       mPlayer(new NuPlayer2(pid, uid, mMediaClock, context)),
       mPlayerFlags(0),
       mMetricsHandle(0),
+      mPlayerVersion(0),
       mClientUid(uid),
       mAtEOS(false),
       mLooping(false),
@@ -137,9 +140,13 @@
 
     mMediaClock->init();
 
+    // XXX: what version are we?
+    // Ideally, this ticks with the apk version info for the APEX packaging
+
     // set up media metrics record
     mMetricsHandle = mediametrics_create(kKeyPlayer);
     mediametrics_setUid(mMetricsHandle, mClientUid);
+    mediametrics_setInt64(mMetricsHandle, kPlayerVersion, mPlayerVersion);
 
     mNuPlayer2Looper->start(
             false, /* runOnCallingThread */
@@ -473,7 +480,7 @@
                 float frameRate = 0;
                 if (stats->findFloat("frame-rate-output", &frameRate)) {
                     mediametrics_setInt64(mMetricsHandle, kPlayerFrameRate, frameRate);
-		}
+                }
 
             } else if (mime.startsWith("audio/")) {
                 mediametrics_setCString(mMetricsHandle, kPlayerAMime, mime.c_str());
@@ -524,6 +531,7 @@
         mediametrics_delete(mMetricsHandle);
         mMetricsHandle = mediametrics_create(kKeyPlayer);
         mediametrics_setUid(mMetricsHandle, mClientUid);
+        mediametrics_setInt64(mMetricsHandle, kPlayerVersion, mPlayerVersion);
     } else {
         ALOGV("did not have anything to record");
     }
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
index 3d299f3..c97e247 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
@@ -134,6 +134,7 @@
     uint32_t mPlayerFlags;
 
     mediametrics_handle_t mMetricsHandle;
+    int64_t mPlayerVersion;
     uid_t mClientUid;
 
     bool mAtEOS;
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
index 3be7e36..a8c9932 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
@@ -1148,8 +1148,7 @@
         ALOGE("sampleRate is 0 in %s mode", offloadingAudio() ? "offload" : "non-offload");
         return 0;
     }
-    // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
-    return (int64_t)((int32_t)numFrames * 1000000LL / sampleRate);
+    return (int64_t)(numFrames * 1000000LL / sampleRate);
 }
 
 // Calculate duration of pending samples if played at normal rate (i.e., 1.0).
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 55867a5..22fa495 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -12,6 +12,7 @@
 
     shared_libs: [
         "android.hardware.media.omx@1.0",
+        "libbase",
         "libaudioclient",
         "libbinder",
         "libcamera_client",
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 37b13f0..d111313 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -24,6 +24,7 @@
 
 #include <algorithm>
 
+#include <android-base/properties.h>
 #include <android/hardware/ICamera.h>
 
 #include <binder/IPCThreadState.h>
@@ -1761,13 +1762,26 @@
         }
     }
 
+    // Enable temporal layering if the expected (max) playback frame rate is greater than ~11% of
+    // the minimum display refresh rate on a typical device. Add layers until the base layer falls
+    // under this limit. Allow device manufacturers to override this limit.
+
+    // TODO: make this configurable by the application
+    std::string maxBaseLayerFpsProperty =
+        ::android::base::GetProperty("ro.media.recorder-max-base-layer-fps", "");
+    float maxBaseLayerFps = (float)::atof(maxBaseLayerFpsProperty.c_str());
+    // TRICKY: use !> to fix up any NaN values
+    if (!(maxBaseLayerFps >= kMinTypicalDisplayRefreshingRate / 0.9)) {
+        maxBaseLayerFps = kMinTypicalDisplayRefreshingRate / 0.9;
+    }
+
     for (uint32_t tryLayers = 1; tryLayers <= kMaxNumVideoTemporalLayers; ++tryLayers) {
         if (tryLayers > tsLayers) {
             tsLayers = tryLayers;
         }
         // keep going until the base layer fps falls below the typical display refresh rate
         float baseLayerFps = maxPlaybackFps / (1 << (tryLayers - 1));
-        if (baseLayerFps < kMinTypicalDisplayRefreshingRate / 0.9) {
+        if (baseLayerFps < maxBaseLayerFps) {
             break;
         }
     }
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 1e85804..5a58aa0 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -94,6 +94,7 @@
     mDisconnected = false;
     mUri.clear();
     mUriHeaders.clear();
+    mSources.clear();
     if (mFd >= 0) {
         close(mFd);
         mFd = -1;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 5cf6bbd..3388097 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1829,11 +1829,21 @@
     closeAudioSink();
     mRenderer->flush(true /* audio */, false /* notifyComplete */);
     if (mVideoDecoder != NULL) {
-        mRenderer->flush(false /* audio */, false /* notifyComplete */);
+        mDeferredActions.push_back(
+                new FlushDecoderAction(FLUSH_CMD_NONE /* audio */,
+                                       FLUSH_CMD_FLUSH /* video */));
+        mDeferredActions.push_back(
+                new SeekAction(currentPositionUs,
+                MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */));
+        // After a flush without shutdown, decoder is paused.
+        // Don't resume it until source seek is done, otherwise it could
+        // start pulling stale data too soon.
+        mDeferredActions.push_back(new ResumeDecoderAction(false));
+        processDeferredActions();
+    } else {
+        performSeek(currentPositionUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */);
     }
 
-    performSeek(currentPositionUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */);
-
     if (forceNonOffload) {
         mRenderer->signalDisableOffloadAudio();
         mOffloadAudio = false;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 6d69d50..2f0da2d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -107,11 +107,16 @@
 }
 
 sp<AMessage> NuPlayer::Decoder::getStats() const {
+
     mStats->setInt64("frames-total", mNumFramesTotal);
     mStats->setInt64("frames-dropped-input", mNumInputFramesDropped);
     mStats->setInt64("frames-dropped-output", mNumOutputFramesDropped);
     mStats->setFloat("frame-rate-total", mFrameRateTotal);
-    return mStats;
+
+    // i'm mutexed right now.
+    // make our own copy, so we aren't victim to any later changes.
+    sp<AMessage> copiedStats = mStats->dup();
+    return copiedStats;
 }
 
 status_t NuPlayer::Decoder::setVideoSurface(const sp<Surface> &surface) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 1b396c0..2b813e7 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -778,7 +778,7 @@
 
 status_t NuPlayerDriver::getParameter(int key, Parcel *reply) {
 
-    if (key == FOURCC('m','t','r','X')) {
+    if (key == FOURCC('m','t','r','X') && mAnalyticsItem != NULL) {
         // mtrX -- a play on 'metrics' (not matrix)
         // gather current info all together, parcel it, and send it back
         updateMetrics("api");
@@ -1006,7 +1006,7 @@
             // when we have an error, add it to the analytics for this playback.
             // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
             // [test against msg is due to fall through from previous switch value]
-            if (msg == MEDIA_ERROR) {
+            if (msg == MEDIA_ERROR && mAnalyticsItem != NULL) {
                 mAnalyticsItem->setInt32(kPlayerError, ext1);
                 if (ext2 != 0) {
                     mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index c990b2a..65d6d61 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -1161,8 +1161,8 @@
         ALOGE("sampleRate is 0 in %s mode", offloadingAudio() ? "offload" : "non-offload");
         return 0;
     }
-    // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
-    return (int64_t)((int32_t)numFrames * 1000000LL / sampleRate);
+
+    return (int64_t)(numFrames * 1000000LL / sampleRate);
 }
 
 // Calculate duration of pending samples if played at normal rate (i.e., 1.0).
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 6d2329f..9c46659 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -4298,24 +4298,27 @@
     int maxDimension = max(width, height);
 
     static const int limits[][5] = {
-        /*   MBps     MB   dim  bitrate        level */
-        {    1485,    99,  28,     64, OMX_VIDEO_AVCLevel1  },
-        {    1485,    99,  28,    128, OMX_VIDEO_AVCLevel1b },
-        {    3000,   396,  56,    192, OMX_VIDEO_AVCLevel11 },
-        {    6000,   396,  56,    384, OMX_VIDEO_AVCLevel12 },
-        {   11880,   396,  56,    768, OMX_VIDEO_AVCLevel13 },
-        {   11880,   396,  56,   2000, OMX_VIDEO_AVCLevel2  },
-        {   19800,   792,  79,   4000, OMX_VIDEO_AVCLevel21 },
-        {   20250,  1620, 113,   4000, OMX_VIDEO_AVCLevel22 },
-        {   40500,  1620, 113,  10000, OMX_VIDEO_AVCLevel3  },
-        {  108000,  3600, 169,  14000, OMX_VIDEO_AVCLevel31 },
-        {  216000,  5120, 202,  20000, OMX_VIDEO_AVCLevel32 },
-        {  245760,  8192, 256,  20000, OMX_VIDEO_AVCLevel4  },
-        {  245760,  8192, 256,  50000, OMX_VIDEO_AVCLevel41 },
-        {  522240,  8704, 263,  50000, OMX_VIDEO_AVCLevel42 },
-        {  589824, 22080, 420, 135000, OMX_VIDEO_AVCLevel5  },
-        {  983040, 36864, 543, 240000, OMX_VIDEO_AVCLevel51 },
-        { 2073600, 36864, 543, 240000, OMX_VIDEO_AVCLevel52 },
+        /*    MBps      MB   dim  bitrate        level */
+        {     1485,     99,   28,     64, OMX_VIDEO_AVCLevel1  },
+        {     1485,     99,   28,    128, OMX_VIDEO_AVCLevel1b },
+        {     3000,    396,   56,    192, OMX_VIDEO_AVCLevel11 },
+        {     6000,    396,   56,    384, OMX_VIDEO_AVCLevel12 },
+        {    11880,    396,   56,    768, OMX_VIDEO_AVCLevel13 },
+        {    11880,    396,   56,   2000, OMX_VIDEO_AVCLevel2  },
+        {    19800,    792,   79,   4000, OMX_VIDEO_AVCLevel21 },
+        {    20250,   1620,  113,   4000, OMX_VIDEO_AVCLevel22 },
+        {    40500,   1620,  113,  10000, OMX_VIDEO_AVCLevel3  },
+        {   108000,   3600,  169,  14000, OMX_VIDEO_AVCLevel31 },
+        {   216000,   5120,  202,  20000, OMX_VIDEO_AVCLevel32 },
+        {   245760,   8192,  256,  20000, OMX_VIDEO_AVCLevel4  },
+        {   245760,   8192,  256,  50000, OMX_VIDEO_AVCLevel41 },
+        {   522240,   8704,  263,  50000, OMX_VIDEO_AVCLevel42 },
+        {   589824,  22080,  420, 135000, OMX_VIDEO_AVCLevel5  },
+        {   983040,  36864,  543, 240000, OMX_VIDEO_AVCLevel51 },
+        {  2073600,  36864,  543, 240000, OMX_VIDEO_AVCLevel52 },
+        {  4177920, 139264, 1055, 240000, OMX_VIDEO_AVCLevel6  },
+        {  8355840, 139264, 1055, 480000, OMX_VIDEO_AVCLevel61 },
+        { 16711680, 139264, 1055, 800000, OMX_VIDEO_AVCLevel62 },
     };
 
     for (size_t i = 0; i < ARRAY_SIZE(limits); i++) {
@@ -4428,9 +4431,9 @@
         h264type.nRefFrames = 2;
         h264type.nBFrames = mLatency == 0 ? 1 : std::min(1U, mLatency - 1);
 
-        // disable B-frames until MPEG4Writer can guarantee finalizing files with B-frames
-        // h264type.nRefFrames = 1;
-        // h264type.nBFrames = 0;
+        // disable B-frames until we have explicit settings for enabling the feature.
+        h264type.nRefFrames = 1;
+        h264type.nBFrames = 0;
 
         h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate, h264type.nBFrames);
         h264type.nAllowedPictureTypes =
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 0f75822..5d2291f 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -643,6 +643,10 @@
             output->mBufferQueue.clear();
             output->mEncoderReachedEOS = true;
             output->mErrorCode = err;
+            if (!(mFlags & FLAG_USE_SURFACE_INPUT)) {
+                mStopping = true;
+                mPuller->stop();
+            }
             output->mCond.signal();
 
             reachedEOS = true;
@@ -761,8 +765,8 @@
 }
 
 status_t MediaCodecSource::onStart(MetaData *params) {
-    if (mStopping) {
-        ALOGE("Failed to start while we're stopping");
+    if (mStopping || mOutput.lock()->mEncoderReachedEOS) {
+        ALOGE("Failed to start while we're stopping or encoder already stopped due to EOS error");
         return INVALID_OPERATION;
     }
     int64_t startTimeUs;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 2e7da01..09424b8 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -192,6 +192,9 @@
         { 50, OMX_VIDEO_AVCLevel5  },
         { 51, OMX_VIDEO_AVCLevel51 },
         { 52, OMX_VIDEO_AVCLevel52 },
+        { 60, OMX_VIDEO_AVCLevel6  },
+        { 61, OMX_VIDEO_AVCLevel61 },
+        { 62, OMX_VIDEO_AVCLevel62 },
     };
     const static ALookup<uint8_t, OMX_VIDEO_AVCPROFILETYPE> profiles {
         { 66, OMX_VIDEO_AVCProfileBaseline },
@@ -1184,6 +1187,16 @@
         }
 
         parseHevcProfileLevelFromHvcc((const uint8_t *)data, dataSize, msg);
+    } else if (meta->findData(kKeyAV1C, &type, &data, &size)) {
+        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+        if (buffer.get() == NULL || buffer->base() == NULL) {
+            return NO_MEMORY;
+        }
+        memcpy(buffer->data(), data, size);
+
+        buffer->meta()->setInt32("csd", true);
+        buffer->meta()->setInt64("timeUs", 0);
+        msg->setBuffer("csd-0", buffer);
     } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
         ESDS esds((const char *)data, size);
         if (esds.InitCheck() != (status_t)OK) {
@@ -1690,6 +1703,11 @@
             meta->setInt32(kKeyIsADTS, isADTS);
         }
 
+        int32_t aacProfile = -1;
+        if (msg->findInt32("aac-profile", &aacProfile)) {
+            meta->setInt32(kKeyAACAOT, aacProfile);
+        }
+
         int32_t pcmEncoding;
         if (msg->findInt32("pcm-encoding", &pcmEncoding)) {
             meta->setInt32(kKeyPcmEncoding, pcmEncoding);
@@ -1743,6 +1761,8 @@
             std::vector<uint8_t> hvcc(csd0size + 1024);
             size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
             meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
+        } else if (mime == MEDIA_MIMETYPE_VIDEO_AV1) {
+            meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
         } else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
             meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
         } else if (mime == MEDIA_MIMETYPE_AUDIO_OPUS) {
diff --git a/media/libstagefright/data/media_codecs_google_c2_audio.xml b/media/libstagefright/data/media_codecs_google_c2_audio.xml
index f664395..47a9715 100644
--- a/media/libstagefright/data/media_codecs_google_c2_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_audio.xml
@@ -79,28 +79,28 @@
     </Decoders>
     <Encoders>
         <MediaCodec name="c2.android.aac.encoder" type="audio/mp4a-latm">
-            <Alias name="OMX.google.aac.decoder" />
+            <Alias name="OMX.google.aac.encoder" />
             <Limit name="channel-count" max="6" />
             <Limit name="sample-rate" ranges="8000,11025,12000,16000,22050,24000,32000,44100,48000" />
             <!-- also may support 64000, 88200  and 96000 Hz -->
             <Limit name="bitrate" range="8000-960000" />
         </MediaCodec>
         <MediaCodec name="c2.android.amrnb.encoder" type="audio/3gpp">
-            <Alias name="OMX.google.amrnb.decoder" />
+            <Alias name="OMX.google.amrnb.encoder" />
             <Limit name="channel-count" max="1" />
             <Limit name="sample-rate" ranges="8000" />
             <Limit name="bitrate" range="4750-12200" />
             <Feature name="bitrate-modes" value="CBR" />
         </MediaCodec>
         <MediaCodec name="c2.android.amrwb.encoder" type="audio/amr-wb">
-            <Alias name="OMX.google.amrwb.decoder" />
+            <Alias name="OMX.google.amrwb.encoder" />
             <Limit name="channel-count" max="1" />
             <Limit name="sample-rate" ranges="16000" />
             <Limit name="bitrate" range="6600-23850" />
             <Feature name="bitrate-modes" value="CBR" />
         </MediaCodec>
         <MediaCodec name="c2.android.flac.encoder" type="audio/flac">
-            <Alias name="OMX.google.flac.decoder" />
+            <Alias name="OMX.google.flac.encoder" />
             <Limit name="channel-count" max="2" />
             <Limit name="sample-rate" ranges="1-655350" />
             <Limit name="bitrate" range="1-21000000" />
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index 2910bd3..437bdb7 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -59,6 +59,7 @@
     kKeyAACProfile        = 'aacp',  // int32_t
     kKeyAVCC              = 'avcc',  // raw data
     kKeyHVCC              = 'hvcc',  // raw data
+    kKeyAV1C              = 'av1c',  // raw data
     kKeyThumbnailHVCC     = 'thvc',  // raw data
     kKeyD263              = 'd263',  // raw data
     kKeyVorbisInfo        = 'vinf',  // raw data
@@ -236,6 +237,7 @@
     kTypeESDS        = 'esds',
     kTypeAVCC        = 'avcc',
     kTypeHVCC        = 'hvcc',
+    kTypeAV1C        = 'av1c',
     kTypeD263        = 'd263',
 };
 
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 362b7f5..4383004 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -87,6 +87,7 @@
     vndk: {
         enabled: true,
     },
+    double_loadable: true,
     srcs: ["OMXUtils.cpp"],
     export_include_dirs: [
         "include",
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 5d993db..8454ca1 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -1913,7 +1913,7 @@
             mLastMediaTimeUs = mediaTimeUs;
         }
 
-        if (mediaTimeUs < 0) {
+        if (mediaTimeUs < 0 && !mSeekable) {
             ALOGV("dropping early accessUnit.");
             return false;
         }
diff --git a/media/libstagefright/xmlparser/Android.bp b/media/libstagefright/xmlparser/Android.bp
index bebfb3b..819058c 100644
--- a/media/libstagefright/xmlparser/Android.bp
+++ b/media/libstagefright/xmlparser/Android.bp
@@ -10,6 +10,7 @@
     vndk: {
         enabled: true,
     },
+    double_loadable: true,
 
     srcs: [
         "MediaCodecsXmlParser.cpp",
diff --git a/media/mtp/IMtpDatabase.h b/media/mtp/IMtpDatabase.h
index 1245092..81fa60c 100644
--- a/media/mtp/IMtpDatabase.h
+++ b/media/mtp/IMtpDatabase.h
@@ -112,8 +112,8 @@
                                             MtpObjectHandle handle, bool succeeded) = 0;
 
     virtual MtpResponseCode         beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
-                                            MtpStorageID newStorage);
-    virtual void                    endCopyObject(MtpObjectHandle handle, bool succeeded);
+                                            MtpStorageID newStorage) = 0;
+    virtual void                    endCopyObject(MtpObjectHandle handle, bool succeeded) = 0;
 };
 
 }; // namespace android
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index 010c1aa..c3eb437 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -69,6 +69,7 @@
         case AIMAGE_FORMAT_DEPTH16:
         case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
         case AIMAGE_FORMAT_Y8:
+        case AIMAGE_FORMAT_HEIC:
             return true;
         case AIMAGE_FORMAT_PRIVATE:
             // For private format, cpu usage is prohibited.
@@ -96,6 +97,7 @@
         case AIMAGE_FORMAT_DEPTH16:
         case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
         case AIMAGE_FORMAT_Y8:
+        case AIMAGE_FORMAT_HEIC:
             return 1;
         case AIMAGE_FORMAT_PRIVATE:
             return 0;
diff --git a/media/ndk/include/media/NdkImage.h b/media/ndk/include/media/NdkImage.h
index 15b340c..14d88cb 100644
--- a/media/ndk/include/media/NdkImage.h
+++ b/media/ndk/include/media/NdkImage.h
@@ -526,7 +526,15 @@
      * (in bytes) between adjacent rows.</p>
      *
      */
-    AIMAGE_FORMAT_Y8 = 0x20203859
+    AIMAGE_FORMAT_Y8 = 0x20203859,
+
+    /**
+     * Compressed HEIC format.
+     *
+     * <p>This format defines the HEIC brand of High Efficiency Image File
+     * Format as described in ISO/IEC 23008-12.</p>
+     */
+    AIMAGE_FORMAT_HEIC = 0x48454946,
 };
 
 /**
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 7733071..4033247 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -347,7 +347,7 @@
             return ret;
         }
     }
-    return AudioMixer::HAPTIC_SCALE_NONE;
+    return AudioMixer::HAPTIC_SCALE_MUTE;
 }
 
 /* static */
@@ -3277,9 +3277,13 @@
             }
             // look for the thread where the specified audio session is present
             for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-                if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
+                uint32_t sessionType = mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId);
+                if (sessionType != 0) {
                     io = mPlaybackThreads.keyAt(i);
-                    break;
+                    // thread with same effect session is preferable
+                    if ((sessionType & ThreadBase::EFFECT_SESSION) != 0) {
+                        break;
+                    }
                 }
             }
             if (io == AUDIO_IO_HANDLE_NONE) {
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index e78c98b..c5b9953 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -139,6 +139,75 @@
     }
 }
 
+void FastMixer::updateMixerTrack(int index, Reason reason) {
+    const FastMixerState * const current = (const FastMixerState *) mCurrent;
+    const FastTrack * const fastTrack = &current->mFastTracks[index];
+
+    // check and update generation
+    if (reason == REASON_MODIFY && mGenerations[index] == fastTrack->mGeneration) {
+        return; // no change on an already configured track.
+    }
+    mGenerations[index] = fastTrack->mGeneration;
+
+    // mMixer == nullptr on configuration failure (check done after generation update).
+    if (mMixer == nullptr) {
+        return;
+    }
+
+    switch (reason) {
+    case REASON_REMOVE:
+        mMixer->destroy(index);
+        break;
+    case REASON_ADD: {
+        const status_t status = mMixer->create(
+                index, fastTrack->mChannelMask, fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX);
+        LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
+                "%s: cannot create fast track index"
+                " %d, mask %#x, format %#x in AudioMixer",
+                __func__, index, fastTrack->mChannelMask, fastTrack->mFormat);
+    }
+        [[fallthrough]];  // now fallthrough to update the newly created track.
+    case REASON_MODIFY:
+        mMixer->setBufferProvider(index, fastTrack->mBufferProvider);
+
+        float vlf, vrf;
+        if (fastTrack->mVolumeProvider != nullptr) {
+            const gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
+            vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
+            vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
+        } else {
+            vlf = vrf = AudioMixer::UNITY_GAIN_FLOAT;
+        }
+
+        // set volume to avoid ramp whenever the track is updated (or created).
+        // Note: this does not distinguish from starting fresh or
+        // resuming from a paused state.
+        mMixer->setParameter(index, AudioMixer::VOLUME, AudioMixer::VOLUME0, &vlf);
+        mMixer->setParameter(index, AudioMixer::VOLUME, AudioMixer::VOLUME1, &vrf);
+
+        mMixer->setParameter(index, AudioMixer::RESAMPLE, AudioMixer::REMOVE, nullptr);
+        mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
+                (void *)mMixerBuffer);
+        mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::MIXER_FORMAT,
+                (void *)(uintptr_t)mMixerBufferFormat);
+        mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::FORMAT,
+                (void *)(uintptr_t)fastTrack->mFormat);
+        mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
+                (void *)(uintptr_t)fastTrack->mChannelMask);
+        mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
+                (void *)(uintptr_t)mSinkChannelMask);
+        mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::HAPTIC_ENABLED,
+                (void *)(uintptr_t)fastTrack->mHapticPlaybackEnabled);
+        mMixer->setParameter(index, AudioMixer::TRACK, AudioMixer::HAPTIC_INTENSITY,
+                (void *)(uintptr_t)fastTrack->mHapticIntensity);
+
+        mMixer->enable(index);
+        break;
+    default:
+        LOG_ALWAYS_FATAL("%s: invalid update reason %d", __func__, reason);
+    }
+}
+
 void FastMixer::onStateChange()
 {
     const FastMixerState * const current = (const FastMixerState *) mCurrent;
@@ -240,21 +309,16 @@
     // check for change in active track set
     const unsigned currentTrackMask = current->mTrackMask;
     dumpState->mTrackMask = currentTrackMask;
+    dumpState->mNumTracks = popcount(currentTrackMask);
     if (current->mFastTracksGen != mFastTracksGen) {
-        ALOG_ASSERT(mMixerBuffer != NULL);
 
         // process removed tracks first to avoid running out of track names
         unsigned removedTracks = previousTrackMask & ~currentTrackMask;
         while (removedTracks != 0) {
             int i = __builtin_ctz(removedTracks);
             removedTracks &= ~(1 << i);
-            const FastTrack* fastTrack = &current->mFastTracks[i];
-            ALOG_ASSERT(fastTrack->mBufferProvider == NULL);
-            if (mMixer != NULL) {
-                mMixer->destroy(i);
-            }
+            updateMixerTrack(i, REASON_REMOVE);
             // don't reset track dump state, since other side is ignoring it
-            mGenerations[i] = fastTrack->mGeneration;
         }
 
         // now process added tracks
@@ -262,40 +326,7 @@
         while (addedTracks != 0) {
             int i = __builtin_ctz(addedTracks);
             addedTracks &= ~(1 << i);
-            const FastTrack* fastTrack = &current->mFastTracks[i];
-            AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
-            if (mMixer != NULL) {
-                const int name = i; // for clarity, choose name as fast track index.
-                status_t status = mMixer->create(
-                        name,
-                        fastTrack->mChannelMask,
-                        fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX);
-                LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-                        "%s: cannot create track name"
-                        " %d, mask %#x, format %#x, sessionId %d in AudioMixer",
-                        __func__, name,
-                        fastTrack->mChannelMask, fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX);
-                mMixer->setBufferProvider(name, bufferProvider);
-                mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
-                        (void *)mMixerBuffer);
-                // newly allocated track names default to full scale volume
-                mMixer->setParameter(
-                        name,
-                        AudioMixer::TRACK,
-                        AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
-                mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
-                        (void *)(uintptr_t)fastTrack->mFormat);
-                mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
-                        (void *)(uintptr_t)fastTrack->mChannelMask);
-                mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
-                        (void *)(uintptr_t)mSinkChannelMask);
-                mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_ENABLED,
-                        (void *)(uintptr_t)fastTrack->mHapticPlaybackEnabled);
-                mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_INTENSITY,
-                        (void *)(uintptr_t)fastTrack->mHapticIntensity);
-                mMixer->enable(name);
-            }
-            mGenerations[i] = fastTrack->mGeneration;
+            updateMixerTrack(i, REASON_ADD);
         }
 
         // finally process (potentially) modified tracks; these use the same slot
@@ -304,44 +335,10 @@
         while (modifiedTracks != 0) {
             int i = __builtin_ctz(modifiedTracks);
             modifiedTracks &= ~(1 << i);
-            const FastTrack* fastTrack = &current->mFastTracks[i];
-            if (fastTrack->mGeneration != mGenerations[i]) {
-                // this track was actually modified
-                AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
-                ALOG_ASSERT(bufferProvider != NULL);
-                if (mMixer != NULL) {
-                    const int name = i;
-                    mMixer->setBufferProvider(name, bufferProvider);
-                    if (fastTrack->mVolumeProvider == NULL) {
-                        float f = AudioMixer::UNITY_GAIN_FLOAT;
-                        mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &f);
-                        mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &f);
-                    }
-                    mMixer->setParameter(name, AudioMixer::RESAMPLE,
-                            AudioMixer::REMOVE, NULL);
-                    mMixer->setParameter(
-                            name,
-                            AudioMixer::TRACK,
-                            AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
-                    mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
-                            (void *)(uintptr_t)fastTrack->mFormat);
-                    mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
-                            (void *)(uintptr_t)fastTrack->mChannelMask);
-                    mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
-                            (void *)(uintptr_t)mSinkChannelMask);
-                    mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_ENABLED,
-                            (void *)(uintptr_t)fastTrack->mHapticPlaybackEnabled);
-                    mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_INTENSITY,
-                            (void *)(uintptr_t)fastTrack->mHapticIntensity);
-                    // already enabled
-                }
-                mGenerations[i] = fastTrack->mGeneration;
-            }
+            updateMixerTrack(i, REASON_MODIFY);
         }
 
         mFastTracksGen = current->mFastTracksGen;
-
-        dumpState->mNumTracks = popcount(currentTrackMask);
     }
 }
 
@@ -408,8 +405,8 @@
                 float vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
                 float vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
 
-                mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &vlf);
-                mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &vrf);
+                mMixer->setParameter(name, AudioMixer::RAMP_VOLUME, AudioMixer::VOLUME0, &vlf);
+                mMixer->setParameter(name, AudioMixer::RAMP_VOLUME, AudioMixer::VOLUME1, &vrf);
             }
             // FIXME The current implementation of framesReady() for fast tracks
             // takes a tryLock, which can block
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index c31d476..97ab635 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -59,6 +59,14 @@
     virtual void onStateChange();
     virtual void onWork();
 
+    enum Reason {
+        REASON_REMOVE,
+        REASON_ADD,
+        REASON_MODIFY,
+    };
+    // called when a fast track of index has been removed, added, or modified
+    void updateMixerTrack(int index, Reason reason);
+
     // FIXME these former local variables need comments
     static const FastMixerState sInitial;
 
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index c27f2b7..396c797 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -49,7 +49,7 @@
     audio_format_t          mFormat;         // track format
     int                     mGeneration;     // increment when any field is assigned
     bool                    mHapticPlaybackEnabled = false; // haptic playback is enabled or not
-    AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_NONE; // intensity of
+    AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_MUTE; // intensity of
                                                                                      // haptic data
 };
 
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 3381e4d..676a575 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -211,8 +211,8 @@
                 ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
                  ((patch->sinks[0].ext.device.hw_module != srcModule) ||
                   !audioHwDevice->supportsAudioPatches()))) {
-                audio_devices_t outputDevice = AUDIO_DEVICE_NONE;
-                String8 outputDeviceAddress;
+                audio_devices_t outputDevice = patch->sinks[0].ext.device.type;
+                String8 outputDeviceAddress = String8(patch->sinks[0].ext.device.address);
                 if (patch->num_sources == 2) {
                     if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
                             (patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module !=
@@ -234,8 +234,6 @@
                             reinterpret_cast<PlaybackThread*>(thread.get()), false /*closeThread*/);
                 } else {
                     audio_config_t config = AUDIO_CONFIG_INITIALIZER;
-                    audio_devices_t device = patch->sinks[0].ext.device.type;
-                    String8 address = String8(patch->sinks[0].ext.device.address);
                     audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
                     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
                     if (patch->sinks[0].config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
@@ -254,8 +252,8 @@
                                                             patch->sinks[0].ext.device.hw_module,
                                                             &output,
                                                             &config,
-                                                            device,
-                                                            address,
+                                                            outputDevice,
+                                                            outputDeviceAddress,
                                                             flags);
                     ALOGV("mAudioFlinger.openOutput_l() returned %p", thread.get());
                     if (thread == 0) {
@@ -263,8 +261,6 @@
                         goto exit;
                     }
                     newPatch.mPlayback.setThread(reinterpret_cast<PlaybackThread*>(thread.get()));
-                    outputDevice = device;
-                    outputDeviceAddress = address;
                 }
                 audio_devices_t device = patch->sources[0].ext.device.type;
                 String8 address = String8(patch->sources[0].ext.device.address);
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 94ea042..357370e 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -124,6 +124,7 @@
             void    setHapticIntensity(AudioMixer::haptic_intensity_t hapticIntensity) {
                 if (AudioMixer::isValidHapticIntensity(hapticIntensity)) {
                     mHapticIntensity = hapticIntensity;
+                    setHapticPlaybackEnabled(mHapticIntensity != AudioMixer::HAPTIC_SCALE_MUTE);
                 }
             }
             sp<os::ExternalVibration> getExternalVibration() const { return mExternalVibration; }
@@ -208,7 +209,7 @@
 
     bool                mHapticPlaybackEnabled = false; // indicates haptic playback enabled or not
     // intensity to play haptic data
-    AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_NONE;
+    AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_MUTE;
     class AudioVibrationController : public os::BnExternalVibrationController {
     public:
         explicit AudioVibrationController(Track* track) : mTrack(track) {}
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index dd1eabf..a8c4bd1 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2372,6 +2372,7 @@
             const int intensity = AudioFlinger::onExternalVibrationStart(
                     track->getExternalVibration());
             mLock.lock();
+            track->setHapticIntensity(static_cast<AudioMixer::haptic_intensity_t>(intensity));
             // Haptic playback should be enabled by vibrator service.
             if (track->getHapticPlaybackEnabled()) {
                 // Disable haptic playback of all active track to ensure only
@@ -2380,7 +2381,6 @@
                     t->setHapticPlaybackEnabled(false);
                 }
             }
-            track->setHapticIntensity(intensity);
         }
 
         track->mResetDone = false;
@@ -4784,7 +4784,10 @@
                 track->mFillingUpStatus = Track::FS_ACTIVE;
                 if (track->mState == TrackBase::RESUMING) {
                     track->mState = TrackBase::ACTIVE;
-                    param = AudioMixer::RAMP_VOLUME;
+                    // If a new track is paused immediately after start, do not ramp on resume.
+                    if (cblk->mServer != 0) {
+                        param = AudioMixer::RAMP_VOLUME;
+                    }
                 }
                 mAudioMixer->setParameter(trackId, AudioMixer::RESAMPLE, AudioMixer::RESET, NULL);
                 mLeftVolFloat = -1.0;
@@ -5462,6 +5465,11 @@
                 mFlushPending = true;
             }
         }
+    } else if (previousTrack == 0) {
+        // there could be an old track added back during track transition for direct
+        // output, so always issues flush to flush data of the previous track if it
+        // was already destroyed with HAL paused, then flush can resume the playback
+        mFlushPending = true;
     }
     PlaybackThread::onAddNewTrack_l();
 }
@@ -5500,7 +5508,6 @@
                 doHwPause = true;
                 mHwPaused = true;
             }
-            tracksToRemove->add(track);
         } else if (track->isFlushPending()) {
             track->flushAck();
             if (last) {
@@ -5597,7 +5604,8 @@
 
                 int64_t framesWritten = mBytesWritten / mFrameSize;
                 if (mStandby || !last ||
-                        track->presentationComplete(framesWritten, audioHALFrames)) {
+                        track->presentationComplete(framesWritten, audioHALFrames) ||
+                        track->isPaused()) {
                     if (track->isStopping_2()) {
                         track->mState = TrackBase::STOPPED;
                     }
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index d4cfd1e..803cfac 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -143,6 +143,16 @@
 
     void trackEffectEnabled(const sp<EffectDescriptor> &effect, bool enabled);
 
+    /**
+    * @brief clearSessionRoutesForDevice: when a device is disconnected, and if this device has
+    * been chosen as the preferred device by any client, the policy manager shall
+    * prevent from using this device any more by clearing all the session routes involving this
+    * device.
+    * In other words, the preferred device port id of these clients will be resetted to NONE.
+    * @param disconnectedDevice device to be disconnected
+    */
+    void clearSessionRoutesForDevice(const sp<DeviceDescriptor> &disconnectedDevice);
+
     void dump(String8 *dst) const;
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 6132bb4..c84636e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -380,6 +380,16 @@
                                       uint32_t inPastMs = 0, nsecs_t sysTime = 0) const;
 
     /**
+     * @brief clearSessionRoutesForDevice: when a device is disconnected, and if this device has
+     * been chosen as the preferred device by any client, the policy manager shall
+     * prevent from using this device any more by clearing all the session routes involving this
+     * device.
+     * In other words, the preferred device port id of these clients will be resetted to NONE.
+     * @param disconnectedDevice device to be disconnected
+     */
+    void clearSessionRoutesForDevice(const sp<DeviceDescriptor> &disconnectedDevice);
+
+    /**
      * returns the A2DP output handle if it is open or 0 otherwise
      */
     audio_io_handle_t getA2dpOutput() const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 1abce6f..d6f24b2 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -43,12 +43,12 @@
 
     android::AudioMix *getMix();
 
-    void setMix(AudioMix &mix);
+    void setMix(const AudioMix &mix);
 
     void dump(String8 *dst, int spaces, int index) const;
 
 private:
-    AudioMix    mMix;                   // Audio policy mix descriptor
+    AudioMix    mMix;                     // Audio policy mix descriptor
     sp<SwAudioOutputDescriptor> mOutput;  // Corresponding output stream
 };
 
@@ -71,7 +71,7 @@
      * @param[out] desc to return if an primary output could be found.
      * @param[out] secondaryDesc other desc that the audio should be routed to.
      */
-    status_t getOutputForAttr(audio_attributes_t attributes, uid_t uid,
+    status_t getOutputForAttr(const audio_attributes_t& attributes, uid_t uid,
                 sp<SwAudioOutputDescriptor> &primaryDesc,
                 std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs);
 
@@ -102,7 +102,7 @@
 private:
     enum class MixMatchStatus { MATCH, NO_MATCH, INVALID_MIX };
     MixMatchStatus mixMatch(const AudioMix* mix, size_t mixIndex,
-                            audio_attributes_t attributes, uid_t uid);
+                            const audio_attributes_t& attributes, uid_t uid);
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index c880e67..1fa1123 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -511,6 +511,19 @@
     }
 }
 
+void AudioInputCollection::clearSessionRoutesForDevice(
+    const sp<DeviceDescriptor> &disconnectedDevice)
+{
+    for (size_t i = 0; i < size(); i++) {
+        sp<AudioInputDescriptor> inputDesc = valueAt(i);
+        for (const auto& client : inputDesc->getClientIterable()) {
+            if (client->preferredDeviceId() == disconnectedDevice->getId()) {
+                client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+            }
+        }
+    }
+}
+
 void AudioInputCollection::dump(String8 *dst) const
 {
     dst->append("\nInputs dump:\n");
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 1dfd88a..77e7add 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -802,6 +802,19 @@
     return 0;
 }
 
+void SwAudioOutputCollection::clearSessionRoutesForDevice(
+        const sp<DeviceDescriptor> &disconnectedDevice)
+{
+    for (size_t i = 0; i < size(); i++) {
+        sp<AudioOutputDescriptor> outputDesc = valueAt(i);
+        for (const auto& client : outputDesc->getClientIterable()) {
+            if (client->preferredDeviceId() == disconnectedDevice->getId()) {
+                client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+            }
+        }
+    }
+}
+
 void SwAudioOutputCollection::dump(String8 *dst) const
 {
     dst->append("\nOutputs dump:\n");
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 6b6d9d2..2c4695d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -42,7 +42,7 @@
     mOutput.clear();
 }
 
-void AudioPolicyMix::setMix(AudioMix &mix)
+void AudioPolicyMix::setMix(const AudioMix &mix)
 {
     mMix = mix;
 }
@@ -157,7 +157,7 @@
 }
 
 status_t AudioPolicyMixCollection::getOutputForAttr(
-        audio_attributes_t attributes, uid_t uid, sp<SwAudioOutputDescriptor> &primaryDesc,
+        const audio_attributes_t& attributes, uid_t uid, sp<SwAudioOutputDescriptor> &primaryDesc,
         std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs)
 {
     ALOGV("getOutputForAttr() querying %zu mixes:", size());
@@ -203,9 +203,21 @@
 }
 
 AudioPolicyMixCollection::MixMatchStatus AudioPolicyMixCollection::mixMatch(
-        const AudioMix* mix, size_t mixIndex, audio_attributes_t attributes, uid_t uid) {
+        const AudioMix* mix, size_t mixIndex, const audio_attributes_t& attributes, uid_t uid) {
 
     if (mix->mMixType == MIX_TYPE_PLAYERS) {
+        // Loopback render mixes are created from a public API and thus restricted
+        // to non sensible audio that have not opted out.
+        if (is_mix_loopback_render(mix->mRouteFlags)) {
+            if ((attributes.flags & AUDIO_FLAG_NO_CAPTURE) == AUDIO_FLAG_NO_CAPTURE) {
+                return MixMatchStatus::NO_MATCH;
+            }
+            if (!(attributes.usage == AUDIO_USAGE_UNKNOWN ||
+                  attributes.usage == AUDIO_USAGE_MEDIA ||
+                  attributes.usage == AUDIO_USAGE_GAME)) {
+                return MixMatchStatus::NO_MATCH;
+            }
+        }
         // TODO if adding more player rules (currently only 2), make rule handling "generic"
         //      as there is no difference in the treatment of usage- or uid-based rules
         bool hasUsageMatchRules = false;
@@ -378,7 +390,7 @@
     ALOGV("getInputMixForAttr looking for address %s\n  mixes available:", address.string());
     for (size_t i = 0; i < size(); i++) {
             sp<AudioPolicyMix> policyMix = valueAt(i);
-            AudioMix *mix = policyMix->getMix();
+            const AudioMix *mix = policyMix->getMix();
             ALOGV("\tmix %zu address=%s", i, mix->mDeviceAddress.string());
     }
 #endif
@@ -435,7 +447,7 @@
     // for each player mix: remove existing rules that match or exclude this uid
     for (size_t i = 0; i < size(); i++) {
         bool foundUidRule = false;
-        AudioMix *mix = valueAt(i)->getMix();
+        const AudioMix *mix = valueAt(i)->getMix();
         if (mix->mMixType != MIX_TYPE_PLAYERS) {
             continue;
         }
@@ -463,7 +475,7 @@
     // for each player mix: find rules that don't exclude this uid, and add the device to the list
     for (size_t i = 0; i < size(); i++) {
         bool ruleAllowsUid = true;
-        AudioMix *mix = valueAt(i)->getMix();
+        const AudioMix *mix = valueAt(i)->getMix();
         if (mix->mMixType != MIX_TYPE_PLAYERS) {
             continue;
         }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index ccec93f..32cc380 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -193,6 +193,8 @@
             // remove device from available output devices
             mAvailableOutputDevices.remove(device);
 
+            mOutputs.clearSessionRoutesForDevice(device);
+
             checkOutputsForDevice(device, state, outputs);
 
             // Reset active device codec
@@ -558,6 +560,10 @@
         muteWaitMs = setOutputDevices(mPrimaryOutput, rxDevices, true, delayMs);
     } else { // create RX path audio patch
         mCallRxPatch = createTelephonyPatch(true /*isRx*/, rxDevices.itemAt(0), delayMs);
+
+        // If the TX device is on the primary HW module but RX device is
+        // on other HW module, SinkMetaData of telephony input should handle it
+        // assuming the device uses audio HAL V5.0 and above
     }
     if (createTxPatch) { // create TX path audio patch
         mCallTxPatch = createTelephonyPatch(false /*isRx*/, txSourceDevice, delayMs);
@@ -929,8 +935,6 @@
     const sp<DeviceDescriptor> requestedDevice =
         mAvailableOutputDevices.getDeviceFromId(requestedPortId);
 
-
-
     status_t status = getAudioAttributes(resultAttr, attr, *stream);
     if (status != NO_ERROR) {
         return status;
@@ -953,8 +957,8 @@
 
     // FIXME: in case of RENDER policy, the output capabilities should be checked
     if ((usePrimaryOutputFromPolicyMixes || !secondaryDescs->empty())
-        && !audio_has_proportional_frames(config->format)) {
-        ALOGW("%s: audio loopback only supports proportional frames", __func__);
+        && !audio_is_linear_pcm(config->format)) {
+        ALOGD("%s: rejecting request as dynamic audio policy only support pcm", __func__);
         return BAD_VALUE;
     }
     if (usePrimaryOutputFromPolicyMixes) {
@@ -1045,6 +1049,14 @@
     audio_attributes_t resultAttr;
     bool isRequestedDeviceForExclusiveUse = false;
     std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputDescs;
+    const sp<DeviceDescriptor> requestedDevice =
+      mAvailableOutputDevices.getDeviceFromId(requestedPortId);
+
+    // Prevent from storing invalid requested device id in clients
+    const audio_port_handle_t sanitizedRequestedPortId =
+      requestedDevice != nullptr ? requestedPortId : AUDIO_PORT_HANDLE_NONE;
+    *selectedDeviceId = sanitizedRequestedPortId;
+
     status_t status = getOutputForAttrInt(&resultAttr, output, session, attr, stream, uid,
             config, flags, selectedDeviceId, &isRequestedDeviceForExclusiveUse,
             &secondaryOutputDescs);
@@ -1064,15 +1076,15 @@
 
     sp<TrackClientDescriptor> clientDesc =
         new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
-                                  requestedPortId, *stream,
+                                  sanitizedRequestedPortId, *stream,
                                   mEngine->getProductStrategyForAttributes(resultAttr),
                                   *flags, isRequestedDeviceForExclusiveUse,
                                   std::move(weakSecondaryOutputDescs));
     sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
     outputDesc->addClient(clientDesc);
 
-    ALOGV("%s() returns output %d selectedDeviceId %d for port ID %d", __func__,
-          *output, *selectedDeviceId, *portId);
+    ALOGV("%s() returns output %d requestedPortId %d selectedDeviceId %d for port ID %d", __func__,
+          *output, requestedPortId, *selectedDeviceId, *portId);
 
     return NO_ERROR;
 }
@@ -1953,6 +1965,8 @@
         if (explicitRoutingDevice != nullptr) {
             device = explicitRoutingDevice;
         } else {
+            // Prevent from storing invalid requested device id in clients
+            requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
             device = mEngine->getInputDeviceForAttributes(attributes, &policyMix);
         }
         if (device == nullptr) {
@@ -5295,16 +5309,17 @@
 
     // filter devices according to output selected
     DeviceVector filteredDevices = outputDesc->filterSupportedDevices(devices);
+    DeviceVector prevDevices = outputDesc->devices();
 
     // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
-    // output profile
-    if (!devices.isEmpty() && filteredDevices.isEmpty()) {
+    // output profile or if new device is not supported AND previous device(s) is(are) still
+    // available (otherwise reset device must be done on the output)
+    if (!devices.isEmpty() && filteredDevices.isEmpty() &&
+            !mAvailableOutputDevices.filter(prevDevices).empty()) {
         ALOGV("%s: unsupported device %s for output", __func__, devices.toString().c_str());
         return 0;
     }
 
-    DeviceVector prevDevices = outputDesc->devices();
-
     ALOGV("setOutputDevices() prevDevice %s", prevDevices.toString().c_str());
 
     if (!filteredDevices.isEmpty()) {
@@ -5819,6 +5834,8 @@
         }
     }
 
+    mInputs.clearSessionRoutesForDevice(deviceDesc);
+
     mHwModules.cleanUpForDevice(deviceDesc);
 }
 
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index a090479..2ca8356 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -41,6 +41,8 @@
         "api2/CameraDeviceClient.cpp",
         "api2/CompositeStream.cpp",
         "api2/DepthCompositeStream.cpp",
+        "api2/HeicEncoderInfoManager.cpp",
+        "api2/HeicCompositeStream.cpp",
         "device1/CameraHardwareInterface.cpp",
         "device3/Camera3Device.cpp",
         "device3/Camera3Stream.cpp",
@@ -62,12 +64,14 @@
         "hidl/HidlCameraService.cpp",
         "utils/CameraTraces.cpp",
         "utils/AutoConditionLock.cpp",
+        "utils/ExifUtils.cpp",
         "utils/TagMonitor.cpp",
         "utils/LatencyHistogram.cpp",
     ],
 
     shared_libs: [
         "libdl",
+        "libexif",
         "libui",
         "liblog",
         "libutilscallstack",
@@ -85,14 +89,17 @@
         "libhidlbase",
         "libhidltransport",
         "libjpeg",
+        "libmedia_omx",
         "libmemunreachable",
         "libsensorprivacy",
+        "libstagefright",
         "libstagefright_foundation",
         "android.frameworks.cameraservice.common@2.0",
         "android.frameworks.cameraservice.service@2.0",
         "android.frameworks.cameraservice.device@2.0",
         "android.hardware.camera.common@1.0",
         "android.hardware.camera.provider@2.4",
+        "android.hardware.camera.provider@2.5",
         "android.hardware.camera.device@1.0",
         "android.hardware.camera.device@3.2",
         "android.hardware.camera.device@3.3",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index ee8d7e1..e06897f 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1654,6 +1654,49 @@
     return Status::ok();
 }
 
+Status CameraService::notifyDeviceStateChange(int64_t newState) {
+    const int pid = CameraThreadState::getCallingPid();
+    const int selfPid = getpid();
+
+    // Permission checks
+    if (pid != selfPid) {
+        // Ensure we're being called by system_server, or similar process with
+        // permissions to notify the camera service about system events
+        if (!checkCallingPermission(
+                String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
+            const int uid = CameraThreadState::getCallingUid();
+            ALOGE("Permission Denial: cannot send updates to camera service about device"
+                    " state changes from pid=%d, uid=%d", pid, uid);
+            return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
+                    "No permission to send updates to camera service about device state"
+                    " changes from pid=%d, uid=%d", pid, uid);
+        }
+    }
+
+    ATRACE_CALL();
+
+    using hardware::camera::provider::V2_5::DeviceState;
+    hardware::hidl_bitfield<DeviceState> newDeviceState{};
+    if (newState & ICameraService::DEVICE_STATE_BACK_COVERED) {
+        newDeviceState |= DeviceState::BACK_COVERED;
+    }
+    if (newState & ICameraService::DEVICE_STATE_FRONT_COVERED) {
+        newDeviceState |= DeviceState::FRONT_COVERED;
+    }
+    if (newState & ICameraService::DEVICE_STATE_FOLDED) {
+        newDeviceState |= DeviceState::FOLDED;
+    }
+    // Only map vendor bits directly
+    uint64_t vendorBits = static_cast<uint64_t>(newState) & 0xFFFFFFFF00000000l;
+    newDeviceState |= vendorBits;
+
+    ALOGV("%s: New device state 0x%" PRIx64, __FUNCTION__, newDeviceState);
+    Mutex::Autolock l(mServiceLock);
+    mCameraProviderManager->notifyDeviceStateChange(newDeviceState);
+
+    return Status::ok();
+}
+
 Status CameraService::addListener(const sp<ICameraServiceListener>& listener,
         /*out*/
         std::vector<hardware::CameraStatus> *cameraStatuses) {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 3af52fa..cf0cef8 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -154,6 +154,8 @@
     virtual binder::Status    notifySystemEvent(int32_t eventId,
             const std::vector<int32_t>& args);
 
+    virtual binder::Status    notifyDeviceStateChange(int64_t newState);
+
     // OK = supports api of that version, -EOPNOTSUPP = does not support
     virtual binder::Status    supportsCameraApi(
             const String16& cameraId, int32_t apiVersion,
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index c9c216b..e002e18 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -1773,6 +1773,8 @@
             break;
     }
 
+    mCaptureSequencer->notifyError(errorCode, resultExtras);
+
     ALOGE("%s: Error condition %d reported by HAL, requestId %" PRId32, __FUNCTION__, errorCode,
               resultExtras.requestId);
 
@@ -1927,9 +1929,6 @@
 
 void Camera2Client::notifyShutter(const CaptureResultExtras& resultExtras,
                                   nsecs_t timestamp) {
-    (void)resultExtras;
-    (void)timestamp;
-
     ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64,
             __FUNCTION__, resultExtras.requestId, timestamp);
     mCaptureSequencer->notifyShutter(resultExtras, timestamp);
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 5029d4b..88799f9 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -117,6 +117,31 @@
     }
 }
 
+void CaptureSequencer::notifyError(int32_t errorCode, const CaptureResultExtras& resultExtras) {
+    ATRACE_CALL();
+    bool jpegBufferLost = false;
+    if (errorCode == hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER) {
+        sp<Camera2Client> client = mClient.promote();
+        if (client == nullptr) {
+            return;
+        }
+        int captureStreamId = client->getCaptureStreamId();
+        if (captureStreamId == resultExtras.errorStreamId) {
+            jpegBufferLost = true;
+        }
+    } else if (errorCode ==
+            hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST) {
+        if (resultExtras.requestId == mShutterCaptureId) {
+            jpegBufferLost = true;
+        }
+    }
+
+    if (jpegBufferLost) {
+        sp<MemoryBase> emptyBuffer;
+        onCaptureAvailable(/*timestamp*/0, emptyBuffer, /*captureError*/true);
+    }
+}
+
 void CaptureSequencer::onResultAvailable(const CaptureResult &result) {
     ATRACE_CALL();
     ALOGV("%s: New result available.", __FUNCTION__);
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index c23b12d..727dd53 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -65,6 +65,9 @@
     void notifyShutter(const CaptureResultExtras& resultExtras,
                        nsecs_t timestamp);
 
+    // Notifications about shutter (capture start)
+    void notifyError(int32_t errorCode, const CaptureResultExtras& resultExtras);
+
     // Notification from the frame processor
     virtual void onResultAvailable(const CaptureResult &result);
 
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index e6f75f4..ddfe5e3 100755
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -62,30 +62,6 @@
     }
 }
 
-void JpegProcessor::onBufferRequestForFrameNumber(uint64_t /*frameNumber*/, int /*streamId*/) {
-    // Intentionally left empty
-}
-
-void JpegProcessor::onBufferAcquired(const BufferInfo& /*bufferInfo*/) {
-    // Intentionally left empty
-}
-
-void JpegProcessor::onBufferReleased(const BufferInfo& bufferInfo) {
-    ALOGV("%s", __FUNCTION__);
-    if (bufferInfo.mError) {
-        // Only lock in case of error, since we get one of these for each
-        // onFrameAvailable as well, and scheduling may delay this call late
-        // enough to run into later preview restart operations, for non-error
-        // cases.
-        // b/29524651
-        ALOGV("%s: JPEG buffer lost", __FUNCTION__);
-        Mutex::Autolock l(mInputMutex);
-        mCaptureDone = true;
-        mCaptureSuccess = false;
-        mCaptureDoneSignal.signal();
-    }
-}
-
 status_t JpegProcessor::updateStream(const Parameters &params) {
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
@@ -180,13 +156,6 @@
                     strerror(-res), res);
             return res;
         }
-
-        res = device->addBufferListenerForStream(mCaptureStreamId, this);
-        if (res != OK) {
-              ALOGE("%s: Camera %d: Can't add buffer listeneri: %s (%d)",
-                    __FUNCTION__, mId, strerror(-res), res);
-              return res;
-        }
     }
     return OK;
 }
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.h b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
index 2ee930e..977f11d 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
@@ -42,8 +42,7 @@
  * Still image capture output image processing
  */
 class JpegProcessor:
-            public Thread, public CpuConsumer::FrameAvailableListener,
-            public camera3::Camera3StreamBufferListener {
+            public Thread, public CpuConsumer::FrameAvailableListener {
   public:
     JpegProcessor(sp<Camera2Client> client, wp<CaptureSequencer> sequencer);
     ~JpegProcessor();
@@ -51,11 +50,6 @@
     // CpuConsumer listener implementation
     void onFrameAvailable(const BufferItem& item);
 
-    // Camera3StreamBufferListener implementation
-    void onBufferAcquired(const BufferInfo& bufferInfo) override;
-    void onBufferReleased(const BufferInfo& bufferInfo) override;
-    void onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId) override;
-
     status_t updateStream(const Parameters &params);
     status_t deleteStream();
     int getStreamId() const;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 9e203da..b512f2b 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -34,6 +34,7 @@
 #include <camera_metadata_hidden.h>
 
 #include "DepthCompositeStream.h"
+#include "HeicCompositeStream.h"
 
 // Convenience methods for constructing binder::Status objects for error returns
 
@@ -711,21 +712,35 @@
                 return res;
 
             if (!isStreamInfoValid) {
-                if (camera3::DepthCompositeStream::isDepthCompositeStream(surface)) {
+                bool isDepthCompositeStream =
+                        camera3::DepthCompositeStream::isDepthCompositeStream(surface);
+                bool isHeicCompositeStream =
+                        camera3::HeicCompositeStream::isHeicCompositeStream(surface);
+                if (isDepthCompositeStream || isHeicCompositeStream) {
                     // We need to take in to account that composite streams can have
                     // additional internal camera streams.
                     std::vector<OutputStreamInfo> compositeStreams;
-                    ret = camera3::DepthCompositeStream::getCompositeStreamInfo(streamInfo,
+                    if (isDepthCompositeStream) {
+                        ret = camera3::DepthCompositeStream::getCompositeStreamInfo(streamInfo,
+                                mDevice->info(), &compositeStreams);
+                    } else {
+                        ret = camera3::HeicCompositeStream::getCompositeStreamInfo(streamInfo,
                             mDevice->info(), &compositeStreams);
+                    }
                     if (ret != OK) {
                         String8 msg = String8::format(
-                                "Camera %s: Failed adding depth composite streams: %s (%d)",
+                                "Camera %s: Failed adding composite streams: %s (%d)",
                                 mCameraIdStr.string(), strerror(-ret), ret);
                         ALOGE("%s: %s", __FUNCTION__, msg.string());
                         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
                     }
 
-                    if (compositeStreams.size() > 1) {
+                    if (compositeStreams.size() == 0) {
+                        // No internal streams means composite stream not
+                        // supported.
+                        *status = false;
+                        return binder::Status::ok();
+                    } else if (compositeStreams.size() > 1) {
                         streamCount += compositeStreams.size() - 1;
                         streamConfiguration.streams.resize(streamCount);
                     }
@@ -937,15 +952,16 @@
 
     int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
     std::vector<int> surfaceIds;
-    if (!camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0])) {
-        err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width,
-                streamInfo.height, streamInfo.format, streamInfo.dataSpace,
-                static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
-                &streamId, physicalCameraId, &surfaceIds, outputConfiguration.getSurfaceSetID(),
-                isShared);
-    } else {
-        sp<CompositeStream> compositeStream = new camera3::DepthCompositeStream(mDevice,
-                getRemoteCallback());
+    bool isDepthCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0]);
+    bool isHeicCompisiteStream = camera3::HeicCompositeStream::isHeicCompositeStream(surfaces[0]);
+    if (isDepthCompositeStream || isHeicCompisiteStream) {
+        sp<CompositeStream> compositeStream;
+        if (isDepthCompositeStream) {
+            compositeStream = new camera3::DepthCompositeStream(mDevice, getRemoteCallback());
+        } else {
+            compositeStream = new camera3::HeicCompositeStream(mDevice, getRemoteCallback());
+        }
+
         err = compositeStream->createStream(surfaces, deferredConsumer, streamInfo.width,
                 streamInfo.height, streamInfo.format,
                 static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
@@ -955,6 +971,12 @@
             mCompositeStreamMap.add(IInterface::asBinder(surfaces[0]->getIGraphicBufferProducer()),
                     compositeStream);
         }
+    } else {
+        err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width,
+                streamInfo.height, streamInfo.format, streamInfo.dataSpace,
+                static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
+                &streamId, physicalCameraId, &surfaceIds, outputConfiguration.getSurfaceSetID(),
+                isShared);
     }
 
     if (err != OK) {
@@ -1437,6 +1459,8 @@
     camera_metadata_ro_entry streamConfigs =
             (dataSpace == HAL_DATASPACE_DEPTH) ?
             info.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS) :
+            (dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_HEIF)) ?
+            info.find(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS) :
             info.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
 
     int32_t bestWidth = -1;
@@ -1930,6 +1954,10 @@
         remoteCb->onCaptureStarted(resultExtras, timestamp);
     }
     Camera2ClientBase::notifyShutter(resultExtras, timestamp);
+
+    for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+        mCompositeStreamMap.valueAt(i)->onShutter(resultExtras, timestamp);
+    }
 }
 
 void CameraDeviceClient::notifyPrepared(int streamId) {
diff --git a/services/camera/libcameraservice/api2/CompositeStream.cpp b/services/camera/libcameraservice/api2/CompositeStream.cpp
index 796bf42..354eaf9 100644
--- a/services/camera/libcameraservice/api2/CompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/CompositeStream.cpp
@@ -82,7 +82,8 @@
     return deleteInternalStreams();
 }
 
-void CompositeStream::onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId) {
+void CompositeStream::onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId,
+        const CameraMetadata& /*settings*/) {
     Mutex::Autolock l(mMutex);
     if (!mErrorState && (streamId == getStreamId())) {
         mPendingCaptureResults.emplace(frameNumber, CameraMetadata());
diff --git a/services/camera/libcameraservice/api2/CompositeStream.h b/services/camera/libcameraservice/api2/CompositeStream.h
index 5837745..a401a82 100644
--- a/services/camera/libcameraservice/api2/CompositeStream.h
+++ b/services/camera/libcameraservice/api2/CompositeStream.h
@@ -23,6 +23,7 @@
 #include <android/hardware/camera2/ICameraDeviceCallbacks.h>
 #include <camera/CameraMetadata.h>
 #include <camera/camera2/OutputConfiguration.h>
+#include <gui/IProducerListener.h>
 #include "common/CameraDeviceBase.h"
 #include "device3/Camera3StreamInterface.h"
 
@@ -66,15 +67,24 @@
     // Return composite stream id.
     virtual int getStreamId() = 0;
 
+    // Notify when shutter notify is triggered
+    virtual void onShutter(const CaptureResultExtras& /*resultExtras*/, nsecs_t /*timestamp*/) {}
+
     void onResultAvailable(const CaptureResult& result);
     bool onError(int32_t errorCode, const CaptureResultExtras& resultExtras);
 
     // Camera3StreamBufferListener implementation
     void onBufferAcquired(const BufferInfo& /*bufferInfo*/) override { /*Empty for now */ }
     void onBufferReleased(const BufferInfo& bufferInfo) override;
-    void onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId) override;
+    void onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId,
+            const CameraMetadata& settings) override;
 
 protected:
+    struct ProducerListener : public BnProducerListener {
+        // ProducerListener impementation
+        void onBufferReleased() override { /*No impl. for now*/ };
+    };
+
     status_t registerCompositeStreamListener(int32_t streamId);
     void eraseResult(int64_t frameNumber);
     void flagAnErrorFrameNumber(int64_t frameNumber);
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
index f627b25..2eec0f7 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -634,6 +634,11 @@
         mDepthStreamId = -1;
     }
 
+    if (mOutputSurface != nullptr) {
+        mOutputSurface->disconnect(NATIVE_WINDOW_API_CAMERA);
+        mOutputSurface.clear();
+    }
+
     return ret;
 }
 
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.h b/services/camera/libcameraservice/api2/DepthCompositeStream.h
index e8fe517..1bf31f4 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.h
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.h
@@ -21,7 +21,6 @@
 #include <dynamic_depth/imaging_model.h>
 #include <dynamic_depth/depth_map.h>
 
-#include <gui/IProducerListener.h>
 #include <gui/CpuConsumer.h>
 
 #include "CompositeStream.h"
@@ -116,11 +115,6 @@
     static const auto kDepthMapDataSpace = HAL_DATASPACE_DEPTH;
     static const auto kJpegDataSpace = HAL_DATASPACE_V0_JFIF;
 
-    struct ProducerListener : public BnProducerListener {
-        // ProducerListener implementation
-        void onBufferReleased() override { /*No impl. for now*/ };
-    };
-
     int                  mBlobStreamId, mBlobSurfaceId, mDepthStreamId, mDepthSurfaceId;
     size_t               mBlobWidth, mBlobHeight;
     sp<CpuConsumer>      mBlobConsumer, mDepthConsumer;
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
new file mode 100644
index 0000000..8e9c39e
--- /dev/null
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -0,0 +1,1610 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Camera3-HeicCompositeStream"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <linux/memfd.h>
+#include <pthread.h>
+#include <sys/syscall.h>
+
+#include <android/hardware/camera/device/3.5/types.h>
+#include <gui/Surface.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <media/ICrypto.h>
+#include <media/MediaCodecBuffer.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/MediaDefs.h>
+#include <media/stagefright/MediaCodecConstants.h>
+
+#include "common/CameraDeviceBase.h"
+#include "utils/ExifUtils.h"
+#include "HeicEncoderInfoManager.h"
+#include "HeicCompositeStream.h"
+
+using android::hardware::camera::device::V3_5::CameraBlob;
+using android::hardware::camera::device::V3_5::CameraBlobId;
+
+namespace android {
+namespace camera3 {
+
+HeicCompositeStream::HeicCompositeStream(wp<CameraDeviceBase> device,
+        wp<hardware::camera2::ICameraDeviceCallbacks> cb) :
+        CompositeStream(device, cb),
+        mUseHeic(false),
+        mNumOutputTiles(1),
+        mOutputWidth(0),
+        mOutputHeight(0),
+        mMaxHeicBufferSize(0),
+        mGridWidth(HeicEncoderInfoManager::kGridWidth),
+        mGridHeight(HeicEncoderInfoManager::kGridHeight),
+        mGridRows(1),
+        mGridCols(1),
+        mUseGrid(false),
+        mAppSegmentStreamId(-1),
+        mAppSegmentSurfaceId(-1),
+        mAppSegmentBufferAcquired(false),
+        mMainImageStreamId(-1),
+        mMainImageSurfaceId(-1),
+        mYuvBufferAcquired(false),
+        mProducerListener(new ProducerListener()),
+        mOutputBufferCounter(0),
+        mGridTimestampUs(0) {
+}
+
+HeicCompositeStream::~HeicCompositeStream() {
+    // Call deinitCodec in case stream hasn't been deleted yet to avoid any
+    // memory/resource leak.
+    deinitCodec();
+
+    mInputAppSegmentBuffers.clear();
+    mCodecOutputBuffers.clear();
+
+    mAppSegmentStreamId = -1;
+    mAppSegmentSurfaceId = -1;
+    mAppSegmentConsumer.clear();
+    mAppSegmentSurface.clear();
+
+    mMainImageStreamId = -1;
+    mMainImageSurfaceId = -1;
+    mMainImageConsumer.clear();
+    mMainImageSurface.clear();
+}
+
+bool HeicCompositeStream::isHeicCompositeStream(const sp<Surface> &surface) {
+    ANativeWindow *anw = surface.get();
+    status_t err;
+    int format;
+    if ((err = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {
+        String8 msg = String8::format("Failed to query Surface format: %s (%d)", strerror(-err),
+                err);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return false;
+    }
+
+    int dataspace;
+    if ((err = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE, &dataspace)) != OK) {
+        String8 msg = String8::format("Failed to query Surface dataspace: %s (%d)", strerror(-err),
+                err);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return false;
+    }
+
+    return ((format == HAL_PIXEL_FORMAT_BLOB) && (dataspace == HAL_DATASPACE_HEIF));
+}
+
+status_t HeicCompositeStream::createInternalStreams(const std::vector<sp<Surface>>& consumers,
+        bool /*hasDeferredConsumer*/, uint32_t width, uint32_t height, int format,
+        camera3_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
+        std::vector<int> *surfaceIds, int /*streamSetId*/, bool /*isShared*/) {
+
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (!device.get()) {
+        ALOGE("%s: Invalid camera device!", __FUNCTION__);
+        return NO_INIT;
+    }
+
+    status_t res = initializeCodec(width, height, device);
+    if (res != OK) {
+        ALOGE("%s: Failed to initialize HEIC/HEVC codec: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return NO_INIT;
+    }
+
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    mAppSegmentConsumer = new CpuConsumer(consumer, 1);
+    mAppSegmentConsumer->setFrameAvailableListener(this);
+    mAppSegmentConsumer->setName(String8("Camera3-HeicComposite-AppSegmentStream"));
+    mAppSegmentSurface = new Surface(producer);
+
+    res = device->createStream(mAppSegmentSurface, mAppSegmentMaxSize, 1, format,
+            kAppSegmentDataSpace, rotation, &mAppSegmentStreamId, physicalCameraId, surfaceIds);
+    if (res == OK) {
+        mAppSegmentSurfaceId = (*surfaceIds)[0];
+    } else {
+        ALOGE("%s: Failed to create JPEG App segment stream: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+        return res;
+    }
+
+    if (!mUseGrid) {
+        res = mCodec->createInputSurface(&producer);
+        if (res != OK) {
+            ALOGE("%s: Failed to create input surface for Heic codec: %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+            return res;
+        }
+    } else {
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        mMainImageConsumer = new CpuConsumer(consumer, 1);
+        mMainImageConsumer->setFrameAvailableListener(this);
+        mMainImageConsumer->setName(String8("Camera3-HeicComposite-HevcInputYUVStream"));
+    }
+    mMainImageSurface = new Surface(producer);
+
+    res = mCodec->start();
+    if (res != OK) {
+        ALOGE("%s: Failed to start codec: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+        return res;
+    }
+
+    std::vector<int> sourceSurfaceId;
+    //Use YUV_888 format if framework tiling is needed.
+    int srcStreamFmt = mUseGrid ? HAL_PIXEL_FORMAT_YCbCr_420_888 :
+            HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+    res = device->createStream(mMainImageSurface, width, height, srcStreamFmt, kHeifDataSpace,
+            rotation, id, physicalCameraId, &sourceSurfaceId);
+    if (res == OK) {
+        mMainImageSurfaceId = sourceSurfaceId[0];
+        mMainImageStreamId = *id;
+    } else {
+        ALOGE("%s: Failed to create main image stream: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+        return res;
+    }
+
+    mOutputSurface = consumers[0];
+    res = registerCompositeStreamListener(getStreamId());
+    if (res != OK) {
+        ALOGE("%s: Failed to register HAL main image stream", __FUNCTION__);
+        return res;
+    }
+
+    return res;
+}
+
+status_t HeicCompositeStream::deleteInternalStreams() {
+    requestExit();
+    auto res = join();
+    if (res != OK) {
+        ALOGE("%s: Failed to join with the main processing thread: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+    }
+
+    deinitCodec();
+
+    if (mAppSegmentStreamId >= 0) {
+        sp<CameraDeviceBase> device = mDevice.promote();
+        if (!device.get()) {
+            ALOGE("%s: Invalid camera device!", __FUNCTION__);
+            return NO_INIT;
+        }
+
+        res = device->deleteStream(mAppSegmentStreamId);
+        mAppSegmentStreamId = -1;
+    }
+
+    if (mOutputSurface != nullptr) {
+        mOutputSurface->disconnect(NATIVE_WINDOW_API_CAMERA);
+        mOutputSurface.clear();
+    }
+    return res;
+}
+
+void HeicCompositeStream::onBufferReleased(const BufferInfo& bufferInfo) {
+    Mutex::Autolock l(mMutex);
+
+    if (bufferInfo.mError) return;
+
+    mCodecOutputBufferTimestamps.push(bufferInfo.mTimestamp);
+}
+
+// We need to get the settings early to handle the case where the codec output
+// arrives earlier than result metadata.
+void HeicCompositeStream::onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId,
+        const CameraMetadata& settings) {
+    ATRACE_ASYNC_BEGIN("HEIC capture", frameNumber);
+
+    Mutex::Autolock l(mMutex);
+    if (mErrorState || (streamId != getStreamId())) {
+        return;
+    }
+
+    mPendingCaptureResults.emplace(frameNumber, CameraMetadata());
+
+    camera_metadata_ro_entry entry;
+
+    int32_t orientation = 0;
+    entry = settings.find(ANDROID_JPEG_ORIENTATION);
+    if (entry.count == 1) {
+        orientation = entry.data.i32[0];
+    }
+
+    int32_t quality = kDefaultJpegQuality;
+    entry = settings.find(ANDROID_JPEG_QUALITY);
+    if (entry.count == 1) {
+        quality = entry.data.i32[0];
+    }
+
+    mSettingsByFrameNumber[frameNumber] = std::make_pair(orientation, quality);
+}
+
+void HeicCompositeStream::onFrameAvailable(const BufferItem& item) {
+    if (item.mDataSpace == static_cast<android_dataspace>(kAppSegmentDataSpace)) {
+        ALOGV("%s: JPEG APP segments buffer with ts: %" PRIu64 " ms. arrived!",
+                __func__, ns2ms(item.mTimestamp));
+
+        Mutex::Autolock l(mMutex);
+        if (!mErrorState) {
+            mInputAppSegmentBuffers.push_back(item.mTimestamp);
+            mInputReadyCondition.signal();
+        }
+    } else if (item.mDataSpace == kHeifDataSpace) {
+        ALOGV("%s: YUV_888 buffer with ts: %" PRIu64 " ms. arrived!",
+                __func__, ns2ms(item.mTimestamp));
+
+        Mutex::Autolock l(mMutex);
+        if (!mUseGrid) {
+            ALOGE("%s: YUV_888 internal stream is only supported for HEVC tiling",
+                    __FUNCTION__);
+            return;
+        }
+        if (!mErrorState) {
+            mInputYuvBuffers.push_back(item.mTimestamp);
+            mInputReadyCondition.signal();
+        }
+    } else {
+        ALOGE("%s: Unexpected data space: 0x%x", __FUNCTION__, item.mDataSpace);
+    }
+}
+
+status_t HeicCompositeStream::getCompositeStreamInfo(const OutputStreamInfo &streamInfo,
+            const CameraMetadata& ch, std::vector<OutputStreamInfo>* compositeOutput /*out*/) {
+    if (compositeOutput == nullptr) {
+        return BAD_VALUE;
+    }
+
+    compositeOutput->clear();
+
+    bool useGrid, useHeic;
+    bool isSizeSupported = isSizeSupportedByHeifEncoder(
+            streamInfo.width, streamInfo.height, &useHeic, &useGrid, nullptr);
+    if (!isSizeSupported) {
+        // Size is not supported by either encoder.
+        return OK;
+    }
+
+    compositeOutput->insert(compositeOutput->end(), 2, streamInfo);
+
+    // JPEG APPS segments Blob stream info
+    (*compositeOutput)[0].width = calcAppSegmentMaxSize(ch);
+    (*compositeOutput)[0].height = 1;
+    (*compositeOutput)[0].format = HAL_PIXEL_FORMAT_BLOB;
+    (*compositeOutput)[0].dataSpace = kAppSegmentDataSpace;
+    (*compositeOutput)[0].consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
+
+    // YUV/IMPLEMENTATION_DEFINED stream info
+    (*compositeOutput)[1].width = streamInfo.width;
+    (*compositeOutput)[1].height = streamInfo.height;
+    (*compositeOutput)[1].format = useGrid ? HAL_PIXEL_FORMAT_YCbCr_420_888 :
+            HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+    (*compositeOutput)[1].dataSpace = kHeifDataSpace;
+    (*compositeOutput)[1].consumerUsage = useHeic ? GRALLOC_USAGE_HW_IMAGE_ENCODER :
+            useGrid ? GRALLOC_USAGE_SW_READ_OFTEN : GRALLOC_USAGE_HW_VIDEO_ENCODER;
+
+    return NO_ERROR;
+}
+
+bool HeicCompositeStream::isSizeSupportedByHeifEncoder(int32_t width, int32_t height,
+        bool* useHeic, bool* useGrid, int64_t* stall) {
+    static HeicEncoderInfoManager& heicManager = HeicEncoderInfoManager::getInstance();
+    return heicManager.isSizeSupported(width, height, useHeic, useGrid, stall);
+}
+
+bool HeicCompositeStream::isInMemoryTempFileSupported() {
+    int memfd = syscall(__NR_memfd_create, "HEIF-try-memfd", MFD_CLOEXEC);
+    if (memfd == -1) {
+        if (errno != ENOSYS) {
+            ALOGE("%s: Failed to create tmpfs file. errno %d", __FUNCTION__, errno);
+        }
+        return false;
+    }
+    close(memfd);
+    return true;
+}
+
+void HeicCompositeStream::onHeicOutputFrameAvailable(
+        const CodecOutputBufferInfo& outputBufferInfo) {
+    Mutex::Autolock l(mMutex);
+
+    ALOGV("%s: index %d, offset %d, size %d, time %" PRId64 ", flags 0x%x",
+            __FUNCTION__, outputBufferInfo.index, outputBufferInfo.offset,
+            outputBufferInfo.size, outputBufferInfo.timeUs, outputBufferInfo.flags);
+
+    if (!mErrorState) {
+        if ((outputBufferInfo.size > 0) &&
+                ((outputBufferInfo.flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) == 0)) {
+            mCodecOutputBuffers.push_back(outputBufferInfo);
+            mInputReadyCondition.signal();
+        } else {
+            mCodec->releaseOutputBuffer(outputBufferInfo.index);
+        }
+    } else {
+        mCodec->releaseOutputBuffer(outputBufferInfo.index);
+    }
+}
+
+void HeicCompositeStream::onHeicInputFrameAvailable(int32_t index) {
+    Mutex::Autolock l(mMutex);
+
+    if (!mUseGrid) {
+        ALOGE("%s: Codec YUV input mode must only be used for Hevc tiling mode", __FUNCTION__);
+        return;
+    }
+
+    mCodecInputBuffers.push_back(index);
+    mInputReadyCondition.signal();
+}
+
+void HeicCompositeStream::onHeicFormatChanged(sp<AMessage>& newFormat) {
+    if (newFormat == nullptr) {
+        ALOGE("%s: newFormat must not be null!", __FUNCTION__);
+        return;
+    }
+
+    Mutex::Autolock l(mMutex);
+
+    AString mime;
+    AString mimeHeic(MIMETYPE_IMAGE_ANDROID_HEIC);
+    newFormat->findString(KEY_MIME, &mime);
+    if (mime != mimeHeic) {
+        // For HEVC codec, below keys need to be filled out or overwritten so that the
+        // muxer can handle them as HEIC output image.
+        newFormat->setString(KEY_MIME, mimeHeic);
+        newFormat->setInt32(KEY_WIDTH, mOutputWidth);
+        newFormat->setInt32(KEY_HEIGHT, mOutputHeight);
+        if (mUseGrid) {
+            newFormat->setInt32(KEY_TILE_WIDTH, mGridWidth);
+            newFormat->setInt32(KEY_TILE_HEIGHT, mGridHeight);
+            newFormat->setInt32(KEY_GRID_ROWS, mGridRows);
+            newFormat->setInt32(KEY_GRID_COLUMNS, mGridCols);
+        }
+    }
+    newFormat->setInt32(KEY_IS_DEFAULT, 1 /*isPrimary*/);
+
+    int32_t gridRows, gridCols;
+    if (newFormat->findInt32(KEY_GRID_ROWS, &gridRows) &&
+            newFormat->findInt32(KEY_GRID_COLUMNS, &gridCols)) {
+        mNumOutputTiles = gridRows * gridCols;
+    } else {
+        mNumOutputTiles = 1;
+    }
+
+    ALOGV("%s: mNumOutputTiles is %zu", __FUNCTION__, mNumOutputTiles);
+    mFormat = newFormat;
+}
+
+void HeicCompositeStream::onHeicCodecError() {
+    Mutex::Autolock l(mMutex);
+    mErrorState = true;
+}
+
+status_t HeicCompositeStream::configureStream() {
+    if (isRunning()) {
+        // Processing thread is already running, nothing more to do.
+        return NO_ERROR;
+    }
+
+    if (mOutputSurface.get() == nullptr) {
+        ALOGE("%s: No valid output surface set!", __FUNCTION__);
+        return NO_INIT;
+    }
+
+    auto res = mOutputSurface->connect(NATIVE_WINDOW_API_CAMERA, mProducerListener);
+    if (res != OK) {
+        ALOGE("%s: Unable to connect to native window for stream %d",
+                __FUNCTION__, mMainImageStreamId);
+        return res;
+    }
+
+    if ((res = native_window_set_buffers_format(mOutputSurface.get(), HAL_PIXEL_FORMAT_BLOB))
+            != OK) {
+        ALOGE("%s: Unable to configure stream buffer format for stream %d", __FUNCTION__,
+                mMainImageStreamId);
+        return res;
+    }
+
+    ANativeWindow *anwConsumer = mOutputSurface.get();
+    int maxConsumerBuffers;
+    if ((res = anwConsumer->query(anwConsumer, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                    &maxConsumerBuffers)) != OK) {
+        ALOGE("%s: Unable to query consumer undequeued"
+                " buffer count for stream %d", __FUNCTION__, mMainImageStreamId);
+        return res;
+    }
+
+    // Cannot use SourceSurface buffer count since it could be codec's 512*512 tile
+    // buffer count.
+    int maxProducerBuffers = 1;
+    if ((res = native_window_set_buffer_count(
+                    anwConsumer, maxProducerBuffers + maxConsumerBuffers)) != OK) {
+        ALOGE("%s: Unable to set buffer count for stream %d", __FUNCTION__, mMainImageStreamId);
+        return res;
+    }
+
+    if ((res = native_window_set_buffers_dimensions(anwConsumer, mMaxHeicBufferSize, 1)) != OK) {
+        ALOGE("%s: Unable to set buffer dimension %zu x 1 for stream %d: %s (%d)",
+                __FUNCTION__, mMaxHeicBufferSize, mMainImageStreamId, strerror(-res), res);
+        return res;
+    }
+
+    run("HeicCompositeStreamProc");
+
+    return NO_ERROR;
+}
+
+status_t HeicCompositeStream::insertGbp(SurfaceMap* /*out*/outSurfaceMap,
+        Vector<int32_t>* /*out*/outputStreamIds, int32_t* /*out*/currentStreamId) {
+    if (outSurfaceMap->find(mAppSegmentStreamId) == outSurfaceMap->end()) {
+        (*outSurfaceMap)[mAppSegmentStreamId] = std::vector<size_t>();
+        outputStreamIds->push_back(mAppSegmentStreamId);
+    }
+    (*outSurfaceMap)[mAppSegmentStreamId].push_back(mAppSegmentSurfaceId);
+
+    if (outSurfaceMap->find(mMainImageStreamId) == outSurfaceMap->end()) {
+        (*outSurfaceMap)[mMainImageStreamId] = std::vector<size_t>();
+        outputStreamIds->push_back(mMainImageStreamId);
+    }
+    (*outSurfaceMap)[mMainImageStreamId].push_back(mMainImageSurfaceId);
+
+    if (currentStreamId != nullptr) {
+        *currentStreamId = mMainImageStreamId;
+    }
+
+    return NO_ERROR;
+}
+
+void HeicCompositeStream::onShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) {
+    Mutex::Autolock l(mMutex);
+    if (mErrorState) {
+        return;
+    }
+
+    if (mSettingsByFrameNumber.find(resultExtras.frameNumber) != mSettingsByFrameNumber.end()) {
+        mFrameNumberMap.emplace(resultExtras.frameNumber, timestamp);
+        mSettingsByTimestamp[timestamp] = mSettingsByFrameNumber[resultExtras.frameNumber];
+        mSettingsByFrameNumber.erase(resultExtras.frameNumber);
+        mInputReadyCondition.signal();
+    }
+}
+
+void HeicCompositeStream::compilePendingInputLocked() {
+    while (!mSettingsByTimestamp.empty()) {
+        auto it = mSettingsByTimestamp.begin();
+        mPendingInputFrames[it->first].orientation = it->second.first;
+        mPendingInputFrames[it->first].quality = it->second.second;
+        mSettingsByTimestamp.erase(it);
+    }
+
+    while (!mInputAppSegmentBuffers.empty() && !mAppSegmentBufferAcquired) {
+        CpuConsumer::LockedBuffer imgBuffer;
+        auto it = mInputAppSegmentBuffers.begin();
+        auto res = mAppSegmentConsumer->lockNextBuffer(&imgBuffer);
+        if (res == NOT_ENOUGH_DATA) {
+            // Canot not lock any more buffers.
+            break;
+        } else if ((res != OK) || (*it != imgBuffer.timestamp)) {
+            if (res != OK) {
+                ALOGE("%s: Error locking JPEG_APP_SEGMENTS image buffer: %s (%d)", __FUNCTION__,
+                        strerror(-res), res);
+            } else {
+                ALOGE("%s: Expecting JPEG_APP_SEGMENTS buffer with time stamp: %" PRId64
+                        " received buffer with time stamp: %" PRId64, __FUNCTION__,
+                        *it, imgBuffer.timestamp);
+            }
+            mPendingInputFrames[*it].error = true;
+            mInputAppSegmentBuffers.erase(it);
+            continue;
+        }
+
+        if ((mPendingInputFrames.find(imgBuffer.timestamp) != mPendingInputFrames.end()) &&
+                (mPendingInputFrames[imgBuffer.timestamp].error)) {
+            mAppSegmentConsumer->unlockBuffer(imgBuffer);
+        } else {
+            mPendingInputFrames[imgBuffer.timestamp].appSegmentBuffer = imgBuffer;
+            mAppSegmentBufferAcquired = true;
+        }
+        mInputAppSegmentBuffers.erase(it);
+    }
+
+    while (!mInputYuvBuffers.empty() && !mYuvBufferAcquired) {
+        CpuConsumer::LockedBuffer imgBuffer;
+        auto it = mInputYuvBuffers.begin();
+        auto res = mMainImageConsumer->lockNextBuffer(&imgBuffer);
+        if (res == NOT_ENOUGH_DATA) {
+            // Canot not lock any more buffers.
+            break;
+        } else if (res != OK) {
+            ALOGE("%s: Error locking YUV_888 image buffer: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+            mPendingInputFrames[*it].error = true;
+            mInputYuvBuffers.erase(it);
+            continue;
+        } else if (*it != imgBuffer.timestamp) {
+            ALOGW("%s: Expecting YUV_888 buffer with time stamp: %" PRId64 " received buffer with "
+                    "time stamp: %" PRId64, __FUNCTION__, *it, imgBuffer.timestamp);
+            mPendingInputFrames[*it].error = true;
+            mInputYuvBuffers.erase(it);
+            continue;
+        }
+
+        if ((mPendingInputFrames.find(imgBuffer.timestamp) != mPendingInputFrames.end()) &&
+                (mPendingInputFrames[imgBuffer.timestamp].error)) {
+            mMainImageConsumer->unlockBuffer(imgBuffer);
+        } else {
+            mPendingInputFrames[imgBuffer.timestamp].yuvBuffer = imgBuffer;
+            mYuvBufferAcquired = true;
+        }
+        mInputYuvBuffers.erase(it);
+    }
+
+    while (!mCodecOutputBuffers.empty()) {
+        auto it = mCodecOutputBuffers.begin();
+        // Bitstream buffer timestamp doesn't necessarily directly correlate with input
+        // buffer timestamp. Assume encoder input to output is FIFO, use a queue
+        // to look up timestamp.
+        int64_t bufferTime = -1;
+        if (mCodecOutputBufferTimestamps.empty()) {
+            ALOGE("%s: Failed to find buffer timestamp for codec output buffer!", __FUNCTION__);
+        } else {
+            // Direct mapping between camera timestamp (in ns) and codec timestamp (in us).
+            bufferTime = mCodecOutputBufferTimestamps.front();
+            mOutputBufferCounter++;
+            if (mOutputBufferCounter == mNumOutputTiles) {
+                mCodecOutputBufferTimestamps.pop();
+                mOutputBufferCounter = 0;
+            }
+
+            mPendingInputFrames[bufferTime].codecOutputBuffers.push_back(*it);
+        }
+        mCodecOutputBuffers.erase(it);
+    }
+
+    while (!mFrameNumberMap.empty()) {
+        auto it = mFrameNumberMap.begin();
+        mPendingInputFrames[it->second].frameNumber = it->first;
+        mFrameNumberMap.erase(it);
+    }
+
+    // Heic composition doesn't depend on capture result, so no need to check
+    // mErrorFrameNumbers. Just remove them.
+    mErrorFrameNumbers.clear();
+
+    // Distribute codec input buffers to be filled out from YUV output
+    for (auto it = mPendingInputFrames.begin();
+            it != mPendingInputFrames.end() && mCodecInputBuffers.size() > 0; it++) {
+        InputFrame& inputFrame(it->second);
+        if (inputFrame.codecInputCounter < mGridRows * mGridCols) {
+            // Available input tiles that are required for the current input
+            // image.
+            size_t newInputTiles = std::min(mCodecInputBuffers.size(),
+                    mGridRows * mGridCols - inputFrame.codecInputCounter);
+            for (size_t i = 0; i < newInputTiles; i++) {
+                CodecInputBufferInfo inputInfo =
+                        { mCodecInputBuffers[0], mGridTimestampUs++, inputFrame.codecInputCounter };
+                inputFrame.codecInputBuffers.push_back(inputInfo);
+
+                mCodecInputBuffers.erase(mCodecInputBuffers.begin());
+                inputFrame.codecInputCounter++;
+            }
+            break;
+        }
+    }
+}
+
+bool HeicCompositeStream::getNextReadyInputLocked(int64_t *currentTs /*out*/) {
+    if (currentTs == nullptr) {
+        return false;
+    }
+
+    bool newInputAvailable = false;
+    for (const auto& it : mPendingInputFrames) {
+        bool appSegmentBufferReady = (it.second.appSegmentBuffer.data != nullptr) &&
+                !it.second.appSegmentWritten;
+        bool codecOutputReady = !it.second.codecOutputBuffers.empty();
+        bool codecInputReady = (it.second.yuvBuffer.data != nullptr) &&
+                (!it.second.codecInputBuffers.empty());
+        if ((!it.second.error) &&
+                (it.first < *currentTs) &&
+                (appSegmentBufferReady || codecOutputReady || codecInputReady)) {
+            *currentTs = it.first;
+            newInputAvailable = true;
+            break;
+        }
+    }
+
+    return newInputAvailable;
+}
+
+int64_t HeicCompositeStream::getNextFailingInputLocked(int64_t *currentTs /*out*/) {
+    int64_t res = -1;
+    if (currentTs == nullptr) {
+        return res;
+    }
+
+    for (const auto& it : mPendingInputFrames) {
+        if (it.second.error && !it.second.errorNotified && (it.first < *currentTs)) {
+            *currentTs = it.first;
+            res = it.second.frameNumber;
+            break;
+        }
+    }
+
+    return res;
+}
+
+status_t HeicCompositeStream::processInputFrame(nsecs_t timestamp,
+        InputFrame &inputFrame) {
+    ATRACE_CALL();
+    status_t res = OK;
+
+    bool appSegmentBufferReady = inputFrame.appSegmentBuffer.data != nullptr &&
+            !inputFrame.appSegmentWritten;
+    bool codecOutputReady = inputFrame.codecOutputBuffers.size() > 0;
+    bool codecInputReady = inputFrame.yuvBuffer.data != nullptr &&
+           !inputFrame.codecInputBuffers.empty();
+
+    if (!appSegmentBufferReady && !codecOutputReady && !codecInputReady) {
+        ALOGW("%s: No valid appSegmentBuffer/codec input/outputBuffer available!", __FUNCTION__);
+        return OK;
+    }
+
+    // Handle inputs for Hevc tiling
+    if (codecInputReady) {
+        res = processCodecInputFrame(inputFrame);
+        if (res != OK) {
+            ALOGE("%s: Failed to process codec input frame: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+            return res;
+        }
+    }
+
+    // Initialize and start muxer if not yet done so
+    if (inputFrame.muxer == nullptr) {
+        res = startMuxerForInputFrame(timestamp, inputFrame);
+        if (res != OK) {
+            ALOGE("%s: Failed to create and start muxer: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+            return res;
+        }
+    }
+
+    // Write JPEG APP segments data to the muxer.
+    if (appSegmentBufferReady && inputFrame.muxer != nullptr) {
+        res = processAppSegment(timestamp, inputFrame);
+        if (res != OK) {
+            ALOGE("%s: Failed to process JPEG APP segments: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+            return res;
+        }
+    }
+
+    // Write media codec bitstream buffers to muxer.
+    while (!inputFrame.codecOutputBuffers.empty()) {
+        res = processOneCodecOutputFrame(timestamp, inputFrame);
+        if (res != OK) {
+            ALOGE("%s: Failed to process codec output frame: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+            return res;
+        }
+    }
+
+    if (inputFrame.appSegmentWritten && inputFrame.pendingOutputTiles == 0) {
+        res = processCompletedInputFrame(timestamp, inputFrame);
+        if (res != OK) {
+            ALOGE("%s: Failed to process completed input frame: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+            return res;
+        }
+    }
+
+    return res;
+}
+
+status_t HeicCompositeStream::startMuxerForInputFrame(nsecs_t timestamp, InputFrame &inputFrame) {
+    sp<ANativeWindow> outputANW = mOutputSurface;
+    if (inputFrame.codecOutputBuffers.size() == 0) {
+        // No single codec output buffer has been generated. Continue to
+        // wait.
+        return OK;
+    }
+
+    auto res = outputANW->dequeueBuffer(mOutputSurface.get(), &inputFrame.anb, &inputFrame.fenceFd);
+    if (res != OK) {
+        ALOGE("%s: Error retrieving output buffer: %s (%d)", __FUNCTION__, strerror(-res),
+                res);
+        return res;
+    }
+
+    // Combine current thread id, stream id and timestamp to uniquely identify image.
+    std::ostringstream tempOutputFile;
+    tempOutputFile << "HEIF-" << pthread_self() << "-"
+            << getStreamId() << "-" << timestamp;
+    inputFrame.fileFd = syscall(__NR_memfd_create, tempOutputFile.str().c_str(), MFD_CLOEXEC);
+    if (inputFrame.fileFd < 0) {
+        ALOGE("%s: Failed to create file %s. Error no is %d", __FUNCTION__,
+                tempOutputFile.str().c_str(), errno);
+        return NO_INIT;
+    }
+    inputFrame.muxer = new MediaMuxer(inputFrame.fileFd, MediaMuxer::OUTPUT_FORMAT_HEIF);
+    if (inputFrame.muxer == nullptr) {
+        ALOGE("%s: Failed to create MediaMuxer for file fd %d",
+                __FUNCTION__, inputFrame.fileFd);
+        return NO_INIT;
+    }
+
+    res = inputFrame.muxer->setOrientationHint(inputFrame.orientation);
+    if (res != OK) {
+        ALOGE("%s: Failed to setOrientationHint: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+        return res;
+    }
+    // Set encoder quality
+    {
+        sp<AMessage> qualityParams = new AMessage;
+        qualityParams->setInt32(PARAMETER_KEY_VIDEO_BITRATE, inputFrame.quality);
+        res = mCodec->setParameters(qualityParams);
+        if (res != OK) {
+            ALOGE("%s: Failed to set codec quality: %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+            return res;
+        }
+    }
+
+    ssize_t trackId = inputFrame.muxer->addTrack(mFormat);
+    if (trackId < 0) {
+        ALOGE("%s: Failed to addTrack to the muxer: %zd", __FUNCTION__, trackId);
+        return NO_INIT;
+    }
+
+    inputFrame.trackIndex = trackId;
+    inputFrame.pendingOutputTiles = mNumOutputTiles;
+
+    res = inputFrame.muxer->start();
+    if (res != OK) {
+        ALOGE("%s: Failed to start MediaMuxer: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return res;
+    }
+
+    return OK;
+}
+
+status_t HeicCompositeStream::processAppSegment(nsecs_t timestamp, InputFrame &inputFrame) {
+    size_t app1Size = 0;
+    auto appSegmentSize = findAppSegmentsSize(inputFrame.appSegmentBuffer.data,
+            inputFrame.appSegmentBuffer.width * inputFrame.appSegmentBuffer.height,
+            &app1Size);
+    ALOGV("%s: appSegmentSize is %zu, width %d, height %d, app1Size %zu", __FUNCTION__,
+          appSegmentSize, inputFrame.appSegmentBuffer.width,
+          inputFrame.appSegmentBuffer.height, app1Size);
+    if (appSegmentSize == 0) {
+        ALOGE("%s: Failed to find JPEG APP segment size", __FUNCTION__);
+        return NO_INIT;
+    }
+
+    std::unique_ptr<ExifUtils> exifUtils(ExifUtils::create());
+    auto exifRes = exifUtils->initialize(inputFrame.appSegmentBuffer.data, app1Size);
+    if (!exifRes) {
+        ALOGE("%s: Failed to initialize ExifUtils object!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    //TODO: Use capture result metadata and static metadata to fill out the
+    //rest.
+    CameraMetadata dummyMeta;
+    exifRes = exifUtils->setFromMetadata(dummyMeta, mOutputWidth, mOutputHeight);
+    if (!exifRes) {
+        ALOGE("%s: Failed to set Exif tags using metadata and main image sizes", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    exifRes = exifUtils->setOrientation(inputFrame.orientation);
+    if (!exifRes) {
+        ALOGE("%s: ExifUtils failed to set orientation", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    exifRes = exifUtils->generateApp1();
+    if (!exifRes) {
+        ALOGE("%s: ExifUtils failed to generate APP1 segment", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    unsigned int newApp1Length = exifUtils->getApp1Length();
+    const uint8_t *newApp1Segment = exifUtils->getApp1Buffer();
+
+    //Assemble the APP1 marker buffer required by MediaCodec
+    uint8_t kExifApp1Marker[] = {'E', 'x', 'i', 'f', 0xFF, 0xE1, 0x00, 0x00};
+    kExifApp1Marker[6] = static_cast<uint8_t>(newApp1Length >> 8);
+    kExifApp1Marker[7] = static_cast<uint8_t>(newApp1Length & 0xFF);
+    size_t appSegmentBufferSize = sizeof(kExifApp1Marker) +
+            appSegmentSize - app1Size + newApp1Length;
+    uint8_t* appSegmentBuffer = new uint8_t[appSegmentBufferSize];
+    memcpy(appSegmentBuffer, kExifApp1Marker, sizeof(kExifApp1Marker));
+    memcpy(appSegmentBuffer + sizeof(kExifApp1Marker), newApp1Segment, newApp1Length);
+    if (appSegmentSize - app1Size > 0) {
+        memcpy(appSegmentBuffer + sizeof(kExifApp1Marker) + newApp1Length,
+                inputFrame.appSegmentBuffer.data + app1Size, appSegmentSize - app1Size);
+    }
+
+    sp<ABuffer> aBuffer = new ABuffer(appSegmentBuffer, appSegmentBufferSize);
+    auto res = inputFrame.muxer->writeSampleData(aBuffer, inputFrame.trackIndex,
+            timestamp, MediaCodec::BUFFER_FLAG_MUXER_DATA);
+    delete[] appSegmentBuffer;
+
+    if (res != OK) {
+        ALOGE("%s: Failed to write JPEG APP segments to muxer: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return res;
+    }
+    inputFrame.appSegmentWritten = true;
+
+    return OK;
+}
+
+status_t HeicCompositeStream::processCodecInputFrame(InputFrame &inputFrame) {
+    for (auto& inputBuffer : inputFrame.codecInputBuffers) {
+        sp<MediaCodecBuffer> buffer;
+        auto res = mCodec->getInputBuffer(inputBuffer.index, &buffer);
+        if (res != OK) {
+            ALOGE("%s: Error getting codec input buffer: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+            return res;
+        }
+
+        // Copy one tile from source to destination.
+        size_t tileX = inputBuffer.tileIndex % mGridCols;
+        size_t tileY = inputBuffer.tileIndex / mGridCols;
+        size_t top = mGridHeight * tileY;
+        size_t left = mGridWidth * tileX;
+        size_t width = (tileX == static_cast<size_t>(mGridCols) - 1) ?
+                mOutputWidth - tileX * mGridWidth : mGridWidth;
+        size_t height = (tileY == static_cast<size_t>(mGridRows) - 1) ?
+                mOutputHeight - tileY * mGridHeight : mGridHeight;
+        ALOGV("%s: inputBuffer tileIndex [%zu, %zu], top %zu, left %zu, width %zu, height %zu",
+                __FUNCTION__, tileX, tileY, top, left, width, height);
+
+        res = copyOneYuvTile(buffer, inputFrame.yuvBuffer, top, left, width, height);
+        if (res != OK) {
+            ALOGE("%s: Failed to copy YUV tile %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+            return res;
+        }
+
+        res = mCodec->queueInputBuffer(inputBuffer.index, 0, buffer->capacity(),
+                inputBuffer.timeUs, 0, nullptr /*errorDetailMsg*/);
+        if (res != OK) {
+            ALOGE("%s: Failed to queueInputBuffer to Codec: %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+            return res;
+        }
+    }
+
+    inputFrame.codecInputBuffers.clear();
+    return OK;
+}
+
+status_t HeicCompositeStream::processOneCodecOutputFrame(nsecs_t timestamp,
+        InputFrame &inputFrame) {
+    auto it = inputFrame.codecOutputBuffers.begin();
+    sp<MediaCodecBuffer> buffer;
+    status_t res = mCodec->getOutputBuffer(it->index, &buffer);
+    if (res != OK) {
+        ALOGE("%s: Error getting Heic codec output buffer at index %d: %s (%d)",
+                __FUNCTION__, it->index, strerror(-res), res);
+        return res;
+    }
+    if (buffer == nullptr) {
+        ALOGE("%s: Invalid Heic codec output buffer at index %d",
+                __FUNCTION__, it->index);
+        return BAD_VALUE;
+    }
+
+    sp<ABuffer> aBuffer = new ABuffer(buffer->data(), buffer->size());
+    res = inputFrame.muxer->writeSampleData(
+            aBuffer, inputFrame.trackIndex, timestamp, 0 /*flags*/);
+    if (res != OK) {
+        ALOGE("%s: Failed to write buffer index %d to muxer: %s (%d)",
+                __FUNCTION__, it->index, strerror(-res), res);
+        return res;
+    }
+
+    mCodec->releaseOutputBuffer(it->index);
+    if (inputFrame.pendingOutputTiles == 0) {
+        ALOGW("%s: Codec generated more tiles than expected!", __FUNCTION__);
+    } else {
+        inputFrame.pendingOutputTiles--;
+    }
+
+    inputFrame.codecOutputBuffers.erase(inputFrame.codecOutputBuffers.begin());
+    return OK;
+}
+
+status_t HeicCompositeStream::processCompletedInputFrame(nsecs_t timestamp,
+        InputFrame &inputFrame) {
+    sp<ANativeWindow> outputANW = mOutputSurface;
+    inputFrame.muxer->stop();
+
+    // Copy the content of the file to memory.
+    sp<GraphicBuffer> gb = GraphicBuffer::from(inputFrame.anb);
+    void* dstBuffer;
+    auto res = gb->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, &dstBuffer, inputFrame.fenceFd);
+    if (res != OK) {
+        ALOGE("%s: Error trying to lock output buffer fence: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+        return res;
+    }
+
+    off_t fSize = lseek(inputFrame.fileFd, 0, SEEK_END);
+    if (static_cast<size_t>(fSize) > mMaxHeicBufferSize - sizeof(CameraBlob)) {
+        ALOGE("%s: Error: MediaMuxer output size %ld is larger than buffer sizer %zu",
+                __FUNCTION__, fSize, mMaxHeicBufferSize - sizeof(CameraBlob));
+        return BAD_VALUE;
+    }
+
+    lseek(inputFrame.fileFd, 0, SEEK_SET);
+    ssize_t bytesRead = read(inputFrame.fileFd, dstBuffer, fSize);
+    if (bytesRead < fSize) {
+        ALOGE("%s: Only %zd of %ld bytes read", __FUNCTION__, bytesRead, fSize);
+        return BAD_VALUE;
+    }
+
+    close(inputFrame.fileFd);
+    inputFrame.fileFd = -1;
+
+    // Fill in HEIC header
+    uint8_t *header = static_cast<uint8_t*>(dstBuffer) + mMaxHeicBufferSize - sizeof(CameraBlob);
+    struct CameraBlob *blobHeader = (struct CameraBlob *)header;
+    // Must be in sync with CAMERA3_HEIC_BLOB_ID in android_media_Utils.cpp
+    blobHeader->blobId = static_cast<CameraBlobId>(0x00FE);
+    blobHeader->blobSize = fSize;
+
+    res = native_window_set_buffers_timestamp(mOutputSurface.get(), timestamp);
+    if (res != OK) {
+        ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
+               __FUNCTION__, getStreamId(), strerror(-res), res);
+        return res;
+    }
+
+    res = outputANW->queueBuffer(mOutputSurface.get(), inputFrame.anb, /*fence*/ -1);
+    if (res != OK) {
+        ALOGE("%s: Failed to queueBuffer to Heic stream: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+        return res;
+    }
+    inputFrame.anb = nullptr;
+
+    return OK;
+}
+
+
+void HeicCompositeStream::releaseInputFrameLocked(InputFrame *inputFrame /*out*/) {
+    if (inputFrame == nullptr) {
+        return;
+    }
+
+    if (inputFrame->appSegmentBuffer.data != nullptr) {
+        mAppSegmentConsumer->unlockBuffer(inputFrame->appSegmentBuffer);
+        inputFrame->appSegmentBuffer.data = nullptr;
+        mAppSegmentBufferAcquired = false;
+    }
+
+    while (!inputFrame->codecOutputBuffers.empty()) {
+        auto it = inputFrame->codecOutputBuffers.begin();
+        ALOGV("%s: releaseOutputBuffer index %d", __FUNCTION__, it->index);
+        mCodec->releaseOutputBuffer(it->index);
+        inputFrame->codecOutputBuffers.erase(it);
+    }
+
+    if (inputFrame->yuvBuffer.data != nullptr) {
+        mMainImageConsumer->unlockBuffer(inputFrame->yuvBuffer);
+        inputFrame->yuvBuffer.data = nullptr;
+        mYuvBufferAcquired = false;
+    }
+
+    while (!inputFrame->codecInputBuffers.empty()) {
+        auto it = inputFrame->codecInputBuffers.begin();
+        inputFrame->codecInputBuffers.erase(it);
+    }
+
+    if ((inputFrame->error || mErrorState) && !inputFrame->errorNotified) {
+        notifyError(inputFrame->frameNumber);
+        inputFrame->errorNotified = true;
+    }
+
+    if (inputFrame->fileFd >= 0) {
+        close(inputFrame->fileFd);
+        inputFrame->fileFd = -1;
+    }
+
+    if (inputFrame->anb != nullptr) {
+        sp<ANativeWindow> outputANW = mOutputSurface;
+        outputANW->cancelBuffer(mOutputSurface.get(), inputFrame->anb, /*fence*/ -1);
+        inputFrame->anb = nullptr;
+    }
+}
+
+void HeicCompositeStream::releaseInputFramesLocked(int64_t currentTs) {
+    auto it = mPendingInputFrames.begin();
+    while (it != mPendingInputFrames.end()) {
+        if (it->first <= currentTs) {
+            releaseInputFrameLocked(&it->second);
+            it = mPendingInputFrames.erase(it);
+        } else {
+            it++;
+        }
+    }
+}
+
+status_t HeicCompositeStream::initializeCodec(uint32_t width, uint32_t height,
+        const sp<CameraDeviceBase>& cameraDevice) {
+    ALOGV("%s", __FUNCTION__);
+
+    bool useGrid = false;
+    bool isSizeSupported = isSizeSupportedByHeifEncoder(width, height,
+            &mUseHeic, &useGrid, nullptr);
+    if (!isSizeSupported) {
+        ALOGE("%s: Encoder doesnt' support size %u x %u!",
+                __FUNCTION__, width, height);
+        return BAD_VALUE;
+    }
+
+    // Create Looper for MediaCodec.
+    auto desiredMime = mUseHeic ? MIMETYPE_IMAGE_ANDROID_HEIC : MIMETYPE_VIDEO_HEVC;
+    mCodecLooper = new ALooper;
+    mCodecLooper->setName("Camera3-HeicComposite-MediaCodecLooper");
+    status_t res = mCodecLooper->start(
+            false,   // runOnCallingThread
+            false,    // canCallJava
+            PRIORITY_AUDIO);
+    if (res != OK) {
+        ALOGE("%s: Failed to start codec looper: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return NO_INIT;
+    }
+
+    // Create HEIC/HEVC codec.
+    mCodec = MediaCodec::CreateByType(mCodecLooper, desiredMime, true /*encoder*/);
+    if (mCodec == nullptr) {
+        ALOGE("%s: Failed to create codec for %s", __FUNCTION__, desiredMime);
+        return NO_INIT;
+    }
+
+    // Create Looper and handler for Codec callback.
+    mCodecCallbackHandler = new CodecCallbackHandler(this);
+    if (mCodecCallbackHandler == nullptr) {
+        ALOGE("%s: Failed to create codec callback handler", __FUNCTION__);
+        return NO_MEMORY;
+    }
+    mCallbackLooper = new ALooper;
+    mCallbackLooper->setName("Camera3-HeicComposite-MediaCodecCallbackLooper");
+    res = mCallbackLooper->start(
+            false,   // runOnCallingThread
+            false,    // canCallJava
+            PRIORITY_AUDIO);
+    if (res != OK) {
+        ALOGE("%s: Failed to start media callback looper: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return NO_INIT;
+    }
+    mCallbackLooper->registerHandler(mCodecCallbackHandler);
+
+    mAsyncNotify = new AMessage(kWhatCallbackNotify, mCodecCallbackHandler);
+    res = mCodec->setCallback(mAsyncNotify);
+    if (res != OK) {
+        ALOGE("%s: Failed to set MediaCodec callback: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+        return res;
+    }
+
+    // Create output format and configure the Codec.
+    sp<AMessage> outputFormat = new AMessage();
+    outputFormat->setString(KEY_MIME, desiredMime);
+    outputFormat->setInt32(KEY_BITRATE_MODE, BITRATE_MODE_CQ);
+    outputFormat->setInt32(KEY_QUALITY, kDefaultJpegQuality);
+    // Ask codec to skip timestamp check and encode all frames.
+    outputFormat->setInt64("max-pts-gap-to-encoder", kNoFrameDropMaxPtsGap);
+
+    int32_t gridWidth, gridHeight, gridRows, gridCols;
+    if (useGrid || mUseHeic) {
+        gridWidth = HeicEncoderInfoManager::kGridWidth;
+        gridHeight = HeicEncoderInfoManager::kGridHeight;
+        gridRows = (height + gridHeight - 1)/gridHeight;
+        gridCols = (width + gridWidth - 1)/gridWidth;
+
+        if (mUseHeic) {
+            outputFormat->setInt32(KEY_TILE_WIDTH, gridWidth);
+            outputFormat->setInt32(KEY_TILE_HEIGHT, gridHeight);
+            outputFormat->setInt32(KEY_GRID_COLUMNS, gridCols);
+            outputFormat->setInt32(KEY_GRID_ROWS, gridRows);
+        }
+
+    } else {
+        gridWidth = width;
+        gridHeight = height;
+        gridRows = 1;
+        gridCols = 1;
+    }
+
+    outputFormat->setInt32(KEY_WIDTH, !useGrid ? width : gridWidth);
+    outputFormat->setInt32(KEY_HEIGHT, !useGrid ? height : gridHeight);
+    outputFormat->setInt32(KEY_I_FRAME_INTERVAL, 0);
+    outputFormat->setInt32(KEY_COLOR_FORMAT,
+            useGrid ? COLOR_FormatYUV420Flexible : COLOR_FormatSurface);
+    outputFormat->setInt32(KEY_FRAME_RATE, gridRows * gridCols);
+    // This only serves as a hint to encoder when encoding is not real-time.
+    outputFormat->setInt32(KEY_OPERATING_RATE, useGrid ? kGridOpRate : kNoGridOpRate);
+
+    res = mCodec->configure(outputFormat, nullptr /*nativeWindow*/,
+            nullptr /*crypto*/, CONFIGURE_FLAG_ENCODE);
+    if (res != OK) {
+        ALOGE("%s: Failed to configure codec: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+        return res;
+    }
+
+    mGridWidth = gridWidth;
+    mGridHeight = gridHeight;
+    mGridRows = gridRows;
+    mGridCols = gridCols;
+    mUseGrid = useGrid;
+    mOutputWidth = width;
+    mOutputHeight = height;
+    mAppSegmentMaxSize = calcAppSegmentMaxSize(cameraDevice->info());
+    mMaxHeicBufferSize = mOutputWidth * mOutputHeight * 3 / 2 + mAppSegmentMaxSize;
+
+    return OK;
+}
+
+void HeicCompositeStream::deinitCodec() {
+    ALOGV("%s", __FUNCTION__);
+    if (mCodec != nullptr) {
+        mCodec->stop();
+        mCodec->release();
+        mCodec.clear();
+    }
+
+    if (mCodecLooper != nullptr) {
+        mCodecLooper->stop();
+        mCodecLooper.clear();
+    }
+
+    if (mCallbackLooper != nullptr) {
+        mCallbackLooper->stop();
+        mCallbackLooper.clear();
+    }
+
+    mAsyncNotify.clear();
+    mFormat.clear();
+}
+
+// Return the size of the complete list of app segment, 0 indicates failure
+size_t HeicCompositeStream::findAppSegmentsSize(const uint8_t* appSegmentBuffer,
+        size_t maxSize, size_t *app1SegmentSize) {
+    if (appSegmentBuffer == nullptr || app1SegmentSize == nullptr) {
+        ALOGE("%s: Invalid input appSegmentBuffer %p, app1SegmentSize %p",
+                __FUNCTION__, appSegmentBuffer, app1SegmentSize);
+        return 0;
+    }
+
+    size_t expectedSize = 0;
+    // First check for EXIF transport header at the end of the buffer
+    const uint8_t *header = appSegmentBuffer + (maxSize - sizeof(struct CameraBlob));
+    const struct CameraBlob *blob = (const struct CameraBlob*)(header);
+    if (blob->blobId != CameraBlobId::JPEG_APP_SEGMENTS) {
+        ALOGE("%s: Invalid EXIF blobId %hu", __FUNCTION__, blob->blobId);
+        return 0;
+    }
+
+    expectedSize = blob->blobSize;
+    if (expectedSize == 0 || expectedSize > maxSize - sizeof(struct CameraBlob)) {
+        ALOGE("%s: Invalid blobSize %zu.", __FUNCTION__, expectedSize);
+        return 0;
+    }
+
+    uint32_t totalSize = 0;
+
+    // Verify APP1 marker (mandatory)
+    uint8_t app1Marker[] = {0xFF, 0xE1};
+    if (memcmp(appSegmentBuffer, app1Marker, sizeof(app1Marker))) {
+        ALOGE("%s: Invalid APP1 marker: %x, %x", __FUNCTION__,
+                appSegmentBuffer[0], appSegmentBuffer[1]);
+        return 0;
+    }
+    totalSize += sizeof(app1Marker);
+
+    uint16_t app1Size = (static_cast<uint16_t>(appSegmentBuffer[totalSize]) << 8) +
+            appSegmentBuffer[totalSize+1];
+    totalSize += app1Size;
+
+    ALOGV("%s: Expected APP segments size %zu, APP1 segment size %u",
+            __FUNCTION__, expectedSize, app1Size);
+    while (totalSize < expectedSize) {
+        if (appSegmentBuffer[totalSize] != 0xFF ||
+                appSegmentBuffer[totalSize+1] <= 0xE1 ||
+                appSegmentBuffer[totalSize+1] > 0xEF) {
+            // Invalid APPn marker
+            ALOGE("%s: Invalid APPn marker: %x, %x", __FUNCTION__,
+                    appSegmentBuffer[totalSize], appSegmentBuffer[totalSize+1]);
+            return 0;
+        }
+        totalSize += 2;
+
+        uint16_t appnSize = (static_cast<uint16_t>(appSegmentBuffer[totalSize]) << 8) +
+                appSegmentBuffer[totalSize+1];
+        totalSize += appnSize;
+    }
+
+    if (totalSize != expectedSize) {
+        ALOGE("%s: Invalid JPEG APP segments: totalSize %u vs expected size %zu",
+                __FUNCTION__, totalSize, expectedSize);
+        return 0;
+    }
+
+    *app1SegmentSize = app1Size + sizeof(app1Marker);
+    return expectedSize;
+}
+
+int64_t HeicCompositeStream::findTimestampInNsLocked(int64_t timeInUs) {
+    for (const auto& fn : mFrameNumberMap) {
+        if (timeInUs == ns2us(fn.second)) {
+            return fn.second;
+        }
+    }
+    for (const auto& inputFrame : mPendingInputFrames) {
+        if (timeInUs == ns2us(inputFrame.first)) {
+            return inputFrame.first;
+        }
+    }
+    return -1;
+}
+
+status_t HeicCompositeStream::copyOneYuvTile(sp<MediaCodecBuffer>& codecBuffer,
+        const CpuConsumer::LockedBuffer& yuvBuffer,
+        size_t top, size_t left, size_t width, size_t height) {
+    ATRACE_CALL();
+
+    // Get stride information for codecBuffer
+    sp<ABuffer> imageData;
+    if (!codecBuffer->meta()->findBuffer("image-data", &imageData)) {
+        ALOGE("%s: Codec input buffer is not for image data!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    if (imageData->size() != sizeof(MediaImage2)) {
+        ALOGE("%s: Invalid codec input image size %zu, expected %zu",
+                __FUNCTION__, imageData->size(), sizeof(MediaImage2));
+        return BAD_VALUE;
+    }
+    MediaImage2* imageInfo = reinterpret_cast<MediaImage2*>(imageData->data());
+    if (imageInfo->mType != MediaImage2::MEDIA_IMAGE_TYPE_YUV ||
+            imageInfo->mBitDepth != 8 ||
+            imageInfo->mBitDepthAllocated != 8 ||
+            imageInfo->mNumPlanes != 3) {
+        ALOGE("%s: Invalid codec input image info: mType %d, mBitDepth %d, "
+                "mBitDepthAllocated %d, mNumPlanes %d!", __FUNCTION__,
+                imageInfo->mType, imageInfo->mBitDepth,
+                imageInfo->mBitDepthAllocated, imageInfo->mNumPlanes);
+        return BAD_VALUE;
+    }
+
+    ALOGV("%s: yuvBuffer chromaStep %d, chromaStride %d",
+            __FUNCTION__, yuvBuffer.chromaStep, yuvBuffer.chromaStride);
+    ALOGV("%s: U offset %u, V offset %u, U rowInc %d, V rowInc %d, U colInc %d, V colInc %d",
+            __FUNCTION__, imageInfo->mPlane[MediaImage2::U].mOffset,
+            imageInfo->mPlane[MediaImage2::V].mOffset,
+            imageInfo->mPlane[MediaImage2::U].mRowInc,
+            imageInfo->mPlane[MediaImage2::V].mRowInc,
+            imageInfo->mPlane[MediaImage2::U].mColInc,
+            imageInfo->mPlane[MediaImage2::V].mColInc);
+
+    // Y
+    for (auto row = top; row < top+height; row++) {
+        uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[MediaImage2::Y].mOffset +
+                imageInfo->mPlane[MediaImage2::Y].mRowInc * (row - top);
+        memcpy(dst, yuvBuffer.data+row*yuvBuffer.stride+left, width);
+    }
+
+    // U is Cb, V is Cr
+    bool codecUPlaneFirst = imageInfo->mPlane[MediaImage2::V].mOffset >
+            imageInfo->mPlane[MediaImage2::U].mOffset;
+    uint32_t codecUvOffsetDiff = codecUPlaneFirst ?
+            imageInfo->mPlane[MediaImage2::V].mOffset - imageInfo->mPlane[MediaImage2::U].mOffset :
+            imageInfo->mPlane[MediaImage2::U].mOffset - imageInfo->mPlane[MediaImage2::V].mOffset;
+    bool isCodecUvSemiplannar = (codecUvOffsetDiff == 1) &&
+            (imageInfo->mPlane[MediaImage2::U].mRowInc ==
+            imageInfo->mPlane[MediaImage2::V].mRowInc) &&
+            (imageInfo->mPlane[MediaImage2::U].mColInc == 2) &&
+            (imageInfo->mPlane[MediaImage2::V].mColInc == 2);
+    bool isCodecUvPlannar =
+            ((codecUPlaneFirst && codecUvOffsetDiff >=
+                    imageInfo->mPlane[MediaImage2::U].mRowInc * imageInfo->mHeight/2) ||
+            ((!codecUPlaneFirst && codecUvOffsetDiff >=
+                    imageInfo->mPlane[MediaImage2::V].mRowInc * imageInfo->mHeight/2))) &&
+            imageInfo->mPlane[MediaImage2::U].mColInc == 1 &&
+            imageInfo->mPlane[MediaImage2::V].mColInc == 1;
+    bool cameraUPlaneFirst = yuvBuffer.dataCr > yuvBuffer.dataCb;
+
+    if (isCodecUvSemiplannar && yuvBuffer.chromaStep == 2 &&
+            (codecUPlaneFirst == cameraUPlaneFirst)) {
+        // UV semiplannar
+        // The chrome plane could be either Cb first, or Cr first. Take the
+        // smaller address.
+        uint8_t *src = std::min(yuvBuffer.dataCb, yuvBuffer.dataCr);
+        MediaImage2::PlaneIndex dstPlane = codecUvOffsetDiff > 0 ? MediaImage2::U : MediaImage2::V;
+        for (auto row = top/2; row < (top+height)/2; row++) {
+            uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[dstPlane].mOffset +
+                    imageInfo->mPlane[dstPlane].mRowInc * (row - top/2);
+            memcpy(dst, src+row*yuvBuffer.chromaStride+left, width);
+        }
+    } else if (isCodecUvPlannar && yuvBuffer.chromaStep == 1) {
+        // U plane
+        for (auto row = top/2; row < (top+height)/2; row++) {
+            uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[MediaImage2::U].mOffset +
+                    imageInfo->mPlane[MediaImage2::U].mRowInc * (row - top/2);
+            memcpy(dst, yuvBuffer.dataCb+row*yuvBuffer.chromaStride+left/2, width/2);
+        }
+
+        // V plane
+        for (auto row = top/2; row < (top+height)/2; row++) {
+            uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[MediaImage2::V].mOffset +
+                    imageInfo->mPlane[MediaImage2::V].mRowInc * (row - top/2);
+            memcpy(dst, yuvBuffer.dataCr+row*yuvBuffer.chromaStride+left/2, width/2);
+        }
+    } else {
+        // Convert between semiplannar and plannar
+        uint8_t *dst = codecBuffer->data();
+        for (auto row = top/2; row < (top+height)/2; row++) {
+            for (auto col = left/2; col < (left+width)/2; col++) {
+                // U/Cb
+                int32_t dstIndex = imageInfo->mPlane[MediaImage2::U].mOffset +
+                        imageInfo->mPlane[MediaImage2::U].mRowInc * (row - top/2) +
+                        imageInfo->mPlane[MediaImage2::U].mColInc * (col - left/2);
+                int32_t srcIndex = row * yuvBuffer.chromaStride + yuvBuffer.chromaStep * col;
+                dst[dstIndex] = yuvBuffer.dataCb[srcIndex];
+
+                // V/Cr
+                dstIndex = imageInfo->mPlane[MediaImage2::V].mOffset +
+                        imageInfo->mPlane[MediaImage2::V].mRowInc * (row - top/2) +
+                        imageInfo->mPlane[MediaImage2::V].mColInc * (col - left/2);
+                srcIndex = row * yuvBuffer.chromaStride + yuvBuffer.chromaStep * col;
+                dst[dstIndex] = yuvBuffer.dataCr[srcIndex];
+            }
+        }
+    }
+    return OK;
+}
+
+size_t HeicCompositeStream::calcAppSegmentMaxSize(const CameraMetadata& info) {
+    camera_metadata_ro_entry_t entry = info.find(ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT);
+    size_t maxAppsSegment = 1;
+    if (entry.count > 0) {
+        maxAppsSegment = entry.data.u8[0] < 1 ? 1 :
+                entry.data.u8[0] > 16 ? 16 : entry.data.u8[0];
+    }
+    return maxAppsSegment * (2 + 0xFFFF) + sizeof(struct CameraBlob);
+}
+
+bool HeicCompositeStream::threadLoop() {
+    int64_t currentTs = INT64_MAX;
+    bool newInputAvailable = false;
+
+    {
+        Mutex::Autolock l(mMutex);
+        if (mErrorState) {
+            // In case we landed in error state, return any pending buffers and
+            // halt all further processing.
+            compilePendingInputLocked();
+            releaseInputFramesLocked(currentTs);
+            return false;
+        }
+
+
+        while (!newInputAvailable) {
+            compilePendingInputLocked();
+            newInputAvailable = getNextReadyInputLocked(&currentTs);
+
+            if (!newInputAvailable) {
+                auto failingFrameNumber = getNextFailingInputLocked(&currentTs);
+                if (failingFrameNumber >= 0) {
+                    // We cannot erase 'mPendingInputFrames[currentTs]' at this point because it is
+                    // possible for two internal stream buffers to fail. In such scenario the
+                    // composite stream should notify the client about a stream buffer error only
+                    // once and this information is kept within 'errorNotified'.
+                    // Any present failed input frames will be removed on a subsequent call to
+                    // 'releaseInputFramesLocked()'.
+                    releaseInputFrameLocked(&mPendingInputFrames[currentTs]);
+                    currentTs = INT64_MAX;
+                }
+
+                auto ret = mInputReadyCondition.waitRelative(mMutex, kWaitDuration);
+                if (ret == TIMED_OUT) {
+                    return true;
+                } else if (ret != OK) {
+                    ALOGE("%s: Timed wait on condition failed: %s (%d)", __FUNCTION__,
+                            strerror(-ret), ret);
+                    return false;
+                }
+            }
+        }
+    }
+
+    auto res = processInputFrame(currentTs, mPendingInputFrames[currentTs]);
+    Mutex::Autolock l(mMutex);
+    if (res != OK) {
+        ALOGE("%s: Failed processing frame with timestamp: %" PRIu64 ": %s (%d)",
+                __FUNCTION__, currentTs, strerror(-res), res);
+        mPendingInputFrames[currentTs].error = true;
+    }
+
+    if (mPendingInputFrames[currentTs].error ||
+            (mPendingInputFrames[currentTs].appSegmentWritten &&
+            mPendingInputFrames[currentTs].pendingOutputTiles == 0)) {
+        releaseInputFramesLocked(currentTs);
+    }
+
+    return true;
+}
+
+bool HeicCompositeStream::onStreamBufferError(const CaptureResultExtras& resultExtras) {
+    bool res = false;
+    // Buffer errors concerning internal composite streams should not be directly visible to
+    // camera clients. They must only receive a single buffer error with the public composite
+    // stream id.
+    if ((resultExtras.errorStreamId == mAppSegmentStreamId) ||
+            (resultExtras.errorStreamId == mMainImageStreamId)) {
+        flagAnErrorFrameNumber(resultExtras.frameNumber);
+        res = true;
+    }
+
+    return res;
+}
+
+void HeicCompositeStream::CodecCallbackHandler::onMessageReceived(const sp<AMessage> &msg) {
+    sp<HeicCompositeStream> parent = mParent.promote();
+    if (parent == nullptr) return;
+
+    switch (msg->what()) {
+        case kWhatCallbackNotify: {
+             int32_t cbID;
+             if (!msg->findInt32("callbackID", &cbID)) {
+                 ALOGE("kWhatCallbackNotify: callbackID is expected.");
+                 break;
+             }
+
+             ALOGV("kWhatCallbackNotify: cbID = %d", cbID);
+
+             switch (cbID) {
+                 case MediaCodec::CB_INPUT_AVAILABLE: {
+                     int32_t index;
+                     if (!msg->findInt32("index", &index)) {
+                         ALOGE("CB_INPUT_AVAILABLE: index is expected.");
+                         break;
+                     }
+                     parent->onHeicInputFrameAvailable(index);
+                     break;
+                 }
+
+                 case MediaCodec::CB_OUTPUT_AVAILABLE: {
+                     int32_t index;
+                     size_t offset;
+                     size_t size;
+                     int64_t timeUs;
+                     int32_t flags;
+
+                     if (!msg->findInt32("index", &index)) {
+                         ALOGE("CB_OUTPUT_AVAILABLE: index is expected.");
+                         break;
+                     }
+                     if (!msg->findSize("offset", &offset)) {
+                         ALOGE("CB_OUTPUT_AVAILABLE: offset is expected.");
+                         break;
+                     }
+                     if (!msg->findSize("size", &size)) {
+                         ALOGE("CB_OUTPUT_AVAILABLE: size is expected.");
+                         break;
+                     }
+                     if (!msg->findInt64("timeUs", &timeUs)) {
+                         ALOGE("CB_OUTPUT_AVAILABLE: timeUs is expected.");
+                         break;
+                     }
+                     if (!msg->findInt32("flags", &flags)) {
+                         ALOGE("CB_OUTPUT_AVAILABLE: flags is expected.");
+                         break;
+                     }
+
+                     CodecOutputBufferInfo bufferInfo = {
+                         index,
+                         (int32_t)offset,
+                         (int32_t)size,
+                         timeUs,
+                         (uint32_t)flags};
+
+                     parent->onHeicOutputFrameAvailable(bufferInfo);
+                     break;
+                 }
+
+                 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED: {
+                     sp<AMessage> format;
+                     if (!msg->findMessage("format", &format)) {
+                         ALOGE("CB_OUTPUT_FORMAT_CHANGED: format is expected.");
+                         break;
+                     }
+
+                     parent->onHeicFormatChanged(format);
+                     break;
+                 }
+
+                 case MediaCodec::CB_ERROR: {
+                     status_t err;
+                     int32_t actionCode;
+                     AString detail;
+                     if (!msg->findInt32("err", &err)) {
+                         ALOGE("CB_ERROR: err is expected.");
+                         break;
+                     }
+                     if (!msg->findInt32("action", &actionCode)) {
+                         ALOGE("CB_ERROR: action is expected.");
+                         break;
+                     }
+                     msg->findString("detail", &detail);
+                     ALOGE("Codec reported error(0x%x), actionCode(%d), detail(%s)",
+                             err, actionCode, detail.c_str());
+
+                     parent->onHeicCodecError();
+                     break;
+                 }
+
+                 default: {
+                     ALOGE("kWhatCallbackNotify: callbackID(%d) is unexpected.", cbID);
+                     break;
+                 }
+             }
+             break;
+        }
+
+        default:
+            ALOGE("shouldn't be here");
+            break;
+    }
+}
+
+}; // namespace camera3
+}; // namespace android
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.h b/services/camera/libcameraservice/api2/HeicCompositeStream.h
new file mode 100644
index 0000000..0a76256
--- /dev/null
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERA3_HEIC_COMPOSITE_STREAM_H
+#define ANDROID_SERVERS_CAMERA_CAMERA3_HEIC_COMPOSITE_STREAM_H
+
+#include <queue>
+
+#include <gui/IProducerListener.h>
+#include <gui/CpuConsumer.h>
+
+#include <media/hardware/VideoAPI.h>
+#include <media/MediaCodecBuffer.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaMuxer.h>
+
+#include "CompositeStream.h"
+
+namespace android {
+namespace camera3 {
+
+class HeicCompositeStream : public CompositeStream, public Thread,
+        public CpuConsumer::FrameAvailableListener {
+public:
+    HeicCompositeStream(wp<CameraDeviceBase> device,
+            wp<hardware::camera2::ICameraDeviceCallbacks> cb);
+    ~HeicCompositeStream() override;
+
+    static bool isHeicCompositeStream(const sp<Surface> &surface);
+
+    status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
+            bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
+            camera3_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
+            std::vector<int> *surfaceIds, int streamSetId, bool isShared) override;
+
+    status_t deleteInternalStreams() override;
+
+    status_t configureStream() override;
+
+    status_t insertGbp(SurfaceMap* /*out*/outSurfaceMap, Vector<int32_t>* /*out*/outputStreamIds,
+            int32_t* /*out*/currentStreamId) override;
+
+    void onShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) override;
+
+    int getStreamId() override { return mMainImageStreamId; }
+
+    // Use onShutter to keep track of frame number <-> timestamp mapping.
+    void onBufferReleased(const BufferInfo& bufferInfo) override;
+    void onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId,
+            const CameraMetadata& settings) override;
+
+    // CpuConsumer listener implementation
+    void onFrameAvailable(const BufferItem& item) override;
+
+    // Return stream information about the internal camera streams
+    static status_t getCompositeStreamInfo(const OutputStreamInfo &streamInfo,
+            const CameraMetadata& ch, std::vector<OutputStreamInfo>* compositeOutput /*out*/);
+
+    static bool isSizeSupportedByHeifEncoder(int32_t width, int32_t height,
+            bool* useHeic, bool* useGrid, int64_t* stall);
+    static bool isInMemoryTempFileSupported();
+protected:
+
+    bool threadLoop() override;
+    bool onStreamBufferError(const CaptureResultExtras& resultExtras) override;
+    void onResultError(const CaptureResultExtras& /*resultExtras*/) override {}
+
+private:
+    //
+    // HEIC/HEVC Codec related structures, utility functions, and callbacks
+    //
+    struct CodecOutputBufferInfo {
+        int32_t index;
+        int32_t offset;
+        int32_t size;
+        int64_t timeUs;
+        uint32_t flags;
+    };
+
+    struct CodecInputBufferInfo {
+        int32_t index;
+        int64_t timeUs;
+        size_t tileIndex;
+    };
+
+    class CodecCallbackHandler : public AHandler {
+    public:
+        explicit CodecCallbackHandler(wp<HeicCompositeStream> parent) {
+            mParent = parent;
+        }
+        virtual void onMessageReceived(const sp<AMessage> &msg);
+    private:
+        wp<HeicCompositeStream> mParent;
+    };
+
+    enum {
+        kWhatCallbackNotify,
+    };
+
+    bool              mUseHeic;
+    sp<MediaCodec>    mCodec;
+    sp<ALooper>       mCodecLooper, mCallbackLooper;
+    sp<CodecCallbackHandler> mCodecCallbackHandler;
+    sp<AMessage>      mAsyncNotify;
+    sp<AMessage>      mFormat;
+    size_t            mNumOutputTiles;
+
+    int32_t           mOutputWidth, mOutputHeight;
+    size_t            mMaxHeicBufferSize;
+    int32_t           mGridWidth, mGridHeight;
+    size_t            mGridRows, mGridCols;
+    bool              mUseGrid; // Whether to use framework YUV frame tiling.
+
+    static const int64_t kNoFrameDropMaxPtsGap = -1000000;
+    static const int32_t kNoGridOpRate = 30;
+    static const int32_t kGridOpRate = 120;
+
+    void onHeicOutputFrameAvailable(const CodecOutputBufferInfo& bufferInfo);
+    void onHeicInputFrameAvailable(int32_t index);  // Only called for YUV input mode.
+    void onHeicFormatChanged(sp<AMessage>& newFormat);
+    void onHeicCodecError();
+
+    status_t initializeCodec(uint32_t width, uint32_t height,
+            const sp<CameraDeviceBase>& cameraDevice);
+    void deinitCodec();
+
+    //
+    // Composite stream related structures, utility functions and callbacks.
+    //
+    struct InputFrame {
+        int32_t                   orientation;
+        int32_t                   quality;
+
+        CpuConsumer::LockedBuffer     appSegmentBuffer;
+        std::vector<CodecOutputBufferInfo> codecOutputBuffers;
+
+        // Fields that are only applicable to HEVC tiling.
+        CpuConsumer::LockedBuffer     yuvBuffer;
+        std::vector<CodecInputBufferInfo> codecInputBuffers;
+
+        bool                      error;
+        bool                      errorNotified;
+        int64_t                   frameNumber;
+
+        sp<MediaMuxer>            muxer;
+        int                       fenceFd;
+        int                       fileFd;
+        ssize_t                   trackIndex;
+        ANativeWindowBuffer       *anb;
+
+        bool                      appSegmentWritten;
+        size_t                    pendingOutputTiles;
+        size_t                    codecInputCounter;
+
+        InputFrame() : orientation(0), quality(kDefaultJpegQuality), error(false),
+                       errorNotified(false), frameNumber(-1), fenceFd(-1), fileFd(-1),
+                       trackIndex(-1), anb(nullptr), appSegmentWritten(false),
+                       pendingOutputTiles(0), codecInputCounter(0) { }
+    };
+
+    void compilePendingInputLocked();
+    // Find first complete and valid frame with smallest timestamp
+    bool getNextReadyInputLocked(int64_t *currentTs /*out*/);
+    // Find next failing frame number with smallest timestamp and return respective frame number
+    int64_t getNextFailingInputLocked(int64_t *currentTs /*out*/);
+
+    status_t processInputFrame(nsecs_t timestamp, InputFrame &inputFrame);
+    status_t processCodecInputFrame(InputFrame &inputFrame);
+    status_t startMuxerForInputFrame(nsecs_t timestamp, InputFrame &inputFrame);
+    status_t processAppSegment(nsecs_t timestamp, InputFrame &inputFrame);
+    status_t processOneCodecOutputFrame(nsecs_t timestamp, InputFrame &inputFrame);
+    status_t processCompletedInputFrame(nsecs_t timestamp, InputFrame &inputFrame);
+
+    void releaseInputFrameLocked(InputFrame *inputFrame /*out*/);
+    void releaseInputFramesLocked(int64_t currentTs);
+
+    size_t findAppSegmentsSize(const uint8_t* appSegmentBuffer, size_t maxSize,
+            size_t* app1SegmentSize);
+    int64_t findTimestampInNsLocked(int64_t timeInUs);
+    status_t copyOneYuvTile(sp<MediaCodecBuffer>& codecBuffer,
+            const CpuConsumer::LockedBuffer& yuvBuffer,
+            size_t top, size_t left, size_t width, size_t height);
+    static size_t calcAppSegmentMaxSize(const CameraMetadata& info);
+
+    static const nsecs_t kWaitDuration = 10000000; // 10 ms
+    static const int32_t kDefaultJpegQuality = 99;
+    static const auto kJpegDataSpace = HAL_DATASPACE_V0_JFIF;
+    static const android_dataspace kAppSegmentDataSpace =
+            static_cast<android_dataspace>(HAL_DATASPACE_JPEG_APP_SEGMENTS);
+    static const android_dataspace kHeifDataSpace =
+            static_cast<android_dataspace>(HAL_DATASPACE_HEIF);
+
+    int               mAppSegmentStreamId, mAppSegmentSurfaceId;
+    sp<CpuConsumer>   mAppSegmentConsumer;
+    sp<Surface>       mAppSegmentSurface;
+    bool              mAppSegmentBufferAcquired;
+    size_t            mAppSegmentMaxSize;
+
+    int               mMainImageStreamId, mMainImageSurfaceId;
+    sp<Surface>       mMainImageSurface;
+    sp<CpuConsumer>   mMainImageConsumer; // Only applicable for HEVC codec.
+    bool              mYuvBufferAcquired; // Only applicable to HEVC codec
+
+    sp<Surface>       mOutputSurface;
+    sp<ProducerListener> mProducerListener;
+
+
+    // Map from frame number to JPEG setting of orientation+quality
+    std::map<int64_t, std::pair<int32_t, int32_t>> mSettingsByFrameNumber;
+    // Map from timestamp to JPEG setting of orientation+quality
+    std::map<int64_t, std::pair<int32_t, int32_t>> mSettingsByTimestamp;
+
+    // Keep all incoming APP segment Blob buffer pending further processing.
+    std::vector<int64_t> mInputAppSegmentBuffers;
+
+    // Keep all incoming HEIC blob buffer pending further processing.
+    std::vector<CodecOutputBufferInfo> mCodecOutputBuffers;
+    std::queue<int64_t> mCodecOutputBufferTimestamps;
+    size_t mOutputBufferCounter;
+
+    // Keep all incoming Yuv buffer pending tiling and encoding (for HEVC YUV tiling only)
+    std::vector<int64_t> mInputYuvBuffers;
+    // Keep all codec input buffers ready to be filled out (for HEVC YUV tiling only)
+    std::vector<int32_t> mCodecInputBuffers;
+
+    // Artificial strictly incremental YUV grid timestamp to make encoder happy.
+    int64_t mGridTimestampUs;
+
+    // In most common use case, entries are accessed in order.
+    std::map<int64_t, InputFrame> mPendingInputFrames;
+};
+
+}; // namespace camera3
+}; // namespace android
+
+#endif //ANDROID_SERVERS_CAMERA_CAMERA3_HEIC_COMPOSITE_STREAM_H
diff --git a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
new file mode 100644
index 0000000..ed9be6e
--- /dev/null
+++ b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HeicEncoderInfoManager"
+//#define LOG_NDEBUG 0
+
+#include <cstdint>
+#include <regex>
+
+#include <cutils/properties.h>
+#include <log/log_main.h>
+#include <system/graphics.h>
+
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/foundation/MediaDefs.h>
+#include <media/stagefright/foundation/ABuffer.h>
+
+#include "HeicEncoderInfoManager.h"
+
+namespace android {
+namespace camera3 {
+
+HeicEncoderInfoManager::HeicEncoderInfoManager() :
+        mIsInited(false),
+        mMinSizeHeic(0, 0),
+        mMaxSizeHeic(INT32_MAX, INT32_MAX),
+        mHasHEVC(false),
+        mHasHEIC(false),
+        mDisableGrid(false) {
+    if (initialize() == OK) {
+        mIsInited = true;
+    }
+}
+
+HeicEncoderInfoManager::~HeicEncoderInfoManager() {
+}
+
+bool HeicEncoderInfoManager::isSizeSupported(int32_t width, int32_t height, bool* useHeic,
+        bool* useGrid, int64_t* stall) const {
+    if (useHeic == nullptr || useGrid == nullptr) {
+        ALOGE("%s: invalid parameters: useHeic %p, useGrid %p",
+                __FUNCTION__, useHeic, useGrid);
+        return false;
+    }
+    if (!mIsInited) return false;
+
+    bool chooseHeic = false, enableGrid = true;
+    if (mHasHEIC && width >= mMinSizeHeic.first &&
+            height >= mMinSizeHeic.second && width <= mMaxSizeHeic.first &&
+            height <= mMaxSizeHeic.second) {
+        chooseHeic = true;
+        enableGrid = false;
+    } else if (mHasHEVC) {
+        bool fullSizeSupportedByHevc = (width >= mMinSizeHevc.first &&
+                height >= mMinSizeHevc.second &&
+                width <= mMaxSizeHevc.first &&
+                height <= mMaxSizeHevc.second);
+        if (fullSizeSupportedByHevc && (mDisableGrid ||
+                (width <= 1920 && height <= 1080))) {
+            enableGrid = false;
+        }
+    } else {
+        // No encoder available for the requested size.
+        return false;
+    }
+
+    if (stall != nullptr) {
+        // Find preferred encoder which advertise
+        // "measured-frame-rate-WIDTHxHEIGHT-range" key.
+        const FrameRateMaps& maps =
+                (chooseHeic && mHeicFrameRateMaps.size() > 0) ?
+                mHeicFrameRateMaps : mHevcFrameRateMaps;
+        const auto& closestSize = findClosestSize(maps, width, height);
+        if (closestSize == maps.end()) {
+            // The "measured-frame-rate-WIDTHxHEIGHT-range" key is optional.
+            // Hardcode to some default value (3.33ms * tile count) based on resolution.
+            *stall = 3333333LL * width * height / (kGridWidth * kGridHeight);
+            return true;
+        }
+
+        // Derive stall durations based on average fps of the closest size.
+        constexpr int64_t NSEC_PER_SEC = 1000000000LL;
+        int32_t avgFps = (closestSize->second.first + closestSize->second.second)/2;
+        float ratio = 1.0f * width * height /
+                (closestSize->first.first * closestSize->first.second);
+        *stall = ratio * NSEC_PER_SEC / avgFps;
+    }
+
+    *useHeic = chooseHeic;
+    *useGrid = enableGrid;
+    return true;
+}
+
+status_t HeicEncoderInfoManager::initialize() {
+    mDisableGrid = property_get_bool("camera.heic.disable_grid", false);
+    sp<IMediaCodecList> codecsList = MediaCodecList::getInstance();
+    if (codecsList == nullptr) {
+        // No media codec available.
+        return OK;
+    }
+
+    sp<AMessage> heicDetails = getCodecDetails(codecsList, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
+    sp<AMessage> hevcDetails = getCodecDetails(codecsList, MEDIA_MIMETYPE_VIDEO_HEVC);
+
+    if (hevcDetails == nullptr) {
+        if (heicDetails != nullptr) {
+            ALOGE("%s: Device must support HEVC codec if HEIC codec is available!",
+                    __FUNCTION__);
+            return BAD_VALUE;
+        }
+        return OK;
+    }
+
+    // Check CQ mode for HEVC codec
+    {
+        AString bitrateModes;
+        auto hasItem = hevcDetails->findString("feature-bitrate-modes", &bitrateModes);
+        if (!hasItem) {
+            ALOGE("%s: Failed to query bitrate modes for HEVC codec", __FUNCTION__);
+            return BAD_VALUE;
+        }
+        ALOGV("%s: HEVC codec's feature-bitrate-modes value is %d, %s",
+                __FUNCTION__, hasItem, bitrateModes.c_str());
+        std::regex pattern("(^|,)CQ($|,)", std::regex_constants::icase);
+        if (!std::regex_search(bitrateModes.c_str(), pattern)) {
+            return OK;
+        }
+    }
+
+    // HEIC size range
+    if (heicDetails != nullptr) {
+        auto res = getCodecSizeRange(MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC,
+                heicDetails, &mMinSizeHeic, &mMaxSizeHeic, &mHeicFrameRateMaps);
+        if (res != OK) {
+            ALOGE("%s: Failed to get HEIC codec size range: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+            return BAD_VALUE;
+        }
+        mHasHEIC = true;
+    }
+
+    // HEVC size range
+    {
+        auto res = getCodecSizeRange(MEDIA_MIMETYPE_VIDEO_HEVC,
+                hevcDetails, &mMinSizeHevc, &mMaxSizeHevc, &mHevcFrameRateMaps);
+        if (res != OK) {
+            ALOGE("%s: Failed to get HEVC codec size range: %s (%d)", __FUNCTION__,
+                    strerror(-res), res);
+            return BAD_VALUE;
+        }
+
+        mHasHEVC = true;
+    }
+
+    return OK;
+}
+
+status_t HeicEncoderInfoManager::getFrameRateMaps(sp<AMessage> details, FrameRateMaps* maps) {
+    if (details == nullptr || maps == nullptr) {
+        ALOGE("%s: Invalid input: details: %p, maps: %p", __FUNCTION__, details.get(), maps);
+        return BAD_VALUE;
+    }
+
+    for (size_t i = 0; i < details->countEntries(); i++) {
+        AMessage::Type type;
+        const char* entryName = details->getEntryNameAt(i, &type);
+        if (type != AMessage::kTypeString) continue;
+        std::regex frameRateNamePattern("measured-frame-rate-([0-9]+)[*x]([0-9]+)-range",
+                std::regex_constants::icase);
+        std::cmatch sizeMatch;
+        if (std::regex_match(entryName, sizeMatch, frameRateNamePattern) &&
+                sizeMatch.size() == 3) {
+            AMessage::ItemData item = details->getEntryAt(i);
+            AString fpsRangeStr;
+            if (item.find(&fpsRangeStr)) {
+                ALOGV("%s: %s", entryName, fpsRangeStr.c_str());
+                std::regex frameRatePattern("([0-9]+)-([0-9]+)");
+                std::cmatch fpsMatch;
+                if (std::regex_match(fpsRangeStr.c_str(), fpsMatch, frameRatePattern) &&
+                        fpsMatch.size() == 3) {
+                    maps->emplace(
+                            std::make_pair(stoi(sizeMatch[1]), stoi(sizeMatch[2])),
+                            std::make_pair(stoi(fpsMatch[1]), stoi(fpsMatch[2])));
+                } else {
+                    return BAD_VALUE;
+                }
+            }
+        }
+    }
+    return OK;
+}
+
+status_t HeicEncoderInfoManager::getCodecSizeRange(
+        const char* codecName,
+        sp<AMessage> details,
+        std::pair<int32_t, int32_t>* minSize,
+        std::pair<int32_t, int32_t>* maxSize,
+        FrameRateMaps* frameRateMaps) {
+    if (codecName == nullptr || minSize == nullptr || maxSize == nullptr ||
+            details == nullptr || frameRateMaps == nullptr) {
+        return BAD_VALUE;
+    }
+
+    AString sizeRange;
+    auto hasItem = details->findString("size-range", &sizeRange);
+    if (!hasItem) {
+        ALOGE("%s: Failed to query size range for codec %s", __FUNCTION__, codecName);
+        return BAD_VALUE;
+    }
+    ALOGV("%s: %s codec's size range is %s", __FUNCTION__, codecName, sizeRange.c_str());
+    std::regex pattern("([0-9]+)[*x]([0-9]+)-([0-9]+)[*x]([0-9]+)");
+    std::cmatch match;
+    if (std::regex_match(sizeRange.c_str(), match, pattern)) {
+        if (match.size() == 5) {
+            minSize->first = stoi(match[1]);
+            minSize->second = stoi(match[2]);
+            maxSize->first = stoi(match[3]);
+            maxSize->second = stoi(match[4]);
+            if (minSize->first > maxSize->first ||
+                    minSize->second > maxSize->second) {
+                ALOGE("%s: Invalid %s code size range: %s",
+                        __FUNCTION__, codecName, sizeRange.c_str());
+                return BAD_VALUE;
+            }
+        } else {
+            return BAD_VALUE;
+        }
+    }
+
+    auto res = getFrameRateMaps(details, frameRateMaps);
+    if (res != OK) {
+        return res;
+    }
+
+    return OK;
+}
+
+HeicEncoderInfoManager::FrameRateMaps::const_iterator HeicEncoderInfoManager::findClosestSize(
+        const FrameRateMaps& maps, int32_t width, int32_t height) const {
+    int32_t minDiff = INT32_MAX;
+    FrameRateMaps::const_iterator closestIter = maps.begin();
+    for (auto iter = maps.begin(); iter != maps.end(); iter++) {
+        // Use area difference between the sizes to approximate size
+        // difference.
+        int32_t diff = abs(iter->first.first * iter->first.second - width * height);
+        if (diff < minDiff) {
+            closestIter = iter;
+            minDiff = diff;
+        }
+    }
+    return closestIter;
+}
+
+sp<AMessage> HeicEncoderInfoManager::getCodecDetails(
+        sp<IMediaCodecList> codecsList, const char* name) {
+    ssize_t idx = codecsList->findCodecByType(name, true /*encoder*/);
+    if (idx < 0) {
+        return nullptr;
+    }
+
+    const sp<MediaCodecInfo> info = codecsList->getCodecInfo(idx);
+    if (info == nullptr) {
+        ALOGE("%s: Failed to get codec info for %s", __FUNCTION__, name);
+        return nullptr;
+    }
+    const sp<MediaCodecInfo::Capabilities> caps =
+            info->getCapabilitiesFor(name);
+    if (caps == nullptr) {
+        ALOGE("%s: Failed to get capabilities for codec %s", __FUNCTION__, name);
+        return nullptr;
+    }
+    const sp<AMessage> details = caps->getDetails();
+    if (details == nullptr) {
+        ALOGE("%s: Failed to get details for codec %s", __FUNCTION__, name);
+        return nullptr;
+    }
+
+    return details;
+}
+} //namespace camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h
new file mode 100644
index 0000000..fb0b914
--- /dev/null
+++ b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_HEICENCODER_INFO_MANAGER_H
+#define ANDROID_SERVERS_CAMERA_HEICENCODER_INFO_MANAGER_H
+
+#include <unordered_map>
+#include <utility>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include <media/IMediaCodecList.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+namespace android {
+namespace camera3 {
+
+class HeicEncoderInfoManager {
+public:
+    static HeicEncoderInfoManager& getInstance() {
+        static HeicEncoderInfoManager instance;
+        return instance;
+    }
+
+    bool isSizeSupported(int32_t width, int32_t height,
+            bool* useHeic, bool* useGrid, int64_t* stall) const;
+
+    static const auto kGridWidth = 512;
+    static const auto kGridHeight = 512;
+private:
+    struct SizePairHash {
+        std::size_t operator () (const std::pair<int32_t,int32_t> &p) const {
+            return p.first * 31 + p.second;
+        }
+    };
+
+    typedef std::unordered_map<std::pair<int32_t, int32_t>,
+            std::pair<int32_t, int32_t>, SizePairHash> FrameRateMaps;
+
+    HeicEncoderInfoManager();
+    virtual ~HeicEncoderInfoManager();
+
+    status_t initialize();
+    status_t getFrameRateMaps(sp<AMessage> details, FrameRateMaps* maps);
+    status_t getCodecSizeRange(const char* codecName, sp<AMessage> details,
+            std::pair<int32_t, int32_t>* minSize, std::pair<int32_t, int32_t>* maxSize,
+            FrameRateMaps* frameRateMaps);
+    FrameRateMaps::const_iterator findClosestSize(const FrameRateMaps& maps,
+            int32_t width, int32_t height) const;
+    sp<AMessage> getCodecDetails(sp<IMediaCodecList> codecsList, const char* name);
+
+    bool mIsInited;
+    std::pair<int32_t, int32_t> mMinSizeHeic, mMaxSizeHeic;
+    std::pair<int32_t, int32_t> mMinSizeHevc, mMaxSizeHevc;
+    bool mHasHEVC, mHasHEIC;
+    FrameRateMaps mHeicFrameRateMaps, mHevcFrameRateMaps;
+    bool mDisableGrid;
+
+};
+
+} // namespace camera3
+} // namespace android
+
+#endif // ANDROID_SERVERS_CAMERA_HEICENCODER_INFO_MANAGER_H
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 8ee3298..d6789a4 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -38,6 +38,8 @@
 #include <hwbinder/IPCThreadState.h>
 #include <utils/Trace.h>
 
+#include "api2/HeicCompositeStream.h"
+
 namespace android {
 
 using namespace ::android::hardware::camera;
@@ -69,6 +71,8 @@
     }
     mListener = listener;
     mServiceProxy = proxy;
+    mDeviceState = static_cast<hardware::hidl_bitfield<provider::V2_5::DeviceState>>(
+        provider::V2_5::DeviceState::NORMAL);
 
     // Registering will trigger notifications for all already-known providers
     bool success = mServiceProxy->registerForNotifications(
@@ -272,6 +276,26 @@
     return OK;
 }
 
+status_t CameraProviderManager::notifyDeviceStateChange(
+        hardware::hidl_bitfield<provider::V2_5::DeviceState> newState) {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+    mDeviceState = newState;
+    status_t res = OK;
+    for (auto& provider : mProviders) {
+        ALOGV("%s: Notifying %s for new state 0x%" PRIx64,
+                __FUNCTION__, provider->mProviderName.c_str(), newState);
+        status_t singleRes = provider->notifyDeviceStateChange(mDeviceState);
+        if (singleRes != OK) {
+            ALOGE("%s: Unable to notify provider %s about device state change",
+                    __FUNCTION__,
+                    provider->mProviderName.c_str());
+            res = singleRes;
+            // continue to do the rest of the providers instead of returning now
+        }
+    }
+    return res;
+}
+
 status_t CameraProviderManager::openSession(const std::string &id,
         const sp<device::V3_2::ICameraDeviceCallback>& callback,
         /*out*/
@@ -357,7 +381,7 @@
     if (!kEnableLazyHal) {
         return;
     }
-    ALOGI("Saving camera provider %s for camera device %s", provider->descriptor, cameraId.c_str());
+    ALOGV("Saving camera provider %s for camera device %s", provider->descriptor, cameraId.c_str());
     std::lock_guard<std::mutex> lock(mProviderInterfaceMapLock);
     std::unordered_map<std::string, sp<provider::V2_4::ICameraProvider>> *primaryMap, *alternateMap;
     if (usageType == DeviceMode::TORCH) {
@@ -381,7 +405,7 @@
     if (!kEnableLazyHal) {
         return;
     }
-    ALOGI("Removing camera device %s", cameraId.c_str());
+    ALOGV("Removing camera device %s", cameraId.c_str());
     std::unordered_map<std::string, sp<provider::V2_4::ICameraProvider>> *providerMap;
     if (usageType == DeviceMode::TORCH) {
         providerMap = &mTorchProviderByCameraId;
@@ -874,6 +898,130 @@
     return res;
 }
 
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fillHeicStreamCombinations(
+        std::vector<int32_t>* outputs,
+        std::vector<int64_t>* durations,
+        std::vector<int64_t>* stallDurations,
+        const camera_metadata_entry& halStreamConfigs,
+        const camera_metadata_entry& halStreamDurations) {
+    if (outputs == nullptr || durations == nullptr || stallDurations == nullptr) {
+        return BAD_VALUE;
+    }
+
+    static bool supportInMemoryTempFile =
+            camera3::HeicCompositeStream::isInMemoryTempFileSupported();
+    if (!supportInMemoryTempFile) {
+        ALOGI("%s: No HEIC support due to absence of in memory temp file support",
+                __FUNCTION__);
+        return OK;
+    }
+
+    for (size_t i = 0; i < halStreamConfigs.count; i += 4) {
+        int32_t format = halStreamConfigs.data.i32[i];
+        // Only IMPLEMENTATION_DEFINED and YUV_888 can be used to generate HEIC
+        // image.
+        if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
+                format != HAL_PIXEL_FORMAT_YCBCR_420_888) {
+            continue;
+        }
+
+        bool sizeAvail = false;
+        for (size_t j = 0; j < outputs->size(); j+= 4) {
+            if ((*outputs)[j+1] == halStreamConfigs.data.i32[i+1] &&
+                    (*outputs)[j+2] == halStreamConfigs.data.i32[i+2]) {
+                sizeAvail = true;
+                break;
+            }
+        }
+        if (sizeAvail) continue;
+
+        int64_t stall = 0;
+        bool useHeic, useGrid;
+        if (camera3::HeicCompositeStream::isSizeSupportedByHeifEncoder(
+                halStreamConfigs.data.i32[i+1], halStreamConfigs.data.i32[i+2],
+                &useHeic, &useGrid, &stall)) {
+            if (useGrid != (format == HAL_PIXEL_FORMAT_YCBCR_420_888)) {
+                continue;
+            }
+
+            // HEIC configuration
+            int32_t config[] = {HAL_PIXEL_FORMAT_BLOB, halStreamConfigs.data.i32[i+1],
+                    halStreamConfigs.data.i32[i+2], 0 /*isInput*/};
+            outputs->insert(outputs->end(), config, config + 4);
+
+            // HEIC minFrameDuration
+            for (size_t j = 0; j < halStreamDurations.count; j += 4) {
+                if (halStreamDurations.data.i64[j] == format &&
+                        halStreamDurations.data.i64[j+1] == halStreamConfigs.data.i32[i+1] &&
+                        halStreamDurations.data.i64[j+2] == halStreamConfigs.data.i32[i+2]) {
+                    int64_t duration[] = {HAL_PIXEL_FORMAT_BLOB, halStreamConfigs.data.i32[i+1],
+                            halStreamConfigs.data.i32[i+2], halStreamDurations.data.i64[j+3]};
+                    durations->insert(durations->end(), duration, duration+4);
+                    break;
+                }
+            }
+
+            // HEIC stallDuration
+            int64_t stallDuration[] = {HAL_PIXEL_FORMAT_BLOB, halStreamConfigs.data.i32[i+1],
+                    halStreamConfigs.data.i32[i+2], stall};
+            stallDurations->insert(stallDurations->end(), stallDuration, stallDuration+4);
+        }
+    }
+    return OK;
+}
+
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::deriveHeicTags() {
+    auto& c = mCameraCharacteristics;
+
+    camera_metadata_entry halHeicSupport = c.find(ANDROID_HEIC_INFO_SUPPORTED);
+    if (halHeicSupport.count > 1) {
+        ALOGE("%s: Invalid entry count %zu for ANDROID_HEIC_INFO_SUPPORTED",
+                __FUNCTION__, halHeicSupport.count);
+        return BAD_VALUE;
+    } else if (halHeicSupport.count == 0 ||
+            halHeicSupport.data.u8[0] == ANDROID_HEIC_INFO_SUPPORTED_FALSE) {
+        // Camera HAL doesn't support mandatory stream combinations for HEIC.
+        return OK;
+    }
+
+    camera_metadata_entry maxJpegAppsSegments =
+            c.find(ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT);
+    if (maxJpegAppsSegments.count != 1 || maxJpegAppsSegments.data.u8[0] == 0 ||
+            maxJpegAppsSegments.data.u8[0] > 16) {
+        ALOGE("%s: ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT must be within [1, 16]",
+                __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    // Populate HEIC output configurations and its related min frame duration
+    // and stall duration.
+    std::vector<int32_t> heicOutputs;
+    std::vector<int64_t> heicDurations;
+    std::vector<int64_t> heicStallDurations;
+
+    camera_metadata_entry halStreamConfigs =
+            c.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+    camera_metadata_entry minFrameDurations =
+            c.find(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+
+    status_t res = fillHeicStreamCombinations(&heicOutputs, &heicDurations, &heicStallDurations,
+            halStreamConfigs, minFrameDurations);
+    if (res != OK) {
+        ALOGE("%s: Failed to fill HEIC stream combinations: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+        return res;
+    }
+
+    c.update(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS,
+           heicOutputs.data(), heicOutputs.size());
+    c.update(ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS,
+            heicDurations.data(), heicDurations.size());
+    c.update(ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS,
+            heicStallDurations.data(), heicStallDurations.size());
+
+    return OK;
+}
+
 bool CameraProviderManager::isLogicalCamera(const std::string& id,
         std::vector<std::string>* physicalCameraIds) {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
@@ -962,7 +1110,7 @@
     }
 
     sp<ProviderInfo> providerInfo = new ProviderInfo(newProvider, this);
-    status_t res = providerInfo->initialize(interface);
+    status_t res = providerInfo->initialize(interface, mDeviceState);
     if (res != OK) {
         return res;
     }
@@ -1023,7 +1171,8 @@
 }
 
 status_t CameraProviderManager::ProviderInfo::initialize(
-        sp<provider::V2_4::ICameraProvider>& interface) {
+        sp<provider::V2_4::ICameraProvider>& interface,
+        hardware::hidl_bitfield<provider::V2_5::DeviceState> currentDeviceState) {
     status_t res = parseProviderName(mProviderName, &mType, &mId);
     if (res != OK) {
         ALOGE("%s: Invalid provider name, ignoring", __FUNCTION__);
@@ -1031,6 +1180,15 @@
     }
     ALOGI("Connecting to new camera provider: %s, isRemote? %d",
             mProviderName.c_str(), interface->isRemote());
+
+    // Determine minor version
+    auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
+    if (castResult.isOk()) {
+        mMinorVersion = 5;
+    } else {
+        mMinorVersion = 4;
+    }
+
     // cameraDeviceStatusChange callbacks may be called (and causing new devices added)
     // before setCallback returns
     hardware::Return<Status> status = interface->setCallback(this);
@@ -1055,6 +1213,24 @@
                 __FUNCTION__, mProviderName.c_str());
     }
 
+    if (!kEnableLazyHal) {
+        // Save HAL reference indefinitely
+        mSavedInterface = interface;
+    } else {
+        mActiveInterface = interface;
+    }
+
+    ALOGV("%s: Setting device state for %s: 0x%" PRIx64,
+            __FUNCTION__, mProviderName.c_str(), mDeviceState);
+    notifyDeviceStateChange(currentDeviceState);
+
+    res = setUpVendorTags();
+    if (res != OK) {
+        ALOGE("%s: Unable to set up vendor tags from provider '%s'",
+                __FUNCTION__, mProviderName.c_str());
+        return res;
+    }
+
     // Get initial list of camera devices, if any
     std::vector<std::string> devices;
     hardware::Return<void> ret = interface->getCameraIdList([&status, this, &devices](
@@ -1111,34 +1287,28 @@
         }
     }
 
-    res = setUpVendorTags();
-    if (res != OK) {
-        ALOGE("%s: Unable to set up vendor tags from provider '%s'",
-                __FUNCTION__, mProviderName.c_str());
-        return res;
-    }
-
     ALOGI("Camera provider %s ready with %zu camera devices",
             mProviderName.c_str(), mDevices.size());
 
     mInitialized = true;
-    if (!kEnableLazyHal) {
-        // Save HAL reference indefinitely
-        mSavedInterface = interface;
-    }
     return OK;
 }
 
 const sp<provider::V2_4::ICameraProvider>
 CameraProviderManager::ProviderInfo::startProviderInterface() {
     ATRACE_CALL();
-    ALOGI("Request to start camera provider: %s", mProviderName.c_str());
+    ALOGV("Request to start camera provider: %s", mProviderName.c_str());
     if (mSavedInterface != nullptr) {
         return mSavedInterface;
     }
+    if (!kEnableLazyHal) {
+        ALOGE("Bad provider state! Should not be here on a non-lazy HAL!");
+        return nullptr;
+    }
+
     auto interface = mActiveInterface.promote();
     if (interface == nullptr) {
-        ALOGI("Could not promote, calling getService(%s)", mProviderName.c_str());
+        ALOGI("Camera HAL provider needs restart, calling getService(%s)", mProviderName.c_str());
         interface = mManager->mServiceProxy->getService(mProviderName);
         interface->setCallback(this);
         hardware::Return<bool> linked = interface->linkToDeath(this, /*cookie*/ mId);
@@ -1151,9 +1321,22 @@
             ALOGW("%s: Unable to link to provider '%s' death notifications",
                     __FUNCTION__, mProviderName.c_str());
         }
+        // Send current device state
+        if (mMinorVersion >= 5) {
+            auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
+            if (castResult.isOk()) {
+                sp<provider::V2_5::ICameraProvider> interface_2_5 = castResult;
+                if (interface_2_5 != nullptr) {
+                    ALOGV("%s: Initial device state for %s: 0x %" PRIx64,
+                            __FUNCTION__, mProviderName.c_str(), mDeviceState);
+                    interface_2_5->notifyDeviceStateChange(mDeviceState);
+                }
+            }
+        }
+
         mActiveInterface = interface;
     } else {
-        ALOGI("Camera provider (%s) already in use. Re-using instance.", mProviderName.c_str());
+        ALOGV("Camera provider (%s) already in use. Re-using instance.", mProviderName.c_str());
     }
     return interface;
 }
@@ -1238,8 +1421,10 @@
 }
 
 status_t CameraProviderManager::ProviderInfo::dump(int fd, const Vector<String16>&) const {
-    dprintf(fd, "== Camera Provider HAL %s (v2.4, %s) static info: %zu devices: ==\n",
-            mProviderName.c_str(), mIsRemote ? "remote" : "passthrough",
+    dprintf(fd, "== Camera Provider HAL %s (v2.%d, %s) static info: %zu devices: ==\n",
+            mProviderName.c_str(),
+            mMinorVersion,
+            mIsRemote ? "remote" : "passthrough",
             mDevices.size());
 
     for (auto& device : mDevices) {
@@ -1438,6 +1623,26 @@
     return OK;
 }
 
+status_t CameraProviderManager::ProviderInfo::notifyDeviceStateChange(
+        hardware::hidl_bitfield<provider::V2_5::DeviceState> newDeviceState) {
+    mDeviceState = newDeviceState;
+    if (mMinorVersion >= 5) {
+        // Check if the provider is currently active - not going to start it up for this notification
+        auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
+        if (interface != nullptr) {
+            // Send current device state
+            auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
+            if (castResult.isOk()) {
+                sp<provider::V2_5::ICameraProvider> interface_2_5 = castResult;
+                if (interface_2_5 != nullptr) {
+                    interface_2_5->notifyDeviceStateChange(mDeviceState);
+                }
+            }
+        }
+    }
+    return OK;
+}
+
 template<class DeviceInfoT>
 std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
     CameraProviderManager::ProviderInfo::initializeDeviceInfo(
@@ -1738,6 +1943,12 @@
         ALOGE("%s: Failed appending dynamic depth tags: %s (%d)", __FUNCTION__, strerror(-stat),
                 stat);
     }
+    res = deriveHeicTags();
+    if (OK != res) {
+        ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+    }
+
     camera_metadata_entry flashAvailable =
             mCameraCharacteristics.find(ANDROID_FLASH_INFO_AVAILABLE);
     if (flashAvailable.count == 1 &&
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 18869f5..a42fb4d 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -28,9 +28,8 @@
 #include <camera/CameraBase.h>
 #include <utils/Errors.h>
 #include <android/hardware/camera/common/1.0/types.h>
-#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
-//#include <android/hardware/camera/provider/2.4/ICameraProviderCallbacks.h>
 #include <android/hidl/manager/1.0/IServiceNotification.h>
 #include <camera/VendorTagDescriptor.h>
 
@@ -206,6 +205,12 @@
     status_t setUpVendorTags();
 
     /**
+     * Inform registered providers about a device state change, such as folding or unfolding
+     */
+    status_t notifyDeviceStateChange(
+        android::hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> newState);
+
+    /**
      * Open an active session to a camera device.
      *
      * This fully powers on the camera device hardware, and returns a handle to a
@@ -277,6 +282,9 @@
     wp<StatusListener> mListener;
     ServiceInteractionProxy* mServiceProxy;
 
+    // Current overall Android device physical status
+    android::hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> mDeviceState;
+
     // mProviderLifecycleLock is locked during onRegistration and removeProvider
     mutable std::mutex mProviderLifecycleLock;
 
@@ -303,10 +311,14 @@
     {
         const std::string mProviderName;
         const metadata_vendor_id_t mProviderTagid;
+        int mMinorVersion;
         sp<VendorTagDescriptor> mVendorTagDescriptor;
         bool mSetTorchModeSupported;
         bool mIsRemote;
 
+        // Current overall Android device physical status
+        hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> mDeviceState;
+
         // This pointer is used to keep a reference to the ICameraProvider that was last accessed.
         wp<hardware::camera::provider::V2_4::ICameraProvider> mActiveInterface;
 
@@ -316,7 +328,9 @@
                 CameraProviderManager *manager);
         ~ProviderInfo();
 
-        status_t initialize(sp<hardware::camera::provider::V2_4::ICameraProvider>& interface);
+        status_t initialize(sp<hardware::camera::provider::V2_4::ICameraProvider>& interface,
+                hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
+                    currentDeviceState);
 
         const sp<hardware::camera::provider::V2_4::ICameraProvider> startProviderInterface();
 
@@ -345,6 +359,13 @@
          */
         status_t setUpVendorTags();
 
+        /**
+         * Notify provider about top-level device physical state changes
+         */
+        status_t notifyDeviceStateChange(
+                hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
+                    newDeviceState);
+
         // Basic device information, common to all camera devices
         struct DeviceInfo {
             const std::string mName;  // Full instance name
@@ -494,6 +515,12 @@
                     std::vector<std::tuple<size_t, size_t>> *internalDepthSizes /*out*/);
             status_t removeAvailableKeys(CameraMetadata& c, const std::vector<uint32_t>& keys,
                     uint32_t keyTag);
+            status_t fillHeicStreamCombinations(std::vector<int32_t>* outputs,
+                    std::vector<int64_t>* durations,
+                    std::vector<int64_t>* stallDurations,
+                    const camera_metadata_entry& halStreamConfigs,
+                    const camera_metadata_entry& halStreamDurations);
+            status_t deriveHeicTags();
         };
 
     private:
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 82dfc0f..f9ef996 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -885,14 +885,14 @@
     return OK;
 }
 
-status_t Camera3Device::capture(CameraMetadata &request, int64_t* /*lastFrameNumber*/) {
+status_t Camera3Device::capture(CameraMetadata &request, int64_t* lastFrameNumber) {
     ATRACE_CALL();
 
     List<const PhysicalCameraSettingsList> requestsList;
     std::list<const SurfaceMap> surfaceMaps;
     convertToRequestList(requestsList, surfaceMaps, request);
 
-    return captureList(requestsList, surfaceMaps, /*lastFrameNumber*/NULL);
+    return captureList(requestsList, surfaceMaps, lastFrameNumber);
 }
 
 void Camera3Device::convertToRequestList(List<const PhysicalCameraSettingsList>& requestsList,
@@ -1027,11 +1027,22 @@
             return hardware::Void();
         }
 
+        if (outputStream->isAbandoned()) {
+            bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
+            allReqsSucceeds = false;
+            continue;
+        }
+
         bufRet.streamId = streamId;
+        size_t handOutBufferCount = outputStream->getOutstandingBuffersCount();
         uint32_t numBuffersRequested = bufReq.numBuffersRequested;
-        size_t totalHandout = outputStream->getOutstandingBuffersCount() + numBuffersRequested;
-        if (totalHandout > outputStream->asHalStream()->max_buffers) {
+        size_t totalHandout = handOutBufferCount + numBuffersRequested;
+        uint32_t maxBuffers = outputStream->asHalStream()->max_buffers;
+        if (totalHandout > maxBuffers) {
             // Not able to allocate enough buffer. Exit early for this stream
+            ALOGE("%s: request too much buffers for stream %d: at HAL: %zu + requesting: %d"
+                    " > max: %d", __FUNCTION__, streamId, handOutBufferCount,
+                    numBuffersRequested, maxBuffers);
             bufRet.val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
             allReqsSucceeds = false;
             continue;
@@ -1757,18 +1768,20 @@
 
     if (format == HAL_PIXEL_FORMAT_BLOB) {
         ssize_t blobBufferSize;
-        if (dataSpace != HAL_DATASPACE_DEPTH) {
-            blobBufferSize = getJpegBufferSize(width, height);
-            if (blobBufferSize <= 0) {
-                SET_ERR_L("Invalid jpeg buffer size %zd", blobBufferSize);
-                return BAD_VALUE;
-            }
-        } else {
+        if (dataSpace == HAL_DATASPACE_DEPTH) {
             blobBufferSize = getPointCloudBufferSize();
             if (blobBufferSize <= 0) {
                 SET_ERR_L("Invalid point cloud buffer size %zd", blobBufferSize);
                 return BAD_VALUE;
             }
+        } else if (dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_JPEG_APP_SEGMENTS)) {
+            blobBufferSize = width * height;
+        } else {
+            blobBufferSize = getJpegBufferSize(width, height);
+            if (blobBufferSize <= 0) {
+                SET_ERR_L("Invalid jpeg buffer size %zd", blobBufferSize);
+                return BAD_VALUE;
+            }
         }
         newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
                 width, height, blobBufferSize, format, dataSpace, rotation,
@@ -2184,12 +2197,11 @@
 
     mStatusWaiters++;
 
-    // Notify HAL to start draining. We need to notify the HalInterface layer
-    // even when the device is already IDLE, so HalInterface can reject incoming
-    // requestStreamBuffers call.
     if (!active && mUseHalBufManager) {
         auto streamIds = mOutputStreams.getStreamIds();
-        mRequestThread->signalPipelineDrain(streamIds);
+        if (mStatus == STATUS_ACTIVE) {
+            mRequestThread->signalPipelineDrain(streamIds);
+        }
         mRequestBufferSM.onWaitUntilIdle();
     }
 
@@ -3878,7 +3890,8 @@
             bool useHalBufManager) :
         mHidlSession(session),
         mRequestMetadataQueue(queue),
-        mUseHalBufManager(useHalBufManager) {
+        mUseHalBufManager(useHalBufManager),
+        mIsReconfigurationQuerySupported(true) {
     // Check with hardware service manager if we can downcast these interfaces
     // Somewhat expensive, so cache the results at startup
     auto castResult_3_5 = device::V3_5::ICameraDeviceSession::castFrom(mHidlSession);
@@ -3984,6 +3997,52 @@
     return res;
 }
 
+bool Camera3Device::HalInterface::isReconfigurationRequired(CameraMetadata& oldSessionParams,
+        CameraMetadata& newSessionParams) {
+    // We do reconfiguration by default;
+    bool ret = true;
+    if ((mHidlSession_3_5 != nullptr) && mIsReconfigurationQuerySupported) {
+        android::hardware::hidl_vec<uint8_t> oldParams, newParams;
+        camera_metadata_t* oldSessioMeta = const_cast<camera_metadata_t*>(
+                oldSessionParams.getAndLock());
+        camera_metadata_t* newSessioMeta = const_cast<camera_metadata_t*>(
+                newSessionParams.getAndLock());
+        oldParams.setToExternal(reinterpret_cast<uint8_t*>(oldSessioMeta),
+                get_camera_metadata_size(oldSessioMeta));
+        newParams.setToExternal(reinterpret_cast<uint8_t*>(newSessioMeta),
+                get_camera_metadata_size(newSessioMeta));
+        hardware::camera::common::V1_0::Status callStatus;
+        bool required;
+        auto hidlCb = [&callStatus, &required] (hardware::camera::common::V1_0::Status s,
+                bool requiredFlag) {
+            callStatus = s;
+            required = requiredFlag;
+        };
+        auto err = mHidlSession_3_5->isReconfigurationRequired(oldParams, newParams, hidlCb);
+        oldSessionParams.unlock(oldSessioMeta);
+        newSessionParams.unlock(newSessioMeta);
+        if (err.isOk()) {
+            switch (callStatus) {
+                case hardware::camera::common::V1_0::Status::OK:
+                    ret = required;
+                    break;
+                case hardware::camera::common::V1_0::Status::METHOD_NOT_SUPPORTED:
+                    mIsReconfigurationQuerySupported = false;
+                    ret = true;
+                    break;
+                default:
+                    ALOGV("%s: Reconfiguration query failed: %d", __FUNCTION__, callStatus);
+                    ret = true;
+            }
+        } else {
+            ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, err.description().c_str());
+            ret = true;
+        }
+    }
+
+    return ret;
+}
+
 status_t Camera3Device::HalInterface::configureStreams(const camera_metadata_t *sessionParams,
         camera3_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
     ATRACE_NAME("CameraHal::configureStreams");
@@ -5095,9 +5154,10 @@
     ATRACE_CALL();
     bool updatesDetected = false;
 
+    CameraMetadata updatedParams(mLatestSessionParams);
     for (auto tag : mSessionParamKeys) {
         camera_metadata_ro_entry entry = settings.find(tag);
-        camera_metadata_entry lastEntry = mLatestSessionParams.find(tag);
+        camera_metadata_entry lastEntry = updatedParams.find(tag);
 
         if (entry.count > 0) {
             bool isDifferent = false;
@@ -5126,17 +5186,26 @@
                 if (!skipHFRTargetFPSUpdate(tag, entry, lastEntry)) {
                     updatesDetected = true;
                 }
-                mLatestSessionParams.update(entry);
+                updatedParams.update(entry);
             }
         } else if (lastEntry.count > 0) {
             // Value has been removed
             ALOGV("%s: Session parameter tag id %d removed", __FUNCTION__, tag);
-            mLatestSessionParams.erase(tag);
+            updatedParams.erase(tag);
             updatesDetected = true;
         }
     }
 
-    return updatesDetected;
+    bool reconfigureRequired;
+    if (updatesDetected) {
+        reconfigureRequired = mInterface->isReconfigurationRequired(mLatestSessionParams,
+                updatedParams);
+        mLatestSessionParams = updatedParams;
+    } else {
+        reconfigureRequired = false;
+    }
+
+    return reconfigureRequired;
 }
 
 bool Camera3Device::RequestThread::threadLoop() {
@@ -5249,6 +5318,11 @@
     ALOGVV("%s: %d: submitting %zu requests in a batch.", __FUNCTION__, __LINE__,
             mNextRequests.size());
 
+    sp<Camera3Device> parent = mParent.promote();
+    if (parent != nullptr) {
+        parent->mRequestBufferSM.onSubmittingRequest();
+    }
+
     bool submitRequestSuccess = false;
     nsecs_t tRequestStart = systemTime(SYSTEM_TIME_MONOTONIC);
     if (mInterface->supportBatchRequest()) {
@@ -5259,13 +5333,6 @@
     nsecs_t tRequestEnd = systemTime(SYSTEM_TIME_MONOTONIC);
     mRequestLatency.add(tRequestStart, tRequestEnd);
 
-    if (submitRequestSuccess) {
-        sp<Camera3Device> parent = mParent.promote();
-        if (parent != nullptr) {
-            parent->mRequestBufferSM.onRequestSubmitted();
-        }
-    }
-
     if (useFlushLock) {
         mFlushLock.unlock();
     }
@@ -5473,8 +5540,22 @@
                     return TIMED_OUT;
                 }
             }
-            outputStream->fireBufferRequestForFrameNumber(
-                    captureRequest->mResultExtras.frameNumber);
+
+            {
+                sp<Camera3Device> parent = mParent.promote();
+                if (parent != nullptr) {
+                    const String8& streamCameraId = outputStream->getPhysicalCameraId();
+                    for (const auto& settings : captureRequest->mSettingsList) {
+                        if ((streamCameraId.isEmpty() &&
+                                parent->getId() == settings.cameraId.c_str()) ||
+                                streamCameraId == settings.cameraId.c_str()) {
+                            outputStream->fireBufferRequestForFrameNumber(
+                                    captureRequest->mResultExtras.frameNumber,
+                                    settings.metadata);
+                        }
+                    }
+                }
+            }
 
             String8 physicalCameraId = outputStream->getPhysicalCameraId();
 
@@ -6413,9 +6494,11 @@
     return;
 }
 
-void Camera3Device::RequestBufferStateMachine::onRequestSubmitted() {
+void Camera3Device::RequestBufferStateMachine::onSubmittingRequest() {
     std::lock_guard<std::mutex> lock(mLock);
     mRequestThreadPaused = false;
+    // inflight map register actually happens in prepareHalRequest now, but it is close enough
+    // approximation.
     mInflightMapEmpty = false;
     if (mStatus == RB_STATUS_STOPPED) {
         mStatus = RB_STATUS_READY;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index e5a38bb..b25d89d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -309,6 +309,8 @@
         status_t close();
 
         void signalPipelineDrain(const std::vector<int>& streamIds);
+        bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
+                CameraMetadata& newSessionParams);
 
         // method to extract buffer's unique ID
         // return pair of (newlySeenBuffer?, bufferId)
@@ -401,6 +403,7 @@
         uint32_t mNextStreamConfigCounter = 1;
 
         const bool mUseHalBufManager;
+        bool mIsReconfigurationQuerySupported;
     };
 
     sp<HalInterface> mInterface;
@@ -1317,7 +1320,7 @@
         void onInflightMapEmpty();
 
         // Events triggered by RequestThread
-        void onRequestSubmitted();
+        void onSubmittingRequest();
         void onRequestThreadPaused();
 
       private:
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index b296513..0571741 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -588,7 +588,11 @@
     if (mState != STATE_CONFIGURED) {
         ALOGE("%s: Stream %d: Can't get buffers if stream is not in CONFIGURED state %d",
                 __FUNCTION__, mId, mState);
-        return INVALID_OPERATION;
+        if (mState == STATE_ABANDONED) {
+            return DEAD_OBJECT;
+        } else {
+            return INVALID_OPERATION;
+        }
     }
 
     // Wait for new buffer returned back if we are running into the limit.
@@ -763,14 +767,15 @@
     return getInputBufferProducerLocked(producer);
 }
 
-void Camera3Stream::fireBufferRequestForFrameNumber(uint64_t frameNumber) {
+void Camera3Stream::fireBufferRequestForFrameNumber(uint64_t frameNumber,
+        const CameraMetadata& settings) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
 
     for (auto &it : mBufferListenerList) {
         sp<Camera3StreamBufferListener> listener = it.promote();
         if (listener.get() != nullptr) {
-            listener->onBufferRequestForFrameNumber(frameNumber, getId());
+            listener->onBufferRequestForFrameNumber(frameNumber, getId(), settings);
         }
     }
 }
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 06deba9..5eb6a23 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -434,7 +434,8 @@
     /**
      * Notify buffer stream listeners about incoming request with particular frame number.
      */
-    void fireBufferRequestForFrameNumber(uint64_t frameNumber) override;
+    void fireBufferRequestForFrameNumber(uint64_t frameNumber,
+            const CameraMetadata& settings) override;
 
   protected:
     const int mId;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h b/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
index 0e6104e..d0aee27 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_SERVERS_CAMERA3_STREAMBUFFERLISTENER_H
 #define ANDROID_SERVERS_CAMERA3_STREAMBUFFERLISTENER_H
 
+#include <camera/CameraMetadata.h>
 #include <gui/Surface.h>
 #include <utils/RefBase.h>
 
@@ -42,7 +43,8 @@
     // Buffer was released by the HAL
     virtual void onBufferReleased(const BufferInfo& bufferInfo) = 0;
     // Notify about incoming buffer request frame number
-    virtual void onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId) = 0;
+    virtual void onBufferRequestForFrameNumber(uint64_t frameNumber, int streamId,
+            const CameraMetadata& settings) = 0;
 };
 
 }; //namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 7b80cbd..5cd11b7 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -18,6 +18,8 @@
 #define ANDROID_SERVERS_CAMERA3_STREAM_INTERFACE_H
 
 #include <utils/RefBase.h>
+
+#include <camera/CameraMetadata.h>
 #include "Camera3StreamBufferListener.h"
 #include "Camera3StreamBufferFreedListener.h"
 
@@ -346,7 +348,8 @@
     /**
      * Notify buffer stream listeners about incoming request with particular frame number.
      */
-    virtual void fireBufferRequestForFrameNumber(uint64_t frameNumber) = 0;
+    virtual void fireBufferRequestForFrameNumber(uint64_t frameNumber,
+            const CameraMetadata& settings) = 0;
 };
 
 } // namespace camera3
diff --git a/services/camera/libcameraservice/tests/Android.mk b/services/camera/libcameraservice/tests/Android.mk
index ad9963a..d777ca1 100644
--- a/services/camera/libcameraservice/tests/Android.mk
+++ b/services/camera/libcameraservice/tests/Android.mk
@@ -29,6 +29,7 @@
     libutils \
     android.hardware.camera.common@1.0 \
     android.hardware.camera.provider@2.4 \
+    android.hardware.camera.provider@2.5 \
     android.hardware.camera.device@1.0 \
     android.hardware.camera.device@3.2 \
     android.hardware.camera.device@3.4
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index 0086c6c..f47e5a5 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -33,6 +33,7 @@
 using android::hardware::camera::common::V1_0::CameraMetadataType;
 using android::hardware::camera::device::V3_2::ICameraDeviceCallback;
 using android::hardware::camera::device::V3_2::ICameraDeviceSession;
+using android::hardware::camera::provider::V2_5::DeviceState;
 
 /**
  * Basic test implementation of a camera ver. 3.2 device interface
@@ -87,7 +88,7 @@
 /**
  * Basic test implementation of a camera provider
  */
-struct TestICameraProvider : virtual public provider::V2_4::ICameraProvider {
+struct TestICameraProvider : virtual public provider::V2_5::ICameraProvider {
     sp<provider::V2_4::ICameraProviderCallback> mCallbacks;
     std::vector<hardware::hidl_string> mDeviceNames;
     sp<device::V3_2::ICameraDevice> mDeviceInterface;
@@ -101,6 +102,7 @@
 
     virtual hardware::Return<Status> setCallback(
             const sp<provider::V2_4::ICameraProviderCallback>& callbacks) override {
+        mCalledCounter[SET_CALLBACK]++;
         mCallbacks = callbacks;
         return hardware::Return<Status>(Status::OK);
     }
@@ -108,6 +110,7 @@
     using getVendorTags_cb = std::function<void(Status status,
             const hardware::hidl_vec<common::V1_0::VendorTagSection>& sections)>;
     hardware::Return<void> getVendorTags(getVendorTags_cb _hidl_cb) override {
+        mCalledCounter[GET_VENDOR_TAGS]++;
         _hidl_cb(Status::OK, mVendorTagSections);
         return hardware::Void();
     }
@@ -117,6 +120,7 @@
              bool support)>;
     virtual ::hardware::Return<void> isSetTorchModeSupported(
             isSetTorchModeSupported_cb _hidl_cb) override {
+        mCalledCounter[IS_SET_TORCH_MODE_SUPPORTED]++;
         _hidl_cb(Status::OK, false);
         return hardware::Void();
     }
@@ -124,6 +128,7 @@
     using getCameraIdList_cb = std::function<void(Status status,
             const hardware::hidl_vec<hardware::hidl_string>& cameraDeviceNames)>;
     virtual hardware::Return<void> getCameraIdList(getCameraIdList_cb _hidl_cb) override {
+        mCalledCounter[GET_CAMERA_ID_LIST]++;
         _hidl_cb(Status::OK, mDeviceNames);
         return hardware::Void();
     }
@@ -148,6 +153,25 @@
         return hardware::Void();
     }
 
+    virtual hardware::Return<void> notifyDeviceStateChange(
+            hardware::hidl_bitfield<DeviceState> newState) override {
+        mCalledCounter[NOTIFY_DEVICE_STATE]++;
+        mCurrentState = newState;
+        return hardware::Void();
+    }
+
+    enum MethodNames {
+        SET_CALLBACK,
+        GET_VENDOR_TAGS,
+        IS_SET_TORCH_MODE_SUPPORTED,
+        NOTIFY_DEVICE_STATE,
+        GET_CAMERA_ID_LIST,
+
+        METHOD_NAME_COUNT
+    };
+    int mCalledCounter[METHOD_NAME_COUNT] {0};
+
+    hardware::hidl_bitfield<DeviceState> mCurrentState = 0xFFFFFFFF; // Unlikely to be a real state
 };
 
 /**
@@ -209,11 +233,26 @@
 
     res = providerManager->initialize(statusListener, &serviceProxy);
     ASSERT_EQ(res, OK) << "Unable to initialize provider manager";
+    // Check that both "legacy" and "external" providers (really the same object) are called
+    // once for all the init methods
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::SET_CALLBACK], 2) <<
+            "Only one call to setCallback per provider expected during init";
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_VENDOR_TAGS], 2) <<
+            "Only one call to getVendorTags per provider expected during init";
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::IS_SET_TORCH_MODE_SUPPORTED], 2) <<
+            "Only one call to isSetTorchModeSupported per provider expected during init";
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_CAMERA_ID_LIST], 2) <<
+            "Only one call to getCameraIdList per provider expected during init";
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::NOTIFY_DEVICE_STATE], 2) <<
+            "Only one call to notifyDeviceState per provider expected during init";
 
     std::string legacyInstanceName = "legacy/0";
     std::string externalInstanceName = "external/0";
     bool gotLegacy = false;
     bool gotExternal = false;
+    EXPECT_EQ(2u, serviceProxy.mLastRequestedServiceNames.size()) <<
+            "Only two service queries expected to be seen by hardware service manager";
+
     for (auto& serviceName : serviceProxy.mLastRequestedServiceNames) {
         if (serviceName == legacyInstanceName) gotLegacy = true;
         if (serviceName == externalInstanceName) gotExternal = true;
@@ -375,3 +414,35 @@
     metadataCopy.dump(1, 2);
     secondMetadata.dump(1, 2);
 }
+
+TEST(CameraProviderManagerTest, NotifyStateChangeTest) {
+    std::vector<hardware::hidl_string> deviceNames {
+        "device@3.2/test/0",
+        "device@1.0/test/0",
+        "device@3.2/test/1"};
+
+    hardware::hidl_vec<common::V1_0::VendorTagSection> vendorSection;
+    status_t res;
+    sp<CameraProviderManager> providerManager = new CameraProviderManager();
+    sp<TestStatusListener> statusListener = new TestStatusListener();
+    TestInteractionProxy serviceProxy;
+    sp<TestICameraProvider> provider =  new TestICameraProvider(deviceNames,
+            vendorSection);
+    serviceProxy.setProvider(provider);
+
+    res = providerManager->initialize(statusListener, &serviceProxy);
+    ASSERT_EQ(res, OK) << "Unable to initialize provider manager";
+
+    ASSERT_EQ(provider->mCurrentState,
+            static_cast<hardware::hidl_bitfield<DeviceState>>(DeviceState::NORMAL))
+            << "Initial device state not set";
+
+    res = providerManager->notifyDeviceStateChange(
+        static_cast<hardware::hidl_bitfield<DeviceState>>(DeviceState::FOLDED));
+
+    ASSERT_EQ(res, OK) << "Unable to call notifyDeviceStateChange";
+    ASSERT_EQ(provider->mCurrentState,
+            static_cast<hardware::hidl_bitfield<DeviceState>>(DeviceState::FOLDED))
+            << "Unable to change device state";
+
+}
diff --git a/services/camera/libcameraservice/utils/ExifUtils.cpp b/services/camera/libcameraservice/utils/ExifUtils.cpp
new file mode 100644
index 0000000..a4027cc
--- /dev/null
+++ b/services/camera/libcameraservice/utils/ExifUtils.cpp
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CameraServerExifUtils"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+
+#include <inttypes.h>
+#include <math.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "ExifUtils.h"
+
+extern "C" {
+#include <libexif/exif-data.h>
+}
+
+namespace std {
+
+template <>
+struct default_delete<ExifEntry> {
+    inline void operator()(ExifEntry* entry) const { exif_entry_unref(entry); }
+};
+
+}  // namespace std
+
+
+namespace android {
+namespace camera3 {
+
+
+class ExifUtilsImpl : public ExifUtils {
+public:
+    ExifUtilsImpl();
+
+    virtual ~ExifUtilsImpl();
+
+    // Initialize() can be called multiple times. The setting of Exif tags will be
+    // cleared.
+    virtual bool initialize(const unsigned char *app1Segment, size_t app1SegmentSize);
+
+    // set all known fields from a metadata structure
+    virtual bool setFromMetadata(const CameraMetadata& metadata,
+            const size_t imageWidth,
+            const size_t imageHeight);
+
+    // sets the len aperture.
+    // Returns false if memory allocation fails.
+    virtual bool setAperture(uint32_t numerator, uint32_t denominator);
+
+    // sets the value of brightness.
+    // Returns false if memory allocation fails.
+    virtual bool setBrightness(int32_t numerator, int32_t denominator);
+
+    // sets the color space.
+    // Returns false if memory allocation fails.
+    virtual bool setColorSpace(uint16_t color_space);
+
+    // sets the information to compressed data.
+    // Returns false if memory allocation fails.
+    virtual bool setComponentsConfiguration(const std::string& components_configuration);
+
+    // sets the compression scheme used for the image data.
+    // Returns false if memory allocation fails.
+    virtual bool setCompression(uint16_t compression);
+
+    // sets image contrast.
+    // Returns false if memory allocation fails.
+    virtual bool setContrast(uint16_t contrast);
+
+    // sets the date and time of image last modified. It takes local time. The
+    // name of the tag is DateTime in IFD0.
+    // Returns false if memory allocation fails.
+    virtual bool setDateTime(const struct tm& t);
+
+    // sets the image description.
+    // Returns false if memory allocation fails.
+    virtual bool setDescription(const std::string& description);
+
+    // sets the digital zoom ratio. If the numerator is 0, it means digital zoom
+    // was not used.
+    // Returns false if memory allocation fails.
+    virtual bool setDigitalZoomRatio(uint32_t numerator, uint32_t denominator);
+
+    // sets the exposure bias.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureBias(int32_t numerator, int32_t denominator);
+
+    // sets the exposure mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureMode(uint16_t exposure_mode);
+
+    // sets the program used by the camera to set exposure when the picture is
+    // taken.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureProgram(uint16_t exposure_program);
+
+    // sets the exposure time, given in seconds.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureTime(uint32_t numerator, uint32_t denominator);
+
+    // sets the status of flash.
+    // Returns false if memory allocation fails.
+    virtual bool setFlash(uint16_t flash);
+
+    // sets the F number.
+    // Returns false if memory allocation fails.
+    virtual bool setFNumber(uint32_t numerator, uint32_t denominator);
+
+    // sets the focal length of lens used to take the image in millimeters.
+    // Returns false if memory allocation fails.
+    virtual bool setFocalLength(uint32_t numerator, uint32_t denominator);
+
+    // sets the degree of overall image gain adjustment.
+    // Returns false if memory allocation fails.
+    virtual bool setGainControl(uint16_t gain_control);
+
+    // sets the altitude in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsAltitude(double altitude);
+
+    // sets the latitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLatitude(double latitude);
+
+    // sets the longitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLongitude(double longitude);
+
+    // sets GPS processing method.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsProcessingMethod(const std::string& method);
+
+    // sets GPS date stamp and time stamp (atomic clock). It takes UTC time.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsTimestamp(const struct tm& t);
+
+    // sets the length (number of rows) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageHeight(uint32_t length);
+
+    // sets the width (number of columes) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageWidth(uint32_t width);
+
+    // sets the ISO speed.
+    // Returns false if memory allocation fails.
+    virtual bool setIsoSpeedRating(uint16_t iso_speed_ratings);
+
+    // sets the kind of light source.
+    // Returns false if memory allocation fails.
+    virtual bool setLightSource(uint16_t light_source);
+
+    // sets the smallest F number of the lens.
+    // Returns false if memory allocation fails.
+    virtual bool setMaxAperture(uint32_t numerator, uint32_t denominator);
+
+    // sets the metering mode.
+    // Returns false if memory allocation fails.
+    virtual bool setMeteringMode(uint16_t metering_mode);
+
+    // sets image orientation.
+    // Returns false if memory allocation fails.
+    virtual bool setOrientation(uint16_t orientation);
+
+    // sets the unit for measuring XResolution and YResolution.
+    // Returns false if memory allocation fails.
+    virtual bool setResolutionUnit(uint16_t resolution_unit);
+
+    // sets image saturation.
+    // Returns false if memory allocation fails.
+    virtual bool setSaturation(uint16_t saturation);
+
+    // sets the type of scene that was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setSceneCaptureType(uint16_t type);
+
+    // sets image sharpness.
+    // Returns false if memory allocation fails.
+    virtual bool setSharpness(uint16_t sharpness);
+
+    // sets the shutter speed.
+    // Returns false if memory allocation fails.
+    virtual bool setShutterSpeed(int32_t numerator, int32_t denominator);
+
+    // sets the distance to the subject, given in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setSubjectDistance(uint32_t numerator, uint32_t denominator);
+
+    // sets the fractions of seconds for the <DateTime> tag.
+    // Returns false if memory allocation fails.
+    virtual bool setSubsecTime(const std::string& subsec_time);
+
+    // sets the white balance mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setWhiteBalance(uint16_t white_balance);
+
+    // sets the number of pixels per resolution unit in the image width.
+    // Returns false if memory allocation fails.
+    virtual bool setXResolution(uint32_t numerator, uint32_t denominator);
+
+    // sets the position of chrominance components in relation to the luminance
+    // component.
+    // Returns false if memory allocation fails.
+    virtual bool setYCbCrPositioning(uint16_t ycbcr_positioning);
+
+    // sets the number of pixels per resolution unit in the image length.
+    // Returns false if memory allocation fails.
+    virtual bool setYResolution(uint32_t numerator, uint32_t denominator);
+
+    // sets the manufacturer of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setMake(const std::string& make);
+
+    // sets the model number of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setModel(const std::string& model);
+
+    // Generates APP1 segment.
+    // Returns false if generating APP1 segment fails.
+    virtual bool generateApp1();
+
+    // Gets buffer of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual const uint8_t* getApp1Buffer();
+
+    // Gets length of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual unsigned int getApp1Length();
+
+  protected:
+    // sets the version of this standard supported.
+    // Returns false if memory allocation fails.
+    virtual bool setExifVersion(const std::string& exif_version);
+
+    // Resets the pointers and memories.
+    virtual void reset();
+
+    // Adds a variable length tag to |exif_data_|. It will remove the original one
+    // if the tag exists.
+    // Returns the entry of the tag. The reference count of returned ExifEntry is
+    // two.
+    virtual std::unique_ptr<ExifEntry> addVariableLengthEntry(ExifIfd ifd,
+            ExifTag tag, ExifFormat format, uint64_t components, unsigned int size);
+
+    // Adds a entry of |tag| in |exif_data_|. It won't remove the original one if
+    // the tag exists.
+    // Returns the entry of the tag. It adds one reference count to returned
+    // ExifEntry.
+    virtual std::unique_ptr<ExifEntry> addEntry(ExifIfd ifd, ExifTag tag);
+
+    // Helpe functions to add exif data with different types.
+    virtual bool setShort(ExifIfd ifd, ExifTag tag, uint16_t value, const std::string& msg);
+
+    virtual bool setLong(ExifIfd ifd, ExifTag tag, uint32_t value, const std::string& msg);
+
+    virtual bool setRational(ExifIfd ifd, ExifTag tag, uint32_t numerator,
+            uint32_t denominator, const std::string& msg);
+
+    virtual bool setSRational(ExifIfd ifd, ExifTag tag, int32_t numerator,
+            int32_t denominator, const std::string& msg);
+
+    virtual bool setString(ExifIfd ifd, ExifTag tag, ExifFormat format,
+            const std::string& buffer, const std::string& msg);
+
+    // Destroys the buffer of APP1 segment if exists.
+    virtual void destroyApp1();
+
+    // The Exif data (APP1). Owned by this class.
+    ExifData* exif_data_;
+    // The raw data of APP1 segment. It's allocated by ExifMem in |exif_data_| but
+    // owned by this class.
+    uint8_t* app1_buffer_;
+    // The length of |app1_buffer_|.
+    unsigned int app1_length_;
+
+};
+
+#define SET_SHORT(ifd, tag, value)                      \
+    do {                                                \
+        if (setShort(ifd, tag, value, #tag) == false)   \
+            return false;                               \
+    } while (0);
+
+#define SET_LONG(ifd, tag, value)                       \
+    do {                                                \
+        if (setLong(ifd, tag, value, #tag) == false)    \
+            return false;                               \
+    } while (0);
+
+#define SET_RATIONAL(ifd, tag, numerator, denominator)                      \
+    do {                                                                    \
+        if (setRational(ifd, tag, numerator, denominator, #tag) == false)   \
+            return false;                                                   \
+    } while (0);
+
+#define SET_SRATIONAL(ifd, tag, numerator, denominator)                       \
+    do {                                                                      \
+        if (setSRational(ifd, tag, numerator, denominator, #tag) == false)    \
+            return false;                                                     \
+    } while (0);
+
+#define SET_STRING(ifd, tag, format, buffer)                                  \
+    do {                                                                      \
+        if (setString(ifd, tag, format, buffer, #tag) == false)               \
+            return false;                                                     \
+    } while (0);
+
+// This comes from the Exif Version 2.2 standard table 6.
+const char gExifAsciiPrefix[] = {0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0};
+
+static void setLatitudeOrLongitudeData(unsigned char* data, double num) {
+    // Take the integer part of |num|.
+    ExifLong degrees = static_cast<ExifLong>(num);
+    ExifLong minutes = static_cast<ExifLong>(60 * (num - degrees));
+    ExifLong microseconds =
+            static_cast<ExifLong>(3600000000u * (num - degrees - minutes / 60.0));
+    exif_set_rational(data, EXIF_BYTE_ORDER_INTEL, {degrees, 1});
+    exif_set_rational(data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL, {minutes, 1});
+    exif_set_rational(data + 2 * sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+            {microseconds, 1000000});
+}
+
+ExifUtils *ExifUtils::create() {
+    return new ExifUtilsImpl();
+}
+
+ExifUtils::~ExifUtils() {
+}
+
+ExifUtilsImpl::ExifUtilsImpl()
+        : exif_data_(nullptr), app1_buffer_(nullptr), app1_length_(0) {}
+
+ExifUtilsImpl::~ExifUtilsImpl() {
+    reset();
+}
+
+
+bool ExifUtilsImpl::initialize(const unsigned char *app1Segment, size_t app1SegmentSize) {
+    reset();
+    exif_data_ = exif_data_new_from_data(app1Segment, app1SegmentSize);
+    if (exif_data_ == nullptr) {
+        ALOGE("%s: allocate memory for exif_data_ failed", __FUNCTION__);
+        return false;
+    }
+    // set the image options.
+    exif_data_set_option(exif_data_, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
+    exif_data_set_data_type(exif_data_, EXIF_DATA_TYPE_COMPRESSED);
+    exif_data_set_byte_order(exif_data_, EXIF_BYTE_ORDER_INTEL);
+
+    // set exif version to 2.2.
+    if (!setExifVersion("0220")) {
+        return false;
+    }
+
+    return true;
+}
+
+bool ExifUtilsImpl::setAperture(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_APERTURE_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setBrightness(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_BRIGHTNESS_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setColorSpace(uint16_t color_space) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_COLOR_SPACE, color_space);
+    return true;
+}
+
+bool ExifUtilsImpl::setComponentsConfiguration(
+        const std::string& components_configuration) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_COMPONENTS_CONFIGURATION,
+            EXIF_FORMAT_UNDEFINED, components_configuration);
+    return true;
+}
+
+bool ExifUtilsImpl::setCompression(uint16_t compression) {
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_COMPRESSION, compression);
+    return true;
+}
+
+bool ExifUtilsImpl::setContrast(uint16_t contrast) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_CONTRAST, contrast);
+    return true;
+}
+
+bool ExifUtilsImpl::setDateTime(const struct tm& t) {
+    // The length is 20 bytes including NULL for termination in Exif standard.
+    char str[20];
+    int result = snprintf(str, sizeof(str), "%04i:%02i:%02i %02i:%02i:%02i",
+            t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+    if (result != sizeof(str) - 1) {
+        ALOGW("%s: Input time is invalid", __FUNCTION__);
+        return false;
+    }
+    std::string buffer(str);
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, buffer);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII, buffer);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_FORMAT_ASCII, buffer);
+    return true;
+}
+
+bool ExifUtilsImpl::setDescription(const std::string& description) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION, EXIF_FORMAT_ASCII, description);
+    return true;
+}
+
+bool ExifUtilsImpl::setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_DIGITAL_ZOOM_RATIO, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureBias(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_BIAS_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureMode(uint16_t exposure_mode) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_MODE, exposure_mode);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureProgram(uint16_t exposure_program) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_PROGRAM, exposure_program);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureTime(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setFlash(uint16_t flash) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_FLASH, flash);
+    return true;
+}
+
+bool ExifUtilsImpl::setFNumber(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setFocalLength(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setGainControl(uint16_t gain_control) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_GAIN_CONTROL, gain_control);
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsAltitude(double altitude) {
+    ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_BYTE, 1, 1);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSAltitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (altitude >= 0) {
+        *refEntry->data = 0;
+    } else {
+        *refEntry->data = 1;
+        altitude *= -1;
+    }
+
+    ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 1, sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSAltitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
+            {static_cast<ExifLong>(altitude * 1000), 1000});
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsLatitude(double latitude) {
+    const ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSLatitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (latitude >= 0) {
+        memcpy(refEntry->data, "N", sizeof("N"));
+    } else {
+        memcpy(refEntry->data, "S", sizeof("S"));
+        latitude *= -1;
+    }
+
+    const ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSLatitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    setLatitudeOrLongitudeData(entry->data, latitude);
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsLongitude(double longitude) {
+    ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSLongitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (longitude >= 0) {
+        memcpy(refEntry->data, "E", sizeof("E"));
+    } else {
+        memcpy(refEntry->data, "W", sizeof("W"));
+        longitude *= -1;
+    }
+
+    ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSLongitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    setLatitudeOrLongitudeData(entry->data, longitude);
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsProcessingMethod(const std::string& method) {
+    std::string buffer =
+            std::string(gExifAsciiPrefix, sizeof(gExifAsciiPrefix)) + method;
+    SET_STRING(EXIF_IFD_GPS, static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD),
+            EXIF_FORMAT_UNDEFINED, buffer);
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsTimestamp(const struct tm& t) {
+    const ExifTag dateTag = static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP);
+    const size_t kGpsDateStampSize = 11;
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(EXIF_IFD_GPS,
+            dateTag, EXIF_FORMAT_ASCII, kGpsDateStampSize, kGpsDateStampSize);
+    if (!entry) {
+        ALOGE("%s: Adding GPSDateStamp exif entry failed", __FUNCTION__);
+        return false;
+    }
+    int result = snprintf(reinterpret_cast<char*>(entry->data), kGpsDateStampSize,
+            "%04i:%02i:%02i", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
+    if (result != kGpsDateStampSize - 1) {
+        ALOGW("%s: Input time is invalid", __FUNCTION__);
+        return false;
+    }
+
+    const ExifTag timeTag = static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP);
+    entry = addVariableLengthEntry(EXIF_IFD_GPS, timeTag, EXIF_FORMAT_RATIONAL, 3,
+            3 * sizeof(ExifRational));
+    if (!entry) {
+        ALOGE("%s: Adding GPSTimeStamp exif entry failed", __FUNCTION__);
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
+            {static_cast<ExifLong>(t.tm_hour), 1});
+    exif_set_rational(entry->data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+            {static_cast<ExifLong>(t.tm_min), 1});
+    exif_set_rational(entry->data + 2 * sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+            {static_cast<ExifLong>(t.tm_sec), 1});
+
+    return true;
+}
+
+bool ExifUtilsImpl::setImageHeight(uint32_t length) {
+    SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, length);
+    SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, length);
+    return true;
+}
+
+bool ExifUtilsImpl::setImageWidth(uint32_t width) {
+    SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
+    SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, width);
+    return true;
+}
+
+bool ExifUtilsImpl::setIsoSpeedRating(uint16_t iso_speed_ratings) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, iso_speed_ratings);
+    return true;
+}
+
+bool ExifUtilsImpl::setLightSource(uint16_t light_source) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_LIGHT_SOURCE, light_source);
+    return true;
+}
+
+bool ExifUtilsImpl::setMaxAperture(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_MAX_APERTURE_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setMeteringMode(uint16_t metering_mode) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_METERING_MODE, metering_mode);
+    return true;
+}
+
+bool ExifUtilsImpl::setOrientation(uint16_t orientation) {
+    /*
+     * Orientation value:
+     *  1      2      3      4      5          6          7          8
+     *
+     *  888888 888888     88 88     8888888888 88                 88 8888888888
+     *  88         88     88 88     88  88     88  88         88  88     88  88
+     *  8888     8888   8888 8888   88         8888888888 8888888888         88
+     *  88         88     88 88
+     *  88         88 888888 888888
+     */
+    int value = 1;
+    switch (orientation) {
+        case 90:
+            value = 6;
+            break;
+        case 180:
+            value = 3;
+            break;
+        case 270:
+            value = 8;
+            break;
+        default:
+            break;
+    }
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_ORIENTATION, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setResolutionUnit(uint16_t resolution_unit) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_RESOLUTION_UNIT, resolution_unit);
+    return true;
+}
+
+bool ExifUtilsImpl::setSaturation(uint16_t saturation) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SATURATION, saturation);
+    return true;
+}
+
+bool ExifUtilsImpl::setSceneCaptureType(uint16_t type) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SCENE_CAPTURE_TYPE, type);
+    return true;
+}
+
+bool ExifUtilsImpl::setSharpness(uint16_t sharpness) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SHARPNESS, sharpness);
+    return true;
+}
+
+bool ExifUtilsImpl::setShutterSpeed(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SHUTTER_SPEED_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setSubjectDistance(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SUBJECT_DISTANCE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setSubsecTime(const std::string& subsec_time) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, EXIF_FORMAT_ASCII, subsec_time);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_FORMAT_ASCII, subsec_time);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_FORMAT_ASCII, subsec_time);
+    return true;
+}
+
+bool ExifUtilsImpl::setWhiteBalance(uint16_t white_balance) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, white_balance);
+    return true;
+}
+
+bool ExifUtilsImpl::setXResolution(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_X_RESOLUTION, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setYCbCrPositioning(uint16_t ycbcr_positioning) {
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_YCBCR_POSITIONING, ycbcr_positioning);
+    return true;
+}
+
+bool ExifUtilsImpl::setYResolution(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_Y_RESOLUTION, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::generateApp1() {
+    destroyApp1();
+    // Save the result into |app1_buffer_|.
+    exif_data_save_data(exif_data_, &app1_buffer_, &app1_length_);
+    if (!app1_length_) {
+        ALOGE("%s: Allocate memory for app1_buffer_ failed", __FUNCTION__);
+        return false;
+    }
+    /*
+     * The JPEG segment size is 16 bits in spec. The size of APP1 segment should
+     * be smaller than 65533 because there are two bytes for segment size field.
+     */
+    if (app1_length_ > 65533) {
+        destroyApp1();
+        ALOGE("%s: The size of APP1 segment is too large", __FUNCTION__);
+        return false;
+    }
+    return true;
+}
+
+const uint8_t* ExifUtilsImpl::getApp1Buffer() {
+    return app1_buffer_;
+}
+
+unsigned int ExifUtilsImpl::getApp1Length() {
+    return app1_length_;
+}
+
+bool ExifUtilsImpl::setExifVersion(const std::string& exif_version) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_EXIF_VERSION, EXIF_FORMAT_UNDEFINED, exif_version);
+    return true;
+}
+
+bool ExifUtilsImpl::setMake(const std::string& make) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_MAKE, EXIF_FORMAT_ASCII, make);
+    return true;
+}
+
+bool ExifUtilsImpl::setModel(const std::string& model) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_MODEL, EXIF_FORMAT_ASCII, model);
+    return true;
+}
+
+void ExifUtilsImpl::reset() {
+    destroyApp1();
+    if (exif_data_) {
+        /*
+         * Since we decided to ignore the original APP1, we are sure that there is
+         * no thumbnail allocated by libexif. |exif_data_->data| is actually
+         * allocated by JpegCompressor. sets |exif_data_->data| to nullptr to
+         * prevent exif_data_unref() destroy it incorrectly.
+         */
+        exif_data_->data = nullptr;
+        exif_data_->size = 0;
+        exif_data_unref(exif_data_);
+        exif_data_ = nullptr;
+    }
+}
+
+std::unique_ptr<ExifEntry> ExifUtilsImpl::addVariableLengthEntry(ExifIfd ifd,
+        ExifTag tag, ExifFormat format, uint64_t components, unsigned int size) {
+    // Remove old entry if exists.
+    exif_content_remove_entry(exif_data_->ifd[ifd],
+            exif_content_get_entry(exif_data_->ifd[ifd], tag));
+    ExifMem* mem = exif_mem_new_default();
+    if (!mem) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        return nullptr;
+    }
+    std::unique_ptr<ExifEntry> entry(exif_entry_new_mem(mem));
+    if (!entry) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        exif_mem_unref(mem);
+        return nullptr;
+    }
+    void* tmpBuffer = exif_mem_alloc(mem, size);
+    if (!tmpBuffer) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        exif_mem_unref(mem);
+        return nullptr;
+    }
+
+    entry->data = static_cast<unsigned char*>(tmpBuffer);
+    entry->tag = tag;
+    entry->format = format;
+    entry->components = components;
+    entry->size = size;
+
+    exif_content_add_entry(exif_data_->ifd[ifd], entry.get());
+    exif_mem_unref(mem);
+
+    return entry;
+}
+
+std::unique_ptr<ExifEntry> ExifUtilsImpl::addEntry(ExifIfd ifd, ExifTag tag) {
+    std::unique_ptr<ExifEntry> entry(exif_content_get_entry(exif_data_->ifd[ifd], tag));
+    if (entry) {
+        // exif_content_get_entry() won't ref the entry, so we ref here.
+        exif_entry_ref(entry.get());
+        return entry;
+    }
+    entry.reset(exif_entry_new());
+    if (!entry) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        return nullptr;
+    }
+    entry->tag = tag;
+    exif_content_add_entry(exif_data_->ifd[ifd], entry.get());
+    exif_entry_initialize(entry.get(), tag);
+    return entry;
+}
+
+bool ExifUtilsImpl::setShort(ExifIfd ifd, ExifTag tag, uint16_t value, const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_short(entry->data, EXIF_BYTE_ORDER_INTEL, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setLong(ExifIfd ifd, ExifTag tag, uint32_t value, const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_long(entry->data, EXIF_BYTE_ORDER_INTEL, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setRational(ExifIfd ifd, ExifTag tag, uint32_t numerator,
+        uint32_t denominator, const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, {numerator, denominator});
+    return true;
+}
+
+bool ExifUtilsImpl::setSRational(ExifIfd ifd, ExifTag tag, int32_t numerator,
+        int32_t denominator, const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_srational(entry->data, EXIF_BYTE_ORDER_INTEL, {numerator, denominator});
+    return true;
+}
+
+bool ExifUtilsImpl::setString(ExifIfd ifd, ExifTag tag, ExifFormat format,
+        const std::string& buffer, const std::string& msg) {
+    size_t entry_size = buffer.length();
+    // Since the exif format is undefined, NULL termination is not necessary.
+    if (format == EXIF_FORMAT_ASCII) {
+        entry_size++;
+    }
+    std::unique_ptr<ExifEntry> entry =
+            addVariableLengthEntry(ifd, tag, format, entry_size, entry_size);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    memcpy(entry->data, buffer.c_str(), entry_size);
+    return true;
+}
+
+void ExifUtilsImpl::destroyApp1() {
+    /*
+     * Since there is no API to access ExifMem in ExifData->priv, we use free
+     * here, which is the default free function in libexif. See
+     * exif_data_save_data() for detail.
+     */
+    free(app1_buffer_);
+    app1_buffer_ = nullptr;
+    app1_length_ = 0;
+}
+
+bool ExifUtilsImpl::setFromMetadata(const CameraMetadata& metadata,
+        const size_t imageWidth, const size_t imageHeight) {
+    // How precise the float-to-rational conversion for EXIF tags would be.
+    constexpr int kRationalPrecision = 10000;
+    if (!setImageWidth(imageWidth) ||
+            !setImageHeight(imageHeight)) {
+        ALOGE("%s: setting image resolution failed.", __FUNCTION__);
+        return false;
+    }
+
+    struct timespec tp;
+    struct tm time_info;
+    bool time_available = clock_gettime(CLOCK_REALTIME, &tp) != -1;
+    localtime_r(&tp.tv_sec, &time_info);
+    if (!setDateTime(time_info)) {
+        ALOGE("%s: setting data time failed.", __FUNCTION__);
+        return false;
+    }
+
+    float focal_length;
+    camera_metadata_ro_entry entry = metadata.find(ANDROID_LENS_FOCAL_LENGTH);
+    if (entry.count) {
+        focal_length = entry.data.f[0];
+
+        if (!setFocalLength(
+                static_cast<uint32_t>(focal_length * kRationalPrecision), kRationalPrecision)) {
+            ALOGE("%s: setting focal length failed.", __FUNCTION__);
+            return false;
+        }
+    } else {
+        ALOGV("%s: Cannot find focal length in metadata.", __FUNCTION__);
+    }
+
+    if (metadata.exists(ANDROID_JPEG_GPS_COORDINATES)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_COORDINATES);
+        if (entry.count < 3) {
+            ALOGE("%s: Gps coordinates in metadata is not complete.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsLatitude(entry.data.d[0])) {
+            ALOGE("%s: setting gps latitude failed.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsLongitude(entry.data.d[1])) {
+            ALOGE("%s: setting gps longitude failed.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsAltitude(entry.data.d[2])) {
+            ALOGE("%s: setting gps altitude failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_JPEG_GPS_PROCESSING_METHOD)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_PROCESSING_METHOD);
+        std::string method_str(reinterpret_cast<const char*>(entry.data.u8));
+        if (!setGpsProcessingMethod(method_str)) {
+            ALOGE("%s: setting gps processing method failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (time_available && metadata.exists(ANDROID_JPEG_GPS_TIMESTAMP)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_TIMESTAMP);
+        time_t timestamp = static_cast<time_t>(entry.data.i64[0]);
+        if (gmtime_r(&timestamp, &time_info)) {
+            if (!setGpsTimestamp(time_info)) {
+                ALOGE("%s: setting gps timestamp failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Time tranformation failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_JPEG_ORIENTATION)) {
+        entry = metadata.find(ANDROID_JPEG_ORIENTATION);
+        if (!setOrientation(entry.data.i32[0])) {
+            ALOGE("%s: setting orientation failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
+        entry = metadata.find(ANDROID_SENSOR_EXPOSURE_TIME);
+        // int64_t of nanoseconds
+        if (!setExposureTime(entry.data.i64[0],1000000000u)) {
+            ALOGE("%s: setting exposure time failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_LENS_APERTURE)) {
+        const int kAperturePrecision = 10000;
+        entry = metadata.find(ANDROID_LENS_APERTURE);
+        if (!setFNumber(entry.data.f[0] * kAperturePrecision, kAperturePrecision)) {
+            ALOGE("%s: setting F number failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_FLASH_INFO_AVAILABLE)) {
+        entry = metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
+        if (entry.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_FALSE) {
+            const uint32_t kNoFlashFunction = 0x20;
+            if (!setFlash(kNoFlashFunction)) {
+                ALOGE("%s: setting flash failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Unsupported flash info: %d",__FUNCTION__, entry.data.u8[0]);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_CONTROL_AWB_MODE)) {
+        entry = metadata.find(ANDROID_CONTROL_AWB_MODE);
+        if (entry.data.u8[0] == ANDROID_CONTROL_AWB_MODE_AUTO) {
+            const uint16_t kAutoWhiteBalance = 0;
+            if (!setWhiteBalance(kAutoWhiteBalance)) {
+                ALOGE("%s: setting white balance failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Unsupported awb mode: %d", __FUNCTION__, entry.data.u8[0]);
+            return false;
+        }
+    }
+
+    if (time_available) {
+        char str[4];
+        if (snprintf(str, sizeof(str), "%03ld", tp.tv_nsec / 1000000) < 0) {
+            ALOGE("%s: Subsec is invalid: %ld", __FUNCTION__, tp.tv_nsec);
+            return false;
+        }
+        if (!setSubsecTime(std::string(str))) {
+            ALOGE("%s: setting subsec time failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+} // namespace camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/utils/ExifUtils.h b/services/camera/libcameraservice/utils/ExifUtils.h
new file mode 100644
index 0000000..8ccdd8f
--- /dev/null
+++ b/services/camera/libcameraservice/utils/ExifUtils.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_EXIF_UTILS_H
+#define ANDROID_SERVERS_CAMERA_EXIF_UTILS_H
+
+#include "CameraMetadata.h"
+
+namespace android {
+namespace camera3 {
+
+// This is based on the camera HIDL shim implementation, which was in turned
+// based on original ChromeOS ARC implementation of a V4L2 HAL
+
+// ExifUtils can override APP1 segment with tags which caller set. ExifUtils can
+// also add a thumbnail in the APP1 segment if thumbnail size is specified.
+// ExifUtils can be reused with different images by calling initialize().
+//
+// Example of using this class :
+//  std::unique_ptr<ExifUtils> utils(ExifUtils::Create());
+//  utils->initialize(const unsigned char* app1Segment, size_t app1SegmentSize);
+//  ...
+//  // Call ExifUtils functions to set Exif tags.
+//  ...
+//  utils->GenerateApp1();
+//  unsigned int app1Length = utils->GetApp1Length();
+//  uint8_t* app1Buffer = new uint8_t[app1Length];
+//  memcpy(app1Buffer, utils->GetApp1Buffer(), app1Length);
+class ExifUtils {
+
+public:
+    virtual ~ExifUtils();
+
+    static ExifUtils* create();
+
+    // Initialize() can be called multiple times. The setting of Exif tags will be
+    // cleared.
+    virtual bool initialize(const unsigned char *app1Segment, size_t app1SegmentSize) = 0;
+
+    // Set all known fields from a metadata structure
+    virtual bool setFromMetadata(const CameraMetadata& metadata,
+            const size_t imageWidth, const size_t imageHeight) = 0;
+
+    // Sets the len aperture.
+    // Returns false if memory allocation fails.
+    virtual bool setAperture(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the value of brightness.
+    // Returns false if memory allocation fails.
+    virtual bool setBrightness(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the color space.
+    // Returns false if memory allocation fails.
+    virtual bool setColorSpace(uint16_t color_space) = 0;
+
+    // Sets the information to compressed data.
+    // Returns false if memory allocation fails.
+    virtual bool setComponentsConfiguration(const std::string& components_configuration) = 0;
+
+    // Sets the compression scheme used for the image data.
+    // Returns false if memory allocation fails.
+    virtual bool setCompression(uint16_t compression) = 0;
+
+    // Sets image contrast.
+    // Returns false if memory allocation fails.
+    virtual bool setContrast(uint16_t contrast) = 0;
+
+    // Sets the date and time of image last modified. It takes local time. The
+    // name of the tag is DateTime in IFD0.
+    // Returns false if memory allocation fails.
+    virtual bool setDateTime(const struct tm& t) = 0;
+
+    // Sets the image description.
+    // Returns false if memory allocation fails.
+    virtual bool setDescription(const std::string& description) = 0;
+
+    // Sets the digital zoom ratio. If the numerator is 0, it means digital zoom
+    // was not used.
+    // Returns false if memory allocation fails.
+    virtual bool setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the exposure bias.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureBias(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the exposure mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureMode(uint16_t exposure_mode) = 0;
+
+    // Sets the program used by the camera to set exposure when the picture is
+    // taken.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureProgram(uint16_t exposure_program) = 0;
+
+    // Sets the exposure time, given in seconds.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureTime(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the status of flash.
+    // Returns false if memory allocation fails.
+    virtual bool setFlash(uint16_t flash) = 0;
+
+    // Sets the F number.
+    // Returns false if memory allocation fails.
+    virtual bool setFNumber(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the focal length of lens used to take the image in millimeters.
+    // Returns false if memory allocation fails.
+    virtual bool setFocalLength(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the degree of overall image gain adjustment.
+    // Returns false if memory allocation fails.
+    virtual bool setGainControl(uint16_t gain_control) = 0;
+
+    // Sets the altitude in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsAltitude(double altitude) = 0;
+
+    // Sets the latitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLatitude(double latitude) = 0;
+
+    // Sets the longitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLongitude(double longitude) = 0;
+
+    // Sets GPS processing method.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsProcessingMethod(const std::string& method) = 0;
+
+    // Sets GPS date stamp and time stamp (atomic clock). It takes UTC time.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsTimestamp(const struct tm& t) = 0;
+
+    // Sets the height (number of rows) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageHeight(uint32_t length) = 0;
+
+    // Sets the width (number of columns) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageWidth(uint32_t width) = 0;
+
+    // Sets the ISO speed.
+    // Returns false if memory allocation fails.
+    virtual bool setIsoSpeedRating(uint16_t iso_speed_ratings) = 0;
+
+    // Sets the kind of light source.
+    // Returns false if memory allocation fails.
+    virtual bool setLightSource(uint16_t light_source) = 0;
+
+    // Sets the smallest F number of the lens.
+    // Returns false if memory allocation fails.
+    virtual bool setMaxAperture(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the metering mode.
+    // Returns false if memory allocation fails.
+    virtual bool setMeteringMode(uint16_t metering_mode) = 0;
+
+    // Sets image orientation.
+    // Returns false if memory allocation fails.
+    virtual bool setOrientation(uint16_t orientation) = 0;
+
+    // Sets the unit for measuring XResolution and YResolution.
+    // Returns false if memory allocation fails.
+    virtual bool setResolutionUnit(uint16_t resolution_unit) = 0;
+
+    // Sets image saturation.
+    // Returns false if memory allocation fails.
+    virtual bool setSaturation(uint16_t saturation) = 0;
+
+    // Sets the type of scene that was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setSceneCaptureType(uint16_t type) = 0;
+
+    // Sets image sharpness.
+    // Returns false if memory allocation fails.
+    virtual bool setSharpness(uint16_t sharpness) = 0;
+
+    // Sets the shutter speed.
+    // Returns false if memory allocation fails.
+    virtual bool setShutterSpeed(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the distance to the subject, given in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setSubjectDistance(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the fractions of seconds for the <DateTime> tag.
+    // Returns false if memory allocation fails.
+    virtual bool setSubsecTime(const std::string& subsec_time) = 0;
+
+    // Sets the white balance mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setWhiteBalance(uint16_t white_balance) = 0;
+
+    // Sets the number of pixels per resolution unit in the image width.
+    // Returns false if memory allocation fails.
+    virtual bool setXResolution(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the position of chrominance components in relation to the luminance
+    // component.
+    // Returns false if memory allocation fails.
+    virtual bool setYCbCrPositioning(uint16_t ycbcr_positioning) = 0;
+
+    // Sets the number of pixels per resolution unit in the image length.
+    // Returns false if memory allocation fails.
+    virtual bool setYResolution(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the manufacturer of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setMake(const std::string& make) = 0;
+
+    // Sets the model number of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setModel(const std::string& model) = 0;
+
+    // Generates APP1 segment.
+    // Returns false if generating APP1 segment fails.
+    virtual bool generateApp1() = 0;
+
+    // Gets buffer of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual const uint8_t* getApp1Buffer() = 0;
+
+    // Gets length of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual unsigned int getApp1Length() = 0;
+};
+
+} // namespace camera3
+} // namespace android
+
+#endif  // ANDROID_SERVERS_CAMERA_EXIF_UTILS_H
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index 9bdd4c8..3870a11 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -58,8 +58,4 @@
 getdents64: 1
 getrandom: 1
 
-# Used by UBSan diagnostic messages
-readlink: 1
-open: 1
-
 @include /system/etc/seccomp_policy/crash_dump.arm.policy
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86.policy b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
index a1ef16f..845f84b 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-x86.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
@@ -67,8 +67,4 @@
 getpid: 1
 gettid: 1
 
-# Used by UBSan diagnostic messages
-readlink: 1
-open: 1
-
 @include /system/etc/seccomp_policy/crash_dump.x86.policy