Merge "Try to fix some builds."
diff --git a/broadcastradio/1.2/Android.bp b/broadcastradio/1.2/Android.bp
index 913da8c..40eb4e0 100644
--- a/broadcastradio/1.2/Android.bp
+++ b/broadcastradio/1.2/Android.bp
@@ -18,6 +18,7 @@
         "android.hidl.base@1.0",
     ],
     types: [
+        "IdentifierType",
     ],
     gen_java: false,
 }
diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
index d3b0f1d..193253a 100644
--- a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
+++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
@@ -223,12 +223,26 @@
     sp<ICas> mMediaCas;
     sp<IDescramblerBase> mDescramblerBase;
     sp<MediaCasListener> mCasListener;
+    typedef struct _OobInputTestParams {
+        const SubSample* subSamples;
+        uint32_t numSubSamples;
+        size_t imemSizeActual;
+        uint64_t imemOffset;
+        uint64_t imemSize;
+        uint64_t srcOffset;
+        uint64_t dstOffset;
+    } OobInputTestParams;
 
     ::testing::AssertionResult createCasPlugin(int32_t caSystemId);
     ::testing::AssertionResult openCasSession(std::vector<uint8_t>* sessionId);
-    ::testing::AssertionResult descrambleTestInputBuffer(const sp<IDescrambler>& descrambler,
-                                                         Status* descrambleStatus,
-                                                         sp<IMemory>* hidlInMemory);
+    ::testing::AssertionResult descrambleTestInputBuffer(
+            const sp<IDescrambler>& descrambler,
+            Status* descrambleStatus,
+            sp<IMemory>* hidlInMemory);
+    ::testing::AssertionResult descrambleTestOobInput(
+            const sp<IDescrambler>& descrambler,
+            Status* descrambleStatus,
+            const OobInputTestParams& params);
 };
 
 ::testing::AssertionResult MediaCasHidlTest::createCasPlugin(int32_t caSystemId) {
@@ -332,6 +346,72 @@
     return ::testing::AssertionResult(returnVoid.isOk());
 }
 
+::testing::AssertionResult MediaCasHidlTest::descrambleTestOobInput(
+        const sp<IDescrambler>& descrambler,
+        Status* descrambleStatus,
+        const OobInputTestParams& params) {
+    hidl_vec<SubSample> hidlSubSamples;
+    hidlSubSamples.setToExternal(
+            const_cast<SubSample*>(params.subSamples), params.numSubSamples, false /*own*/);
+
+    sp<MemoryDealer> dealer = new MemoryDealer(params.imemSizeActual, "vts-cas");
+    if (nullptr == dealer.get()) {
+        ALOGE("couldn't get MemoryDealer!");
+        return ::testing::AssertionFailure();
+    }
+
+    sp<IMemory> mem = dealer->allocate(params.imemSizeActual);
+    if (nullptr == mem.get()) {
+        ALOGE("couldn't allocate IMemory!");
+        return ::testing::AssertionFailure();
+    }
+
+    // build hidl_memory from memory heap
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+    if (nullptr == heap.get()) {
+        ALOGE("couldn't get memory heap!");
+        return ::testing::AssertionFailure();
+    }
+
+    native_handle_t* nativeHandle = native_handle_create(1, 0);
+    if (!nativeHandle) {
+        ALOGE("failed to create native handle!");
+        return ::testing::AssertionFailure();
+    }
+    nativeHandle->data[0] = heap->getHeapID();
+
+    SharedBuffer srcBuffer = {
+            .heapBase = hidl_memory("ashmem", hidl_handle(nativeHandle), heap->getSize()),
+            .offset = (uint64_t) offset + params.imemOffset,
+            .size = (uint64_t) params.imemSize,
+    };
+
+    DestinationBuffer dstBuffer;
+    dstBuffer.type = BufferType::SHARED_MEMORY;
+    dstBuffer.nonsecureMemory = srcBuffer;
+
+    uint32_t outBytes;
+    hidl_string detailedError;
+    auto returnVoid = descrambler->descramble(
+        ScramblingControl::EVENKEY /*2*/, hidlSubSamples,
+        srcBuffer,
+        params.srcOffset,
+        dstBuffer,
+        params.dstOffset,
+        [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) {
+            *descrambleStatus = status;
+            outBytes = bytesWritten;
+            detailedError = detailedErr;
+        });
+    if (!returnVoid.isOk() || *descrambleStatus != Status::OK) {
+        ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s",
+              returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str());
+    }
+    return ::testing::AssertionResult(returnVoid.isOk());
+}
+
 TEST_F(MediaCasHidlTest, EnumeratePlugins) {
     description("Test enumerate plugins");
     hidl_vec<HidlCasPluginDescriptor> descriptors;
@@ -613,6 +693,153 @@
     EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("bad"));
 }
 
