前言

简单跟一下AndroidAudioManager申请焦点的代码流程,顺便记录一下,方便自己查阅。

这里以Android 13的代码分析,而且以车载模式(car模式)跟踪。其实大部分内容跟《Android 9焦点申请源码简单记录》。

记录得有点绕,只是简单走一下流程,不一定适合你看。

正文

前面《Android 9焦点申请源码简单记录》跟过,部分细节就不详说了,直接进入正题。

AudioManager.java

requestAudioFocus()
public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
    return requestAudioFocus(focusRequest, null );
}
requestAudioFocus()
public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
    //略
    //注册到mAudioFocusIdListenerMap中,后面查询需要
    registerAudioFocusRequest(afr);
    //略
    final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
    //BlockingFocusResultReceiver后面会单独关注
    final BlockingFocusResultReceiver focusReceiver;
    synchronized (mFocusRequestsLock) {
        try {
            //status为返回状态,如果非车载模式,返回的就是申请焦点成功或失败,但车载模式不同。
            //mAudioFocusDispatcher这个重要,有状态回调,需要关注。
            //service是AudioService
            status = service.requestAudioFocus(afr.getAudioAttributes(),
                    afr.getFocusGain(), mICallBack,
                    mAudioFocusDispatcher,
                    clientId,
                    getContext().getOpPackageName(),
                    getContext().getAttributionTag(),
                    afr.getFlags(),
                    ap != null ? ap.cb() : null,
                    sdk);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        //返回的status就是AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY
        if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
            return status;
        }
        //如果开机第一次申请焦点,为null,进行初始化
        if (mFocusRequestsAwaitingResult == null) {
            mFocusRequestsAwaitingResult =
                    new HashMap<String, BlockingFocusResultReceiver>(1);
        }
        //创建BlockingFocusResultReceiver,
        focusReceiver = new BlockingFocusResultReceiver(clientId);
        //添加到申请结果等待列表,key为clientId后面需要根据key找focusReceiver
        mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
    }
    //延迟200ms,也就等待200ms是否能返回结果。
    focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
    //延迟已经获取结果的focusReceiver
    synchronized (mFocusRequestsLock) {
        //这里是根据clientID移除的
        mFocusRequestsAwaitingResult.remove(clientId);
    }
    //返回结果焦点申请成功或失败
    return focusReceiver.requestResult();
}

这里有几个重点

  1. 通过AudioService的requestAudioFocus()申请焦点

  2. 传入mAudioFocusDispatcher用于回调焦点申请状态

  3. BlockingFocusResultReceiver等待返回的焦点申请状态

下面先看一下2和3点,1后面进入AudioService中分析。

mAudioFocusDispatcher

对于mAudioFocusDispatcher,之前有介绍过。

这里主要是下面两个回调方法。

  1. 第一个之前看过,就是分发焦点变化,然后通知到app层。

  2. 第二个方法就是焦点申请结果状态的回调。

private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
    @Override
    public void dispatchAudioFocusChange(int focusChange, String id) {
        //根据客户端ID查找对应的FocusRequestInfo,这个是一开始注册焦点时放入mAudioFocusIdListenerMap中的。
        final FocusRequestInfo fri = findFocusRequestInfo(id);
        //下面符合条件的就会通知焦点变化。
        if (fri != null)  {
            final OnAudioFocusChangeListener listener =
                    fri.mRequest.getOnAudioFocusChangeListener();
            if (listener != null) {
                final Handler h = (fri.mHandler == null) ?
                        mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
                final Message m = h.obtainMessage(
                        MSSG_FOCUS_CHANGE, focusChange, 0,id);
                h.sendMessage(m);
            }
        }
    }

    @Override
    public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
        synchronized (mFocusRequestsLock) {
            //重点
            //先从队列中移除,然后返回对应的BlockingFocusResultReceiver
            final BlockingFocusResultReceiver focusReceiver =
                    mFocusRequestsAwaitingResult.remove(clientId);
            //不为null,就通知焦点申请requestResult结果
            if (focusReceiver != null) {
                focusReceiver.notifyResult(requestResult);
            } else {
                Log.e(TAG, "dispatchFocusResultFromExtPolicy 3 found no result receiver");
            }
        }
    }
};
BlockingFocusResultReceiver
private static final class BlockingFocusResultReceiver {
    private final SafeWaitObject mLock = new SafeWaitObject();
    @GuardedBy("mLock")
    private boolean mResultReceived = false;
    private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
    private final String mFocusClientId;

