Loading services/core/java/com/android/server/audio/AudioService.java +41 −12 Original line number Diff line number Diff line Loading @@ -185,6 +185,9 @@ public class AudioService extends IAudioService.Stub private static final String TAG = "AS.AudioService"; private final AudioSystemAdapter mAudioSystem; private final SystemServerAdapter mSystemServer; /** Debug audio mode */ protected static final boolean DEBUG_MODE = false; Loading Loading @@ -649,10 +652,19 @@ public class AudioService extends IAudioService.Stub /** @hide */ public AudioService(Context context) { this(context, AudioSystemAdapter.getDefaultAdapter(), SystemServerAdapter.getDefaultAdapter(context)); } public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer) { mContext = context; mContentResolver = context.getContentResolver(); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); mAudioSystem = audioSystem; mSystemServer = systemServer; mPlatformType = AudioSystem.getPlatformType(context); mIsSingleVolume = AudioSystem.isSingleVolume(context); Loading Loading @@ -842,11 +854,13 @@ public class AudioService extends IAudioService.Stub context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null); if (mSystemServer.isPrivileged()) { LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal()); mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener); mRecordMonitor.initMonitor(); } final float[] preScale = new float[3]; preScale[0] = mContext.getResources().getFraction( Loading Loading @@ -935,7 +949,7 @@ public class AudioService extends IAudioService.Stub onIndicateSystemReady(); mMicMuteFromSystemCached = AudioSystem.isMicrophoneMuted(); mMicMuteFromSystemCached = mAudioSystem.isMicrophoneMuted(); setMicMuteFromSwitchInput(); } Loading Loading @@ -1636,12 +1650,15 @@ public class AudioService extends IAudioService.Stub } if (currentImeUid != mCurrentImeUid || forceUpdate) { AudioSystem.setCurrentImeUid(currentImeUid); mAudioSystem.setCurrentImeUid(currentImeUid); mCurrentImeUid = currentImeUid; } } private void readPersistedSettings() { if (!mSystemServer.isPrivileged()) { return; } final ContentResolver cr = mContentResolver; int ringerModeFromSettings = Loading Loading @@ -1712,6 +1729,9 @@ public class AudioService extends IAudioService.Stub } private void readUserRestrictions() { if (!mSystemServer.isPrivileged()) { return; } final int currentUser = getCurrentUserId(); // Check the current user restriction. Loading Loading @@ -2782,6 +2802,9 @@ public class AudioService extends IAudioService.Stub } private void sendBroadcastToAll(Intent intent) { if (!mSystemServer.isPrivileged()) { return; } intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); final long ident = Binder.clearCallingIdentity(); Loading Loading @@ -3174,12 +3197,12 @@ public class AudioService extends IAudioService.Stub } // only mute for the current user if (getCurrentUserId() == userId || userId == android.os.Process.SYSTEM_UID) { final boolean currentMute = AudioSystem.isMicrophoneMuted(); final boolean currentMute = mAudioSystem.isMicrophoneMuted(); final long identity = Binder.clearCallingIdentity(); final int ret = AudioSystem.muteMicrophone(muted); final int ret = mAudioSystem.muteMicrophone(muted); // update cache with the real state independently from what was set mMicMuteFromSystemCached = AudioSystem.isMicrophoneMuted(); mMicMuteFromSystemCached = mAudioSystem.isMicrophoneMuted(); if (ret != AudioSystem.AUDIO_STATUS_OK) { Log.e(TAG, "Error changing mic mute state to " + muted + " current:" + mMicMuteFromSystemCached); Loading Loading @@ -4518,6 +4541,9 @@ public class AudioService extends IAudioService.Stub } private void broadcastRingerMode(String action, int ringerMode) { if (!mSystemServer.isPrivileged()) { return; } // Send sticky broadcast Intent broadcast = new Intent(action); broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode); Loading @@ -4527,6 +4553,9 @@ public class AudioService extends IAudioService.Stub } private void broadcastVibrateSetting(int vibrateType) { if (!mSystemServer.isPrivileged()) { return; } // Send broadcast if (mActivityManagerInternal.isSystemReady()) { Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); Loading Loading @@ -5258,6 +5287,9 @@ public class AudioService extends IAudioService.Stub } public int observeDevicesForStream_syncVSS(boolean checkOthers) { if (!mSystemServer.isPrivileged()) { return AudioSystem.DEVICE_NONE; } final int devices = AudioSystem.getDevicesForStream(mStreamType); if (devices == mObservedDevices) { return devices; Loading Loading @@ -5998,10 +6030,7 @@ public class AudioService extends IAudioService.Stub break; case MSG_BROADCAST_MICROPHONE_MUTE: mContext.sendBroadcastAsUser( new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED) .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL); mSystemServer.sendMicrophoneMuteChangedIntent(); break; } } Loading services/core/java/com/android/server/audio/AudioSystemAdapter.java +65 −4 Original line number Diff line number Diff line Loading @@ -40,10 +40,11 @@ public class AudioSystemAdapter { /** * Create an adapter for AudioSystem that always succeeds, and does nothing. * @return a no-op AudioSystem adapter * Overridden methods can be configured * @return a no-op AudioSystem adapter with configurable adapter */ static final @NonNull AudioSystemAdapter getAlwaysOkAdapter() { return new AudioSystemOkAdapter(); static final @NonNull AudioSystemAdapter getConfigurableAdapter() { return new AudioSystemConfigurableAdapter(); } /** Loading Loading @@ -113,10 +114,51 @@ public class AudioSystemAdapter { return AudioSystem.setParameters(keyValuePairs); } /** * Same as {@link AudioSystem#isMicrophoneMuted()}} * Checks whether the microphone mute is on or off. * @return true if microphone is muted, false if it's not */ public boolean isMicrophoneMuted() { return AudioSystem.isMicrophoneMuted(); } /** * Same as {@link AudioSystem#muteMicrophone(boolean)} * Sets the microphone mute on or off. * * @param on set <var>true</var> to mute the microphone; * <var>false</var> to turn mute off * @return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR */ public int muteMicrophone(boolean on) { return AudioSystem.muteMicrophone(on); } /** * Same as {@link AudioSystem#setCurrentImeUid(int)} * Communicate UID of current InputMethodService to audio policy service. */ public int setCurrentImeUid(int uid) { return AudioSystem.setCurrentImeUid(uid); } //-------------------------------------------------------------------- protected static class AudioSystemOkAdapter extends AudioSystemAdapter { protected static class AudioSystemConfigurableAdapter extends AudioSystemAdapter { private static final String TAG = "ASA"; private boolean mIsMicMuted = false; private boolean mMuteMicrophoneFails = false; public void configureIsMicrophoneMuted(boolean muted) { mIsMicMuted = muted; } public void configureMuteMicrophoneToFail(boolean fail) { mMuteMicrophoneFails = fail; } //----------------------------------------------------------------- // Overrides of AudioSystemAdapter @Override public int setDeviceConnectionState(int device, int state, String deviceAddress, String deviceName, int codecFormat) { Loading Loading @@ -152,5 +194,24 @@ public class AudioSystemAdapter { public int setParameters(String keyValuePairs) { return AudioSystem.AUDIO_STATUS_OK; } @Override public boolean isMicrophoneMuted() { return mIsMicMuted; } @Override public int muteMicrophone(boolean on) { if (mMuteMicrophoneFails) { return AudioSystem.AUDIO_STATUS_ERROR; } mIsMicMuted = on; return AudioSystem.AUDIO_STATUS_OK; } @Override public int setCurrentImeUid(int uid) { return AudioSystem.AUDIO_STATUS_OK; } } } services/core/java/com/android/server/audio/SystemServerAdapter.java 0 → 100644 +90 −0 Original line number Diff line number Diff line /* * Copyright 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. */ package com.android.server.audio; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.os.UserHandle; /** * Provides an adapter to access functionality reserved to components running in system_server * Functionality such as sending privileged broadcasts is to be accessed through the default * adapter, whereas tests can inject a no-op adapter. */ public class SystemServerAdapter { protected final Context mContext; private SystemServerAdapter(@Nullable Context context) { mContext = context; } /** * Create a wrapper around privileged functionality. * @return the adapter */ static final @NonNull SystemServerAdapter getDefaultAdapter(Context context) { return new SystemServerAdapter(context); } /** * Create an adapter that does nothing. * Use for running non-privileged tests, such as unit tests * @return a no-op adapter */ static final @NonNull SystemServerAdapter getNoOpAdapter() { return new NoOpSystemServerAdapter(); } /** * @return true if this is supposed to be run in system_server, false otherwise (e.g. for a * unit test) */ public boolean isPrivileged() { return true; } /** * Broadcast ACTION_MICROPHONE_MUTE_CHANGED */ public void sendMicrophoneMuteChangedIntent() { mContext.sendBroadcastAsUser( new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED) .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL); } //-------------------------------------------------------------------- protected static class NoOpSystemServerAdapter extends SystemServerAdapter { NoOpSystemServerAdapter() { super(null); } @Override public boolean isPrivileged() { return false; } @Override public void sendMicrophoneMuteChangedIntent() { // no-op } } } services/tests/servicestests/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ <uses-permission android:name="android.permission.DUMP"/> <uses-permission android:name="android.permission.READ_DREAM_STATE"/> <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <!-- Uses API introduced in O (26) --> <uses-sdk android:minSdkVersion="1" Loading services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -66,7 +66,7 @@ public class AudioDeviceBrokerTest { mContext = InstrumentationRegistry.getTargetContext(); mMockAudioService = mock(AudioService.class); mSpyAudioSystem = spy(AudioSystemAdapter.getAlwaysOkAdapter()); mSpyAudioSystem = spy(AudioSystemAdapter.getConfigurableAdapter()); mSpyDevInventory = spy(new AudioDeviceInventory(mSpyAudioSystem)); mAudioDeviceBroker = new AudioDeviceBroker(mContext, mMockAudioService, mSpyDevInventory); mSpyDevInventory.setDeviceBroker(mAudioDeviceBroker); Loading Loading
services/core/java/com/android/server/audio/AudioService.java +41 −12 Original line number Diff line number Diff line Loading @@ -185,6 +185,9 @@ public class AudioService extends IAudioService.Stub private static final String TAG = "AS.AudioService"; private final AudioSystemAdapter mAudioSystem; private final SystemServerAdapter mSystemServer; /** Debug audio mode */ protected static final boolean DEBUG_MODE = false; Loading Loading @@ -649,10 +652,19 @@ public class AudioService extends IAudioService.Stub /** @hide */ public AudioService(Context context) { this(context, AudioSystemAdapter.getDefaultAdapter(), SystemServerAdapter.getDefaultAdapter(context)); } public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer) { mContext = context; mContentResolver = context.getContentResolver(); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); mAudioSystem = audioSystem; mSystemServer = systemServer; mPlatformType = AudioSystem.getPlatformType(context); mIsSingleVolume = AudioSystem.isSingleVolume(context); Loading Loading @@ -842,11 +854,13 @@ public class AudioService extends IAudioService.Stub context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null); if (mSystemServer.isPrivileged()) { LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal()); mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener); mRecordMonitor.initMonitor(); } final float[] preScale = new float[3]; preScale[0] = mContext.getResources().getFraction( Loading Loading @@ -935,7 +949,7 @@ public class AudioService extends IAudioService.Stub onIndicateSystemReady(); mMicMuteFromSystemCached = AudioSystem.isMicrophoneMuted(); mMicMuteFromSystemCached = mAudioSystem.isMicrophoneMuted(); setMicMuteFromSwitchInput(); } Loading Loading @@ -1636,12 +1650,15 @@ public class AudioService extends IAudioService.Stub } if (currentImeUid != mCurrentImeUid || forceUpdate) { AudioSystem.setCurrentImeUid(currentImeUid); mAudioSystem.setCurrentImeUid(currentImeUid); mCurrentImeUid = currentImeUid; } } private void readPersistedSettings() { if (!mSystemServer.isPrivileged()) { return; } final ContentResolver cr = mContentResolver; int ringerModeFromSettings = Loading Loading @@ -1712,6 +1729,9 @@ public class AudioService extends IAudioService.Stub } private void readUserRestrictions() { if (!mSystemServer.isPrivileged()) { return; } final int currentUser = getCurrentUserId(); // Check the current user restriction. Loading Loading @@ -2782,6 +2802,9 @@ public class AudioService extends IAudioService.Stub } private void sendBroadcastToAll(Intent intent) { if (!mSystemServer.isPrivileged()) { return; } intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); final long ident = Binder.clearCallingIdentity(); Loading Loading @@ -3174,12 +3197,12 @@ public class AudioService extends IAudioService.Stub } // only mute for the current user if (getCurrentUserId() == userId || userId == android.os.Process.SYSTEM_UID) { final boolean currentMute = AudioSystem.isMicrophoneMuted(); final boolean currentMute = mAudioSystem.isMicrophoneMuted(); final long identity = Binder.clearCallingIdentity(); final int ret = AudioSystem.muteMicrophone(muted); final int ret = mAudioSystem.muteMicrophone(muted); // update cache with the real state independently from what was set mMicMuteFromSystemCached = AudioSystem.isMicrophoneMuted(); mMicMuteFromSystemCached = mAudioSystem.isMicrophoneMuted(); if (ret != AudioSystem.AUDIO_STATUS_OK) { Log.e(TAG, "Error changing mic mute state to " + muted + " current:" + mMicMuteFromSystemCached); Loading Loading @@ -4518,6 +4541,9 @@ public class AudioService extends IAudioService.Stub } private void broadcastRingerMode(String action, int ringerMode) { if (!mSystemServer.isPrivileged()) { return; } // Send sticky broadcast Intent broadcast = new Intent(action); broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode); Loading @@ -4527,6 +4553,9 @@ public class AudioService extends IAudioService.Stub } private void broadcastVibrateSetting(int vibrateType) { if (!mSystemServer.isPrivileged()) { return; } // Send broadcast if (mActivityManagerInternal.isSystemReady()) { Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); Loading Loading @@ -5258,6 +5287,9 @@ public class AudioService extends IAudioService.Stub } public int observeDevicesForStream_syncVSS(boolean checkOthers) { if (!mSystemServer.isPrivileged()) { return AudioSystem.DEVICE_NONE; } final int devices = AudioSystem.getDevicesForStream(mStreamType); if (devices == mObservedDevices) { return devices; Loading Loading @@ -5998,10 +6030,7 @@ public class AudioService extends IAudioService.Stub break; case MSG_BROADCAST_MICROPHONE_MUTE: mContext.sendBroadcastAsUser( new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED) .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL); mSystemServer.sendMicrophoneMuteChangedIntent(); break; } } Loading
services/core/java/com/android/server/audio/AudioSystemAdapter.java +65 −4 Original line number Diff line number Diff line Loading @@ -40,10 +40,11 @@ public class AudioSystemAdapter { /** * Create an adapter for AudioSystem that always succeeds, and does nothing. * @return a no-op AudioSystem adapter * Overridden methods can be configured * @return a no-op AudioSystem adapter with configurable adapter */ static final @NonNull AudioSystemAdapter getAlwaysOkAdapter() { return new AudioSystemOkAdapter(); static final @NonNull AudioSystemAdapter getConfigurableAdapter() { return new AudioSystemConfigurableAdapter(); } /** Loading Loading @@ -113,10 +114,51 @@ public class AudioSystemAdapter { return AudioSystem.setParameters(keyValuePairs); } /** * Same as {@link AudioSystem#isMicrophoneMuted()}} * Checks whether the microphone mute is on or off. * @return true if microphone is muted, false if it's not */ public boolean isMicrophoneMuted() { return AudioSystem.isMicrophoneMuted(); } /** * Same as {@link AudioSystem#muteMicrophone(boolean)} * Sets the microphone mute on or off. * * @param on set <var>true</var> to mute the microphone; * <var>false</var> to turn mute off * @return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR */ public int muteMicrophone(boolean on) { return AudioSystem.muteMicrophone(on); } /** * Same as {@link AudioSystem#setCurrentImeUid(int)} * Communicate UID of current InputMethodService to audio policy service. */ public int setCurrentImeUid(int uid) { return AudioSystem.setCurrentImeUid(uid); } //-------------------------------------------------------------------- protected static class AudioSystemOkAdapter extends AudioSystemAdapter { protected static class AudioSystemConfigurableAdapter extends AudioSystemAdapter { private static final String TAG = "ASA"; private boolean mIsMicMuted = false; private boolean mMuteMicrophoneFails = false; public void configureIsMicrophoneMuted(boolean muted) { mIsMicMuted = muted; } public void configureMuteMicrophoneToFail(boolean fail) { mMuteMicrophoneFails = fail; } //----------------------------------------------------------------- // Overrides of AudioSystemAdapter @Override public int setDeviceConnectionState(int device, int state, String deviceAddress, String deviceName, int codecFormat) { Loading Loading @@ -152,5 +194,24 @@ public class AudioSystemAdapter { public int setParameters(String keyValuePairs) { return AudioSystem.AUDIO_STATUS_OK; } @Override public boolean isMicrophoneMuted() { return mIsMicMuted; } @Override public int muteMicrophone(boolean on) { if (mMuteMicrophoneFails) { return AudioSystem.AUDIO_STATUS_ERROR; } mIsMicMuted = on; return AudioSystem.AUDIO_STATUS_OK; } @Override public int setCurrentImeUid(int uid) { return AudioSystem.AUDIO_STATUS_OK; } } }
services/core/java/com/android/server/audio/SystemServerAdapter.java 0 → 100644 +90 −0 Original line number Diff line number Diff line /* * Copyright 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. */ package com.android.server.audio; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.os.UserHandle; /** * Provides an adapter to access functionality reserved to components running in system_server * Functionality such as sending privileged broadcasts is to be accessed through the default * adapter, whereas tests can inject a no-op adapter. */ public class SystemServerAdapter { protected final Context mContext; private SystemServerAdapter(@Nullable Context context) { mContext = context; } /** * Create a wrapper around privileged functionality. * @return the adapter */ static final @NonNull SystemServerAdapter getDefaultAdapter(Context context) { return new SystemServerAdapter(context); } /** * Create an adapter that does nothing. * Use for running non-privileged tests, such as unit tests * @return a no-op adapter */ static final @NonNull SystemServerAdapter getNoOpAdapter() { return new NoOpSystemServerAdapter(); } /** * @return true if this is supposed to be run in system_server, false otherwise (e.g. for a * unit test) */ public boolean isPrivileged() { return true; } /** * Broadcast ACTION_MICROPHONE_MUTE_CHANGED */ public void sendMicrophoneMuteChangedIntent() { mContext.sendBroadcastAsUser( new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED) .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL); } //-------------------------------------------------------------------- protected static class NoOpSystemServerAdapter extends SystemServerAdapter { NoOpSystemServerAdapter() { super(null); } @Override public boolean isPrivileged() { return false; } @Override public void sendMicrophoneMuteChangedIntent() { // no-op } } }
services/tests/servicestests/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ <uses-permission android:name="android.permission.DUMP"/> <uses-permission android:name="android.permission.READ_DREAM_STATE"/> <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <!-- Uses API introduced in O (26) --> <uses-sdk android:minSdkVersion="1" Loading
services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -66,7 +66,7 @@ public class AudioDeviceBrokerTest { mContext = InstrumentationRegistry.getTargetContext(); mMockAudioService = mock(AudioService.class); mSpyAudioSystem = spy(AudioSystemAdapter.getAlwaysOkAdapter()); mSpyAudioSystem = spy(AudioSystemAdapter.getConfigurableAdapter()); mSpyDevInventory = spy(new AudioDeviceInventory(mSpyAudioSystem)); mAudioDeviceBroker = new AudioDeviceBroker(mContext, mMockAudioService, mSpyDevInventory); mSpyDevInventory.setDeviceBroker(mAudioDeviceBroker); Loading