diff options
-rw-r--r-- | aosp_trout_common.mk | 2 | ||||
-rw-r--r-- | aosp_trout_x86.mk | 2 | ||||
-rw-r--r-- | hal/audiocontrol/2.0/Android.bp | 81 | ||||
-rw-r--r-- | hal/audiocontrol/2.0/AudioControl.cpp | 31 | ||||
-rw-r--r-- | hal/audiocontrol/2.0/AudioControl.h | 11 | ||||
-rw-r--r-- | hal/audiocontrol/2.0/AudioControlServer.cpp | 376 | ||||
-rw-r--r-- | hal/audiocontrol/2.0/AudioControlServer.h | 42 | ||||
-rw-r--r-- | hal/audiocontrol/2.0/CloseHandle.cpp | 35 | ||||
-rw-r--r-- | hal/audiocontrol/2.0/CloseHandle.h | 48 | ||||
-rw-r--r-- | hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.cpp | 36 | ||||
-rw-r--r-- | hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.h | 7 | ||||
-rw-r--r-- | hal/audiocontrol/2.0/proto/AudioFocusControl.proto | 1 | ||||
-rw-r--r-- | hal/audiocontrol/2.0/service.cpp | 25 | ||||
-rw-r--r-- | sepolicy/vendor/google/hal_audiocontrol_impl.te | 7 |
14 files changed, 687 insertions, 17 deletions
diff --git a/aosp_trout_common.mk b/aosp_trout_common.mk index 113e8dd..c4e5b50 100644 --- a/aosp_trout_common.mk +++ b/aosp_trout_common.mk @@ -37,3 +37,5 @@ PRODUCT_PROPERTY_OVERRIDES += \ ${LOCAL_DUMPSTATE_PROPERTIES} TARGET_BOARD_INFO_FILE ?= device/google/trout/board-info.txt + +include packages/services/Car/computepipe/products/computepipe.mk diff --git a/aosp_trout_x86.mk b/aosp_trout_x86.mk index 9c0c432..59fb9d9 100644 --- a/aosp_trout_x86.mk +++ b/aosp_trout_x86.mk @@ -18,8 +18,6 @@ $(call inherit-product, device/google/cuttlefish/vsoc_x86/auto/device.mk) include device/google/trout/aosp_trout_common.mk -include packages/services/Car/computepipe/products/computepipe.mk - DEVICE_MANIFEST_FILE += device/google/trout/manifest_x86.xml DEVICE_MATRIX_FILE += device/google/trout/compatibility_matrix.xml DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE := device/google/trout/framework_compatibility_matrix.xml diff --git a/hal/audiocontrol/2.0/Android.bp b/hal/audiocontrol/2.0/Android.bp index 4f77ef6..27dcf17 100644 --- a/hal/audiocontrol/2.0/Android.bp +++ b/hal/audiocontrol/2.0/Android.bp @@ -14,26 +14,95 @@ * limitations under the License. */ +cc_defaults { + name: "audio_control_hal_v2_0_default_trout", + defaults: [ + "hidl_defaults", + ], + shared_libs: [ + "android.hardware.automotive.audiocontrol@2.0", + "libbase", + "libhidlbase", + "liblog", + "libutils", + ], +} + +genrule { + name: "AudioFocusControlProtoStub_h", + tools: [ + "aprotoc", + "protoc-gen-grpc-cpp-plugin", + ], + cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", + srcs: [ + "proto/AudioFocusControl.proto", + ], + out: [ + "AudioFocusControl.pb.h", + "AudioFocusControl.grpc.pb.h", + ], +} + +genrule { + name: "AudioFocusControlProtoStub_cc", + tools: [ + "aprotoc", + "protoc-gen-grpc-cpp-plugin", + ], + cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", + srcs: [ + "proto/AudioFocusControl.proto", + ], + out: [ + "AudioFocusControl.pb.cc", + "AudioFocusControl.grpc.pb.cc", + ], +} + +cc_library { + name: "android.hardware.audiocontrol@2.0-service-audio-control-grpc-server", + vendor: true, + defaults: ["audio_control_hal_v2_0_default_trout"], + srcs: [ + "AudioControlServer.cpp", + ], + generated_headers: [ + "AudioFocusControlProtoStub_h", + ], + generated_sources: [ + "AudioFocusControlProtoStub_cc", + ], + shared_libs: [ + "libgrpc++", + "libprotobuf-cpp-full", + ], + cflags: [ + "-Wno-unused-parameter", + ], +} + cc_binary { name: "android.hardware.audiocontrol@2.0-service.trout", - defaults: ["hidl_defaults"], + defaults: ["audio_control_hal_v2_0_default_trout"], vendor: true, relative_install_path: "hw", srcs: [ "AudioControl.cpp", + "CloseHandle.cpp", "service.cpp", "WatchdogClient.cpp" ], init_rc: ["android.hardware.audiocontrol@2.0-service.trout.rc"], + static_libs: [ + "android.hardware.automotive.utils.vsockinfo", + ], shared_libs: [ - "android.hardware.automotive.audiocontrol@2.0", + "android.hardware.audiocontrol@2.0-service-audio-control-grpc-server", "android.hardware.automotive.utils.watchdog", "carwatchdog_aidl_interface-ndk_platform", - "libbase", "libbinder_ndk", - "libhidlbase", - "liblog", - "libutils", + "libcutils", ], vintf_fragments: ["manifest_android.hardware.audiocontrol@2.0-service.trout.xml"], } diff --git a/hal/audiocontrol/2.0/AudioControl.cpp b/hal/audiocontrol/2.0/AudioControl.cpp index f64effa..9c926fb 100644 --- a/hal/audiocontrol/2.0/AudioControl.cpp +++ b/hal/audiocontrol/2.0/AudioControl.cpp @@ -18,15 +18,29 @@ #include "AudioControl.h" +#include <android-base/logging.h> #include <hidl/HidlTransportSupport.h> +#include "CloseHandle.h" + namespace android::hardware::automotive::audiocontrol::V2_0::implementation { using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; -Return<sp<ICloseHandle>> AudioControl::registerFocusListener(const sp<IFocusListener>&) { +AudioControl::AudioControl(const std::string& audio_control_server_addr) + : mAudioControlServer(MakeAudioControlServer(audio_control_server_addr)) {} + +Return<sp<ICloseHandle>> AudioControl::registerFocusListener(const sp<IFocusListener>& listener) { + LOG(DEBUG) << "registering focus listener"; sp<ICloseHandle> closeHandle(nullptr); + + if (listener) { + closeHandle = new CloseHandle(mAudioControlServer->RegisterFocusListener(listener)); + } else { + LOG(ERROR) << "Unexpected nullptr for listener resulting in no-op."; + } + return closeHandle; } @@ -38,8 +52,11 @@ Return<void> AudioControl::setFadeTowardFront(float) { return Void(); } -Return<void> AudioControl::onAudioFocusChange(hidl_bitfield<AudioUsage>, int, - hidl_bitfield<AudioFocusChange>) { +Return<void> AudioControl::onAudioFocusChange(hidl_bitfield<AudioUsage> usage, int zoneId, + hidl_bitfield<AudioFocusChange> focusChange) { + LOG(INFO) << "Focus changed: " << toString(static_cast<AudioUsage>(focusChange)) + << " for usage " << toString(static_cast<AudioFocusChange>(usage)) << " in zone " + << zoneId; return Void(); } @@ -53,4 +70,12 @@ bool AudioControl::isHealthy() { return true; } +void AudioControl::ServerStart() { + mAudioControlServer->Start(); +} + +void AudioControl::ServerJoin() { + mAudioControlServer->Join(); +} + } // namespace android::hardware::automotive::audiocontrol::V2_0::implementation diff --git a/hal/audiocontrol/2.0/AudioControl.h b/hal/audiocontrol/2.0/AudioControl.h index b61480c..a0c718e 100644 --- a/hal/audiocontrol/2.0/AudioControl.h +++ b/hal/audiocontrol/2.0/AudioControl.h @@ -22,14 +22,22 @@ #include <hidl/MQDescriptor.h> #include <hidl/Status.h> +#include "AudioControlServer.h" + using android::hardware::audio::common::V6_0::AudioUsage; namespace android::hardware::automotive::audiocontrol::V2_0::implementation { class AudioControl : public IAudioControl { public: + explicit AudioControl(const std::string& audio_control_server_addr); + bool isHealthy(); + void ServerStart(); + + void ServerJoin(); + // Methods from ::android::hardware::automotive::audiocontrol::V2_0::IAudioControl follow. Return<sp<ICloseHandle>> registerFocusListener(const sp<IFocusListener>& listener); Return<void> onAudioFocusChange(hidl_bitfield<AudioUsage> usage, int zoneId, @@ -38,7 +46,8 @@ class AudioControl : public IAudioControl { Return<void> setFadeTowardFront(float value) override; Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override; - AudioControl() = default; + private: + std::unique_ptr<AudioControlServer> mAudioControlServer; }; } // namespace android::hardware::automotive::audiocontrol::V2_0::implementation diff --git a/hal/audiocontrol/2.0/AudioControlServer.cpp b/hal/audiocontrol/2.0/AudioControlServer.cpp new file mode 100644 index 0000000..1452549 --- /dev/null +++ b/hal/audiocontrol/2.0/AudioControlServer.cpp @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2020 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 "AudioControlServer.h" + +#include <deque> +#include <string> +#include <thread> + +#include <android-base/logging.h> +#include <grpc++/grpc++.h> + +#include "AudioFocusControl.grpc.pb.h" +#include "AudioFocusControl.pb.h" +#include "libandroid_audio_controller/utils.h" + +using android::hardware::audio::common::V6_0::AudioUsage; +using std::literals::chrono_literals::operator""s; + +namespace android::hardware::automotive::audiocontrol::V2_0::implementation { + +class AudioControlServerImpl : public AudioControlServer, + audio_focus_control_proto::AudioFocusControlServer::Service { + public: + explicit AudioControlServerImpl(const std::string& addr); + + ~AudioControlServerImpl(); + + close_handle_func_t RegisterFocusListener(const sp<IFocusListener>& focusListener) override; + + grpc::Status AudioRequests(::grpc::ServerContext* context, + const audio_focus_control_proto::AudioFocusControlMessage* message, + ::google::protobuf::Empty*) override; + + void Start() override; + + void Join() override; + + private: + void RequestWorker(); + + void CheckSessionHeartbeats(std::chrono::steady_clock::time_point current_timestamp); + + void HandleHeartbeat(aafc_session_id_t session, + std::chrono::steady_clock::time_point timestamp); + + void HandleAcquiring(audio_focus_control_proto::AudioFocusRequest&& acquire_request, + std::chrono::steady_clock::time_point timestamp); + + void HandleReleasing(aafc_session_id_t release_session); + + void RequestAudioFocus(aafc_audio_usage_t usage, aafc_zone_id_t zone, + hidl_bitfield<AudioFocusChange> focus_change); + + void AbandonAudioFocus(aafc_audio_usage_t usage, aafc_zone_id_t zone); + + using grpc_request_t = audio_focus_control_proto::AudioFocusControlMessage; + using focus_listener_request_key_t = std::pair<aafc_audio_usage_t, aafc_zone_id_t>; + + struct AudioFocusSession { + audio_focus_control_proto::AudioFocusRequest mRequest; + std::chrono::steady_clock::time_point mLastHeartbeat; + + focus_listener_request_key_t GetRequestKey() const; + hidl_bitfield<AudioFocusChange> GetFocusChange() const; + }; + + using session_pool_t = std::map<aafc_session_id_t, AudioFocusSession>; + + // data members + + std::string mServiceAddr; + std::unique_ptr<::grpc::Server> mGrpcServer; + sp<IFocusListener> mFocusListener{nullptr}; + + // grpc request queue + std::deque<grpc_request_t> mRequestQueue; + + // On the focus listener side, the usage/zone pair is used as the key, + // and acquiring focus multiple times on the same usage and zone will + // be treated as once, so we have to maintain the "sessions" and ref count + // by ourselves here. + // + // Active audio focus sessions from grpc clients + session_pool_t mSessionPool; + + // ref counts of usage/zone pair + std::map<focus_listener_request_key_t, unsigned> mAudioFocusCount; + + std::atomic<bool> mShutdownFlag{false}; + std::thread mRequestWorker; + + mutable std::mutex mFocusListenerMutex; + mutable std::mutex mRequestQueueMutex; + + std::condition_variable mRequestQueueCV; +}; + +static std::shared_ptr<::grpc::ServerCredentials> getServerCredentials() { + // TODO(chenhaosjtuacm): get secured credentials here + return ::grpc::InsecureServerCredentials(); +} + +AudioControlServerImpl::AudioControlServerImpl(const std::string& addr) : mServiceAddr(addr) {} + +AudioControlServerImpl::~AudioControlServerImpl() { + mShutdownFlag.store(true); + if (mRequestWorker.joinable()) { + mRequestWorker.join(); + } +} + +AudioControlServer::close_handle_func_t AudioControlServerImpl::RegisterFocusListener( + const sp<IFocusListener>& focusListener) { + std::lock_guard<std::mutex> lock(mFocusListenerMutex); + mFocusListener = focusListener; + + return [this, focusListener]() { + std::lock_guard<std::mutex> lock(mFocusListenerMutex); + if (mFocusListener == focusListener) { + mFocusListener = nullptr; + } + }; +} + +void AudioControlServerImpl::Start() { + if (mGrpcServer) { + LOG(WARNING) << __func__ << ": GRPC Server is running."; + return; + } + + ::grpc::ServerBuilder builder; + builder.RegisterService(this); + builder.AddListeningPort(mServiceAddr, getServerCredentials()); + + mGrpcServer = builder.BuildAndStart(); + + CHECK(mGrpcServer) << __func__ << ": failed to create the GRPC server, " + << "please make sure the configuration and permissions are correct."; + + mRequestWorker = std::thread(std::bind(&AudioControlServerImpl::RequestWorker, this)); +} + +void AudioControlServerImpl::Join() { + if (!mGrpcServer) { + LOG(WARNING) << __func__ << ": GRPC Server is not running."; + return; + } + mGrpcServer->Wait(); +} + +grpc::Status AudioControlServerImpl::AudioRequests( + ::grpc::ServerContext* context, + const audio_focus_control_proto::AudioFocusControlMessage* message, + ::google::protobuf::Empty*) { + { + std::lock_guard<std::mutex> lock(mRequestQueueMutex); + mRequestQueue.emplace_back(*message); + } + mRequestQueueCV.notify_all(); + return ::grpc::Status::OK; +} + +void AudioControlServerImpl::RequestWorker() { + constexpr auto kCheckHeartbeatFreq = 1s; + auto nextHeartbeatCheckTime = std::chrono::steady_clock::now(); + while (!mShutdownFlag.load()) { + std::optional<grpc_request_t> message; + { + std::unique_lock<std::mutex> lock(mRequestQueueMutex); + if (mRequestQueue.empty()) { + mRequestQueueCV.wait_until(lock, nextHeartbeatCheckTime, + [this]() { return !mRequestQueue.empty(); }); + } + if (!mRequestQueue.empty()) { + message = std::move(*mRequestQueue.begin()); + mRequestQueue.pop_front(); + } + } + + auto current_timestamp = std::chrono::steady_clock::now(); + if (message) { + for (auto&& active_session : message->active_sessions()) { + HandleHeartbeat(active_session, current_timestamp); + } + + for (auto&& acquire_request : *message->mutable_acquire_requests()) { + HandleAcquiring(std::move(acquire_request), current_timestamp); + } + + for (auto&& release_session : message->release_requests()) { + HandleReleasing(release_session); + } + } + if (current_timestamp >= nextHeartbeatCheckTime) { + nextHeartbeatCheckTime += kCheckHeartbeatFreq; + CheckSessionHeartbeats(current_timestamp); + } + } +} + +void AudioControlServerImpl::HandleHeartbeat(aafc_session_id_t session, + std::chrono::steady_clock::time_point timestamp) { + auto session_search = mSessionPool.find(session); + if (session_search == mSessionPool.end()) { + LOG(ERROR) << __func__ << ": unknown session ID: " << session; + return; + } + auto& session_info = session_search->second; + session_info.mLastHeartbeat = timestamp; +} + +void AudioControlServerImpl::HandleAcquiring( + audio_focus_control_proto::AudioFocusRequest&& acquire_request, + std::chrono::steady_clock::time_point timestamp) { + const auto session_id = acquire_request.session_id(); + const auto session_emplace = mSessionPool.emplace( + session_id, AudioFocusSession{std::move(acquire_request), timestamp}); + if (session_emplace.second == false) { + LOG(ERROR) << __func__ << ": duplicate session ID: " << session_id; + return; + } + + const auto& session_emplace_iter = session_emplace.first; + const auto& session_info = session_emplace_iter->second; + const auto request_key = session_info.GetRequestKey(); + const auto focus_change = session_info.GetFocusChange(); + const auto ref_count_search = mAudioFocusCount.find(request_key); + const auto& [audio_usage, zone_id] = request_key; + LOG(DEBUG) << __func__ << ": acquiring: " << toString(static_cast<AudioUsage>(audio_usage)) + << " " << zone_id << " " << focus_change; + + const bool not_found = ref_count_search == mAudioFocusCount.end(); + const bool count_zero = !not_found && ref_count_search->second == 0; + + if (count_zero) { + LOG(WARNING) << __func__ << ": unexcepted unremoved zero ref count, treating as missing."; + } + + if (not_found || count_zero) { + mAudioFocusCount[request_key] = 1; + RequestAudioFocus(audio_usage, zone_id, focus_change); + } else { + ++ref_count_search->second; + } +} + +void AudioControlServerImpl::HandleReleasing(aafc_session_id_t release_session) { + const auto session_search = mSessionPool.find(release_session); + if (session_search == mSessionPool.end()) { + LOG(ERROR) << __func__ << ": unknown session ID: " << release_session; + return; + } + const auto& session_info = session_search->second; + const auto request_key = session_info.GetRequestKey(); + const auto& [audio_usage, zone_id] = request_key; + mSessionPool.erase(session_search); + LOG(DEBUG) << __func__ << ": releasing: " << toString(static_cast<AudioUsage>(audio_usage)) + << " " << zone_id; + + const auto ref_count_search = mAudioFocusCount.find(request_key); + if (ref_count_search == mAudioFocusCount.end()) { + LOG(ERROR) << __func__ << ": unknown request, audio usage: " + << toString(static_cast<AudioUsage>(audio_usage)) << ", zone: " << zone_id; + return; + } + auto& request_ref_count = ref_count_search->second; + if (--request_ref_count == 0) { + AbandonAudioFocus(audio_usage, zone_id); + mAudioFocusCount.erase(ref_count_search); + } +} + +void AudioControlServerImpl::RequestAudioFocus(aafc_audio_usage_t usage, aafc_zone_id_t zone, + hidl_bitfield<AudioFocusChange> focus_change) { + std::lock_guard<std::mutex> lock(mFocusListenerMutex); + auto listener = mFocusListener; + LOG(DEBUG) << __func__ + << ": requesting focus, usage: " << toString(static_cast<AudioUsage>(usage)) + << ", zone: " << zone + << ", focus change: " << toString(static_cast<AudioFocusChange>(focus_change)); + if (!listener) { + LOG(ERROR) << __func__ << ": audio focus listener has not been registered."; + return; + } + listener->requestAudioFocus(usage, zone, focus_change); +} + +void AudioControlServerImpl::AbandonAudioFocus(aafc_audio_usage_t usage, aafc_zone_id_t zone) { + std::lock_guard<std::mutex> lock(mFocusListenerMutex); + auto listener = mFocusListener; + LOG(DEBUG) << __func__ + << ": abandoning focus, usage: " << toString(static_cast<AudioUsage>(usage)) + << ", zone: " << zone; + if (!listener) { + LOG(ERROR) << __func__ << ": audio focus listener has not been registered."; + return; + } + listener->abandonAudioFocus(usage, zone); +} + +void AudioControlServerImpl::CheckSessionHeartbeats( + std::chrono::steady_clock::time_point current_timestamp) { + constexpr auto kSessionHeartbeatTimeout = 5s; + const auto timestamp_to_sec = [](auto&& timestamp) { + return std::chrono::duration_cast<std::chrono::duration<double>>( + timestamp.time_since_epoch()) + .count(); + }; + + constexpr size_t max_timeout_session_num = 256; + std::array<aafc_session_id_t, max_timeout_session_num> timeout_sessions; + size_t num_of_timeout_sessions = 0; + + for (auto&& current_session : mSessionPool) { + const auto& current_session_id = current_session.first; + const auto& current_session_info = current_session.second; + if (current_session_info.mLastHeartbeat + kSessionHeartbeatTimeout < current_timestamp) { + if (num_of_timeout_sessions >= max_timeout_session_num) { + LOG(ERROR) << __func__ << ": timeout session number exceeds the limit: " + << max_timeout_session_num; + break; + } + LOG(WARNING) << __func__ << ": timeout on session " << current_session_id + << ", last heartbeat at " + << timestamp_to_sec(current_session_info.mLastHeartbeat) + << ", current timestamp is " << timestamp_to_sec(current_timestamp) + << ", timeout limit " << kSessionHeartbeatTimeout.count() << "s"; + timeout_sessions[num_of_timeout_sessions++] = current_session_id; + } + } + + for (int i = 0; i < num_of_timeout_sessions; ++i) { + HandleReleasing(timeout_sessions[i]); + } +} + +AudioControlServerImpl::focus_listener_request_key_t +AudioControlServerImpl::AudioFocusSession::GetRequestKey() const { + return {mRequest.audio_usage(), mRequest.zone_id()}; +} + +hidl_bitfield<AudioFocusChange> AudioControlServerImpl::AudioFocusSession::GetFocusChange() const { + constexpr auto cast_to_bitfield = [](auto&& focus_change) { + return static_cast<hidl_bitfield<AudioFocusChange>>(focus_change); + }; + if (!mRequest.is_transient()) { + return cast_to_bitfield(AudioFocusChange::GAIN); + } + if (mRequest.is_exclusive()) { + return cast_to_bitfield(AudioFocusChange::GAIN_TRANSIENT_EXCLUSIVE); + } + if (mRequest.allow_duck()) { + return cast_to_bitfield(AudioFocusChange::GAIN_TRANSIENT_MAY_DUCK); + } + return cast_to_bitfield(AudioFocusChange::GAIN_TRANSIENT); +} + +std::unique_ptr<AudioControlServer> MakeAudioControlServer(const std::string& addr) { + return std::make_unique<AudioControlServerImpl>(addr); +} + +} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation diff --git a/hal/audiocontrol/2.0/AudioControlServer.h b/hal/audiocontrol/2.0/AudioControlServer.h new file mode 100644 index 0000000..b0cc60b --- /dev/null +++ b/hal/audiocontrol/2.0/AudioControlServer.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#include <functional> +#include <memory> +#include <string> + +#include <android/hardware/automotive/audiocontrol/2.0/IFocusListener.h> + +namespace android::hardware::automotive::audiocontrol::V2_0::implementation { + +class AudioControlServer { + public: + using close_handle_func_t = std::function<void()>; + + virtual ~AudioControlServer() = default; + + virtual close_handle_func_t RegisterFocusListener(const sp<IFocusListener>& focusListener) = 0; + + virtual void Start() = 0; + + virtual void Join() = 0; +}; + +std::unique_ptr<AudioControlServer> MakeAudioControlServer(const std::string& addr); + +} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation diff --git a/hal/audiocontrol/2.0/CloseHandle.cpp b/hal/audiocontrol/2.0/CloseHandle.cpp new file mode 100644 index 0000000..bc47931 --- /dev/null +++ b/hal/audiocontrol/2.0/CloseHandle.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 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 "CloseHandle.h" + +namespace android::hardware::automotive::audiocontrol::V2_0::implementation { + +CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {} + +CloseHandle::~CloseHandle() { + close(); +} + +Return<void> CloseHandle::close() { + const auto wasClosed = mIsClosed.exchange(true); + if (wasClosed) return {}; + + if (mCallback) mCallback(); + return {}; +} + +} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation diff --git a/hal/audiocontrol/2.0/CloseHandle.h b/hal/audiocontrol/2.0/CloseHandle.h new file mode 100644 index 0000000..2378dea --- /dev/null +++ b/hal/audiocontrol/2.0/CloseHandle.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#include <android-base/macros.h> +#include <android/hardware/automotive/audiocontrol/2.0/ICloseHandle.h> + +namespace android::hardware::automotive::audiocontrol::V2_0::implementation { + +/** Generic ICloseHandle implementation ignoring double-close events. */ +class CloseHandle : public ICloseHandle { + public: + using Callback = std::function<void()>; + + /** + * Create a handle with a callback. + * + * The callback is guaranteed to be called exactly once. + * + * \param callback Called on the first close() call, or on destruction of the handle + */ + explicit CloseHandle(Callback callback = nullptr); + virtual ~CloseHandle(); + + Return<void> close() override; + + private: + const Callback mCallback; + std::atomic<bool> mIsClosed = false; + + DISALLOW_COPY_AND_ASSIGN(CloseHandle); +}; + +} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation diff --git a/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.cpp b/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.cpp index d68a3a6..ecfc8cc 100644 --- a/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.cpp +++ b/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.cpp @@ -16,7 +16,9 @@ #include "android_audio_controller.h" -#include <cutils/threads.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <unistd.h> #include <chrono> #include <condition_variable> @@ -34,6 +36,16 @@ namespace android::hardware::automotive::audiocontrol::V2_0::implementation { using std::literals::chrono_literals::operator""s; +static pid_t getCurrentThreadID() { +#ifdef gettid + return gettid(); +#elif defined(SYS_gettid) + return syscall(SYS_gettid); +#else + return getpid(); +#endif +} + class AudioFocusControllerImpl { public: static AudioFocusControllerImpl* GetInstance(); @@ -86,6 +98,23 @@ static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() { return ::grpc::InsecureChannelCredentials(); } +static void validateRequest(aafc_audio_focus_request_t* request) { + if (!request) { + std::cerr << "Validate null request is a no-op"; + return; + } + if (!request->is_transient && (request->allow_duck || request->is_exclusive)) { + std::cerr << "If request is not transient, allow_duck and " + "exclusive options will be ignored." + << std::endl; + } else if (request->allow_duck && request->is_exclusive) { + std::cerr << "allow_duck and is_exclusive cannot be set together, " + "disabled ducking." + << std::endl; + request->allow_duck = false; + } +} + AudioFocusControllerImpl::AudioFocusControllerImpl() : mRequestWorkerThread(std::bind(&AudioFocusControllerImpl::RequestWorker, this)) {} @@ -120,7 +149,7 @@ AudioFocusControllerImpl* AudioFocusControllerImpl::GetInstance() { } aafc_session_id_t AudioFocusControllerImpl::GetNewUniqueSessionID() { - static const auto tid = static_cast<uint64_t>(gettid()); + static const auto tid = static_cast<uint64_t>(getCurrentThreadID()); // 48 bits for timestamp (in nanoseconds), so a session ID // within a thread is guaranteed not to reappear in about 3 days, @@ -139,6 +168,8 @@ aafc_session_id_t AudioFocusControllerImpl::GetNewUniqueSessionID() { } aafc_session_id_t AudioFocusControllerImpl::AcquireFocus(aafc_audio_focus_request_t&& request) { + validateRequest(&request); + auto session_id = AAFC_SESSION_ID_INVALID; { @@ -226,6 +257,7 @@ void AudioFocusControllerImpl::RequestWorker() { acquire_request.set_zone_id(request.request.zone_id); acquire_request.set_allow_duck(request.request.allow_duck); acquire_request.set_is_transient(request.request.is_transient); + acquire_request.set_is_exclusive(request.request.is_exclusive); } for (auto session_id : mSessionsReleaseRequests) { audio_requests.add_release_requests(session_id); diff --git a/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.h b/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.h index ee44317..2d5311d 100644 --- a/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.h +++ b/hal/audiocontrol/2.0/libandroid_audio_controller/android_audio_controller.h @@ -16,6 +16,8 @@ #pragma once +#include <stdbool.h> + #include "utils.h" #ifdef __cplusplus @@ -25,8 +27,9 @@ extern "C" { typedef struct { aafc_audio_usage_t audio_usage; aafc_zone_id_t zone_id; - int allow_duck; - int is_transient; + bool allow_duck; + bool is_transient; + bool is_exclusive; } aafc_audio_focus_request_t; /* Initialize the audio focus controller before using, return 0 when success. diff --git a/hal/audiocontrol/2.0/proto/AudioFocusControl.proto b/hal/audiocontrol/2.0/proto/AudioFocusControl.proto index 1887cae..04db33d 100644 --- a/hal/audiocontrol/2.0/proto/AudioFocusControl.proto +++ b/hal/audiocontrol/2.0/proto/AudioFocusControl.proto @@ -26,6 +26,7 @@ message AudioFocusRequest { int32 zone_id = 3; bool allow_duck = 4; bool is_transient = 5; + bool is_exclusive = 6; } message AudioFocusControlMessage { diff --git a/hal/audiocontrol/2.0/service.cpp b/hal/audiocontrol/2.0/service.cpp index 79c7eec..32ca63f 100644 --- a/hal/audiocontrol/2.0/service.cpp +++ b/hal/audiocontrol/2.0/service.cpp @@ -24,6 +24,7 @@ #include "AudioControl.h" #include "WatchdogClient.h" +#include "vsockinfo.h" // libhidl: using android::hardware::configureRpcThreadpool; @@ -36,11 +37,29 @@ using android::Looper; using android::OK; using android::hardware::automotive::audiocontrol::V2_0::implementation::AudioControl; using android::hardware::automotive::audiocontrol::V2_0::implementation::WatchdogClient; +using android::hardware::automotive::utils::VsockConnectionInfo; // Main service entry point int main() { + const auto si = VsockConnectionInfo::fromRoPropertyStore( + { + "ro.boot.vendor.audiocontrol.server.cid", + "ro.vendor.audiocontrol.server.cid", + }, + { + "ro.boot.vendor.audiocontrol.server.port", + "ro.vendor.audiocontrol.server.port", + }); + + if (!si) { + LOG(ERROR) << "failed to get server connection cid/port; configure and try again."; + return 1; + } else { + LOG(INFO) << "Creating audio control server at " << si->str(); + } + // Create an instance of our service class - android::sp<AudioControl> service = new AudioControl(); + android::sp<AudioControl> service = new AudioControl(si->str()); configureRpcThreadpool(4, false /*callerWillJoin*/); if (service->registerAsService() != OK) { @@ -48,6 +67,9 @@ int main() { return 1; } + // Start audio control server + service->ServerStart(); + // Setup a binder thread pool to be a car watchdog client. ABinderProcess_setThreadPoolMaxThreadCount(1); ABinderProcess_startThreadPool(); @@ -62,6 +84,7 @@ int main() { while (true) { looper->pollAll(-1 /* timeoutMillis */); } + service->ServerJoin(); // We don't ever actually expect to return, so return an error if we do get here return 2; diff --git a/sepolicy/vendor/google/hal_audiocontrol_impl.te b/sepolicy/vendor/google/hal_audiocontrol_impl.te index 823e436..214e7dc 100644 --- a/sepolicy/vendor/google/hal_audiocontrol_impl.te +++ b/sepolicy/vendor/google/hal_audiocontrol_impl.te @@ -12,3 +12,10 @@ carwatchdog_client_domain(hal_audiocontrol_impl) binder_use(hal_audiocontrol_impl) allow system_server hal_audiocontrol_server:process sigkill; + +allow hal_audiocontrol_impl self:vsock_socket { create_socket_perms_no_ioctl listen accept }; + +# TODO(b/130668487): Label the vsock sockets. +allow hal_audiocontrol_impl unlabeled:vsock_socket { read shutdown write }; + +allow hal_audiocontrol_impl proc_net:file { getattr open read }; |