Android13 CarAudioFocus onAudioFocusRequest回调处理流程分析

CarZonesAudioFocus 继承于AudioPolicy.AudioPolicyFocusListener,当有音频焦点请求时就会调用到CarZonesAudioFocus的onAudioFocusRequest方法:

//packages/services/Car/service/src/com/android/car/audio/CarZonesAudioFocus.java
final class CarZonesAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
    private final SparseArray<CarAudioFocus> mFocusZones;
    public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
        int zoneId = getAudioZoneIdForAudioFocusInfo(afi); //通过AudioFocusInfo获取zoneId 
        getCarAudioFocusForZoneId(zoneId).onAudioFocusRequest(afi, requestResult); //调用CarAudioFocus的onAudioFocusRequest方法
        notifyFocusCallback(new int[]{zoneId}); //通知音频焦点回调
    }
}

上面方法进行如下处理:

调用getAudioZoneIdForAudioFocusInfo方法获取zoneId。

调用CarAudioFocus的onAudioFocusRequest方法,进行音频焦点仲裁。

调用notifyFocusCallback方法,进行Ducking处理。

getAudioZoneIdForAudioFocusInfo

调用getAudioZoneIdForAudioFocusInfo方法获取zoneId:

//packages/services/Car/service/src/com/android/car/audio/CarZonesAudioFocus.java
final class CarZonesAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
    private int getAudioZoneIdForAudioFocusInfo(AudioFocusInfo afi) {
        int zoneId = mCarAudioService.getZoneIdForUid(afi.getClientUid());


        // If the bundle attribute for AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID has been assigned
        // Use zone id from that instead.
        Bundle bundle = afi.getAttributes().getBundle();


        if (bundle != null) {
            int bundleZoneId =
                    bundle.getInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID,
                            -1);
            // check if the zone id is within current zones bounds
            if (mCarAudioService.isAudioZoneIdValid(bundleZoneId)) {
                Slogf.d(TAG, "getFocusForAudioFocusInfo valid zoneId %d with bundle request for"
                        + " client %s", bundleZoneId, afi.getClientId());
                zoneId = bundleZoneId;
            } else {
                Slogf.w(TAG, "getFocusForAudioFocusInfo invalid zoneId %d with bundle request for "
                                + "client %s, dispatching focus request to zoneId %d", bundleZoneId,
                        afi.getClientId(), zoneId);
            }
        }


        return zoneId;
    }
}

onAudioFocusRequest

调用CarAudioFocus的onAudioFocusRequest方法:

//packages/services/Car/service/src/com/android/car/audio/CarAudioFocus.java
class CarAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
    public void onAudioFocusRequest(AudioFocusInfo afi, int requestResult) {
        int response;
        AudioPolicy policy;
        synchronized (mLock) {
            policy = mAudioPolicy;
            response = evaluateFocusRequestLocked(afi); //评估焦点请求
        }


        // Post our reply for delivery to the original focus requester
        mAudioManager.setFocusRequestResult(afi, response, policy); //设置音频焦点请求结果
        logFocusEvent("onAudioFocusRequest for client " + afi.getClientId()
                + " with gain type " + focusEventToString(afi.getGainRequest())
                + " resulted in " + focusRequestResponseToString(response));
    }
}

CarAudioFocus .evaluateFocusRequestLocked

调用evaluateFocusRequestLocked评估焦点请求:

