Android10.0CarAudioZone(六)

前言

我们之前分析了CarAudioZone的比较核心的一个Api,setZoneIdForUid,我们知道通过将uid与zoneId绑定到一起的方式,实现多音区的功能。即不同音区的AudioFocus管理互不影响,我们的媒体也可以想播放在哪个Zone中就播放在哪个zone中,只要我们配置好car_audio_configuration.xml,以及设置对应的setZoneIdForUid即可。上一篇分析了AudioFocus在CarAudioZone中如何实现不同音区管理的,那么今天我们继续分析下播放流又是如何控制的,即播放流的一个路由策略

正文

我们知道在我们对上层的应用调用setZoneIdForUid的时候,我们会调用到mAudioPolicy.setUidDeviceAffinity(uid, mCarAudioZones[zoneId].getAudioDeviceInfos()),关于这个调用的逻辑可查看下Android10.0CarAudioZone(五),这里也是先简单分析一下这几个参数都是做什么的,udi,是上层应用传入的应用的uid,我们知道zoneId也是上层应用传入的,这样我们就可以定位到我们要的CarAudioZone,再看下它的getAudioDeviceInfos

    List<AudioDeviceInfo> getAudioDeviceInfos() {
        final List<AudioDeviceInfo> devices = new ArrayList<>();
        for (CarVolumeGroup group : mVolumeGroups) {
            for (int busNumber : group.getBusNumbers()) {
                devices.add(group.getCarAudioDeviceInfoForBus(busNumber).getAudioDeviceInfo());
            }
        }
        return devices;
    }

其实拿的就是我们解析car_audio_configuration.xml中,每个zone里group下所有的device的集合,拿到这个devices后与uid一同传给了AudioPolicy的setUidDeviceAffinity

    public boolean setUidDeviceAffinity(int uid, @NonNull List<AudioDeviceInfo> devices) {
        if (devices == null) {
            throw new IllegalArgumentException("Illegal null list of audio devices");
        }
        synchronized (mLock) {
            if (mStatus != POLICY_STATUS_REGISTERED) {
                throw new IllegalStateException("Cannot use unregistered AudioPolicy");
            }
            final int[] deviceTypes = new int[devices.size()];
            final String[] deviceAdresses = new String[devices.size()];
            int i = 0;
            for (AudioDeviceInfo device : devices) {
                if (device == null) {
                    throw new IllegalArgumentException(
                            "Illegal null AudioDeviceInfo in setUidDeviceAffinity");
                }
                // 根据type的是 TYPE_BUS ,对应内部map映射拿到的device是
                // DEVICE_OUT_BUS
                deviceTypes[i] =
                        AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType());
                // addres即每个bus device的address
                deviceAdresses[i] = device.getAddress();
                i++;
            }
            final IAudioService service = getService();
            try {
            调用了AudioServe的setUidDeviceAffinity
                final int status = service.setUidDeviceAffinity(this.cb(),
                        uid, deviceTypes, deviceAdresses);
                return (status == AudioManager.SUCCESS);
            } catch (RemoteException e) {
                Log.e(TAG, "Dead object in setUidDeviceAffinity", e);
                return false;
            }
        }
    }

我们发现在AudioPolicy了一个封装,主要处理的是deviceTypes,和deviceAdresses,然后继续调用AudioService的setUidDeviceAffinity

    public int setUidDeviceAffinity(IAudioPolicyCallback pcb, int uid,
            @NonNull int[] deviceTypes, @NonNull String[] deviceAddresses) {
        if (DEBUG_AP) {
            Log.d(TAG, "setUidDeviceAffinity for " + pcb.asBinder() + " uid:" + uid);
        }
        synchronized (mAudioPolicies) {
         //因为之前已经注册过了 因此这个check 肯定是能拿到的即app不为null
            final AudioPolicyProxy app =
                    checkUpdateForPolicy(pcb, "Cannot change device affinity in audio policy");
            if (app == null) {
                return AudioManager.ERROR;
            }
            if (!app.hasMixRoutedToDevices(deviceTypes, deviceAddresses)) {
                return AudioManager.ERROR;
            }
            return app.setUidDeviceAffinities(uid, deviceTypes, deviceAddresses);
        }
    }

