Merge "Update Android V compatibility matrix" into main
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl
index bcbf870..046c220 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Flags.aidl
@@ -43,6 +43,8 @@
   boolean audioModeIndication;
   boolean audioSourceIndication;
   boolean bypass;
+  boolean sinkMetadataIndication;
+  boolean sourceMetadataIndication;
   @Backing(type="byte") @VintfStability
   enum Type {
     INSERT = 0,
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
index 7313b57..ff33c42 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
@@ -41,6 +41,8 @@
   boolean offload;
   android.hardware.audio.effect.Parameter.VolumeStereo volumeStereo;
   android.hardware.audio.effect.Parameter.Specific specific;
+  android.hardware.audio.common.SinkMetadata sinkMetadata;
+  android.hardware.audio.common.SourceMetadata sourceMetadata;
   @VintfStability
   union Id {
     android.hardware.audio.effect.VendorExtension vendorEffectTag;
diff --git a/audio/aidl/android/hardware/audio/effect/Flags.aidl b/audio/aidl/android/hardware/audio/effect/Flags.aidl
index 28685c3..70668a3 100644
--- a/audio/aidl/android/hardware/audio/effect/Flags.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Flags.aidl
@@ -144,4 +144,18 @@
      * Set to true if the effect instance bypass audio data (no processing).
      */
     boolean bypass;
+
+    /**
+     * Effect instance sets this flag to true if it requires record AudioTrack metadata update. In
+     * this case the framework must call IEffect.setParameter to notify effect instance when there
+     * is a change in sinkMetadata.
+     */
+    boolean sinkMetadataIndication;
+
+    /**
+     * Effect instance sets this flag to true if it requires playback AudioTrack metadata update. In
+     * this case the framework must call IEffect.setParameter to notify effect instance when there
+     * is a change in sourceMetadata.
+     */
+    boolean sourceMetadataIndication;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
index 6ec7226..6fd9161 100644
--- a/audio/aidl/android/hardware/audio/effect/Parameter.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.audio.effect;
 
+import android.hardware.audio.common.SinkMetadata;
+import android.hardware.audio.common.SourceMetadata;
 import android.hardware.audio.effect.AcousticEchoCanceler;
 import android.hardware.audio.effect.AutomaticGainControlV1;
 import android.hardware.audio.effect.AutomaticGainControlV2;
@@ -198,4 +200,20 @@
         Spatializer spatializer;
     }
     Specific specific;
+
+    /**
+     * SinkMetadata defines the metadata of record AudioTracks which the effect instance associate
+     * with.
+     * The effect engine is required to set Flags.sinkMetadataIndication to true if it wants to
+     * receive sinkMetadata update from the audio framework.
+     */
+    SinkMetadata sinkMetadata;
+
+    /**
+     * SourceMetadata defines the metadata of playback AudioTracks which the effect instance
+     * associate with.
+     * The effect engine is required to set Flags.sourceMetadataIndication to true if it wants to
+     * receive sourceMetadata update from the audio framework.
+     */
+    SourceMetadata sourceMetadata;
 }
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index 254eb46..d63e353 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -320,9 +320,9 @@
 //    - no profiles specified
 //
 // Mix ports:
-//  * "r_submix output", maximum 20 opened streams, maximum 10 active streams
+//  * "r_submix output", maximum 10 opened streams, maximum 10 active streams
 //    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//  * "r_submix input", maximum 20 opened streams, maximum 10 active streams
+//  * "r_submix input", maximum 10 opened streams, maximum 10 active streams
 //    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //
 // Routes:
@@ -355,12 +355,12 @@
         // Mix ports
 
         AudioPort rsubmixOutMix =
-                createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(20, 10));
+                createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(10, 10));
         rsubmixOutMix.profiles = remoteSubmixPcmAudioProfiles;
         c.ports.push_back(rsubmixOutMix);
 
         AudioPort rsubmixInMix =
-                createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(20, 10));
+                createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(10, 10));
         rsubmixInMix.profiles = remoteSubmixPcmAudioProfiles;
         c.ports.push_back(rsubmixInMix);
 
diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
index 21592b3..ee10abf 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -71,6 +71,10 @@
     static constexpr int kMaxReadFailureAttempts = 3;
     // 5ms between two read attempts when pipe is empty
     static constexpr int kReadAttemptSleepUs = 5000;