//packages/services/Car/service/src/com/android/car/audio/CarAudioFocus.java
class CarAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
    private int evaluateFocusRequestLocked(AudioFocusInfo afi) {
        Slogf.i(TAG, "Evaluating " + focusEventToString(afi.getGainRequest())
                + " request for client " + afi.getClientId()
                + " with usage " + usageToString(afi.getAttributes().getUsage()));


        if (mIsFocusRestricted) {
            int audioContext = CarAudioContext.getContextForAttributes(afi.getAttributes());
            if (!isCriticalAudioContext(audioContext)) {
                return AUDIOFOCUS_REQUEST_FAILED;
            }
        }


        // Is this a request for premanant focus?
        // AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE -- Means Notifications should be denied
        // AUDIOFOCUS_GAIN_TRANSIENT -- Means current focus holders should get transient loss
        // AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK -- Means other can duck (no loss message from us)
        // NOTE:  We expect that in practice it will be permanent for all media requests and
        //        transient for everything else, but that isn't currently an enforced requirement.
        final boolean permanent =
                (afi.getGainRequest() == AUDIOFOCUS_GAIN);
        final boolean allowDucking =
                (afi.getGainRequest() == AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);


        boolean delayFocusForCurrentRequest = false;


        int requestedContext = CarAudioContext.getContextForAttributes(afi.getAttributes());


        // If we happen to find entries that this new request should replace, we'll store them here.
        // This happens when a client makes a second AF request on the same listener.
        // After we've granted audio focus to our current request, we'll abandon these requests.
        FocusEntry replacedCurrentEntry = null;
        FocusEntry replacedBlockedEntry = null;


        boolean allowDelayedFocus = canReceiveDelayedFocus(afi); //可以接收延迟聚焦


        // We don't allow sharing listeners (client IDs) between two concurrent requests
        // (because the app would have no way to know to which request a later event applied)
        if (mDelayedRequest != null && afi.getClientId().equals(mDelayedRequest.getClientId())) {
            int delayedRequestedContext = CarAudioContext.getContextForAttributes(
                    mDelayedRequest.getAttributes());
            // If it is for a different context then reject
            if (delayedRequestedContext != requestedContext) {
                // Trivially reject a request for a different USAGE
                Slogf.e(TAG, "Client %s has already delayed requested focus for %s - cannot request"
                        + " focus for %s on same listener.", mDelayedRequest.getClientId(),
                        usageToString(mDelayedRequest.getAttributes().getUsage()),
                        usageToString(afi.getAttributes().getUsage()));
                return AUDIOFOCUS_REQUEST_FAILED;
            }
        }


        // Scan all active and pending focus requests.  If any should cause rejection of
        // this new request, then we're done.  Keep a list of those against whom we're exclusive
        // so we can update the relationships if/when we are sure we won't get rejected.
        Slogf.i(TAG, "Scanning focus holders...");
        final ArrayList<FocusEntry> losers = new ArrayList<FocusEntry>();
        for (FocusEntry entry : mFocusHolders.values()) { //扫描拥有焦点者
            Slogf.d(TAG, "Evaluating focus holder: " + entry.getClientId());


            // If this request is for Notifications and a current focus holder has specified
            // AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE, then reject the request.
            // This matches the hardwired behavior in the default audio policy engine which apps
            // might expect (The interaction matrix doesn't have any provision for dealing with
            // override flags like this).
            if ((requestedContext == CarAudioContext.NOTIFICATION)
                    && (entry.getAudioFocusInfo().getGainRequest()
                    == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
                return AUDIOFOCUS_REQUEST_FAILED;
            }


            // We don't allow sharing listeners (client IDs) between two concurrent requests
            // (because the app would have no way to know to which request a later event applied)
            if (afi.getClientId().equals(entry.getAudioFocusInfo().getClientId())) {
                if ((entry.getAudioContext() == requestedContext)
                        || canSwapCallOrRingerClientRequest(afi.getClientId(),
                        entry.getAudioContext(), requestedContext)) {
                    // This is a request from a current focus holder.
                    // Abandon the previous request (without sending a LOSS notification to it),
                    // and don't check the interaction matrix for it.
                    Slogf.i(TAG, "Replacing accepted request from same client: %s",
                            afi.getClientId());
                    replacedCurrentEntry = entry;
                    continue;
                } else {
                    // Trivially reject a request for a different USAGE
                    Slogf.e(TAG, "Client %s has already requested focus for %s - cannot request "
                            + "focus for %s on same listener.", entry.getClientId(),
                            usageToString(entry.getAudioFocusInfo().getAttributes().getUsage()),
                            usageToString(afi.getAttributes().getUsage()));
                    return AUDIOFOCUS_REQUEST_FAILED;
                }
            }


            int interactionResult = mFocusInteraction.evaluateRequest(requestedContext, entry,
                    losers, allowDucking, allowDelayedFocus); //基于交互矩阵评估传入焦点与当前焦点请求之间的交互
            if (interactionResult == AUDIOFOCUS_REQUEST_FAILED) { //失败
                return interactionResult;
            }
            if (interactionResult == AUDIOFOCUS_REQUEST_DELAYED) { //延迟
                delayFocusForCurrentRequest = true;
            }
        }
        Slogf.i(TAG, "Scanning those who've already lost focus...");
        final ArrayList<FocusEntry> blocked = new ArrayList<FocusEntry>();
        for (FocusEntry entry : mFocusLosers.values()) { //扫描失去焦点者
            Slogf.i(TAG, entry.getAudioFocusInfo().getClientId());


            // If this request is for Notifications and a pending focus holder has specified
            // AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE, then reject the request
            if ((requestedContext == CarAudioContext.NOTIFICATION)
                    && (entry.getAudioFocusInfo().getGainRequest()
                    == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)) {
                return AUDIOFOCUS_REQUEST_FAILED;
            }


            // We don't allow sharing listeners (client IDs) between two concurrent requests
            // (because the app would have no way to know to which request a later event applied)
            if (afi.getClientId().equals(entry.getAudioFocusInfo().getClientId())) {
                if (entry.getAudioContext() == requestedContext) {
                    // This is a repeat of a request that is currently blocked.
                    // Evaluate it as if it were a new request, but note that we should remove
                    // the old pending request, and move it.
                    // We do not want to evaluate the new request against itself.
                    Slogf.i(TAG, "Replacing pending request from same client");
                    replacedBlockedEntry = entry;
                    continue;
                } else {
                    // Trivially reject a request for a different USAGE
                    Slogf.e(TAG, "Client %s has already requested focus for %s - cannot request "
                            + "focus for %s on same listener.", entry.getClientId(),
                            usageToString(entry.getAudioFocusInfo().getAttributes().getUsage()),
                            usageToString(afi.getAttributes().getUsage()));
                    return AUDIOFOCUS_REQUEST_FAILED;
                }
            }


            int interactionResult = mFocusInteraction
                    .evaluateRequest(requestedContext, entry, blocked, allowDucking,
                            allowDelayedFocus); //基于交互矩阵评估传入焦点与当前焦点请求之间的交互
            if (interactionResult == AUDIOFOCUS_REQUEST_FAILED) { //失败
                return interactionResult;
            }
            if (interactionResult == AUDIOFOCUS_REQUEST_DELAYED) { //延迟
                delayFocusForCurrentRequest = true;
            }
        }


        // Now that we've decided we'll grant focus, construct our new FocusEntry
        // 现在我们已经决定授予焦点,构建我们的新焦点条目
        FocusEntry newEntry = new FocusEntry(afi, requestedContext, mPackageManager);
// 由于此请求,这些条目已永久失去焦点,因此应从所有阻止程序列表中删除它们。
        // These entries have permanently lost focus as a result of this request, so they
        // should be removed from all blocker lists.
        ArrayList<FocusEntry> permanentlyLost = new ArrayList<>();


        if (replacedCurrentEntry != null) {
            mFocusHolders.remove(replacedCurrentEntry.getClientId());
            permanentlyLost.add(replacedCurrentEntry);
        }
        if (replacedBlockedEntry != null) {
            mFocusLosers.remove(replacedBlockedEntry.getClientId());
            permanentlyLost.add(replacedBlockedEntry);
        }


 // 现在我们确定我们会接受此请求,请更新我们将要更新的任何请求
        // Now that we're sure we'll accept this request, update any requests which we would
        // block but are already out of focus but waiting to come back
        for (FocusEntry entry : blocked) {
            // If we're out of focus it must be because somebody is blocking us
            assert !entry.isUnblocked();


            if (permanent) {
                // This entry has now lost focus forever
                sendFocusLossLocked(entry.getAudioFocusInfo(), AUDIOFOCUS_LOSS); //发送焦点失去消息
                entry.setDucked(false);
                final FocusEntry deadEntry = mFocusLosers.remove(
                        entry.getAudioFocusInfo().getClientId());
                assert deadEntry != null;
                permanentlyLost.add(entry);
            } else {
                if (!allowDucking && entry.isDucked()) {
                    // This entry was previously allowed to duck, but can no longer do so.
                    Slogf.i(TAG, "Converting duckable loss to non-duckable for "
                            + entry.getClientId());
                    sendFocusLossLocked(entry.getAudioFocusInfo(), AUDIOFOCUS_LOSS_TRANSIENT); //发送焦点短暂失去消息
                    entry.setDucked(false);
                }
                // Note that this new request is yet one more reason we can't (yet) have focus
                entry.addBlocker(newEntry);
            }
        }


        // Notify and update any requests which are now losing focus as a result of the new request
// 通知并更新由于新请求而失去焦点的任何请求
        for (FocusEntry entry : losers) {
            // If we have focus (but are about to loose it), nobody should be blocking us yet
            assert entry.isUnblocked();


            int lossType;
            if (permanent) {
                lossType = AUDIOFOCUS_LOSS; //失去焦点
            } else if (allowDucking && entry.receivesDuckEvents()) {
                lossType = AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK; //失去焦点并且进行Duck处理
                entry.setDucked(true);
            } else {
                lossType = AUDIOFOCUS_LOSS_TRANSIENT; //暂时失去
            }
            sendFocusLossLocked(entry.getAudioFocusInfo(), lossType); //发送焦点失去消息


            // The entry no longer holds focus, so take it out of the holders list
            mFocusHolders.remove(entry.getAudioFocusInfo().getClientId());


            if (permanent) {
                permanentlyLost.add(entry);
            } else {
                // Add ourselves to the list of requests waiting to get focus back and
                // note why we lost focus so we can tell when it's time to get it back
                mFocusLosers.put(entry.getAudioFocusInfo().getClientId(), entry);
                entry.addBlocker(newEntry);
            }
        }


        // Now that all new blockers have been added, clear out any other requests that have been
        // permanently lost as a result of this request. Treat them as abandoned - if they're on
        // any blocker lists, remove them. If any focus requests become unblocked as a result,
        // re-grant them. (This can happen when a GAIN_TRANSIENT_MAY_DUCK request replaces a
        // GAIN_TRANSIENT request from the same listener.)
        for (FocusEntry entry : permanentlyLost) {
            Slogf.d(TAG, "Cleaning up entry " + entry.getClientId());
            removeBlockerAndRestoreUnblockedWaitersLocked(entry);
        }


        if (delayFocusForCurrentRequest) {
            swapDelayedAudioFocusRequestLocked(afi);
            return AUDIOFOCUS_REQUEST_DELAYED;
        }


        mFocusHolders.put(afi.getClientId(), newEntry);


        Slogf.i(TAG, "AUDIOFOCUS_REQUEST_GRANTED");
        return AUDIOFOCUS_REQUEST_GRANTED;
    }
}