    BlockingFocusResultReceiver(String clientId) {
        mFocusClientId = clientId;
    }

    boolean receivedResult() { return mResultReceived; }
    int requestResult() { return mFocusRequestResult; }

    void notifyResult(int requestResult) {
        //更新状态
        synchronized (mLock) {
            mResultReceived = true;
            mFocusRequestResult = requestResult;
            //通知解锁
            mLock.safeNotify();
        }
    }

    public void waitForResult(long timeOutMs) {
        synchronized (mLock) {
            //如果提前有结果,就直接返回,否则等待200ms
            if (mResultReceived) {
                return;
            }
            try {
                mLock.safeWait(timeOutMs);
            } catch (InterruptedException e) { }
        }
    }
}
小结一下

车载模式跟非车载模式区别就是上面

  1. 车载模式和手机模式(非车载模式)申请流程类似,但返回焦点状态流程不一样

  2. 车载模式会之多等待200ms返回结果

好奇,如果当系统卡主,超过200ms返回的结果是啥?

进入AudioService

AudioService.java

requestAudioFocus()
public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
        IAudioFocusDispatcher fd, String clientId, String callingPackageName,
        String attributionTag, int flags, IAudioPolicyCallback pcb, int sdk) {
    //非法或权限等检查,略
    //是是否有锁住标签,普通app无法设置AudioManager.AUDIOFOCUS_FLAG_LOCK,暂时不关心
    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)) {
                final String reason = "Invalid permission to (un)lock audio focus";
                mmi.set(MediaMetrics.Property.EARLY_RETURN, reason)
                        .record();
                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
            }
        } else {
            // only a registered audio policy can be used to lock focus
            synchronized (mAudioPolicies) {
                if (!mAudioPolicies.containsKey(pcb.asBinder())) {
                    final String reason =
                            "Invalid unregistered AudioPolicy to (un)lock audio focus";
                    mmi.set(MediaMetrics.Property.EARLY_RETURN, reason)
                            .record();
                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
                }
            }
        }
    }
    //正常下肯定不为null
    if (callingPackageName == null || clientId == null || aa == null) {
        final String reason = "Invalid null parameter to request audio focus";
        mmi.set(MediaMetrics.Property.EARLY_RETURN, reason)
                .record();
        return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
    }
    mmi.record();
    //最终进入MediaFocusControl
    return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
            clientId, callingPackageName, attributionTag, flags, sdk,
            forceFocusDuckingForAccessibility(aa, durationHint, uid), -1 /*testUid, ignored*/);
}

MediaFocusControl.java

requestAudioFocus()

大部分跟之前手机模式(非车载模式)流程一样,但由于这里是车载模式,mFocusPolicy不为null,所以走的流程会不一样。

