当前位置: 首页 > news >正文

做网站和推广新闻发布系统

做网站和推广,新闻发布系统,app安装下载官网,有什么做树状图的网站摘要: 1.在Android9中为了防止App后台录音,实际上已经存在一个静音的接口用于禁止App录音,不过这个接口存在两个问题:1)仅在C层供系统调用,没有暴露给App调用;2)这个接口是根据uid静音的,很多时…

摘要:
1.在Android9中为了防止App后台录音,实际上已经存在一个静音的接口用于禁止App录音,不过这个接口存在两个问题:1)仅在C++层供系统调用,没有暴露给App调用;2)这个接口是根据uid静音的,很多时候App开发人员为了图省事都将自己的App设置为系统级别的App,如果根据uid静音,那么系统级别的uid都是1000,就会造成误伤,所以我们增加了根据包名静音的接口并暴露给上层调用
2.并发录音是项目中很常见的需求,其实Android9中已经包含并发录音的代码,只不过被屏蔽了,只要稍加修改就可以实现功能

一、根据包名静音接口的实现

1.Java层实现

我决定将接口设置在CarAudioService中(因为本人是搞车机的),其实CarAudioService里面的很多接口最终都会调用到AudioService里面,这个接口也不例外,闲话少说,上代码:
CarAudioManager.java:

    /*** setRecordSilenced according to uid** @hide*/@SystemApipublic int setRecordSilenced(String packageName, boolean silenced) throws CarNotConnectedException {try {return mService.setRecordSilenced(packageName, silenced);} catch (RemoteException e) {Log.e(CarLibLog.TAG_CAR, "setRecordSilenced failed", e);throw new CarNotConnectedException(e);}}

ICarAudio.aidl:

    int setRecordSilenced(String packageName, boolean silenced);

CarAudioService.java:

    @Overridepublic int setRecordSilenced(String packageName, boolean silenced) {return mAudioManager.setRecordSilenced(packageName, silenced);}

