Android10.0CarAudioZone(四)

前言

上几篇讲了CarAudioZone相关的volume、audiofocus以及device,我们也知道在CarAudioService的初始化过程中,最后通过mAudioManager.registerAudioPolicy(mAudioPolicy)将AudioPolicy注册下去的,那么今天我们继续分析AudioPolicy的register过程。

正文

首先看下AudioManager的registerAudioPolicy

    public int registerAudioPolicy(@NonNull AudioPolicy policy) {
        return registerAudioPolicyStatic(policy);
    }

继续看

    static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
        if (policy == null) {
            throw new IllegalArgumentException("Illegal null AudioPolicy argument");
        }
        final IAudioService service = getService();
        try {
        // projection 是null
            MediaProjection projection = policy.getMediaProjection();

            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;
    

最终调到了AudioService的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)) {
            Slog.w(TAG, "Permission denied to register audio policy for pid "
                    + Binder.getCallingPid() + " / uid " + Binder.getCallingUid()
                    + ", need MODIFY_AUDIO_ROUTING or MediaProjection that can project audio");
            return null;
        }

        mDynPolicyLogger.log((new AudioEventLogger.StringEvent("registerAudioPolicy for "
                + pcb.asBinder() + " with config:" + policyConfig)).printLog(TAG));

        String regId = null;
        synchronized (mAudioPolicies) {
            // 由于pcb是audiopolicy自己创建的,这里姑且认为如果已经有了pcb.asBinder()就
            //等于已经 register过audiopolicy了
            if (mAudioPolicies.containsKey(pcb.asBinder())) {
                Slog.e(TAG, "Cannot re-register policy");
                return null;
            }
            try {
                //创建audiopolicy的proxy
                AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener,
                        isFocusPolicy, isTestFocusPolicy, isVolumeController, projection);
                pcb.asBinder().linkToDeath(app, 0/*flags*/);
                regId = app.getRegistrationId();
                // 最终把audiopolicy 放入map中维护起来
                mAudioPolicies.put(pcb.asBinder(), app);
            } catch (RemoteException e) {
                // audio policy owner has already died!
                Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
                        " binder death", e);
                return null;
            } catch (IllegalStateException e) {
                Slog.w(TAG, "Audio policy registration failed for binder " + pcb, e);
                return null;
            }
        }
        return regId;
    }

我们先看下这几个传入的参数,policyConfig是我们构建AudioPolicy的时候new的,pcb是AudioPolicy中初始化的,用于处理音频焦点的回调, 即 private final IAudioPolicyCallback mPolicyCb = new IAudioPolicyCallback.Stub(),hasFocusListener(即CarZonesAudioFocus)和isFocusPolicy都是true,isTestFocusPolicy是false,isVolumeController是ture(在CarAudioService中创建的 private final AudioPolicy.AudioPolicyVolumeCallback mAudioPolicyVolumeCallback), projection是null,首先执行了 AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback),通过jni最终

/*static*/ void AudioSystem::setDynPolicyCallback(dynamic_policy_callback cb)
{
    Mutex::Autolock _l(gLock);
    gDynPolicyCallback = cb;
}