下面说一下不同点。

  1. 因为mFocusPolicy不为null,所以afiForExtPolicy也不为null

  2. 因为mFocusPolicy不为null,走notifyExtFocusPolicyFocusRequest_syncAf流程,然后判断直接return了。

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) {
    //略
    synchronized(mAudioFocusLock) {
        //队列中是否过多的FocusRequester,一般不会超过限制
        if (mFocusStack.size() > MAX_STACK_SIZE) {
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        }
        //铃声
        boolean enteringRingOrCall = !mRingOrCallActive
                & (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0);
        if (enteringRingOrCall) { mRingOrCallActive = true; }
        final AudioFocusInfo afiForExtPolicy;
        //mFocusPolicy是IAudioPolicyCallback对象
        //车载模式焦点策略
        if (mFocusPolicy != null) {
            //new一个AudioFocusInfo对象
            afiForExtPolicy = new AudioFocusInfo(aa, uid,
                    clientId, callingPackageName, focusChangeHint, 0 /*lossReceived*/,
                    flags, sdk);
        } else {
            afiForExtPolicy = null;
        }
        //是否可以请求焦点
        //一般来说通话(或BT或或有申请锁住flag的焦点应用)时,是不允许,否则运行
        if (!canReassignAudioFocus()) {
            //当此时不允许申请焦点时,看是否有延迟焦点标签
            if ((flags & AudioManager.AUDIOFOCUS_FLAG_DELAY_OK) == 0) {
                //没有就返回申请失败
                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
            } else {
                设置可以延迟获取焦点标签为true,等通话结束后可以重新获取到焦点
                focusGrantDelayed = true;
            }
        }
        //车载模式时焦点车略不为null
        if (mFocusPolicy != null) {
            //申请焦点
            if (notifyExtFocusPolicyFocusRequest_syncAf(afiForExtPolicy, fd, cb)) {
                return AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY;
            } else {
                //申请焦点失败
                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
            }
        }
    //由于车载模式,走了上面,下面的代码不走的。
    //略
}

下面关注notifyExtFocusPolicyFocusRequest_syncAf()。

notifyExtFocusPolicyFocusRequest_syncAf()
boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi,
        IAudioFocusDispatcher fd, @NonNull IBinder cb) {
    //外部(车载模式)焦点计数
    synchronized (mExtFocusChangeLock) {
        afi.setGen(mExtFocusChangeCounter++);
    }
    //查询id是否已经在队列中
    final FocusRequester existingFr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
    boolean keepTrack = false;
    //我们这是第一次,不存在,为null
    if (existingFr != null) {
        //看是否存在一样的IAudioFocusDispatcher回调
        if (!existingFr.hasSameDispatcher(fd)) {
            existingFr.release();
            keepTrack = true;
        }
    } else {
        keepTrack = true;
    }
    //为true
    if (keepTrack) {
        final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
        try {
            cb.linkToDeath(hdlr, 0);
        } catch (RemoteException e) {
            return false;
        }
        //创建FocusRequester并添加到队列中
        mFocusOwnersForFocusPolicy.put(afi.getClientId(),
                new FocusRequester(afi, fd, cb, hdlr, this));
    }
    try {
        //通知焦点申请
        mFocusPolicy.notifyAudioFocusRequest(afi, AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
        return true;
    } catch (RemoteException e) {
    }
    return false;
}

这里重点

mFocusPolicy.notifyAudioFocusRequest(afi, AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
private IAudioPolicyCallback mFocusPolicy = null;

mFocusPolicy是在setFocusPolicy()中赋值的。

setFocusPolicy()
void setFocusPolicy(IAudioPolicyCallback policy, boolean isTestFocusPolicy) {
    if (policy == null) {
        return;
    }
    synchronized (mAudioFocusLock) {
        if (isTestFocusPolicy) {
            mPreviousFocusPolicy = mFocusPolicy;
        }
        mFocusPolicy = policy;
    }
}

上面可以看出mFocusPolicy是其他地方传入的。

而setFocusPolicy的调用是在AudioService.java中的内部类AudioPolicyProxy中。

AudioService.java

AudioPolicyProxy()
AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
        boolean hasFocusListener, boolean isFocusPolicy, boolean isTestFocusPolicy,
        boolean isVolumeController, IMediaProjection projection) {
    super(config);
    setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
    //这里赋值的。
    mPolicyCallback = token;
    mHasFocusListener = hasFocusListener;
    mIsVolumeController = isVolumeController;
    mProjection = projection;
    if (mHasFocusListener) {
        mMediaFocusControl.addFocusFollower(mPolicyCallback);
        if (isFocusPolicy) {
            mIsFocusPolicy = true;
            mIsTestFocusPolicy = isTestFocusPolicy;
			//这里设置policy
            mMediaFocusControl.setFocusPolicy(mPolicyCallback, mIsTestFocusPolicy);
        }
    }
	//略
}

而AudioPolicyProxy的初始化在,AudioService.java的registerAudioPolicy()中

registerAudioPolicy()
public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
        boolean hasFocusListener, boolean isFocusPolicy, boolean isTestFocusPolicy,
        boolean isVolumeController, IMediaProjection projection) {
    AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
	//判断是否允许注册
    if (!isPolicyRegisterAllowed(policyConfig,
                                 isFocusPolicy || isTestFocusPolicy || hasFocusListener,
                                 isVolumeController,
                                 projection)) {
        return null;
    }
    String regId = null;
    synchronized (mAudioPolicies) {
        if (mAudioPolicies.containsKey(pcb.asBinder())) {
            return null;
        }
        try {
			//初始化AudioPolicyProxy对象
			//关注第二个参数pcb,为IAudioPolicyCallback对象。
            AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener,
                    isFocusPolicy, isTestFocusPolicy, isVolumeController, projection);
            pcb.asBinder().linkToDeath(app, 0/*flags*/);
            regId = app.getRegistrationId();
            mAudioPolicies.put(pcb.asBinder(), app);
        } catch (RemoteException e) {
            return null;
        } catch (IllegalStateException e) {
            return null;
        }
    }
    return regId;
}

