Merge "remove the com.android.threadnetwork from apex_available list" into main
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 0bcafa3..c283148 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -439,6 +439,9 @@
 }
 
 void BluetoothAudioSession::ReportLowLatencyModeAllowedChanged(bool allowed) {
+  if (session_type_ != SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    return;
+  }
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   low_latency_allowed_ = allowed;
   // TODO(b/294498919): Remove this after there is API to update latency mode
@@ -588,15 +591,32 @@
                << " has NO session";
     return std::vector<LatencyMode>();
   }
-  if (low_latency_allowed_) return latency_modes_;
-  std::vector<LatencyMode> modes;
-  for (LatencyMode mode : latency_modes_) {
-    if (mode == LatencyMode::LOW_LATENCY)
-      // ignore those low latency mode if Bluetooth stack doesn't allow
-      continue;
-    modes.push_back(mode);
+
+  std::vector<LatencyMode> supported_latency_modes;
+  if (session_type_ ==
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    for (LatencyMode mode : latency_modes_) {
+      if (mode == LatencyMode::LOW_LATENCY) {
+        // LOW_LATENCY is not supported for LE_HARDWARE_OFFLOAD_ENC sessions
+        continue;
+      }
+      supported_latency_modes.push_back(mode);
+    }
+  } else {
+    for (LatencyMode mode : latency_modes_) {
+      if (!low_latency_allowed_ && mode == LatencyMode::LOW_LATENCY) {
+        // ignore LOW_LATENCY mode if Bluetooth stack doesn't allow
+        continue;
+      }
+      if (mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_SOFTWARE ||
+          mode == LatencyMode::DYNAMIC_SPATIAL_AUDIO_HARDWARE) {
+        // DSA_SW and DSA_HW only supported for LE_HARDWARE_OFFLOAD_ENC sessions
+        continue;
+      }
+      supported_latency_modes.push_back(mode);
+    }
   }
-  return modes;
+  return supported_latency_modes;
 }
 
 void BluetoothAudioSession::SetLatencyMode(const LatencyMode& latency_mode) {
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index 83d2665..9f6b78b 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -302,6 +302,14 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.security.secretkeeper</name>
+        <version>1</version>
+        <interface>
+            <name>ISecretkeeper</name>
+            <instance>nonsecure</instance>
+        </interface>
+    </hal>
     <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.security.keymint</name>
         <version>1-3</version>
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl b/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
index 4c1b965..0bc39d6 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/Arc.cddl
@@ -28,19 +28,19 @@
     ? -70003 : int,   ; Timestamp in milliseconds since some starting point (generally
                       ; the most recent device boot) which all of the applications within
                       ; the secure domain must agree upon
-    ? -70004 : bstr .size 16,      ; Nonce used in key exchange methods
+    ? -70004 : bstr .size 16,      ; Nonce (a cryptographic random number of 16 bytes) used in key
+                                   ; exchange methods
     ? -70005 : PayloadType,        ; Payload type, if needed to disambiguate, when processing an arc
     ? -70006 : int,                ; Version of the payload structure (if applicable)
     ? -70007 : int,                ; Sequence number (if needed to prevent replay attacks)
     ? -70008 : Direction           ; Direction of the encryption key (i.e. whether it is used to
                                    ; encrypt incoming messages or outgoing messages)
     ? -70009 : bool,               ; "authentication_completed" - this is used during authenticated
-                                   ; key exchange indicate whether signature verification is done
-    ? -70010 : bstr .size 32       ; "session_id" computed during key exchange protocol
+                                   ; key exchange to indicate whether signature verification is done
+    ? -70010 : bstr .size 32       ; "session_id" computed during the key exchange protocol
 }
 
-; Permissions indicate what an arc can be used with. Permissions are added to an arc during the
-; `create()` primitive operation and are propagated during `mint` and `snap` primitive operations.
+; Permissions indicate what an arc can be used with.
 Permission = &(
     -4770552 : IdentityEncoded,  ; "source_id" - in the operations performed by a source, the
                                  ; source adds its own identity to the permissions of an arc.
@@ -54,12 +54,10 @@
                                      ; biometrics.
 )
 
-; Limitations indicate what restrictions are applied on the usage of an arc. Permissions are added
-; to an arc during the `create` primitive operation and are propagated during `snap` primitive
-; operation.
+; Limitations indicate what restrictions are applied on the usage of an arc.
 Limitation = &(
-    -4770554 : bstr,      ; "challenge" - is added to an arc that transfers an auth key to a channel
-                          ; key, in order to ensure the freshness of the authentication.
+    -4770554 : bstr,      ; "challenge" - is added to an arc that encrypts an auth key from a
+                          ; channel key, in order to ensure the freshness of the authentication.
                           ; A challenge is issued by a sink (e.g. Keymint TA, Biometric TAs).
 )
 
@@ -83,7 +81,7 @@
     ; Any other payload formats should also be defined here
 )
 
