Merge "Volume Control: Add tests to validate Volume Control Effect" into main
diff --git a/audio/aidl/default/apex/com.android.hardware.audio/Android.bp b/audio/aidl/default/apex/com.android.hardware.audio/Android.bp
index 9c91e27..2ece7a1 100644
--- a/audio/aidl/default/apex/com.android.hardware.audio/Android.bp
+++ b/audio/aidl/default/apex/com.android.hardware.audio/Android.bp
@@ -38,6 +38,7 @@
         "libpreprocessingaidl",
         "libpresetreverbsw",
         "libreverbaidl",
+        "libspatializersw",
         "libvirtualizersw",
         "libvisualizeraidl",
         "libvolumesw",
diff --git a/audio/aidl/default/spatializer/Android.bp b/audio/aidl/default/spatializer/Android.bp
index 400629e..2c229fe 100644
--- a/audio/aidl/default/spatializer/Android.bp
+++ b/audio/aidl/default/spatializer/Android.bp
@@ -35,6 +35,6 @@
     ],
     relative_install_path: "soundfx",
     visibility: [
-        "//hardware/interfaces/audio/aidl/default",
+        "//hardware/interfaces/audio/aidl/default:__subpackages__",
     ],
 }
diff --git a/audio/aidl/default/spatializer/SpatializerSw.cpp b/audio/aidl/default/spatializer/SpatializerSw.cpp
index 6d3c4bd..ef86ddb 100644
--- a/audio/aidl/default/spatializer/SpatializerSw.cpp
+++ b/audio/aidl/default/spatializer/SpatializerSw.cpp
@@ -108,6 +108,8 @@
 
 ndk::ScopedAStatus SpatializerSw::getParameterSpecific(const Parameter::Id& id,
                                                        Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::spatializerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
     auto spatializerId = id.get<Parameter::Id::spatializerTag>();
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index 7b98634..789e8a1 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -2583,6 +2583,10 @@
 
 TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
        GetDataPathConfiguration) {
+  if (GetProviderFactoryInterfaceVersion() <
+      BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+    GTEST_SKIP();
+  }
   IBluetoothAudioProvider::StreamConfig sink_requirement;
   IBluetoothAudioProvider::StreamConfig source_requirement;
   std::vector<IBluetoothAudioProvider::LeAudioDataPathConfiguration>
diff --git a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
index 4778020..0430ea7 100644
--- a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
+++ b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
@@ -144,7 +144,8 @@
             auto status = mAllocator->getIMapperLibrarySuffix(&mapperSuffix);
             ASSERT_TRUE(status.isOk());
             std::string lib_name = "mapper." + mapperSuffix + ".so";
-            void* so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW);
+            void* so = AServiceManager_openDeclaredPassthroughHal("mapper", mapperSuffix.c_str(),
+                                                                  RTLD_LOCAL | RTLD_NOW);
             ASSERT_NE(nullptr, so) << "Failed to load " << lib_name;
             auto loadIMapper = (AIMapper_loadIMapperFn)dlsym(so, "AIMapper_loadIMapper");
             ASSERT_NE(nullptr, loadIMapper) << "AIMapper_locaIMapper missing from " << lib_name;
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
index b329de2..1e0c427 100644
--- a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -166,7 +166,8 @@
         auto status = mAllocator->getIMapperLibrarySuffix(&mapperSuffix);
         ASSERT_TRUE(status.isOk()) << "Failed to get IMapper library suffix";
         std::string lib_name = "mapper." + mapperSuffix + ".so";
-        void* so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW);
+        void* so = AServiceManager_openDeclaredPassthroughHal("mapper", mapperSuffix.c_str(),
+                                                              RTLD_LOCAL | RTLD_NOW);
         ASSERT_NE(nullptr, so) << "Failed to load " << lib_name;
         mIMapperLoader = (AIMapper_loadIMapperFn)dlsym(so, "AIMapper_loadIMapper");
         ASSERT_NE(nullptr, mIMapperLoader) << "AIMapper_locaIMapper missing from " << lib_name;
diff --git a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
index 1bff076..a076438 100644
--- a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
+++ b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
@@ -51,7 +51,7 @@
     };
 
     using KeymasterVec = std::vector<sp<IKeymasterDevice>>;