registerAudioPolicy()注册时在AudioManager中调用的。

AudioManager.java

registerAudioPolicyStatic()

然后调用的是AudioService中的registerAudioPolicy()。

static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
    if (policy == null) {
        throw new IllegalArgumentException("Illegal null AudioPolicy argument");
    }
    final IAudioService service = getService();
    try {
        MediaProjection projection = policy.getMediaProjection();
		//service就是AudioService的代理
		//依旧关注第二个参数,policy.cb()
        String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
                policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
                policy.isVolumeController(),
                projection == null ? null : projection.getProjection());
        if (regId == null) {
            return ERROR;
        } else {
            policy.setRegistration(regId);
        }
        // successful registration
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
    return SUCCESS;
}

重点是第二个参数,policy.cb(),返回的是mPolicyCb

public IAudioPolicyCallback cb() { return mPolicyCb; }

这里先看一下Policy哪里注册的。

registerAudioPolicy()
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public int registerAudioPolicy(@NonNull AudioPolicy policy) {
    return registerAudioPolicyStatic(policy);
}

这种事car模式(车载模式)下,调用这个注册是在Car的CarAudioService中的。

CarAudioService.java

\packages\services\Car\service\src\com\android\car\audio\CarAudioService.java
setupDynamicRoutingLocked()
private void setupDynamicRoutingLocked() {
    final AudioPolicy.Builder builder = new AudioPolicy.Builder(mContext);
    
    //略
    
    //mFocusHandler需要重点关注
    mFocusHandler = CarZonesAudioFocus.createCarZonesAudioFocus(mAudioManager,
            mContext.getPackageManager(),
            mCarAudioZones,
            mCarAudioSettings,
            mCarDucking);
			Log.w(TAG, "setupDynamicRoutingLocked  mFocusHandler : "+mFocusHandler );
	//这里mFocusHandler比较重要哈,用于回调状态
    builder.setAudioPolicyFocusListener(mFocusHandler);
    builder.setIsAudioFocusPolicy(true);

	//AudioPolicy的初始化,使用了Build模式
    mAudioPolicy = builder.build();

    mFocusHandler.setOwningPolicy(this, mAudioPolicy);
	
	//注册到mAudioManager中
    int r = mAudioManager.registerAudioPolicy(mAudioPolicy);
    if (r != AudioManager.SUCCESS) {
        throw new RuntimeException("registerAudioPolicy failed " + r);
    }
    setupOccupantZoneInfo();
}

