Merge "WiFi: Add VTS for Wifi HAL V1.2"
diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
index b9f505d..bf8b547 100644
--- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
+++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
@@ -90,13 +90,15 @@
 #define EVENT_NUMBER_OF_COMPLETED_PACKETS_NUM_HANDLES 2
 
 #define ACL_BROADCAST_FLAG_OFFSET 6
-#define ACL_BROADCAST_FLAG_ACTIVE_SLAVE 0x1
-#define ACL_BROADCAST_ACTIVE_SLAVE (ACL_BROADCAST_FLAG_ACTIVE_SLAVE << ACL_BROADCAST_FLAG_OFFSET)
+#define ACL_BROADCAST_FLAG_POINT_TO_POINT 0x0
+#define ACL_BROADCAST_POINT_TO_POINT \
+  (ACL_BROADCAST_FLAG_POINT_TO_POINT << ACL_BROADCAST_FLAG_OFFSET)
 
 #define ACL_PACKET_BOUNDARY_FLAG_OFFSET 4
-#define ACL_PACKET_BOUNDARY_FLAG_COMPLETE 0x3
-#define ACL_PACKET_BOUNDARY_COMPLETE \
-    (ACL_PACKET_BOUNDARY_FLAG_COMPLETE << ACL_PACKET_BOUNDARY_FLAG_OFFSET)
+#define ACL_PACKET_BOUNDARY_FLAG_FIRST_AUTO_FLUSHABLE 0x2
+#define ACL_PACKET_BOUNDARY_FIRST_AUTO_FLUSHABLE \
+  (ACL_PACKET_BOUNDARY_FLAG_FIRST_AUTO_FLUSHABLE \
+   << ACL_PACKET_BOUNDARY_FLAG_OFFSET)
 
 constexpr char kCallbackNameAclEventReceived[] = "aclDataReceived";
 constexpr char kCallbackNameHciEventReceived[] = "hciEventReceived";
@@ -189,6 +191,7 @@
 
   virtual void TearDown() override {
     bluetooth->close();
+    handle_no_ops();
     EXPECT_EQ(static_cast<size_t>(0), event_queue.size());
     EXPECT_EQ(static_cast<size_t>(0), sco_queue.size());
     EXPECT_EQ(static_cast<size_t>(0), acl_queue.size());
@@ -204,6 +207,8 @@
   // Helper functions to try to get a handle on verbosity
   void enterLoopbackMode(std::vector<uint16_t>& sco_handles,
                          std::vector<uint16_t>& acl_handles);
+  void handle_no_ops();
+  void wait_for_event(bool timeout_is_error);
   void wait_for_command_complete_event(hidl_vec<uint8_t> cmd);
   int wait_for_completed_packets_event(uint16_t handle);
 
@@ -269,31 +274,50 @@
   int max_sco_data_packets;
 };
 
-// Receive and check status events until a COMMAND_COMPLETE is received.
-void BluetoothHidlTest::wait_for_command_complete_event(hidl_vec<uint8_t> cmd) {
-  // Allow intermediate COMMAND_STATUS events
-  int status_event_count = 0;
+// Discard NO-OPs from the event queue.
+void BluetoothHidlTest::handle_no_ops() {
+  while (event_queue.size() > 0) {
+    hidl_vec<uint8_t> event = event_queue.front();
+    EXPECT_GE(event.size(),
+              static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
+    bool event_is_no_op =
+        (event[EVENT_CODE_BYTE] == EVENT_COMMAND_COMPLETE) &&
+        (event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE] == 0x00) &&
+        (event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1] == 0x00);
+    event_is_no_op |= (event[EVENT_CODE_BYTE] == EVENT_COMMAND_STATUS) &&
+                      (event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE] == 0x00) &&
+                      (event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1] == 0x00);
+    if (event_is_no_op) {
+      event_queue.pop();
+    } else {
+      return;
+    }
+  }
+}
+
+// Receive an event, discarding NO-OPs.
+void BluetoothHidlTest::wait_for_event(bool timeout_is_error = true) {
   hidl_vec<uint8_t> event;
   do {
-      EXPECT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameHciEventReceived)
-                      .no_timeout);
+    bool no_timeout =
+        bluetooth_cb->WaitForCallback(kCallbackNameHciEventReceived).no_timeout;
+    EXPECT_TRUE(no_timeout || !timeout_is_error);
+    if (no_timeout && timeout_is_error) {
       EXPECT_LT(static_cast<size_t>(0), event_queue.size());
-      if (event_queue.size() == 0) {
-          event.resize(0);
-          break;
     }
-    event = event_queue.front();
-    event_queue.pop();
-    EXPECT_GT(event.size(),
-              static_cast<size_t>(EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1));
-    if (event[EVENT_CODE_BYTE] == EVENT_COMMAND_STATUS) {
-      EXPECT_EQ(EVENT_COMMAND_STATUS_LENGTH, event[EVENT_LENGTH_BYTE]);
-      EXPECT_EQ(cmd[0], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE]);
-      EXPECT_EQ(cmd[1], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1]);
-      EXPECT_EQ(event[EVENT_COMMAND_STATUS_STATUS_BYTE], HCI_STATUS_SUCCESS);
-      status_event_count++;
+    if (event_queue.size() == 0) {
+      // WaitForCallback timed out.
+      return;
     }
