当前位置:首页 > 嵌入式 > 嵌入式软件

Android平台是基于Linxu内核搭建的,Linux内核的优势在于大内存管理、进程管理、基于权限的安全模型、统一的驱动模型、共享库支持、代码开源等。

Android平台在设计过程中,针对移动终端资源有限的特点,对Linux进行了一定程度的裁剪:砍掉了原生的窗口系统、去除了对GNU Libc的支持(引入了更高效、针对优化过的Bionic)、裁剪掉了一些标准Linux工具的部分特性等。

另外Android针对移动终端的特点还对Linux内核在闹钟(Alarm)、Low Memory Killer、Ashmem、内核调试(Kernel Debugger)、进程间通信(Binder)、日志(Logger)、电源管理(Power Management)等方面做了大量的优化。

其中Low Memory Killer相对于Linux标准OOM(Out Of Memory)机制更加灵活,它可以根据需要杀死进程来释放需要的内存。Low Memory Killer的实现主要位于auroramsmmsm drivers/staging/android/lowmemorykiller.c文件中。

Ashmem为进程间提供大块共享内存,同时为内核提供回收和管理这个内存的机制。 Ashmem的实现位于systemcorelibcutilsashmem-dev.c文件中。

下面重点介绍进程间通信和电源管理的内容。

1.进程间通信

在多进程环境下,应用程序和后台服务间通常会运行在不同的进程中,彼此有着独立的地址空间,但是因为需要相互协作,彼此间又必须进行通信和数据共享,而传统的进程间通信(IPC,Internet Process Connection)却有着进程过载和安全漏洞等方面的风险。在Android中,引入了Binder的进程间通信机制,Binder的好处在于在驱动层面就对进程间通信提供了支持、通过SMD共享内存机制提高了进程间通信的性能、采用线程池的方式来处理进程请求、针对系统中的对象引入了引用计数机制和跨进程的对象引用映射机制、在进程间的同步调用。图1显示了Android的进程间通信过程。


图1 Android的进程间通信过程

为了进行进程间通信,Binder采用AIDL(Android Interface Definition Lanaguage)来描述进程间的接口。
在实际的实现中,Binder是作为一个特殊的字符型设备来存在的,其实现遵循Linux设备驱动模型,相关的主要代码位于auroramsmmsmdriversstagingandroid binder.c文件中。

在Binder驱动中,binder_thread_write()函数通过binder_transaction()函数来发送请求或返回结果,而binder_thread_read()函数用于读取结果,Binder主要通过binder_ioctl()函数与用户空间的进程交换数据。

Binder的私有数据结构binder_proc则被用来记录当前进程、进程ID、内存映射信息、Binder的统计信息和线程信息等。

如果收到请求,binder_transaction()函数会通过对象的句柄找到对象所在的进程,如果句柄为空就认为对象是 context_mgr,把请求发给context_mgr所在的进程。所有的Binder对象会全部放到一个RB树中。最后context_mgr把请求放到目标进程的事件队列中,等待目标进程读取。数据的解析工作放在binder_parse()中实现。

下面是Binder驱动中最重要的binder_ioctl()函数的实现:

代码1-1 binder_ioctl()函数的实现

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc=filp->private_data;
struct binder_thread *thread;
unsigned int size=_IOC_SIZE(cmd);
void __user *ubuf=(void __user *)arg;
/*printk(KERN_INFO "binder_ioctl: %d:%d %x %lxn", proc->pid, current->pid, cmd, arg);*/
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret)
return ret;
mutex_lock(&binder_lock);
thread=binder_get_thread(proc); //获取一个Binder线程
if (thread==NULL) {
ret=-ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size!=sizeof(struct binder_write_read)) {
ret=-EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { //从用户空间缓冲复制数据
ret=-EFAULT;
goto err;
}
if (binder_debug_mask & BINDER_DEBUG_READ_WRITE)
printk(KERN_INFO "binder: %d:%d write %ld at %08lx, read %ld at %08lxn",
proc->pid, thread->pid, bwr.write_size, bwr.write_buffer, bwr.read_size, bwr.read_buffer);
if (bwr.write_size > 0) {
ret=binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); //传递数据
if (ret < 0) {
bwr.read_consumed=0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) //将数据写回用户空间
ret=-EFAULT;
goto err;
}
}
if (bwr.read_size>0) {
ret=binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); //读取数据
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait); //唤醒挂起的线程
if (ret<0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto err;
}
}
if (binder_debug_mask & BINDER_DEBUG_READ_WRITE)
printk(KERN_INFO "binder: %d:%d wrote %ld of %ld, read return %ld of %ldn",
proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, bwr.read_consumed, bwr.read_size);
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret=-EFAULT;
goto err;
}
break;
}
case BINDER_SET_MAX_THREADS: 设置最大线程数
if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
ret=-EINVAL;
goto err;
}
break;
case BINDER_SET_CONTEXT_MGR: //设为上下文管理器
if (binder_context_mgr_node!=NULL) {
printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already setn");
ret=-EBUSY;
goto err;
}
if (binder_context_mgr_uid!=-1) {
if (binder_context_mgr_uid!=current->cred->euid) {
printk(KERN_ERR "binder:BINDER_SET_"
"CONTEXT_MGR bad uid %d!= %dn",
current->cred->euid,
binder_context_mgr_uid);
ret=-EPERM;
goto err;
}
} else
binder_context_mgr_uid=current->cred->euid;
binder_context_mgr_node=binder_new_node(proc, NULL, NULL);//新的RB树节点
if (binder_context_mgr_node==NULL) {
ret=-ENOMEM;
goto err;
}
binder_context_mgr_node->local_weak_refs++;
binder_context_mgr_node->local_strong_refs++;
binder_context_mgr_node->has_strong_ref = 1;
binder_context_mgr_node->has_weak_ref = 1;
break;
case BINDER_THREAD_EXIT: //销毁消除
if (binder_debug_mask & BINDER_DEBUG_THREADS)
printk(KERN_INFO "binder: %d:%d exitn",
proc->pid, thread->pid);
binder_free_thread(proc, thread); //释放线程
thread=NULL;
break;
case BINDER_VERSION: //获取Binder版本信息
if (size!=sizeof(struct binder_version)) {
ret=-EINVAL;
goto err;
}
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) {
ret=-EINVAL;
goto err;
}
break;
default:
ret=-EINVAL;
goto err;
}
ret=0;
err:
if (thread)
thread->looper&=~BINDER_LOOPER_STATE_NEED_RETURN;
mutex_unlock(&binder_lock);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret !=-ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %dn", proc->pid, current->pid, cmd, arg, ret);
return ret;
}

2.电源管理

在目前的移动终端中,系统承载的功能越来越多,同时为了获得更好的用户体验,GUI的设计越来越华丽,但这都不可避免地增加了系统的功耗,导致目前的智能移动终端普遍待机时间较短。在目前电池技术尚无法有大的突破情况下,电源管理显得尤为重要,需要在满足用户需求的前提下,尽可能地减少功耗。电源管理策略是一个系统工程,应用程序、内核框架、设备驱动、硬件设备都涉及其中。

对半导体器件而言,功耗分为静态功耗、动态功耗。静态功耗主要是指待机状态下的泄漏电流,动态功耗才是电源管理要解决的主要问题。

Android的电源管理机制是建立在标准的Linux电源管理机制ACPI (Advanced Configuration and Power Interface)之上的,同时针对移动终端的特点采取了更积极的电源管理策略,支持休眠模式、动态电压和调频调节、电源管理质量服务(PM QoS)、唤醒锁等。

休眠模式、动态电压和调频调节等策略这里就不再多做介绍了。下面简要介绍PM QoS和唤醒锁的实现。

1)PM QoS

在初始化阶段,Android定义的PM QoS参数有3个:cpu_dma_latency(CPU DMA延迟)、network_latency(网络延迟)、 network_throughput(网络吞吐量)。供驱动、子系统、用户空间应用等注册PM QoS请求。默认的参数级别有延迟、超时(Aurora中暂时不用)、吞吐量等。

在Aurora(auroramsmmsmkernelpm_qos_params.c)中, PM QoS有4个参数:PM_QOS_CPU_DMA_LATENCY、PM_QOS_NETWORK_LATENCY、PM_QOS_NETWORK_ THROUGHPUT和PM_QOS_SYSTEM_BUS_FREQ等,分别针对CPU DMA延迟、网络延迟、网络吞吐量、系统总线频率等性能指标。参数集的实现在pm_qos_power_init()函数中进行,使用pm_qos_init()函数在内核里可以增加新的参数。在系统中,PM QoS主要用来管理CPU空闲管理、WiFi应用等。

在内核空间,通过pm_qos_add_requirement()函数可以注册PM QoS请求;通过pm_qos_update_requirement()函数可以更新已注册的PM QoS请求;通过pm_qos_remove_requirement()函数可以删除已注册的PM QoS请求。图2显示了注册PM QoS请求的过程。