+TEST_F(MediaCasHidlTest, TestClearKeyOobFails) {
+    description("Test that oob descramble request fails with expected error");
+
+    ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+    auto returnStatus = mMediaCas->provision(hidl_string(PROVISION_STR));
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    std::vector<uint8_t> sessionId;
+    ASSERT_TRUE(openCasSession(&sessionId));
+
+    returnStatus = mDescramblerBase->setMediaCasSession(sessionId);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    hidl_vec<uint8_t> hidlEcm;
+    hidlEcm.setToExternal(const_cast<uint8_t*>(kEcmBinaryBuffer), sizeof(kEcmBinaryBuffer));
+    returnStatus = mMediaCas->processEcm(sessionId, hidlEcm);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    sp<IDescrambler> descrambler = IDescrambler::castFrom(mDescramblerBase);
+    ASSERT_NE(nullptr, descrambler.get());
+
+    Status descrambleStatus = Status::OK;
+
+    // test invalid src buffer offset
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = kSubSamples,
+                .numSubSamples  = sizeof(kSubSamples)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 0xcccccc,
+                .imemSize       = sizeof(kInBinaryBuffer),
+                .srcOffset      = 0,
+                .dstOffset      = 0
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    // test invalid src buffer size
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = kSubSamples,
+                .numSubSamples  = sizeof(kSubSamples)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 0,
+                .imemSize       = 0xcccccc,
+                .srcOffset      = 0,
+                .dstOffset      = 0
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    // test invalid src buffer size
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = kSubSamples,
+                .numSubSamples  = sizeof(kSubSamples)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 1,
+                .imemSize       = (uint64_t)-1,
+                .srcOffset      = 0,
+                .dstOffset      = 0
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    // test invalid srcOffset
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = kSubSamples,
+                .numSubSamples  = sizeof(kSubSamples)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 0,
+                .imemSize       = sizeof(kInBinaryBuffer),
+                .srcOffset      = 0xcccccc,
+                .dstOffset      = 0
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    // test invalid dstOffset
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = kSubSamples,
+                .numSubSamples  = sizeof(kSubSamples)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 0,
+                .imemSize       = sizeof(kInBinaryBuffer),
+                .srcOffset      = 0,
+                .dstOffset      = 0xcccccc
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    // test detection of oob subsample sizes
+    const SubSample invalidSubSamples1[] =
+        {{162, 0}, {0, 184}, {0, 0xdddddd}};
+
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = invalidSubSamples1,
+                .numSubSamples  = sizeof(invalidSubSamples1)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 0,
+                .imemSize       = sizeof(kInBinaryBuffer),
+                .srcOffset      = 0,
+                .dstOffset      = 0
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    // test detection of overflowing subsample sizes
+    const SubSample invalidSubSamples2[] =
+        {{162, 0}, {0, 184}, {2, (uint32_t)-1}};
+
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = invalidSubSamples2,
+                .numSubSamples  = sizeof(invalidSubSamples2)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 0,
+                .imemSize       = sizeof(kInBinaryBuffer),
+                .srcOffset      = 0,
+                .dstOffset      = 0
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    returnStatus = mDescramblerBase->release();
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    returnStatus = mMediaCas->release();
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+}
+
 }  // anonymous namespace
 
 int main(int argc, char** argv) {
diff --git a/contexthub/1.0/default/Contexthub.cpp b/contexthub/1.0/default/Contexthub.cpp
index 8d10c75..5f83a22 100644
--- a/contexthub/1.0/default/Contexthub.cpp
+++ b/contexthub/1.0/default/Contexthub.cpp
@@ -281,11 +281,11 @@
                 result = TransactionResult::FAILURE;
             }
 
+            mIsTransactionPending = false;
             if (cb != nullptr) {
                 cb->handleTxnResult(mTransactionId, result);
             }
             retVal = 0;
-            mIsTransactionPending = false;
             break;
         }
 
@@ -383,6 +383,7 @@
 
         msg.appName = rxMsg->app_name.id;
         msg.msgType = rxMsg->message_type;
+        msg.hostEndPoint = static_cast<uint16_t>(HostEndPoint::BROADCAST);
         msg.msg = std::vector<uint8_t>(static_cast<const uint8_t *>(rxMsg->message),
                                        static_cast<const uint8_t *>(rxMsg->message) +
                                        rxMsg->message_len);
diff --git a/keymaster/4.0/Android.bp b/keymaster/4.0/Android.bp
index 34997d2..378204a 100644
--- a/keymaster/4.0/Android.bp
+++ b/keymaster/4.0/Android.bp
@@ -16,12 +16,10 @@
     ],
     types: [
         "HardwareAuthToken",
-        "HardwareAuthTokenMacMethod",
         "KeyCharacteristics",
         "KeyParameter",
         "KeyPurpose",
         "Tag",
-        "TagType",
     ],
     gen_java: false,
 }