+
+    long mStartTimeNs = 0;
+    long mFramesSinceStart = 0;
+    int mReadErrorCount = 0;
 };
 
 class StreamInRemoteSubmix final : public StreamIn, public StreamSwitcher {
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index fc61dcb..6258c93 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -16,6 +16,9 @@
 
 #define LOG_TAG "AHAL_StreamRemoteSubmix"
 #include <android-base/logging.h>
+#include <audio_utils/clock.h>
+#include <error/Result.h>
+#include <error/expected_utils.h>
 
 #include "core-impl/StreamRemoteSubmix.h"
 
@@ -50,37 +53,33 @@
         if (routeItr != sSubmixRoutes.end()) {
             mCurrentRoute = routeItr->second;
         }
-    }
-    // If route is not available for this port, add it.
-    if (mCurrentRoute == nullptr) {
-        // Initialize the pipe.
-        mCurrentRoute = std::make_shared<SubmixRoute>();
-        if (::android::OK != mCurrentRoute->createPipe(mStreamConfig)) {
-            LOG(ERROR) << __func__ << ": create pipe failed";
-            return ::android::NO_INIT;
-        }
-        {
-            std::lock_guard guard(sSubmixRoutesLock);
-            sSubmixRoutes.emplace(mDeviceAddress, mCurrentRoute);
-        }
-    } else {
-        if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
-            LOG(ERROR) << __func__ << ": invalid stream config";
-            return ::android::NO_INIT;
-        }
-        sp<MonoPipe> sink = mCurrentRoute->getSink();
-        if (sink == nullptr) {
-            LOG(ERROR) << __func__ << ": nullptr sink when opening stream";
-            return ::android::NO_INIT;
-        }
-        // If the sink has been shutdown or pipe recreation is forced, delete the pipe and
-        // recreate it.
-        if (sink->isShutdown()) {
-            LOG(DEBUG) << __func__ << ": Non-nullptr shut down sink when opening stream";
-            if (::android::OK != mCurrentRoute->resetPipe()) {
-                LOG(ERROR) << __func__ << ": reset pipe failed";
+        // If route is not available for this port, add it.
+        if (mCurrentRoute == nullptr) {
+            // Initialize the pipe.
+            mCurrentRoute = std::make_shared<SubmixRoute>();
+            if (::android::OK != mCurrentRoute->createPipe(mStreamConfig)) {
+                LOG(ERROR) << __func__ << ": create pipe failed";
                 return ::android::NO_INIT;
             }
+            sSubmixRoutes.emplace(mDeviceAddress, mCurrentRoute);
+        }
+    }
+    if (!mCurrentRoute->isStreamConfigValid(mIsInput, mStreamConfig)) {
+        LOG(ERROR) << __func__ << ": invalid stream config";
+        return ::android::NO_INIT;
+    }
+    sp<MonoPipe> sink = mCurrentRoute->getSink();
+    if (sink == nullptr) {
+        LOG(ERROR) << __func__ << ": nullptr sink when opening stream";
+        return ::android::NO_INIT;
+    }
+    // If the sink has been shutdown or pipe recreation is forced, delete the pipe and
+    // recreate it.
+    if (sink->isShutdown()) {
+        LOG(DEBUG) << __func__ << ": Non-nullptr shut down sink when opening stream";
+        if (::android::OK != mCurrentRoute->resetPipe()) {
+            LOG(ERROR) << __func__ << ": reset pipe failed";
+            return ::android::NO_INIT;
         }
     }
 
@@ -110,6 +109,8 @@
 
 ::android::status_t StreamRemoteSubmix::start() {
     mCurrentRoute->exitStandby(mIsInput);
+    mStartTimeNs = ::android::uptimeNanos();
+    mFramesSinceStart = 0;
     return ::android::OK;
 }
 
@@ -161,8 +162,21 @@
     *latencyMs = getDelayInUsForFrameCount(getStreamPipeSizeInFrames()) / 1000;
     LOG(VERBOSE) << __func__ << ": Latency " << *latencyMs << "ms";
     mCurrentRoute->exitStandby(mIsInput);
-    return (mIsInput ? inRead(buffer, frameCount, actualFrameCount)
-                     : outWrite(buffer, frameCount, actualFrameCount));
+    RETURN_STATUS_IF_ERROR(mIsInput ? inRead(buffer, frameCount, actualFrameCount)
+                                    : outWrite(buffer, frameCount, actualFrameCount));
+    const long bufferDurationUs =
+            (*actualFrameCount) * MICROS_PER_SECOND / mContext.getSampleRate();
+    const long totalDurationUs = (::android::uptimeNanos() - mStartTimeNs) / NANOS_PER_MICROSECOND;
+    mFramesSinceStart += *actualFrameCount;
+    const long totalOffsetUs =
+            mFramesSinceStart * MICROS_PER_SECOND / mContext.getSampleRate() - totalDurationUs;
+    LOG(VERBOSE) << __func__ << ": totalOffsetUs " << totalOffsetUs;
+    if (totalOffsetUs > 0) {
+        const long sleepTimeUs = std::min(totalOffsetUs, bufferDurationUs);
+        LOG(VERBOSE) << __func__ << ": sleeping for " << sleepTimeUs << " us";
+        usleep(sleepTimeUs);
+    }
+    return ::android::OK;
 }
 
 ::android::status_t StreamRemoteSubmix::refinePosition(StreamDescriptor::Position* position) {
@@ -200,12 +214,7 @@
     if (sink != nullptr) {
         if (sink->isShutdown()) {
             sink.clear();
-            const auto delayUs = getDelayInUsForFrameCount(frameCount);
-            LOG(DEBUG) << __func__ << ": pipe shutdown, ignoring the write, sleeping for "
-                       << delayUs << " us";
-            // the pipe has already been shutdown, this buffer will be lost but we must
-            // simulate timing so we don't drain the output faster than realtime
-            usleep(delayUs);
+            LOG(DEBUG) << __func__ << ": pipe shutdown, ignoring the write";
             *actualFrameCount = frameCount;
             return ::android::OK;
         }
@@ -214,6 +223,9 @@
         return ::android::UNKNOWN_ERROR;
     }
 
+    LOG(VERBOSE) << __func__ << ": " << mDeviceAddress.toString() << ", " << frameCount
+                 << " frames";
+
     const bool shouldBlockWrite = mCurrentRoute->shouldBlockWrite();
     size_t availableToWrite = sink->availableToWrite();
     // NOTE: sink has been checked above and sink and source life cycles are synchronized
@@ -236,6 +248,8 @@
     availableToWrite = sink->availableToWrite();
 
     if (!shouldBlockWrite && frameCount > availableToWrite) {
+        LOG(WARNING) << __func__ << ": writing " << availableToWrite << " vs. requested "
+                     << frameCount;
         // Truncate the request to avoid blocking.
         frameCount = availableToWrite;
     }
@@ -258,92 +272,59 @@
         *actualFrameCount = 0;
         return ::android::UNKNOWN_ERROR;
     }