CarAudioFocus.sendFocusLossLocked

调用sendFocusLossLocked发送焦点失去消息:

//packages/services/Car/service/src/com/android/car/audio/CarAudioFocus.java
class CarAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
    private final AudioManager mAudioManager;
    private void sendFocusLossLocked(AudioFocusInfo loser, int lossType) {
        int result = mAudioManager.dispatchAudioFocusChange(loser, lossType,
                mAudioPolicy); //通过AudioManager通知具有焦点侦听器的应用程序音频焦点的变化
        if (result != AUDIOFOCUS_REQUEST_GRANTED) {
            // TODO:  Is this actually an error, or is it okay for an entry in the focus stack
            // to NOT have a listener?  If that's the case, should we even keep it in the focus
            // stack?
            Slogf.e(TAG, "Failure to signal loss of audio focus with error: " + result);
        }


        logFocusEvent("sendFocusLoss for client " + loser.getClientId()
                + " with loss type " + focusEventToString(lossType)
                + " resulted in " + focusRequestResponseToString(result));
    }
}
AudioManager dispatchAudioFocusChange

通过AudioManager通知具有焦点侦听器的应用程序音频焦点的变化:

//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
    //Notifies an application with a focus listener of gain or loss of audio focus.
    //通知具有焦点侦听器的应用程序音频焦点的增益或损失。
    public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
            @NonNull AudioPolicy ap) {
        if (afi == null) {
            throw new NullPointerException("Illegal null AudioFocusInfo");
        }
        if (ap == null) {
            throw new NullPointerException("Illegal null AudioPolicy");
        }
        final IAudioService service = getService(); //获取IAudioService对象
        try {
            return service.dispatchFocusChange(afi, focusChange, ap.cb()); //调用IAudioService的dispatchFocusChange方法
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}

调用IAudioService的dispatchFocusChange方法,IAudioService是一个接口,由AudioService的dispatchFocusChange方法实现:

//frameworks/base/service/java/com/android/server/audio/AudioService.java
public class AudioService extends IAudioService.Stub
    private final MediaFocusControl mMediaFocusControl;
    public int dispatchFocusChange(AudioFocusInfo afi, int focusChange, 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 focus dispatch");
            }
            return mMediaFocusControl.dispatchFocusChange(afi, focusChange); //调用MediaFocusControl的dispatchFocusChange方法
        }
    }
}

