Merge master@5406228 into git_qt-dev-plus-aosp.
am: 08465e2c76

Change-Id: I66c27279e5e9849c978c659aafffa5c24904c6f0
diff --git a/atrace/1.0/default/AtraceDevice.cpp b/atrace/1.0/default/AtraceDevice.cpp
index 43bcd9a..35d11e9 100644
--- a/atrace/1.0/default/AtraceDevice.cpp
+++ b/atrace/1.0/default/AtraceDevice.cpp
@@ -30,24 +30,25 @@
 
 struct TracingConfig {
     std::string description;
+    // path and if error on failure
     std::vector<std::pair<std::string, bool>> paths;
 };
 
 // This is a map stores categories and their sysfs paths with required flags
 const std::map<std::string, TracingConfig> kTracingMap = {
-    // gfx
-    {
-        "gfx",
-        {"Graphics",
-         {{"/sys/kernel/debug/tracing/events/mdss/enable", false},
-          {"/sys/kernel/debug/tracing/events/sde/enable", false},
-          {"/sys/kernel/debug/tracing/events/mali_systrace/enable", false}}},
-    },
-    {
-        "ion",
-        {"ION allocation",
-         {{"/sys/kernel/debug/tracing/events/kmem/ion_alloc_buffer_start/enable", true}}},
-    },
+        // gfx
+        {
+                "gfx",
+                {"Graphics",
+                 {{"/sys/kernel/debug/tracing/events/mdss/enable", false},
+                  {"/sys/kernel/debug/tracing/events/sde/enable", false},
+                  {"/sys/kernel/debug/tracing/events/mali_systrace/enable", false}}},
+        },
+        {
+                "ion",
+                {"ION allocation",
+                 {{"/sys/kernel/debug/tracing/events/kmem/ion_alloc_buffer_start/enable", false}}},
+        },
 };
 
 // Methods from ::android::hardware::atrace::V1_0::IAtraceDevice follow.