调用到native的AudioSystem中。我们在看到这个参数记得是这里传下去的。继续看register的过程,下来是isPolicyRegisterAllowed的判断

   private boolean isPolicyRegisterAllowed(AudioPolicyConfig policyConfig,
                                            boolean hasFocusAccess,
                                            boolean isVolumeController,
                                            IMediaProjection projection) {

        boolean requireValidProjection = false;
        boolean requireCaptureAudioOrMediaOutputPerm = false;
        boolean requireModifyRouting = false;
		// hasFocusAccess 是true,isVolumeController也是true
        if (hasFocusAccess || isVolumeController) {
          // 这个if是进来的 
            requireModifyRouting |= true;
        } else if (policyConfig.getMixes().isEmpty()) {
            // An empty policy could be used to lock the focus or add mixes later
            requireModifyRouting |= true;
        }
        //这个getMixes就是我们之前我们构建AudioMix的那个集合
        for (AudioMix mix : policyConfig.getMixes()) {
            // If mix is requesting a privileged capture
            //默认false
            if (mix.getRule().allowPrivilegedPlaybackCapture()) {
                // then it must have CAPTURE_MEDIA_OUTPUT or CAPTURE_AUDIO_OUTPUT permission
                requireCaptureAudioOrMediaOutputPerm |= true;
                // and its format must be low quality enough
                String error = mix.canBeUsedForPrivilegedCapture(mix.getFormat());
                if (error != null) {
                    Log.e(TAG, error);
                    return false;
                }
            }

            // If mix is RENDER|LOOPBACK, then an audio MediaProjection is enough
            // otherwise MODIFY_AUDIO_ROUTING permission is required
            // flag是ture,但projection is null
            if (mix.getRouteFlags() == mix.ROUTE_FLAG_LOOP_BACK_RENDER && projection != null) {
                requireValidProjection |= true;
            } else {
                requireModifyRouting |= true;
            }
        }
		// 这个也走不进来
        if (requireCaptureAudioOrMediaOutputPerm
                && !callerHasPermission(android.Manifest.permission.CAPTURE_MEDIA_OUTPUT)
                && !callerHasPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)) {
            Log.e(TAG, "Privileged audio capture requires CAPTURE_MEDIA_OUTPUT or "
                      + "CAPTURE_AUDIO_OUTPUT system permission");
            return false;
        }
		// 这个也走不进来
        if (requireValidProjection && !canProjectAudio(projection)) {
            return false;
        }
		//这个callerHasPermission是true,即有权限,因此也走不进来
        if (requireModifyRouting
                && !callerHasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)) {
            Log.e(TAG, "Can not capture audio without MODIFY_AUDIO_ROUTING");
            return false;
        }
		//最终return
        return true;
    }

代码很长,但里面的if基本都是不满足的,最终return true,继续往下看就是new AudioPolicyProxy了。我们看下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;
            //mHasFocusListener是true
            if (mHasFocusListener) {
                mMediaFocusControl.addFocusFollower(mPolicyCallback);
                // can only ever be true if there is a focus listener
                if (isFocusPolicy) {
                    mIsFocusPolicy = true;
                    mIsTestFocusPolicy = isTestFocusPolicy;
                    mMediaFocusControl.setFocusPolicy(mPolicyCallback, mIsTestFocusPolicy);
                }
            }
            if (mIsVolumeController) {
                setExtVolumeController(mPolicyCallback);
            }
            //mProjection 是null
            if (mProjection != null) {
                mProjectionCallback = new UnregisterOnStopCallback();
                try {
                    mProjection.registerCallback(mProjectionCallback);
                } catch (RemoteException e) {
                    release();
                    throw new IllegalStateException("MediaProjection callback registration failed, "
                            + "could not link to " + projection + " binder death", e);
                }
            }
            //向下注册audiopolicy
            int status = connectMixes();
            if (status != AudioSystem.SUCCESS) {
                release();
                throw new IllegalStateException("Could not connect mix, error: " + status);
            }
        }

他是AudioService的一个内部类继承自AudioPolicyConfig。这部分很重要,我们拆分一点一点来看, 首先setRegistration(new String(config.hashCode() + “:ap:” + mAudioPolicyCounter++))

    protected void setRegistration(String regId) {
    // currentRegNull 是ture
        final boolean currentRegNull = (mRegistrationId == null) || mRegistrationId.isEmpty();
        // 我们传入的regId 不为null,因此newRegNull是true
        final boolean newRegNull = (regId == null) || regId.isEmpty();
        if (!currentRegNull && !newRegNull && !mRegistrationId.equals(regId)) {
            Log.e(TAG, "Invalid registration transition from " + mRegistrationId + " to " + regId);
            return;
        }
        //mRegistrationId 即我们传入的regId
        mRegistrationId = regId == null ? "" : regId;
        for (AudioMix mix : mMixes) {
            setMixRegistration(mix);
        }
    }

这个是父类AudioPolicyConfig中的方法,通过源码了解设置了一个mRegistrationId 后遍历AudioMix执行setMixRegistration,我们继续看看下setMixRegistration(mix)

    private void setMixRegistration(@NonNull final AudioMix mix) {
    //mRegistrationId不为null
        if (!mRegistrationId.isEmpty()) {
            if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) ==
                    AudioMix.ROUTE_FLAG_LOOP_BACK) {
                mix.setRegistration(mRegistrationId + "mix" + mixTypeId(mix.getMixType()) + ":"
                        + mMixCounter);
            //我们在CarAudioDynamicRouting中构建AudioMix的时候传入的flag是ROUTE_FLAG_RENDER
            //可参照Android10.0CarAudioZone(三)
            } else if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_RENDER) ==
                    AudioMix.ROUTE_FLAG_RENDER) {
                    //对audiomix进行setRegistration设置
                mix.setRegistration(mix.mDeviceAddress);
            }
        } else {
            mix.setRegistration("");
        }
        mMixCounter++;
    }