调用MediaFocusControl的dispatchFocusChange方法:

//frameworks/base/service/java/com/android/server/audio/MediaFocusControl.java
public class MediaFocusControl implements PlayerFocusEnforcer {
    int dispatchFocusChange(AudioFocusInfo afi, int focusChange) {
        if (DEBUG) {
            Log.v(TAG, "dispatchFocusChange " + focusChange + " to afi client="
                    + afi.getClientId());
        }
        synchronized (mAudioFocusLock) {
            if (mFocusPolicy == null) {
                if (DEBUG) { Log.v(TAG, "> failed: no focus policy" ); }
                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
            }
            final FocusRequester fr;
            if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
                fr = mFocusOwnersForFocusPolicy.remove(afi.getClientId());
            } else {
                fr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
            }
            if (fr == null) {
                if (DEBUG) { Log.v(TAG, "> failed: no such focus requester known" ); }
                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
            }
            return fr.dispatchFocusChange(focusChange); //调用FocusRequester的dispatchFocusChange方法
        }
    }
}

调用FocusRequester的dispatchFocusChange方法:

//frameworks/base/service/java/com/android/server/audio/FocusRequester.java
public class FocusRequester {
    int dispatchFocusChange(int focusChange) {
        final IAudioFocusDispatcher fd = mFocusDispatcher;
        if (fd == null) {
            if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusChange: no focus dispatcher"); }
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        }
        if (focusChange == AudioManager.AUDIOFOCUS_NONE) {
            if (MediaFocusControl.DEBUG) { Log.v(TAG, "dispatchFocusChange: AUDIOFOCUS_NONE"); }
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        } else if ((focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
                || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
                || focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
                || focusChange == AudioManager.AUDIOFOCUS_GAIN)
                && (mFocusGainRequest != focusChange)){
            Log.w(TAG, "focus gain was requested with " + mFocusGainRequest
                    + ", dispatching " + focusChange);
        } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
                || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT
                || focusChange == AudioManager.AUDIOFOCUS_LOSS) {
            mFocusLossReceived = focusChange;
        }
        try {
            fd.dispatchAudioFocusChange(focusChange, mClientId); //调用IAudioFocusDispatcher的dispatchAudioFocusChange方法
        } catch (android.os.RemoteException e) {
            Log.e(TAG, "dispatchFocusChange: error talking to focus listener " + mClientId, e);
            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        }
        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
    }
}

