安卓14[AudioService]安全音量设置逻辑
1./frameworks/base/services/core/java/com/android/server/audio/AudioService.java
public static final class Lifecycle extends SystemService { private AudioService mService; public Lifecycle(Context context) { super(context); mService = new AudioService(context, AudioSystemAdapter.getDefaultAdapter(), SystemServerAdapter.getDefaultAdapter(context), SettingsAdapter.getDefaultAdapter(), new DefaultAudioPolicyFacade(), null); } @Override public void onStart() { publishBinderService(Context.AUDIO_SERVICE, mService); } @Override public void onBootPhase(int phase) { //Activity Manager 已经完成初始化,开始启动服务 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { mService.systemReady(); } } } public void systemReady() { sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE, 0, 0, null, 0); if (false) { // This is turned off for now, because it is racy and thus causes apps to break. // Currently banning a uid means that if an app tries to start playing an audio // stream, that will be preventing, and unbanning it will not allow that stream // to resume. However these changes in uid state are racy with what the app is doing, // so that after taking a process out of the cached state we can't guarantee that // we will unban the uid before the app actually tries to start playing audio. // (To do that, the activity manager would need to wait until it knows for sure // that the ban has been removed, before telling the app to do whatever it is // supposed to do that caused it to go out of the cached state.) try { ActivityManager.getService().registerUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_CACHED | ActivityManager.UID_OBSERVER_GONE, ActivityManager.PROCESS_STATE_UNKNOWN, null); } catch (RemoteException e) { // ignored; both services live in system_server } } } case MSG_SYSTEM_READY: onSystemReady(); break; public void onSystemReady() { mSystemReady = true; scheduleLoadSoundEffects(); mDeviceBroker.onSystemReady(); if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) { synchronized (mHdmiClientLock) { mHdmiManager = mContext.getSystemService(HdmiControlManager.class); if (mHdmiManager != null) { mHdmiManager.addHdmiControlStatusChangeListener( mHdmiControlStatusChangeListenerCallback); mHdmiManager.addHdmiCecVolumeControlFeatureListener(mContext.getMainExecutor(), mMyHdmiCecVolumeControlFeatureListener); } mHdmiTvClient = mHdmiManager.getTvClient(); if (mHdmiTvClient != null) { mFixedVolumeDevices.removeAll( AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET); } mHdmiPlaybackClient = mHdmiManager.getPlaybackClient(); mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient(); } } if (mSupportsMicPrivacyToggle) { mSensorPrivacyManagerInternal.addSensorPrivacyListenerForAllUsers( SensorPrivacyManager.Sensors.MICROPHONE, (userId, enabled) -> { if (userId == getCurrentUserId()) { mMicMuteFromPrivacyToggle = enabled; setMicrophoneMuteNoCallerCheck(getCurrentUserId()); } }); } mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); //定义了一个名为 SoundDoseHelper 的类,用于安全管理媒体音量,这里是去进行配置 mSoundDoseHelper.configureSafeMedia(/*forced=*/true, TAG); initA11yMonitoring(); mRoleObserver = new RoleObserver(); mRoleObserver.register(); onIndicateSystemReady(); mMicMuteFromSystemCached = mAudioSystem.isMicrophoneMuted(); setMicMuteFromSwitchInput(); initMinStreamVolumeWithoutModifyAudioSettings(); updateVibratorInfos(); synchronized (mSupportedSystemUsagesLock) { AudioSystem.setSupportedSystemUsages(mSupportedSystemUsages); } } /*package*/ void configureSafeMedia(boolean forced, String caller) { int msg = forced ? MSG_CONFIGURE_SAFE_MEDIA_FORCED : MSG_CONFIGURE_SAFE_MEDIA; mAudioHandler.removeMessages(msg); long time = 0; if (forced) { time = (SystemClock.uptimeMillis() + (SystemProperties.getBoolean( "audio.safemedia.bypass", false) ? 0 : SAFE_VOLUME_CONFIGURE_TIMEOUT_MS)); } mAudioHandler.sendMessageAtTime( mAudioHandler.obtainMessage(msg, /*arg1=*/0, /*arg2=*/0, caller), time); } case MSG_CONFIGURE_SAFE_MEDIA_FORCED: case MSG_CONFIGURE_SAFE_MEDIA: onConfigureSafeMedia((msg.what == MSG_CONFIGURE_SAFE_MEDIA_FORCED), (String) msg.obj); break; //配置安全媒体音量索引和安全音量功能 private void onConfigureSafeMedia(boolean force, String caller) { updateCsdEnabled(caller); synchronized (mSafeMediaVolumeStateLock) { int mcc = mContext.getResources().getConfiguration().mcc; if ((mMcc != mcc) || ((mMcc == 0) && force)) { mSafeMediaVolumeIndex = mContext.getResources().getInteger( com.android.internal.R.integer.config_safe_media_volume_index) * 10; initSafeMediaVolumeIndex(); updateSafeMediaVolume_l(caller); mMcc = mcc; } } } //最重要的地方,决定是否设置安全音量功能
private void updateSafeMediaVolume_l(String caller) { boolean safeMediaVolumeEnabled = SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_FORCE, false) || (mContext.getResources().getBoolean( com.android.internal.R.bool.config_safe_media_volume_enabled) && !mEnableCsd.get()); boolean safeMediaVolumeBypass = SystemProperties.getBoolean(SYSTEM_PROPERTY_SAFEMEDIA_BYPASS, false); // The persisted state is either "disabled" or "active": this is the state applied // next time we boot and cannot be "inactive" int persistedState; if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) { //安全音量功能状态为启动 persistedState = SAFE_MEDIA_VOLUME_ACTIVE; // The state can already be "inactive" here if the user has forced it before // the 30 seconds timeout for forced configuration. In this case we don't reset // it to "active". if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) { if (mMusicActiveMs == 0) { mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE; enforceSafeMediaVolume(caller); } else { // We have existing playback time recorded, already confirmed. mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE; mLastMusicActiveTimeMs = 0; } } } else { //安全音量功能状态为关闭 persistedState = SAFE_MEDIA_VOLUME_DISABLED; mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED; } mAudioHandler.sendMessageAtTime( mAudioHandler.obtainMessage(MSG_PERSIST_SAFE_VOLUME_STATE, persistedState, /*arg2=*/0, /*obj=*/null), /*delay=*/0); } 关闭安全音量弹窗,将true改为false
/frameworks/base/core/res/res/values/config.xml
<!-- Whether safe headphone volume is enabled or not (country specific). --> <bool name="config_safe_media_volume_enabled">true</bool>