-    using ByteString = std::basic_string<uint8_t>;
+    using ByteString = std::vector<uint8_t>;
     // using NonceVec = std::vector<HidlBuf>;
 
     GetParamsResult getHmacSharingParameters(IKeymasterDevice& keymaster) {
@@ -98,7 +98,7 @@
     std::vector<ByteString> copyNonces(const hidl_vec<HmacSharingParameters>& paramsVec) {
         std::vector<ByteString> nonces;
         for (auto& param : paramsVec) {
-            nonces.emplace_back(param.nonce.data(), param.nonce.size());
+            nonces.emplace_back(param.nonce.data(), param.nonce.data() + param.nonce.size());
         }
         return nonces;
     }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index aeb0163..4ebafee 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -794,33 +794,40 @@
             in @nullable HardwareAuthToken authToken);
 
     /**
-     * Called by client to notify the IKeyMintDevice that the device is now locked, and keys with
-     * the UNLOCKED_DEVICE_REQUIRED tag should no longer be usable.  When this function is called,
-     * the IKeyMintDevice should note the current timestamp, and attempts to use
-     * UNLOCKED_DEVICE_REQUIRED keys must be rejected with Error::DEVICE_LOCKED until an
-     * authentication token with a later timestamp is presented.  If the `passwordOnly' argument is
-     * set to true the sufficiently-recent authentication token must indicate that the user
-     * authenticated with a password, not a biometric.
+     * This method is deprecated and has never been used.  Implementations should return
+     * ErrorCode::UNIMPLEMENTED.
      *
-     * Note that the IKeyMintDevice UNLOCKED_DEVICE_REQUIRED semantics are slightly different from
-     * the UNLOCKED_DEVICE_REQUIRED semantics enforced by keystore.  Keystore handles device locking
-     * on a per-user basis.  Because auth tokens do not contain an Android user ID, it's not
-     * possible to replicate the keystore enforcement logic in IKeyMintDevice.  So from the
-     * IKeyMintDevice perspective, any user unlock unlocks all UNLOCKED_DEVICE_REQUIRED keys.
-     * Keystore will continue enforcing the per-user device locking.
+     * This method was originally intended to be used to notify KeyMint that the device is now
+     * locked, and keys with the UNLOCKED_DEVICE_REQUIRED tag should no longer be usable until a
+     * later valid HardwareAuthToken is presented.  However, Android has never called this method
+     * and it cannot start doing so, because KeyMint's enforcement of UNLOCKED_DEVICE_REQUIRED did
+     * not provide the correct semantics and therefore could never be enabled.  Specifically, the
+     * following issues existed with the design of KeyMint's enforcement of
+     * UNLOCKED_DEVICE_REQUIRED:
      *
-     * @param passwordOnly specifies whether the device must be unlocked with a password, rather
-     * than a biometric, before UNLOCKED_DEVICE_REQUIRED keys can be used.
+     * o It assumed a global device lock state only.  Android actually has a separate lock state for
+     *   each user.  See the javadoc for KeyguardManager#isDeviceLocked().
+     * o It assumed that unlocking the device involves a successful user authentication that
+     *   generates a HardwareAuthToken.  This is not necessarily the case, since Android supports
+     *   weaker unlock methods including class 1 and 2 biometrics and trust agents.  These unlock
+     *   methods do not generate a HardwareAuthToken or interact with KeyMint in any way.  Also,
+     *   UNLOCKED_DEVICE_REQUIRED must work even for users who do not have a secure lock screen.
+     * o It would have made UNLOCKED_DEVICE_REQUIRED incompatible with requiring user
+     *   authentication in some cases.  These two key protections can each require a different
+     *   HardwareAuthToken, but KeyMint only supports one HardwareAuthToken per operation.
+     * o It would have provided no security benefit over Keystore's enforcement of
+     *   UNLOCKED_DEVICE_REQUIRED.  This is because since Android 12, Keystore enforces
+     *   UNLOCKED_DEVICE_REQUIRED not just logically, but it also cryptographically by
+     *   superencrypting all such keys and wiping or re-encrypting the superencryption key when the
+     *   device is locked (whenever possible).  KeyMint is still used to support biometric unlocks,
+     *   but this mechanism does not use KeyMint's direct enforcement of UNLOCKED_DEVICE_REQUIRED.
      *
-     * @param timestampToken is used by StrongBox implementations of IKeyMintDevice.  It
-     * provides the StrongBox IKeyMintDevice with a fresh, MACed timestamp which it can use as the
-     * device-lock time, for future comparison against auth tokens when operations using
-     * UNLOCKED_DEVICE_REQUIRED keys are attempted.  Unless the auth token timestamp is newer than
-     * the timestamp in the timestampToken, the device is still considered to be locked.
-     * Crucially, if a StrongBox IKeyMintDevice receives a deviceLocked() call with a timestampToken
-     * timestamp that is less than the timestamp in the last deviceLocked() call, it must ignore the
-     * new timestamp.  TEE IKeyMintDevice implementations will receive an empty timestampToken (zero
-     * values and empty vectors) and should use their own clock as the device-lock time.
+     * Therefore, this method is not useful, and there is no reason for it be called.
+     * Implementations should return ErrorCode::UNIMPLEMENTED and should not include
+     * UNLOCKED_DEVICE_REQUIRED in the list of hardware-enforced key parameters.
+     *
+     * @param passwordOnly N/A due to the deprecation
+     * @param timestampToken N/A due to the deprecation
      */
     void deviceLocked(in boolean passwordOnly, in @nullable TimeStampToken timestampToken);
 
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index be29f59..996e4e3 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -482,11 +482,12 @@
 
     /**
      * Tag::UNLOCKED_DEVICE_REQUIRED specifies that the key may only be used when the device is
-     * unlocked, as reported to KeyMint via authToken operation parameter and the
-     * IKeyMintDevice::deviceLocked() method
+     * unlocked.
      *
-     * Must be hardware-enforced (but is also keystore-enforced on a per-user basis: see the
-     * deviceLocked() documentation).
+     * This tag was originally intended to be hardware-enforced.  However, the support for hardware
+     * enforcement of this tag is now considered deprecated because it cannot work correctly, and
+     * even if implemented it does nothing because it was never enabled by Keystore.  Refer to the
+     * documentation for the deprecated method IKeyMintDevice::deviceLocked().
      */
     UNLOCKED_DEVICE_REQUIRED = TagType.BOOL | 509,
 
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 0b7627c..a8f41c3 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -8760,40 +8760,6 @@
 
 INSTANTIATE_KEYMINT_AIDL_TEST(EarlyBootKeyTest);
 