调用IAudioFocusDispatcher的dispatchAudioFocusChange方法,IAudioFocusDispatcher是一个接口,由AudioManager实现:

//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
    private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
        @Override
        public void dispatchAudioFocusChange(int focusChange, String id) {
            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/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/, //获取要发送的消息
                            id/*obj*/);
                    h.sendMessage(m); //发送消息
                }
            }
        }
    };
}

发送MSSG_FOCUS_CHANGE消息,AudioManager的内部类ServiceEventHandlerDelegate的handleMessage方法会处理这个消息:

//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
    private class ServiceEventHandlerDelegate {
        private final Handler mHandler;


        ServiceEventHandlerDelegate(Handler handler) {
            Looper looper;
            if (handler == null) {
                if ((looper = Looper.myLooper()) == null) {
                    looper = Looper.getMainLooper();
                }
            } else {
                looper = handler.getLooper();
            }


            if (looper != null) {
                // implement the event handler delegate to receive events from audio service
                mHandler = new Handler(looper) {
                    @Override
                    public void handleMessage(Message msg) {
                        switch (msg.what) {
                            case MSSG_FOCUS_CHANGE: {
                                final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
                                if (fri != null)  {
                                    final OnAudioFocusChangeListener listener =
                                            fri.mRequest.getOnAudioFocusChangeListener(); //获取OnAudioFocusChange监听器
                                    if (listener != null) {
                                        Log.d(TAG, "dispatching onAudioFocusChange("
                                                + msg.arg1 + ") to " + msg.obj);
                                        listener.onAudioFocusChange(msg.arg1); //调用监听器的onAudioFocusChange方法,通知监听App
                                    }
                                }
                            } break;
                            default:
                                Log.e(TAG, "Unknown event " + msg.what);
                        }
                    }
                };
            } else {
                mHandler = null;
            }
        }


        Handler getHandler() {
            return mHandler;
        }
    }
}

AudioManager setFocusRequestResult

当App调用AudioManager的requestAudioFocus方法申请音频焦点时,会通过AudioPolicy.AudioPolicyFocusListener的方式调用到CarZonesAudioFocus的onAudioFocusRequest方法,经过CarZonesAudioFocus对音频焦点进行仲裁后后,再通过CarAudioFocus的setFocusRequestResult通知AudioManager,这时AudioManager的requestAudioFocus方法才会返回处理结果,接下来我们分析AudioManager的setFocusRequestResult方法:

//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
    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(); //取得IAudioService对象
        try {
            service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb()); //调用IAudioService的setFocusRequestResultFromExtPolicy方法
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}

调用IAudioService的setFocusRequestResultFromExtPolicy方法,IAudioService是一个接口,由AudioService实现,因此会调用AudioService的setFocusRequestResultFromExtPolicy方法:

//frameworks/base/service/java/com/android/server/audio/AudioService.java
public class AudioService extends IAudioService.Stub
    private final MediaFocusControl mMediaFocusControl;
    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); //调用MediaFocusControl的setFocusRequestResultFromExtPolicy方法
        }
    }
}

调用MediaFocusControl的setFocusRequestResultFromExtPolicy方法:

//frameworks/base/service/java/com/android/server/audio/MediaFocusControl.java
public class MediaFocusControl implements PlayerFocusEnforcer {
    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()); //获取FocusRequester对象
        } else {
            fr = mFocusOwnersForFocusPolicy.get(afi.getClientId()); //获取FocusRequester对象
        }
        if (fr != null) {
            fr.dispatchFocusResultFromExtPolicy(requestResult); //调用FocusRequester的dispatchFocusResultFromExtPolicy方法
        }
    }
}