通过代码了解这里又调到了 mix.setRegistration(mix.mDeviceAddress),我们在看下AudioMIx中的逻辑

    void setRegistration(String regId) {
        mDeviceAddress = regId;
    }

这个regId也就是我们传下来的mix.mDeviceAddress,是我我们构建AudioMix时setDevice传入的device的info的address,关于构建AudioMix的过程我们可以参照Android10.0CarAudioZone(三),好了回到AudioPolicyProxy中急需往下看,接下来是 mMediaFocusControl.addFocusFollower(mPolicyCallback),我们看下MediaFocusControl

    private ArrayList<IAudioPolicyCallback> mFocusFollowers = new ArrayList<IAudioPolicyCallback>();

    void addFocusFollower(IAudioPolicyCallback ff) {
        if (ff == null) {
            return;
        }
        synchronized(mAudioFocusLock) {
            boolean found = false;
            //遍历 如果已经add过的直接return,否则add到mFocusFollowers中
            for (IAudioPolicyCallback pcb : mFocusFollowers) {
                if (pcb.asBinder().equals(ff.asBinder())) {
                    found = true;
                    break;
                }
            }
            if (found) {
                return;
            } else {
                mFocusFollowers.add(ff);
                //刷新外部policy策略
                notifyExtPolicyCurrentFocusAsync(ff);
            }
        }
    }

这里有个很重要的逻辑notifyExtPolicyCurrentFocusAsync(ff)

    void notifyExtPolicyCurrentFocusAsync(IAudioPolicyCallback pcb) {
        final IAudioPolicyCallback pcb2 = pcb;
        final Thread thread = new Thread() {
            @Override
            public void run() {
                synchronized(mAudioFocusLock) {
                    if (mFocusStack.isEmpty()) {
                        return;
                    }
                    try {
                        pcb2.notifyAudioFocusGrant(mFocusStack.peek().toAudioFocusInfo(),
                                // top of focus stack always has focus
                                AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
                    } catch (RemoteException e) {
                        Log.e(TAG, "Can't call notifyAudioFocusGrant() on IAudioPolicyCallback "
                                + pcb2.asBinder(), e);
                    }
                }
            }
        };
        thread.start();
    }

如果当前栈里的AudioFocus不为null,也就是有人在我们registerAudioPolicy前requestAudioFocus了。那么我们要把这个AudioFocus拿出来给到外部的音频焦点策略去处理。这里是给到了CarZonesAudioFocus中去处理音频焦点的优先级,具体处理过程,等我们后面通过demo来说明,这里先不说了。接下来又调用了 mMediaFocusControl.setFocusPolicy(mPolicyCallback, mIsTestFocusPolicy)

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

这里赋值了mFocusPolicy 。通过这个我们也看出了一点AudioPolicy的setAudioPolicyFocusListener(mFocusHandler)和setIsAudioFocusPolicy(true),这俩方法是配套使用的。MediaFocusControl的部分就结束了,回到AudioService的new AudioPolicyProxy中继续,setExtVolumeController(mPolicyCallback)

    private void setExtVolumeController(IAudioPolicyCallback apc) {
    //config_handleVolumeKeysInWindowManager默认true,一般是/overlay/frameworks/base/core/res/res/values/config.xml中设置
        if (!mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_handleVolumeKeysInWindowManager)) {
            Log.e(TAG, "Cannot set external volume controller: device not set for volume keys" +
                    " handled in PhoneWindowManager");
            return;
        }
        synchronized (mExtVolumeControllerLock) {
            if (mExtVolumeController != null && !mExtVolumeController.asBinder().pingBinder()) {
                Log.e(TAG, "Cannot set external volume controller: existing controller");
            }
            mExtVolumeController = apc;
        }
    }

这部分主要是apc赋值给了mExtVolumeController,也就是把AudioPolicy中的mPolicyCb赋值给了mExtVolumeController。回到new AudioPolicyProxy中最后一步connectMixes()

        int connectMixes() {
            final long identity = Binder.clearCallingIdentity();
            int status = AudioSystem.registerPolicyMixes(mMixes, true);
            Binder.restoreCallingIdentity(identity);
            return status;
        }

