Android 10 音频焦点申请框架层调用流程详解
// 说明:
Android 10及以上的版本才有packages/services/Car/service/src/com/android/car/audio/CarAudioFocus.java
一、整体调用流程图
应用调用 requestAudioFocus
AudioManager.requestAudioFocus
AudioManager.requestAudioFocus 重载
IAudioService.requestAudioFocus
Binder IPC 到 AudioService
AudioService.requestAudioFocus
MediaFocusControl.requestAudioFocus
二、详细代码调用流程
2.1 应用层入口
java
// 应用代码
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
AudioAttributes attributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.build();
AudioFocusRequest request = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setAudioAttributes(attributes)
.setOnAudioFocusChangeListener(listener)
.build();
// 关键调用入口
int result = audioManager.requestAudioFocus(request);
2.2 AudioManager.java
java
// 路径: frameworks/base/media/java/android/media/AudioManager.java
public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
if (afr == null) {
throw new NullPointerException("Illegal null AudioFocusRequest");
}
// this can only be checked now, not during the creation of the AudioFocusRequest instance
if (afr.locksFocus() && ap == null) {
throw new IllegalArgumentException(
"Illegal null audio policy when locking audio focus");
}
registerAudioFocusRequest(afr);
final IAudioService service = getService();
final int status;
int sdk;
try {
sdk = getContext().getApplicationInfo().targetSdkVersion;
} catch (NullPointerException e) {
// some tests don't have a Context
sdk = Build.VERSION.SDK_INT;
}
final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
final BlockingFocusResultReceiver focusReceiver;
synchronized (mFocusRequestsLock) {
try {
// TODO status contains result and generation counter for ext policy
status = service.requestAudioFocus(afr.getAudioAttributes(),
afr.getFocusGain(), mICallBack,
mAudioFocusDispatcher,
clientId,
getContext().getOpPackageName() /* package name */, afr.getFlags(),
ap != null ? ap.cb() : null,
sdk);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
// default path with no external focus policy
return status;
}
if (mFocusRequestsAwaitingResult == null) {
mFocusRequestsAwaitingResult =
new HashMap<String, BlockingFocusResultReceiver>(1);
}
focusReceiver = new BlockingFocusResultReceiver(clientId);
mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
}
focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
if (DEBUG && !focusReceiver.receivedResult()) {
Log.e(TAG, "requestAudio response from ext policy timed out, denying request");
}
synchronized (mFocusRequestsLock) {
mFocusRequestsAwaitingResult.remove(clientId);
}
return focusReceiver.requestResult();
}
2.3 IAudioService.aidl 接口定义
java
// 路径: frameworks/base/media/java/android/media/IAudioService.aidl
interface IAudioService {
int requestAudioFocus(in AudioAttributes aa, int durationHint,
IAudioFocusDispatcher fd, String clientId,
IBinder cb, String callingPackageName,
int flags, IAudioPolicyCallback pcb);
}
2.4 AudioService.java
java
// 路径: frameworks/base/services/core/java/com/android/server/audio/AudioService.java
public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
IAudioPolicyCallback pcb, int sdk) {
// permission checks
if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE)) {
Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
} else {
// only a registered audio policy can be used to lock focus
synchronized (mAudioPolicies) {
if (!mAudioPolicies.containsKey(pcb.asBinder())) {
Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
}
}
}
if (callingPackageName == null || clientId == null || aa == null) {
Log.e(TAG, "Invalid null parameter to request audio focus");
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
clientId, callingPackageName, flags, sdk,
forceFocusDuckingForAccessibility(aa, durationHint, Binder.getCallingUid()));
}
2.5 MediaFocusControl.java 焦点控制核心
java
// 路径: frameworks/base/services/core/java/com/android/server/audio/MediaFocusControl.java
protected int requestAudioFocus(@NonNull AudioAttributes aa, int focusChangeHint, IBinder cb,
IAudioFocusDispatcher fd, @NonNull String clientId, @NonNull String callingPackageName,
String attributionTag, int flags, int sdk, boolean forceDuck, int testUid) {
// external focus policy?
if (mFocusPolicy != null) {
if (notifyExtFocusPolicyFocusRequest_syncAf(afiForExtPolicy, fd, cb)) {
// stop handling focus request here as it is handled by external audio
// focus policy (return code will be handled in AudioManager)
return AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY;
} else {
// an error occured, client already dead, bail early
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
}
}
boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi,
IAudioFocusDispatcher fd, @NonNull IBinder cb) {
if (DEBUG) {
Log.v(TAG, "notifyExtFocusPolicyFocusRequest client="+afi.getClientId()
+ " dispatcher=" + fd);
}
try {
//oneway
mFocusPolicy.notifyAudioFocusRequest(afi, AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
return true;
} catch (RemoteException e) {
Log.e(TAG, "Can't call notifyAudioFocusRequest() on IAudioPolicyCallback "
+ mFocusPolicy.asBinder(), e);
}
return false;
}
2.6 AudioPolicy.java
java
// 路径: frameworks/base/media/java/android/media/audiopolicy/AudioPolicy.java
private final IAudioPolicyCallback mPolicyCb = new IAudioPolicyCallback.Stub() {
public void notifyAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
sendMsg(MSG_FOCUS_REQUEST, afi, requestResult);
if (DEBUG) {
Log.v(TAG, "notifyAudioFocusRequest: pack=" + afi.getPackageName() + " client="
+ afi.getClientId() + " gen=" + afi.getGen());
}
}
};
private class EventHandler extends Handler {
public EventHandler(AudioPolicy ap, Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_FOCUS_REQUEST:
if (mFocusListener != null) {
mFocusListener.onAudioFocusRequest((AudioFocusInfo) msg.obj, msg.arg1);
} else { // should never be null, but don't crash
Log.e(TAG, "Invalid null focus listener for focus request event");
}
break;
default:
Log.e(TAG, "Unknown event " + msg.what);
}
}
}
2.7 CarZonesAudioFocus.java
java
// 路径: packages/services/Car/service/src/com/android/car/audio/CarZonesAudioFocus.java
public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
CarAudioFocus focus = getFocusForAudioFocusInfo(afi);
focus.onAudioFocusRequest(afi, requestResult);
}
2.8 CarAudioFocus.java
java
// 路径: packages/services/Car/service/src/com/android/car/audio/CarAudioFocus.java
public synchronized void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
Log.i(TAG, "onAudioFocusRequest " + afi.getClientId());
int response = evaluateFocusRequest(afi);
// Post our reply for delivery to the original focus requester
mAudioManager.setFocusRequestResult(afi, response, mAudioPolicy);
}
2.9 AudioManager.java
java
// 路径: frameworks/base/media/java/android/media/AudioManager.java
public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
@FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
if (afi == null) {
throw new IllegalArgumentException("Illegal null AudioFocusInfo");
}
if (ap == null) {
throw new IllegalArgumentException("Illegal null AudioPolicy");
}
final IAudioService service = getService();
try {
service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
3.1 IAudioService.aidl
java
// 路径: frameworks/base/media/java/android/media/IAudioService.aidl
oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
in IAudioPolicyCallback pcb);
3.2 AudioService.java
java
// 路径: frameworks/base/services/core/java/com/android/server/audio/AudioService.java
public void setFocusRequestResultFromExtPolicy(AudioFocusInfo afi, int requestResult,
IAudioPolicyCallback pcb) {
if (afi == null) {
throw new IllegalArgumentException("Illegal null AudioFocusInfo");
}
if (pcb == null) {
throw new IllegalArgumentException("Illegal null AudioPolicy callback");
}
synchronized (mAudioPolicies) {
if (!mAudioPolicies.containsKey(pcb.asBinder())) {
throw new IllegalStateException("Unregistered AudioPolicy for external focus");
}
mMediaFocusControl.setFocusRequestResultFromExtPolicy(afi, requestResult);
}
}
3.3 MediaFocusControl.java
java
// 路径: frameworks/base/services/core/java/com/android/server/audio/MediaFocusControl.java
void setFocusRequestResultFromExtPolicy(AudioFocusInfo afi, int requestResult) {
synchronized (mExtFocusChangeLock) {
if (afi.getGen() > mExtFocusChangeCounter) {
return;
}
}
final FocusRequester fr;
if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
fr = mFocusOwnersForFocusPolicy.remove(afi.getClientId());
} else {
fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
}
if (fr != null) {
fr.dispatchFocusResultFromExtPolicy(requestResult);
}
}
3.4 FocusRequester.java
java
// 路径: frameworks/base/services/core/java/com/android/server/audio/FocusRequester.java
void dispatchFocusResultFromExtPolicy(int requestResult) {
final IAudioFocusDispatcher fd = mFocusDispatcher;
if (fd == null) {
if (MediaFocusControl.DEBUG) {
Log.e(TAG, "dispatchFocusResultFromExtPolicy: no focus dispatcher");
}
return;
}
if (DEBUG) {
Log.v(TAG, "dispatching result" + requestResult + " to " + mClientId);
}
try {
fd.dispatchFocusResultFromExtPolicy(requestResult, mClientId);
} catch (android.os.RemoteException e) {
Log.e(TAG, "dispatchFocusResultFromExtPolicy: error talking to focus listener"
+ mClientId, e);
}
}
3.5 AudioManager.java
java
// 路径: frameworks/base/media/java/android/media/AudioManager.java
private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
@Override
public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
synchronized (mFocusRequestsLock) {
// TODO use generation counter as the key instead
final BlockingFocusResultReceiver focusReceiver =
mFocusRequestsAwaitingResult.remove(clientId);
if (focusReceiver != null) {
focusReceiver.notifyResult(requestResult);
} else {
Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
}
}
}
};
三、调试和日志
3.1 调试方法
bash
# 查看音频焦点状态
adb shell dumpsys audio
# 查看焦点栈
adb shell dumpsys media.audio_policy
# 启用详细日志
adb shell setprop log.tag.AudioFocus V