调用FocusRequester的dispatchFocusResultFromExtPolicy方法:

//frameworks/base/service/java/com/android/server/audio/FocusRequester.java
public class FocusRequester {
    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); //调用IAudioFocusDispatcher的dispatchFocusResultFromExtPolicy方法
        } catch (android.os.RemoteException e) {
            Log.e(TAG, "dispatchFocusResultFromExtPolicy: error talking to focus listener"
                    + mClientId, e);
        }
    }
}

调用IAudioFocusDispatcher的dispatchFocusResultFromExtPolicy方法,IAudioFocusDispatcher是一个接口,由AudioManager实现:

//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
    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); //调用BlockingFocusResultReceiver的notifyResult方法
                } else {
                    Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
                }
            }
        }
    };
}

调用BlockingFocusResultReceiver的notifyResult方法,BlockingFocusResultReceiver是AudioManager的内部类:

//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
    private static final class BlockingFocusResultReceiver {
        private final SafeWaitObject mLock = new SafeWaitObject();
        @GuardedBy("mLock")
        private boolean mResultReceived = false;
        // request denied by default (e.g. timeout)
        private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        private final String mFocusClientId;
  
        void notifyResult(int requestResult) {
            synchronized (mLock) {
                mResultReceived = true;
                mFocusRequestResult = requestResult;
                mLock.safeNotify(); //调用SafeWaitObject 的safeNotify方法,通知锁
            }
        }
    }
}

在AudioManager的requestAudioFocus方法中调用focusReceiver的waitForResult方法等待上面的Notify:

//frameworks/base/media/java/android/media/AudioManager.java
public class AudioManager {
    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 */,
                        getContext().getAttributionTag(),
                        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(); //返回焦点申请结果
    }
}

BlockingFocusResultReceiver的waitForResult方法如下:

public class AudioManager {
    private static final class BlockingFocusResultReceiver {
        private final SafeWaitObject mLock = new SafeWaitObject();
        @GuardedBy("mLock")
        private boolean mResultReceived = false;
        // request denied by default (e.g. timeout)
        private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
        private final String mFocusClientId;


        public void waitForResult(long timeOutMs) {
            synchronized (mLock) {
                if (mResultReceived) {
                    // the result was received before waiting
                    return;
                }
                try {
                    mLock.safeWait(timeOutMs); //调用SafeWaitObject的safeWait,等待锁
                } catch (InterruptedException e) { }
            }
        }
    }
}

notifyFocusCallback

我们再分析notifyFocusCallback的处理:

//packages/services/Car/service/src/com/android/car/audio/CarZonesAudioFocus.java
final class CarZonesAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
    private final CarFocusCallback mCarFocusCallback;
    private void notifyFocusCallback(int[] zoneIds) {
        if (mCarFocusCallback == null) {
            return;
        }
        SparseArray<List<AudioFocusInfo>> focusHoldersByZoneId = new SparseArray<>(); //创建AudioFocusInfo队列focusHoldersByZoneId 
        for (int i = 0; i < zoneIds.length; i++) {
            int zoneId = zoneIds[i];
            List<AudioFocusInfo> focusHolders = mFocusZones.get(zoneId).getAudioFocusHolders(); //获取AudioFocusInfo队列
            focusHoldersByZoneId.put(zoneId, focusHolders); //将focusHolders加入到focusHoldersByZoneId 
        }


        mCarFocusCallback.onFocusChange(zoneIds, focusHoldersByZoneId); //调用回调接口的onFocusChange方法
    }
}

CarDucking onFocusChange

调用CarFocusCallback的onFocusChange方法,CarFocusCallback是一个接口,由CarDucking实现,因此调用CarDucking的onFocusChange方法:

//packages/services/Car/service/src/com/android/car/audio/CarZonesAudioFocus.java
final class CarZonesAudioFocus extends AudioPolicy.AudioPolicyFocusListener {
    private final CarFocusCallback mCarFocusCallback;
    private void notifyFocusCallback(int[] zoneIds) {
        if (mCarFocusCallback == null) {
            return;
        }
        SparseArray<List<AudioFocusInfo>> focusHoldersByZoneId = new SparseArray<>();
        for (int i = 0; i < zoneIds.length; i++) {
            int zoneId = zoneIds[i];
            List<AudioFocusInfo> focusHolders = mFocusZones.get(zoneId).getAudioFocusHolders();
            focusHoldersByZoneId.put(zoneId, focusHolders);
        }


        mCarFocusCallback.onFocusChange(zoneIds, focusHoldersByZoneId); //调用回调接口的onFocusChange方法
    }
}