diff --git a/keymaster/4.0/IKeymasterDevice.hal b/keymaster/4.0/IKeymasterDevice.hal
index 06b4b73..84354bf 100644
--- a/keymaster/4.0/IKeymasterDevice.hal
+++ b/keymaster/4.0/IKeymasterDevice.hal
@@ -26,22 +26,147 @@
 interface IKeymasterDevice {
 
     /**
-     * Returns information about the underlying keymaster hardware.
+     * Returns information about the underlying Keymaster hardware.
      *
-     * @return isSecure Indicates whether this keymaster implementation is in some sort of secure
-     *         hardware.
+     * @return security level of the Keymaster implementation accessed through this HAL.
      *
-     * @return keymasterName is the name of the keymaster implementation.
+     * @return keymasterName is the name of the Keymaster implementation.
      *
-     * @return keymasterAuthorName is the name of the author of the keymaster implementation
+     * @return keymasterAuthorName is the name of the author of the Keymaster implementation
      *         (organization name, not individual).
      */
-    getHardwareInfo() generates (bool isSecure, string keymasterName, string keymasterAuthorName);
+    getHardwareInfo()
+        generates (SecurityLevel securityLevel, string keymasterName, string keymasterAuthorName);
 
     /**
-     * Adds entropy to the RNG used by keymaster.  Entropy added through this method must not be the
-     * only source of entropy used.  The keymaster implementation must securely mix entropy provided
-     * through this method with internally-generated entropy.
+     * Start the creation of an HMAC key, shared with another Keymaster implementation.  Any device
+     * with a StrongBox Keymaster has two Keymaster instances, because there must be a TEE Keymaster
+     * as well.  The HMAC key used to MAC and verify authentication tokens must be shared between
+     * TEE and StrongBox so they can each validate tokens produced by the other.  This method is the
+     * first step in the process for for agreeing on a shared key.  It is called by Keystore during
+     * startup if and only if Keystore loads multiple Keymaster HALs.  Keystore calls it on each of
+     * the HAL instances and collects the results in preparation for the second step.
+     */
+    getHmacSharingParameters() generates (ErrorCode error, HmacSharingParameters params);
+
+    /**
+     * Complete the creation of an HMAC key, shared with another Keymaster implementation.  Any
+     * device with a StrongBox Keymaster has two Keymasters instances, because there must be a TEE
+     * Keymaster as well.  The HMAC key used to MAC and verify authentication tokens must be shared
+     * between TEE and StrongBox so they can each validate tokens produced by the other.  This
+     * method is the second and final step in the process for for agreeing on a shared key.  It is
+     * called by Keystore during startup if and only if Keystore loads multiple Keymaster HALs.
+     * Keystore calls it on each of the HAL instances, and sends to it all of the
+     * HmacSharingParameters returned by all HALs.
+     *
+     * This method computes the shared 32-byte HMAC ``H'' as follows (all Keymaster instances
+     * perform the same computation to arrive at the same result):
+     *
+     *     H = CKDF(key = K,
+     *              context = P1 || P2 || ... || Pn,
+     *              label = "KeymasterSharedMac")
+     *
+     * where:
+     *
+     *     ``CKDF'' is the standard AES-CMAC KDF from NIST SP 800-108 in counter mode (see Section
+     *           5.1 of the referenced publication).  ``key'', ``context'', and ``label'' are
+     *           defined in the standard.  The counter is prefixed, as shown in the construction on
+     *           page 12 of the standard.  The label string is UTF-8 encoded.
+     *
+     *     ``K'' is a pre-established shared secret, set up during factory reset.  The mechanism for
+     *           establishing this shared secret is implementation-defined, but see below for a
+     *           recommended approach, which assumes that the TEE Keymaster does not have storage
+     *           available to it, but the StrongBox Keymaster does.
+     *
+     *           <b>CRITICAL SECURITY REQUIREMENT</b>: All keys created by a Keymaster instance must
+     *           be cryptographically bound to the value of K, such that establishing a new K
+     *           permanently destroys them.
+     *
+     *     ``||'' represents concatenation.
+     *
+     *     ``Pi'' is the i'th HmacSharingParameters value in the params vector.  Note that at
+     *           present only two Keymaster implementations are supported, but this mechanism
+     *           extends without modification to any number of implementations.  Encoding of an
+     *           HmacSharingParameters is the concatenation of its two fields, i.e. seed || nonce.
+     *
+     * Process for establishing K:
+     *
+     *     Any method of securely establishing K that ensures that an attacker cannot obtain or
+     *     derive its value is acceptable.  What follows is a recommended approach, to be executed
+     *     during each factory reset.  It relies on use of the factory-installed attestation keys to
+     *     mitigate man-in-the-middle attacks.  This protocol requires that one of the instancess
+     *     have secure persistent storage.  This model was chosen because StrongBox has secure
+     *     persistent storage (by definition), but the TEE may not.  The instance without storage is
+     *     assumed to be able to derive a unique hardware-bound key (HBK) which is used only for
+     *     this purpose, and is not derivable outside of the secure environment..
+     *
+     *     In what follows, T is the Keymaster instance without storage, S is the Keymaster instance
+     *     with storage:
+     *
+     *     1. T generates an ephemeral EC P-256 key pair K1
+     *     2. T sends K1_pub to S, signed with T's attestation key.
+     *     3. S validates the signature on K1_pub.
+     *     4. S generates an ephemeral EC P-256 key pair K2.
+     *     5. S sends {K1_pub, K2_pub}, to T, signed with S's attestation key.
+     *     6. T validates the signature on {K1_pub, K2_pub}
+     *     7. T uses {K1_priv, K2_pub} with ECDH to compute session secret Q.
+     *     8. T generates a random seed S
+     *     9. T computes K = KDF(HBK, S), where KDF is some secure key derivation function.
+     *     10. T sends M = AES-GCM-ENCRYPT(Q, {S || K}) to S.
+     *     10. S uses {K2_priv, K1_pub} with ECDH to compute session secret Q.
+     *     11. S computes S || K = AES-GCM-DECRYPT(Q, M) and stores S and K.
+     *
+     *     When S receives the getHmacSharingParameters call, it returns the stored S as the seed
+     *     and a nonce.  When T receives the same call, it returns an empty seed and a nonce.  When
+     *     T receives the computeSharedHmac call, it uses the seed provided by S to compute K.  S,
+     *     of course, has K stored.
+     *
+     * @param params The HmacSharingParameters data returned by all Keymaster instances when
+     *        getHmacSharingParameters was called.
+     *
+     * @return sharingCheck A 32-byte value used to verify that all Keymaster instances have
+     *         computed the same shared HMAC key.  The sharingCheck value is computed as follows:
+     *
+     *             sharingCheck = HMAC(H, "Keymaster HMAC Verification")
+     *
+     *         The string is UTF-8 encoded.  If the returned values of all Keymaster instances don't
+     *         match, Keystore will assume that HMAC agreement failed.
+     */
+    computeSharedHmac(vec<HmacSharingParameters> params)
+        generates (ErrorCode error, vec<uint8_t> sharingCheck);
+
+    /**
+     * Verify authorizations for another Keymaster instance.
+     *
+     * On systems with both a StrongBox and a TEE Keymaster instance it is sometimes useful to ask
+     * the TEE Keymaster to verify authorizations for a key hosted in StrongBox.
+     *
+     * For every StrongBox operation, Keystore is required to call this method on the TEE Keymaster,
+     * passing in the StrongBox key's hardwareEnforced authorization list and the operation handle
+     * returned by StrongBox begin().  The TEE Keymaster must validate all of the authorizations it
+     * can and return those it validated in the VerificationToken.  If it cannot verify any, the
+     * parametersVerified field of the VerificationToken must be empty.  Keystore must then pass the
+     * VerificationToken to the subsequent invocations of StrongBox update() and finish().
+     *
+     * StrongBox implementations must return ErrorCode::UNIMPLEMENTED.
+     *
+     * @param operationHandle the operation handle returned by StrongBox Keymaster's begin().
+     *
+     * @param parametersToVerify Set of authorizations to verify.
+     *
+     * @param authToken A HardwareAuthToken if needed to authorize key usage.
+     */
+    verifyAuthorization(uint64_t operationHandle, vec<KeyParameter> parametersToVerify,
+                        HardwareAuthToken authToken)
+        generates (ErrorCode error, VerificationToken token);
+
+
+    /**
+     * Adds entropy to the RNG used by Keymaster.  Entropy added through this method is guaranteed
+     * not to be the only source of entropy used, and the mixing function is required to be secure,
+     * in the sense that if the RNG is seeded (from any source) with any data the attacker cannot
+     * predict (or control), then the RNG output is indistinguishable from random.  Thus, if the
+     * entropy from any source is good, the output must be good.
      *
      * @param data Bytes to be mixed into the RNG.
      *
@@ -52,7 +177,7 @@
     /**
      * Generates a key, or key pair, returning a key blob and a description of the key.
      *
-     * @param keyParams Key generation parameters are defined as keymaster tag/value pairs, provided
+     * @param keyParams Key generation parameters are defined as Keymaster tag/value pairs, provided
      *        in params.  See Tag in types.hal for the full list.
      *
      * @return error See the ErrorCode enum in types.hal.
@@ -70,7 +195,7 @@
     /**
      * Imports a key, or key pair, returning a key blob and/or a description of the key.
      *
-     * @param keyParams Key generation parameters are defined as keymaster tag/value pairs, provided
+     * @param keyParams Key generation parameters are defined as Keymaster tag/value pairs, provided
      *        in params.  See Tag for the full list.
      *
      * @param keyFormat The format of the key material to import.
@@ -89,6 +214,77 @@
         generates (ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
 
     /**
+     * Securely imports a key, or key pair, returning a key blob and a description of the imported
+     * key.
+     *
+     * @param wrappedKeyData The wrapped key material to import.  The wrapped key is in DER-encoded
+     * ASN.1 format, specified by the following schema:
+     *
+     *     KeyDescription ::= SEQUENCE(
+     *         keyFormat INTEGER,                   # Values from KeyFormat enum.
+     *         keyParams AuthorizationList,
+     *     )
+     *
+     *     SecureKeyWrapper ::= SEQUENCE(
+     *         version INTEGER,                     # Contains value 0
+     *         encryptedTransportKey OCTET_STRING,
+     *         initializationVector OCTET_STRING,
+     *         keyDescription KeyDescription,
+     *         encryptedKey OCTET_STRING,
+     *         tag OCTET_STRING
+     *     )
+     *
+     *     Where:
+     *
+     *     o keyFormat is an integer from the KeyFormat enum, defining the format of the plaintext
+     *       key material.
+     *     o keyParams is the characteristics of the key to be imported (as with generateKey or
+     *       importKey).  If the secure import is successful, these characteristics must be
+     *       associated with the key exactly as if the key material had been insecurely imported
+     *       with the @3.0::IKeymasterDevice::importKey.
+     *     o encryptedTransportKey is a 256-bit AES key, XORed with a masking key and then encrypted
+     *       in RSA-OAEP mode (SHA-256 digest, SHA-1 MGF1 digest) with the wrapping key specified by
+     *       wrappingKeyBlob.
+     *     o keyDescription is a KeyDescription, above.
+     *     o encryptedKey is the key material of the key to be imported, in format keyFormat, and
+     *       encrypted with encryptedEphemeralKey in AES-GCM mode, with the DER-encoded
+     *       representation of keyDescription provided as additional authenticated data.
+     *     o tag is the tag produced by the AES-GCM encryption of encryptedKey.
+     *
+     * So, importWrappedKey does the following:
+     *
+     *     1. Get the private key material for wrappingKeyBlob, verifying that the wrapping key has
+     *        purpose KEY_WRAP, padding mode RSA_OAEP, and digest SHA_2_256, returning the
+     *        appropriate error if any of those requirements fail.
+     *     2. Extract the encryptedTransportKey field from the SecureKeyWrapper, and decrypt
+     *        it with the wrapping key.
+     *     3. XOR the result of step 2 with maskingKey.
+     *     4. Use the result of step 3 as an AES-GCM key to decrypt encryptedKey, using the encoded
+     *        value of keyDescription as the additional authenticated data.  Call the result
+     *        "keyData" for the next step.
+     *     5. Perform the equivalent of calling importKey(keyParams, keyFormat, keyData), except
+     *        that the origin tag should be set to SECURELY_IMPORTED.
+     *
+     * @param wrappingKeyBlob The opaque key descriptor returned by generateKey() or importKey().
+     *        This key must have been created with Purpose::WRAP_KEY, and must be a key algorithm
+     *        that supports encryption and must be at least as strong (in key size) as the key to be
+     *        imported (per NIST key length recommendations: 112 bits symmetric is equivalent to
+     *        2048-bit RSA or 224-bit EC, 128 bits symmetric ~ 3072-bit RSA or 256-bit EC, etc.).
+     *
+     * @param maskingKey The 32-byte value XOR'd with the transport key in the SecureWrappedKey
+     *        structure.
+     *
+     * @return error See the ErrorCode enum.
+     *
+     * @return keyBlob Opaque descriptor of the imported key.  It is recommended that the keyBlob
+     *         contain a copy of the key material, wrapped in a key unavailable outside secure
+     *         hardware.
+     */
+    importWrappedKey(vec<uint8_t> wrappedKeyData, vec<uint8_t> wrappingKeyBlob,
+                     vec<uint8_t> maskingKey)
+        generates (ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
+
+    /**
      * Returns the characteristics of the specified key, if the keyBlob is valid (implementations
      * must fully validate the integrity of the key).
      *
@@ -139,7 +335,7 @@
 
     /**
      * Generates a signed X.509 certificate chain attesting to the presence of keyToAttest in
-     * keymaster.  The certificate must contain an extension with OID 1.3.6.1.4.1.11129.2.1.17 and
+     * Keymaster.  The certificate must contain an extension with OID 1.3.6.1.4.1.11129.2.1.17 and
      * value defined in:
      *
      *     https://developer.android.com/training/articles/security-key-attestation.html.
@@ -161,7 +357,7 @@
      * Upgrades an old key blob.  Keys can become "old" in two ways: Keymaster can be upgraded to a
      * new version with an incompatible key blob format, or the system can be updated to invalidate
      * the OS version and/or patch level.  In either case, attempts to use an old key blob with
-     * getKeyCharacteristics(), exportKey(), attestKey() or begin() must result in keymaster
+     * getKeyCharacteristics(), exportKey(), attestKey() or begin() must result in Keymaster
      * returning ErrorCode::KEY_REQUIRES_UPGRADE.  The caller must use this method to upgrade the
      * key blob.
      *
@@ -221,7 +417,7 @@
      * to update(), finish() or abort().
      *
      * It is critical that each call to begin() be paired with a subsequent call to finish() or
-     * abort(), to allow the keymaster implementation to clean up any internal operation state.  The
+     * abort(), to allow the Keymaster implementation to clean up any internal operation state.  The
      * caller's failure to do this may leak internal state space or other internal resources and may
      * eventually cause begin() to return ErrorCode::TOO_MANY_OPERATIONS when it runs out of space
      * for operations.  Any result other than ErrorCode::OK from begin(), update() or finish()
@@ -282,6 +478,10 @@
      * @param authToken Authentication token.  Callers that provide no token must set all numeric
      *        fields to zero and the MAC must be an empty vector.
      *
+     * @param verificationToken Verification token, used to prove that another Keymaster HAL has
+     *        verified some parameters, and to deliver the other HAL's current timestamp, if needed.
+     *        If not provided, all fields must be initialized to zero and vectors empty.
+     *
      * @return error See the ErrorCode enum in types.hal.
      *
      * @return inputConsumed Amount of data that was consumed by update().  If this is less than the
@@ -294,7 +494,7 @@
      * @return output The output data, if any.
      */
     update(OperationHandle operationHandle, vec<KeyParameter> inParams, vec<uint8_t> input,
-           HardwareAuthToken authToken)
+           HardwareAuthToken authToken, VerificationToken verificationToken)
         generates (ErrorCode error, uint32_t inputConsumed, vec<KeyParameter> outParams,
                    vec<uint8_t> output);
 
@@ -316,6 +516,10 @@
      * @param authToken Authentication token.  Callers that provide no token must set all numeric
      *        fields to zero and the MAC must be an empty vector.
      *
+     * @param verificationToken Verification token, used to prove that another Keymaster HAL has
+     *        verified some parameters, and to deliver the other HAL's current timestamp, if needed.
+     *        If not provided, all fields must be initialized to zero and vectors empty.
+     *
      * @return error See the ErrorCode enum in types.hal.
      *
      * @return outParams Any output parameters generated by finish().
@@ -323,7 +527,7 @@
      * @return output The output data, if any.
      */
     finish(OperationHandle operationHandle, vec<KeyParameter> inParams, vec<uint8_t> input,
-           vec<uint8_t> signature, HardwareAuthToken authToken)
+           vec<uint8_t> signature, HardwareAuthToken authToken, VerificationToken verificationToken)
         generates (ErrorCode error, vec<KeyParameter> outParams, vec<uint8_t> output);
 
     /**
diff --git a/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h b/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h
index 203b349..fae403a 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h
@@ -24,9 +24,6 @@
 namespace keymaster {
 namespace V4_0 {
 
-using V3_0::ErrorCode;
-using V3_0::SecurityLevel;
-
 class AuthorizationSet;
 
 /**
diff --git a/keymaster/4.0/support/include/keymasterV4_0/key_param_output.h b/keymaster/4.0/support/include/keymasterV4_0/key_param_output.h
index 04ba3a4..9736da0 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/key_param_output.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/key_param_output.h
@@ -50,14 +50,14 @@
     return os << toString(value);
 }
 
-inline ::std::ostream& operator<<(::std::ostream& os, KeyOrigin value) {
-    return os << toString(value);
-}
-
 }  // namespace V3_0
 
 namespace V4_0 {
 
+inline ::std::ostream& operator<<(::std::ostream& os, KeyOrigin value) {
+    return os << toString(value);
+}
+
 template <typename ValueT>
 ::std::ostream& operator<<(::std::ostream& os, const NullOr<ValueT>& value) {
     if (!value.isOk()) {
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index a3aae8b..e5187df 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -72,8 +72,8 @@
 using ::android::hardware::keymaster::V3_0::BlockMode;
 using ::android::hardware::keymaster::V3_0::Digest;
 using ::android::hardware::keymaster::V3_0::EcCurve;
+using ::android::hardware::keymaster::V3_0::HardwareAuthenticatorType;
 using ::android::hardware::keymaster::V3_0::KeyFormat;
-using ::android::hardware::keymaster::V3_0::KeyOrigin;
 using ::android::hardware::keymaster::V3_0::PaddingMode;
 using ::android::hardware::keymaster::V3_0::TagType;
 
diff --git a/keymaster/4.0/types.hal b/keymaster/4.0/types.hal
index b82848b..8ca2274 100644
--- a/keymaster/4.0/types.hal
+++ b/keymaster/4.0/types.hal
@@ -27,8 +27,24 @@
 import android.hardware.keymaster@3.0::KeyFormat;
 import android.hardware.keymaster@3.0::KeyOrigin;
 import android.hardware.keymaster@3.0::PaddingMode;
+import android.hardware.keymaster@3.0::SecurityLevel;
 import android.hardware.keymaster@3.0::TagType;
 
+/**
+ * Time in milliseconds since some arbitrary point in time.  Time must be monotonically increasing,
+ * and a secure environment's notion of "current time" must not repeat until the Android device
+ * reboots, or until at least 50 million years have elapsed (note that this requirement is satisfied
+ * by setting the clock to zero during each boot, and then counting time accurately).
+ */
+typedef uint64_t Timestamp;
+
+/**
+ * A place to define any needed constants.
+ */
+enum Constants : uint32_t {
+    AUTH_TOKEN_MAC_LENGTH = 32,
+};
+
 enum Tag : uint32_t {
     INVALID = TagType:INVALID | 0,
 
@@ -66,6 +82,14 @@
                                                    * resistance, it must return
                                                    * ROLLBACK_RESISTANCE_UNAVAILABLE. */
 
+    /* HARDWARE_TYPE specifies the type of the secure hardware that is requested for the key
+     * generation / import.  See the SecurityLevel enum.  In the absence of this tag, keystore must
+     * use TRUSTED_ENVIRONMENT.  If this tag is present and the requested hardware type is not
+     * available, Keymaster returns HARDWARE_TYPE_UNAVAILABLE. This tag is not included in
+     * attestations, but hardware type must be reflected in the Keymaster SecurityLevel of the
+     * attestation header. */
+    HARDWARE_TYPE = TagType:ENUM | 304,
+
     /**
      * Tags that should be semantically enforced by hardware if possible and will otherwise be
      * enforced by software (keystore).
@@ -151,6 +175,15 @@
 };
 
 /**
+ * The origin of a key, i.e. where it was generated.
+ */
+enum KeyOrigin : @3.0::KeyOrigin {
+    /** Securely imported into Keymaster.  Was created elsewhere, and passed securely through
+     *  Android to secure hardware. */
+    SECURELY_IMPORTED = 4,
+};
+
+/**
  * Possible purposes of a key (or pair).
  */
 enum KeyPurpose : uint32_t {
@@ -162,6 +195,54 @@
     WRAP_KEY = 5,   /* Usable with wrapping keys. */
 };
 
+/**
+ * Keymaster error codes.
+ */
+enum ErrorCode : @3.0::ErrorCode {
+    ROLLBACK_RESISTANCE_UNAVAILABLE = -67,
+    HARDWARE_TYPE_UNAVAILABLE = -68,
+};
+
+/**
+ * Device security levels.
+ */
+enum SecurityLevel : @3.0::SecurityLevel {
+    /**
+     * STRONGBOX specifies that the secure hardware satisfies the following requirements:
+     *
+     *    a) Has a discrete CPU.  The StrongBox device must not be the same CPU that is used to run
+     *       the Android non-secure world, or any other untrusted code.  The StrongBox CPU must not
+     *       share cache, RAM or any other critical resources with any device that runs untrusted
+     *       code.
+     *
+     *    b) Has integral secure storage.  The StrongBox device must have its own non-volatile
+     *       storage that is not accessible by any other hardware component.
+     *
+     *    c) Has a high-quality True Random Number Generator.  The StrongBox device must have sole
+     *       control of and access to a high-quality TRNG which it uses for generating necessary
+     *       random bits.  It must combine the output of this TRNG with caller-provided entropy in a
+     *       strong CPRNG, as do non-Strongbox Keymaster implementations.
+     *
+     *    d) Is enclosed in tamper-resistant packaging.  The StrongBox device must have
+     *       tamper-resistant packaging which provides obstacles to physical penetration which are
+     *       higher than those provided by normal integrated circuit packages.
+     *
+     *    e) Provides side-channel resistance.  The StrongBox device must implement resistance
+     *       against common side-channel attacks, including power analysis, timing analysis, EM
+     *       snooping, etc.
+     *
+     * Devices with StrongBox Keymasters must also have a non-StrongBox Keymaster, which lives in
+     * the higher-performance TEE.  Keystore must load both StrongBox (if available) and
+     * non-StrongBox HALs and route key generation/import requests appropriately.  Callers that want
+     * StrongBox keys must add Tag::HARDWARE_TYPE with value SecurityLevel::STRONGBOX to the key
+     * description provided to generateKey or importKey.  Keytore must route the request to a
+     * StrongBox HAL (a HAL whose isStrongBox method returns true).  Keymaster implementations that
+     * receive a request for a Tag::HARDWARE_TYPE that is inappropriate must fail with
+     * ErrorCode::HARDWARE_TYPE_UNAVAILABLE.
+     */
+    STRONGBOX = 2,              /* See IKeymaster::isStrongBox */
+};
+
 struct KeyParameter {
     /**
      * Discriminates the uinon/blob field used.  The blob cannot be coincided with the union, but
@@ -179,6 +260,7 @@
         KeyPurpose purpose;
         KeyDerivationFunction keyDerivationFunction;
         HardwareAuthenticatorType hardwareAuthenticatorType;
+        SecurityLevel hardwareType;
 
         /** Other types */
         bool boolValue;  // Always true, if a boolean tag is present.
@@ -203,21 +285,100 @@
     uint64_t userId;             // Secure User ID, not Android user ID.
     uint64_t authenticatorId;    // Secure authenticator ID.
     HardwareAuthenticatorType authenticatorType;
-    uint64_t timestamp;
+    Timestamp timestamp;
     /**
      * MACs are computed with a backward-compatible method, used by Keymaster 3.0, Gatekeeper 1.0
      * and Fingerprint 1.0, as well as pre-treble HALs.
      *
-     * The MAC is 32 bytes in length and is computed as follows:
+     * The MAC is Constants::AUTH_TOKEN_MAC_LENGTH bytes in length and is computed as follows:
      *
-     *     HMAC(H, 0 || challenge || user_id || authenticator_id || authenticator_type || timestamp)
+     *     HMAC_SHA256(
+     *         H, 0 || challenge || user_id || authenticator_id || authenticator_type || timestamp)
      *
      * where ``||'' represents concatenation, the leading zero is a single byte, and all integers
      * are represented as unsigned values, the full width of the type.  The challenge, userId and
      * authenticatorId values are in machine order, but authenticatorType and timestamp are in
      * network order.  This odd construction is compatible with the hw_auth_token_t structure,
+     *
+     * Note that mac is a vec rather than an array, not because it's actually variable-length but
+     * because it could be empty.  As documented in the IKeymasterDevice::begin,
+     * IKeymasterDevice::update and IKeymasterDevice::finish doc comments, an empty mac indicates
+     * that this auth token is empty.
      */
-    uint8_t[32] mac;
+    vec<uint8_t> mac;
 };
 
 typedef uint64_t OperationHandle;
+
+/**
+ * HmacSharingParameters holds the data used in the process of establishing a shared HMAC key
+ * between multiple Keymaster instances.  Sharing parameters are returned in this struct by
+ * getHmacSharingParameters() and send to computeSharedHmac().  See the named methods in IKeymaster
+ * for details of usage.
+ */
+struct HmacSharingParameters {
+    /**
+     * Either empty or contains a persistent value that is associated with the pre-shared HMAC
+     * agreement key (see documentation of computeSharedHmac in @4.0::IKeymaster).  It is either
+     * empty or 32 bytes in length.
+     */
+    vec<uint8_t> seed;
+
+    /**
+     * A 32-byte value which is guaranteed to be different each time
+     * getHmacSharingParameters() is called.  Probabilistic uniqueness (i.e. random) is acceptable,
+     * though a stronger uniqueness guarantee (e.g. counter) is recommended where possible.
+     */
+    uint8_t[32] nonce;
+};
+
+/**
+ * VerificationToken enables one Keymaster instance to validate authorizations for another.  See
+ * verifyAuthorizations() in IKeymaster for details.
+ */
+struct VerificationToken {
+    /**
+     * The operation handle, used to ensure freshness.
+     */
+    uint64_t challenge;
+
+    /**
+     * The current time of the secure environment that generates the VerificationToken.  This can be
+     * checked against auth tokens generated by the same secure environment, which avoids needing to
+     * synchronize clocks.
+     */
+    Timestamp timestamp;
+
+    /**
+     * A list of the parameters verified.  Empty if the only parameters verified are time-related.
+     * In that case the timestamp is the payload.
+     */
+    vec<KeyParameter> parametersVerified;
+
+    /**
+     * SecurityLevel of the secure environment that generated the token.
+     */
+    SecurityLevel securityLevel;
+
+    /**
+     * 32-byte HMAC of the above values, computed as:
+     *
+     *    HMAC(H,
+     *         "Auth Verification" || challenge || timestamp || securityLevel || parametersVerified)
+     *
+     * where:
+     *
+     *   ``HMAC'' is the shared HMAC key (see computeSharedHmac() in IKeymaster).
+     *
+     *   ``||'' represents concatenation
+     *
+     * The representation of challenge and timestamp is as 64-bit unsigned integers in big-endian
+     * order.  securityLevel is represented as a 32-bit unsigned integer in big-endian order.
+     *
+     * If parametersVerified is non-empty, the representation of parametersVerified is an ASN.1 DER
+     * encoded representation of the values.  The ASN.1 schema used is the AuthorizationList schema
+     * from the Keystore attestation documentation.  If parametersVerified is empty, it is simply
+     * omitted from the HMAC computation.
+     */
+    vec<uint8_t> mac;
+};
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 38dd302..c8858de 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -138,6 +138,8 @@
             return a.f.integer == b.f.integer;
         case Tag::ORIGIN:
             return a.f.origin == b.f.origin;
+        case Tag::HARDWARE_TYPE:
+            return a.f.hardwareType == b.f.hardwareType;
     }
 
     return false;