-SecretKey = &(                     ; One of the payload types of an Arc is a secret key
+SecretKey = &(
     SymmetricKey,
     ECPrivateKey,    ; Private key of a key pair generated for key exchange
 )
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
index 6ceb09c..a3fb959 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/IAuthGraphKeyExchange.aidl
@@ -41,8 +41,8 @@
 interface IAuthGraphKeyExchange {
     /**
      * This method is invoked on P1 (source).
-     * Create an ephermeral EC key pair on NIST curve P-256 and a nonce (of 16 bytes) for
-     * key exchange.
+     * Create an ephermeral EC key pair on NIST curve P-256 and a nonce (a cryptographic random
+     * number of 16 bytes) for key exchange.
      *
      * @return SessionInitiationInfo including the `Key` containing the public key of the created
      * key pair and an arc from the per-boot key to the private key, the nonce, the persistent
@@ -52,8 +52,8 @@
      * `SessionInitiationInfo` serves two purposes:
      * i. A mapping to correlate `create` and `finish` calls to P1 in a particular instance of the
      *    key exchange protocol.
-     * ii.A way to minimize the in-memory storage (P1 can include the nonce in the protected headers
-     *    of the arc).
+     * ii.A way to minimize the in-memory storage of P1 allocated for key exchange (P1 can include
+     *    the nonce in the protected headers of the arc).
      * However, P1 should maintain some form of in-memory record to be able to verify that the input
      * `Key` sent to `finish` is from an unfinished instance of a key exchange protocol, to prevent
      * any replay attacks in `finish`.
@@ -66,9 +66,9 @@
      *     0. If either `peerPubKey`, `peerId`, `peerNonce` is not in the expected format, return
      *        errors: INVALID_PEER_KE_KEY, INVALID_IDENTITY, INVALID_PEER_NONCE respectively.
      *     1. Create an ephemeral EC key pair on NIST curve P-256.
-     *     2. Create a nonce (of 16 bytes).
-     *     3. Compute the diffie-hellman shared secret: Z.
-     *     4. Compute a salt = bstr .cbor [
+     *     2. Create a nonce (a cryptographic random number of 16 bytes).
+     *     3. Compute the Diffie-Hellman shared secret: Z.
+     *     4. Compute a salt_input = bstr .cbor [
      *            source_version:    int,                    ; from input `peerVersion`
      *            sink_pub_key:      bstr .cbor PlainPubKey, ; from step #1
      *            source_pub_key:    bstr .cbor PlainPubKey, ; from input `peerPubKey`
@@ -77,7 +77,8 @@
      *            sink_cert_chain:   bstr .cbor ExplicitKeyDiceCertChain, ; from own identity
      *            source_cert_chain: bstr .cbor ExplicitKeyDiceCertChain, ; from input `peerId`
      *        ]
-     *     5. Extract a cryptographic secret S from Z, using the salt from #4 above.
+     *     5. Extract a cryptographic secret S from Z, using the SHA256 digest of the salt_input
+     *        as the salt.
      *     6. Derive two symmetric encryption keys of 256 bits with:
      *        i. b"KE_ENCRYPTION_KEY_SOURCE_TO_SINK" as context for the key used to encrypt incoming
      *           messages
@@ -96,28 +97,29 @@
      *        part of the party's identity.
      *
      * @param peerPubKey - the public key of the key pair created by the peer (P1) for key exchange
+     *                     in `create`
      *
      * @param peerId - the persistent identity of the peer
      *
-     * @param peerNonce - nonce created by the peer
+     * @param peerNonce - nonce created by the peer in `create`
      *
      * @param peerVersion - an integer representing the latest protocol version (i.e. AIDL version)
      *                      supported by the peer
      *
-     * @return KeInitResult including the `Key` containing the public key of the created key pair,
-     * the nonce, the persistent identity, two shared key arcs from step #7, session id, signature
-     * over the session id and the negotiated protocol version. The negotiated protocol version
-     * should be less than or equal to the peer's version.
+     * @return KeInitResult including the `Key` containing the public key of the key pair created in
+     * step #1, the nonce from step #2, the persistent identity of P2, two shared key arcs
+     * from step #7, session id from step #10, signature over the session id from step #11 and the
+     * negotiated protocol version. The negotiated protocol version should be less than or equal to
+     * the `peerVersion`.
      *
-     * Note: The two shared key arcs in the return type: `KeInitResult` serves two purposes:
+     * Note: The two shared key arcs in the return type: `KeInitResult` serve two purposes:
      * i. A mapping to correlate `init` and `authenticationComplete` calls to P2 in a particular
      *    instance of the key exchange protocol.
      * ii.A way to minimize the in-memory storage of P2 allocated for key exchange.
      * However, P2 should maintain some in-memory record to be able to verify that the input
-     * `sharedkeys` sent to `authenticationComplete` and to any subsequent AuthGraph protocol
-     * methods are valid shared keys agreed with the party identified by `peerId`, to prevent
-     * any replay attacks in `authenticationComplete` and in any subsequent AuthGraph protocol
-     * methods which use the shared keys to encrypt the secret messages.
+     * `sharedkeys` sent to `authenticationComplete` are from an unfinished instance of a key
+     * exchange protocol carried out with the party identified by `peerId`, to prevent any replay
+     * attacks in `authenticationComplete`.
      */
     KeInitResult init(
             in PubKey peerPubKey, in Identity peerId, in byte[] peerNonce, in int peerVersion);
@@ -133,8 +135,8 @@
      *        exchange protocol, return error: INVALID_KE_KEY. Similarly, if the public key or the
      *        arc containing the private key in `ownKey` is invalid, return INVALID_PUB_KEY_IN_KEY
      *        and INVALID_PRIV_KEY_ARC_IN_KEY respectively.
-     *     1. Compute the diffie-hellman shared secret: Z.
-     *     2. Compute a salt = bstr .cbor [
+     *     1. Compute the Diffie-Hellman shared secret: Z.
+     *     2. Compute a salt_input = bstr .cbor [
      *            source_version:    int,                    ; the protocol version used in `create`
      *            sink_pub_key:      bstr .cbor PlainPubKey, ; from input `peerPubKey`
      *            source_pub_key:    bstr .cbor PlainPubKey, ; from the output of `create`
@@ -143,7 +145,8 @@
      *            sink_cert_chain:   bstr .cbor ExplicitKeyDiceCertChain, ; from input `peerId`
      *            source_cert_chain: bstr .cbor ExplicitKeyDiceCertChain, ; from own identity
      *        ]
-     *     3. Extract a cryptographic secret S from Z, using the salt from #2 above.
+     *     3. Extract a cryptographic secret S from Z, using the SHA256 digest of the salt_input
+     *        as the salt.
      *     4. Derive two symmetric encryption keys of 256 bits with:
      *        i. b"KE_ENCRYPTION_KEY_SOURCE_TO_SINK" as context for the key used to encrypt outgoing
      *           messages
@@ -164,25 +167,26 @@
      *        part of the party's identity.
      *
      * @param peerPubKey - the public key of the key pair created by the peer (P2) for key exchange
+     *                     in `init`
      *
      * @param peerId - the persistent identity of the peer
      *
      * @param peerSignature - the signature created by the peer over the session id computed by the
-     *                        peer
+     *                        peer in `init`
      *
-     * @param peerNonce - nonce created by the peer
+     * @param peerNonce - nonce created by the peer in `init`
      *
      * @param peerVersion - an integer representing the protocol version (i.e. AIDL version)
      *                      negotiated with the peer
      *
-     * @param ownKey - the key created by P1 (source) in `create()` for key exchange
+     * @param ownKey - the key created by P1 (source) in `create` for key exchange
      *
-     * @return SessionInfo including the two shared key arcs from step #9, session id and the
-     * signature over the session id.
+     * @return SessionInfo including the two shared key arcs from step #9, session id from step #7
+     * and the signature over the session id from step #10.
      *
-     * Note: The two shared key arcs in the return type: `SessionInfo` serves two purposes:
+     * Note: The two shared key arcs in the return type: `SessionInfo` serve two purposes:
      * i. A mapping to correlate the key exchange protocol taken place with a particular peer and
-     *    subsequent AuthGraph protocols execued with the same peer.
+     *    subsequent AuthGraph protocols executed with the same peer.
      * ii.A way to minimize the in-memory storage for shared keys.
      * However, P1 should maintain some in-memory record to be able to verify that the shared key
      * arcs sent to any subsequent AuthGraph protocol methods are valid shared keys agreed with the
@@ -196,21 +200,33 @@
      * This method is invoked on P2 (sink).
      * Perform the following steps:
      *   0. If input `sharedKeys` is invalid (i.e. they cannot be decrypted with P2's per-boot key
-     *      or they are not in P2's in-memory records as valid shared keys agreed with the party
-     *      identified by `peerId`), return error: INVALID_SHARED_KEY_ARCS.
+     *      or they are not in P2's in-memory records for unfinished instances of a key exchange
+     *      protocol carried out with the party identified by the identity included in the
+     *      `source_id` protected header of the shared key arcs),
+     *      return error: INVALID_SHARED_KEY_ARCS.
      *   1. Verify that both shared key arcs have the same session id and peer identity.
-     *   2. Verify the peer's signature over the session id attached to the shared key arcs'
-     *      headers. If successful, proceed, otherwise, return error: INVALID_SIGNATURE.
-     *   3. Mark authentication_complete = true in the shared key arcs' headers
+     *   2. Verify the `peerSignature` over the session id included in the `session_id` protected
+     *      header of the shared key arcs.
+     *      If successful, proceed, otherwise, return error: INVALID_SIGNATURE.
+     *   3. Mark authentication_complete = true in the shared key arcs' headers.
      *
      * @param peerSignature - the signature created by the peer over the session id computed by the
-     *                        peer
+     *                        peer in `finish`
      *
      * @param sharedKeys - two shared key arcs created by P2 in `init`. P2 obtains from the arcs'
      *                     protected headers, the session id and the peer's identity to verify the
      *                     peer's signature over the session id.
      *
      * @return Arc[] - an array of two updated shared key arcs
+     *
+     * Note: The two returned shared key arcs serve two purposes:
+     * i. A mapping to correlate the key exchange protocol taken place with a particular peer and
+     *    subsequent AuthGraph protocols executed with the same peer.
+     * ii.A way to minimize the in-memory storage for shared keys.
+     * However, P2 should maintain some in-memory record to be able to verify that the shared key
+     * arcs sent to any subsequent AuthGraph protocol methods are valid shared keys agreed with the
+     * party identified by the identity included in the `source_id` protected header of the shared
+     * key arcs, to prevent any replay attacks.
      */
     Arc[2] authenticationComplete(in SessionIdSignature peerSignature, in Arc[2] sharedKeys);
 }
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
index ef49a1a..82b8c17 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInfo.aidl
@@ -26,8 +26,8 @@
 @RustDerive(Clone=true, Eq=true, PartialEq=true)
 parcelable SessionInfo {
     /**
-     * The arcs that encrypt the two derived symmetric encryption keys (for two-way communication)
-     * from the party's per-boot key.
+     * The arcs that encrypt the two derived symmetric encryption keys (for two-way communication).
+     * The encryption key is the party's per-boot key.
      */
     Arc[2] sharedKeys;
 
diff --git a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
index c630d91..8179ac2 100644
--- a/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
+++ b/security/authgraph/aidl/android/hardware/security/authgraph/SessionInitiationInfo.aidl
@@ -27,20 +27,22 @@
 @RustDerive(Clone=true, Eq=true, PartialEq=true)
 parcelable SessionInitiationInfo {
     /**
-     * An ephemeral EC key created for the ECDH process.
+     * An ephemeral EC key created for the Elliptic-curve Diffie-Hellman (ECDH) process.
      */
     Key key;
 
     /**
-     * The identity of the party who created the Diffie-Hellman key exchange key.
+     * The identity of the party who creates this `SessionInitiationInfo`.
      */
     Identity identity;
 
     /**
-     * Nonce value specific to this session. The nonce serves three purposes:
+     * Nonce (a cryptographic random number of 16 bytes) specific to this session.
+     * The nonce serves three purposes:
      * 1. freshness of key exchange
      * 2. creating a session id (a publicly known value related to the exchanged keys)
-     * 3. usage as salt into the HKDF-EXTRACT function during key derivation from the shared DH key
+     * 3. usage as salt into the HKDF-EXTRACT function during key derivation from the Diffie-Hellman
+     *    shared secret
      */
     byte[] nonce;
 
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index aa7bf28..be29f59 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -974,8 +974,8 @@
      * time in milliseconds.  This value is used when generating attestation or self signed
      * certificates.  ErrorCode::MISSING_NOT_BEFORE must be returned if this tag is not provided if
      * this tag is not provided to generateKey or importKey.  For importWrappedKey, there is no way
-     * to specify the value of this tag for the wrapped key, so a value of 0 must be used for
-     * certificate generation.
+     * to specify the value of this tag for a wrapped asymmetric key, so a value of 0 is suggested
+     * for certificate generation.
      */
     CERTIFICATE_NOT_BEFORE = TagType.DATE | 1008,
 
@@ -983,8 +983,9 @@
      * Tag::CERTIFICATE_NOT_AFTER the end of the validity of the certificate in UNIX epoch time in
      * milliseconds.  This value is used when generating attestation or self signed certificates.
      * ErrorCode::MISSING_NOT_AFTER must be returned if this tag is not provided to generateKey or
-     * importKey.  For importWrappedKey, there is no way to specify the value of this tag for the
-     * wrapped key, so a value of 253402300799000 is used for certificate generation.
+     * importKey.  For importWrappedKey, there is no way to specify the value of this tag for a
+     * wrapped asymmetric key, so a value of 253402300799000 is suggested for certificate
+     * generation.
      */
     CERTIFICATE_NOT_AFTER = TagType.DATE | 1009,
 
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index a8f17dd..d4adab5 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -4123,13 +4123,13 @@
  * when the EC_CURVE is not explicitly specified.
  */
 TEST_P(ImportKeyTest, EcdsaSuccessCurveNotSpecified) {
-    if (AidlVersion() < 4) {
+    if (get_vsr_api_level() < __ANDROID_API_V__) {
         /*
-         * The KeyMint spec before V4 was not clear as to whether EC_CURVE was optional on import of
-         * EC keys. However, this was not checked at the time so we can only be strict about
-         * checking this for implementations of KeyMint version 4 and above.
+         * The KeyMint spec was previously not clear as to whether EC_CURVE was optional on import
+         * of EC keys. However, this was not checked at the time so we can only be strict about
+         * checking this for implementations at VSR-V or later.
          */
-        GTEST_SKIP() << "Skipping EC_CURVE on import only strict since KeyMint v4";
+        GTEST_SKIP() << "Skipping EC_CURVE on import only strict >= VSR-V";
     }
 
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
diff --git a/security/secretkeeper/aidl/Android.bp b/security/secretkeeper/aidl/Android.bp
new file mode 100644
index 0000000..c77d299
--- /dev/null
+++ b/security/secretkeeper/aidl/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+    name: "android.hardware.security.secretkeeper",
+    vendor_available: true,
+    srcs: ["android/hardware/security/secretkeeper/*.aidl"],
+    stability: "vintf",
+    backend: {
+        ndk: {
+            enabled: true,
+        },
+        rust: {
+            enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.virt",
+            ],
+        },
+    },
+}
diff --git a/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
new file mode 100644
index 0000000..2eb33c5
--- /dev/null
+++ b/security/secretkeeper/aidl/aidl_api/android.hardware.security.secretkeeper/current/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.secretkeeper;
+@VintfStability
+interface ISecretkeeper {
+  byte[] processSecretManagementRequest(in byte[] request);
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
new file mode 100644
index 0000000..af715a9
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/ISecretkeeper.aidl
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 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.secretkeeper;
+
+@VintfStability
+/**
+ * Secretkeeper service definition.
+ *
+ * An ISecretkeeper instance provides secure storage of secrets on behalf of other components in
+ * Android, in particular for protected virtual machine instances. From the perspective of security
+ * privilege, Secretkeeper must be implemented in an environment with privilege higher than any of
+ * its clients. Since AVF based protected Virtual Machines are one set of its clients, the
+ * implementation of ISecretkeeper should live in a secure environment, such as:
+ * - A trusted execution environment such as ARM TrustZone.
+ * - A completely separate, purpose-built and certified secure CPU.
+ *
+ * TODO(b/291224769): Extend the HAL interface to include:
+ * 1. Session setup api: This is used to perform cryptographic operations that allow shared keys to
+ * be exchanged between session participants, typically (but not necessarily) a pVM instance and
+ * Secretkeeper. This session setup is based on public key cryptography.
+ * 2. Dice policy operation - These allow sealing of the secrets with a class of Dice chains.
+ * Typical operations are (securely) updating the dice policy sealing the Secrets above. These
+ * operations are core to AntiRollback protected secrets - ie, ensuring secrets of a pVM are only
+ * accessible to same or higher versions of the images.
+ * 3. Maintenance api: This is required for removing the Secretkeeper entries for obsolete pvMs.
+ */
+interface ISecretkeeper {
+    /**
+     * processSecretManagementRequest method is used for interacting with the Secret Management API
+     *
+     * Secret Management API: The clients can use this API to store (& get) 32 bytes of data.
+     * The API is a CBOR based protocol, which follows request/response model.
+     * See SecretManagement.cddl for the API spec.
+     *
+     * Further, the requests (from client) & responses (from service) must be encrypted into
+     * ProtectedRequestPacket & ProtectedResponsePacket using symmetric keys agreed between
+     * the client & service. This cryptographic protection is required because the messages are
+     * ferried via Android, which is allowed to be outside the TCB of clients (for example protected
+     * Virtual Machines). For this, service (& client) must implement a key exchange protocol, which
+     * is critical for establishing the secure channel.
+     *
+     * Secretkeeper database should guarantee the following properties:
+     * 1. Confidentiality: No entity (of security privilege lower than Secretkeeper) should
+     *    be able to get a client's data in clear.
+     *
+     * 2. Integrity: The data is protected against malicious Android OS tampering with database.
+     *    ie, if Android (userspace & kernel) tampers with the client's secret, the Secretkeeper
+     *    service must be able to detect it & return error when clients requests for their secrets.
+     *    Note: the integrity requirements also include Antirollback protection ie, reverting the
+     *    database into an old state should be detected.
+     *
+     * 3. The data is persistent across device boot.
+     *    Note: Denial of service is not in scope. A malicious Android may be able to delete data,
+     *    but for ideal Android, the data should be persistent.
+     *
+     * @param CBOR-encoded ProtectedRequestPacket. See SecretManagement.cddl for its definition.
+     * @return CBOR-encoded ProtectedResponsePacket. See SecretManagement.cddl for its definition
+     */
+    byte[] processSecretManagementRequest(in byte[] request);
+}
diff --git a/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
new file mode 100644
index 0000000..5631937
--- /dev/null
+++ b/security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
@@ -0,0 +1,116 @@
+; CDDL for the Secret Management API.
+; Also see processSecretManagementRequest method in ISecretkeeper.aidl
+
+; ProtectedRequestPacket is used by client for accessing Secret Management API
+; in Secretkeeper service. The service returns ProtectedResponsePacket of the corresponding type.
+
+; ProtectedRequestPacket & ProtectedResponsePacket are encrypted wrappers
+; on RequestPacket & ResponsePacket using symmetric keys agreed between Secretkeeper & clients
+; (these are referred to as KeySourceToSink & KeySinkToSource)
+;
+; The API operation required is encoded using 'Opcode', the arguments using 'Params'
+; and returned values as 'Result'.
+
+ProtectedRequestPacket =
+        ProtectedGetVersionRequest / ProtectedStoreSecretRequest / ProtectedGetSecretRequest
+ProtectedResponsePacket =
+        ProtectedGetVersionResponse / ProtectedStoreSecretResponse / ProtectedGetSecretResponse
+
+ProtectedGetVersionRequest = ProtectedRequestPacket<GetVersionRequestPacket>
+ProtectedGetVersionResponse = ProtectedResponsePacket<GetVersionResponsePacket>
+ProtectedStoreSecretRequest = ProtectedRequestPacket<StoreSecretRequestPacket>
+ProtectedStoreSecretResponse = ProtectedResponsePacket<StoreSecretResponsePacket>
+ProtectedGetSecretRequest = ProtectedRequestPacket<GetSecretRequestPacket>
+ProtectedGetSecretResponse = ProtectedResponsePacket<GetSecretResponsePacket>
+
+GetVersionRequestPacket = RequestPacket<GetVersionOpcode, GetVersionParams>
+GetVersionResponsePacket = ResponsePacket<GetVersionResult>
+StoreSecretRequestPacket = RequestPacket<StoreSecretOpcode, StoreSecretParams>
+StoreSecretResponsePacket = ResponsePacket<StoreSecretResult>
+GetSecretRequestPacket = RequestPacket<GetOpcode, GetSecretParams>
+GetSecretResponsePacket = ResponsePacket<GetSecretResult>
+
+RequestPacket<Opcode, Params> = [
+    Opcode,
+    Params
+]
+ResponsePacket<Result> = ResponsePacketError / ResponsePacketSuccess<Result>
+
+ResponsePacketSuccess = [
+    0,                          ; Indicates successful Response
+    result : Result
+]
+ResponsePacketError = [
+    error_code: ErrorCode,      ; Indicate the error
+    error_message: tstr         ; Additional human-readable context
+]
+
+Opcode = &(
+    GetVersionOpcode: 1,     ; Get version of the SecretManagement API
+    StoreSecretOpcode: 2,          ; Store a secret
+    GetSecretOpcode: 3,            ; Get the secret
+)
+
+GetVersionParams = ()
+GetVersionResult = (version : uint)
+
+StoreSecretParams = (
+    id : bstr .size 64              ; Unique identifier of the secret
+    secret : bstr .size 32,
+    sealing_policy : bstr .cbor DicePolicy,    ; See DicePolicy.cddl for definition of DicePolicy
+)
+StoreSecretResult = ()
+
+GetSecretParams = (
+    id : bstr .size 64              ; Unique identifier of the secret
+    ; Use this to update the sealing policy associated with a secret during GetSecret operation.
+    updated_sealing_policy : bstr .cbor DicePolicy / nil,
+)
+GetSecretResult = (secret : bstr .size 32)
+
+
+ProtectedRequestPacket<Payload, Key> = CryptoPayload<Payload, KeySourceToSink>
+ProtectedResponsePacket<Payload, Key> = ProtectedResponseError
+                                    / ProtectedResponseSuccess<Payload>
+
+ProtectedResponseSuccess<Payload> = [
+    0,                                ; Indicates successful crypto operations. Note: Payload
+                                                    ; may contain Error from functional layer.
+    message: CryptoPayload<Payload, KeySinkToSource>         ; message is the encrypted payload
+]
+
+ProtectedResponseError = [
+    error_code: CryptoErrorCode,           ; Indicates the error. This is in cleartext & will be
+                                           ; visible to Android. These are errors from crypto
+                                           ; layer & indicates the request could not even be read
+    message: tstr                          ; Additional human-readable context
+]
+
+CryptoPayload<Payload, Key> = [         ; COSE_Encrypt0 (untagged), [RFC 9052 s5.2]
+    protected: bstr .cbor {
+        1 : 3,                  ; Algorithm: AES-GCM mode w/ 256-bit key, 128-bit tag
+        4 : bstr                ; key identifier, uniquely identifies the session
+                                ; TODO(b/291228560): Refer to the Key Exchange spec.
+    },
+    unprotected: {
+        5 : bstr .size 12          ; IV
+    },
+    ciphertext : bstr     ; AES-GCM-256(Key, bstr .cbor Payload)
+                          ; AAD for the encryption is CBOR-serialized
+                          ; Enc_structure (RFC 9052 s5.3) with empty external_aad.
+]
+
+; TODO(b/291224769): Create a more exhaustive set of CryptoErrorCode
+CryptoErrorCode = &(
+    CryptoErrorCode_SessionExpired: 1,
+)
+
+; TODO(b/291224769): Create a more exhaustive set of ErrorCodes
+ErrorCode = &(
+    ; Use this as if no other error code can be used.
+    ErrorCode_UnexpectedServerError: 1,
+    ; Indicate the Request was malformed & hence couldnt be served.
+    ErrorCode_RequestMalformed: 2,
+)
+
+; INCLUDE DicePolicy.cddl for: DicePolicy
\ No newline at end of file
diff --git a/security/secretkeeper/aidl/vts/Android.bp b/security/secretkeeper/aidl/vts/Android.bp
new file mode 100644
index 0000000..6818298
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/Android.bp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_test {
+    name: "VtsSecretkeeperTargetTest",
+    srcs: ["secretkeeper_test_client.rs"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    rustlibs: [
+        "libsecretkeeper_comm_nostd",
+        "android.hardware.security.secretkeeper-V1-rust",
+        "libbinder_rs",
+        "liblog_rust",
+    ],
+    require_root: true,
+}
diff --git a/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
new file mode 100644
index 0000000..28923f7
--- /dev/null
+++ b/security/secretkeeper/aidl/vts/secretkeeper_test_client.rs
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#[cfg(test)]
+use binder::StatusCode;
+use log::warn;
+use secretkeeper_comm::data_types::error::SecretkeeperError;
+use secretkeeper_comm::data_types::request::Request;
+use secretkeeper_comm::data_types::request_response_impl::{
+    GetVersionRequest, GetVersionResponse,
+};
+use secretkeeper_comm::data_types::response::Response;
+use secretkeeper_comm::data_types::packet::{ResponsePacket, ResponseType};
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::ISecretkeeper;
+
+const SECRETKEEPER_IDENTIFIER: &str =
+    "android.hardware.security.secretkeeper.ISecretkeeper/nonsecure";
+const CURRENT_VERSION: u64 = 1;
+
+fn get_connection() -> Option<binder::Strong<dyn ISecretkeeper>> {
+    match binder::get_interface(SECRETKEEPER_IDENTIFIER) {
+        Ok(sk) => Some(sk),
+        Err(StatusCode::NAME_NOT_FOUND) => None,
+        Err(e) => {
+            panic!(
+                "unexpected error while fetching connection to Secretkeeper {:?}",
+                e
+            );
+        }
+    }
+}
+
+// TODO(b/2797757): Add tests that match different HAL defined objects (like request/response)
+// with expected bytes.
+
+#[test]
+fn secret_management_get_version() {
+    let secretkeeper = match get_connection() {
+        Some(sk) => sk,
+        None => {
+            warn!("Secretkeeper HAL is unavailable, skipping test");
+            return;
+        }
+    };
+    let request = GetVersionRequest {};
+    let request_packet = request.serialize_to_packet();
+    let request_bytes = request_packet.into_bytes().unwrap();
+
+    // TODO(b/291224769) The request will need to be encrypted & response need to be decrypted
+    // with key & related artifacts pre-shared via Authgraph Key Exchange HAL.
+
+    let response_bytes = secretkeeper
+        .processSecretManagementRequest(&request_bytes)
+        .unwrap();
+
+    let response_packet = ResponsePacket::from_bytes(&response_bytes).unwrap();
+    assert_eq!(
+        response_packet.response_type().unwrap(),
+        ResponseType::Success
+    );
+    let get_version_response =
+        *GetVersionResponse::deserialize_from_packet(response_packet).unwrap();
+    assert_eq!(get_version_response.version(), CURRENT_VERSION);
+}
+
+#[test]
+fn secret_management_malformed_request() {
+    let secretkeeper = match get_connection() {
+        Some(sk) => sk,
+        None => {
+            warn!("Secretkeeper HAL is unavailable, skipping test");
+            return;
+        }
+    };
+    let request = GetVersionRequest {};
+    let request_packet = request.serialize_to_packet();
+    let mut request_bytes = request_packet.into_bytes().unwrap();
+
+    // Deform the request
+    request_bytes[0] = !request_bytes[0];
+
+    // TODO(b/291224769) The request will need to be encrypted & response need to be decrypted
+    // with key & related artifacts pre-shared via Authgraph Key Exchange HAL.
+
+    let response_bytes = secretkeeper
+        .processSecretManagementRequest(&request_bytes)
+        .unwrap();
+
+    let response_packet = ResponsePacket::from_bytes(&response_bytes).unwrap();
+    assert_eq!(
+        response_packet.response_type().unwrap(),
+        ResponseType::Error
+    );
+    let err = *SecretkeeperError::deserialize_from_packet(response_packet).unwrap();
+    assert_eq!(err, SecretkeeperError::RequestMalformed);
+}
diff --git a/security/secretkeeper/default/Android.bp b/security/secretkeeper/default/Android.bp
new file mode 100644
index 0000000..1c39fa6
--- /dev/null
+++ b/security/secretkeeper/default/Android.bp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_binary {
+    name: "android.hardware.security.secretkeeper-service.nonsecure",
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["secretkeeper.rc"],
+    vintf_fragments: ["secretkeeper.xml"],
+    rustlibs: [
+        "android.hardware.security.secretkeeper-V1-rust",
+        "libandroid_logger",
+        "libbinder_rs",
+        "liblog_rust",
+        "libsecretkeeper_comm_nostd",
+    ],
+    srcs: [
+        "src/main.rs",
+    ],
+}
diff --git a/security/secretkeeper/default/secretkeeper.rc b/security/secretkeeper/default/secretkeeper.rc
new file mode 100644
index 0000000..f39f9b7
--- /dev/null
+++ b/security/secretkeeper/default/secretkeeper.rc
@@ -0,0 +1,5 @@
+service vendor.secretkeeper /vendor/bin/hw/android.hardware.security.secretkeeper-service.nonsecure
+    interface aidl android.hardware.security.secretkeeper.ISecretkeeper/nonsecure
+    class hal
+    user nobody
+    group nobody
diff --git a/security/secretkeeper/default/secretkeeper.xml b/security/secretkeeper/default/secretkeeper.xml
new file mode 100644
index 0000000..40aebe0
--- /dev/null
+++ b/security/secretkeeper/default/secretkeeper.xml
@@ -0,0 +1,28 @@
+<manifest version="1.0" type="device">
+<!--
+/*
+** Copyright 2022, 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.
+*/
+-->
+
+    <hal format="aidl">
+        <name>android.hardware.security.secretkeeper</name>
+        <version>1</version>
+        <interface>
+            <name>ISecretkeeper</name>
+            <instance>nonsecure</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/security/secretkeeper/default/src/main.rs b/security/secretkeeper/default/src/main.rs
new file mode 100644
index 0000000..2d367c5
--- /dev/null
+++ b/security/secretkeeper/default/src/main.rs
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+use binder::{BinderFeatures, Interface};
+use log::{error, info, Level};
+use secretkeeper_comm::data_types::error::SecretkeeperError;
+use secretkeeper_comm::data_types::packet::{RequestPacket, ResponsePacket};
+use secretkeeper_comm::data_types::request::Request;
+use secretkeeper_comm::data_types::request_response_impl::{
+    GetVersionRequest, GetVersionResponse, Opcode,
+};
+use secretkeeper_comm::data_types::response::Response;
+
+use android_hardware_security_secretkeeper::aidl::android::hardware::security::secretkeeper::ISecretkeeper::{
+    BnSecretkeeper, BpSecretkeeper, ISecretkeeper,
+};
+
+const CURRENT_VERSION: u64 = 1;
+
+#[derive(Debug, Default)]
+pub struct NonSecureSecretkeeper;
+
+impl Interface for NonSecureSecretkeeper {}
+
+impl ISecretkeeper for NonSecureSecretkeeper {
+    fn processSecretManagementRequest(&self, request: &[u8]) -> binder::Result<Vec<u8>> {
+        Ok(self.process_opaque_request(request))
+    }
+}
+
+impl NonSecureSecretkeeper {
+    // A set of requests to Secretkeeper are 'opaque' - encrypted bytes with inner structure
+    // described by CDDL. They need to be decrypted, deserialized and processed accordingly.
+    fn process_opaque_request(&self, request: &[u8]) -> Vec<u8> {
+        // TODO(b/291224769) The request will need to be decrypted & response need to be encrypted
+        // with key & related artifacts pre-shared via Authgraph Key Exchange HAL.
+        self.process_opaque_request_unhandled_error(request)
+            .unwrap_or_else(
+                // SecretkeeperError is also a valid 'Response', serialize to a response packet.
+                |sk_err| {
+                    Response::serialize_to_packet(&sk_err)
+                        .into_bytes()
+                        .expect("Panicking due to serialization failing")
+                },
+            )
+    }
+
+    fn process_opaque_request_unhandled_error(
+        &self,
+        request: &[u8],
+    ) -> Result<Vec<u8>, SecretkeeperError> {
+        let request_packet = RequestPacket::from_bytes(request).map_err(|e| {
+            error!("Failed to get Request packet from bytes: {:?}", e);
+            SecretkeeperError::RequestMalformed
+        })?;
+        let response_packet = match request_packet
+            .opcode()
+            .map_err(|_| SecretkeeperError::RequestMalformed)?
+        {
+            Opcode::GetVersion => Self::process_get_version_request(request_packet)?,
+            _ => todo!("TODO(b/291224769): Unimplemented operations"),
+        };
+
+        response_packet
+            .into_bytes()
+            .map_err(|_| SecretkeeperError::UnexpectedServerError)
+    }
+
+    fn process_get_version_request(
+        request: RequestPacket,
+    ) -> Result<ResponsePacket, SecretkeeperError> {
+        // Deserialization really just verifies the structural integrity of the request such
+        // as args being empty.
+        let _request = GetVersionRequest::deserialize_from_packet(request)
+            .map_err(|_| SecretkeeperError::RequestMalformed)?;
+        let response = GetVersionResponse::new(CURRENT_VERSION);
+        Ok(response.serialize_to_packet())
+    }
+}
+
+fn main() {
+    // Initialize Android logging.
+    android_logger::init_once(
+        android_logger::Config::default()
+            .with_tag("NonSecureSecretkeeper")
+            .with_min_level(Level::Info)
+            .with_log_id(android_logger::LogId::System),
+    );
+    // Redirect panic messages to logcat.
+    std::panic::set_hook(Box::new(|panic_info| {
+        error!("{}", panic_info);
+    }));
+
+    let service = NonSecureSecretkeeper::default();
+    let service_binder = BnSecretkeeper::new_binder(service, BinderFeatures::default());
+    let service_name = format!(
+        "{}/nonsecure",
+        <BpSecretkeeper as ISecretkeeper>::get_descriptor()
+    );
+    binder::add_service(&service_name, service_binder.as_binder()).unwrap_or_else(|e| {
+        panic!(
+            "Failed to register service {} because of {:?}.",
+            service_name, e
+        );
+    });
+    info!("Registered Binder service, joining threadpool.");
+    binder::ProcessState::join_thread_pool();
+}