我们发现这里有个hasMixRoutedToDevices的检查

        boolean hasMixRoutedToDevices(@NonNull int[] deviceTypes,
                @NonNull String[] deviceAddresses) {
            for (int i = 0; i < deviceTypes.length; i++) {
                boolean hasDevice = false;
                //mMixes是最早构建时传入的,可参照Android10.0CarAudioZone(三)
                for (AudioMix mix : mMixes) {
                    // this will check both that the mix has ROUTE_FLAG_RENDER and the device
                    // is reached by this mix
                    if (mix.isRoutedToDevice(deviceTypes[i], deviceAddresses[i])) {
                        hasDevice = true;
                        break;
                    }
                }
                if (!hasDevice) {
                    return false;
                }
            }
            return true;
        }

这个继续判断mix.isRoutedToDevice(deviceTypes[i], deviceAddresses[i]),我们知道deviceType都是bus,那么就在继续看下AudioMix的这个函数

    public boolean isRoutedToDevice(int deviceType, @NonNull String deviceAddress) {
       // 这里的mRouteFlags 就是 ROUTE_FLAG_RENDER
        if ((mRouteFlags & ROUTE_FLAG_RENDER) != ROUTE_FLAG_RENDER) {
            return false;
        }
        // 这里的deviceType与mDeviceSystemType一样都是DEVICE_OUT_BUS,
        // mDeviceSystemType 与deviceType的获取方式一样。
        // mDeviceSystemType = AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType());
        if (deviceType != mDeviceSystemType) {
            return false;
        }
        // deviceAddress与mDeviceAddress也是相等的
        if (!deviceAddress.equals(mDeviceAddress)) {
            return false;
        }
        return true;
    }

从这个isRoutedToDevice的判断看返回ture,那么hasMixRoutedToDevices反回也是ture,回到AudioService中,继续调用AudioPolicyProxy的setUidDeviceAffinities

        int setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
            final Integer Uid = new Integer(uid);
            int res;
            // 第一次调用,这个mUidDeviceAffinities为空,如果已经调用过了则先remove
            if (mUidDeviceAffinities.remove(Uid) != null) {
                final long identity = Binder.clearCallingIdentity();
                // 通过AudioSystem调用到native层中
                res = AudioSystem.removeUidDeviceAffinities(uid);
                Binder.restoreCallingIdentity(identity);
                if (res != AudioSystem.SUCCESS) {
                    Log.e(TAG, "AudioSystem. removeUidDeviceAffinities(" + uid + ") failed, "
                            + " cannot call AudioSystem.setUidDeviceAffinities");
                    return AudioManager.ERROR;
                }
            }
            // 因为要通过binder向下调用。因此先清掉id状态,这个id维护的是应用通过audiopolicy调用过来的uid和pid,并不是当前的uid和pid
            // 因此 这里要先clearCallingIdentity
            final long identity = Binder.clearCallingIdentity();
            res = AudioSystem.setUidDeviceAffinities(uid, types, addresses);
            // 对应调用结束,恢复之前的id
            Binder.restoreCallingIdentity(identity);
            if (res == AudioSystem.SUCCESS) {
               //将uid 以及对应的types和addresses存起来
                mUidDeviceAffinities.put(Uid, new AudioDeviceArray(types, addresses));
                return AudioManager.SUCCESS;
            }
            Log.e(TAG, "AudioSystem. setUidDeviceAffinities(" + uid + ") failed");
            return AudioManager.ERROR;
        }

这里我们看到通过AudioSystem继续向下调用了,jni的部分略过,直接看AudioSystem中的setUidDeviceAffinities

status_t AudioSystem::setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    if (aps == 0) return PERMISSION_DENIED;
    return aps->setUidDeviceAffinities(uid, devices);
}

调用到了AudioPolicyService

status_t AudioPolicyService::setUidDeviceAffinities(uid_t uid,
        const Vector<AudioDeviceTypeAddr>& devices) {
    Mutex::Autolock _l(mLock);
    if(!modifyAudioRoutingAllowed()) {
        return PERMISSION_DENIED;
    }
    if (mAudioPolicyManager == NULL) {
        return NO_INIT;
    }
    AutoCallerClear acc;
    return mAudioPolicyManager->setUidDeviceAffinities(uid, devices);
}

在AudioPolicyService中继续调用到AudioPolicyManager