-  } while (event.size() > 0 && event[EVENT_CODE_BYTE] == EVENT_COMMAND_STATUS);
+    handle_no_ops();
+  } while (event_queue.size() == 0);
+}
+
+// Wait until a COMMAND_COMPLETE is received.
+void BluetoothHidlTest::wait_for_command_complete_event(hidl_vec<uint8_t> cmd) {
+  wait_for_event();
+  hidl_vec<uint8_t> event = event_queue.front();
+  event_queue.pop();
 
   EXPECT_GT(event.size(),
             static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
@@ -308,10 +332,7 @@
   hidl_vec<uint8_t> cmd = COMMAND_HCI_READ_BUFFER_SIZE;
   bluetooth->sendHciCommand(cmd);
 
-  EXPECT_TRUE(
-      bluetooth_cb->WaitForCallback(kCallbackNameHciEventReceived).no_timeout);
-
-  EXPECT_LT(static_cast<size_t>(0), event_queue.size());
+  wait_for_event();
   if (event_queue.size() == 0) return;
 
   hidl_vec<uint8_t> event = event_queue.front();
@@ -341,6 +362,7 @@
 // Send an HCI command (in Loopback mode) and check the response.
 void BluetoothHidlTest::sendAndCheckHCI(int num_packets) {
   ThroughputLogger logger = {__func__};
+  int command_size = 0;
   for (int n = 0; n < num_packets; n++) {
     // Send an HCI packet
     std::vector<uint8_t> write_name = COMMAND_HCI_WRITE_LOCAL_NAME;
@@ -350,11 +372,9 @@
     for (size_t i = 0; i < new_name_length; i++)
       write_name.push_back(static_cast<uint8_t>(new_name[i]));
     // And the packet number
-    {
-      size_t i = new_name_length - 1;
-      for (int digits = n; digits > 0; digits = digits / 10, i--)
-        write_name[i] = static_cast<uint8_t>('0' + digits % 10);
-    }
+    size_t i = new_name_length - 1;
+    for (int digits = n; digits > 0; digits = digits / 10, i--)
+      write_name[i] = static_cast<uint8_t>('0' + digits % 10);
     // And padding
     for (size_t i = 0; i < 248 - new_name_length; i++)
       write_name.push_back(static_cast<uint8_t>(0));
@@ -363,8 +383,9 @@
     bluetooth->sendHciCommand(cmd);
 
     // Check the loopback of the HCI packet
-    EXPECT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameHciEventReceived)
-                    .no_timeout);
+    wait_for_event();
+    if (event_queue.size() == 0) return;
+
     hidl_vec<uint8_t> event = event_queue.front();
     event_queue.pop();
     size_t compare_length =
@@ -374,11 +395,21 @@
 
     EXPECT_EQ(EVENT_LOOPBACK_COMMAND, event[EVENT_CODE_BYTE]);
     EXPECT_EQ(compare_length, event[EVENT_LENGTH_BYTE]);
-    if (n == 0) logger.setTotalBytes(cmd.size() * num_packets * 2);
+
+    // Don't compare past the end of the event.
+    if (compare_length + EVENT_FIRST_PAYLOAD_BYTE > event.size()) {
+      compare_length = event.size() - EVENT_FIRST_PAYLOAD_BYTE;
+      ALOGE("Only comparing %d bytes", static_cast<int>(compare_length));
+    }
+
+    if (n == num_packets - 1) {
+      command_size = cmd.size();
+    }
 
     for (size_t i = 0; i < compare_length; i++)
       EXPECT_EQ(cmd[i], event[EVENT_FIRST_PAYLOAD_BYTE + i]);
   }
+  logger.setTotalBytes(command_size * num_packets * 2);
 }
 
 // Send a SCO data packet (in Loopback mode) and check the response.
@@ -408,8 +439,6 @@
     EXPECT_EQ(sco_packet.size(), sco_loopback.size());
     size_t successful_bytes = 0;
 
-    if (n == 0) logger.setTotalBytes(num_packets * size * 2);
-
     for (size_t i = 0; i < sco_packet.size(); i++) {
       if (sco_packet[i] == sco_loopback[i]) {
         successful_bytes = i;
@@ -423,6 +452,7 @@
     }
     EXPECT_EQ(sco_packet.size(), successful_bytes + 1);
   }
+  logger.setTotalBytes(num_packets * size * 2);
 }
 
 // Send an ACL data packet (in Loopback mode) and check the response.