AudioManager.java:

    /*** setRecordSilenced according to packageName** @hide*/public int setRecordSilenced(String packageName, boolean silenced) {final IAudioService service = getService();try {return service.setRecordSilenced(packageName, silenced);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}

IAudioService.aidl:

    int setRecordSilenced(String packageName, boolean silenced);

AudioService.java:

    /** @hide */@Overridepublic int setRecordSilenced(String packageName, boolean silenced) {return AudioSystem.setRecordSilenced(packageName, silenced);}

AudioSystem.java:

    /*** @hide*/public static native int setRecordSilenced(String packageName, boolean silenced);

2.JNI层实现

android_media_AudioSystem.cpp:

static jint
android_media_AudioSystem_setRecordSilenced(JNIEnv *env, jobject thiz, jstring packageName, jboolean silenced)
{const char *c_packageName = env->GetStringUTFChars(packageName, NULL);int status = check_AudioSystem_Command(AudioSystem::setRecordSilenced(c_packageName, silenced));env->ReleaseStringUTFChars(packageName, c_packageName);return (jint) status;
}
static const JNINativeMethod gMethods[] = {......{"setRecordSilenced",      "(Ljava/lang/String;Z)I",     (void *)android_media_AudioSystem_setRecordSilenced},......

hiddenapi-light-greylist.txt:

Landroid/media/AudioSystem;->setRecordSilenced(Ljava/lang/String;Z)I

hiddenapi-private-dex.txt:

Landroid/media/AudioSystem;->setRecordSilenced(Ljava/lang/String;Z)I

3.C++层实现

AudioSystem.cpp:

status_t AudioSystem::setRecordSilenced(const char *packageName, bool silenced)
{ALOGV("setRecordSilencedByName : packageName = %s, is silenced = %d", packageName, silenced);const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();if (aps == 0) return PERMISSION_DENIED;aps->setRecordSilencedByName(packageName, silenced);return NO_ERROR;
}

AudioSystem.h:

class AudioSystem
{
public:
......static status_t muteMicrophone(bool state);......static status_t setRecordSilenced(const char *packageName, bool active);
};

这里有两点需要说明:

  1. 原生的setRecordSilenced接口在AudioPolicyService.cpp中,我们需要调用到AudioPolicyService中,要利用Binder机制,幸运的是AudioSystem中很轻易就能获取到BpAudioPolicyService实例,接下来理所当然要修改一些Binder有关的文件
  2. 因为AudioPolicyService.cpp中本来就有一个接口叫setRecordSilenced,我们并不是直接调用那个接口,而是先进行一些处理,所以我们调用的时候要换一个名字,叫setRecordSilencedByName

IAudioPolicyService.cpp:

enum {SET_DEVICE_CONNECTION_STATE = IBinder::FIRST_CALL_TRANSACTION,GET_DEVICE_CONNECTION_STATE,......//在枚举中加入代表咱们函数的成员SET_RECORD_SILENCED_BY_NAME
};
class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
{
public:explicit BpAudioPolicyService(const sp<IBinder>& impl): BpInterface<IAudioPolicyService>(impl){}virtual status_t setDeviceConnectionState(audio_devices_t device,audio_policy_dev_state_t state,const char *device_address,const char *device_name){Parcel data, reply;data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());data.writeInt32(static_cast <uint32_t>(device));data.writeInt32(static_cast <uint32_t>(state));data.writeCString(device_address);data.writeCString(device_name);remote()->transact(SET_DEVICE_CONNECTION_STATE, data, &reply);return static_cast <status_t> (reply.readInt32());}......//在BpAudioPolicyService中加入咱们的函数virtual void setRecordSilencedByName(const char *packageName, bool silenced){Parcel data, reply;data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());data.writeCString(packageName);data.writeInt32(silenced ? 1 : 0);remote()->transact(SET_RECORD_SILENCED_BY_NAME, data, &reply);}......
};
status_t BnAudioPolicyService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{......switch (code) {case SET_DEVICE_CONNECTION_STATE: {CHECK_INTERFACE(IAudioPolicyService, data, reply);audio_devices_t device =static_cast <audio_devices_t>(data.readInt32());audio_policy_dev_state_t state =static_cast <audio_policy_dev_state_t>(data.readInt32());const char *device_address = data.readCString();const char *device_name = data.readCString();if (device_address == nullptr || device_name == nullptr) {ALOGE("Bad Binder transaction: SET_DEVICE_CONNECTION_STATE for device %u", device);reply->writeInt32(static_cast<int32_t> (BAD_VALUE));} else {reply->writeInt32(static_cast<uint32_t> (setDeviceConnectionState(device,state,device_address,device_name)));}return NO_ERROR;} break;......//在BnAudioPolicyService::onTransact的switch/case中加入咱们的函数case SET_RECORD_SILENCED_BY_NAME: {CHECK_INTERFACE(IAudioPolicyService, data, reply);const char *packageName = data.readCString();setRecordSilencedByName(packageName, data.readInt32() == 1);return NO_ERROR;} break;default:return BBinder::onTransact(code, data, reply, flags);}
}

IAudioPolicyService.h:

class IAudioPolicyService : public IInterface
{
public:DECLARE_META_INTERFACE(AudioPolicyService);//// IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)//virtual status_t setDeviceConnectionState(audio_devices_t device,audio_policy_dev_state_t state,const char *device_address,const char *device_name) = 0;......virtual void setRecordSilencedByName(const char *packageName, bool silenced) = 0;......};

AudioPolicyService.cpp:

void AudioPolicyService::setRecordSilencedByName(const char *packageName, bool silenced)
{Mutex::Autolock _l(mNotificationClientsLock);ALOGD("AudioPolicyService:setRecordSilencedByName(packageName: %s, silenced: %d)", packageName, silenced);int count = mAudioRecordClients.size();for (int i = 0; i<count ; i++) {sp<AudioRecordClient> client = mAudioRecordClients.valueAt(i);//遍历mAudioRecordClients,根据packageName找到sessionID,之后我们会根据这个sessionID来静音if (strcmp(String8(client->opPackageName).string(), packageName) == 0) {ALOGD("AudioPolicyService:setRecordSilencedByName Find same package name in mAudioRecordClients");int32_t sessionID = client->session;setRecordSilenced(sessionID, silenced);}     }
}

AudioPolicyService.h:

    virtual void setAudioPortCallbacksEnabled(bool enabled);......virtual void setRecordSilencedByName(const char *packageName, bool silenced);

这里需要稍微解释一下:

  1. 名义上是根据包名静音,实际上在这里必须把包名转换为sessionID,因为sessionID才是AudioSession等对象共同持有的“通货”,packageName只保存在AudioPolicyService
  2. 之后我们直接调用了原生代码的setRecordSilenced方法,但是传入的却是sessionID而不是UID,为什么可以这样用?这是因为sessionIDUID都是int类型,而且巧合的是,它们的取值范围正好错开的,这就避免了增加一大堆新方法,直接修改老方法的实现,在老方法上根据取值判断是sessionID还是UID,并采取不同的操作就可以了

AudioPolicyManager.cpp:

#define AID_ROOT 0
#define AID_SYSTEM 1000
......
void AudioPolicyManager::setRecordSilenced(uid_t uid, bool silenced)
{ALOGV("AudioPolicyManager:setRecordSilenced(uid:%d, silenced:%d)", uid, silenced);Vector<sp<AudioInputDescriptor> > activeInputs = mInputs.getActiveInputs();//根据取值范围判断if (AID_ROOT < uid < AID_SYSTEM) {for (size_t i = 0; i < activeInputs.size(); i++) {sp<AudioInputDescriptor> activeDesc = activeInputs[i];AudioSessionCollection activeSessions = activeDesc->getAudioSessions(true);for (size_t j = 0; j < activeSessions.size(); j++) {sp<AudioSession> activeSession = activeSessions.valueAt(j);uid_t session = activeSession->session();if (session == uid) {activeSession->setSilenced(silenced);ALOGD("setRecordSilencedByName in AudioPolicyManager:setRecordSilenced, find it!");}}}} else {for (size_t i = 0; i < activeInputs.size(); i++) {sp<AudioInputDescriptor> activeDesc = activeInputs[i];AudioSessionCollection activeSessions = activeDesc->getAudioSessions(true);for (size_t j = 0; j < activeSessions.size(); j++) {sp<AudioSession> activeSession = activeSessions.valueAt(j);if (activeSession->uid() == uid) {activeSession->setSilenced(silenced);}}}}
}

Threads.cpp:

#define AID_ROOT 0
#define AID_SYSTEM 1000
......
void AudioFlinger::RecordThread::setRecordSilenced(uid_t uid, bool silenced)
{Mutex::Autolock _l(mLock);if (AID_ROOT < uid < AID_SYSTEM) {for (size_t i = 0; i < mTracks.size() ; i++) {sp<RecordTrack> track = mTracks[i];uid_t session = track->sessionId();if (track != 0 && session == uid) {track->setSilenced(silenced);ALOGD("setRecordSilencedByName in AudioFlinger::RecordThread, find it!");}}} else {for (size_t i = 0; i < mTracks.size() ; i++) {sp<RecordTrack> track = mTracks[i];if (track != 0 && track->uid() == uid) {track->setSilenced(silenced);}}}
}
......
void AudioFlinger::MmapCaptureThread::setRecordSilenced(uid_t uid, bool silenced)
{ALOGD("setRecordSilencedByName AudioFlinger::MmapCaptureThread::setRecordSilenced");Mutex::Autolock _l(mLock);if (AID_ROOT < uid < AID_SYSTEM) {for (size_t i = 0; i < mActiveTracks.size() ; i++) {uid_t session = mActiveTracks[i]->sessionId();if (session == uid) {ALOGD("setRecordSilencedByName in AudioFlinger::MmapCaptureThread, find it!");mActiveTracks[i]->setSilenced_l(silenced);broadcast_l();}}} else {for (size_t i = 0; i < mActiveTracks.size() ; i++) {if (mActiveTracks[i]->uid() == uid) {mActiveTracks[i]->setSilenced_l(silenced);broadcast_l();}}}
}

以上

二、并发录音的实现

非常简单,只要在AudioPolicyManager.cpp中修改三个地方:

    sp<AudioSession> audioSession = new AudioSession(session,inputSource,config->format,samplingRate,config->channel_mask,flags,uid,isSoundTrigger,policyMix, mpClientInterface);// FIXME: disable concurrent capture until UI is ready
//这里将#if 0改为#if 1
#if 1// reuse an open input if possiblesp<AudioInputDescriptor> reusedInputDesc;
    sp<AudioSession> audioSession = inputDesc->getAudioSession(session);if (audioSession == 0) {ALOGW("startInput() unknown session %d on input %d", session, input);return BAD_VALUE;}// FIXME: disable concurrent capture until UI is ready
//同样将#if 0改为#if 1
#if 1if (!isConcurentCaptureAllowed(inputDesc, audioSession)) {ALOGW("startInput(%d) failed: other input already started", input);return INVALID_OPERATION;}
//static
bool AudioPolicyManager::isConcurrentSource(audio_source_t source)
{return (source == AUDIO_SOURCE_HOTWORD) ||(source == AUDIO_SOURCE_VOICE_RECOGNITION) ||//这里把需要实现并发录音的录音类型加上(source == AUDIO_SOURCE_MIC) ||(source == AUDIO_SOURCE_FM_TUNER);
}

关于最后一个修改的解释:将两个if 0改为if 1后,Android实际上已经可以并发录音,但是允许并发录音的类型仅限isConcurrentSource里面包含的AUDIO_SOURCE_HOTWORDAUDIO_SOURCE_VOICE_RECOGNITIONAUDIO_SOURCE_FM_TUNER,如果还录其他类型,就需要在这里加上,例如作者在这里增加的AUDIO_SOURCE_MIC

以上

如果文章存在错误和不明白的地方,欢迎留言讨论!

http://www.lbrq.cn/news/2728369.html

相关文章:

  • html网站用什么空间百度网络科技有限公司
  • 河南双师培训网站百度指数数据分析报告
  • 做网站的市场怎么样抖音seo关键词优化怎么做
  • 网站开发 需求说明书企业查询网
  • 深圳分销网站设计哪家好网络营销推广活动有哪些
  • 网站建设经验做法和取得的成效友情链接如何添加
  • 北京工程工程建设交易信息网站长尾词seo排名优化
  • 买汽车最好的网站建设东莞做网页建站公司
  • 事业单位网站建设工作方案域名注册查询阿里云
  • 天津城市基础设施建设投资集团有限公司网站我想在百度上做广告怎么做
  • 龙口有没有做网站的网站接广告
  • 景区网站的作用线上营销推广方案
  • 网站seo优化费用做外贸有哪些网站平台
  • 昆山网站建设秦皇岛seo自学网视频教程
  • 贵阳做网站的公司新闻稿代写
  • 购物网站优惠券怎么做国内免费域名注册
  • wordpress大神教程网站需要怎么优化比较好
  • 杭州临安网站建设网页制作的步骤
  • 做英语陪同翻译兼职的网站怎么免费注册域名
  • 进不去的网站用什么浏览器台州关键词优化推荐
  • 企业做网站设计怎么宣传网站
  • 后台给网站做关键字抖音企业推广
  • 定制杯子sem推广优化
  • 2017电商网站建设背景网站如何进行seo
  • 做网站的需求分析百度推广的方式有哪些
  • 12306网站做的好垃圾优化网站seo
  • wordpress网站实现微信登录东莞网络公司电话
  • 武汉网站建设索王道下拉深圳seo云哥
  • 网页制作题用什么软件上海排名优化seo
  • 机场建设相关网站seo关键词排名实用软件
  • pdf合并代码
  • Windows 基于ACL(访问控制列表)的权限管理
  • Javar如何用RabbitMQ订单超时处理
  • Vue2与Vue3生命周期函数全面解析:从入门到精通
  • 公司项目用户密码加密方案推荐(兼顾安全、可靠与通用性)
  • MCP协议更新:从HTTP+SSE到Streamable HTTP,大模型通信的进化之路