mAudioPolicy就是AudioPolicy,这后面跟。

该方法在init()中初始化的。

init()
@Override
public void init() {
    synchronized (mImplLock) {
        mOccupantZoneService = CarLocalServices.getService(CarOccupantZoneService.class);
        Car car = new Car(mContext, /* service= */null, /* handler= */ null);
        mOccupantZoneManager = new CarOccupantZoneManager(car, mOccupantZoneService);
       //这里判断是否用动态路由
        if (mUseDynamicRouting) {
            setupDynamicRoutingLocked();
            setupHalAudioFocusListenerLocked();
            setupHalAudioGainCallbackLocked();
            setupAudioConfigurationCallbackLocked();
            setupPowerPolicyListener();
        } else {
            setupLegacyVolumeChangedListener();
        }
        mAudioManager.setSupportedSystemUsages(SYSTEM_USAGES);
    }
    restoreMasterMuteState();
}

也就是Car模式下,切设置了使用动态路由,就需要注册mAudioPolicy。

AudioPolicy.java

frameworks\base\media\java\android\media\audiopolicy\AudioPolicy.java

AudioPolicy的初始化使用了Builder模式,因此这里直接看build()方法。

build()
@NonNull
public AudioPolicy build() {
    if (mStatusListener != null) {
        for (AudioMix mix : mMixes) {
            mix.mCallbackFlags |= AudioMix.CALLBACK_FLAG_NOTIFY_ACTIVITY;
        }
    }
    if (mIsFocusPolicy && mFocusListener == null) {
        throw new IllegalStateException("Cannot be a focus policy without "
                + "an AudioPolicyFocusListener");
    }
    return new AudioPolicy(new AudioPolicyConfig(mMixes), mContext, mLooper,
            mFocusListener, mStatusListener, mIsFocusPolicy, mIsTestFocusPolicy,
            mVolCb, mProjection);
}
AudioPolicy()
private AudioPolicy(AudioPolicyConfig config, Context context, Looper looper,
        AudioPolicyFocusListener fl, AudioPolicyStatusListener sl,
        boolean isFocusPolicy, boolean isTestFocusPolicy,
        AudioPolicyVolumeCallback vc, @Nullable MediaProjection projection) {
    mConfig = config;
    mStatus = POLICY_STATUS_UNREGISTERED;
    mContext = context;
    if (looper == null) {
        looper = Looper.getMainLooper();
    }
    if (looper != null) {
        mEventHandler = new EventHandler(this, looper);
    } else {
        mEventHandler = null;
    }
    mFocusListener = fl;
    mStatusListener = sl;
    mIsFocusPolicy = isFocusPolicy;
    mIsTestFocusPolicy = isTestFocusPolicy;
    mVolCb = vc;
    mProjection = projection;
}

重点关注是传入的mFocusListener。这个参数是使用Build模式传入的,这里略过,但需要这个是用于焦点回调的即可。

当然其他参数也比较重要,这里只挑暂时关注的看哈。

小结
  1. Car模式下,在CarAudioService中初始化并注册AudioPolicy,并传入了mFocusListener

  2. mFocusPolicy是通过AudioPolicy.cb()赋值的,也就是AudioPolicy中的mPolicyCb

MediaFocusControl.java

继续上面,我们说介绍在notifyExtFocusPolicyFocusRequest_syncAf()中

mFocusPolicy.notifyAudioFocusRequest(afi, AudioManager.AUDIOFOCUS_REQUEST_GRANTED);

从上面可以知道,mFocusPolicy就是AudioPolicy中的mPolicyCb。

AudioPolicy.java

进入看mPolicyCb变量。

