diff --git a/frameworks/native/audiocapturer/src/audio_capturer.cpp b/frameworks/native/audiocapturer/src/audio_capturer.cpp index 53e285d8ac1baa5a11c28bf1df1315d61d2494bc..980710196c0b572d9fcd9fcac27761bdb98a7a32 100644 --- a/frameworks/native/audiocapturer/src/audio_capturer.cpp +++ b/frameworks/native/audiocapturer/src/audio_capturer.cpp @@ -167,7 +167,7 @@ std::shared_ptr AudioCapturer::CreateCapturer(const AudioCapturer } AUDIO_INFO_LOG("StreamClientState for Capturer::CreateCapturer sourceType:%{public}d, capturerFlags:%{public}d, " - "AppInfo:[%{public}d] [%{public}s] [%{public}s], ", sourceType, capturerOptions.capturerInfo.capturerFlags, + "AppInfo:[%{public}d] [%{public}s] [%{public}s] ", sourceType, capturerOptions.capturerInfo.capturerFlags, appInfo.appUid, appInfo.appTokenId == 0 ? "T" : "F", appInfo.appFullTokenId == 0 ? "T" : "F"); AudioStreamType audioStreamType = FindStreamTypeBySourceType(sourceType); diff --git a/frameworks/native/audioutils/include/audio_utils.h b/frameworks/native/audioutils/include/audio_utils.h index 1c884eda976a5bbe7223fa9510029f5a0493a2bc..1c0afd0d3fa3eb4a14a55b43245949fea9d92b1e 100644 --- a/frameworks/native/audioutils/include/audio_utils.h +++ b/frameworks/native/audioutils/include/audio_utils.h @@ -159,8 +159,11 @@ public: static int32_t StartUsingPermission(uint32_t targetTokenId, const char* permission); static int32_t StopUsingPermission(uint32_t targetTokenId, const char* permission); static bool CheckCallingUidPermission(const std::vector &allowedUids); + static bool VerifyMicrophoneBackgroundPermission(uint32_t tokenId); + static bool IsNotNeedBackgroundCaptureSA(int32_t callerUid); + static bool IsNotNeedBackgroundCaptureSourceType(SourceType sourceType); }; - +// will be move to audio_permission.h in the feture class SwitchStreamUtil { public: static bool UpdateSwitchStreamRecord(SwitchStreamInfo &info, SwitchState targetState); diff --git a/frameworks/native/audioutils/src/audio_utils.cpp b/frameworks/native/audioutils/src/audio_utils.cpp index c6f549b05290401c63b4084160c856bbfddad94b..1e49016abcf31d73bdded8cc33516907af687438 100644 --- a/frameworks/native/audioutils/src/audio_utils.cpp +++ b/frameworks/native/audioutils/src/audio_utils.cpp @@ -482,6 +482,34 @@ bool PermissionUtil::VerifySelfPermission() return false; } +bool PermissionUtil::VerifyMicrophoneBackgroundPermission(uint32_t tokenId) +{ + Trace trace("PermissionUtil::VerifyMicrophoneBackground"); + int res = Security::AccessToken::AccessTokenKit::VerifyAccessToken( + tokenId, MICROPHONE_BACKGROUND_PERMISSION); + CHECK_AND_RETURN_RET_LOG(res == Security::AccessToken::PermissionState::PERMISSION_GRANTED, + false, "Permission denied[MICROPHONE_BACKGROUND_PERMISSION]"); + return true; +} + +bool PermissionUtil::IsNotNeedBackgroundCaptureSA(int32_t callerUid) +{ + if (RECORD_ALLOW_BACKGROUND_LIST.count(callerUid)) { + AUDIO_INFO_LOG("internal sa(%{public}d) user directly recording", callerUid); + return true; + } + return false; +} + +bool PermissionUtil::IsNotNeedBackgroundCaptureSourceType(SourceType sourceType) +{ + if (NO_BACKGROUND_CHECK_SOURCE_TYPE.count(sourceType)) { + AUDIO_INFO_LOG("sourceType %{public}d", sourceType); + return true; + } + return false; +} + bool PermissionUtil::VerifySystemPermission() { auto tokenId = IPCSkeleton::GetCallingTokenID(); diff --git a/interfaces/inner_api/native/audiocommon/include/audio_info.h b/interfaces/inner_api/native/audiocommon/include/audio_info.h index d984c5f3857342036547b4b8b5e10a04efe41fef..5854768b10d10dcefaea5cc529596145a22ab288 100644 --- a/interfaces/inner_api/native/audiocommon/include/audio_info.h +++ b/interfaces/inner_api/native/audiocommon/include/audio_info.h @@ -81,6 +81,7 @@ const float MIN_FLOAT_VOLUME = 0.0f; const float MAX_FLOAT_VOLUME = 1.0f; const char* MICROPHONE_PERMISSION = "ohos.permission.MICROPHONE"; +const char* MICROPHONE_BACKGROUND_PERMISSION = "ohos.permission.MICROPHONE_BACKGROUND"; const char* MODIFY_AUDIO_SETTINGS_PERMISSION = "ohos.permission.MODIFY_AUDIO_SETTINGS"; const char* ACCESS_NOTIFICATION_POLICY_PERMISSION = "ohos.permission.ACCESS_NOTIFICATION_POLICY"; const char* CAPTURER_VOICE_DOWNLINK_PERMISSION = "ohos.permission.CAPTURE_VOICE_DOWNLINK_AUDIO"; @@ -1482,6 +1483,20 @@ struct SwitchStreamInfo { } }; +enum BackgroundCaptureState { + DENIED_INVALID, + DENIED_APP_IN_BACKGROUND, + ALLOWED_APP_IN_FOREGROUND, + ALLOWED_INTERRUPT_RESUME, + ALLOWED_SWITCH_STREAM_CREATE, + ALLOWED_SWITCH_STREAM_START, + ALLOWED_EXEMPTION_FOREGROUND_APP, + NOTNEED_SYSTEM_APP, + NOTNEED_EXEMPTION_SA, + NOTNEED_EXEMPTION_SOURCETYPE, + NOTNEED_MICROPHONE_BACKGROUND_PERMISSION +}; + struct StreamSetStateEventInternal : public Parcelable { StreamSetState streamSetState; StreamUsage streamUsage; diff --git a/interfaces/inner_api/native/audiocommon/include/audio_interrupt_info.h b/interfaces/inner_api/native/audiocommon/include/audio_interrupt_info.h index a303b6f778d6915c63d01ce37d8767944f512bd9..048c4931f77e5198e3ca062613fef943961d0b01 100644 --- a/interfaces/inner_api/native/audiocommon/include/audio_interrupt_info.h +++ b/interfaces/inner_api/native/audiocommon/include/audio_interrupt_info.h @@ -154,6 +154,7 @@ struct InterruptEventInternal : public Parcelable { InterruptHint hintType = INTERRUPT_HINT_NONE; float duckVolume = 1.0f; bool callbackToApp = true; + int64_t eventTimestamp = 0; InterruptEventInternal() = default; @@ -164,6 +165,7 @@ struct InterruptEventInternal : public Parcelable { forceType = forcetype; hintType = hinttype; duckVolume = duckvolume; + eventTimestamp = 0; } bool Marshalling(Parcel &parcel) const override diff --git a/services/audio_policy/server/domain/interrupt/include/audio_interrupt_service.h b/services/audio_policy/server/domain/interrupt/include/audio_interrupt_service.h index 1b4845448bc4fdb810e31d40a348241f824fa6bf..4601729ec5ba37bb292f850f0ff3c59261a19b3d 100644 --- a/services/audio_policy/server/domain/interrupt/include/audio_interrupt_service.h +++ b/services/audio_policy/server/domain/interrupt/include/audio_interrupt_service.h @@ -122,6 +122,11 @@ public: std::vector GetAudioSessionUidList(int32_t zoneId); StreamUsage GetAudioSessionStreamUsage(int32_t callerPid); + bool ShouldAudioServerProcessInruptEvent(const InterruptEventInternal &interruptEvent, + const AudioInterrupt &audioInterrupt); + void SendInterruptEventToAudioServer(const InterruptEventInternal &interruptEvent, + const AudioInterrupt &audioInterrupt); + void ProcessRemoteInterrupt(std::set streamIds, InterruptEventInternal interruptEvent); int32_t SetQueryBundleNameListCallback(const sptr &object); void RegisterDefaultVolumeTypeListener(); diff --git a/services/audio_policy/server/domain/interrupt/src/audio_interrupt_service.cpp b/services/audio_policy/server/domain/interrupt/src/audio_interrupt_service.cpp index a4a89fe517050c5639e9c9c744450c37e16361bd..b4ff2b73eb16b7e6968ffa505d2636df60c34822 100644 --- a/services/audio_policy/server/domain/interrupt/src/audio_interrupt_service.cpp +++ b/services/audio_policy/server/domain/interrupt/src/audio_interrupt_service.cpp @@ -30,6 +30,7 @@ #include "app_mgr_client.h" #include "dfx_msg_manager.h" #include "audio_bundle_manager.h" +#include "audio_server_proxy.h" #include "istandard_audio_service.h" #include "session_manager_lite.h" #include "audio_zone_service.h" @@ -2501,6 +2502,49 @@ void AudioInterruptService::SendInterruptEvent(AudioFocuState oldState, AudioFoc iterActive->second = newState; } +bool AudioInterruptService::ShouldAudioServerProcessInruptEvent(const InterruptEventInternal &interruptEvent, + const AudioInterrupt &audioInterrupt) +{ + //only process capture interruptEvent + CHECK_AND_RETURN_RET_LOG(!audioInterrupt.audioFocusType.isPlay, false, + "audioServer need not process playback interruptEvent"); + +#ifdef FEATURE_APPGALLERY + //CLIENT_TYPE_GAME will be muted or unmuted, need not process in FEATURE_APPGALLERY + auto it = interruptClients_.find(audioInterrupt.streamId); + if (it != interruptClients_.end() && it->second != nullptr) { + uint32_t uid = interruptClients_[audioInterrupt.streamId]->GetCallingUid(); + ClientType clientType = ClientTypeManager::GetInstance()->GetClientTypeByUid(uid); + CHECK_AND_RETURN_RET_LOG(clientType != CLIENT_TYPE_GAME, false, "clientType is Game"); + } +#endif + //only process INTERRUPT_HINT_PAUSE INTERRUPT_HINT_STOP INTERRUPT_HINT_RESUME + auto hintType = interruptEvent.hintType; + return hintType == INTERRUPT_HINT_PAUSE || + hintType == INTERRUPT_HINT_RESUME; +} + +void AudioInterruptService::SendInterruptEventToAudioServer( + const InterruptEventInternal &interruptEvent, const AudioInterrupt &audioInterrupt) +{ + CHECK_AND_RETURN_LOG(ShouldAudioServerProcessInruptEvent(interruptEvent, audioInterrupt), + "need not send audioInterrupt to audioServer"); + if (audioInterrupt.isAudioSessionInterrupt) { + AUDIO_INFO_LOG("is audioSession interrupt"); + // record stream may use audioSession in the future,only playback stream use audioSession now + CHECK_AND_RETURN_LOG(sessionService_ != nullptr, "sessionService_ is nullptr"); + const auto &audioInterrupts = sessionService_->GetStreams(audioInterrupt.pid); + for (auto &it : audioInterrupts) { + AudioServerProxy::GetInstance().SendInterruptEventToAudioServerProxy( + interruptEvent, it.streamId); + } + } else { + //send interruptEvent to audioServer , deal with recording in background + AudioServerProxy::GetInstance().SendInterruptEventToAudioServerProxy( + interruptEvent, audioInterrupt.streamId); + } +} + void AudioInterruptService::SendInterruptEventCallback(const InterruptEventInternal &interruptEvent, const uint32_t &streamId, const AudioInterrupt &audioInterrupt) { @@ -2522,7 +2566,7 @@ void AudioInterruptService::SendInterruptEventCallback(const InterruptEventInter AUDIO_ERR_LOG("AudioPolicyServerHandler is nullptr"); return; } - + SendInterruptEventToAudioServer(interruptEvent, audioInterrupt); if (audioInterrupt.isAudioSessionInterrupt) { SendAudioSessionInterruptEventCallback(interruptEvent, audioInterrupt); } else { diff --git a/services/audio_policy/server/infra/ipc_proxy/include/audio_server_proxy.h b/services/audio_policy/server/infra/ipc_proxy/include/audio_server_proxy.h index b66412a1196352bd75d17d7fb20eb0ad67be8ac8..9e55b517148523051fef77048a4382c322355886 100644 --- a/services/audio_policy/server/infra/ipc_proxy/include/audio_server_proxy.h +++ b/services/audio_policy/server/infra/ipc_proxy/include/audio_server_proxy.h @@ -120,6 +120,7 @@ public: void SetSessionMuteState(const uint32_t sessionId, const bool insert, const bool muteFlag); void SetBtHdiInvalidState(); int32_t ForceStopAudioStreamProxy(StopAudioType audioType); + void SendInterruptEventToAudioServerProxy(InterruptEventInternal interruptEvent, int32_t sessionId); private: AudioServerProxy() {} ~AudioServerProxy() {} diff --git a/services/audio_policy/server/infra/ipc_proxy/src/audio_server_proxy.cpp b/services/audio_policy/server/infra/ipc_proxy/src/audio_server_proxy.cpp index 4e0cb0edff7843441f54db0d81303c66a63ad960..49b63e2bf2dfef9aa81afc642fc0d2009bd92e46 100644 --- a/services/audio_policy/server/infra/ipc_proxy/src/audio_server_proxy.cpp +++ b/services/audio_policy/server/infra/ipc_proxy/src/audio_server_proxy.cpp @@ -699,5 +699,16 @@ int32_t AudioServerProxy::ForceStopAudioStreamProxy(StopAudioType audioType) IPCSkeleton::SetCallingIdentity(identity); return res; } + +void AudioServerProxy::SendInterruptEventToAudioServerProxy(InterruptEventInternal interruptEvent, + int32_t sessionId) +{ + AUDIO_INFO_LOG("hintType:%{public}d for stream:%{public}u", interruptEvent.hintType, sessionId); + const sptr gsp = GetAudioServerProxy(); + std::string identity = IPCSkeleton::ResetCallingIdentity(); + CHECK_AND_RETURN_LOG(gsp != nullptr, "error for audio server proxy null"); + gsp->SendInterruptEventToAudioServer(sessionId, interruptEvent); + IPCSkeleton::SetCallingIdentity(identity); +} } } diff --git a/services/audio_service/idl/IStandardAudioService.idl b/services/audio_service/idl/IStandardAudioService.idl index 491bfeaa64d9bbc302ddcb2f963eff5f2cc4b582..5989f0b4c83232f2c3f4a3e3a3f103d605219c71 100644 --- a/services/audio_service/idl/IStandardAudioService.idl +++ b/services/audio_service/idl/IStandardAudioService.idl @@ -32,6 +32,7 @@ sequenceable audio_effect..OHOS.AudioStandard.AudioEnhancePropertyArray; sequenceable hdi_adapter_type..OHOS.AudioStandard.IAudioSinkAttr; sequenceable hdi_adapter_type..OHOS.AudioStandard.IAudioSourceAttr; sequenceable audio_stutter..OHOS.AudioStandard.DataTransferMonitorParam; +sequenceable audio_interrupt_info..OHOS.AudioStandard.InterruptEventInternal; interface IStandardAudioService { [ipccode 0] void GetAudioParameter([in] String key, [out] String value); @@ -143,4 +144,5 @@ interface IStandardAudioService { // undefined in AudioServerInterfaceCode [ipccode 1000] void SetForegroundList([in] List list); void GetVolumeDataCount([in] String sinkName, [out] long ret); + void SendInterruptEventToAudioServer([in] unsigned int sessionId, [in] InterruptEventInternal interruptEvent); } diff --git a/services/audio_service/libaudio_process_service.versionscript b/services/audio_service/libaudio_process_service.versionscript index 5ab9e8992aabb89142dfbdfa3c26e19629f7c3ce..056d705215d7b52c7c2c1c4eb747c38d003e8475 100644 --- a/services/audio_service/libaudio_process_service.versionscript +++ b/services/audio_service/libaudio_process_service.versionscript @@ -80,6 +80,10 @@ *SaveRenderWhitelist*; *InRenderWhitelist*; *HpaeCapturerStreamImpl*; + *UpdateSwitchStreamMap*; + *UpdateBackgroundCaptureMap*; + *SendInterruptEventToAudioServer*; + *SendInterruptEventToAudioService*; local: *; }; \ No newline at end of file diff --git a/services/audio_service/server/include/audio_server.h b/services/audio_service/server/include/audio_server.h index d282d6000d2005f453cacbb5eb737689af160c1f..4c2e85fd6fc810c9fa04030eb6c28321fed71ff5 100644 --- a/services/audio_service/server/include/audio_server.h +++ b/services/audio_service/server/include/audio_server.h @@ -267,6 +267,8 @@ public: void OnMuteStateChange(const int32_t &pid, const int32_t &callbackId, const int32_t &uid, const uint32_t &sessionId, const bool &isMuted) override; int32_t SetBtHdiInvalidState() override; + int32_t SendInterruptEventToAudioServer(uint32_t sessionId, + const InterruptEventInternal &interruptEvent) override; protected: void OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId) override; diff --git a/services/audio_service/server/include/audio_service.h b/services/audio_service/server/include/audio_service.h index d7e6213c33f6409ee7f73340532a76e663b6c9f8..333db3af8c83a3c27b36074415236f3e04350e7d 100644 --- a/services/audio_service/server/include/audio_service.h +++ b/services/audio_service/server/include/audio_service.h @@ -142,6 +142,27 @@ public: #endif void RenderersCheckForAudioWorkgroup(int32_t pid); + bool IsInSwitchStreamMap(uint32_t sessionId, SwitchState &switchState); + bool UpdateSwitchStreamMap(uint32_t sessionId, SwitchState switchState); + void RemoveSwitchStreamMap(uint32_t sessionId); + + bool IsInInterruptEventMap(const uint32_t sessionId, InterruptEventInternal &interruptEvent); + bool UpdateInterruptEventMap(const uint32_t sessionId, InterruptEventInternal interruptEvent); + bool RemoveInterruptEventMap(const uint32_t sessionIdt); + + bool IsInBackgroudCaptureMap(uint32_t sessionId, BackgroundCaptureState &backCapState); + + void UpdateBackgroundCaptureMap(const uint32_t sessionId, const BackgroundCaptureState backCapState); + void RemoveBackgroundCaptureMap(const uint32_t sessionId); + bool NeedRemoveInterruptEventAndBackCap(uint32_t sessionId); + + bool NeedVerifyBackgroundCapture(uint32_t sessionId, AudioProcessConfig config); + BackgroundCaptureState VerifyBackgroundCapture(uint32_t sessionId, AudioProcessConfig config); + BackgroundCaptureState UpdateVerifyBackgroundCapture(uint32_t sessionId, AudioProcessConfig config); + bool IsAllowedUsingMicrophone(uint32_t sessionId, AudioProcessConfig config); + + void SendInterruptEventToAudioService(uint32_t sessionId, InterruptEventInternal interruptEvent); + private: AudioService(); void DelayCallReleaseEndpoint(std::string endpointName); @@ -187,6 +208,12 @@ private: std::mutex foregroundSetMutex_; std::set foregroundSet_; std::set foregroundUidSet_; + std::mutex audioSwitchStreamMutex_; + std::map audioSwitchStreamMap_; + std::mutex audioStreamInterruptEventMutex_; + std::map audioStreamInterruptEventMap_; + std::mutex audioStreamBackCapMutex_; + std::map audioStreamBackCapMap_; std::mutex processListMutex_; std::mutex releaseEndpointMutex_; std::condition_variable releaseEndpointCV_; diff --git a/services/audio_service/server/src/audio_process_in_server.cpp b/services/audio_service/server/src/audio_process_in_server.cpp index 6249face778fd29da243b3a26658f9bd3c4ca3da..dde62d636512fffa4b3b8d050e4fbfb5046eb6b6 100644 --- a/services/audio_service/server/src/audio_process_in_server.cpp +++ b/services/audio_service/server/src/audio_process_in_server.cpp @@ -231,8 +231,12 @@ bool AudioProcessInServer::TurnOnMicIndicator(CapturerState capturerState) tokenId, capturerState, }; - if (!SwitchStreamUtil::IsSwitchStreamSwitching(info, SWITCH_STATE_STARTED)) { - CHECK_AND_RETURN_RET_LOG(CheckBGCapturer(), false, "Verify failed"); + if (SwitchStreamUtil::IsSwitchStreamSwitching(info, SWITCH_STATE_STARTED)) { + AudioService::GetInstance()->UpdateBackgroundCaptureMap(sessionId_, ALLOWED_SWITCH_STREAM_START); + AudioService::GetInstance()->UpdateSwitchStreamMap(sessionId_, SWITCH_STATE_STARTED); + } else { + CHECK_AND_RETURN_RET_LOG(AudioService::GetInstance()->IsAllowedUsingMicrophone( + sessionId_, processConfig_), false, "Verify failed"); } SwitchStreamUtil::UpdateSwitchStreamRecord(info, SWITCH_STATE_STARTED); @@ -262,6 +266,11 @@ bool AudioProcessInServer::TurnOffMicIndicator(CapturerState capturerState) }; SwitchStreamUtil::UpdateSwitchStreamRecord(info, SWITCH_STATE_FINISHED); + if (AudioService::GetInstance()->NeedRemoveInterruptEventAndBackCap(sessionId_)) { + AudioService::GetInstance()->RemoveBackgroundCaptureMap(sessionId_); + AudioService::GetInstance()->RemoveInterruptEventMap(sessionId_); + } + if (isMicIndicatorOn_) { PermissionUtil::NotifyPrivacyStop(tokenId, sessionId_); AUDIO_INFO_LOG("Turn off micIndicator of stream:%{public}d from on after NotifyPrivacyStop!", sessionId_); @@ -835,8 +844,8 @@ RestoreStatus AudioProcessInServer::RestoreSession(RestoreInfo restoreInfo) HandleStreamStatusToCapturerState(streamStatus_->load()) }; AUDIO_INFO_LOG("Insert fast record stream:%{public}u uid:%{public}d tokenId:%{public}u " - "into switchStreamRecord because restoreStatus:NEED_RESTORE", - sessionId_, info.callerUid, info.appTokenId); + "restoreStatus:NEED_RESTORE", sessionId_, info.callerUid, info.appTokenId); + AudioService::GetInstance()->UpdateSwitchStreamMap(sessionId_, SWITCH_STATE_WAITING); SwitchStreamUtil::UpdateSwitchStreamRecord(info, SWITCH_STATE_WAITING); } diff --git a/services/audio_service/server/src/audio_server.cpp b/services/audio_service/server/src/audio_server.cpp index 2319cf0186623edef51277e3674fa86270f5302a..574f9244d572ceace169043a8c5148101423f282 100644 --- a/services/audio_service/server/src/audio_server.cpp +++ b/services/audio_service/server/src/audio_server.cpp @@ -2272,6 +2272,15 @@ bool AudioServer::CheckRecorderPermission(const AudioProcessConfig &config) } // LCOV_EXCL_STOP +int32_t AudioServer::SendInterruptEventToAudioServer(uint32_t sessionId, const InterruptEventInternal &interruptEvent) +{ + int32_t callingUid = IPCSkeleton::GetCallingUid(); + CHECK_AND_RETURN_RET_LOG(PermissionUtil::VerifyIsAudio(), ERR_PERMISSION_DENIED, + "Refused for %{public}d", callingUid); + AudioService::GetInstance()->SendInterruptEventToAudioService(sessionId, interruptEvent); + return SUCCESS; +} + bool AudioServer::HandleCheckRecorderBackgroundCapture(const AudioProcessConfig &config) { if (!PermissionUtil::NeedVerifyBackgroundCapture(config.callerUid, config.capturerInfo.sourceType)) { @@ -2297,6 +2306,8 @@ bool AudioServer::HandleCheckRecorderBackgroundCapture(const AudioProcessConfig AUDIO_INFO_LOG("Recreating stream for callerUid:%{public}d need not VerifyBackgroundCapture", config.callerUid); SwitchStreamUtil::UpdateSwitchStreamRecord(info, SWITCH_STATE_CREATED); + AudioService::GetInstance()->UpdateBackgroundCaptureMap(config.originalSessionId, ALLOWED_SWITCH_STREAM_CREATE); + AudioService::GetInstance()->UpdateSwitchStreamMap(config.originalSessionId, SWITCH_STATE_CREATED); return true; } diff --git a/services/audio_service/server/src/audio_service.cpp b/services/audio_service/server/src/audio_service.cpp index f9f4e3365a87dd794300d5eaf3711d3646079ac5..bcc8f11e0b5115b2d2b10127739a31cba5785f71 100644 --- a/services/audio_service/server/src/audio_service.cpp +++ b/services/audio_service/server/src/audio_service.cpp @@ -54,6 +54,7 @@ static const int32_t MEDIA_SERVICE_UID = 1013; static const int32_t RENDERER_STREAM_CNT_PER_UID_LIMIT = 40; static const int32_t INVALID_APP_UID = -1; static const int32_t INVALID_APP_CREATED_AUDIO_STREAM_NUM = 0; +static const uint32_t ALLOW_BACKGROUND_CAPTURE_INTERRUPT_RESUME_TIME_OUT = 2; //2s namespace { static inline const std::unordered_set specialSourceTypeSet_ = { SOURCE_TYPE_PLAYBACK_CAPTURE, @@ -61,6 +62,22 @@ static inline const std::unordered_set specialSourceTypeSet_ = { SOURCE_TYPE_VIRTUAL_CAPTURE, SOURCE_TYPE_REMOTE_CAST }; + +const std::set NEED_NOT_VERIFY_BACKGROUND_CAPTURE_LIST = { + NOTNEED_SYSTEM_APP, + NOTNEED_EXEMPTION_SA, + NOTNEED_EXEMPTION_SOURCETYPE, + NOTNEED_MICROPHONE_BACKGROUND_PERMISSION +}; + +const std::set ALLOWED_BACKGROUND_CAPTURE_LIST = { + ALLOWED_APP_IN_FOREGROUND, + ALLOWED_EXEMPTION_FOREGROUND_APP, + ALLOWED_SWITCH_STREAM_CREATE, + ALLOWED_SWITCH_STREAM_START, + ALLOWED_INTERRUPT_RESUME +}; + const size_t MAX_FG_LIST_SIZE = 10; } @@ -343,6 +360,291 @@ bool AudioService::InForegroundList(uint32_t uid) return false; } +bool AudioService::IsInSwitchStreamMap(uint32_t sessionId, SwitchState &switchState) +{ + std::lock_guard lock(audioSwitchStreamMutex_); + auto iter = audioSwitchStreamMap_.find(sessionId); + CHECK_AND_RETURN_RET_LOG(iter != audioSwitchStreamMap_.end(), false, + "can not find switchStream:%{public}u", sessionId); + switchState = iter->second; + AUDIO_INFO_LOG("SwitchStream:%{public}u, switchState:%{public}d", sessionId, switchState); + return true; +} + +bool AudioService::UpdateSwitchStreamMap(uint32_t sessionId, SwitchState switchState) +{ + std::lock_guard lock(audioSwitchStreamMutex_); + auto iter = audioSwitchStreamMap_.find(sessionId); + if (iter == audioSwitchStreamMap_.end()) { + audioSwitchStreamMap_[sessionId] = switchState; + AUDIO_WARNING_LOG ("Inserted switchStream:%{public}u, switchState:%{public}d", sessionId, switchState); + return true; + } + iter->second = switchState; + AUDIO_INFO_LOG("Updated switchStream:%{public}u, switchState:%{public}d", sessionId, switchState); + return true; +} + +void AudioService::RemoveSwitchStreamMap(uint32_t sessionId) +{ + std::lock_guard lock(audioSwitchStreamMutex_); + auto iter = audioSwitchStreamMap_.find(sessionId); + if (iter != audioSwitchStreamMap_.end()) { + AUDIO_INFO_LOG("Removed switchStream:%{public}u, switchState:%{public}d", sessionId, iter->second); + audioSwitchStreamMap_.erase(iter); + } else { + AUDIO_WARNING_LOG("switchStream:%{public}u not found", sessionId); + } +} + +bool AudioService::IsInBackgroudCaptureMap(uint32_t sessionId, BackgroundCaptureState &backCapState) +{ + std::lock_guard lock(audioStreamBackCapMutex_); + auto iter = audioStreamBackCapMap_.find(sessionId); + CHECK_AND_RETURN_RET_LOG(iter != audioStreamBackCapMap_.end(), false, + "can not find sessionId:%{public}u", sessionId); + backCapState = iter->second; + AUDIO_INFO_LOG("sessionId:%{public}u, backCapState:%{public}d", sessionId, backCapState); + return true; +} + +void AudioService::UpdateBackgroundCaptureMap(const uint32_t sessionId, + const BackgroundCaptureState backCapState) +{ + std::unique_lock lock(audioStreamBackCapMutex_); + auto it = audioStreamBackCapMap_.find(sessionId); + if (it == audioStreamBackCapMap_.end()) { + audioStreamBackCapMap_[sessionId] = backCapState; + AUDIO_WARNING_LOG("Inserted backgroundCapture:%{public}u backCapState:%{public}d", sessionId, backCapState); + } else { + it->second = backCapState; + AUDIO_INFO_LOG("Updated backgroundCapture:%{public}u backCapState:%{public}d", sessionId, backCapState); + } +} + +void AudioService::RemoveBackgroundCaptureMap(const uint32_t sessionId) +{ + std::unique_lock lock(audioStreamBackCapMutex_); + auto it = audioStreamBackCapMap_.find(sessionId); + if (it != audioStreamBackCapMap_.end()) { + audioStreamBackCapMap_.erase(it); + AUDIO_INFO_LOG("Remove stream:%{public}u from map", sessionId); + } else { + AUDIO_ERR_LOG("Remove failed, stream:%{public}u not found", sessionId); + } +} + +bool AudioService::NeedVerifyBackgroundCapture(uint32_t sessionId, AudioProcessConfig config) +{ + auto sourceType = config.capturerInfo.sourceType; + int32_t callerUid = config.callerUid; + uint32_t tokenId = config.appInfo.appTokenId; + if (PermissionUtil::IsNotNeedBackgroundCaptureSA(config.callerUid)) { + AUDIO_INFO_LOG("Stream:%{public}u Result:not need Reason:internal sa[%{public}d]", + sessionId, callerUid); + return false; + } + if (PermissionUtil::IsNotNeedBackgroundCaptureSourceType(sourceType)) { + AUDIO_INFO_LOG("Stream:%{public}u Result:not need Reason:special sourceType[%{public}d]", + sessionId, sourceType); + return false; + } + if (PermissionUtil::VerifyIsSystemApp()) { + AUDIO_INFO_LOG("Stream:%{public}u Result:not need Reason:system app", sessionId); + return false; + } + if (PermissionUtil::VerifyMicrophoneBackgroundPermission(tokenId)) { + AUDIO_INFO_LOG("Stream:%{public}u Result:not need " + "Reason:has permission[MICROPHONE_BACKGROUND_PERMISSION]", sessionId); + return false; + } + + AUDIO_INFO_LOG("stream:%{public}u need check backgroud capture", sessionId); + return true; +} + +BackgroundCaptureState AudioService::VerifyBackgroundCapture(uint32_t sessionId, AudioProcessConfig config) +{ + uint32_t tokenId = config.appInfo.appTokenId; + uint64_t fullTokenId = config.appInfo.appFullTokenId; + BackgroundCaptureState backCapState = DENIED_INVALID; + bool res = PermissionUtil::VerifyBackgroundCapture(tokenId, fullTokenId); + if (res) { + AUDIO_INFO_LOG("Stream:%{public}u Result:allowed Reason:app in foreground", sessionId); + backCapState = ALLOWED_APP_IN_FOREGROUND; + return backCapState; + } else { + backCapState = DENIED_APP_IN_BACKGROUND; + if (config.capturerInfo.sourceType == SOURCE_TYPE_VOICE_COMMUNICATION && + InForegroundList(config.appInfo.appUid)) { + UpdateForegroundState(tokenId, true); + res = PermissionUtil::VerifyBackgroundCapture(tokenId, fullTokenId); + UpdateForegroundState(tokenId, false); + backCapState = res ? ALLOWED_EXEMPTION_FOREGROUND_APP : DENIED_APP_IN_BACKGROUND; + } + } + AUDIO_INFO_LOG("Stream:%{public}u Result:%{public}s Reason:%{public}d", + sessionId, res ? "allowed" : "denied", backCapState); + return backCapState; +} + +BackgroundCaptureState AudioService::UpdateVerifyBackgroundCapture( + uint32_t sessionId, AudioProcessConfig config) +{ + BackgroundCaptureState backCapState = DENIED_INVALID; + //InterruptEvent Resume + InterruptEventInternal interruptEvent; + if (IsInInterruptEventMap(sessionId, interruptEvent)) { + int64_t stamp = interruptEvent.eventTimestamp; + stamp = (ClockTime::GetCurNano() - stamp) / AUDIO_US_PER_SECOND; + if (stamp <= ALLOW_BACKGROUND_CAPTURE_INTERRUPT_RESUME_TIME_OUT) { + if (interruptEvent.hintType == INTERRUPT_HINT_NONE) { + AUDIO_WARNING_LOG("NONE Interrupt means Pause and Resume, need change to Pause "); + interruptEvent.hintType = INTERRUPT_HINT_PAUSE; + UpdateInterruptEventMap(sessionId, interruptEvent); + backCapState = ALLOWED_INTERRUPT_RESUME; + UpdateBackgroundCaptureMap(sessionId, backCapState); + } else if (interruptEvent.hintType == INTERRUPT_HINT_RESUME) { + backCapState = ALLOWED_INTERRUPT_RESUME; + UpdateBackgroundCaptureMap(sessionId, backCapState); + RemoveInterruptEventMap(sessionId); + } else { + AUDIO_WARNING_LOG("PAUSE interrupt event"); + return backCapState; + } + } else { + AUDIO_WARNING_LOG("Timeout! Remove all interruptEvent for stream:%{public}u", sessionId); + RemoveInterruptEventMap(sessionId); + } + } + return backCapState; +} + +bool AudioService::IsAllowedUsingMicrophone(uint32_t sessionId, AudioProcessConfig config) +{ + uint32_t tokenId = config.appInfo.appTokenId; + //check mic permission + if (!PermissionUtil::VerifyPermission(MICROPHONE_PERMISSION, tokenId)) { + RemoveBackgroundCaptureMap(sessionId); + AUDIO_ERR_LOG("Stream:%{public}u Result:deined Reason:no permission[MICROPHONE_PERMISSION]", sessionId); + return false; + } + //check background capture + BackgroundCaptureState backCapState = DENIED_INVALID; + if (IsInBackgroudCaptureMap(sessionId, backCapState)) { + if (NEED_NOT_VERIFY_BACKGROUND_CAPTURE_LIST.count(backCapState)) { + AUDIO_INFO_LOG("Stream:%{public}u, Result:not need, Reason:%{public}d", sessionId, backCapState); + return true; + } + BackgroundCaptureState lastBackCapState = backCapState; + backCapState = VerifyBackgroundCapture(sessionId, config); + if (ALLOWED_BACKGROUND_CAPTURE_LIST.count(backCapState)) { + AUDIO_INFO_LOG("Stream:%{public}u, Result:allowed, Reason:%{public}d", sessionId, backCapState); + UpdateBackgroundCaptureMap(sessionId, backCapState); + return true; + } + if (ALLOWED_BACKGROUND_CAPTURE_LIST.count(lastBackCapState)) { + backCapState = UpdateVerifyBackgroundCapture(sessionId, config); + CHECK_AND_RETURN_RET_LOG(!ALLOWED_BACKGROUND_CAPTURE_LIST.count(backCapState), + true, "check alloewd"); + } + } else { + if (NeedVerifyBackgroundCapture(sessionId, config)) { + backCapState = VerifyBackgroundCapture(sessionId, config); + UpdateBackgroundCaptureMap(sessionId, backCapState); + CHECK_AND_RETURN_RET_LOG(!ALLOWED_BACKGROUND_CAPTURE_LIST.count(backCapState), + true, "check alloewd"); + } else { + UpdateBackgroundCaptureMap(sessionId, backCapState); + AUDIO_INFO_LOG("stream:%{public}u result:not need Reason:%{public}d", sessionId, backCapState); + return true; + } + } + AUDIO_ERR_LOG("check background capture denied! stream:%{public}u", sessionId); + return false; +} + +bool AudioService::IsInInterruptEventMap(const uint32_t sessionId, + InterruptEventInternal &interruptEvent) +{ + std::lock_guard lock(audioStreamInterruptEventMutex_); + auto iter = audioStreamInterruptEventMap_.find(sessionId); + CHECK_AND_RETURN_RET_LOG(iter != audioStreamInterruptEventMap_.end(), false, + "can not find sessionId:%{public}u", sessionId); + interruptEvent = iter->second; + AUDIO_INFO_LOG("sessionId:%{public}u, hintType:%{public}d", sessionId, interruptEvent.hintType); + return true; +} + +bool AudioService::UpdateInterruptEventMap(const uint32_t sessionId, + InterruptEventInternal interruptEvent) +{ + std::lock_guard lock(audioStreamInterruptEventMutex_); + auto iter = audioStreamInterruptEventMap_.find(sessionId); + if (iter == audioStreamInterruptEventMap_.end()) { + audioStreamInterruptEventMap_[sessionId] = interruptEvent; + AUDIO_INFO_LOG("Inserted sessionId:%{public}u, hintType:%{public}d", sessionId, interruptEvent.hintType); + } else if ((iter->second.hintType == INTERRUPT_HINT_PAUSE && interruptEvent.hintType == INTERRUPT_HINT_RESUME) || + (iter->second.hintType == INTERRUPT_HINT_RESUME && interruptEvent.hintType == INTERRUPT_HINT_PAUSE)) { + AUDIO_WARNING_LOG("Updated sessionId:%{public}u, interruptEvent:NONE " + "hintType:%{public}d", sessionId, interruptEvent.hintType); + interruptEvent.hintType = INTERRUPT_HINT_NONE; + iter->second = interruptEvent; + } else { + iter->second = interruptEvent; + AUDIO_INFO_LOG("Updated sessionId:%{public}u, hintType:%{public}d", sessionId, interruptEvent.hintType); + } + return true; +} + +bool AudioService::RemoveInterruptEventMap(const uint32_t sessionId) +{ + std::lock_guard lock(audioStreamInterruptEventMutex_); + auto iter = audioStreamInterruptEventMap_.find(sessionId); + if (iter == audioStreamInterruptEventMap_.end()) { + return false; + } + audioStreamInterruptEventMap_.erase(iter); + AUDIO_INFO_LOG("Removed sessionId:%{public}u", sessionId); + return true; +} + +bool AudioService::NeedRemoveInterruptEventAndBackCap(uint32_t sessionId) +{ + SwitchState switchState; + if (IsInSwitchStreamMap(sessionId, switchState)) { + if (switchState == SWITCH_STATE_WAITING) { + AUDIO_WARNING_LOG("SwitchStream should not reset"); + return false; + } + RemoveSwitchStreamMap(sessionId); + } + InterruptEventInternal interruptEvent; + BackgroundCaptureState backCapState = DENIED_INVALID; + if (IsInInterruptEventMap(sessionId, interruptEvent) && IsInBackgroudCaptureMap(sessionId, backCapState)) { + if (interruptEvent.hintType == INTERRUPT_HINT_PAUSE) { + AUDIO_WARNING_LOG ("Pause Intertrupt Event need not reset"); + RemoveInterruptEventMap(sessionId); + return false; + } + if (interruptEvent.hintType == INTERRUPT_HINT_NONE) { + AUDIO_WARNING_LOG("NONE Interrupt means Pause and Resume, need change to Resume "); + interruptEvent.hintType = INTERRUPT_HINT_RESUME; + UpdateInterruptEventMap(sessionId, interruptEvent); + return false; + } + } + return true; +} + +void AudioService::SendInterruptEventToAudioService(uint32_t sessionId, + InterruptEventInternal interruptEvent) +{ + interruptEvent.eventTimestamp = ClockTime::GetCurNano(); + AUDIO_INFO_LOG("Recive InterruptEvent:[%{public}d] from InterruptService", interruptEvent.hintType); + UpdateInterruptEventMap(sessionId, interruptEvent); +} + void AudioService::SaveRenderWhitelist(std::vector list) { std::lock_guard lock(renderWhitelistMutex_); diff --git a/services/audio_service/server/src/capturer_in_server.cpp b/services/audio_service/server/src/capturer_in_server.cpp index 79bc27a988d306292e34d6b40f0b649c39dae2cb..2ad6d9391da44b69ba73305eee7d891d6ddc499d 100644 --- a/services/audio_service/server/src/capturer_in_server.cpp +++ b/services/audio_service/server/src/capturer_in_server.cpp @@ -521,19 +521,22 @@ bool CapturerInServer::TurnOnMicIndicator(CapturerState capturerState) tokenId, capturerState, }; - if (!SwitchStreamUtil::IsSwitchStreamSwitching(info, SWITCH_STATE_STARTED)) { - CHECK_AND_RETURN_RET_LOG(CheckBGCapture(), false, "Verify failed"); + if (SwitchStreamUtil::IsSwitchStreamSwitching(info, SWITCH_STATE_STARTED)) { + AudioService::GetInstance()->UpdateBackgroundCaptureMap( + streamIndex_, ALLOWED_SWITCH_STREAM_START); + AudioService::GetInstance()->UpdateSwitchStreamMap(streamIndex_, SWITCH_STATE_STARTED); + } else { + CHECK_AND_RETURN_RET_LOG(AudioService::GetInstance()->IsAllowedUsingMicrophone( + streamIndex_, processConfig_), false, "Verify failed"); } SwitchStreamUtil::UpdateSwitchStreamRecord(info, SWITCH_STATE_STARTED); if (isMicIndicatorOn_) { - AUDIO_WARNING_LOG("MicIndicator of stream:%{public}d is already on." - "No need to call NotifyPrivacyStart!", streamIndex_); + AUDIO_WARNING_LOG("MicIndicator of stream:%{public}d is already on", streamIndex_); } else { CHECK_AND_RETURN_RET_LOG(PermissionUtil::NotifyPrivacyStart(tokenId, streamIndex_), false, "NotifyPrivacyStart failed!"); - AUDIO_INFO_LOG("Turn on micIndicator of stream:%{public}d from off " - "after NotifyPrivacyStart success!", streamIndex_); + AUDIO_INFO_LOG("Turn on micIndicator of stream:%{public}d", streamIndex_); isMicIndicatorOn_ = true; } return true; @@ -552,6 +555,11 @@ bool CapturerInServer::TurnOffMicIndicator(CapturerState capturerState) }; SwitchStreamUtil::UpdateSwitchStreamRecord(info, SWITCH_STATE_FINISHED); + if (AudioService::GetInstance()->NeedRemoveInterruptEventAndBackCap(streamIndex_)) { + AudioService::GetInstance()->RemoveBackgroundCaptureMap(streamIndex_); + AudioService::GetInstance()->RemoveInterruptEventMap(streamIndex_); + } + if (isMicIndicatorOn_) { PermissionUtil::NotifyPrivacyStop(tokenId, streamIndex_); AUDIO_INFO_LOG("Turn off micIndicator of stream:%{public}d from on after NotifyPrivacyStop!", streamIndex_); @@ -904,10 +912,9 @@ RestoreStatus CapturerInServer::RestoreSession(RestoreInfo restoreInfo) HandleStreamStatusToCapturerState(status_) }; AUDIO_INFO_LOG("Insert fast record stream:%{public}u uid:%{public}d tokenId:%{public}u " - "into switchStreamRecord because restoreStatus:NEED_RESTORE", - streamIndex_, info.callerUid, info.appTokenId); + "restoreStatus:NEED_RESTORE", streamIndex_, info.callerUid, info.appTokenId); + AudioService::GetInstance()->UpdateSwitchStreamMap(streamIndex_, SWITCH_STATE_WAITING); SwitchStreamUtil::UpdateSwitchStreamRecord(info, SWITCH_STATE_WAITING); - audioServerBuffer_->SetRestoreInfo(restoreInfo); } return restoreStatus;