status_t AudioPolicyManager::setUidDeviceAffinities(uid_t uid,
        const Vector<AudioDeviceTypeAddr>& devices) {
    ALOGV("%s() uid=%d num devices %zu", __FUNCTION__, uid, devices.size());
    // uid/device affinity is only for output devices
    for (size_t i = 0; i < devices.size(); i++) {
    	// 因为我们配置的device都是out_bus,也就都是output device
        if (!audio_is_output_device(devices[i].mType)) {
            ALOGE("setUidDeviceAffinities() device=%08x is NOT an output device",
                    devices[i].mType);
            return BAD_VALUE;
        }
    }
    status_t res =  mPolicyMixes.setUidDeviceAffinities(uid, devices);
    if (res == NO_ERROR) {
        // reevaluate outputs for all given devices
        for (size_t i = 0; i < devices.size(); i++) {
            sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
                            devices[i].mType, devices[i].mAddress, String8(),
                            AUDIO_FORMAT_DEFAULT);
            SortedVector<audio_io_handle_t> outputs;
            if (checkOutputsForDevice(devDesc, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                    outputs) != NO_ERROR) {
                ALOGE("setUidDeviceAffinities() error in checkOutputsForDevice for device=%08x"
                        " addr=%s", devices[i].mType, devices[i].mAddress.string());
                return INVALID_OPERATION;
            }
        }
    }
    return res;
}

在AudioPolicyManager中继续调用到mPolicyMixes.setUidDeviceAffinities(uid, devices),我们看下

status_t AudioPolicyMixCollection::setUidDeviceAffinities(uid_t uid,
        const Vector<AudioDeviceTypeAddr>& devices) {
    // verify feasibility: for each player mix: if it already contains a
    //    "match uid" rule for this uid, return an error
    //    (adding a uid-device affinity would result in contradictory rules)
    for (size_t i = 0; i < size(); i++) {
        const AudioPolicyMix* mix = itemAt(i).get();
        //这里判断的mMixType is MIX_TYPE_PLAYERS 以及mRouteFlags == MIX_ROUTE_FLAG_RENDER,都是true
        if (!mix->isDeviceAffinityCompatible()) {
            continue;
        }
        // 这个函数匹配的是match_rule,我们构建的时候设置的match_rule是attribute_usage,因此这个函数返回false
        if (mix->hasUidRule(true /*match*/, uid)) {
            return INVALID_OPERATION;
        }
    }

    // remove existing rules for this uid
    //移除已经有的uid
    removeUidDeviceAffinities(uid);

    // for each player mix:
    //   IF    device is not a target for the mix,
    //     AND it doesn't have a "match uid" rule
    //   THEN add a rule to exclude the uid
    //开始遍历AudioPolicyMix
    for (size_t i = 0; i < size(); i++) {
        const AudioPolicyMix *mix = itemAt(i).get();
        if (!mix->isDeviceAffinityCompatible()) {
            continue;
        }
        // check if this mix goes to a device in the list of devices
        bool deviceMatch = false;
        //找到AudioPolicyMix中的device与我们传下来的device匹配他们的type,传下来的mtype都是AUDIO_DEVICE_OUT_BUS,而mDeviceType是 AUDIO_DEVICE_OUT_BUS
        for (size_t j = 0; j < devices.size(); j++) {
            if (devices[j].mType == mix->mDeviceType
                    && devices[j].mAddress == mix->mDeviceAddress) {
                deviceMatch = true;
                break;
            }
        }
        // deviceMatch 匹配不到的时候并且mix->hasMatchUidRule()也是false的时候我们要set exclued的uid
        if (!deviceMatch && !mix->hasMatchUidRule()) {
            // this mix doesn't go to one of the listed devices for the given uid,
            // and it's not already restricting the mix on a uid,
            // modify its rules to exclude the uid
            // 这个if刚说过不说了 也满足
            if (!mix->hasUidRule(false /*match*/, uid)) {
                // no need to do it again if uid is already excluded
                // 将mix的match_rule添加一个为RULE_EXCLUDE_UID的
                mix->setExcludeUid(uid);
            }
        }
    }

    return NO_ERROR;
}

最终的mix->setExcludeUid(uid),改变了add了一个crit,我们简单看下这个源码

void AudioMix::setExcludeUid(uid_t uid) const {
    AudioMixMatchCriterion crit;
    crit.mRule = RULE_EXCLUDE_UID;
    crit.mValue.mUid = uid;
    mCriteria.add(crit);
}