-using UnlockedDeviceRequiredTest = KeyMintAidlTestBase;
-
-// This may be a problematic test.  It can't be run repeatedly without unlocking the device in
-// between runs... and on most test devices there are no enrolled credentials so it can't be
-// unlocked at all, meaning the only way to get the test to pass again on a properly-functioning
-// device is to reboot it.  For that reason, this is disabled by default.  It can be used as part of
-// a manual test process, which includes unlocking between runs, which is why it's included here.
-// Well, that and the fact that it's the only test we can do without also making calls into the
-// Gatekeeper HAL.  We haven't written any cross-HAL tests, and don't know what all of the
-// implications might be, so that may or may not be a solution.
-TEST_P(UnlockedDeviceRequiredTest, DISABLED_KeysBecomeUnusable) {
-    auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
-            CreateTestKeys(TAG_UNLOCKED_DEVICE_REQUIRED, ErrorCode::OK);
-    KeyBlobDeleter aes_deleter(keymint_, aesKeyData.blob);
-    KeyBlobDeleter hmac_deleter(keymint_, hmacKeyData.blob);
-    KeyBlobDeleter rsa_deleter(keymint_, rsaKeyData.blob);
-    KeyBlobDeleter ecdsa_deleter(keymint_, ecdsaKeyData.blob);
-
-    EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
-    EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
-    EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
-    EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
-
-    ErrorCode rc = GetReturnErrorCode(
-            keyMint().deviceLocked(false /* passwordOnly */, {} /* timestampToken */));
-    ASSERT_EQ(ErrorCode::OK, rc);
-    EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseAesKey(aesKeyData.blob));
-    EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseHmacKey(hmacKeyData.blob));
-    EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseRsaKey(rsaKeyData.blob));
-    EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseEcdsaKey(ecdsaKeyData.blob));
-}
-
-INSTANTIATE_KEYMINT_AIDL_TEST(UnlockedDeviceRequiredTest);
-
 using VsrRequirementTest = KeyMintAidlTestBase;
 
 // @VsrTest = VSR-3.10-008