我们知道一般调到AudioSystem的基本都是要通过jni向下调用了,这里也一样,最终在AudioSystem的native中调到了AudioPolicyService的registerPolicyMixes

status_t AudioPolicyService::registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration)
{
    Mutex::Autolock _l(mLock);

    // loopback|render only need a MediaProjection (checked in caller AudioService.java)
    bool needModifyAudioRouting = std::any_of(mixes.begin(), mixes.end(), [](auto& mix) {
            return !is_mix_loopback_render(mix.mRouteFlags); });
    if (needModifyAudioRouting && !modifyAudioRoutingAllowed()) {
        return PERMISSION_DENIED;
    }

    bool needCaptureMediaOutput = std::any_of(mixes.begin(), mixes.end(), [](auto& mix) {
            return mix.mAllowPrivilegedPlaybackCapture; });
    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
    const pid_t callingPid = IPCThreadState::self()->getCallingPid();
    if (needCaptureMediaOutput && !captureMediaOutputAllowed(callingPid, callingUid)) {
        return PERMISSION_DENIED;
    }

    if (mAudioPolicyManager == NULL) {
        return NO_INIT;
    }
    AutoCallerClear acc;
    //这里传入的registration是true
    if (registration) {
        return mAudioPolicyManager->registerPolicyMixes(mixes);
    } else {
        return mAudioPolicyManager->unregisterPolicyMixes(mixes);
    }
}

这里继续调用到了AudioPolicyManager的registerPolicyMixes