图2 注册PM QoS请求的过程

在用户空间,仅进程可以注册PM QoS请求,为了注册PM QoS请求,进程必须打开/dev/[cpu_dma_latency, network_latency, network_throughput]设备,默认的PM QoS请求名为“process_<PID>”。其中PID值在系统调用中获得。

2)唤醒锁

通过支持多种类型的唤醒锁(wake locks),Android支持组件在电源管理方面的请求。需要注意的是,在使用唤醒锁时需要相当小心。图3显示了创建唤醒锁的过程。


图3 创建唤醒锁的过程

在实际的开发过程中,为了测试各应用电量消耗的情况,电量分析软件powerTop不可或缺,它可以分析出每个具体的应用对电量的消耗情况。

Android电源管理的实现主要位于auroramsmmsmkernelpower目录下,主要的文件包括earlysuspend.c、consoleearlysuspend.c、fbearlysuspend.c、wakelock.c、userwakelock.c等。

在Java层,Android封装了一个PowerManager类来进行电源的管理。

3.驱动

驱动的实现与硬件平台密切相关,由于在Linux Kernel 2.6中引入了Linux设备驱动模型,Linux的驱动开发变得十分简单。在auroramsmmsmdrivers目录中,Qualcomm提供了非常多的硬件驱动,如BT、i2C、USB、FM、音频、视频等。下面简要介绍部分驱动的情况。

●显示驱动(Display Driver):常用基于Linux的帧缓冲( Buffer)驱动。
●照相机驱动(Camera):常用基于Linux的V4L2驱动。
●音频驱动:常用基于ALSA(高级Linux音频架构,Advanced Linux Sound Architecture)驱动。
●WIFI驱动:基于IEEE 802.11标准的驱动程序。Aurora支持的WIFI标准为802.11 bgn。对WAPI的支持则需要硬件平台厂商的支持。
●Binder IPC驱动:Android的一个特殊的驱动程序,具有单独的设备节点,实现进程间通信的功能。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

为了满足日益增长的数据处理需求,铁威马NAS推出了全新的性能巅峰2024年旗舰之作F4-424 Pro,并搭载了最新的操作系统--TOS 6。这款高效办公神器的问世,无疑将为企业和专业人士带来前所未有的便捷与效率。

关键字: 存储 Linux 服务器

双系统将是下述内容的主要介绍对象,通过这篇文章,小编希望大家可以对双系统的相关情况以及信息有所认识和了解,详细内容如下。

关键字: 双系统 Windows Linux

罗德与施瓦茨与SmartViser携手开发了一种用于测试符合欧盟销售的智能手机和平板电脑的新Energy Efficiency Index(EEI)标签法规的解决方案。该解决方案的核心是R&S CMX500,这是...

关键字: 智能手机 Android iOS

安装Linux操作系统并不复杂,下面是一个大致的步骤指南,以帮助您完成安装。1. 下载Linux发行版:首先,您需要从Linux发行版官方网站下载最新的ISO镜像文件。

关键字: Linux 操作系统 ISO镜像

计算机是由一堆硬件组成的,为了有限的控制这些硬件资源,于是就有了操作系统的产生,操作系统是软件子系统的一部分,是硬件基础上的第一层软件。

关键字: Linux 操作系统 计算机

Linux操作系统是一套免费使用和自由传播的类Unix操作系统,通常被称为GNU/Linux。它是由林纳斯·托瓦兹在1991年首次发布的,并基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。Lin...

关键字: Linux 操作系统

所谓进程间通信就是在不同进程之间传播或交换信息,它是一组编程接口,让程序员能够协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息;还可以让一个程序能够在同一时间里处理许多用户的需求。

关键字: Linux 进程通信 编程接口

串口通信作为一种最传统的通信方式,在工业自动化、通讯、控制等领域得到广泛使用。

关键字: Linux 串口通信 通讯

2023年11月16日: MikroElektronika(MIKROE) ,作为一家通过提供基于成熟标准的创新式硬软件产品来大幅缩短开发时间的嵌入式解决方案公司,今天宣布推出一款基于单线设备的软硬件开源解决方案Cli...

关键字: 嵌入式 Linux 操作系统

Linux是一种免费使用和自由传播的类Unix操作系统,其内核由林纳斯·本纳第克特·托瓦兹于1991年10月5日首次发布。它主要受到Minix和Unix思想的启发,是一个基于POSIX的多用户、多任务、支持多线程和多CP...

关键字: Linux 操作系统
关闭
关闭