@@ -435,9 +437,9 @@
         ASSERT_NE(keymaster_, nullptr);
 
         ASSERT_TRUE(keymaster_
-                        ->getHardwareInfo([&](bool is_secure, const hidl_string& name,
+                        ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
                                               const hidl_string& author) {
-                            is_secure_ = is_secure;
+                            securityLevel_ = securityLevel;
                             name_ = name;
                             author_ = author;
                         })
@@ -617,7 +619,7 @@
         ErrorCode error;
         EXPECT_TRUE(keymaster_
                         ->update(op_handle, in_params.hidl_data(), HidlBuf(input),
-                                 HardwareAuthToken(),
+                                 HardwareAuthToken(), VerificationToken(),
                                  [&](ErrorCode hidl_error, uint32_t hidl_input_consumed,
                                      const hidl_vec<KeyParameter>& hidl_out_params,
                                      const HidlBuf& hidl_output) {
@@ -647,7 +649,7 @@
         EXPECT_TRUE(
             keymaster_
                 ->finish(op_handle, in_params.hidl_data(), HidlBuf(input), HidlBuf(signature),
-                         HardwareAuthToken(),
+                         HardwareAuthToken(), VerificationToken(),
                          [&](ErrorCode hidl_error, const hidl_vec<KeyParameter>& hidl_out_params,
                              const HidlBuf& hidl_output) {
                              error = hidl_error;
@@ -869,7 +871,7 @@
         return retval;
     }
 
-    static bool IsSecure() { return is_secure_; }
+    static bool IsSecure() { return securityLevel_ != SecurityLevel::SOFTWARE; }
 
     HidlBuf key_blob_;
     KeyCharacteristics key_characteristics_;
@@ -880,7 +882,7 @@
     static uint32_t os_version_;
     static uint32_t os_patch_level_;
 
-    static bool is_secure_;
+    static SecurityLevel securityLevel_;
     static hidl_string name_;
     static hidl_string author_;
 };
@@ -947,7 +949,7 @@
 sp<IKeymasterDevice> KeymasterHidlTest::keymaster_;
 uint32_t KeymasterHidlTest::os_version_;
 uint32_t KeymasterHidlTest::os_patch_level_;
-bool KeymasterHidlTest::is_secure_;
+SecurityLevel KeymasterHidlTest::securityLevel_;
 hidl_string KeymasterHidlTest::name_;
 hidl_string KeymasterHidlTest::author_;
 
diff --git a/tests/memory/1.0/Android.bp b/tests/memory/1.0/Android.bp
index 5038664..cbee247 100644
--- a/tests/memory/1.0/Android.bp
+++ b/tests/memory/1.0/Android.bp
@@ -7,9 +7,9 @@
         "IMemoryTest.hal",
     ],
     interfaces: [
-        "android.hidl.memory.token@1.0",
-        "android.hidl.memory.block@1.0",
         "android.hidl.base@1.0",
+        "android.hidl.memory.block@1.0",
+        "android.hidl.memory.token@1.0",
     ],
     gen_java: false,
 }
diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp
index 79fdfdc..4e2191d 100644
--- a/wifi/1.2/default/wifi_chip.cpp
+++ b/wifi/1.2/default/wifi_chip.cpp
@@ -71,6 +71,7 @@
 namespace V1_2 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
+using hidl_return_util::validateAndCallWithLock;
 
 WifiChip::WifiChip(
     ChipId chip_id, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
@@ -121,9 +122,9 @@
 
 Return<void> WifiChip::configureChip(ChipModeId mode_id,
                                      configureChip_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::configureChipInternal, hidl_status_cb,
-                           mode_id);
+    return validateAndCallWithLock(
+        this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+        &WifiChip::configureChipInternal, hidl_status_cb, mode_id);
 }
 
 Return<void> WifiChip::getMode(getMode_cb hidl_status_cb) {
@@ -397,7 +398,9 @@
             {sta_chip_mode, ap_chip_mode}};
 }
 
-WifiStatus WifiChip::configureChipInternal(ChipModeId mode_id) {
+WifiStatus WifiChip::configureChipInternal(
+    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+    ChipModeId mode_id) {
     if (mode_id != kStaChipModeId && mode_id != kApChipModeId) {
         return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
     }
@@ -405,7 +408,7 @@
         LOG(DEBUG) << "Already in the specified mode " << mode_id;
         return createWifiStatus(WifiStatusCode::SUCCESS);
     }
-    WifiStatus status = handleChipConfiguration(mode_id);
+    WifiStatus status = handleChipConfiguration(lock, mode_id);
     if (status.code != WifiStatusCode::SUCCESS) {
         for (const auto& callback : event_cb_handler_.getCallbacks()) {
             if (!callback->onChipReconfigureFailure(status).isOk()) {
@@ -421,6 +424,7 @@
         }
     }
     current_mode_id_ = mode_id;
+    LOG(INFO) << "Configured chip in mode " << mode_id;
     return status;
 }
 
@@ -792,15 +796,22 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
-WifiStatus WifiChip::handleChipConfiguration(ChipModeId mode_id) {
+WifiStatus WifiChip::handleChipConfiguration(
+    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+    ChipModeId mode_id) {
     // If the chip is already configured in a different mode, stop
     // the legacy HAL and then start it after firmware mode change.
-    // Currently the underlying implementation has a deadlock issue.
-    // We should return ERROR_NOT_SUPPORTED if chip is already configured in
-    // a different mode.
     if (current_mode_id_ != kInvalidModeId) {
-        // TODO(b/37446050): Fix the deadlock.
-        return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+        LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_
+                  << " to mode " << mode_id;
+        invalidateAndRemoveAllIfaces();
+        legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->stop(lock, []() {});
+        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+            LOG(ERROR) << "Failed to stop legacy HAL: "
+                       << legacyErrorToString(legacy_status);
+            return createWifiStatusFromLegacyError(legacy_status);
+        }
     }
     bool success;
     if (mode_id == kStaChipModeId) {
diff --git a/wifi/1.2/default/wifi_chip.h b/wifi/1.2/default/wifi_chip.h
index 8cb15bb..ac59d59 100644
--- a/wifi/1.2/default/wifi_chip.h
+++ b/wifi/1.2/default/wifi_chip.h
@@ -141,7 +141,8 @@
         const sp<IWifiChipEventCallback>& event_callback);
     std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
     std::pair<WifiStatus, std::vector<ChipMode>> getAvailableModesInternal();
-    WifiStatus configureChipInternal(ChipModeId mode_id);
+    WifiStatus configureChipInternal(
+        std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
     std::pair<WifiStatus, uint32_t> getModeInternal();
     std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
     requestChipDebugInfoInternal();
@@ -185,7 +186,8 @@
     WifiStatus selectTxPowerScenarioInternal(TxPowerScenario scenario);
     WifiStatus resetTxPowerScenarioInternal();
 
-    WifiStatus handleChipConfiguration(ChipModeId mode_id);
+    WifiStatus handleChipConfiguration(
+        std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
     WifiStatus registerDebugRingBufferCallback();
 
     ChipId chip_id_;
diff --git a/wifi/1.2/default/wifi_legacy_hal.cpp b/wifi/1.2/default/wifi_legacy_hal.cpp
index 8289c67..24b80d5 100644
--- a/wifi/1.2/default/wifi_legacy_hal.cpp
+++ b/wifi/1.2/default/wifi_legacy_hal.cpp
@@ -309,6 +309,15 @@
         on_nan_event_range_report_user_callback(*event);
     }
 }
+
+std::function<void(const NanDataPathScheduleUpdateInd&)>
+    on_nan_event_schedule_update_user_callback;
+void onAsyncNanEventScheduleUpdate(NanDataPathScheduleUpdateInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_schedule_update_user_callback && event) {
+        on_nan_event_schedule_update_user_callback(*event);
+    }
+}
 // End of the free-standing "C" style callbacks.
 
 WifiLegacyHal::WifiLegacyHal()
@@ -1061,6 +1070,8 @@
         user_callbacks.on_event_range_request;
     on_nan_event_range_report_user_callback =
         user_callbacks.on_event_range_report;
+    on_nan_event_schedule_update_user_callback =
+        user_callbacks.on_event_schedule_update;
 
     return global_func_table_.wifi_nan_register_handler(
         getIfaceHandle(iface_name),
@@ -1072,7 +1083,7 @@
          onAysncNanEventBeaconSdfPayload, onAysncNanEventDataPathRequest,
          onAysncNanEventDataPathConfirm, onAysncNanEventDataPathEnd,
          onAysncNanEventTransmitFollowUp, onAysncNanEventRangeRequest,
-         onAysncNanEventRangeReport});
+         onAysncNanEventRangeReport, onAsyncNanEventScheduleUpdate});
 }
 
 wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name,