status_t AudioPolicyManager::registerPolicyMixes(const Vector<AudioMix>& mixes)
{
    ALOGV("registerPolicyMixes() %zu mix(es)", mixes.size());
    status_t res = NO_ERROR;

    sp<HwModule> rSubmixModule;
    // examine each mix's route type
    for (size_t i = 0; i < mixes.size(); i++) {
        AudioMix mix = mixes[i];
        // Only capture of playback is allowed in LOOP_BACK & RENDER mode
        //RouteFlags是render那个以及mMixType 是 MIX_TYPE_PLAYERS因此这个if进不来
        if (is_mix_loopback_render(mix.mRouteFlags) && mix.mMixType != MIX_TYPE_PLAYERS) {
            ALOGE("Unsupported Policy Mix %zu of %zu: "
                  "Only capture of playback is allowed in LOOP_BACK & RENDER mode",
                   i, mixes.size());
            res = INVALID_OPERATION;
            break;
        }
        // LOOP_BACK and LOOP_BACK | RENDER have the same remote submix backend and are handled
        // in the same way.
        //这个if也进不来
        if ((mix.mRouteFlags & MIX_ROUTE_FLAG_LOOP_BACK) == MIX_ROUTE_FLAG_LOOP_BACK) {
            ALOGV("registerPolicyMixes() mix %zu of %zu is LOOP_BACK %d", i, mixes.size(),
                  mix.mRouteFlags);
            if (rSubmixModule == 0) {
                rSubmixModule = mHwModules.getModuleFromName(
                        AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX);
                if (rSubmixModule == 0) {
                    ALOGE("Unable to find audio module for submix, aborting mix %zu registration",
                            i);
                    res = INVALID_OPERATION;
                    break;
                }
            }

            String8 address = mix.mDeviceAddress;
            audio_devices_t deviceTypeToMakeAvailable;
           
            if (mix.mMixType == MIX_TYPE_PLAYERS) {
                mix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
                deviceTypeToMakeAvailable = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
            } else {
                mix.mDeviceType = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
                deviceTypeToMakeAvailable = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
            }
			//AudioPolicyMixCollection的registerMix
            if (mPolicyMixes.registerMix(mix, 0 /*output desc*/) != NO_ERROR) {
                ALOGE("Error registering mix %zu for address %s", i, address.string());
                res = INVALID_OPERATION;
                //register成功即break了,后面就不执行了
                break;
            }
            audio_config_t outputConfig = mix.mFormat;
            audio_config_t inputConfig = mix.mFormat;
            // NOTE: audio flinger mixer does not support mono output: configure remote submix HAL in
            // stereo and let audio flinger do the channel conversion if needed.
            outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
            inputConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
            rSubmixModule->addOutputProfile(address, &outputConfig,
                    AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address);
            rSubmixModule->addInputProfile(address, &inputConfig,
                    AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);

            if ((res = setDeviceConnectionStateInt(deviceTypeToMakeAvailable,
                    AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                    address.string(), "remote-submix", AUDIO_FORMAT_DEFAULT)) != NO_ERROR) {
                ALOGE("Failed to set remote submix device available, type %u, address %s",
                        mix.mDeviceType, address.string());
                break;
            }
            // //这个else if满足因为我们设置的flag就是MIX_ROUTE_FLAG_RENDER
        } else if ((mix.mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
            String8 address = mix.mDeviceAddress;
            audio_devices_t type = mix.mDeviceType;
            ALOGV(" registerPolicyMixes() mix %zu of %zu is RENDER, dev=0x%X addr=%s",
                    i, mixes.size(), type, address.string());
			//拿到DeviceDescriptor
            sp<DeviceDescriptor> device = mHwModules.getDeviceDescriptor(
                    mix.mDeviceType, mix.mDeviceAddress,
                    String8(), AUDIO_FORMAT_DEFAULT);
            if (device == nullptr) {
                res = INVALID_OPERATION;
                break;
            }

            bool foundOutput = false;
            for (size_t j = 0 ; j < mOutputs.size() ; j++) {
                sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(j);

                if (desc->supportedDevices().contains(device)) {
                
                    if (mPolicyMixes.registerMix(mix, desc) != NO_ERROR) {
                        ALOGE("Could not register mix RENDER,  dev=0x%X addr=%s", type,
                              address.string());
                        res = INVALID_OPERATION;
                    } else {
                        foundOutput = true;
                    }
                    break;
                }
            }

            if (res != NO_ERROR) {
                ALOGE(" Error registering mix %zu for device 0x%X addr %s",
                        i, type, address.string());
                res = INVALID_OPERATION;
                break;
            } else if (!foundOutput) {
                ALOGE(" Output not found for mix %zu for device 0x%X addr %s",
                        i, type, address.string());
                res = INVALID_OPERATION;
                break;
            }
        }
    }
    if (res != NO_ERROR) {
        unregisterPolicyMixes(mixes);
    }
    return res;
}

我们看到主要是registerMix(mix, desc),接下来再来AudioPolicyMix.cpp中看下

status_t AudioPolicyMixCollection::registerMix(AudioMix mix, sp<SwAudioOutputDescriptor> desc)
{
   // 第一次size是0
    for (size_t i = 0; i < size(); i++) {
        const sp<AudioPolicyMix>& registeredMix = itemAt(i);
        if (mix.mDeviceType == registeredMix->mDeviceType
                && mix.mDeviceAddress.compare(registeredMix->mDeviceAddress) == 0) {
            ALOGE("registerMix(): mix already registered for dev=0x%x addr=%s",
                    mix.mDeviceType, mix.mDeviceAddress.string());
            return BAD_VALUE;
        }
    }
    创建AudioPolicyMix并add到mPolicyMixes中
    sp<AudioPolicyMix> policyMix = new AudioPolicyMix(mix);
    add(policyMix);
    ALOGD("registerMix(): adding mix for dev=0x%x addr=%s",
            policyMix->mDeviceType, policyMix->mDeviceAddress.string());
	//desc 传入的不是0, 
    if (desc != 0) {
        desc->mPolicyMix = policyMix;
        policyMix->setOutput(desc);
    }
    return NO_ERROR;
}

到此注册就结束了,总结一下,registerAudioPolicy主要有这么几个作用
1.可以将按键调节音量的方法通过AudioPolicy拿到外面我们自定义的模块处理
2.可以将AudioFocus的优先级处理通过AudioPolicy拿到外面我们自定义的模块处理
3.将AuiioMix注册到AudioPolicyManager下,这样路由策略由原来的根据stream选device,然后根据device选output的方式变更为通过usage直接选output,这个更适合Car上的AUDIO_DEVICE_OUT_BUS

下一篇我们再说下关于uid在CarAudioZone中的作用
以上欢迎大家交流沟通~

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答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系统也提供了更加严格的权限管理功能。用户可以通过设置菜单中的 “应用程序和通知”-“应用程序权限” 来查看和修改应用程序的权限,在此基础上更好地控制应用程序的使用和权限访问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

轻量级LZ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值