Android框架理解之USB
以下理解只代表我个人此时的观点,并没有义务进行更新通知,内容如有不妥、交流请致信share1999@gmail.com 目的是看一下android下的usb和linux下的usb有什么区别?如果现在就能回答,就不用往下看了。 我的理解是android下没有usb。一 Android诞生的背景 乍一看这个话题与android框架似乎毫无关系,但是每
以下理解只代表我个人此时的观点,并没有义务进行更新通知,内容如有不妥、交流请致信share1999@gmail.com
目的是看一下android下的usb和linux下的usb有什么区别?如果现在就能回答,就不用往下看了。
我的理解是android下没有usb。
一 Android诞生的背景
乍一看这个话题与android框架似乎毫无关系,但是每一个新生事物的诞生必然取决于当时的环境,环境造就了这个新生事物,同时这个新生事物也应该承载着历史所赋予他的责任,他也将因此拥有某种能力,来完成他的使命。
最近几年手机的快速增长大家是有目共睹,手机已经摆脱了他最初的角色:打电话。他开始发短信、上网、打游戏、看电影、聊天等等。基于手机的增值服务对手机软件环境的需求越来越大。Android诞生前的手机操作系统是什么样子的?symbian、winCE、linux以及mtk,还有其他厂商的一些手机平台。当时的情况是手机厂家只管造出手机,没人考虑还需要在手机上开发应用软件,所以这些操作系统可以说基本上没有给别人留出进一步开发应用程序的余地、或者根本就没想留。或者你会说linux是开源的,想怎么开发就怎么开发。能在linux下开发应用程序的有几个,跟没提供接口一样,那个winCE还收费,更扯淡。所以说android诞生之前的手机操作系统市场是一个不懂服务、没有服务的军阀混战时期。但是我们已经过了只求温饱、不求娱乐的时期了,但是这些手机系统没有跟上,他们没有意识到服务的重要性、开放的重要性、与人方便的重要性。是iPhone,她抢先了一步,为广大手机客户创造了非凡的体验效果,手机原来可以做到这种效果。但这并不够,仅仅让用户拥有暂时的体验是不够的,要有持续不断的新鲜体验注入。苹果公司针对iPhone引入了一个新的模式appstore,让广大的手机软件开发者不断的为iPhone注入新鲜的血液,不断的给iPhone手机用户带来新的体验,手机软件开发者也获得了可观的收入,这是一个双赢的模式,是iPhone养活了手机软件开发者,还是软件开发者养活了iPhone,这已经说不清楚了。但是我们能看到的是用户对手机应用的需求决定着手机系统的发展的方向。那么市场需要什么样的手机系统(或者叫做手机软件环境)?从手机厂商来说:要开源,不需要再买什么手机开发平台。从应用的角度来说:要让应用软件的开发变得简单,让广大的软件开发人员来一起养活这个系统。Linux是成熟的、开源的操作系统。Java一种开发应用最快捷的平台,大量从事java开发的软件人员。是google,和iPhone几乎同时被历史所选中。Google,一个做互联网搜索的公司,轻易的切入了手机行业、移动互联网行业。他将linux和java结合在了一起,其实谁都能做到,但是却没有想到。谁会去做自己不赚钱,给别人提供方便、赚钱机会的事情:google可以做,大赚的机会应该在后面。Linux和java的结合产生了什么样的效果?类似于刚才提到的在军阀混战的时期突然站出了一位众望所归的英雄。短短几个月就被大家认可。被无数的java开发人员追捧,终于有了用武之地,就跟找到了人生的方向、信仰一样,大量的android团队、网站纷纷出现,因为只要会java就可以做手机应用软件赚钱。所以只要手机厂商推出了一款android手机,不用担心没有应用软件,不用花钱去开发应用软件,市场为他们开发了。
通过以上的总结,可以看出android最重要的是给java开发人员提供了应用软件的开发环境。至此,我们终于引出了下一个话题:android是怎么实现这个机制的?让java和linux(一个C环境)融合在了一起。
了解一个新的事物,不一定要从应用者的角度、也不一定要从研发人员的角度,我们还可以从设计者的角度来考虑、从他诞生的环境来切入等等,并没有固定的,只是在不同的阶段可以考虑从不同的角度来切入。
二是JNI
上面我们只是说android让java开发人员能够方便的进行手机应用软件开发了,更具体的说应该是更方便的在linux操作系统上以java语言进行应用软件开发了。所以说android不是操作系统,是linux操作系统下的一个框架。一个可以使用java语言进行开发的框架,一个实现了通过java调用C或者C++(.so)进而linux操作系统的框架。这个框架是运行在linux系统上的一个程序,没有这个框架,下面的linux系统已经完全能够实现我们所需要的应用(和使用android达到一样的效果),但是他不够人性化。Linux强大的可移植性和java的平台无关性,两者的结合简直就是perfect。
上层应用和UI有java来完成,底层的硬件有C/C++来完成。如果底层的硬件有改动,只需要改动lib层(.so)和kernel层就可以了(我觉得叫做linux系统层更好)。层是一个很好的概念,层代表着独立、自由。每一层的首要任务是负责自己层的事情,但是层与层之间需要沟通。Java层在实现某种功能时,如果需要调用底层的C组件,那么就会使用JNI接口。JNI是Java Native Interface的缩写,译为Java本地接口。它允许Java代码和其他语言编写的代码进行交互。在android中提供JNI的方式,让Java程序可以调用C语言程序。android中很多Java类都具有native接口,这些接口由本地实现,然后注册到系统中。
JNI代码放在以下的路径中:frameworks/base/core/jni/,这个路径中的内容被编译成库 libandroid_runtime.so
Java转化为字节码之后就需要虚拟机来执行了。Dalvik virtual machine。在java执行的过程中,如果java类需要使用C++函数,那么虚拟机就会载入这个C函数。虚拟机可以让java和C之间通过标准的JNI相互调用。System.loadLibrary(*.so)这个动作就是java程序要求虚拟机载入C函数,载入之后java类和.so库就一起运行了。
下面是一个jni 例子。
http://developer.51cto.com/art/200509/2815.htm
关于jni如何使用,这里就没有必要介绍了,他只是用来连接Java和C++的一个简单的机制,结合着java虚拟机共同完成了java和C++的互动。
到了这里我们可以考虑一下,JNI这个机制在android作用,他的作用也间接的反映出android的框架。作用就是连接java类和lib库(.so C++),那么也就是说android就是两层:一层是java,另外一层是C++,通过JNI将两层连接起来。当我们还不了解一件事物的时候,最好把他先想的简单一点,之后再慢慢细分。
那么为什么android的框架模型中却是4层呢?google在这点上我觉得有点不厚道。
图1
底层的kernel层不属于google的android,当然属于linus torvalds还是google,已经不重要了,重要的是误导了我对android的理解,以为android是一个操作系统,其实他不是。Kernel层的叫法我也不认同,我觉得应该叫做linux系统层。Android为什么这么叫?
三挟天子以令诸侯
linux被android绑架了!android本来是运行在linux系统下的一个应用开发框架,但是他的光环已经掩盖了linux系统,更可怕的是android正在逐步的修改linux系统,操作系统成了傀儡。Google嫁了女儿带回来一个儿子(linux),这个被linus torvalds养了20年的儿子,给人做了上门女婿,并且在不断的被洗脑、改造着。而linus torvalds和广大的linux爱好者还要不断的给linux提供生活补助。并且这个女儿好像也不是google的,好像是sun的。收养了一个看似普通的女儿,经过打扮,找了一个上门女婿(一个并未施展才华的小伙),组成了一个新的家庭:google称其为android。1+1 远远打大于了 2。
Google正在不遗余力的包装着这个新的组合,包装都是有欺骗性的。但是做为即将在android环境下开发的人员来说,不能被他的宣传广告所迷惑,掌握了他的真实脉络,才能进行开发、移植。
经过上面的感性认识,我们要回归理性的分析。最底层kernel层(大家都这么叫),入乡随俗,不仅包括内核本身,各种驱动、文件系统也尽在其中。对硬件的所有基本操作都在这一层,这一层有谁来维护,总之不是google,但是google却可以在里边加入自己的元素:android元素,其实没有说google这样做不好的意思,相反很赞成,Google根据这套框架所运行的环境对linux 内核进行不断的改造,可谓是为嵌入式量身打造。其上一层是lib库层,为什么会诞生这一层?我觉得他是为java层而生。Java层的应用程序在试图操作kernel底层的设备时,发现很费劲,所以设计者可能考虑需要在java应用层和kernel层之间插入一层:lib层。这一层将设备驱动层和java应用层联系了起来。所以如果我们要让我们的某个设备在android的环境下使用起来(如果android当前的框架中无法支持这个设备),就需要在开发完驱动后,再在lib层用C++写一组JNI接口函数,供java层调用。这个机制并不复杂,这个开发工作是否复杂取决于你要将这个设备呈现给java开发者的功能,如果只想做个helloworld,能复杂的了么?所以写到这我有一个想法(等待以后的验证):android开发的难易取决于我们以后要实现的某种功能,而这个功能与android环境、linux系统没有多大关系(可能有点关系,毕竟在人家的地盘)。Lib层之上是所谓的framework层,我觉得从我们公司的性质来看,更倾向于将framework层和app层统称为java层。这两层都是java程序,一层是jar包,就是一些封装好的API函数,一层是使用这些API,对于我们做芯片、做驱动、做方案来说,这两层就是一层。我们只要理解一个宗旨就可以了:android诞生的目的就是让java开发人员能够方便的使用java语言操作各种硬件资源,进行应用程序的开发,所以在framework这一层的jar包仅仅是为app层使用的,仅仅是一个纯软件及别的层面,这一层和lib层相呼应。或者这样来划分:jni之上的framework和app叫做软件层(或应用层),之下的lib和kernel叫做硬件层(或系统层)。软件层的framework间接的反应着硬件的操作方法和功能,称其为软件层中的硬件反映层。Lib层就成为硬件层中的软件供给层。
软件中的软件、软件中的硬件、硬件中的软件、硬件中的硬件,简单理解就两层;软件层和硬件层。每一层的开发都基于下一层提供的功能接口。
记得当时有同事讨论在android这个环境下能否直接使用C语言开发。中华人民共和国是有共产党领导的,既然选择了在这里生活,你就应该坚持四项基本原则、拥护党的领导,不要老是想着国外那些情况,动不动就罢工、游行什么的。在这里就要按照我们国家的制度办事,游行可以,不过要按照中国的游行法来做。享受着android带来的开发便捷,还想着以前的linux,用什么C语言来开发应用程序,枉费google的一片心血。所以我觉得不是不可以,但要看android的脸色和气度。我觉得应该是可能的,android虽然强大,绑架了linux系统,但是linux毕竟是一个操作系统,是可以直接运行程序的。这个基于linux系统运行的程序和android是同级别的[m1] 。
图2
http://www.you01.com/dzly/dzswf/2010072932.swf
四从系统装载过程再认识android
android和kernel是单独编译,单独加载的。可以说是这个真相,触发了这篇文章。
在编译android 之后,会生成几个image 文件,这些文件是:
1 ramdisk.img : 一个分区影像文件,它会在kernel 启动的时候,以只读的方式被 mount,这个文件中只是包含了 /init 以及一些配置文件,这个ramdisk 被用来调用init,以及把真正的root file system mount 起来
2 system.img:是包含了整个系统,android 的framework,application 等等,会被挂接到 "/" 上,包含了系统中所有的二进制文件
3 userdata.img:将会被挂接到 /data 下,包含了所有应用相关的配置文件,以及用户相关的数据
ramdisk.img is a small partition image that is mounted read-only by the kernel at boot time. It only contains /init and a few config files. It is used to start init which will mount the rest of the system images properly and run the init procedure. A Ramdisk is a standard Linux feature.
system.img is a partition image that will be mounted as / and thus contains all system binaries
userdata.img is a partition image that can be mounted as /data and thus contains all application-specific and user-specific data.
Ramdisk是kernel和android的桥梁,linux启动后挂在ramdisk,然后再ramdisk里边有启动android的脚本。
Linux内核启动完成后,会启动第一个进程:init进程,它是一个由内核启动的用户级进程。内核启动后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程。
Init进程一起来就根据init.rc脚本文件建立了几个基本的服务:
- servicemanamger
- zygote
………………
init.rc这个脚本里的内容就是android需要维护的,里边应当有启动android的过程。这方面的内容将有zhicheng来讲解。
从这个linux-----àandroid的启动过程,是不是再一次感觉到了层的重要性,层与层之间相互独立,层与层之间又提供了某种开发的接口,允许对方的侵入。同时从这个启动过程也能够知道我们的工作需要落实在哪一层上(根据我们的需求)。
五以特定应用为主线纵向贯穿各层
经过上面的理解,对android应该是有了一定的理解的。理解的目的是要用,如何把这个框架使用起来。我们是做SOC的,还得给他们做解决方案,以前只做驱动就可以了,但是既然在andoird下混了,就要按照android的规则出牌,我们得给人提供jar包、lib库。我们得有服务精神,让广大的java应用开发人员在我们的解决方案上,游刃有余的开发应用程序,我们的奖金得依靠他们。
那么针对某种应用我们都需要干什么呢?需求驱动着一切(底层反应着一切),软件开发人员需要什么,我们就提供什么,所以我们从app层的某个特定的功能应用开始。
以向sd卡中写入一个文件为例:
下面这段代码是从网上找的,用于向sd卡中写入一个文件的片段。
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ File sdCardDir = Environment.getExternalStorageDirectory();//获取SDCard目录,2.2的时候为:/mnt/sdcart 2.1的时候为:/sdcard,所以使用静态方法得到路径会好一点。
File saveFile = new File(sdCardDir, "abc.txt");
FileOutputStream outStream = new FileOutputStream(saveFile);
outStream.write("你好".getBytes());
outStream.close();
}
对于一个应用程序来说,必须要知道自己要向哪个目录中写入文件。如果想往sd卡中写,就需要知道sd卡对应的目录:Environment.getExternalStorageDirectory();这句话是用来获取sd卡的存储目录,将目录存放到sdCardDir,比如是/sdcard。
那么些这个文件的过程是什么?outStream.write("你好".getBytes());到底干了什么?
进入FileOutputStream.java,可以看到write的具体实现:
public void write(byte[] buffer, int offset, int count) throws IOException {
if (buffer == null) {
throw new NullPointerException(Msg.getString("K0047")); //$NON-NLS-1$
}
if ((count | offset) < 0 || count > buffer.length - offset) {
throw new IndexOutOfBoundsException(Msg.getString("K002f"));
}
if (count == 0) {
return;
}
openCheck();
fileSystem.write(fd.descriptor, buffer, offset, count);
}
然后调用到了fileSystem.write,fd.descriptor中含有路径信息。
这个write会像一个linux中所谓的scsi设备中写入数据,经过一层层传到sd的驱动层。这个sd设备应该会在/dev目录下有一个设备节点,最终会通过这个设备节点,调用到这个设备的write驱动函数,实现最终的写入动作。
当然从fileSystem这个对象的write到设备驱动的write,中间走过了2层,一个是framework、一个是lib层。(这两个write已经不是同一个write了,第一个write是fileSystem这个对象呈现给app层的,而第二个write的功能也许没那么丰富,这都取决于设计者)。
在kernel层之上,应该能够找到open这个设备的地方。如open(“/dev/sd”)。
http://daydayup1989.javaeye.com/blog/745338
六你看到题目中的USB了么?
初衷是看看android中的usb是什么样子的,但是都快讲完了usb也没有出现。通过上面的sd的文件操作,在android的框架中看到sd卡的驱动了么?我没有看到,希望永远不要看到,因为他不应该在android的框架里出现,应该出现在kernel层(linux系统)。USB
和sd的角色是一样的。所以也不应该出现在android的框架中、代码中。
七未济的话题
通篇都是在说android只是一个框架、如何捡了便宜,其实这是不客观的,这么多人将android认为是一个操作系统,是有它的道理的。Android做了很多东西,并不是简单的一堆jar包。他在linux系统之上衍生出了一个新的准系统,实现着程序的管理、通讯、存储等功能。如activity、intent、service、content provider等,这些工作不是一个简单的程序所能做的,java人员享受的开发之快捷是建立在android所提供的强大功能之上,称其为android系统并不为过。Android不仅是一个系统,也是一种新的商业模式,一种企业文化的体现。
这些理解并不一定正确,不过是一个开始,还有很多工作需要我们去做。
所以这里一共涉及到两个大环境:一个是我们以前的linux环境,一个是android环境。
如果我们不提供解决方案,只提供驱动,只要关注linux环境中的驱动部分就可以。如果提供解决方案,假设已经有了针对硬件的驱动(linux层的驱动),那么还需要在lib层加入一层C++的代码,向上提供操作驱动层的接口。同时还要在framework层针对我们设备的功能封装出相应的类和接口出来,并实现该类或接口的方法,提供给app层应用。App层我们不会用到,但是需要了解或让客户提需求,因为只有了解客户要怎么用这个设备,才能封装出好的类和接口。不过android系统的东西只要会用、有个了解就差不多了。
更多推荐
所有评论(0)