@@ -435,8 +465,8 @@
     std::vector<uint8_t> acl_vector;
     acl_vector.push_back(static_cast<uint8_t>(handle & 0xff));
     acl_vector.push_back(static_cast<uint8_t>((handle & 0x0f00) >> 8) |
-                         ACL_BROADCAST_ACTIVE_SLAVE |
-                         ACL_PACKET_BOUNDARY_COMPLETE);
+                         ACL_BROADCAST_POINT_TO_POINT |
+                         ACL_PACKET_BOUNDARY_FIRST_AUTO_FLUSHABLE);
     acl_vector.push_back(static_cast<uint8_t>(size & 0xff));
     acl_vector.push_back(static_cast<uint8_t>((size & 0xff00) >> 8));
     for (size_t i = 0; i < size; i++) {
@@ -454,8 +484,6 @@
     EXPECT_EQ(acl_packet.size(), acl_loopback.size());
     size_t successful_bytes = 0;
 
-    if (n == 0) logger.setTotalBytes(num_packets * size * 2);
-
     for (size_t i = 0; i < acl_packet.size(); i++) {
       if (acl_packet[i] == acl_loopback[i]) {
         successful_bytes = i;
@@ -469,25 +497,28 @@
     }
     EXPECT_EQ(acl_packet.size(), successful_bytes + 1);
   }
+  logger.setTotalBytes(num_packets * size * 2);
 }
 
 // Return the number of completed packets reported by the controller.
 int BluetoothHidlTest::wait_for_completed_packets_event(uint16_t handle) {
-    if (!bluetooth_cb->WaitForCallback(kCallbackNameHciEventReceived).no_timeout) {
-        ALOGW("%s: WaitForCallback timed out.", __func__);
-    }
-    int packets_processed = 0;
-    while (event_queue.size() > 0) {
-        hidl_vec<uint8_t> event = event_queue.front();
-        event_queue.pop();
+  int packets_processed = 0;
+  wait_for_event(false);
+  if (event_queue.size() == 0) {
+    ALOGW("%s: WaitForCallback timed out.", __func__);
+    return packets_processed;
+  }
+  while (event_queue.size() > 0) {
+    hidl_vec<uint8_t> event = event_queue.front();
+    event_queue.pop();
 
-        EXPECT_EQ(EVENT_NUMBER_OF_COMPLETED_PACKETS, event[EVENT_CODE_BYTE]);
-        EXPECT_EQ(1, event[EVENT_NUMBER_OF_COMPLETED_PACKETS_NUM_HANDLES]);
+    EXPECT_EQ(EVENT_NUMBER_OF_COMPLETED_PACKETS, event[EVENT_CODE_BYTE]);
+    EXPECT_EQ(1, event[EVENT_NUMBER_OF_COMPLETED_PACKETS_NUM_HANDLES]);
 
-        uint16_t event_handle = event[3] + (event[4] << 8);
-        EXPECT_EQ(handle, event_handle);
+    uint16_t event_handle = event[3] + (event[4] << 8);
+    EXPECT_EQ(handle, event_handle);
 
-        packets_processed += event[5] + (event[6] << 8);
+    packets_processed += event[5] + (event[6] << 8);
   }
   return packets_processed;
 }
@@ -500,45 +531,48 @@
 
   // Receive connection complete events with data channels
   int connection_event_count = 0;
-  hidl_vec<uint8_t> event;
-  do {
-      EXPECT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameHciEventReceived)
-                      .no_timeout);
-      event = event_queue.front();
-      event_queue.pop();
-      EXPECT_GT(event.size(),
-                static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
-      if (event[EVENT_CODE_BYTE] == EVENT_CONNECTION_COMPLETE) {
-          EXPECT_GT(event.size(),
-                    static_cast<size_t>(EVENT_CONNECTION_COMPLETE_TYPE));
-          EXPECT_EQ(event[EVENT_LENGTH_BYTE],
-                    EVENT_CONNECTION_COMPLETE_PARAM_LENGTH);
-          uint8_t connection_type = event[EVENT_CONNECTION_COMPLETE_TYPE];
-
-          EXPECT_TRUE(connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO ||
-                      connection_type == EVENT_CONNECTION_COMPLETE_TYPE_ACL);
-
-          // Save handles
-          uint16_t handle = event[EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE] |
-                            event[EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE + 1]
-                                << 8;
-          if (connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO)
-              sco_handles.push_back(handle);
-          else
-              acl_handles.push_back(handle);
-
-          ALOGD("Connect complete type = %d handle = %d",
-                event[EVENT_CONNECTION_COMPLETE_TYPE], handle);
-          connection_event_count++;
+  bool command_complete_received = false;
+  while (true) {
+    wait_for_event(false);
+    if (event_queue.size() == 0) {
+      // Fail if there was no event received or no connections completed.
+      EXPECT_TRUE(command_complete_received);
+      EXPECT_LT(0, connection_event_count);
+      return;
     }
-  } while (event[EVENT_CODE_BYTE] == EVENT_CONNECTION_COMPLETE);
+    hidl_vec<uint8_t> event = event_queue.front();
+    event_queue.pop();
+    EXPECT_GT(event.size(),
+              static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
+    if (event[EVENT_CODE_BYTE] == EVENT_CONNECTION_COMPLETE) {
+      EXPECT_GT(event.size(),
+                static_cast<size_t>(EVENT_CONNECTION_COMPLETE_TYPE));
+      EXPECT_EQ(event[EVENT_LENGTH_BYTE],
+                EVENT_CONNECTION_COMPLETE_PARAM_LENGTH);
+      uint8_t connection_type = event[EVENT_CONNECTION_COMPLETE_TYPE];
 
-  EXPECT_GT(connection_event_count, 0);
+      EXPECT_TRUE(connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO ||
+                  connection_type == EVENT_CONNECTION_COMPLETE_TYPE_ACL);
 
-  EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
-  EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
-  EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
-  EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+      // Save handles
+      uint16_t handle = event[EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE] |
+                        event[EVENT_CONNECTION_COMPLETE_HANDLE_LSBYTE + 1] << 8;
+      if (connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO)
+        sco_handles.push_back(handle);
+      else
+        acl_handles.push_back(handle);
+
+      ALOGD("Connect complete type = %d handle = %d",
+            event[EVENT_CONNECTION_COMPLETE_TYPE], handle);
+      connection_event_count++;
+    } else {
+      EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+      EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+      EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+      EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+      command_complete_received = true;
+    }
+  }
 }
 
 // Empty test: Initialize()/Close() are called in SetUp()/TearDown().
@@ -557,8 +591,8 @@
   hidl_vec<uint8_t> cmd = COMMAND_HCI_READ_LOCAL_VERSION_INFORMATION;
   bluetooth->sendHciCommand(cmd);
 
-  EXPECT_TRUE(
-      bluetooth_cb->WaitForCallback(kCallbackNameHciEventReceived).no_timeout);
+  wait_for_event();
+  if (event_queue.size() == 0) return;
 
   hidl_vec<uint8_t> event = event_queue.front();
   event_queue.pop();
@@ -578,19 +612,26 @@
   hidl_vec<uint8_t> cmd = COMMAND_HCI_SHOULD_BE_UNKNOWN;
   bluetooth->sendHciCommand(cmd);
 
-  EXPECT_TRUE(
-      bluetooth_cb->WaitForCallback(kCallbackNameHciEventReceived).no_timeout);
+  wait_for_event();
+  if (event_queue.size() == 0) return;
 
   hidl_vec<uint8_t> event = event_queue.front();
   event_queue.pop();
-  EXPECT_GT(event.size(),
-            static_cast<size_t>(EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1));
 
-  EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
-  EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
-  EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
-  EXPECT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND,
-            event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+  EXPECT_GT(event.size(),
+            static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
+  if (event[EVENT_CODE_BYTE] == EVENT_COMMAND_COMPLETE) {
+    EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+    EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+    EXPECT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND,
+              event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+  } else {
+    EXPECT_EQ(EVENT_COMMAND_STATUS, event[EVENT_CODE_BYTE]);
+    EXPECT_EQ(cmd[0], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE]);
+    EXPECT_EQ(cmd[1], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1]);
+    EXPECT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND,
+              event[EVENT_COMMAND_STATUS_STATUS_BYTE]);
+  }
 }
 
 // Enter loopback mode, but don't send any packets.