-    LOG(VERBOSE) << __func__ << ": wrote " << writtenFrames << "frames";
+    if (writtenFrames > 0 && frameCount > (size_t)writtenFrames) {
+        LOG(WARNING) << __func__ << ": wrote " << writtenFrames << " vs. requested " << frameCount;
+    }
     *actualFrameCount = writtenFrames;
     return ::android::OK;
 }
 
 ::android::status_t StreamRemoteSubmix::inRead(void* buffer, size_t frameCount,
                                                size_t* actualFrameCount) {
+    // in any case, it is emulated that data for the entire buffer was available
+    memset(buffer, 0, mStreamConfig.frameSize * frameCount);
+    *actualFrameCount = frameCount;
+
     // about to read from audio source
     sp<MonoPipeReader> source = mCurrentRoute->getSource();
     if (source == nullptr) {
-        int readErrorCount = mCurrentRoute->notifyReadError();
-        if (readErrorCount < kMaxReadErrorLogs) {
+        if (++mReadErrorCount < kMaxReadErrorLogs) {
             LOG(ERROR) << __func__
                        << ": no audio pipe yet we're trying to read! (not all errors will be "
                           "logged)";
-        } else {
-            LOG(ERROR) << __func__ << ": Read errors " << readErrorCount;
         }
-        const auto delayUs = getDelayInUsForFrameCount(frameCount);
-        LOG(DEBUG) << __func__ << ": no source, ignoring the read, sleeping for " << delayUs
-                   << " us";
-        usleep(delayUs);
-        memset(buffer, 0, mStreamConfig.frameSize * frameCount);
-        *actualFrameCount = frameCount;
         return ::android::OK;
     }
 
+    LOG(VERBOSE) << __func__ << ": " << mDeviceAddress.toString() << ", " << frameCount
+                 << " frames";
     // read the data from the pipe
-    int attempts = 0;
-    const long delayUs = kReadAttemptSleepUs;
     char* buff = (char*)buffer;
-    size_t remainingFrames = frameCount;
-    int availableToRead = source->availableToRead();
-
-    while ((remainingFrames > 0) && (availableToRead > 0) && (attempts < kMaxReadFailureAttempts)) {
-        LOG(VERBOSE) << __func__ << ": frames available to read " << availableToRead;
-
+    size_t actuallyRead = 0;
+    long remainingFrames = frameCount;
+    const long deadlineTimeNs = ::android::uptimeNanos() +
+                                getDelayInUsForFrameCount(frameCount) * NANOS_PER_MICROSECOND;
+    while (remainingFrames > 0) {
         ssize_t framesRead = source->read(buff, remainingFrames);
-
         LOG(VERBOSE) << __func__ << ": frames read " << framesRead;
-
         if (framesRead > 0) {
             remainingFrames -= framesRead;
             buff += framesRead * mStreamConfig.frameSize;
-            availableToRead -= framesRead;
-            LOG(VERBOSE) << __func__ << ": (attempts = " << attempts << ") got " << framesRead
+            LOG(VERBOSE) << __func__ << ": got " << framesRead
                          << " frames, remaining =" << remainingFrames;
-        } else {
-            attempts++;
-            LOG(WARNING) << __func__ << ": read returned " << framesRead
-                         << " , read failure attempts = " << attempts << ", sleeping for "
-                         << delayUs << " us";
-            usleep(delayUs);
+            actuallyRead += framesRead;
+        }
+        if (::android::uptimeNanos() >= deadlineTimeNs) break;
+        if (framesRead <= 0) {
+            LOG(VERBOSE) << __func__ << ": read returned " << framesRead
+                         << ", read failure, sleeping for " << kReadAttemptSleepUs << " us";
+            usleep(kReadAttemptSleepUs);
         }
     }
-    // done using the source
-    source.clear();
-
-    if (remainingFrames > 0) {
-        const size_t remainingBytes = remainingFrames * mStreamConfig.frameSize;
-        LOG(VERBOSE) << __func__ << ": clearing remaining_frames = " << remainingFrames;
-        memset(((char*)buffer) + (mStreamConfig.frameSize * frameCount) - remainingBytes, 0,
-               remainingBytes);
+    if (actuallyRead < frameCount) {
+        LOG(WARNING) << __func__ << ": read " << actuallyRead << " vs. requested " << frameCount;
     }
-
-    long readCounterFrames = mCurrentRoute->updateReadCounterFrames(frameCount);
-    *actualFrameCount = frameCount;
-
-    // compute how much we need to sleep after reading the data by comparing the wall clock with
-    //   the projected time at which we should return.
-    // wall clock after reading from the pipe
-    auto recordDurationUs = std::chrono::duration_cast<std::chrono::microseconds>(
-            std::chrono::steady_clock::now() - mCurrentRoute->getRecordStartTime());
-
-    // readCounterFrames contains the number of frames that have been read since the beginning of
-    // recording (including this call): it's converted to usec and compared to how long we've been
-    // recording for, which gives us how long we must wait to sync the projected recording time, and
-    // the observed recording time.
-    const long projectedVsObservedOffsetUs =
-            getDelayInUsForFrameCount(readCounterFrames) - recordDurationUs.count();
-
-    LOG(VERBOSE) << __func__ << ": record duration " << recordDurationUs.count()
-                 << " us, will wait: " << projectedVsObservedOffsetUs << " us";
-    if (projectedVsObservedOffsetUs > 0) {
-        usleep(projectedVsObservedOffsetUs);
-    }
+    mCurrentRoute->updateReadCounterFrames(*actualFrameCount);
     return ::android::OK;
 }
 
diff --git a/audio/aidl/default/r_submix/SubmixRoute.cpp b/audio/aidl/default/r_submix/SubmixRoute.cpp
index ddac64d..f04e607 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.cpp
+++ b/audio/aidl/default/r_submix/SubmixRoute.cpp
@@ -81,11 +81,6 @@
     return (mStreamInOpen || (mStreamInStandby && (mReadCounterFrames != 0)));
 }
 
-int SubmixRoute::notifyReadError() {
-    std::lock_guard guard(mLock);
-    return ++mReadErrorCount;
-}
-
 long SubmixRoute::updateReadCounterFrames(size_t frameCount) {
     std::lock_guard guard(mLock);
     mReadCounterFrames += frameCount;
@@ -103,7 +98,6 @@
         }
         mStreamInStandby = true;
         mReadCounterFrames = 0;
-        mReadErrorCount = 0;
     } else {
         mStreamOutOpen = true;
     }
@@ -214,9 +208,6 @@
         if (mStreamInStandby || mStreamOutStandbyTransition) {
             mStreamInStandby = false;
             mStreamOutStandbyTransition = false;
-            // keep track of when we exit input standby (== first read == start "real recording")
-            // or when we start recording silence, and reset projected time
-            mRecordStartTime = std::chrono::steady_clock::now();
             mReadCounterFrames = 0;
         }
     } else {
diff --git a/audio/aidl/default/r_submix/SubmixRoute.h b/audio/aidl/default/r_submix/SubmixRoute.h
index 92b95e9..252b1c9 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.h
+++ b/audio/aidl/default/r_submix/SubmixRoute.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include <chrono>
 #include <mutex>
 
 #include <android-base/thread_annotations.h>
@@ -83,14 +82,6 @@
         std::lock_guard guard(mLock);
         return mReadCounterFrames;
     }