mPolicyCb

其的重写的方法很多,重点关注notifyAudioFocusRequest()

private final IAudioPolicyCallback mPolicyCb = new IAudioPolicyCallback.Stub() {
    public void notifyAudioFocusGrant(AudioFocusInfo afi, int requestResult) {
        sendMsg(MSG_FOCUS_GRANT, afi, requestResult);
    }

    public void notifyAudioFocusLoss(AudioFocusInfo afi, boolean wasNotified) {
        sendMsg(MSG_FOCUS_LOSS, afi, wasNotified ? 1 : 0);
    }

    public void notifyAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
        sendMsg(MSG_FOCUS_REQUEST, afi, requestResult);
    }

    public void notifyAudioFocusAbandon(AudioFocusInfo afi) {
        sendMsg(MSG_FOCUS_ABANDON, afi, 0 /* ignored */);
    }
    //略
};

notifyAudioFocusRequest()只是发生了MSG_FOCUS_REQUEST消息。

handleMessage()
private final EventHandler mEventHandler;
private final static int MSG_POLICY_STATUS_CHANGE = 0;
private final static int MSG_FOCUS_GRANT = 1;
private final static int MSG_FOCUS_LOSS = 2;
private final static int MSG_MIX_STATE_UPDATE = 3;
private final static int MSG_FOCUS_REQUEST = 4;
private final static int MSG_FOCUS_ABANDON = 5;
private final static int MSG_VOL_ADJUST = 6;

private class EventHandler extends Handler {
    public EventHandler(AudioPolicy ap, Looper looper) {
        super(looper);
    }
    
    @Override
    public void handleMessage(Message msg) {
        switch(msg.what) {
            case MSG_POLICY_STATUS_CHANGE:
                onPolicyStatusChange();
                break;
            case MSG_FOCUS_GRANT:
                if (mFocusListener != null) {
                    mFocusListener.onAudioFocusGrant(
                            (AudioFocusInfo) msg.obj, msg.arg1);
                }
                break;
            case MSG_FOCUS_LOSS:
                if (mFocusListener != null) {
                    mFocusListener.onAudioFocusLoss(
                            (AudioFocusInfo) msg.obj, msg.arg1 != 0);
                }
                break;
            case MSG_MIX_STATE_UPDATE:
                if (mStatusListener != null) {
                    mStatusListener.onMixStateUpdate((AudioMix) msg.obj);
                }
                break;
            case MSG_FOCUS_REQUEST:
            	//是不是很熟悉,CarAudioService中创建和传入的。
                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;
            case MSG_FOCUS_ABANDON:
                if (mFocusListener != null) { // should never be null
                    mFocusListener.onAudioFocusAbandon((AudioFocusInfo) msg.obj);
                } else { // should never be null, but don't crash
                    Log.e(TAG, "Invalid null focus listener for focus abandon event");
                }
                break;
            case MSG_VOL_ADJUST:
                if (mVolCb != null) {
                    mVolCb.onVolumeAdjustment(msg.arg1);
                } else { // should never be null, but don't crash
                    Log.e(TAG, "Invalid null volume event");
                }
                break;
            default:
                Log.e(TAG, "Unknown event " + msg.what);
        }
    }
}

这里调用了

mFocusListener.onAudioFocusRequest((AudioFocusInfo) msg.obj, msg.arg1);

因此,我们回到Car中的CarAudioService中。

CarAudioService.java

setupDynamicRoutingLocked()

在setupDynamicRoutingLocked()中重点看mFocusHandler的初始化

mFocusHandler = CarZonesAudioFocus.createCarZonesAudioFocus(mAudioManager,
        mContext.getPackageManager(),
        mCarAudioZones,
        mCarAudioSettings,
        mCarDucking);

知道,mFocusHandler是CarZonesAudioFocus对象。

CarZonesAudioFocus.java