diff --git a/security/keymint/support/remote_prov_utils_test.cpp b/security/keymint/support/remote_prov_utils_test.cpp
index 630f7bb..89469f1 100644
--- a/security/keymint/support/remote_prov_utils_test.cpp
+++ b/security/keymint/support/remote_prov_utils_test.cpp
@@ -14,20 +14,23 @@
  * limitations under the License.
  */
 
-#include "cppbor.h"
-#include "keymaster/cppcose/cppcose.h"
 #include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
 #include <android-base/properties.h>
+#include <cppbor.h>
 #include <cppbor_parse.h>
-#include <cstdint>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <keymaster/android_keymaster_utils.h>
+#include <keymaster/cppcose/cppcose.h>
 #include <keymaster/logger.h>
 #include <keymaster/remote_provisioning_utils.h>
 #include <openssl/curve25519.h>
 #include <remote_prov/remote_prov_utils.h>
 
+#include <algorithm>
+#include <cstdint>
+#include <span>
+
 namespace aidl::android::hardware::security::keymint::remote_prov {
 namespace {
 
@@ -36,7 +39,11 @@
 using ::keymaster::kStatusInvalidEek;
 using ::keymaster::StatusOr;
 using ::testing::ElementsAreArray;
-using byte_view = std::basic_string_view<uint8_t>;
+using byte_view = std::span<const uint8_t>;
+
+inline bool equal_byte_views(const byte_view& view1, const byte_view& view2) {
+    return std::equal(view1.begin(), view1.end(), view2.begin(), view2.end());
+}
 
 struct KeyInfoEcdsa {
     CoseKeyCurve curve;
@@ -44,7 +51,8 @@
     byte_view pubKeyY;
 
     bool operator==(const KeyInfoEcdsa& other) const {
-        return curve == other.curve && pubKeyX == other.pubKeyX && pubKeyY == other.pubKeyY;
+        return curve == other.curve && equal_byte_views(pubKeyX, other.pubKeyX) &&
+               equal_byte_views(pubKeyY, other.pubKeyY);
     }
 };
 
diff --git a/staging/security/see/storage/aidl/Android.bp b/staging/security/see/storage/aidl/Android.bp
new file mode 100644
index 0000000..f669be8
--- /dev/null
+++ b/staging/security/see/storage/aidl/Android.bp
@@ -0,0 +1,26 @@
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.security.see.storage",
+    unstable: true,
+    host_supported: true,
+    srcs: [
+        "android/hardware/security/see/storage/*.aidl",
+    ],
+    backend: {
+        java: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: true,
+        },
+        ndk: {
+            enabled: true,
+        },
+        rust: {
+            enabled: true,
+        },
+    },
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/CreationMode.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/CreationMode.aidl
new file mode 100644
index 0000000..1c65038
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/CreationMode.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+enum CreationMode {
+    /** Returns an error if the file does not already exist. */
+    NO_CREATE,
+
+    /** Creates the file or returns an error if it already exists. */
+    CREATE_EXCLUSIVE,
+
+    /** Creates the file if it does not already exist. */
+    CREATE,
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/DeleteOptions.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/DeleteOptions.aidl
new file mode 100644
index 0000000..1a94eb2
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/DeleteOptions.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+import android.hardware.security.see.storage.ReadIntegrity;
+
+parcelable DeleteOptions {
+    /**
+     * Set to acknowledge possible files tampering.
+     *
+     * If unacknowledged tampering is detected, the operation will fail with an ERR_FS_*
+     * service-specific code.
+     */
+    ReadIntegrity readIntegrity = ReadIntegrity.NO_TAMPER;
+
+    /**
+     * Allow writes to succeed while the filesystem is in the middle of an A/B update.
+     *
+     * If the A/B update fails, the operation will be rolled back. This rollback will not
+     * cause subsequent operations fail with any ERR_FS_* code nor will need to be
+     * acknowledged by setting the `readIntegrity`.
+     */
+    boolean allowWritesDuringAbUpdate = false;
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileAvailability.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileAvailability.aidl
new file mode 100644
index 0000000..d339170
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileAvailability.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+/** Determines how early during the boot process file is able to be accessed. */
+enum FileAvailability {
+    /** Available before userdata is mounted, but after android has booted. */
+    BEFORE_USERDATA,
+
+    /** Available after userdata is mounted. */
+    AFTER_USERDATA,
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileIntegrity.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileIntegrity.aidl
new file mode 100644
index 0000000..1879b16
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileIntegrity.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+enum FileIntegrity {
+    /** REE may prevent operations, but cannot alter data once written. */
+    TAMPER_PROOF_AT_REST,
+
+    /**
+     * REE may alter written data, but changes will be detected and reported as
+     * an error on read.
+     */
+    TAMPER_DETECT,
+
+    /**
+     * REE may alter written data. Changes other than full filesystem resets will be detected and
+     * reported.
+     */
+    TAMPER_DETECT_IGNORE_RESET,
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileMode.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileMode.aidl
new file mode 100644
index 0000000..18a2eae
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileMode.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+enum FileMode {
+    /** The file may only be read from. */
+    READ_ONLY,
+
+    /** The file may only be written to. */
+    WRITE_ONLY,
+
+    /** The file may be both read from and written to. */
+    READ_WRITE,
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileProperties.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileProperties.aidl
new file mode 100644
index 0000000..733b5b0
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/FileProperties.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+import android.hardware.security.see.storage.FileAvailability;
+import android.hardware.security.see.storage.FileIntegrity;
+
+parcelable FileProperties {
+    FileIntegrity integrity = FileIntegrity.TAMPER_PROOF_AT_REST;
+    FileAvailability availability = FileAvailability.BEFORE_USERDATA;
+
+    /** Whether the file is reset when user data is wiped. */
+    boolean persistent;
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/IDir.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/IDir.aidl
new file mode 100644
index 0000000..a0a9f3d
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/IDir.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+/** The interface for an open directory */
+interface IDir {
+    /**
+     * Gets the next batch of filenames in this directory.
+     *
+     * Calling multiple times will return different results as the IDir iterates through all the
+     * files it contains. When all filenames have been returned, all successive calls will return an
+     * empty list.
+     *
+     * @maxCount:
+     *     the maximum number of filenames to return. A @maxCount of 0 signifies no limit on the
+     * number of filenames returned.
+     *
+     * Returns:
+     *     An ordered list of filenames. If @maxCount > 0, the length of the returned list will be
+     * less than or equal to @maxCount.
+     *
+     * May return service-specific errors:
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the `readIntegrity` the
+     *       dir was opened with does not acknowledge
+     */
+    @utf8InCpp String[] readNextFilenames(int maxCount);
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/IFile.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/IFile.aidl
new file mode 100644
index 0000000..ff26aa4
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/IFile.aidl
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+import android.hardware.security.see.storage.CreationMode;
+
+/** The interface for an open file */
+interface IFile {
+    /**
+     * Read bytes from this file.
+     *
+     * @size:
+     *     the size (in bytes) of the segment to read. If @size is larger than the service's maximum
+     *       read size, the call will return an error (EX_ILLEGAL_ARGUMENT).
+     * @offset:
+     *     the offset (in bytes) at which to start reading
+     *
+     * Return:
+     *     the sequence of bytes at [offset, offset + size) in the file
+     *
+     * May return service-specific errors:
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the `readIntegrity` the
+     *       file was opened with does not acknowledge
+     */
+    byte[] read(long size, long offset);
+
+    /**
+     * Write the bytes in `buffer` to this file.
+     *
+     * @offset:
+     *     the offset (in bytes) at which to start writing
+     *
+     * Return:
+     *     the number of bytes written successfully
+     *
+     * May return service-specific errors:
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the `readIntegrity` the
+     *       file was opened with does not acknowledge
+     */
+    long write(long offset, in byte[] buffer);
+
+    /**
+     * Reads this file's size.
+     *
+     * May return service-specific errors:
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the `readIntegrity` the
+     *       file was opened with does not acknowledge
+     */
+    long getSize();
+
+    /**
+     * Sets this file's size.
+     *
+     * Truncates the file if `new_size` is less than the current size. If `new_size` is greater than
+     * the current size, the file will be extended with zeroed data.
+     *
+     * @newSize:
+     *     the file's new size
+     *
+     * May return service-specific errors:
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the `readIntegrity` the
+     *       file was opened with does not acknowledge
+     */
+    void setSize(long newSize);
+
+    /**
+     * Renames this file.
+     *
+     * @destPath:
+     *     the file's new path, relative to filesystem root
+     * @destCreateMode:
+     *     controls creation behavior of the dest file
+     *
+     * May return service-specific errors:
+     *   - ERR_NOT_FOUND if no file exists at @destPath and @destCreateMode is `NO_CREATE`
+     *   - ERR_ALREADY_EXISTS if a file already exists at @destPath and @destCreateMode is
+     *       `CREATE_EXCLUSIVE`
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that the `readIntegrity` the
+     *       file was opened with does not acknowledge
+     */
+    void rename(in @utf8InCpp String destPath, in CreationMode destCreateMode);
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/ISecureStorage.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/ISecureStorage.aidl
new file mode 100644
index 0000000..be3c045
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/ISecureStorage.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+import android.hardware.security.see.storage.FileProperties;
+import android.hardware.security.see.storage.IStorageSession;
+
+/**
+ * Interface for the Secure Storage HAL
+ *
+ * Creates sessions which can be used to access storage.
+ */
+interface ISecureStorage {
+    const int ERR_UNSUPPORTED_PROPERTIES = 1;
+    const int ERR_NOT_FOUND = 2;
+    const int ERR_ALREADY_EXISTS = 3;
+    const int ERR_BAD_TRANSACTION = 4;
+
+    const int ERR_FS_RESET = 5;
+    const int ERR_FS_ROLLED_BACK = 6;
+    const int ERR_FS_TAMPERED = 7;
+
+    /**
+     * Starts a storage session for a filesystem.
+     *
+     * @properties:
+     *     the minimum filesystem properties requested for the session.
+     *
+     * May return service-specific errors:
+     *   - ERR_UNSUPPORTED_PROPERTIES if no filesystems exist which meet the minimum requested
+     * requirements
+     */
+    IStorageSession startSession(in FileProperties properties);
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/IStorageSession.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/IStorageSession.aidl
new file mode 100644
index 0000000..cd126b8
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/IStorageSession.aidl
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+import android.hardware.security.see.storage.DeleteOptions;
+import android.hardware.security.see.storage.IDir;
+import android.hardware.security.see.storage.IFile;
+import android.hardware.security.see.storage.OpenOptions;
+import android.hardware.security.see.storage.ReadIntegrity;
+import android.hardware.security.see.storage.RenameOptions;
+
+/**
+ * Interface for a Secure Storage session
+ *
+ * When the connection is opened, it will start a transaction and any changes made through this
+ * session or the interfaces this session returns will be added to this transaction's pending
+ * changes. Calling `CommitChanges`/`AbandonChanges` will commit/abandon these pending changes, and
+ * start a new, empty transaction. The interfaces this session returns _remain_ valid across
+ * transactions; it is not necessary, for example, to reopen a file after a commit.
+ *
+ * Any changes still pending when the session is dropped will be abandoned.
+ */
+interface IStorageSession {
+    /**
+     * Commits any pending changes made through this session to storage.
+     *
+     * The session will no longer have pending changes after this call returns. Files may then still
+     * be modified through this session to create another commit.
+     *
+     * May return service-specific errors:
+     *   - ERR_BAD_TRANSACTION
+     */
+    void commitChanges();
+
+    /**
+     * Abandons any pending changes made through this session.
+     *
+     * The session can then be reused to make new changes.
+     */
+    void abandonChanges();
+
+    /**
+     * Opens a secure file for writing and/or reading.
+     *
+     * Changes made to the file are part of the current transaction. Dropping this session
+     * invalidates the returned `IFile` interface
+     *
+     * @filePath:
+     *     path to the file, relative to filesystem root
+     * @options:
+     *     options controlling opening behavior
+     *
+     * May return service-specific errors:
+     *   - ERR_NOT_FOUND
+     *   - ERR_ALREADY_EXISTS
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that @options.readIntegrity
+     *       does not acknowledge
+     */
+    IFile openFile(in @utf8InCpp String filePath, in OpenOptions options);
+
+    /**
+     * Delete a file.
+     *
+     * @filePath:
+     *     path to the file, relative to filesystem root
+     * @options:
+     *     options controlling deletion behavior
+     *
+     * May return service-specific errors:
+     *   - ERR_NOT_FOUND
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that @options.readIntegrity
+     *       does not acknowledge
+     */
+    void deleteFile(in @utf8InCpp String filePath, in DeleteOptions options);
+
+    /**
+     * Renames an existing file.
+     *
+     * The file must not already be opened. (If it is, use `IFile::rename`.)
+     *
+     * @currentPath:
+     *     path to the file, relative to filesystem root
+     * @destPath:
+     *     the file's new path, relative to filesystem root
+     * @options:
+     *     options controlling rename behavior
+     *
+     * May return service-specific errors:
+     *   - ERR_NOT_FOUND if no file exists at @currentPath, or if @options.destCreateMode is
+     *       `NO_CREATE` and no file exists at @destPath
+     *   - ERR_ALREADY_EXISTS if @options.destCreateMode is `CREATE_EXCLUSIVE` and a file exists at
+     *       @destPath
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that @options.readIntegrity
+     *       does not acknowledge
+     */
+    void renameFile(in @utf8InCpp String currentPath, in @utf8InCpp String destPath,
+            in RenameOptions options);
+
+    /**
+     * Opens a directory from a filesystem with the given properties.
+     *
+     * Dropping this session invalidates the returned `IDir` interface.
+     *
+     * @path:
+     *     path to the directory, relative to filesystem root
+     * @readIntegrity:
+     *     allow opening (and subsequent read/write operations) despite possible tampering for the
+     * directory
+     *
+     * May return service-specific errors:
+     *   - ERR_NOT_FOUND
+     *   - ERR_FS_* if the filesystem has been tampered with in a way that @readIntegrity does not
+     *       acknowledge
+     */
+    IDir openDir(in @utf8InCpp String path, in ReadIntegrity readIntegrity);
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/OpenOptions.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/OpenOptions.aidl
new file mode 100644
index 0000000..997ca62
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/OpenOptions.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+import android.hardware.security.see.storage.CreationMode;
+import android.hardware.security.see.storage.FileMode;
+import android.hardware.security.see.storage.ReadIntegrity;
+
+parcelable OpenOptions {
+    /** Controls creation behavior of the to-be-opened file. See `CreationMode` docs for details. */
+    CreationMode createMode = CreationMode.NO_CREATE;
+
+    /** Controls access behavior of the to-be-opened file. See `FileMode` docs for details. */
+    FileMode accessMode = FileMode.READ_WRITE;
+
+    /**
+     * Set to acknowledge possible files tampering.
+     *
+     * If unacknowledged tampering is detected, the operation will fail with an ERR_FS_*
+     * service-specific code.
+     */
+    ReadIntegrity readIntegrity = ReadIntegrity.NO_TAMPER;
+
+    /**
+     * If this file already exists, discard existing content and open
+     * it as a new file. No semantic change if the file does not exist.
+     */
+    boolean truncateOnOpen;
+
+    /**
+     * Allow writes to succeed while the filesystem is in the middle of an A/B update.
+     *
+     * If the A/B update fails, the operation will be rolled back. This rollback will not
+     * cause subsequent operations fail with any ERR_FS_* code nor will need to be
+     * acknowledged by setting the `readIntegrity`.
+     */
+    boolean allowWritesDuringAbUpdate = false;
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/ReadIntegrity.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/ReadIntegrity.aidl
new file mode 100644
index 0000000..cc0e4f9
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/ReadIntegrity.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+enum ReadIntegrity {
+    /**
+     * Return an error on reads if any REE alteration of the written data
+     * has been detected.
+     */
+    NO_TAMPER,
+
+    /**
+     * Return an error on reads if any REE alteration other than a reset
+     * has been detected.
+     */
+    IGNORE_RESET,
+
+    /**
+     * Return an error if any REE alteration other than a rollback to a
+     * valid checkpoint has been detected. (What makes a checkpoint valid is
+     * implementation defined; an implementation might take a checkpoint on its
+     * first post-factory boot. A reset is a rollback to the initial state.)
+     */
+    IGNORE_ROLLBACK,
+
+    // There's no `IGNORE_ALL` because if REE has done any alteration other
+    // than a rollback, the file contents will be known-bad data.
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/RenameOptions.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/RenameOptions.aidl
new file mode 100644
index 0000000..f55ea7f
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/RenameOptions.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+import android.hardware.security.see.storage.CreationMode;
+import android.hardware.security.see.storage.ReadIntegrity;
+
+parcelable RenameOptions {
+    /** Controls creation behavior of the dest file. See `CreationMode` docs for details. */
+    CreationMode destCreateMode = CreationMode.CREATE_EXCLUSIVE;
+
+    /**
+     * Set to acknowledge possible files tampering.
+     *
+     * If unacknowledged tampering is detected, the operation will fail with an ERR_FS_*
+     * service-specific code.
+     */
+    ReadIntegrity readIntegrity = ReadIntegrity.NO_TAMPER;
+
+    /**
+     * Allow writes to succeed while the filesystem is in the middle of an A/B update.
+     *
+     * If the A/B update fails, the operation will be rolled back. This rollback will not
+     * cause subsequent operations fail with any ERR_FS_* code nor will need to be
+     * acknowledged by setting the `readIntegrity`.
+     */
+    boolean allowWritesDuringAbUpdate = false;
+}
diff --git a/staging/security/see/storage/aidl/android/hardware/security/see/storage/Tamper.aidl b/staging/security/see/storage/aidl/android/hardware/security/see/storage/Tamper.aidl
new file mode 100644
index 0000000..0a39fdd
--- /dev/null
+++ b/staging/security/see/storage/aidl/android/hardware/security/see/storage/Tamper.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.security.see.storage;
+
+/** Specifies types of REE tampering the filesystem may detect */
+enum Tamper {
+    /** REE has reset this file or the containing file system. */
+    RESET,
+
+    /** REE has rolled back this file or the containing file system to a previous state. */
+    ROLLBACK,
+
+    /** REE has made some other modification to the file. */
+    OTHER,
+}
diff --git a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
index fa7149f..e456e49 100644
--- a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
@@ -74,7 +74,17 @@
         return testing::deviceSupportsFeature("com.google.android.tv.mdns_offload");
     }
 
-    // Detected panel TV device by using ro.oem.key1 property.
+    bool doesDeviceSupportFullNetworkingUnder2w() {
+        return testing::deviceSupportsFeature("com.google.android.tv.full_networking_under_2w");
+    }
+
+    // Detect TV devices.
+    bool isTvDevice() {
+        return testing::deviceSupportsFeature("android.software.leanback") ||
+               testing::deviceSupportsFeature("android.hardware.type.television");
+    }
+
+    // Detect Panel TV devices by using ro.oem.key1 property.
     // https://docs.partner.android.com/tv/build/platform/props-vars/ro-oem-key1
     bool isPanelTvDevice() {
         const std::string oem_key1 = getPropertyString("ro.oem.key1");
@@ -135,10 +145,23 @@
  */
 // @VsrTest = 5.3.12
 TEST_P(WifiStaIfaceAidlTest, CheckApfIsSupported) {
-    // Flat panel TV devices that support MDNS offload do not have to implement APF if the WiFi
-    // chipset does not have sufficient RAM to do so.
-    if (isPanelTvDevice() && isMdnsOffloadPresentInNIC()) {
-        GTEST_SKIP() << "Panel TV supports mDNS offload. It is not required to support APF";
+    const std::string oem_key1 = getPropertyString("ro.oem.key1");
+    if (isTvDevice()) {
+        // Flat panel TV devices that support MDNS offload do not have to implement APF if the WiFi
+        // chipset does not have sufficient RAM to do so.
+        if (isPanelTvDevice() && isMdnsOffloadPresentInNIC()) {
+            GTEST_SKIP() << "Panel TV supports mDNS offload. It is not required to support APF";
+        }
+        // For TV devices declaring the
+        // com.google.android.tv.full_networking_under_2w feature, this indicates
+        // the device can meet the <= 2W standby power requirement while
+        // continuously processing network packets on the CPU, even in standby mode.
+        // In these cases, APF support is strongly recommended rather than being
+        // mandatory.
+        if (doesDeviceSupportFullNetworkingUnder2w()) {
+            GTEST_SKIP() << "TV Device meets the <= 2W standby power demand requirement. It is not "
+                            "required to support APF.";
+        }
     }
     int vendor_api_level = property_get_int32("ro.vendor.api_level", 0);
     // Before VSR 14, APF support is optional.