@@ -603,8 +644,6 @@
 // Enter loopback mode and send single packets.
 TEST_F(BluetoothHidlTest, LoopbackModeSinglePackets) {
   setBufferSizes();
-  EXPECT_LT(0, max_sco_data_packet_length);
-  EXPECT_LT(0, max_acl_data_packet_length);
 
   std::vector<uint16_t> sco_connection_handles;
   std::vector<uint16_t> acl_connection_handles;
@@ -615,6 +654,7 @@
   // This should work, but breaks on some current platforms.  Figure out how to
   // grandfather older devices but test new ones.
   if (0 && sco_connection_handles.size() > 0) {
+    EXPECT_LT(0, max_sco_data_packet_length);
     sendAndCheckSCO(1, max_sco_data_packet_length, sco_connection_handles[0]);
     int sco_packets_sent = 1;
     int completed_packets = wait_for_completed_packets_event(sco_connection_handles[0]);
@@ -625,6 +665,7 @@
   }
 
   if (acl_connection_handles.size() > 0) {
+    EXPECT_LT(0, max_acl_data_packet_length);
     sendAndCheckACL(1, max_acl_data_packet_length, acl_connection_handles[0]);
     int acl_packets_sent = 1;
     int completed_packets = wait_for_completed_packets_event(acl_connection_handles[0]);
@@ -648,6 +689,7 @@
   // This should work, but breaks on some current platforms.  Figure out how to
   // grandfather older devices but test new ones.
   if (0 && sco_connection_handles.size() > 0) {
+    EXPECT_LT(0, max_sco_data_packet_length);
     sendAndCheckSCO(NUM_SCO_PACKETS_BANDWIDTH, max_sco_data_packet_length,
                     sco_connection_handles[0]);
     int sco_packets_sent = NUM_SCO_PACKETS_BANDWIDTH;
@@ -659,6 +701,7 @@
   }
 
   if (acl_connection_handles.size() > 0) {
+    EXPECT_LT(0, max_acl_data_packet_length);
     sendAndCheckACL(NUM_ACL_PACKETS_BANDWIDTH, max_acl_data_packet_length,
                     acl_connection_handles[0]);
     int acl_packets_sent = NUM_ACL_PACKETS_BANDWIDTH;
diff --git a/camera/common/1.0/default/VendorTagDescriptor.cpp b/camera/common/1.0/default/VendorTagDescriptor.cpp
index bc18270..1f53857 100644
--- a/camera/common/1.0/default/VendorTagDescriptor.cpp
+++ b/camera/common/1.0/default/VendorTagDescriptor.cpp
@@ -116,11 +116,11 @@
 }
 
 int VendorTagDescriptor::getTagType(uint32_t tag) const {
-    ssize_t index = mTagToNameMap.indexOfKey(tag);
-    if (index < 0) {
+    auto iter = mTagToTypeMap.find(tag);
+    if (iter == mTagToTypeMap.end()) {
         return VENDOR_TAG_TYPE_ERR;
     }
-    return mTagToTypeMap.valueFor(tag);
+    return iter->second;
 }
 
 const SortedVector<String8>* VendorTagDescriptor::getAllSectionNames() const {
@@ -167,7 +167,7 @@
         String8 name = mTagToNameMap.valueAt(i);
         uint32_t sectionId = mTagToSectionMap.valueFor(tag);
         String8 sectionName = mSections[sectionId];
-        int type = mTagToTypeMap.valueFor(tag);
+        int type = mTagToTypeMap.at(tag);
         const char* typeName = (type >= 0 && type < NUM_TYPES) ?
                 camera_metadata_type_names[type] : "UNKNOWN";
         dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2,
@@ -251,7 +251,7 @@
             ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
             return BAD_VALUE;
         }
-        desc->mTagToTypeMap.add(tag, tagType);
+        desc->mTagToTypeMap.insert(std::make_pair(tag, tagType));
     }
 
     desc->mSections = sections;
diff --git a/camera/common/1.0/default/include/VendorTagDescriptor.h b/camera/common/1.0/default/include/VendorTagDescriptor.h
index 8d8ded9..a040540 100644
--- a/camera/common/1.0/default/include/VendorTagDescriptor.h
+++ b/camera/common/1.0/default/include/VendorTagDescriptor.h
@@ -24,6 +24,7 @@
 #include <system/camera_vendor_tags.h>
 
 #include <stdint.h>
+#include <unordered_map>
 
 namespace android {
 namespace hardware {
@@ -94,7 +95,8 @@
         KeyedVector<String8, KeyedVector<String8, uint32_t>*> mReverseMapping;
         KeyedVector<uint32_t, String8> mTagToNameMap;
         KeyedVector<uint32_t, uint32_t> mTagToSectionMap; // Value is offset in mSections
-        KeyedVector<uint32_t, int32_t> mTagToTypeMap;
+
+        std::unordered_map<uint32_t, int32_t> mTagToTypeMap;
         SortedVector<String8> mSections;
         // must be int32_t to be compatible with Parcel::writeInt32
         int32_t mTagCount;
diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp
index bb4886d..b032357 100644
--- a/camera/device/3.4/default/CameraDeviceSession.cpp
+++ b/camera/device/3.4/default/CameraDeviceSession.cpp
@@ -107,7 +107,6 @@
 
     const camera_metadata_t *paramBuffer = nullptr;
     if (0 < requestedConfiguration.sessionParams.size()) {
-        ::android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams;
         V3_2::implementation::convertFromHidl(requestedConfiguration.sessionParams, &paramBuffer);
     }
 
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index 14f82bc..9a02ce8 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -638,12 +638,6 @@
         }
     }
 
-    // The document in aeAvailableTargetFpsRanges section says the minFps should
-    // not be larger than 15.
-    // We cannot support fixed 30fps but Android requires (min, max) and
-    // (max, max) ranges.
-    // TODO: populate more, right now this does not support 30,30 if the device
-    //       has higher than 30 fps modes
     std::vector<int32_t> fpsRanges;
     // Variable range
     fpsRanges.push_back(minFps);
@@ -693,7 +687,7 @@
 #undef UPDATE
 
 void ExternalCameraDevice::getFrameRateList(
-        int fd, float fpsUpperBound, SupportedV4L2Format* format) {
+        int fd, double fpsUpperBound, SupportedV4L2Format* format) {
     format->frameRates.clear();
 
     v4l2_frmivalenum frameInterval {
@@ -715,7 +709,7 @@
                 if (framerate > fpsUpperBound) {
                     continue;
                 }
-                ALOGI("index:%d, format:%c%c%c%c, w %d, h %d, framerate %f",
+                ALOGV("index:%d, format:%c%c%c%c, w %d, h %d, framerate %f",
                     frameInterval.index,
                     frameInterval.pixel_format & 0xFF,
                     (frameInterval.pixel_format >> 8) & 0xFF,
@@ -738,71 +732,68 @@
     }
 }
 
-CroppingType ExternalCameraDevice::initCroppingType(
-        /*inout*/std::vector<SupportedV4L2Format>* pSortedFmts) {
-    std::vector<SupportedV4L2Format>& sortedFmts = *pSortedFmts;
+void ExternalCameraDevice::trimSupportedFormats(
+        CroppingType cropType,
+        /*inout*/std::vector<SupportedV4L2Format>* pFmts) {
+    std::vector<SupportedV4L2Format>& sortedFmts = *pFmts;
+    if (cropType == VERTICAL) {
+        std::sort(sortedFmts.begin(), sortedFmts.end(),
+                [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool {
+                    if (a.width == b.width) {
+                        return a.height < b.height;
+                    }
+                    return a.width < b.width;
+                });
+    } else {
+        std::sort(sortedFmts.begin(), sortedFmts.end(),
+                [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool {
+                    if (a.height == b.height) {
+                        return a.width < b.width;
+                    }
+                    return a.height < b.height;
+                });
+    }
+
+    if (sortedFmts.size() == 0) {
+        ALOGE("%s: input format list is empty!", __FUNCTION__);
+        return;
+    }
+
     const auto& maxSize = sortedFmts[sortedFmts.size() - 1];
     float maxSizeAr = ASPECT_RATIO(maxSize);
-    float minAr = kMaxAspectRatio;
-    float maxAr = kMinAspectRatio;
+
+    // Remove formats that has aspect ratio not croppable from largest size
+    std::vector<SupportedV4L2Format> out;
     for (const auto& fmt : sortedFmts) {
         float ar = ASPECT_RATIO(fmt);
-        if (ar < minAr) {
-            minAr = ar;
-        }
-        if (ar > maxAr) {
-            maxAr = ar;
-        }
-    }
-
-    CroppingType ct = VERTICAL;
-    if (isAspectRatioClose(maxSizeAr, maxAr)) {
-        // Ex: 16:9 sensor, cropping horizontally to get to 4:3
-        ct = HORIZONTAL;
-    } else if (isAspectRatioClose(maxSizeAr, minAr)) {
-        // Ex: 4:3 sensor, cropping vertically to get to 16:9
-        ct = VERTICAL;
-    } else {
-        ALOGI("%s: camera maxSizeAr %f is not close to minAr %f or maxAr %f",
-                __FUNCTION__, maxSizeAr, minAr, maxAr);
-        if ((maxSizeAr - minAr) < (maxAr - maxSizeAr)) {
-            ct = VERTICAL;
+        if (isAspectRatioClose(ar, maxSizeAr)) {
+            out.push_back(fmt);
+        } else if (cropType == HORIZONTAL && ar < maxSizeAr) {
+            out.push_back(fmt);
+        } else if (cropType == VERTICAL && ar > maxSizeAr) {
+            out.push_back(fmt);
         } else {
-            ct = HORIZONTAL;
+            ALOGV("%s: size (%d,%d) is removed due to unable to crop %s from (%d,%d)",
+                __FUNCTION__, fmt.width, fmt.height,
+                cropType == VERTICAL ? "vertically" : "horizontally",
+                maxSize.width, maxSize.height);
         }
-
-        // Remove formats that has aspect ratio not croppable from largest size
-        std::vector<SupportedV4L2Format> out;
-        for (const auto& fmt : sortedFmts) {
-            float ar = ASPECT_RATIO(fmt);
-            if (isAspectRatioClose(ar, maxSizeAr)) {
-                out.push_back(fmt);
-            } else if (ct == HORIZONTAL && ar < maxSizeAr) {
-                out.push_back(fmt);
-            } else if (ct == VERTICAL && ar > maxSizeAr) {
-                out.push_back(fmt);
-            } else {
-                ALOGD("%s: size (%d,%d) is removed due to unable to crop %s from (%d,%d)",
-                    __FUNCTION__, fmt.width, fmt.height,
-                    ct == VERTICAL ? "vertically" : "horizontally",
-                    maxSize.width, maxSize.height);
-            }
-        }
-        sortedFmts = out;
     }
-    ALOGI("%s: camera croppingType is %s", __FUNCTION__,
-            ct == VERTICAL ? "VERTICAL" : "HORIZONTAL");
-    return ct;
+    sortedFmts = out;
 }
 
-void ExternalCameraDevice::initSupportedFormatsLocked(int fd) {
+std::vector<SupportedV4L2Format>
+ExternalCameraDevice::getCandidateSupportedFormatsLocked(
+        int fd, CroppingType cropType,
+        const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits) {
+    std::vector<SupportedV4L2Format> outFmts;
     struct v4l2_fmtdesc fmtdesc {
         .index = 0,
         .type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
     int ret = 0;
     while (ret == 0) {
         ret = TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc));
-        ALOGD("index:%d,ret:%d, format:%c%c%c%c", fmtdesc.index, ret,
+        ALOGV("index:%d,ret:%d, format:%c%c%c%c", fmtdesc.index, ret,
                 fmtdesc.pixelformat & 0xFF,
                 (fmtdesc.pixelformat >> 8) & 0xFF,
                 (fmtdesc.pixelformat >> 16) & 0xFF,
@@ -835,13 +826,20 @@
                             .fourcc = fmtdesc.pixelformat
                         };
 
-                        float fpsUpperBound = -1.0;
-                        for (const auto& limit : mCfg.fpsLimits) {
-                            if (format.width <= limit.size.width &&
-                                    format.height <= limit.size.height) {
-                                fpsUpperBound = limit.fpsUpperBound;
-                                break;
+                        double fpsUpperBound = -1.0;
+                        for (const auto& limit : fpsLimits) {
+                            if (cropType == VERTICAL) {
+                                if (format.width <= limit.size.width) {
+                                    fpsUpperBound = limit.fpsUpperBound;
+                                    break;
+                                }
+                            } else { // HORIZONTAL
+                                if (format.height <= limit.size.height) {
+                                    fpsUpperBound = limit.fpsUpperBound;
+                                    break;
+                                }
                             }
+
                         }
                         if (fpsUpperBound < 0.f) {
                             continue;
@@ -849,7 +847,7 @@
 
                         getFrameRateList(fd, fpsUpperBound, &format);
                         if (!format.frameRates.empty()) {
-                            mSupportedFormats.push_back(format);
+                            outFmts.push_back(format);
                         }
                     }
                 }
@@ -857,16 +855,66 @@
         }
         fmtdesc.index++;
     }
+    trimSupportedFormats(cropType, &outFmts);
+    return outFmts;
+}
 
-    std::sort(mSupportedFormats.begin(), mSupportedFormats.end(),
-            [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool {
-                if (a.width == b.width) {
-                    return a.height < b.height;
-                }
-                return a.width < b.width;
-            });
+void ExternalCameraDevice::initSupportedFormatsLocked(int fd) {
 
-    mCroppingType = initCroppingType(&mSupportedFormats);
+    std::vector<SupportedV4L2Format> horizontalFmts =
+            getCandidateSupportedFormatsLocked(fd, HORIZONTAL, mCfg.fpsLimits);
+    std::vector<SupportedV4L2Format> verticalFmts =
+            getCandidateSupportedFormatsLocked(fd, VERTICAL, mCfg.fpsLimits);
+
+    size_t horiSize = horizontalFmts.size();
+    size_t vertSize = verticalFmts.size();
+
+    if (horiSize == 0 && vertSize == 0) {
+        ALOGE("%s: cannot find suitable cropping type!", __FUNCTION__);
+        return;
+    }
+
+    if (horiSize == 0) {
+        mSupportedFormats = verticalFmts;
+        mCroppingType = VERTICAL;
+        return;
+    } else if (vertSize == 0) {
+        mSupportedFormats = horizontalFmts;
+        mCroppingType = HORIZONTAL;
+        return;
+    }
+
+    const auto& maxHoriSize = horizontalFmts[horizontalFmts.size() - 1];
+    const auto& maxVertSize = verticalFmts[verticalFmts.size() - 1];
+
+    // Try to keep largest possible output size
+    // When they are the same or ambiguous, pick the one support more sizes
+    if (maxHoriSize.width == maxVertSize.width &&
+            maxHoriSize.height == maxVertSize.height) {
+        if (horiSize > vertSize) {
+            mSupportedFormats = horizontalFmts;
+            mCroppingType = HORIZONTAL;
+        } else {
+            mSupportedFormats = verticalFmts;
+            mCroppingType = VERTICAL;
+        }
+    } else if (maxHoriSize.width >= maxVertSize.width &&
+            maxHoriSize.height >= maxVertSize.height) {
+        mSupportedFormats = horizontalFmts;
+        mCroppingType = HORIZONTAL;
+    } else if (maxHoriSize.width <= maxVertSize.width &&
+            maxHoriSize.height <= maxVertSize.height) {
+        mSupportedFormats = verticalFmts;
+        mCroppingType = VERTICAL;
+    } else {
+        if (horiSize > vertSize) {
+            mSupportedFormats = horizontalFmts;
+            mCroppingType = HORIZONTAL;
+        } else {
+            mSupportedFormats = verticalFmts;
+            mCroppingType = VERTICAL;
+        }
+    }
 }
 
 }  // namespace implementation
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 5346f80..01d7371 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -160,7 +160,6 @@
     SupportedV4L2Format streamingFmt;
     std::unordered_set<uint32_t>  inflightFrames;
     {
-        Mutex::Autolock _l(mLock);
         bool sessionLocked = tryLock(mLock);
         if (!sessionLocked) {
             dprintf(fd, "!! ExternalCameraDeviceSession mLock may be deadlocked !!\n");
@@ -180,12 +179,13 @@
             streaming ? "streaming" : "not streaming");
     if (streaming) {
         // TODO: dump fps later
-        dprintf(fd, "Current V4L2 format %c%c%c%c %dx%d\n",
+        dprintf(fd, "Current V4L2 format %c%c%c%c %dx%d @ %ffps\n",
                 streamingFmt.fourcc & 0xFF,
                 (streamingFmt.fourcc >> 8) & 0xFF,
                 (streamingFmt.fourcc >> 16) & 0xFF,
                 (streamingFmt.fourcc >> 24) & 0xFF,
-                streamingFmt.width, streamingFmt.height);
+                streamingFmt.width, streamingFmt.height,
+                mV4l2StreamingFps);
 
         size_t numDequeuedV4l2Buffers = 0;
         {
@@ -291,7 +291,6 @@
         config_v32.streams[i] = requestedConfiguration.streams[i].v3_2;
     }
 
-    // Ignore requestedConfiguration.sessionParams. External camera does not support it
     Status status = configureStreams(config_v32, &outStreams_v33);
 
     V3_4::HalStreamConfiguration outStreams;
@@ -451,6 +450,23 @@
     }
 }
 
+int ExternalCameraDeviceSession::waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk) {
+    std::chrono::seconds timeout = std::chrono::seconds(kBufferWaitTimeoutSec);
+    mLock.unlock();
+    auto st = mV4L2BufferReturned.wait_for(lk, timeout);
+    // Here we introduce a order where mV4l2BufferLock is acquired before mLock, while
+    // the normal lock acquisition order is reversed. This is fine because in most of
+    // cases we are protected by mInterfaceLock. The only thread that can cause deadlock
+    // is the OutputThread, where we do need to make sure we don't acquire mLock then
+    // mV4l2BufferLock
+    mLock.lock();
+    if (st == std::cv_status::timeout) {
+        ALOGE("%s: wait for V4L2 buffer return timeout!", __FUNCTION__);
+        return -1;
+    }
+    return 0;
+}
+
 Status ExternalCameraDeviceSession::processOneCaptureRequest(const CaptureRequest& request)  {
     Status status = initStatus();
     if (status != Status::OK) {
@@ -510,15 +526,59 @@
         return Status::ILLEGAL_ARGUMENT;
     }
 
+    camera_metadata_entry fpsRange = mLatestReqSetting.find(ANDROID_CONTROL_AE_TARGET_FPS_RANGE);
+    if (fpsRange.count == 2) {
+        double requestFpsMax = fpsRange.data.i32[1];
+        double closestFps = 0.0;
+        double fpsError = 1000.0;
+        bool fpsSupported = false;
+        for (const auto& fr : mV4l2StreamingFmt.frameRates) {
+            double f = fr.getDouble();
+            if (std::fabs(requestFpsMax - f) < 1.0) {
+                fpsSupported = true;
+                break;
+            }
+            if (std::fabs(requestFpsMax - f) < fpsError) {
+                fpsError = std::fabs(requestFpsMax - f);
+                closestFps = f;
+            }
+        }
+        if (!fpsSupported) {
+            /* This can happen in a few scenarios:
+             * 1. The application is sending a FPS range not supported by the configured outputs.
+             * 2. The application is sending a valid FPS range for all cofigured outputs, but
+             *    the selected V4L2 size can only run at slower speed. This should be very rare
+             *    though: for this to happen a sensor needs to support at least 3 different aspect
+             *    ratio outputs, and when (at least) two outputs are both not the main aspect ratio
+             *    of the webcam, a third size that's larger might be picked and runs into this
+             *    issue.
+             */
+            ALOGW("%s: cannot reach fps %d! Will do %f instead",
+                    __FUNCTION__, fpsRange.data.i32[1], closestFps);
+            requestFpsMax = closestFps;
+        }
+
+        if (requestFpsMax != mV4l2StreamingFps) {
+            {
+                std::unique_lock<std::mutex> lk(mV4l2BufferLock);
+                while (mNumDequeuedV4l2Buffers != 0) {
+                    // Wait until pipeline is idle before reconfigure stream
+                    int waitRet = waitForV4L2BufferReturnLocked(lk);
+                    if (waitRet != 0) {
+                        ALOGE("%s: wait for pipeline idle failed!", __FUNCTION__);
+                        return Status::INTERNAL_ERROR;
+                    }
+                }
+            }
+            configureV4l2StreamLocked(mV4l2StreamingFmt, requestFpsMax);
+        }
+    }
+
     status = importRequest(request, allBufPtrs, allFences);
     if (status != Status::OK) {
         return status;
     }
 
-    // TODO: program fps range per capture request here
-    //       or limit the set of availableFpsRange
-
-
     nsecs_t shutterTs = 0;
     sp<V4L2Frame> frameIn = dequeueV4l2FrameLocked(&shutterTs);
     if ( frameIn == nullptr) {
@@ -1979,7 +2039,46 @@
     return OK;
 }
 
-int ExternalCameraDeviceSession::configureV4l2StreamLocked(const SupportedV4L2Format& v4l2Fmt) {
+int ExternalCameraDeviceSession::setV4l2FpsLocked(double fps) {
+    // VIDIOC_G_PARM/VIDIOC_S_PARM: set fps
+    v4l2_streamparm streamparm = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
+    // The following line checks that the driver knows about framerate get/set.
+    int ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_G_PARM, &streamparm));
+    if (ret != 0) {
+        if (errno == -EINVAL) {
+            ALOGW("%s: device does not support VIDIOC_G_PARM", __FUNCTION__);
+        }
+        return -errno;
+    }
+    // Now check if the device is able to accept a capture framerate set.
+    if (!(streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)) {
+        ALOGW("%s: device does not support V4L2_CAP_TIMEPERFRAME", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    // fps is float, approximate by a fraction.
+    const int kFrameRatePrecision = 10000;
+    streamparm.parm.capture.timeperframe.numerator = kFrameRatePrecision;
+    streamparm.parm.capture.timeperframe.denominator =
+        (fps * kFrameRatePrecision);
+
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_PARM, &streamparm)) < 0) {
+        ALOGE("%s: failed to set framerate to %f: %s", __FUNCTION__, fps, strerror(errno));
+        return -1;
+    }
+
+    double retFps = streamparm.parm.capture.timeperframe.denominator /
+            static_cast<double>(streamparm.parm.capture.timeperframe.numerator);
+    if (std::fabs(fps - retFps) > 1.0) {
+        ALOGE("%s: expect fps %f, got %f instead", __FUNCTION__, fps, retFps);
+        return -1;
+    }
+    mV4l2StreamingFps = fps;
+    return 0;
+}
+
+int ExternalCameraDeviceSession::configureV4l2StreamLocked(
+        const SupportedV4L2Format& v4l2Fmt, double requestFps) {
     int ret = v4l2StreamOffLocked();
     if (ret != OK) {
         ALOGE("%s: stop v4l2 streaming failed: ret %d", __FUNCTION__, ret);
@@ -2016,46 +2115,31 @@
     uint32_t bufferSize = fmt.fmt.pix.sizeimage;
     ALOGI("%s: V4L2 buffer size is %d", __FUNCTION__, bufferSize);
 
-    float maxFps = -1.f;
-    float fps = 1000.f;
-    const float kDefaultFps = 30.f;
-    // Try to pick the slowest fps that is at least 30
-    for (const auto& fr : v4l2Fmt.frameRates) {
-        double f = fr.getDouble();
-        if (maxFps < f) {
-            maxFps = f;
-        }
-        if (f >= kDefaultFps && f < fps) {
-            fps = f;
-        }
-    }
-    if (fps == 1000.f) {
-        fps = maxFps;
-    }
-
-    // VIDIOC_G_PARM/VIDIOC_S_PARM: set fps
-    v4l2_streamparm streamparm = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
-    // The following line checks that the driver knows about framerate get/set.
-    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_G_PARM, &streamparm)) >= 0) {
-        // Now check if the device is able to accept a capture framerate set.
-        if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
-            // |frame_rate| is float, approximate by a fraction.
-            const int kFrameRatePrecision = 10000;
-            streamparm.parm.capture.timeperframe.numerator = kFrameRatePrecision;
-            streamparm.parm.capture.timeperframe.denominator =
-                (fps * kFrameRatePrecision);
-
-            if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_PARM, &streamparm)) < 0) {
-                ALOGE("%s: failed to set framerate to %f", __FUNCTION__, fps);
-                return UNKNOWN_ERROR;
+    const double kDefaultFps = 30.0;
+    double fps = 1000.0;
+    if (requestFps != 0.0) {
+        fps = requestFps;
+    } else {
+        double maxFps = -1.0;
+        // Try to pick the slowest fps that is at least 30
+        for (const auto& fr : v4l2Fmt.frameRates) {
+            double f = fr.getDouble();
+            if (maxFps < f) {
+                maxFps = f;
+            }
+            if (f >= kDefaultFps && f < fps) {
+                fps = f;
             }
         }
+        if (fps == 1000.0) {
+            fps = maxFps;
+        }
     }
-    float retFps = streamparm.parm.capture.timeperframe.denominator /
-                streamparm.parm.capture.timeperframe.numerator;
-    if (std::fabs(fps - retFps) > std::numeric_limits<float>::epsilon()) {
-        ALOGE("%s: expect fps %f, got %f instead", __FUNCTION__, fps, retFps);
-        return BAD_VALUE;
+
+    int fpsRet = setV4l2FpsLocked(fps);
+    if (fpsRet != 0 && fpsRet != -EINVAL) {
+        ALOGE("%s: set fps failed: %s", __FUNCTION__, strerror(fpsRet));
+        return fpsRet;
     }
 
     uint32_t v4lBufferCount = (fps >= kDefaultFps) ?
@@ -2136,17 +2220,8 @@
     {
         std::unique_lock<std::mutex> lk(mV4l2BufferLock);
         if (mNumDequeuedV4l2Buffers == mV4L2BufferCount) {
-            std::chrono::seconds timeout = std::chrono::seconds(kBufferWaitTimeoutSec);
-            mLock.unlock();
-            auto st = mV4L2BufferReturned.wait_for(lk, timeout);
-            // Here we introduce a case where mV4l2BufferLock is acquired before mLock, while
-            // the normal lock acquisition order is reversed, but this is fine because in most of
-            // cases we are protected by mInterfaceLock. The only thread that can compete these
-            // locks are the OutputThread, where we do need to make sure we don't acquire mLock then
-            // mV4l2BufferLock
-            mLock.lock();
-            if (st == std::cv_status::timeout) {
-                ALOGE("%s: wait for V4L2 buffer return timeout!", __FUNCTION__);
+            int waitRet = waitForV4L2BufferReturnLocked(lk);
+            if (waitRet != 0) {
                 return ret;
             }
         }
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index 9c0ad7f..5315097 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -177,8 +177,11 @@
     status_t initDefaultRequests();
     status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
     Status configureStreams(const V3_2::StreamConfiguration&, V3_3::HalStreamConfiguration* out);
-    int configureV4l2StreamLocked(const SupportedV4L2Format& fmt);
+    // fps = 0.0 means default, which is
+    // slowest fps that is at least 30, or fastest fps if 30 is not supported
+    int configureV4l2StreamLocked(const SupportedV4L2Format& fmt, double fps = 0.0);
     int v4l2StreamOffLocked();
+    int setV4l2FpsLocked(double fps);
 
     // TODO: change to unique_ptr for better tracking
     sp<V4L2Frame> dequeueV4l2FrameLocked(/*out*/nsecs_t* shutterTs); // Called with mLock hold
@@ -212,6 +215,8 @@
 
     ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
 
+    int waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk);
+
     class OutputThread : public android::Thread {
     public:
         OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType);
@@ -307,6 +312,7 @@
 
     bool mV4l2Streaming = false;
     SupportedV4L2Format mV4l2StreamingFmt;
+    double mV4l2StreamingFps = 0.0;
     size_t mV4L2BufferCount = 0;
 
     static const int kBufferWaitTimeoutSec = 3; // TODO: handle long exposure (or not allowing)
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index 5880469..a52f0e4 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -78,7 +78,6 @@
     /* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */
 
 protected:
-    void getFrameRateList(int fd, float fpsUpperBound, SupportedV4L2Format* format);
     // Init supported w/h/format/fps in mSupportedFormats. Caller still owns fd
     void initSupportedFormatsLocked(int fd);
 
@@ -92,7 +91,15 @@
     status_t initOutputCharsKeys(int fd,
             ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
 
-    static CroppingType initCroppingType(/*inout*/std::vector<SupportedV4L2Format>*);
+    static void getFrameRateList(int fd, double fpsUpperBound, SupportedV4L2Format* format);
+
+    // Get candidate supported formats list of input cropping type.
+    static std::vector<SupportedV4L2Format> getCandidateSupportedFormatsLocked(
+            int fd, CroppingType cropType,
+            const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits);
+    // Trim supported format list by the cropping type. Also sort output formats by width/height
+    static void trimSupportedFormats(CroppingType cropType,
+            /*inout*/std::vector<SupportedV4L2Format>* pFmts);
 
     Mutex mLock;
     bool mInitFailed = false;