\packages\services\Car\service\src\com\android\car\audio\CarZonesAudioFocus.java
onAudioFocusRequest()
@Override
public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
    int zoneId = getAudioZoneIdForAudioFocusInfo(afi);
	//通知焦点回调,这里根据zoneId返回CarAudioFocus
    getCarAudioFocusForZoneId(zoneId).onAudioFocusRequest(afi, requestResult);
    notifyFocusCallback(new int[]{zoneId});
}

不同zone的焦点配置可能不一样,这里不关注细节。

getCarAudioFocusForZoneId()
@NonNull
private CarAudioFocus getCarAudioFocusForZoneId(int zoneId) {
    return mFocusZones.get(zoneId);
}

CarAudioFocus.java

\packages\services\Car\service\src\com\android\car\audio\CarAudioFocus.java
onAudioFocusRequest()
@Override
public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
    int response;
    AudioPolicy policy;
    synchronized (mLock) {
        policy = mAudioPolicy;
        response = evaluateFocusRequestLocked(afi);
    }
    //这又回调了AudioManager
    mAudioManager.setFocusRequestResult(afi, response, policy);
}

AudioManager.java

setFocusRequestResult.java
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
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 {
    	//调用AudioService.java
        service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

AudioService.java

setFocusRequestResultFromExtPolicy()
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");
        }
        //进入MediaFocusControl
        mMediaFocusControl.setFocusRequestResultFromExtPolicy(afi, requestResult);
    }
}

MediaFocusControl.java

setFocusRequestResultFromExtPolicy()
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());
    }
    //如果不为null,分发结果
    if (fr != null) {
        fr.dispatchFocusResultFromExtPolicy(requestResult);
    }
}

FocusRequester.java

dispatchFocusResultFromExtPolicy()
void dispatchFocusResultFromExtPolicy(int requestResult) {
    final IAudioFocusDispatcher fd = mFocusDispatcher;
    if (fd == null) {
        return;
    }
    try {
    	//IAudioFocusDispatcher在AudioManager中有对应的实现类
    	//也就是请求焦点时传入的mAudioFocusDispatcher
        fd.dispatchFocusResultFromExtPolicy(requestResult, mClientId);
    } catch (android.os.RemoteException e) {
    }
}

mAudioFocusDispatcher前面在AudioManager中有介绍的。

AudioManager.java

mAudioFocusDispatcher
private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
    @Override
    public void dispatchAudioFocusChange(int focusChange, String id) {
    	//根据客户端ID查找对应的FocusRequestInfo,这个是一开始注册焦点时放入mAudioFocusIdListenerMap中的。
        final FocusRequestInfo fri = findFocusRequestInfo(id);
        //下面符合条件的就会通知焦点变化。
        if (fri != null)  {
            final OnAudioFocusChangeListener listener =
                    fri.mRequest.getOnAudioFocusChangeListener();
            if (listener != null) {
                final Handler h = (fri.mHandler == null) ?
                        mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
                final Message m = h.obtainMessage(
                        MSSG_FOCUS_CHANGE, focusChange, 0,id);
                h.sendMessage(m);
            }
        }
    }

    @Override
    public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
        synchronized (mFocusRequestsLock) {
        	//重点
        	//先从队列中移除,然后返回对应的BlockingFocusResultReceiver
            final BlockingFocusResultReceiver focusReceiver =
                    mFocusRequestsAwaitingResult.remove(clientId);
            //不为null,就通知焦点申请requestResult结果
            if (focusReceiver != null) {
                focusReceiver.notifyResult(requestResult);
            } else {
                Log.e(TAG, "dispatchFocusResultFromExtPolicy 3 found no result receiver");
            }
        }
    }
};

然后就是进入BlockingFocusResultReceiver中了,最后就是返回焦点申请结果。

至于焦点变化通知,这个后面再单独介绍一下吧。

参考文章

  1. 《Android 13源码》

相关文章

暂无评论

none
暂无评论...