-    int getReadErrorCount() {
-        std::lock_guard guard(mLock);
-        return mReadErrorCount;
-    }
-    std::chrono::time_point<std::chrono::steady_clock> getRecordStartTime() {
-        std::lock_guard guard(mLock);
-        return mRecordStartTime;
-    }
     sp<MonoPipe> getSink() {
         std::lock_guard guard(mLock);
         return mSink;
@@ -126,9 +117,6 @@
     bool mStreamOutStandby GUARDED_BY(mLock) = true;
     // how many frames have been requested to be read since standby
     long mReadCounterFrames GUARDED_BY(mLock) = 0;
-    int mReadErrorCount GUARDED_BY(mLock) = 0;
-    // wall clock when recording starts
-    std::chrono::time_point<std::chrono::steady_clock> mRecordStartTime GUARDED_BY(mLock);
 
     // Pipe variables: they handle the ring buffer that "pipes" audio:
     //  - from the submix virtual audio output == what needs to be played
diff --git a/audio/effect/5.0/xml/Android.bp b/audio/effect/5.0/xml/Android.bp
index 7982e2a..ed12e38 100644
--- a/audio/effect/5.0/xml/Android.bp
+++ b/audio/effect/5.0/xml/Android.bp
@@ -9,6 +9,6 @@
 
 xsd_config {
     name: "audio_effects_conf_V5_0",
-    srcs: ["audio_effects_conf.xsd"],
+    srcs: [":audio_effects_conf_V2_0"],
     package_name: "audio.effects.V5_0",
 }
diff --git a/audio/effect/5.0/xml/audio_effects_conf.xsd b/audio/effect/5.0/xml/audio_effects_conf.xsd
deleted file mode 120000
index 9d85fa7..0000000
--- a/audio/effect/5.0/xml/audio_effects_conf.xsd
+++ /dev/null
@@ -1 +0,0 @@
-../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
index 2148244..418dd7a 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AacObjectType.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum AacObjectType {
-  MPEG2_LC = 0,
-  MPEG4_LC = 1,
-  MPEG4_LTP = 2,
-  MPEG4_SCALABLE = 3,
+  MPEG2_LC,
+  MPEG4_LC,
+  MPEG4_LTP,
+  MPEG4_SCALABLE,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
index 0499b70..675f9f2 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
@@ -38,5 +38,5 @@
   MONO = 1,
   DUAL_MONO = 2,
   TWS_STEREO = 4,
-  UNKNOWN = 255,
+  UNKNOWN = 0xFF,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
index f702939..a18303e 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
@@ -34,6 +34,6 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="int") @VintfStability
 enum AptxAdaptiveInputMode {
-  STEREO = 0,
-  DUAL_MONO = 1,
+  STEREO = 0x00,
+  DUAL_MONO = 0x01,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxMode.aidl
index d5dd9d9..dd8cf08 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AptxMode.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="int") @VintfStability
 enum AptxMode {
-  UNKNOWN = 0,
-  HIGH_QUALITY = 4096,
-  LOW_LATENCY = 8192,
-  ULTRA_LOW_LATENCY = 16384,
+  UNKNOWN = 0x00,
+  HIGH_QUALITY = 0x1000,
+  LOW_LATENCY = 0x2000,
+  ULTRA_LOW_LATENCY = 0x4000,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl
index 319a5e2..941344c 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/AudioLocation.aidl
@@ -35,6 +35,6 @@
 @Backing(type="int") @VintfStability
 enum AudioLocation {
   UNKNOWN = 1,
-  FRONT_LEFT = 2,
-  FRONT_RIGHT = 4,
+  FRONT_LEFT = (1 << 1) /* 2 */,
+  FRONT_RIGHT = (1 << 2) /* 4 */,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
index feacb80..2bb5cd8 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum ChannelMode {
-  UNKNOWN = 0,
-  MONO = 1,
-  STEREO = 2,
-  DUALMONO = 3,
+  UNKNOWN,
+  MONO,
+  STEREO,
+  DUALMONO,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
index 3e204f9..d4f205e 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
@@ -34,16 +34,16 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="int") @VintfStability
 enum CodecType {
-  UNKNOWN = 0,
-  SBC = 1,
-  AAC = 2,
-  APTX = 3,
-  APTX_HD = 4,
-  LDAC = 5,
-  LC3 = 6,
-  VENDOR = 7,
-  APTX_ADAPTIVE = 8,
-  OPUS = 9,
-  APTX_ADAPTIVE_LE = 10,
-  APTX_ADAPTIVE_LEX = 11,
+  UNKNOWN,
+  SBC,
+  AAC,
+  APTX,
+  APTX_HD,
+  LDAC,
+  LC3,
+  VENDOR,
+  APTX_ADAPTIVE,
+  OPUS,
+  APTX_ADAPTIVE_LE,
+  APTX_ADAPTIVE_LEX,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
index 88d6faf..3d80c4b 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacChannelMode.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum LdacChannelMode {
-  UNKNOWN = 0,
-  STEREO = 1,
-  DUAL = 2,
-  MONO = 3,
+  UNKNOWN,
+  STEREO,
+  DUAL,
+  MONO,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
index 35e4358..a332dc5 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
@@ -34,8 +34,8 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum LdacQualityIndex {
-  HIGH = 0,
-  MID = 1,
-  LOW = 2,
-  ABR = 3,
+  HIGH,
+  MID,
+  LOW,
+  ABR,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
index 091f6d7..9cf65d5 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
@@ -34,6 +34,6 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum SbcAllocMethod {
-  ALLOC_MD_S = 0,
-  ALLOC_MD_L = 1,
+  ALLOC_MD_S,
+  ALLOC_MD_L,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
index 6441a99..7779aa0 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SbcChannelMode.aidl
@@ -34,9 +34,9 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum SbcChannelMode {
-  UNKNOWN = 0,
-  JOINT_STEREO = 1,
-  STEREO = 2,
-  DUAL = 3,
-  MONO = 4,
+  UNKNOWN,
+  JOINT_STEREO,
+  STEREO,
+  DUAL,
+  MONO,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl
index 33a3187..4b2c10f 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/SessionType.aidl
@@ -34,16 +34,16 @@
 package android.hardware.bluetooth.audio;
 @Backing(type="byte") @VintfStability
 enum SessionType {
-  UNKNOWN = 0,
-  A2DP_SOFTWARE_ENCODING_DATAPATH = 1,
-  A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 2,
-  HEARING_AID_SOFTWARE_ENCODING_DATAPATH = 3,
-  LE_AUDIO_SOFTWARE_ENCODING_DATAPATH = 4,
-  LE_AUDIO_SOFTWARE_DECODING_DATAPATH = 5,
-  LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 6,
-  LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH = 7,
-  LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH = 8,
-  LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 9,
-  A2DP_SOFTWARE_DECODING_DATAPATH = 10,
-  A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH = 11,
+  UNKNOWN,
+  A2DP_SOFTWARE_ENCODING_DATAPATH,
+  A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+  LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+  LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
+  LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+  LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH,
+  LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  A2DP_SOFTWARE_DECODING_DATAPATH,
+  A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH,
 }
diff --git a/bluetooth/finder/aidl/Android.bp b/bluetooth/finder/aidl/Android.bp
new file mode 100644
index 0000000..e606d2d
--- /dev/null
+++ b/bluetooth/finder/aidl/Android.bp
@@ -0,0 +1,34 @@
+// 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.bluetooth.finder",
+    vendor_available: true,
+    srcs: ["android/hardware/bluetooth/finder/*.aidl"],
+    stability: "vintf",
+
+    backend: {
+        ndk: {
+            enabled: true,
+        },
+        java: {
+            enabled: true,
+            platform_apis: true,
+        },
+    },
+}
diff --git a/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/Eid.aidl b/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/Eid.aidl
new file mode 100644
index 0000000..42461c5
--- /dev/null
+++ b/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/Eid.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.bluetooth.finder;
+@VintfStability
+parcelable Eid {
+  byte[20] bytes;
+}
diff --git a/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/IBluetoothFinder.aidl b/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/IBluetoothFinder.aidl
new file mode 100644
index 0000000..4bc9041
--- /dev/null
+++ b/bluetooth/finder/aidl/aidl_api/android.hardware.bluetooth.finder/current/android/hardware/bluetooth/finder/IBluetoothFinder.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.bluetooth.finder;
+@VintfStability
+interface IBluetoothFinder {
+  void sendEids(in android.hardware.bluetooth.finder.Eid[] eids);
+  void setPoweredOffFinderMode(in boolean enable);
+  boolean getPoweredOffFinderMode();
+}
diff --git a/bluetooth/finder/aidl/android/hardware/bluetooth/finder/Eid.aidl b/bluetooth/finder/aidl/android/hardware/bluetooth/finder/Eid.aidl
new file mode 100644
index 0000000..ae9b159
--- /dev/null
+++ b/bluetooth/finder/aidl/android/hardware/bluetooth/finder/Eid.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.bluetooth.finder;
+
+/**
+ * Ephemeral Identifier
+ */
+@VintfStability
+parcelable Eid {
+    byte[20] bytes;
+}
diff --git a/bluetooth/finder/aidl/android/hardware/bluetooth/finder/IBluetoothFinder.aidl b/bluetooth/finder/aidl/android/hardware/bluetooth/finder/IBluetoothFinder.aidl
new file mode 100644
index 0000000..615739b
--- /dev/null
+++ b/bluetooth/finder/aidl/android/hardware/bluetooth/finder/IBluetoothFinder.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.bluetooth.finder;
+
+import android.hardware.bluetooth.finder.Eid;
+
+@VintfStability
+interface IBluetoothFinder {
+    /**
+     * API to set the EIDs to the Bluetooth Controller
+     *
+     * @param eids array of 20 bytes EID to the Bluetooth
+     * controller
+     */
+    void sendEids(in Eid[] eids);
+
+    /**
+     * API to enable the powered-off finder feature, which allows the Bluetooth controller to send
+     * beacons after the device is powered off.
+     *
+     * @param enable true to enable; false to disable
+     */
+    void setPoweredOffFinderMode(in boolean enable);
+
+    /**
+     * API for retrieving feature enablement status
+     *
+     * @return the value last set by setPoweredOffFinderMode, false if setPoweredOffFinderMode was
+     *         never been invoked since boot.
+     */
+    boolean getPoweredOffFinderMode();
+}
diff --git a/bluetooth/finder/aidl/default/Android.bp b/bluetooth/finder/aidl/default/Android.bp
new file mode 100644
index 0000000..b364ae1
--- /dev/null
+++ b/bluetooth/finder/aidl/default/Android.bp
@@ -0,0 +1,42 @@
+// 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"],
+}
+
+cc_binary {
+    name: "android.hardware.bluetooth.finder-service.default",
+    relative_install_path: "hw",
+    init_rc: ["bluetooth-finder-service-default.rc"],
+    vintf_fragments: [":manifest_android.hardware.bluetooth.finder-service.default.xml"],
+    vendor: true,
+    srcs: [
+        "BluetoothFinder.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.bluetooth.finder-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+        "libhidlbase",
+        "libutils",
+        "liblog",
+    ],
+}
+
+filegroup {
+    name: "manifest_android.hardware.bluetooth.finder-service.default.xml",
+    srcs: ["bluetooth-finder-service-default.xml"],
+}
diff --git a/bluetooth/finder/aidl/default/BluetoothFinder.cpp b/bluetooth/finder/aidl/default/BluetoothFinder.cpp
new file mode 100644
index 0000000..236a1f8
--- /dev/null
+++ b/bluetooth/finder/aidl/default/BluetoothFinder.cpp
@@ -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.
+ */
+
+#include "BluetoothFinder.h"
+
+namespace aidl::android::hardware::bluetooth::finder::impl {
+
+::ndk::ScopedAStatus BluetoothFinder::sendEids(const ::std::vector<Eid>& keys) {
+  keys_.insert(keys_.end(), keys.begin(), keys.end());
+  return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus BluetoothFinder::setPoweredOffFinderMode(bool enable) {
+  pof_enabled_ = enable;
+  return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus BluetoothFinder::getPoweredOffFinderMode(
+    bool* _aidl_return) {
+  *_aidl_return = pof_enabled_;
+  return ::ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::bluetooth::finder::impl
diff --git a/bluetooth/finder/aidl/default/BluetoothFinder.h b/bluetooth/finder/aidl/default/BluetoothFinder.h
new file mode 100644
index 0000000..16110f6
--- /dev/null
+++ b/bluetooth/finder/aidl/default/BluetoothFinder.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#include <aidl/android/hardware/bluetooth/finder/BnBluetoothFinder.h>
+
+#include <vector>
+
+namespace aidl::android::hardware::bluetooth::finder::impl {
+
+using ::aidl::android::hardware::bluetooth::finder::BnBluetoothFinder;
+using ::aidl::android::hardware::bluetooth::finder::Eid;
+
+class BluetoothFinder : public BnBluetoothFinder {
+ public:
+  BluetoothFinder() = default;
+
+  ::ndk::ScopedAStatus sendEids(const ::std::vector<Eid>& keys) override;
+  ::ndk::ScopedAStatus setPoweredOffFinderMode(bool enable) override;
+  ::ndk::ScopedAStatus getPoweredOffFinderMode(bool* _aidl_return) override;
+
+ private:
+  bool pof_enabled_;
+  std::vector<Eid> keys_;
+};
+
+}  // namespace aidl::android::hardware::bluetooth::finder::impl
diff --git a/bluetooth/finder/aidl/default/bluetooth-finder-service-default.rc b/bluetooth/finder/aidl/default/bluetooth-finder-service-default.rc
new file mode 100644
index 0000000..fea07f0
--- /dev/null
+++ b/bluetooth/finder/aidl/default/bluetooth-finder-service-default.rc
@@ -0,0 +1,6 @@
+service vendor.bluetooth.finder-default /vendor/bin/hw/android.hardware.bluetooth.finder.default
+    class hal
+    capabilities BLOCK_SUSPEND NET_ADMIN SYS_NICE
+    user bluetooth
+    group bluetooth
+    task_profiles ServicePerformance
diff --git a/bluetooth/finder/aidl/default/bluetooth-finder-service-default.xml b/bluetooth/finder/aidl/default/bluetooth-finder-service-default.xml
new file mode 100644
index 0000000..be7c00d
--- /dev/null
+++ b/bluetooth/finder/aidl/default/bluetooth-finder-service-default.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.bluetooth.finder</name>
+        <version>1</version>
+        <fqname>IBluetoothFinder/default</fqname>
+    </hal>
+</manifest>
diff --git a/bluetooth/finder/aidl/default/service.cpp b/bluetooth/finder/aidl/default/service.cpp
new file mode 100644
index 0000000..a117df8
--- /dev/null
+++ b/bluetooth/finder/aidl/default/service.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "aidl.android.hardware.bluetooth.finder.default"
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+#include "BluetoothFinder.h"
+
+using ::aidl::android::hardware::bluetooth::finder::impl::BluetoothFinder;
+
+int main(int /* argc */, char** /* argv */) {
+  ALOGI("Bluetooth Finder HAL registering");
+  if (!ABinderProcess_setThreadPoolMaxThreadCount(0)) {
+    ALOGE("failed to set thread pool max thread count");
+    return 1;
+  }
+
+  std::shared_ptr<BluetoothFinder> service =
+      ndk::SharedRefBase::make<BluetoothFinder>();
+  std::string instance =
+      std::string() + BluetoothFinder::descriptor + "/default";
+  auto result =
+      AServiceManager_addService(service->asBinder().get(), instance.c_str());
+  if (result == STATUS_OK) {
+    ABinderProcess_joinThreadPool();
+  } else {
+    ALOGE("Could not register as a service!");
+  }
+  return 0;
+}
diff --git a/bluetooth/finder/aidl/vts/Android.bp b/bluetooth/finder/aidl/vts/Android.bp
new file mode 100644
index 0000000..6b0285e
--- /dev/null
+++ b/bluetooth/finder/aidl/vts/Android.bp
@@ -0,0 +1,41 @@
+// 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: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalBluetoothFinderTargetTest",
+    defaults: [
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalBluetoothFinderTargetTest.cpp"],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libbinder_ndk",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.bluetooth.finder-V1-ndk",
+        "libbluetooth-types",
+    ],
+    test_config: "VtsHalBluetoothFinderTargetTest.xml",
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.cpp b/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.cpp
new file mode 100644
index 0000000..be07a7d
--- /dev/null
+++ b/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/bluetooth/finder/IBluetoothFinder.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <array>
+#include <vector>
+
+using ::aidl::android::hardware::bluetooth::finder::Eid;
+using ::aidl::android::hardware::bluetooth::finder::IBluetoothFinder;
+using ::ndk::ScopedAStatus;
+
+class BluetoothFinderTest : public ::testing::TestWithParam<std::string> {
+ public:
+  virtual void SetUp() override {
+    ALOGI("SetUp Finder Test");
+    bluetooth_finder = IBluetoothFinder::fromBinder(
+        ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+    ASSERT_NE(bluetooth_finder, nullptr);
+  }
+
+  virtual void TearDown() override {
+    ALOGI("TearDown Finder Test");
+    bluetooth_finder = nullptr;
+    ASSERT_EQ(bluetooth_finder, nullptr);
+  }
+
+  ScopedAStatus sendEids(uint8_t num);
+  ScopedAStatus setPoweredOffFinderMode(bool enable);
+  ScopedAStatus getPoweredOffFinderMode(bool* status);
+
+ private:
+  std::shared_ptr<IBluetoothFinder> bluetooth_finder;
+};
+
+ScopedAStatus BluetoothFinderTest::sendEids(uint8_t numKeys) {
+  std::vector<Eid> keys(numKeys);
+  for (uint_t i = 0; i < numKeys; i++) {
+    std::array<uint8_t, 20> key;
+    key.fill(i + 1);
+    keys[i].bytes = key;
+  }
+  return bluetooth_finder->sendEids(keys);
+}
+
+ScopedAStatus BluetoothFinderTest::setPoweredOffFinderMode(bool enable) {
+  return bluetooth_finder->setPoweredOffFinderMode(enable);
+}
+
+ScopedAStatus BluetoothFinderTest::getPoweredOffFinderMode(bool* status) {
+  return bluetooth_finder->getPoweredOffFinderMode(status);
+}
+
+TEST_P(BluetoothFinderTest, SendEidsSingle) {
+  ScopedAStatus status = sendEids(1);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothFinderTest, Send255Eids) {
+  ScopedAStatus status = sendEids(255);
+  ASSERT_TRUE(status.isOk());
+}
+
+TEST_P(BluetoothFinderTest, setAndGetPoweredOffFinderModeEnable) {
+  ScopedAStatus status = setPoweredOffFinderMode(true);
+  ASSERT_TRUE(status.isOk());
+  bool pof_status;
+  status = getPoweredOffFinderMode(&pof_status);
+  ASSERT_TRUE(status.isOk());
+  ASSERT_TRUE(pof_status);
+}
+
+TEST_P(BluetoothFinderTest, setAndGetPoweredOffFinderModeDisable) {
+  ScopedAStatus status = setPoweredOffFinderMode(false);
+  ASSERT_TRUE(status.isOk());
+  bool pof_status;
+  status = getPoweredOffFinderMode(&pof_status);
+  ASSERT_TRUE(status.isOk());
+  ASSERT_TRUE(!pof_status);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothFinderTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothFinderTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothFinder::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  ABinderProcess_startThreadPool();
+  int status = RUN_ALL_TESTS();
+  ALOGI("Test result = %d", status);
+  return status;
+}
diff --git a/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.xml b/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.xml
new file mode 100644
index 0000000..46053dd
--- /dev/null
+++ b/bluetooth/finder/aidl/vts/VtsHalBluetoothFinderTargetTest.xml
@@ -0,0 +1,33 @@
+<!--
+  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.
+-->
+
+<configuration description="Runs VtsHalBluetoothFinderTargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalBluetoothFinderTargetTest->/data/local/tmp/VtsHalBluetoothFinderTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalBluetoothFinderTargetTest" />
+    </test>
+</configuration>
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index 9f6b78b..de2e1d1 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -147,6 +147,14 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.bluetooth.finder</name>
+        <version>1</version>
+        <interface>
+            <name>IBluetoothFinder</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.boot</name>
         <interface>
             <name>IBootControl</name>
diff --git a/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp b/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp
index 0212e7e..8a3c6f0 100644
--- a/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp
+++ b/tv/hdmi/cec/aidl/default/HdmiCecMock.cpp
@@ -36,6 +36,7 @@
     ALOGE("HdmiCecMock died");
     auto hdmiCecMock = static_cast<HdmiCecMock*>(cookie);
     hdmiCecMock->mCecThreadRun = false;
+    pthread_join(hdmiCecMock->mThreadId, NULL);
 }
 
 ScopedAStatus HdmiCecMock::addLogicalAddress(CecLogicalAddress addr, Result* _aidl_return) {
@@ -89,7 +90,9 @@
     mCallback = callback;
 
     if (callback != nullptr) {
-        AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
+        mDeathRecipient =
+                ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+        AIBinder_linkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this /* cookie */);
 
         mInputFile = open(CEC_MSG_IN_FIFO, O_RDWR | O_CLOEXEC);
         mOutputFile = open(CEC_MSG_OUT_FIFO, O_RDWR | O_CLOEXEC);
@@ -220,7 +223,7 @@
     int r = -1;
 
     // Open the input pipe
-    while (mInputFile < 0) {
+    while (mCecThreadRun && mInputFile < 0) {
         usleep(1000 * 1000);
         mInputFile = open(CEC_MSG_IN_FIFO, O_RDONLY | O_CLOEXEC);
     }
@@ -257,7 +260,15 @@
 HdmiCecMock::HdmiCecMock() {
     ALOGE("[halimp_aidl] Opening a virtual CEC HAL for testing and virtual machine.");
     mCallback = nullptr;
-    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
+}
+
+HdmiCecMock::~HdmiCecMock() {
+    ALOGE("[halimp_aidl] HdmiCecMock shutting down.");
+    mCallback = nullptr;
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(nullptr);
+    mCecThreadRun = false;
+    pthread_join(mThreadId, NULL);
 }
 
 }  // namespace implementation
diff --git a/tv/hdmi/cec/aidl/default/HdmiCecMock.h b/tv/hdmi/cec/aidl/default/HdmiCecMock.h
index aca0581..e78b1cf 100644
--- a/tv/hdmi/cec/aidl/default/HdmiCecMock.h
+++ b/tv/hdmi/cec/aidl/default/HdmiCecMock.h
@@ -40,6 +40,7 @@
 
 struct HdmiCecMock : public BnHdmiCec {
     HdmiCecMock();
+    ~HdmiCecMock();
     ::ndk::ScopedAStatus addLogicalAddress(CecLogicalAddress addr, Result* _aidl_return) override;
     ::ndk::ScopedAStatus clearLogicalAddress() override;
     ::ndk::ScopedAStatus enableAudioReturnChannel(int32_t portId, bool enable) override;