diff --git a/camera/device/3.5/types.hal b/camera/device/3.5/types.hal
index f98c603..6d861e2 100644
--- a/camera/device/3.5/types.hal
+++ b/camera/device/3.5/types.hal
@@ -21,6 +21,14 @@
 import @3.2::CameraBlobId;
 
 /**
+ * If the result metadata cannot be produced for a physical camera device part of a logical
+ * multi-camera, then HAL must invoke the notification callback and pass a message with ERROR_RESULT
+ * code and errorStreamId that contains the stream id associated with that physical device.
+ * The behavior during absent result metadata remains unchanged for a logical or a non-logical
+ * camera device and the errorStreamId must be set to -1.
+ */
+
+/**
  * StreamConfiguration:
  *
  * Identical to @3.4::StreamConfiguration, except that it contains streamConfigCounter
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index d77bb0e..5dfc783 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -767,7 +767,7 @@
             const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& metadata);
     void verifyStreamCombination(sp<device::V3_5::ICameraDevice> cameraDevice3_5,
             const ::android::hardware::camera::device::V3_4::StreamConfiguration &config3_4,
-            bool expectedStatus);
+            bool expectedStatus, bool expectStreamCombQuery);
     void verifyLogicalCameraResult(const camera_metadata_t* staticMetadata,
             const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& resultMetadata);
 
@@ -2877,8 +2877,9 @@
             createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE,
                                       &config3_2, &config3_4, &config3_5, jpegBufferSize);
             if (session3_5 != nullptr) {
+                bool expectStreamCombQuery = (isLogicalMultiCamera(staticMeta) == Status::OK);
                 verifyStreamCombination(cameraDevice3_5, config3_4,
-                        /*expectedStatus*/ true);
+                        /*expectedStatus*/ true, expectStreamCombQuery);
                 config3_5.streamConfigCounter = streamConfigCounter++;
                 ret = session3_5->configureStreams_3_5(config3_5,
                         [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) {
@@ -2971,7 +2972,8 @@
         createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
                                   &config3_2, &config3_4, &config3_5, jpegBufferSize);
         if (session3_5 != nullptr) {
-            verifyStreamCombination(cameraDevice3_5, config3_4, /*expectedStatus*/ false);
+            verifyStreamCombination(cameraDevice3_5, config3_4, /*expectedStatus*/ false,
+                    /*expectStreamCombQuery*/false);
             config3_5.streamConfigCounter = streamConfigCounter++;
             ret = session3_5->configureStreams_3_5(config3_5,
                     [](Status s, device::V3_4::HalStreamConfiguration) {
@@ -3232,7 +3234,7 @@
                                           &config3_2, &config3_4, &config3_5, jpegBufferSize);
                 if (session3_5 != nullptr) {
                     verifyStreamCombination(cameraDevice3_5, config3_4,
-                            /*expectedStatus*/ true);
+                            /*expectedStatus*/ true, /*expectStreamCombQuery*/ false);
                     config3_5.streamConfigCounter = streamConfigCounter++;
                     ret = session3_5->configureStreams_3_5(config3_5,
                             [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
@@ -3483,7 +3485,7 @@
                                           &config3_2, &config3_4, &config3_5, jpegBufferSize);
                 if (session3_5 != nullptr) {
                     verifyStreamCombination(cameraDevice3_5, config3_4,
-                            /*expectedStatus*/ true);
+                            /*expectedStatus*/ true, /*expectStreamCombQuery*/ false);
                     config3_5.streamConfigCounter = streamConfigCounter++;
                     ret = session3_5->configureStreams_3_5(config3_5,
                             [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
@@ -3578,7 +3580,7 @@
                                   &config3_2, &config3_4, &config3_5);
         if (session3_5 != nullptr) {
             verifyStreamCombination(cameraDevice3_5, config3_4,
-                    /*expectedStatus*/ true);
+                    /*expectedStatus*/ true, /*expectStreamCombQuery*/ false);
             config3_5.streamConfigCounter = streamConfigCounter++;
             ret = session3_5->configureStreams_3_5(config3_5,
                     [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) {
@@ -3811,7 +3813,7 @@
                                           &config3_2, &config3_4, &config3_5, jpegBufferSize);
                 if (session3_5 != nullptr) {
                     verifyStreamCombination(cameraDevice3_5, config3_4,
-                            /*expectedStatus*/ true);
+                            /*expectedStatus*/ true, /*expectStreamCombQuery*/ false);
                     config3_5.streamConfigCounter = streamConfigCounter++;
                     ret = session3_5->configureStreams_3_5(config3_5,
                             [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
@@ -5535,11 +5537,12 @@
 
 void CameraHidlTest::verifyStreamCombination(sp<device::V3_5::ICameraDevice> cameraDevice3_5,
         const ::android::hardware::camera::device::V3_4::StreamConfiguration &config3_4,
-        bool expectedStatus) {
+        bool expectedStatus, bool expectMethodSupported) {
     if (cameraDevice3_5.get() != nullptr) {
         auto ret = cameraDevice3_5->isStreamCombinationSupported(config3_4,
-                [expectedStatus] (Status s, bool combStatus) {
-                    ASSERT_TRUE((Status::OK == s) || (Status::METHOD_NOT_SUPPORTED == s));
+                [expectedStatus, expectMethodSupported] (Status s, bool combStatus) {
+                    ASSERT_TRUE((Status::OK == s) ||
+                            (!expectMethodSupported && Status::METHOD_NOT_SUPPORTED == s));
                     if (Status::OK == s) {
                         ASSERT_TRUE(combStatus == expectedStatus);
                     }
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 566bd48..09cbc20 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -301,7 +301,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.nfc</name>
-        <version>1.1</version>
+        <version>1.2</version>
         <interface>
             <name>INfc</name>
             <instance>default</instance>
diff --git a/current.txt b/current.txt
index 1108beb..8518c5e 100644
--- a/current.txt
+++ b/current.txt
@@ -396,6 +396,8 @@
 d702fb01dc2a0733aa820b7eb65435ee3334f75632ef880bafd2fb8803a20a58 android.hardware.gnss@1.0::IGnssMeasurementCallback
 7c7721c0f773fcf422b71a4f558545e9e36acc973e58ca51e5bd53905cf46bc0 android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer
 d4fea995378bb4f421b4e24ccf68cad2734ab07fe4f874a126ba558b99df5766 android.hardware.graphics.composer@2.1::IComposerClient
+f7d7cb747dc01a9fdb2d39a80003b4d8df9be733d65f5842198802eb6209db69 android.hardware.graphics.mapper@2.0::IMapper
+65a021fa89085b62fc96b2b6d3bef2f9103cf4d63379c68bc154fd9eef672852 android.hardware.health@1.0::types
 b7ecf29927055ec422ec44bf776223f07d79ad9f92ccf9becf167e62c2607e7a android.hardware.keymaster@4.0::IKeymasterDevice
 574e8f1499436fb4075894dcae0b36682427956ecb114f17f1fe22d116a83c6b android.hardware.neuralnetworks@1.0::IPreparedModel
 417ab60fe1ef786778047e4486f3d868ebce570d91addd8fe4251515213072de android.hardware.neuralnetworks@1.0::types
@@ -446,7 +448,7 @@
 09ab9b24994429d9bb32a3fb420b6f6be3e47eb655139a2c08c4e80d3f33ff95 android.hardware.camera.device@3.5::ICameraDevice
 06237de53c42890029e3f8fe7d1480d078469c0d07608e51c37b4d485d342992 android.hardware.camera.device@3.5::ICameraDeviceCallback
 08c68b196e2fc4e5ba67ba0d0917bde828a87cbe2cffec19d04733972da9eb49 android.hardware.camera.device@3.5::ICameraDeviceSession
-a848f7cb3cb3d080cf175bf08412322bfddb535168253796cdf777afdbf05b38 android.hardware.camera.device@3.5::types
+f9b8b388c0c76669e4b9189e4943efd2982f9bda5c10e276f96cc91bc8e818d6 android.hardware.camera.device@3.5::types
 f727d5f350f55a6d3354aad2feb64e43200de77c10d9d642465566bc260bb8ec android.hardware.camera.metadata@3.4::types
 0fb39a7809ad1c52b3efbbed5ef4749b06c2a4f1f19cdc3efa2e3d9b28f1205c android.hardware.camera.provider@2.5::ICameraProvider
 f5777403d65135a5407723671bc7a864cdca83aea13ee3ce2894b95e6588ca3a android.hardware.camera.provider@2.5::types
@@ -505,14 +507,14 @@
 21aa259585caaa27b6470ebcd8509aabde0ef5d039160aa6425d589cb787488b android.hardware.media.c2@1.0::IInputSink
 b9422a9aca84df1ff9623dc12c0562abce97716e28d63a965f2bfb88f9ad9607 android.hardware.media.c2@1.0::IInputSurface
 0a786a19e6753f9774a7ca7781c2a2edfe5c0b5fa112355dfa0e50ebedeb08b9 android.hardware.media.c2@1.0::IInputSurfaceConnection
-4cb139f729c29d8d6f4ecdab149c4feb571dad8a06e56cd57fcb52e70208bab4 android.hardware.media.c2@1.0::types
+7d3c292ca75ec3e22a8fd4ae72d2edb0659d280257e763786e766f3429954dd1 android.hardware.media.c2@1.0::types
 4880af120fc1640225abdc2c60bda6d79617d73484d5124913c7278af3b11e2d android.hardware.neuralnetworks@1.2::IBurstCallback
 19877e466ad8c6ed42b38050b77bd010cf7800ff365fdc8574f45bbfda03a758 android.hardware.neuralnetworks@1.2::IBurstContext
 b83317b66721241887d2770b5ae95fd5af1e77c5daa7530ecb08fae8892f2b43 android.hardware.neuralnetworks@1.2::IDevice
 92714960d1a53fc2ec557302b41c7cc93d2636d8364a44bd0f85be0c92927ff8 android.hardware.neuralnetworks@1.2::IExecutionCallback
 36e1064c869965dee533c537cefbe87e54db8bd8cd45be7e0e93e00e8a43863a android.hardware.neuralnetworks@1.2::IPreparedModel
 e1c734d1545e1a4ae749ff1dd9704a8e594c59aea7c8363159dc258e93e0df3b android.hardware.neuralnetworks@1.2::IPreparedModelCallback
-209a5ee694b94328afb2af2768f1fe6a69148e2cbb85ec3c340a36eed818c697 android.hardware.neuralnetworks@1.2::types
+9b3963253e521cca19fd81aeca83aee6dcfe3bdf2805c07cb2d3f64381709b71 android.hardware.neuralnetworks@1.2::types
 cf7a4ba516a638f9b82a249c91fb603042c2d9ca43fd5aad9cf6c0401ed2a5d7 android.hardware.nfc@1.2::INfc
 abf98c2ae08bf765db54edc8068e36d52eb558cff6706b6fd7c18c65a1f3fc18 android.hardware.nfc@1.2::types
 4cb252dc6372a874aef666b92a6e9529915aa187521a700f0789065c3c702ead android.hardware.power.stats@1.0::IPowerStats
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
index 3a73f84..1df496c 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
@@ -170,7 +170,7 @@
     }
 
     Error lookupCache(uint32_t slot, const native_handle_t** outHandle) {
-        if (slot < mHandles.size()) {
+        if (slot >= 0 && slot < mHandles.size()) {
             *outHandle = mHandles[slot];
             return Error::NONE;
         } else {
@@ -180,7 +180,7 @@
 
     Error updateCache(uint32_t slot, const native_handle_t* handle,
                       const native_handle** outReplacedHandle) {
-        if (slot < mHandles.size()) {
+        if (slot >= 0 && slot < mHandles.size()) {
             auto& cachedHandle = mHandles[slot];
             *outReplacedHandle = cachedHandle;
             cachedHandle = handle;
diff --git a/graphics/mapper/2.0/IMapper.hal b/graphics/mapper/2.0/IMapper.hal
index 4566135..0e18f42 100644
--- a/graphics/mapper/2.0/IMapper.hal
+++ b/graphics/mapper/2.0/IMapper.hal
@@ -147,6 +147,9 @@
      * outside of accessRegion is undefined, except that it must not cause
      * process termination.
      *
+     * An accessRegion of all-zeros means the entire buffer. That is, it is
+     * equivalent to '(0,0)-(buffer width, buffer height)'.
+     *
      * data will be filled with a pointer to the locked buffer memory. This
      * address will represent the top-left corner of the entire buffer, even
      * if accessRegion does not begin at the top-left corner.
diff --git a/health/1.0/types.hal b/health/1.0/types.hal
index 377d1bd..90b8bb1 100644
--- a/health/1.0/types.hal
+++ b/health/1.0/types.hal
@@ -190,7 +190,13 @@
     /** Remaining battery capacity in percent */
     int32_t batteryLevel;
 
-    /** Instantaneous battery voltage in uV */
+    /**
+     * Instantaneous battery voltage in millivolts (mV).
+     *
+     * Historically, the unit of this field is microvolts (uV), but all
+     * clients and implementations uses millivolts in practice, making it
+     * the de-facto standard.
+     */
     int32_t batteryVoltage;
 
     /** Instantaneous battery temperature in tenths of degree celcius */
diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp
index 729e1c1..e35fdd3 100644
--- a/keymaster/4.0/support/keymaster_utils.cpp
+++ b/keymaster/4.0/support/keymaster_utils.cpp
@@ -21,7 +21,9 @@
 namespace hardware {
 
 inline static bool operator<(const hidl_vec<uint8_t>& a, const hidl_vec<uint8_t>& b) {
-    return memcmp(a.data(), b.data(), std::min(a.size(), b.size())) == -1;
+    auto result = memcmp(a.data(), b.data(), std::min(a.size(), b.size()));
+    if (!result) return a.size() < b.size();
+    return result < 0;
 }
 
 template <size_t SIZE>
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index a9c6f6c..5c07532 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -172,6 +172,20 @@
     "E78E70BEFE930DB34818EE4D5C26259F5C6B8E28A652950F9F88D7B4B2C9"
     "D9");
 
+string ec_256_key_rfc5915 =
+        hex2str("308193020100301306072a8648ce3d020106082a8648ce3d030107047930"
+                "770201010420782370a8c8ce5537baadd04dcff079c8158cfa9c67b818b3"
+                "8e8d21c9fa750c1da00a06082a8648ce3d030107a14403420004e2cc561e"
+                "e701da0ad0ef0d176bb0c919d42e79c393fdc1bd6c4010d85cf2cf8e68c9"
+                "05464666f98dad4f01573ba81078b3428570a439ba3229fbc026c550682f");
+
+string ec_256_key_sec1 =
+        hex2str("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30"
+                "6b0201010420782370a8c8ce5537baadd04dcff079c8158cfa9c67b818b3"
+                "8e8d21c9fa750c1da14403420004e2cc561ee701da0ad0ef0d176bb0c919"
+                "d42e79c393fdc1bd6c4010d85cf2cf8e68c905464666f98dad4f01573ba8"
+                "1078b3428570a439ba3229fbc026c550682f");
+
 struct RSA_Delete {
     void operator()(RSA* p) { RSA_free(p); }
 };
@@ -1778,6 +1792,56 @@
 }
 
 /*
+ * ImportKeyTest.EcdsaP256RFC5915Success
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair encoded using RFC5915 works correctly.
+ */
+TEST_F(ImportKeyTest, EcdsaP256RFC5915Success) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaSigningKey(256)
+                                               .Digest(Digest::SHA_2_256),
+                                       KeyFormat::PKCS8, ec_256_key_rfc5915));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_KEY_SIZE, 256U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.EcdsaP256SEC1Success
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair encoded using SEC1 works correctly.
+ */
+TEST_F(ImportKeyTest, EcdsaP256SEC1Success) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaSigningKey(256)
+                                               .Digest(Digest::SHA_2_256),
+                                       KeyFormat::PKCS8, ec_256_key_sec1));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_KEY_SIZE, 256U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
  * ImportKeyTest.Ecdsa521Success
  *
  * Verifies that importing and using an ECDSA P-521 key pair works correctly.
diff --git a/media/c2/1.0/Android.bp b/media/c2/1.0/Android.bp
index 7307a81..895e9db 100644
--- a/media/c2/1.0/Android.bp
+++ b/media/c2/1.0/Android.bp
@@ -27,6 +27,7 @@
         "android.hardware.media.omx@1.0",
         "android.hardware.media@1.0",
         "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
     ],
     gen_java: false,
 }
diff --git a/media/c2/1.0/types.hal b/media/c2/1.0/types.hal
index ec422b1..f4f6f2f 100644
--- a/media/c2/1.0/types.hal
+++ b/media/c2/1.0/types.hal
@@ -17,6 +17,7 @@
 package android.hardware.media.c2@1.0;
 
 import android.hardware.media.bufferpool@2.0::BufferStatusMessage;
+import android.hidl.safe_union@1.0::Monostate;
 
 /**
  * Common return values for Codec2 operations.
@@ -190,89 +191,68 @@
  */
 typedef uint64_t PrimitiveValue;
 
+/**
+ * Description of a set of values.
+ *
+ * If the `step` member is 0, and `num` and `denom` are both 1, the `Range`
+ * structure represents a closed interval bounded by `min` and `max`.
+ *
+ * Otherwise, the #ValueRange structure represents a finite sequence of numbers
+ * produced from the following recurrence relation:
+ *
+ * @code
+ * v[0] = min
+ * v[i] = v[i - 1] * num / denom + step ; i >= 1
+ * @endcode
+ *
+ * Both the ratio `num / denom` and the value `step` must be positive. The
+ * last number in the sequence described by this #Range structure is the
+ * largest number in the sequence that is smaller than or equal to `max`.
+ *
+ * @note
+ * The division in the formula may truncate the result if the data type of
+ * these values is an integral type.
+ */
+struct ValueRange {
+    /**
+     * Lower end of the range (inclusive).
+     */
+    PrimitiveValue min;
+    /**
+     * Upper end of the range (inclusive).
+     */
+    PrimitiveValue max;
+    /**
+     * The non-homogeneous term in the recurrence relation.
+     */
+    PrimitiveValue step;
+    /**
+     * The numerator of the scale coefficient in the recurrence relation.
+     */
+    PrimitiveValue num;
+    /**
+     * The denominator of the scale coefficient in the recurrence relation.
+     */
+    PrimitiveValue denom;
+};
+
 /*
  * Description of supported values for a field.
  *
  * This can be a continuous range or a discrete set of values.
+ *
+ * The intended type of values must be made clear in the context where
+ * `FieldSupportedValues` is used.
  */
-struct FieldSupportedValues {
-    /**
-     * Used if #type is `RANGE`.
-     *
-     * If the `step` member is 0, and `num` and `denom` are both 1, the `Range`
-     * structure represents a closed interval bounded by `min` and `max`.
-     *
-     * Otherwise, the #Range structure represents a finite sequence of numbers
-     * produced from the following recurrence relation:
-     *
-     * @code
-     * v[0] = min
-     * v[i] = v[i - 1] * num / denom + step ; i >= 1
-     * @endcode
-     *
-     * Both the ratio `num / denom` and the value `step` must be positive. The
-     * last number in the sequence described by this #Range structure is the
-     * largest number in the sequence that is smaller than or equal to `max`.
-     *
-     * @note
-     * The division in the formula may truncate the result if the data type of
-     * these values is an integral type.
-     */
-    struct Range {
-        /**
-         * Lower end of the range (inclusive).
-         */
-        PrimitiveValue min;
-        /**
-         * Upper end of the range (inclusive).
-         */
-        PrimitiveValue max;
-        /**
-         * The non-homogeneous term in the recurrence relation.
-         */
-        PrimitiveValue step;
-        /**
-         * The numerator of the scale coefficient in the recurrence relation.
-         */
-        PrimitiveValue num;
-        /**
-         * The denominator of the scale coefficient in the recurrence relation.
-         */
-        PrimitiveValue denom;
-    };
-
-    enum Type : int32_t {
-        /** No supported values */
-        EMPTY = 0,
-        /** Numeric range, described in a #Range structure */
-        RANGE,
-        /** List of values */
-        VALUES,
-        /** List of flags that can be OR-ed */
-        FLAGS,
-    };
-    /**
-     * Type of the supported values.
-     */
-    Type type;
-
-    /**
-     * When #type is #Type.RANGE, #range shall specify the range of possible
-     * values.
-     *
-     * The intended type of members of #range shall be clear in the context
-     * where `FieldSupportedValues` is used.
-     */
-    Range range;
-
-    /**
-     * When #type is #Type.VALUES or #Type.FLAGS, #value shall list supported
-     * values/flags.
-     *
-     * The intended type of components of #value shall be clear in the context
-     * where `FieldSupportedValues` is used.
-     */
+safe_union FieldSupportedValues {
+    /** No supported values */
+    Monostate empty;
+    /** Numeric range, described in a #ValueRange structure */
+    ValueRange range;
+    /** List of values */
     vec<PrimitiveValue> values;
+    /** List of flags that can be OR-ed */
+    vec<PrimitiveValue> flags;
 };
 
 /**
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 106f332..c819b52 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -125,9 +125,9 @@
     ADD_FAILURE() << "asking for burst execution at V1_0";
     return nullptr;
 }
-static std::unique_ptr<::android::nn::ExecutionBurstController> CreateBurst(
+static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst(
         const sp<V1_2::IPreparedModel>& preparedModel) {
-    return ::android::nn::createExecutionBurstController(preparedModel, /*blocking=*/true);
+    return ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
 }
 enum class Executor { ASYNC, SYNC, BURST };
 enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
@@ -286,7 +286,7 @@
                 SCOPED_TRACE("burst");
 
                 // create burst
-                const std::unique_ptr<::android::nn::ExecutionBurstController> controller =
+                const std::shared_ptr<::android::nn::ExecutionBurstController> controller =
                         CreateBurst(preparedModel);
                 ASSERT_NE(nullptr, controller.get());
 
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index 8c57796..67a61c1 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -1188,8 +1188,11 @@
      *   value if the recurrent projection layer exists, and should otherwise
      *   have no value.
      * * (API level >= 29) The four layer normalization weights either all have
-     *   values or none of them have values. Layer normalization is used when
-     *   values are present.
+     *   values or none of them have values. Additionally, if CIFG is used,
+     *   input layer normalization weights tensor is omitted and the other layer
+     *   normalization weights either all have values or none of them have
+     *   values. Layer normalization is used when the values of all the layer
+     *   normalization weights are present.
      *
      * References:
      *
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index b15f657..870d017 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -155,8 +155,8 @@
         SCOPED_TRACE(message + " [burst]");
 
         // create burst
-        std::unique_ptr<::android::nn::ExecutionBurstController> burst =
-                ::android::nn::createExecutionBurstController(preparedModel, /*blocking=*/true);
+        std::shared_ptr<::android::nn::ExecutionBurstController> burst =
+                ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
         ASSERT_NE(nullptr, burst.get());
 
         // create memory keys
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
index 76d8758..2093c25 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
@@ -758,3 +758,40 @@
                                      {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
     }
 }
+
+/*
+ * Test IRadio.getDataRegistrationStateResponse_1_4() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_4, getDataRegistrationState_1_4) {
+    int rat;
+    serial = GetRandomSerialNumber();
+
+    Return<void> res = radio_v1_4->getDataRegistrationState(serial);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_4->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_4->rspInfo.serial);
+
+    ALOGI("getDataRegistrationStateResponse_1_4, rspInfo.error = %s\n",
+          toString(radioRsp_v1_4->rspInfo.error).c_str());
+
+    ASSERT_TRUE(CheckAnyOfErrors(
+        radioRsp_v1_4->rspInfo.error,
+        {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::NOT_PROVISIONED}));
+
+    rat = radioRsp_v1_4->dataRegResp.base.rat;
+    /*
+     *  - Expect Valid vopsinfo when device is on LTE
+     *  - Expect empty vopsInfo when device is not on LTE
+     */
+    if (rat == ((int )::android::hardware::radio::V1_4::RadioTechnology::LTE)
+        || (rat == (int )::android::hardware::radio::V1_4::RadioTechnology::LTE_CA)) {
+
+        EXPECT_EQ(::android::hardware::radio::V1_4::DataRegStateResult::VopsInfo::hidl_discriminator
+                  ::lteVopsInfo, radioRsp_v1_4->dataRegResp.vopsInfo.getDiscriminator());
+    } else {
+
+        EXPECT_EQ(::android::hardware::radio::V1_4::DataRegStateResult::VopsInfo::hidl_discriminator
+                  ::noinit, radioRsp_v1_4->dataRegResp.vopsInfo.getDiscriminator());
+    }
+}
diff --git a/sensors/2.0/default/Android.bp b/sensors/2.0/default/Android.bp
index d05634b..05a34bb 100644
--- a/sensors/2.0/default/Android.bp
+++ b/sensors/2.0/default/Android.bp
@@ -23,7 +23,7 @@
         "Sensor.cpp",
         "Sensors.cpp",
     ],
-    init_rc: ["android.hardware.sensors@2.0-service.rc"],
+    init_rc: ["android.hardware.sensors@2.0-service-mock.rc"],
     shared_libs: [
         "android.hardware.sensors@1.0",
         "android.hardware.sensors@2.0",
diff --git a/sensors/2.0/default/android.hardware.sensors@2.0-service.rc b/sensors/2.0/default/android.hardware.sensors@2.0-service-mock.rc
similarity index 100%
rename from sensors/2.0/default/android.hardware.sensors@2.0-service.rc
rename to sensors/2.0/default/android.hardware.sensors@2.0-service-mock.rc
diff --git a/vibrator/1.3/example/OWNERS b/vibrator/1.3/example/OWNERS
new file mode 100644
index 0000000..4b34968
--- /dev/null
+++ b/vibrator/1.3/example/OWNERS
@@ -0,0 +1,2 @@
+eliptus@google.com
+michaelwr@google.com
diff --git a/vibrator/1.3/example/Vibrator.cpp b/vibrator/1.3/example/Vibrator.cpp
index eb50187..0cb37e6 100644
--- a/vibrator/1.3/example/Vibrator.cpp
+++ b/vibrator/1.3/example/Vibrator.cpp
@@ -100,14 +100,22 @@
 Return<void> Vibrator::perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
     uint8_t amplitude;
     uint32_t ms;
-    Status status;
+    Status status = Status::OK;
 
-    ALOGI("Perform: Effect %s\n", effectToName(effect));
+    ALOGI("Perform: Effect %s\n", effectToName(effect).c_str());
 
-    amplitude = strengthToAmplitude(strength);
+    amplitude = strengthToAmplitude(strength, &status);
+    if (status != Status::OK) {
+        _hidl_cb(status, 0);
+        return Void();
+    }
     setAmplitude(amplitude);
 
-    ms = effectToMs(effect);
+    ms = effectToMs(effect, &status);
+    if (status != Status::OK) {
+        _hidl_cb(status, 0);
+        return Void();
+    }
     status = activate(ms);
 
     _hidl_cb(status, ms);
@@ -178,11 +186,11 @@
     static_cast<Vibrator*>(sigval.sival_ptr)->timeout();
 }
 
-const char* Vibrator::effectToName(Effect effect) {
-    return toString(effect).c_str();
+const std::string Vibrator::effectToName(Effect effect) {
+    return toString(effect);
 }
 
-uint32_t Vibrator::effectToMs(Effect effect) {
+uint32_t Vibrator::effectToMs(Effect effect, Status* status) {
     switch (effect) {
         case Effect::CLICK:
             return 10;
@@ -228,9 +236,11 @@
         case Effect::RINGTONE_15:
             return 30000;
     }
+    *status = Status::UNSUPPORTED_OPERATION;
+    return 0;
 }
 
-uint8_t Vibrator::strengthToAmplitude(EffectStrength strength) {
+uint8_t Vibrator::strengthToAmplitude(EffectStrength strength, Status* status) {
     switch (strength) {
         case EffectStrength::LIGHT:
             return 128;
@@ -239,6 +249,8 @@
         case EffectStrength::STRONG:
             return 255;
     }
+    *status = Status::UNSUPPORTED_OPERATION;
+    return 0;
 }
 
 }  // namespace implementation
diff --git a/vibrator/1.3/example/Vibrator.h b/vibrator/1.3/example/Vibrator.h
index 8cf0b1e..64e8e1b 100644
--- a/vibrator/1.3/example/Vibrator.h
+++ b/vibrator/1.3/example/Vibrator.h
@@ -59,9 +59,9 @@
     void timeout();
 
     static void timerCallback(union sigval sigval);
-    static const char* effectToName(Effect effect);
-    static uint32_t effectToMs(Effect effect);
-    static uint8_t strengthToAmplitude(EffectStrength strength);
+    static const std::string effectToName(Effect effect);
+    static uint32_t effectToMs(Effect effect, Status* status);
+    static uint8_t strengthToAmplitude(EffectStrength strength, Status* status);
 
   private:
     bool mEnabled{false};
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
index 72cafd1..1b7e821 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
@@ -361,8 +361,8 @@
 
 /*
  * CreateApIface
- * Configures the chip in AP mode and ensures that only 1 iface creation
- * succeeds. The 2nd iface creation should be rejected.
+ * Configures the chip in AP mode and ensures that at least 1 iface creation
+ * succeeds.
  */
 TEST_F(WifiChipHidlTest, CreateApIface) {
     if (!gEnv->isSoftApOn) return;
@@ -371,8 +371,6 @@
     sp<IWifiApIface> iface;
     EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
     EXPECT_NE(nullptr, iface.get());
-
-    EXPECT_EQ(WifiStatusCode::ERROR_NOT_AVAILABLE, createApIface(&iface));
 }
 
 /*
@@ -460,8 +458,8 @@
 
 /*
  * CreateNanIface
- * Configures the chip in NAN mode and ensures that only 1 iface creation
- * succeeds. The 2nd iface creation should be rejected.
+ * Configures the chip in NAN mode and ensures that at least 1 iface creation
+ * succeeds.
  */
 TEST_F(WifiChipHidlTest, CreateNanIface) {
     if (!gEnv->isNanOn) return;
@@ -470,8 +468,6 @@
     sp<IWifiNanIface> iface;
     ASSERT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
     EXPECT_NE(nullptr, iface.get());
-
-    EXPECT_EQ(WifiStatusCode::ERROR_NOT_AVAILABLE, createNanIface(&iface));
 }
 
 /*
@@ -560,8 +556,8 @@
 
 /*
  * CreateP2pIface
- * Configures the chip in P2P mode and ensures that only 1 iface creation
- * succeeds. The 2nd iface creation should be rejected.
+ * Configures the chip in P2P mode and ensures that at least 1 iface creation
+ * succeeds.
  */
 TEST_F(WifiChipHidlTest, CreateP2pIface) {
     configureChipForIfaceType(IfaceType::P2P, true);
@@ -569,8 +565,6 @@
     sp<IWifiP2pIface> iface;
     EXPECT_EQ(WifiStatusCode::SUCCESS, createP2pIface(&iface));
     EXPECT_NE(nullptr, iface.get());
-
-    EXPECT_EQ(WifiStatusCode::ERROR_NOT_AVAILABLE, createP2pIface(&iface));
 }
 
 /*
@@ -655,8 +649,8 @@
 
 /*
  * CreateStaIface
- * Configures the chip in STA mode and ensures that only 1 iface creation
- * succeeds. The 2nd iface creation should be rejected.
+ * Configures the chip in STA mode and ensures that at least 1 iface creation
+ * succeeds.
  */
 TEST_F(WifiChipHidlTest, CreateStaIface) {
     configureChipForIfaceType(IfaceType::STA, true);
@@ -664,8 +658,6 @@
     sp<IWifiStaIface> iface;
     EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&iface));
     EXPECT_NE(nullptr, iface.get());
-
-    EXPECT_EQ(WifiStatusCode::ERROR_NOT_AVAILABLE, createStaIface(&iface));
 }
 
 /*
diff --git a/wifi/1.3/default/tests/mock_wifi_legacy_hal.h b/wifi/1.3/default/tests/mock_wifi_legacy_hal.h
index deb3a5a..53fa8d6 100644
--- a/wifi/1.3/default/tests/mock_wifi_legacy_hal.h
+++ b/wifi/1.3/default/tests/mock_wifi_legacy_hal.h
@@ -39,6 +39,16 @@
     MOCK_METHOD2(registerRadioModeChangeCallbackHandler,
                  wifi_error(const std::string&,
                             const on_radio_mode_change_callback&));
+    MOCK_METHOD1(getFirmwareVersion, std::pair<wifi_error, std::string>(
+                 const std::string& iface_name));
+    MOCK_METHOD1(getDriverVersion, std::pair<wifi_error, std::string>(
+                 const std::string& iface_name));
+
+    MOCK_METHOD2(selectTxPowerScenario,
+                 wifi_error(const std::string& iface_name,
+                            wifi_power_scenario scenario));
+    MOCK_METHOD1(resetTxPowerScenario,
+                 wifi_error(const std::string& iface_name));
     MOCK_METHOD2(nanRegisterCallbackHandlers,
                  wifi_error(const std::string&, const NanCallbackHandlers&));
     MOCK_METHOD2(nanDisableRequest,
diff --git a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
index 134563c..7928328 100644
--- a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
@@ -122,7 +122,7 @@
     void setup_MultiIfaceCombination() {
         // clang-format off
         const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
-            {{{{IfaceType::STA}, 3}}}
+            {{{{IfaceType::STA}, 3}, {{IfaceType::AP}, 1}}}
         };
         const std::vector<V1_0::IWifiChip::ChipMode> modes = {
             {feature_flags::chip_mode_ids::kV3, combinations}
@@ -261,6 +261,17 @@
         return success;
     }
 
+    sp<WifiChip> chip_;
+    ChipId chip_id_ = kFakeChipId;
+    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+        new NiceMock<legacy_hal::MockWifiLegacyHal>};
+    std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>>
+        mode_controller_{new NiceMock<mode_controller::MockWifiModeController>};
+    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
+        new NiceMock<iface_util::MockWifiIfaceUtil>};
+    std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
+        feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
+
    public:
     void SetUp() override {
         chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_,
@@ -272,17 +283,12 @@
             .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
     }
 
-   private:
-    sp<WifiChip> chip_;
-    ChipId chip_id_ = kFakeChipId;
-    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-        new NiceMock<legacy_hal::MockWifiLegacyHal>};
-    std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>>
-        mode_controller_{new NiceMock<mode_controller::MockWifiModeController>};
-    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
-        new NiceMock<iface_util::MockWifiIfaceUtil>};
-    std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
-        feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
+    void TearDown() override {
+        // Restore default system iface names (This should ideally be using a
+        // mock).
+        property_set("wifi.interface", "wlan0");
+        property_set("wifi.concurrent.interface", "wlan1");
+    }
 };
 
 ////////// V1 Iface Combinations ////////////
@@ -300,7 +306,7 @@
 
 TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
 }
 
 TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
@@ -326,7 +332,7 @@
 
 TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
 }
 
 TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
@@ -359,7 +365,7 @@
 
 TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
 }
 
 TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
@@ -427,7 +433,7 @@
 
 TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
 }
 
 TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
@@ -445,18 +451,18 @@
     ASSERT_TRUE(createIface(IfaceType::NAN).empty());
 }
 
-TEST_F(WifiChipV1IfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
     findModeAndConfigureForIfaceType(IfaceType::STA);
     ASSERT_TRUE(createRttController());
 }
 
-TEST_F(WifiChipV1IfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
     findModeAndConfigureForIfaceType(IfaceType::STA);
     ASSERT_FALSE(createIface(IfaceType::STA).empty());
     ASSERT_TRUE(createRttController());
 }
 
-TEST_F(WifiChipV1IfaceCombinationTest, RttControllerFlowApToSta) {
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowApToSta) {
     findModeAndConfigureForIfaceType(IfaceType::AP);
     const auto ap_iface_name = createIface(IfaceType::AP);
     ASSERT_FALSE(ap_iface_name.empty());
@@ -468,6 +474,30 @@
     ASSERT_TRUE(createRttController());
 }
 
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    chip_->selectTxPowerScenario_1_2(
+        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+        [](const WifiStatus& status) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        });
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    chip_->selectTxPowerScenario_1_2(
+        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+        [](const WifiStatus& status) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        });
+}
+
 ////////// V2 + Aware Iface Combinations ////////////
 // Mode 1 - STA + STA/AP
 //        - STA + P2P/NAN
@@ -483,7 +513,7 @@
 
 TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
 }
 
 TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) {
@@ -498,19 +528,25 @@
 
 TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
 }
 
 TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldFail) {
     findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
     ASSERT_TRUE(createIface(IfaceType::STA).empty());
 }
 
 TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) {
     findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
 }
 
 TEST_F(WifiChipV2_AwareIfaceCombinationTest,
@@ -640,6 +676,30 @@
     ASSERT_TRUE(createRttController());
 }
 
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    chip_->selectTxPowerScenario_1_2(
+        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+        [](const WifiStatus& status) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan1", testing::_))
+        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    chip_->selectTxPowerScenario_1_2(
+        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+        [](const WifiStatus& status) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        });
+}
+
 ////////// V1 Iface Combinations when AP creation is disabled //////////
 class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
    public:
@@ -707,8 +767,8 @@
     property_set("wifi.interface", "bad0");
     property_set("wifi.concurrent.interface", "bad1");
     findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "test0");
-    ASSERT_EQ(createIface(IfaceType::STA), "test1");
+    ASSERT_EQ(createIface(IfaceType::STA), "bad0");
+    ASSERT_EQ(createIface(IfaceType::STA), "bad1");
     ASSERT_EQ(createIface(IfaceType::STA), "test2");
 }
 
@@ -724,6 +784,16 @@
     ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
 }
 
+TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    // First AP will be slotted to wlan1.
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    // First STA will be slotted to wlan0.
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    // All further STA will be slotted to the remaining free indices.
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
+}
 }  // namespace implementation
 }  // namespace V1_3
 }  // namespace wifi
diff --git a/wifi/1.3/default/wifi_chip.cpp b/wifi/1.3/default/wifi_chip.cpp
index 3697d50..25eb289 100644
--- a/wifi/1.3/default/wifi_chip.cpp
+++ b/wifi/1.3/default/wifi_chip.cpp
@@ -41,7 +41,9 @@
 constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60 * 10;
 constexpr uint32_t kMaxRingBufferFileNum = 20;
 constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/";
-constexpr unsigned kMaxWlanIfaces = 100;
+constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface";
+constexpr char kNoActiveWlanIfaceNamePropertyValue[] = "";
+constexpr unsigned kMaxWlanIfaces = 5;
 
 template <typename Iface>
 void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
@@ -105,6 +107,13 @@
     return buffer.data();
 }
 
+void setActiveWlanIfaceNameProperty(const std::string& ifname) {
+    auto res = property_set(kActiveWlanIfaceNameProperty, ifname.data());
+    if (res != 0) {
+        PLOG(ERROR) << "Failed to set active wlan iface name property";
+    }
+}
+
 // delete files that meet either conditions:
 // 1. older than a predefined time in the wifi tombstone dir.
 // 2. Files in excess to a predefined amount, starting from the oldest ones
@@ -316,13 +325,16 @@
       is_valid_(true),
       current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
       modes_(feature_flags.lock()->getChipModes()),
-      debug_ring_buffer_cb_registered_(false) {}
+      debug_ring_buffer_cb_registered_(false) {
+    setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
+}
 
 void WifiChip::invalidate() {
     if (!writeRingbufferFilesInternal()) {
         LOG(ERROR) << "Error writing files to flash";
     }
     invalidateAndRemoveAllIfaces();
+    setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
     legacy_hal_.reset();
     event_cb_handler_.invalidate();
     is_valid_ = false;
@@ -641,7 +653,7 @@
     legacy_hal::wifi_error legacy_status;
     uint32_t legacy_feature_set;
     uint32_t legacy_logger_feature_set;
-    const auto ifname = getWlanIfaceName(0);
+    const auto ifname = getFirstActiveWlanIfaceName();
     std::tie(legacy_status, legacy_feature_set) =
         legacy_hal_.lock()->getSupportedFeatureSet(ifname);
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
@@ -693,6 +705,7 @@
     }
     current_mode_id_ = mode_id;
     LOG(INFO) << "Configured chip in mode " << mode_id;
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
     return status;
 }
 
@@ -709,7 +722,7 @@
     IWifiChip::ChipDebugInfo result;
     legacy_hal::wifi_error legacy_status;
     std::string driver_desc;
-    const auto ifname = getWlanIfaceName(0);
+    const auto ifname = getFirstActiveWlanIfaceName();
     std::tie(legacy_status, driver_desc) =
         legacy_hal_.lock()->getDriverVersion(ifname);
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
@@ -741,7 +754,8 @@
     legacy_hal::wifi_error legacy_status;
     std::vector<uint8_t> driver_dump;
     std::tie(legacy_status, driver_dump) =
-        legacy_hal_.lock()->requestDriverMemoryDump(getWlanIfaceName(0));
+        legacy_hal_.lock()->requestDriverMemoryDump(
+            getFirstActiveWlanIfaceName());
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
         LOG(ERROR) << "Failed to get driver debug dump: "
                    << legacyErrorToString(legacy_status);
@@ -756,7 +770,8 @@
     legacy_hal::wifi_error legacy_status;
     std::vector<uint8_t> firmware_dump;
     std::tie(legacy_status, firmware_dump) =
-        legacy_hal_.lock()->requestFirmwareMemoryDump(getWlanIfaceName(0));
+        legacy_hal_.lock()->requestFirmwareMemoryDump(
+            getFirstActiveWlanIfaceName());
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
         LOG(ERROR) << "Failed to get firmware debug dump: "
                    << legacyErrorToString(legacy_status);
@@ -766,10 +781,10 @@
 }
 
 std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::createApIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfType(IfaceType::AP)) {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
-    std::string ifname = allocateApOrStaIfaceName();
+    std::string ifname = allocateApIfaceName();
     sp<WifiApIface> iface =
         new WifiApIface(ifname, legacy_hal_, iface_util_, feature_flags_);
     ap_ifaces_.push_back(iface);
@@ -778,6 +793,7 @@
             LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
         }
     }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
     return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
 }
 
@@ -809,15 +825,16 @@
             LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
         }
     }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
 std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::createNanIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfType(IfaceType::NAN)) {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) {
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
     // These are still assumed to be based on wlan0.
-    std::string ifname = getWlanIfaceName(0);
+    std::string ifname = getFirstActiveWlanIfaceName();
     sp<WifiNanIface> iface = new WifiNanIface(ifname, legacy_hal_);
     nan_ifaces_.push_back(iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -860,7 +877,7 @@
 }
 
 std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfType(IfaceType::P2P)) {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::P2P)) {
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
     std::string ifname = getP2pIfaceName();
@@ -906,10 +923,10 @@
 }
 
 std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::createStaIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) {
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
-    std::string ifname = allocateApOrStaIfaceName();
+    std::string ifname = allocateStaIfaceName();
     sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_, iface_util_);
     sta_ifaces_.push_back(iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -917,6 +934,7 @@
             LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
         }
     }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
     return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
 }
 
@@ -948,6 +966,7 @@
             LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
         }
     }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
@@ -959,8 +978,8 @@
                       "(and RTT by extension)";
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
-    sp<WifiRttController> rtt =
-        new WifiRttController(getWlanIfaceName(0), bound_iface, legacy_hal_);
+    sp<WifiRttController> rtt = new WifiRttController(
+        getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
     rtt_controllers_.emplace_back(rtt);
     return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
 }
@@ -971,7 +990,7 @@
     std::vector<legacy_hal::wifi_ring_buffer_status>
         legacy_ring_buffer_status_vec;
     std::tie(legacy_status, legacy_ring_buffer_status_vec) =
-        legacy_hal_.lock()->getRingBuffersStatus(getWlanIfaceName(0));
+        legacy_hal_.lock()->getRingBuffersStatus(getFirstActiveWlanIfaceName());
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
         return {createWifiStatusFromLegacyError(legacy_status), {}};
     }
@@ -993,7 +1012,7 @@
     }
     legacy_hal::wifi_error legacy_status =
         legacy_hal_.lock()->startRingBufferLogging(
-            getWlanIfaceName(0), ring_name,
+            getFirstActiveWlanIfaceName(), ring_name,
             static_cast<
                 std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(
                 verbose_level),
@@ -1010,7 +1029,8 @@
         return status;
     }
     legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->getRingBufferData(getWlanIfaceName(0), ring_name);
+        legacy_hal_.lock()->getRingBufferData(getFirstActiveWlanIfaceName(),
+                                              ring_name);
 
     return createWifiStatusFromLegacyError(legacy_status);
 }
@@ -1026,7 +1046,7 @@
 WifiStatus WifiChip::stopLoggingToDebugRingBufferInternal() {
     legacy_hal::wifi_error legacy_status =
         legacy_hal_.lock()->deregisterRingBufferCallbackHandler(
-            getWlanIfaceName(0));
+            getFirstActiveWlanIfaceName());
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
@@ -1035,7 +1055,7 @@
     legacy_hal::wifi_error legacy_status;
     legacy_hal::WakeReasonStats legacy_stats;
     std::tie(legacy_status, legacy_stats) =
-        legacy_hal_.lock()->getWakeReasonStats(getWlanIfaceName(0));
+        legacy_hal_.lock()->getWakeReasonStats(getFirstActiveWlanIfaceName());
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
         return {createWifiStatusFromLegacyError(legacy_status), {}};
     }
@@ -1067,10 +1087,10 @@
             }
         };
         legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
-            getWlanIfaceName(0), on_alert_callback);
+            getFirstActiveWlanIfaceName(), on_alert_callback);
     } else {
         legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler(
-            getWlanIfaceName(0));
+            getFirstActiveWlanIfaceName());
     }
     return createWifiStatusFromLegacyError(legacy_status);
 }
@@ -1078,20 +1098,20 @@
 WifiStatus WifiChip::selectTxPowerScenarioInternal(
     V1_1::IWifiChip::TxPowerScenario scenario) {
     auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
-        getWlanIfaceName(0),
+        getFirstActiveWlanIfaceName(),
         hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
 WifiStatus WifiChip::resetTxPowerScenarioInternal() {
     auto legacy_status =
-        legacy_hal_.lock()->resetTxPowerScenario(getWlanIfaceName(0));
+        legacy_hal_.lock()->resetTxPowerScenario(getFirstActiveWlanIfaceName());
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
 WifiStatus WifiChip::setLatencyModeInternal(LatencyMode mode) {
     auto legacy_status = legacy_hal_.lock()->setLatencyMode(
-        getWlanIfaceName(0),
+        getFirstActiveWlanIfaceName(),
         hidl_struct_util::convertHidlLatencyModeToLegacy(mode));
     return createWifiStatusFromLegacyError(legacy_status);
 }
@@ -1107,7 +1127,7 @@
 WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(
     TxPowerScenario scenario) {
     auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
-        getWlanIfaceName(0),
+        getFirstActiveWlanIfaceName(),
         hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
     return createWifiStatusFromLegacyError(legacy_status);
 }
@@ -1197,7 +1217,7 @@
         };
     legacy_hal::wifi_error legacy_status =
         legacy_hal_.lock()->registerRingBufferCallbackHandler(
-            getWlanIfaceName(0), on_ring_buffer_data_callback);
+            getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
 
     if (legacy_status == legacy_hal::WIFI_SUCCESS) {
         debug_ring_buffer_cb_registered_ = true;
@@ -1231,7 +1251,7 @@
         };
     legacy_hal::wifi_error legacy_status =
         legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
-            getWlanIfaceName(0), on_radio_mode_change_callback);
+            getFirstActiveWlanIfaceName(), on_radio_mode_change_callback);
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
@@ -1298,8 +1318,9 @@
     return expanded_combos;
 }
 
-bool WifiChip::canExpandedIfaceCombinationSupportIfaceOfType(
-    const std::map<IfaceType, size_t>& combo, IfaceType requested_type) {
+bool WifiChip::canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+    const std::map<IfaceType, size_t>& expanded_combo,
+    IfaceType requested_type) {
     const auto current_combo = getCurrentIfaceCombination();
 
     // Check if we have space for 1 more iface of |type| in this combo
@@ -1309,7 +1330,7 @@
         if (type == requested_type) {
             num_ifaces_needed++;
         }
-        size_t num_ifaces_allowed = combo.at(type);
+        size_t num_ifaces_allowed = expanded_combo.at(type);
         if (num_ifaces_needed > num_ifaces_allowed) {
             return false;
         }
@@ -1320,8 +1341,10 @@
 // This method does the following:
 // a) Enumerate all possible iface combos by expanding the current
 //    ChipIfaceCombination.
-// b) Check if the requested iface type can be added to the current mode.
-bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType type) {
+// b) Check if the requested iface type can be added to the current mode
+//    with the iface combination that is already active.
+bool WifiChip::canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
+    IfaceType requested_type) {
     if (!isValidModeId(current_mode_id_)) {
         LOG(ERROR) << "Chip not configured in a mode yet";
         return false;
@@ -1330,8 +1353,8 @@
     for (const auto& combination : combinations) {
         const auto expanded_combos = expandIfaceCombinations(combination);
         for (const auto& expanded_combo : expanded_combos) {
-            if (canExpandedIfaceCombinationSupportIfaceOfType(expanded_combo,
-                                                              type)) {
+            if (canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+                    expanded_combo, requested_type)) {
                 return true;
             }
         }
@@ -1339,6 +1362,62 @@
     return false;
 }
 
+// Note: This does not consider ifaces already active. It only checks if the
+// provided expanded iface combination can support the requested combo.
+bool WifiChip::canExpandedIfaceComboSupportIfaceCombo(
+    const std::map<IfaceType, size_t>& expanded_combo,
+    const std::map<IfaceType, size_t>& req_combo) {
+    // Check if we have space for 1 more iface of |type| in this combo
+    for (const auto type :
+         {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+        if (req_combo.count(type) == 0) {
+            // Iface of "type" not in the req_combo.
+            continue;
+        }
+        size_t num_ifaces_needed = req_combo.at(type);
+        size_t num_ifaces_allowed = expanded_combo.at(type);
+        if (num_ifaces_needed > num_ifaces_allowed) {
+            return false;
+        }
+    }
+    return true;
+}
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+//    ChipIfaceCombination.
+// b) Check if the requested iface combo can be added to the current mode.
+// Note: This does not consider ifaces already active. It only checks if the
+// current mode can support the requested combo.
+bool WifiChip::canCurrentModeSupportIfaceCombo(
+    const std::map<IfaceType, size_t>& req_combo) {
+    if (!isValidModeId(current_mode_id_)) {
+        LOG(ERROR) << "Chip not configured in a mode yet";
+        return false;
+    }
+    const auto combinations = getCurrentModeIfaceCombinations();
+    for (const auto& combination : combinations) {
+        const auto expanded_combos = expandIfaceCombinations(combination);
+        for (const auto& expanded_combo : expanded_combos) {
+            if (canExpandedIfaceComboSupportIfaceCombo(expanded_combo,
+                                                       req_combo)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+//    ChipIfaceCombination.
+// b) Check if the requested iface type can be added to the current mode.
+bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType requested_type) {
+    // Check if we can support atleast 1 iface of type.
+    std::map<IfaceType, size_t> req_iface_combo;
+    req_iface_combo[requested_type] = 1;
+    return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
 bool WifiChip::isValidModeId(ChipModeId mode_id) {
     for (const auto& mode : modes_) {
         if (mode.id == mode_id) {
@@ -1348,11 +1427,32 @@
     return false;
 }
 
-// Return the first wlan (wlan0, wlan1 etc.) not already in use.
-// This doesn't check the actual presence of these interfaces.
-std::string WifiChip::allocateApOrStaIfaceName() {
-    for (unsigned i = 0; i < kMaxWlanIfaces; i++) {
-        const auto ifname = getWlanIfaceName(i);
+bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() {
+    // Check if we can support atleast 1 STA & 1 AP concurrently.
+    std::map<IfaceType, size_t> req_iface_combo;
+    req_iface_combo[IfaceType::AP] = 1;
+    req_iface_combo[IfaceType::STA] = 1;
+    return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
+std::string WifiChip::getFirstActiveWlanIfaceName() {
+    for (unsigned idx = 0; idx < kMaxWlanIfaces; idx++) {
+        const auto ifname = getWlanIfaceName(idx);
+        if (findUsingName(sta_ifaces_, ifname)) return ifname;
+        if (findUsingName(ap_ifaces_, ifname)) return ifname;
+    }
+    // This could happen if the chip call is made before any STA/AP
+    // iface is created. Default to wlan0 for such cases.
+    LOG(WARNING) << "No active wlan interfaces in use!";
+    return getWlanIfaceName(0);
+}
+
+// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
+// not already in use.
+// Note: This doesn't check the actual presence of these interfaces.
+std::string WifiChip::allocateApOrStaIfaceName(uint32_t start_idx) {
+    for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
+        const auto ifname = getWlanIfaceName(idx);
         if (findUsingName(ap_ifaces_, ifname)) continue;
         if (findUsingName(sta_ifaces_, ifname)) continue;
         return ifname;
@@ -1362,6 +1462,19 @@
     return {};
 }
 
+// AP iface names start with idx 1 for modes supporting
+// concurrent STA, else start with idx 0.
+std::string WifiChip::allocateApIfaceName() {
+    return allocateApOrStaIfaceName(
+        isStaApConcurrencyAllowedInCurrentMode() ? 1 : 0);
+}
+
+// STA iface names start with idx 0.
+// Primary STA iface will always be 0.
+std::string WifiChip::allocateStaIfaceName() {
+    return allocateApOrStaIfaceName(0);
+}
+
 bool WifiChip::writeRingbufferFilesInternal() {
     if (!removeOldFilesInternal()) {
         LOG(ERROR) << "Error occurred while deleting old tombstone files";
diff --git a/wifi/1.3/default/wifi_chip.h b/wifi/1.3/default/wifi_chip.h
index 3eb0aee..3d12f4c 100644
--- a/wifi/1.3/default/wifi_chip.h
+++ b/wifi/1.3/default/wifi_chip.h
@@ -224,11 +224,23 @@
     std::map<IfaceType, size_t> getCurrentIfaceCombination();
     std::vector<std::map<IfaceType, size_t>> expandIfaceCombinations(
         const IWifiChip::ChipIfaceCombination& combination);
-    bool canExpandedIfaceCombinationSupportIfaceOfType(
-        const std::map<IfaceType, size_t>& combo, IfaceType type);
-    bool canCurrentModeSupportIfaceOfType(IfaceType type);
+    bool canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+        const std::map<IfaceType, size_t>& expanded_combo,
+        IfaceType requested_type);
+    bool canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
+        IfaceType requested_type);
+    bool canExpandedIfaceComboSupportIfaceCombo(
+        const std::map<IfaceType, size_t>& expanded_combo,
+        const std::map<IfaceType, size_t>& req_combo);
+    bool canCurrentModeSupportIfaceCombo(
+        const std::map<IfaceType, size_t>& req_combo);
+    bool canCurrentModeSupportIfaceOfType(IfaceType requested_type);
     bool isValidModeId(ChipModeId mode_id);
-    std::string allocateApOrStaIfaceName();
+    bool isStaApConcurrencyAllowedInCurrentMode();
+    std::string getFirstActiveWlanIfaceName();
+    std::string allocateApOrStaIfaceName(uint32_t start_idx);
+    std::string allocateApIfaceName();
+    std::string allocateStaIfaceName();
     bool writeRingbufferFilesInternal();
 
     ChipId chip_id_;
diff --git a/wifi/1.3/default/wifi_legacy_hal.cpp b/wifi/1.3/default/wifi_legacy_hal.cpp
index 5aa98c4..7f9b635 100644
--- a/wifi/1.3/default/wifi_legacy_hal.cpp
+++ b/wifi/1.3/default/wifi_legacy_hal.cpp
@@ -777,7 +777,7 @@
 }
 
 wifi_error WifiLegacyHal::startSendingOffloadedPacket(
-    const std::string& iface_name, uint32_t cmd_id,
+    const std::string& iface_name, uint32_t cmd_id, uint16_t ether_type,
     const std::vector<uint8_t>& ip_packet_data,
     const std::array<uint8_t, 6>& src_address,
     const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
@@ -787,9 +787,9 @@
     std::vector<uint8_t> dst_address_internal(
         dst_address.data(), dst_address.data() + dst_address.size());
     return global_func_table_.wifi_start_sending_offloaded_packet(
-        cmd_id, getIfaceHandle(iface_name), ip_packet_data_internal.data(),
-        ip_packet_data_internal.size(), src_address_internal.data(),
-        dst_address_internal.data(), period_in_ms);
+        cmd_id, getIfaceHandle(iface_name), ether_type,
+        ip_packet_data_internal.data(), ip_packet_data_internal.size(),
+        src_address_internal.data(), dst_address_internal.data(), period_in_ms);
 }
 
 wifi_error WifiLegacyHal::stopSendingOffloadedPacket(
diff --git a/wifi/1.3/default/wifi_legacy_hal.h b/wifi/1.3/default/wifi_legacy_hal.h
index 70a919f..a3ed460 100644
--- a/wifi/1.3/default/wifi_legacy_hal.h
+++ b/wifi/1.3/default/wifi_legacy_hal.h
@@ -184,9 +184,9 @@
     // Checks if legacy HAL has successfully started
     bool isStarted();
     // Wrappers for all the functions in the legacy HAL function table.
-    std::pair<wifi_error, std::string> getDriverVersion(
+    virtual std::pair<wifi_error, std::string> getDriverVersion(
         const std::string& iface_name);
-    std::pair<wifi_error, std::string> getFirmwareVersion(
+    virtual std::pair<wifi_error, std::string> getFirmwareVersion(
         const std::string& iface_name);
     std::pair<wifi_error, std::vector<uint8_t>> requestDriverMemoryDump(
         const std::string& iface_name);
@@ -246,7 +246,7 @@
                                      fw_roaming_state_t state);
     wifi_error configureNdOffload(const std::string& iface_name, bool enable);
     wifi_error startSendingOffloadedPacket(
-        const std::string& iface_name, uint32_t cmd_id,
+        const std::string& iface_name, uint32_t cmd_id, uint16_t ether_type,
         const std::vector<uint8_t>& ip_packet_data,
         const std::array<uint8_t, 6>& src_address,
         const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
@@ -254,9 +254,9 @@
                                           uint32_t cmd_id);
     wifi_error setScanningMacOui(const std::string& iface_name,
                                  const std::array<uint8_t, 3>& oui);
-    wifi_error selectTxPowerScenario(const std::string& iface_name,
-                                     wifi_power_scenario scenario);
-    wifi_error resetTxPowerScenario(const std::string& iface_name);
+    virtual wifi_error selectTxPowerScenario(const std::string& iface_name,
+                                             wifi_power_scenario scenario);
+    virtual wifi_error resetTxPowerScenario(const std::string& iface_name);
     wifi_error setLatencyMode(const std::string& iface_name,
                               wifi_latency_mode mode);
     // Logger/debug functions.
diff --git a/wifi/1.3/default/wifi_sta_iface.cpp b/wifi/1.3/default/wifi_sta_iface.cpp
index 17f3e3d..a6539e5 100644
--- a/wifi/1.3/default/wifi_sta_iface.cpp
+++ b/wifi/1.3/default/wifi_sta_iface.cpp
@@ -562,12 +562,12 @@
 
 WifiStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
     uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
-    uint16_t /* ether_type */, const std::array<uint8_t, 6>& src_address,
+    uint16_t ether_type, const std::array<uint8_t, 6>& src_address,
     const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
     legacy_hal::wifi_error legacy_status =
         legacy_hal_.lock()->startSendingOffloadedPacket(
-            ifname_, cmd_id, ip_packet_data, src_address, dst_address,
-            period_in_ms);
+            ifname_, cmd_id, ether_type, ip_packet_data, src_address,
+            dst_address, period_in_ms);
     return createWifiStatusFromLegacyError(legacy_status);
 }