双Android系统AudioFramework及驱动设计
2019-08-02郭瑞祥李玉范叶平操李节杨德胜
郭瑞祥, 李玉, 范叶平, 操李节, 杨德胜
(安徽继远软件有限公司, 合肥 230088)
0 引言
随着移动智能手机的迅速发展,移动智能手机的功能已不仅仅是简单的通讯功能,用户经常使用智能手机处理日常生活中遇到的各种问题,同时由于移动智能手机便于携带及功能强大的优势,移动智能手机开始进入办公领域,许多用户为了使用方便,利用同一部智能手机来处理生活和工作内容,这将造成生活与工作的混淆,且容易造成企业敏感信息的泄漏,为了区分工作和生活,同时也对企业敏感数据进行保护[1-2],基于虚拟化技术和容器技术的双系统智能手机成了一种选择方案,在一台智能移动手机上运行两套系统,分别称为外域系统和内域系统,同一时刻只有一个系统占用智能移动设备显示、输入、音频等资源,用户可通过系统界面按钮一键切换内外域系统的前后台状态,实现了工作和生活的分离[3-4]。
利用虚拟化技术和容器技术实现双系统时需要对系统模块进行重新设计研发,本文提出了一种对双系统中音频模块的实现方法与逻辑重新设计方案[5-6],实现了触发系统前后台切换时,Audio子系统内的处理逻辑,及后台系统如有应用想播放声音时的处理逻辑等。
1 双安卓AudioFramework和驱动软件架构
基于容器技术实现的双Android系统拥有容器服务,本文所述方法基于容器支撑平台之上的ContainerService和ContainerControlService实现,软件架构如图1所示。
针对双安卓系统的Audio Framework框架,关键的控制模块为Java层的ContainerService和Native层的ContainerControlService。Audio Framework执行的控制通路与数据通路的切换都是受ContainerService或ContainerControlService控制。
Audio Framework和驱动的设计,主要是针对容器切换时,系统所处的前后台状态来决定不同的业务逻辑,内域系统和外域系统的代码处理逻辑类似,都是需要关注两部分:容器切换时的处理逻辑和新建音频播放流的处理逻辑。
图1 软件架构图
2 AudioFramwork及驱动设计说明
2.1 容器切换
在用户切换内外域系统时,也就是容器切换时,最容易发生内外域系统对音频设备的访问冲突,为符合用户使用的便捷性,原则上只有前台系统才能访问音频设备,后台的系统禁止访问音频设备。
前台系统请求切换到后台时,ContainerService会调用AudioManager的接口setParameters()来设置系统的所处的前后台状态。setParameters()中的参数是个键值对字符串,如果系统是从前台切到后台,其键值对为”container_state=back”;如果系统是从后台切到前台,其键值对为“container_state=front”。此键值对经过层层传递,最终在AudioALSAStreamManager中解析,并以布尔值的方式保存。当系统切换至后台时,会调用standbyAllStreams()方法。暂停所有播放的声音,并把音频设备关闭。如图2所示。具体代码修改为修改AudioALSAHardware.cpp文件中两段代码,具体见下文。
图2 容器切换时序图
AudioALSAHardware.cpp
status_t AudioALSAHardware::setParameters(const String8 & keyValuePairs)
{
String8 value_str;
AudioParameter param = AudioParameter(keyValuePairs);
if (param.get(String8("container_state ") , value_str) == NO_ERROR)
{
mStreamManager->setParameter(keyValuePairs, 0);
}
}
AudioALSAStreamManager.cpp
static String8 keyContainerState = String8(“container_state”);
status_t AudioALSAStreamManager::setParameters(const String8 & keyValuePairs , int IOport)
{
String8 value_str;
AudioParameter param = AudioParameter(keyValuePairs);
if (param.get(String8(keyContainerState) , value_str) ==NO_ERROR)
{
param.remove(String8(keyContainerState));
if(value_str == “back”)
{
standbyAllStreams(true);
container_state = false;
}
else
{
Container_state = true;
}
return 0;
}
}
2.2 音频的播放与录制
双安卓系统中,针对音频的播放/录制流程,只有是系统处在后台时才需要进行特殊处理;如果是前台系统,针对音频的播放/录制是与安卓原生系统是一致,不需要进行特殊处理。
相对于原生的安卓系统中音频驱动适配层,最关键的就是在新建音频流之前,双安卓会判断当前应用所属系统的前后台状态。根据用户体验需求,只有处在前台系统的应用才可以播放音频,即只有处理前台系统的应用才能操作音频设备。而标记系统前后台状态的参数保存在音频驱动的适配层AudioALSAStreamManager中。如图3所示。具体代码修改为修改AudioALSAHardware.cpp文件中代码,具体见下文。
1) 前台应用播放音频
如果是前台系统的应用想播放音频,双安卓系统中的处理逻辑与原生安卓的处理逻辑一致,创建播放音频所需的所有资源,包括对音频设备的控制操作。
2) 后台应用播放音频
如果是后台系统的应用想播放音频,在双安卓系统中会返回错误码,而不会创建播放音频所需的资源,更不会对音频设备进行控制操作。
3) 音频录制
由于音频的录制跟播放的流程在AudioALSAHardware类里一样,都需调用createAudioPatch()方法,所以其处理逻辑跟播放是一样的,无需另外添加代码。
图3 AudioHal层新建播放/录制音频流的时序图
AudioALSAHardware.cpp
int AudioALSAHardware::createAudioPatch(unsigned int num_sources , const struct audio_port_config *sources , unsigned int num_sinks , const struct audio_port_config *sinks , audio_patch_handle_t *handle)
{
if (handle == NULL || sources == NULL || sinks == NULL)
{
return BAD_VALUE;
}
if ( false == mStreamManager-> getContainerState())
{
return BAD_VALUE;
}
}
2.3 接口函数及成员变量
Audio Framework在双安卓系统中的修改,主要是通过已有的setParameters()方法,传递了一个新增的用以表示系统前后台状态的键值对,并最终在类AudioALSAStreamManager进行解析,存储及控制新建音频流的业务逻辑。前后台系统切换音频控制的接口函数及成员变量如下所示:
AudioALSAStreamManager.cpp
Class AudioALSAStreamManager{
public:
//设置系统前后台状态的方法
void AudioALSAStreamManager :: setContainerState(bool state);
//获取系统前后台状态的方法
bool AudioALSAStreamManager :: getContainerState();
private:
//系统前后台状态的标识:true: 前台;false:后台
bool container_state;
}
3 总结
移动智能终端的发展方便了人们的生活,同时改变了企业办公方式,基于虚拟化技术及容器技术的双系统技术保障了用户在同一台设备上处理生活与工作时企业数据的安全。在实现双系统时需要对系统模块进行重新设计,以便解决系统切换时出现的资源访问冲突,本文提出了一种基于双安卓系统的音频控制方法,通过对系统AudioFramework及驱动的重新设计,实现了双安卓系统内外域系统切换时的音频控制策略,保障了只有前台系统才具备设备音频设备的访问权限。