android P的系统为了进一步提高用户的安全隐私,禁止了后台闲置应用使用麦克风。
所以当一个app进入后台后,变成闲置idle状态,是无法在使用麦克风录音的。
下面的分析是从系统framework层代码入手,libaudiopolicyservice.so文件源码,来了解后台闲置app无法使用麦克风的原理,并从系统的角度,屏蔽了后台app无法使用麦克风的限制。
代码路径:frameworks\av\services\audiopolicy\service\AudioPolicyService.cpp
禁止闲置app使用麦克风的逻辑是在AudioPolicyService中处理的。
安卓应用在后台一段时间后,就会被置为闲置状态(Idel),下面是几个监听应用激活,闲置状态的方法:
void AudioPolicyService::UidPolicy::onUidActive(uid_t uid) {
updateUidCache(uid, true, true);
}
void AudioPolicyService::UidPolicy::onUidGone(uid_t uid, __unused bool disabled) {
updateUidCache(uid, false, false);
}
void AudioPolicyService::UidPolicy::onUidIdle(uid_t uid, __unused bool disabled) {
updateUidCache(uid, false, true);
}
都执行了updateUidCache(),当闲置Idle状态时,传入的参数是false,true.我们在来看看updateUidCache。
void AudioPolicyService::UidPolicy::updateUidCache(uid_t uid, bool active, bool insert) {
if (isServiceUid(uid)) return;
bool wasActive = false;
{
Mutex::Autolock _l(mLock);
updateUidLocked(&mCachedUids, uid, active, insert, nullptr, &wasActive);
// Do not notify service if currently overridden.
if (mOverrideUids.find(uid) != mOverrideUids.end()) return;
}
bool nowActive = active && insert;
if (wasActive != nowActive) notifyService(uid, nowActive);
}
updateUidCache中调用了notifyService,并把nowActive的表示传给了notifyService,Idle状态传入的nowActive是false.
void AudioPolicyService::UidPolicy::notifyService(uid_t uid, bool active) {
sp<AudioPolicyService> service = mService.promote();
if (service != nullptr) {
service->setRecordSilenced(uid, !active);
}
}
关键的函数: service->setRecordSilenced(uid, !active);
setRecordSilenced函数就是将麦克风mute掉,导致应用无法在使用麦克风进行录音了。
修改notifyService为以下:
void AudioPolicyService::UidPolicy::notifyService(uid_t uid, bool active) {
sp<AudioPolicyService> service = mService.promote();
if (service != nullptr) {
//将active标志置为true,这样不管是闲置idle状态还是active状态,都可以使用麦克风录音
active = true;
service->setRecordSilenced(uid, !active);
}
}
但是这样安卓为了保护用户隐私的初衷就改变了。
上述的分析中得知,系统只对后台闲置服务进行闲置,不让后台服务偷偷使用麦克风。
那么我的应用程序中,把后台服务改成前台服务,就可以解决这个问题。
目前Android9.0的前台服务中,必须弹出一个通知,告知用户,某个前台服务正在运行。