@@ -1330,6 +1341,7 @@
     on_nan_event_transmit_follow_up_user_callback = nullptr;
     on_nan_event_range_request_user_callback = nullptr;
     on_nan_event_range_report_user_callback = nullptr;
+    on_nan_event_schedule_update_user_callback = nullptr;
 }
 
 }  // namespace legacy_hal
diff --git a/wifi/1.2/default/wifi_legacy_hal.h b/wifi/1.2/default/wifi_legacy_hal.h
index 193928b..05f700e 100644
--- a/wifi/1.2/default/wifi_legacy_hal.h
+++ b/wifi/1.2/default/wifi_legacy_hal.h
@@ -100,6 +100,7 @@
         on_event_transmit_follow_up;
     std::function<void(const NanRangeRequestInd&)> on_event_range_request;
     std::function<void(const NanRangeReportInd&)> on_event_range_report;
+    std::function<void(const NanDataPathScheduleUpdateInd&)> on_event_schedule_update;
 };
 
 // Full scan results contain IE info and are hence passed by reference, to
diff --git a/wifi/1.2/default/wifi_nan_iface.cpp b/wifi/1.2/default/wifi_nan_iface.cpp
index 1d786e3..e7bbfaa 100644
--- a/wifi/1.2/default/wifi_nan_iface.cpp
+++ b/wifi/1.2/default/wifi_nan_iface.cpp
@@ -467,6 +467,11 @@
             LOG(ERROR) << "on_event_range_report - should not be called";
         };
 
+    callback_handlers.on_event_schedule_update =
+        [weak_ptr_this](const legacy_hal::NanDataPathScheduleUpdateInd& /* msg */) {
+            LOG(ERROR) << "on_event_schedule_update - should not be called";
+        };
+
     legacy_hal::wifi_error legacy_status =
         legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_,
                                                         callback_handlers);