在notifyFocusCallback方法中会调用CarFocusCallback的onFocusChange方法,CarFocusCallback是一个接口,由CarDucking实现,因此会调用CarDucking的onFocusChange方法:

//packages/services/Car/service/src/com/android/car/audio/CarDucking.java
final class CarDucking implements CarFocusCallback {
    private final AudioControlWrapper mAudioControlWrapper;
    @Override
    public void onFocusChange(int[] audioZoneIds,
            @NonNull SparseArray<List<AudioFocusInfo>> focusHoldersByZoneId) {
        synchronized (mLock) {
     
       List<CarDuckingInfo> newDuckingInfos = new ArrayList<>(audioZoneIds.length); //创建CarDuckingInfo队列
            for (int i = 0; i < audioZoneIds.length; i++) {
                int zoneId = audioZoneIds[i];
                List<AudioFocusInfo> focusHolders = focusHoldersByZoneId.get(zoneId); //循环获取每个audioZoneIds的AudioFocusInfo
                CarDuckingInfo newDuckingInfo = updateDuckingForZoneIdLocked(zoneId, focusHolders); //更新DuckingInfo
                newDuckingInfos.add(newDuckingInfo); //将DuckingInfo添加到DuckingInfo队列
            }
            mAudioControlWrapper.onDevicesToDuckChange(newDuckingInfos); //调用AudioControlWrapper的onDevicesToDuckChange方法,通知audiocontrol HAL
        }
    }
}

以上方法中主要有两个处理:

调用updateDuckingForZoneIdLocked更新DuckingInfo

调用AudioControlWrapper的onDevicesToDuckChange方法

下面我们分别分析:

updateDuckingForZoneIdLocked

首先是updateDuckingForZoneIdLocked:

//packages/services/Car/service/src/com/android/car/audio/CarDucking.java
final class CarDucking implements CarFocusCallback {
    private final SparseArray<CarDuckingInfo> mCurrentDuckingInfo = new SparseArray<>();
    private CarDuckingInfo updateDuckingForZoneIdLocked(int zoneId,
            List<AudioFocusInfo> focusHolders) {
        CarDuckingInfo oldDuckingInfo = mCurrentDuckingInfo.get(zoneId); //获取oldDuckingInfo 
        CarDuckingInfo newDuckingInfo = generateNewDuckingInfoLocked(oldDuckingInfo,
                focusHolders); //通过oldDuckingInfo和focusHolders生成newDuckingInfo 
        mCurrentDuckingInfo.put(zoneId, newDuckingInfo); //将newDuckingInfo和zoneId放入CurrentDuckingInfo
        return newDuckingInfo;
    }
}

调用generateNewDuckingInfoLocked方法,通过oldDuckingInfo和focusHolders生成newDuckingInfo:

//packages/services/Car/service/src/com/android/car/audio/CarDucking.java
final class CarDucking implements CarFocusCallback {
    private CarDuckingInfo generateNewDuckingInfoLocked(CarDuckingInfo oldDuckingInfo,
            List<AudioFocusInfo> focusHolders) {
        int zoneId = oldDuckingInfo.mZoneId; //获取zoneId
        CarAudioZone zone = mCarAudioZones.get(zoneId); //获取CarAudioZone 


        int[] usagesHoldingFocus = CarDuckingUtils.getUsagesHoldingFocus(focusHolders); //获取usagesHoldingFocus 
        List<String> addressesToDuck = CarDuckingUtils.getAddressesToDuck(usagesHoldingFocus, zone); //获取addressesToDuck 
        List<String> addressesToUnduck = CarDuckingUtils.getAddressesToUnduck(addressesToDuck,
                oldDuckingInfo.mAddressesToDuck); //获取addressesToUnduck 


        return new CarDuckingInfo(zoneId, addressesToDuck, addressesToUnduck, usagesHoldingFocus); //返回CarDuckingInfo对象
    }
}

调用CarDuckingUtils的getUsagesHoldingFocus方法获取usagesHoldingFocus对象:

//packages/services/Car/service/src/com/android/car/audio/CarDuckingUtils.java
final class CarDuckingUtils {
    static int[] getUsagesHoldingFocus(List<AudioFocusInfo> focusHolders) {
        Set<Integer> uniqueUsages = new HashSet<>();
        for (AudioFocusInfo focusInfo : focusHolders) {
            uniqueUsages.add(focusInfo.getAttributes().getSystemUsage());
        }


        int index = 0;
        int[] usagesHoldingFocus = new int[uniqueUsages.size()];
        for (int usage : uniqueUsages) {
            usagesHoldingFocus[index] = usage;
            index++;
        }
        return usagesHoldingFocus;
    }
}

调用CarDuckingUtils的getAddressesToDuck方法,获取addressesToDuck对象:

//packages/services/Car/service/src/com/android/car/audio/CarDuckingUtils.java
final class CarDuckingUtils {
    static List<String> getAddressesToDuck(int[] usages, CarAudioZone zone) {
        Set<Integer> uniqueContexts = CarAudioContext.getUniqueContextsForUsages(usages);
        uniqueContexts.remove(INVALID);
        Set<Integer> contextsToDuck = getContextsToDuck(uniqueContexts);
        Set<String> addressesToDuck = getAddressesForContexts(contextsToDuck, zone);


        Set<Integer> unduckedContexts = getUnduckedContexts(uniqueContexts, contextsToDuck);
        Set<String> unduckedAddresses = getAddressesForContexts(unduckedContexts, zone);


        // We should not duck any device that's associated with an unducked context holding focus.
        addressesToDuck.removeAll(unduckedAddresses);
        return new ArrayList<>(addressesToDuck);
    }
}

调用CarDuckingUtils的getAddressesToUnduck,获取addressesToUnduck对象:

//packages/services/Car/service/src/com/android/car/audio/CarDuckingUtils.java
final class CarDuckingUtils {
    static List<String> getAddressesToUnduck(List<String> addressesToDuck,
            List<String> oldAddressesToDuck) {
        List<String> addressesToUnduck = new ArrayList<>(oldAddressesToDuck);
        addressesToUnduck.removeAll(addressesToDuck);
        return addressesToUnduck;
    }
}

创建CarDuckingInfo对象,CarDuckingInfo的构造函数如下:

//packages/services/Car/service/src/com/android/car/audio/CarDuckingInfo.java
public final class CarDuckingInfo {
    public CarDuckingInfo(int zoneId, @NonNull List<String> addressesToDuck,
            @NonNull List<String> addressesToUnduck, @NonNull int[] usagesHoldingFocus) {
        mZoneId = zoneId;
        mAddressesToDuck = Objects.requireNonNull(addressesToDuck);
        mAddressesToUnduck = Objects.requireNonNull(addressesToUnduck);
        mUsagesHoldingFocus = Objects.requireNonNull(usagesHoldingFocus);
    }
}

AudioControlWrapper.onDevicesToDuckChange

我们分析onDevicesToDuckChange方法,调用AudioControlWrapper的onDevicesToDuckChange方法,AudioControlWrapper是一个接口,由AudioControlWrapperAidl实现,因此会调用AudioControlWrapperAidl的onDevicesToDuckChange方法:

//packages/services/Car/service/src/com/android/car/audio/hal/AudioControlWrapperAidl.java
public final class AudioControlWrapperAidl implements AudioControlWrapper {
    private IAudioControl mAudioControl;
    @Override
    public void onDevicesToDuckChange(@NonNull List<CarDuckingInfo> carDuckingInfos) {
        Objects.requireNonNull(carDuckingInfos);
        DuckingInfo[] duckingInfos = new DuckingInfo[carDuckingInfos.size()]; //创建DuckingInfo对象
        for (int i = 0; i < carDuckingInfos.size(); i++) {
            CarDuckingInfo info = Objects.requireNonNull(carDuckingInfos.get(i));  调用carDuckingInfos的get方法获取CarDuckingInfo
            duckingInfos[i] = info.generateDuckingInfo();
        }


        try {
            mAudioControl.onDevicesToDuckChange(duckingInfos); //调用IAudioControl的onDevicesToDuckChange方法
        } catch (RemoteException e) {
            Slogf.e(TAG, "onDevicesToDuckChange failed", e);
        }
    }
}

调用IAudioControl的onDevicesToDuckChange方法,IAudioControl是一个Aidl接口,由AudioControl实现,因此会调用AudioControl的onDevicesToDuckChange方法:

ndk::ScopedAStatus AudioControl::onDevicesToDuckChange(
        const std::vector<DuckingInfo>& in_duckingInfos) {
    LOG(INFO) << "AudioControl::onDevicesToDuckChange";
    for (const DuckingInfo& duckingInfo : in_duckingInfos) {
        LOG(INFO) << "zone: " << duckingInfo.zoneId;
        LOG(INFO) << "Devices to duck:";
        for (const auto& addressToDuck : duckingInfo.deviceAddressesToDuck) {
            LOG(INFO) << addressToDuck;
        }
        LOG(INFO) << "Devices to unduck:";
        for (const auto& addressToUnduck : duckingInfo.deviceAddressesToUnduck) {
            LOG(INFO) << addressToUnduck;
        }
        LOG(INFO) << "Usages holding focus:";
        for (const auto& usage : duckingInfo.usagesHoldingFocus) {
            LOG(INFO) << usage;
        }
    }
    return ndk::ScopedAStatus::ok();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值