Android Audio系列 AudioPatch的bug


最近发现一个奇怪的bug,注册OnAudioPortUpdateListener后,却没有收到onAudioPatchListUpdate callback

debug后发现android在这一块有个bug


可以看下OnAudioPortUpdateListener的注册过程

AudioManager.java:

    public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
        sAudioPortEventHandler.init();
        sAudioPortEventHandler.registerListener(l);
    }


sAudioPortEventHandler是一个event handle,它接受来自native层的event,并调用OnAudioPortUpdateListener中的call,在它的Init函数中和native层联系起来


    void init() {
        synchronized (this) {
            if (mHandler != null) {
                return;
            }
            // find the looper for our new event handler
            Looper looper = Looper.getMainLooper();

            if (looper != null) {
                mHandler = new Handler(looper) {

                };
                native_setup(new WeakReference<AudioPortEventHandler>(this));
            } else {
                mHandler = null;
            }
        }
    }

native_setup会通过jni调到native层:

static void
android_media_AudioSystem_eventHandlerSetup(JNIEnv *env, jobject thiz, jobject weak_this)
{
    ALOGV("eventHandlerSetup");

    sp<JNIAudioPortCallback> callback = new JNIAudioPortCallback(env, thiz, weak_this);

    if (AudioSystem::addAudioPortCallback(callback) == NO_ERROR) {
        setJniCallback(env, thiz, callback);
    }
}

这里象调用了AudioSystem的addAudioPortCallback, JNIAudioPortCallback在收到natvie层的callback后,向java层的AudioPortEventHandler发送消息


status_t AudioSystem::addAudioPortCallback(const sp<AudioPortCallback>& callback)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    if (aps == 0) return PERMISSION_DENIED;

    Mutex::Autolock _l(gLockAPS);
    if (gAudioPolicyServiceClient == 0) {
        return NO_INIT;
    }
    int ret = gAudioPolicyServiceClient->addAudioPortCallback(callback);
    if (ret == 1) {
        aps->setAudioPortCallbacksEnabled(true);
    }
    return (ret < 0) ? INVALID_OPERATION : NO_ERROR;
}

每个AudioSystem都是AudioPolicyService的一个client,在get_audio_policy_service()里会生成两个全局的binder,一个BpBinder,用于AudioSystem向AudioPolicyService发生消息,一个BnBinder,用于AudioPolicyService向AudioSystem发生消息,BnBinder就是AudioPolicyServiceClient. 然后把callback加到AudioPolicyServiceClient中去.

int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
        const sp<AudioPortCallback>& callback)
{
    Mutex::Autolock _l(mLock);
    for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) {
        if (mAudioPortCallbacks[i] == callback) {
            return -1;
        }
    }
    mAudioPortCallbacks.add(callback);
    return mAudioPortCallbacks.size();
}


bug马上要出现了,接下来看看  get_audio_policy_service()

// establish binder interface to AudioPolicy service
const sp<IAudioPolicyService> AudioSystem::get_audio_policy_service()
{
    sp<IAudioPolicyService> ap;
    sp<AudioPolicyServiceClient> apc;
    {
        Mutex::Autolock _l(gLockAPS);
        if (gAudioPolicyService == 0) {
            sp<IServiceManager> sm = defaultServiceManager();
            sp<IBinder> binder;
            do {
                binder = sm->getService(String16("media.audio_policy"));
                if (binder != 0)
                    break;
                ALOGW("AudioPolicyService not published, waiting...");
                usleep(500000); // 0.5 s
            } while (true);
            if (gAudioPolicyServiceClient == NULL) {
                gAudioPolicyServiceClient = new AudioPolicyServiceClient();
            }
            binder->linkToDeath(gAudioPolicyServiceClient);
            gAudioPolicyService = interface_cast<IAudioPolicyService>(binder);
            LOG_ALWAYS_FATAL_IF(gAudioPolicyService == 0);
            apc = gAudioPolicyServiceClient;
        }
        ap = gAudioPolicyService;
    }
    if (apc != 0) {
        ap->registerClient(apc);
    }

    return ap;
}

按照前面的解释,很好理解,为当前进程生成全局的BpBInder( gAudioPolicyService) 和BnBinder(gAudioPolicyServiceClient), 然后调用gAudioPolicyService->registerClient


// A notification client is always registered by AudioSystem when the client process
// connects to AudioPolicyService.
void AudioPolicyService::registerClient(const sp<IAudioPolicyServiceClient>& client)
{

    Mutex::Autolock _l(mNotificationClientsLock);

    uid_t uid = IPCThreadState::self()->getCallingUid();
    if (mNotificationClients.indexOfKey(uid) < 0) {
        sp<NotificationClient> notificationClient = new NotificationClient(this,
                                                                           client,
                                                                           uid);
        ALOGV("registerClient() client %p, uid %d", client.get(), uid);

        mNotificationClients.add(uid, notificationClient);

        sp<IBinder> binder = IInterface::asBinder(client);
        binder->linkToDeath(notificationClient);
    }
}

问题就出在这里了,这里通过检查uid来查看client是否已经注册了,如果几个进程共享uid的话,这里的client就没有加mNotificationClients里去,也就不会收到callback,

可以看一下,这IAudioPolicyServiceClient目前只有三个callback,几乎也没有app使用,所以还没有什么问题.如果用进程号的话,应该能解决这个问题.

class IAudioPolicyServiceClient : public IInterface
{
public:
    DECLARE_META_INTERFACE(AudioPolicyServiceClient);

    // Notifies a change of audio port configuration.
    virtual void onAudioPortListUpdate() = 0;
    // Notifies a change of audio patch configuration.
    virtual void onAudioPatchListUpdate() = 0;
    // Notifies a change in the mixing state of a specific mix in a dynamic audio policy
    virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
};

至于callack的过程,就是一个相反的过程,event的源头都是AudioPolicyManager中的openOutput, closeOutput, startOutput, openInput, closeInput, startInput



下一遍打算详细介绍下audioPatch...



  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值