这样把uid与audiomix就关联到一起了,这个逻辑就像这个单词Exclude,这是一个排除的关联,如果我们把uid关联到zone1中,那么zone2的audiomix会执行setExcludeUid。不是把uid和它对应音区的AudioMIx关联到一起,而是把uid与其对应因音区外的AudioMix关联上,此这块逻辑还需要细细体会理解。
到此AudioMix的部分也就结束了。

总结

我们上层应用在setZoneIdForUid的时候,会调用到setUidDeviceAffinity,进而最终调用到AudioPolicy下的AudioPolicyMix中,最后把uid与AudioMix绑定到一起,实现路由功能。
到此CarAudio关于源码的逻辑就到这里了,可能有些地方说的不是很清楚,接下来会从一个demo在重新梳理下这部分逻辑。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
### 回答1: android 10.0系统应用默认授权是指在android 10.0系统中,部分应用在安装后默认会被授予一些权限,而不需要用户在应用启动后再去手动开启这些权限,这样可以提高用户的使用体验。 android 10.0系统应用默认授权的目的是为了加强应用的安全性,提高用户的隐私保护。应用需要访问某些敏感数据或功能时,用户在使用前需要手动开启权限,这样可以减少恶意应用通过获取用户授权的方式获取用户的私人信息。 在android 10.0系统中,应用默认被授权的权限包括日历、相机、联系人、位置、麦克风、电话、短信、存储空间等。这些权限是应用正常运行所必需的,用户可以在应用管理器中查看和管理应用授权的权限。 尽管android 10.0系统应用默认授权提高了用户的使用体验,但也存在一些风险。如果用户使用的是恶意应用,这些应用也可以默认获取一些敏感权限,从而获取用户的私人信息。因此,用户需要保持对应用的警惕,并仔细审核应用的权限请求。 ### 回答2: 在Android 10.0系统中,应用默认授权是一种新的权限模型。它改变了以往Android系统中权限管理的方式,使用户对应用程序的权限管理更加方便和安全。 传统的权限管理模型通常是一次性处理权限请求,无法区分应用程序对某一项权限的使用情况。这种方式缺少细节和灵活性,可能导致应用程序通过某些权限去访问用户的隐私信息。而Android 10.0系统应用默认授权则可以保护用户的隐私信息和数据安全。 应用默认授权模型允许应用程序在不请求用户手动授权的情况下,自动获得某些权限,并在必要的时候再向用户请求授权。这种方式可以减少用户被安装并包含恶意代码的应用程序所利用的风险。 具体地说,当应用程序请求任何运行时权限时,Android 10.0系统将无法立即授予权限。相反,它将显示一个对话框,询问用户是否要授予权限。只有在用户同意授予权限时,应用程序才能获得此权限。 此外,应用默认授权模型还能够自动限制应用程序对某些权限的访问,比如位置信息和网络数据,除非用户主动授予权限或应用程序已经获得了相应的批准。 总之,Android 10.0系统的应用默认授权能够保护用户隐私,增加应用程序的灵活性,并减少用户遭受来自恶意应用程序的风险。 ### 回答3: Android 10.0系统的应用默认授权,是指所有应用程序在安装时系统会默认授予其部分权限,而不是像以前版本的系统一样需要用户在应用使用时手动授权。 Android 10.0系统应用默认授权的目的,是为了提高应用程序的用户便利性和操作流畅性,同时还可以降低用户在使用应用程序时需要授权的次数。但是这也有可能导致一些应用程序获取用户隐私的风险。 在Android 10.0系统中,应用程序默认被授权的权限包括:网络访问、用户日历、联系人和传感器等。对于其他一些权限,如摄像头、麦克风、存储空间和定位等信息,用户在应用程序使用时需要手动授权才能访问。 因此,用户在使用Android 10.0系统时需要非常谨慎地选择哪些应用程序可以获得自己的隐私权限。建议用户在安装应用程序前,仔细检查其权限请求,尽可能减少不必要的隐私授权操作。 同时,为了更好地保护用户的隐私,Android 10.0系统也提供了更加严格的权限管理功能。用户可以通过设置菜单中的 “应用程序和通知”-“应用程序权限” 来查看和修改应用程序的权限,在此基础上更好地控制应用程序的使用和权限访问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

轻量级LZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值