??xml version="1.0" encoding="utf-8" standalone="yes"?> 发布?011-09-28 Android 核心分析 之七------Service深入分析 上一章我们分析了Android IPC架构,知道了Android服务构徏的一些基本理念和原理Q本章我们将深入分析Android的服务。Android体系架构中三U意义上服务Q?/p>
Native服务 Android服务 InitI间的服务,主要是属性设|,q个QPQ是利用QIcket来完成的Q这个我在另外一章来讨论?/p>
Navite服务Q实际上是指完全在C++I间完成的服务,主要是指pȝ一开始初始化Q通过Init.rc脚本h的服务,例如Service Manger service,Zygote service,Media service , ril_demon service{?/p>
Android服务是指在JVMI间完成的服务,虽然也要使用Navite上的框架Q但是服务主体存在于AndroidI间。Android是二阶段初始QInit2Q初始化时徏立的服务?/p>
1 Service本质l构 我们q是从Service的根本意义分析入手,服务的本质就是响应客Lh。要提供服务Q就必须建立接收hQ处理请求,应答客服端的框架。我惛_Android Service设计者也会无时不Lq个服务本质框图挂在脑v中。从E序的角度,服务一定要存在一个闭合@环框架和h处理框架 分析清楚服务框就必须弄清楚以下的机制及其构成?/p>
Q?Q闭合@环结构放|在哪里Q?/p>
Q?Q处理请求是如何分发和管理? Q?Q处理框架是如何建立的? Q?Q概忉|架是如何建立的? 2 Service基本框架分析 Android设计中,Native Service和Android Service采用了同一个闭合@环框架。这个闭合@环框架放|在Native的C++I间中,,ProcessState@ProcessState.cpp 和IPCThreadState@IPCThreadState.cpp两个cd成了全部工作?/p>
在服务框架中QProcessState是公用的部分Q这个公用部分最主要的框架就是闭合@环框架和接收CBinder来的h后的处理框架。我们将服务框架用ProcessSate来表C?a之: Q?Q?addservice Q?Q?建立闭合循环处理框架?/p>
int main(int argc, char** argv) { sp<ProcessState> proc(ProcessState::self()); addService(String16("xxx0"), new xxx0Service()); addService(String16("xxx1"), new xxx1Service()); … ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool();//闭合循环框架 } 2.1 Native Service Native Service是在pȝInit阶段通过Init.rc脚本建立的服务?/p>
首先来看看一个例子mediaserver@main_mediaserver.cpp的徏立过E?/p>
int main(int argc, char** argv) { sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); LOGI("ServiceManager: %p", sm.get()); AudioFlinger::instantiate(); MediaPlayerService::instantiate(); CameraService::instantiate(); AudioPolicyService::instantiate(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); } 我们代码向下展开了一层,更能看到事物的本质?/p>
int main(int argc, char** argv) { sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); defaultServiceManager()->addService(String16("media.audio_flinger"), new AudioFlinger()); … ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); } Q?Q服务进E徏立了ProcessState对象Qƈ给对象登记在进E的上下文中?/p>
Q?Q徏立一个新AudioFlinger对象Qƈ对象登记Service Manager Service中?/p>
Q?Q开始就收请求,处理hQ应{这个@环闭合框架?/p>
2.2 Android Service Androids service是系l二阶段QInit2Q初始化时徏立的服务?/p>
Android的所有服务@环框枉是徏立SystemServer@(SystemServer.javaQ上。在SystemServer.java中看不到循环l构Q只是可以看到徏立了init2的实现函敎ͼ建立了一大堆服务QƈAddService到service Manager?/p>
main() @ com/android/server/SystemServer { init1(); } Init1()是在NativeI间实现的(com_andoird_server_systemServer.cppQ。我们一看这个函数就知道了,原来q个闭合循环处理框架在这里: init1->system_init() @System_init.cpp 在system_init()我们看到了这个久q的循环闭合理框架?/p>
{ Call "com/android/server/SystemServer", "init2" ….. ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); } Init2()@SystemServer.java中徏立了Android中所有要用到的服务: Entropy Service Power Manager Activity Manager Telephony Registry Package Manager Account Manager Content Manager System Content Providers Battery Service Hardware Service Alarm Manager Init Watchdog Sensor Service Window Manager Bluetooth Service statusbar Clipboard Service Input Method Service NetStat Service Connectivity Service Accessibility Manager Notification Manager Mount Service Device Storage Monitor Location Manager Search Service Checkin Service Wallpaper Service Audio Service Headset Observer Backup Service AppWidget Service 3 ProcessState和IPCThreadState 从宏观来ԌPocessState及其IPCThreadState处于IPC与内核打交道包装层。前面的章节已经提到Q下面我更详细的分析。有关IPC的c++I间的实现都是从ProcessStateq个对象完成的?/p>
我们可以得出如下的结论:不管JVM的Binder做了多么复杂的操作,最l还是需要利用ProcessState q个c++I间的对象把数据传递给Binder DriverQ接收数据也是通过ProcessStateq个对象完成QProcessState是所有Binder IPC必经的通道?/p>
ProcessState攄在全局变量gProcess中,每个q程只有一个ProcessState对象Q负责打开Binder讑֤驱动Q徏立线E池{。而IPCThreadState每个U程有一个,IPCThreadState实例登记在LinuxU程E的上下文附属数据中Q主要负责Binder数据dQ写入和h处理框架。IPCThreadSate在构造的时候,获取q程的ProcessSateq记录在自己的成员变量mProcess?通过mProcess可以获取到Binder的句柄?/p>
3.1 ProcessState的生命周?/p>
既然ProcessState是Binder通讯的基Q那么Process必须在Binder通讯之前建立。客LQ服务端都必d立。由于现在重点讨论服务端Q所以重心放|在服务端。在Android体系中有c++I间的服务,JVMI间的服务,q两cL务在本质上相同的Q只是Ş式上不同Q由于他们都是徏立在QͽocessStateq个基础上,所以在形式上不同就仅仅表现在对OnTransact的回调处理的不同?/p>
Native Service 我们直接可以看到使用sp<ProcessState> proc(ProcessState::self())Q徏立徏立ProcessStateQ一旦调用ProcessState徏立了Qƈ且这个selfProcessSate登记在全局变量中?/p>
Android Service 建立Android Service服务system_init @System_init.cpp中我们可以看到相同的l构。有一点不同的是所有的Android Service都运行在一个进E中Qsystemseverq程?/p>
3.2 Binder Driver包装 @IPCThreadState ProcessSate构造的时候,使用open_binder打开/driver/binderQƈ句柄记录在mDriverFDQ在ProcessState中ƈ不用这个句柄,真正使用q个Binder讑֤句柄的是IPCThreadStateQ所有关于Binder的操作放|在IPCThreadState中: (1)d/写入QtalkWithDriverQ)@IPCThreadState对ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)q行包装?/p>
(2)h处理QexecuteCommand(...)@ IPCThreadState (3)循环l构QjoinThreadPool() joinThreadPool() { While(1){ talkWithDriver(...) ... executeCommand(...) } } 众所周知Qandroid的主界面名ؓ laucher2Q功能强大,会在android启动之后q行Q也是所有其他应用程序的入口E序。那么,如何让自q应用E序取代laucher2的位 |,成ؓandroidpȝ的主界面呢?其实说出来很单,接下来,我就来ؓ大家揭开q其中的秘面纱?/p> 首先Q我们来看看一个普通的应用E序的intent声明Q?/p>
]]>
]]>
]]>
]]>
]]>
]]>
http://gitorious.org/0xdroid/packages_apps_phone/trees/5f6f01ecda4336dfb47108e67ff909a65f14b820/src/com/android/phone
]]>
]]>
]]>
]]>
]]>
]]>
Intent妙用之编写自qandroidȝ?/strong>
是不是看着很眼熟呢Q没错了Q这D代码是在AndroidManifest.xml中相应activity的intent声明Q相信大家目前羃写的应用E序的intent声明无一例外都是q样的吧。可能很多h都会对着两行代码有下面的理解Q?p>W二?span style="line-height: 18px; "><action android:name="android.intent.action.MAIN" />表示q个activity是当前应用程序的主activityQ而第二行表示当前activity在lancher中加载?/span>
q么理解的却是没错,但事实上Q有更加单的理解方式。这里请容许我先卖个兛_。我们l往下看?/span>
既然是想让我们自q应用E序取代laucher的位|,那么我们来看一下lancher的intent声明是怎么L吧:
大家看出q两个intent声明之间的差别了吗?没错Q当出现 <category android:name="android.intent.category.HOME"/> 的时候,我们的应用程序就会变成跟lancherh相同功能的(当然Q我指的仅仅是主界面Qlaucher的功能是在是太强大了Q,成ؓ androidpȝ的主界面Qƈ且,当我们按下Home键的时候,会出C个选择界面Q是不是发现你的应用E序和laucher同时出现在了选择框中呢? 如果是,那么恭喜你,从功能上来说Q你已经实现了。如果没有看刎ͼ请email我louiswangbing@gmail.com?/span>
但是Q所谓一׃容二虎,同时有两个主界面存在当然不是我们惌的?/span>
?果你有android源代码的话,你甚臛_以把laucher删掉Q直接将你自q应用E序~译到androidpȝ中,q样Q系l启动的时候就会直接运 行你的应用程序,而你的应用程序就会堂而皇之地鸠占鹊l(f)Q顺理成章的成ؓpȝ的主界面Qƈ且当你按下Home键的时候,׃跛_你的应用E序的主 activity了!Q?/span>
如果你只是一个功能上的追求者,那么看到q里你就可以xq个面去试试上面的功能了?/span>
如果你是一个好奇心比较强的人,那么误着我l往下看?/span>
刚才我说q,intent声明的理解问题。事实上Q你可以有更好的理解方式Q当Ӟq要建立在你对androidpȝ的启动进E有一定的了解的基上?/span>
单来_intent其实是一个条件过滤器Qactivity的intent声明的每一条都可以作ؓ一个过滤条Ӟ条目多Q过滤条件也p强,定位?来也pҎ(gu)。相信这个原理学q数据库的朋友理解v来更加容易。你可以整个androidpȝ中所有的activity都集中v来当成是一个数据库Q?intent本n是一条select语句Q其中每一声明都是一过滤条Ӟ而过滤之后剩下的Q就是将要被调用的activity。当qo条g_强大 或者过滤条件比较特D的时候,最后剩下的只有一个activityQ那么系l会毫不犹U地启动它Q当qo条g不Dqo之后q剩下比较多?activity的时候,pȝ会将满q些条g的所有的activity用一个listview列出来让你选择?/span>
怿原理大家都已l很清楚了,那么上面所q的q个功能很好理解了。没错,android在启动的时候会有一个PackageManager选择pȝ中满滤条Ӟ
有时候真的,生活跟计机Q居然有如此之多的相g?.....
Android开发组?#8212;—Intent
Intent提供了一U通用的消息系l,允许你的应用E序与其它的应用E序间传逺ntent来执行动作和产生事g。通过使用Intent可以ȀzAndroid应用的三个核心组Ӟzd、服务和q播接收器?/p>
Intent 的意思是意图Q也是说App通过Intent向android表达自己的意囑֍惛_什么,惛_动另一个Activity或者去调用其它的App{?{;Intentfilter反应了AppҎ(gu)囄响应能力Q比如书上的例子拨号E序Q在自己的App中声明一个Intentfilter对这个动作意?q行相应Q这样当我们按下拨号键时Qandroid׃在所用的Intentfilter中找到合适的App来满?/p>
¥ Intent的分c?/strong>
Ø 昄意图Q?/p>
调用Intent.setComponent()或Intent.setClass()Ҏ(gu)明确指定了组件名的Intent为显C意图,明确指定了Intent应该传递到哪个lg?/p>
Ø 隐式意图
没有明确指定lg名的Intent为隐式意图。Androidpȝ会根据隐式意图中讄的动作、类别、数据找到最适合的组件来处理q个意图
¥ IntentI竟是什?/strong>
?们可以将Intent看成是Activity通信的标准的。比如Intent中的内容告诉了系l激发Intent的Activity需要什么服务,而服?者Activity应该满的条件。然后就是Androidpȝ的事了,它负责找出符合条件的Activity服务者,q将Intentl?Activity服务者,然后q个ActivityҎ(gu)Intent中剩余的信息做出相应的操作。由上面可知QIntent包含两部分信息:
Ø Activity服务者的信息Q这个是lAndroid用来扑ֈ合适Activity的?/p>
Ø Activity服务者要做什么操作的信息Q这个是lActivity服务者用的?/p>
¥ Intent
Android 中提供了Intent机制来协助应用间的交互与通讯QIntent负责对应用中一ơ操作的动作、动作涉及数据、附加数据进行描qͼAndroid则根据此 Intent的描qͼ负责扑ֈ对应的组ӞIntent传递给调用的组Ӟq完成组件的调用。Intent不仅可用于应用程序之_也可用于应用E序?部的Activity/Service之间的交互。因此,Intent在这里v着一个媒体中介的作用Q专门提供组件互相调用的相关信息Q实现调用者与被调 用者之间的解耦?/p>
¥ Intent的属?/strong>
Ø Action
表示要执行的动作Q当然也可以自定义动作,q可定义相应的Activity
来处理我们的自定义动作?/p>
Ø Data
也就是执行动作要操作的数据。Android中采用指向数据的一个URI
来表C。如在联pMh应用中,一个指向某联系人的URI可能?content://contacts/1。对于不同的动作Q其URI数据的类型是不同的(可以讄type属性指定特定类型数据)Q如ACTION_EDIT指定Data为文件URIQ打?sh)话?a href="tel:URI">tel:URIQ访问网lؓhttp:URIQ而由content provider提供的数据则为content:URIs?/p>
如果动作字段是ACTION_EDITQ数据字D包含将昄用于~辑的文
档的URIQ如果动作时ACTION_CALL。数据字D将是一?a href="tel:URI%E5%92%8C%E5%B0%86%E6%8B%A8">tel:URI和将?/a> 打的LQ如果动作是ACTION_VIEWQ数据字D|一个http:URIQ接收活动将被调用去下蝲和显CURI指向的数据?/p>
Ø Type
数据cdQ显C指定Intent的数据类型(MIMEQ。一般Intent的数?/p>
cd能够Ҏ(gu)数据本nq行判断Q但是通过讄q个属性,可以强制采用昑ּ指定的类型而不再进行推对{?/p>
Ø Category
被执行动作的附加信息。例如LAUNCHER_CATEGORY表示intent的接
?者应该在Launcher中作为顶U应用出玎ͼ而ALTERNATIVE_CATEGORY表示当前的Intent是一pd的可选动作中的一个,q些动作 可以在同一数据上执行。Alternative表明Q这个Activity可以变成OptionMenuQ供其他Activity直接调用?/p>
Ø Component
指定Intent的目标组件的cdU。通常Android会根据Intent中包?/p>
?其它属性的信息Q比如action、data/type、categoryq行查找Q最l找C个与之匹配的目标lg。但是,如果componentq个 属性有指定的话Q将直接使用它指定的lgQ而不再执行上q查找过E。指定了q个属性以后,Intent的其它所有属性都是可选的?/p>
Ø Extra
是其它所有附加信息的集合。用extras可以为组件提供扩展信息,
比如Q如果要执行“发送电(sh)子邮?#8221;q个动作Q可以将?sh)子邮g的标题、正文等保存在extras里,传给?sh)子邮g发送组件?/p>
Android需要解析的是那些隐式IntentQ通过解析Q将Intent映射l可?/p>
处理此Intent的Activity、IntentReceiver或Service。Intent解析机制主要是?/p>
q查扑ַ注册在AndroidManifest.xml中的所有IntentFilter及其中定义的IntentQ?/p>
最l找到匹配的Intent。在q个解析q程中,Android是通过Intent的action?/p>
type、categoryq三个属性来q行判断Q判断方法如下:
@ 如果Intent指定了actionQ则目标lg的IntentFilter的action列表中就必须包含有这个actionQ否则就不能匚w?/p>
@ 如果Intent没有提供typeQ系l将从data中得到数据类型。和action一P目标lg的数据类型列表中必须包含Intent的数据类型,否则不能匚w?/p>
@ 如果Intent中的数据不是contentQ类型的URIQ而且Intent也没有明指定它的typeQ将Ҏ(gu)Intent中数据的schemeQ比 如http:或者mailto:Q进行匹配。同上,Intent的scheme必须出现在目标组件的scheme列表中?/p>
@ 如果Intent指定了一个或多个categoryQ这些类别必d部出现在lg的类别列表中。比如Intent中包含了两个cd:LAUNCHER_CATEGORY和ALTERNATIVE_CATEGORYQ解析得到的目标lg必须臛_包含q两个类别?/p>
当匹配一个intentC个能够处理数据的lgQ通常知道数据的类型(?/p>
的MIME cdQ和它的URI很重要。例如,一个组件能够显C图像数据,不应该被调用L放一个音频文件?/p>
在许多情况下Q数据类型能够从URI中推,特别是content:URIs,它表
C?位于讑֤上的数据且被内容提供?content provider)控制。但是类型也能够昄地设|,setData()Ҏ(gu)指定数据的URIQsetType()指定MIMEc?型,setDataAndType()指定数据的URI和MIMEcd。通过getData()dURIQgetType()dcd?/p>
¥ Intentqo?/strong>
zd、服务、广播接收者ؓ了告知系l能够处理哪些隐式IntentQ它?/p>
?以有一个或多个intentqo器。每个过滤器描述lg的一U能力,即乐意接收的一lIntent。实际上Q它{掉不想要的IntentsQ也仅仅是不?要的隐式Intents。一个显CIntentL能够传递到它的目标lgQ不它包含什么;不考虑qo器。但是一个隐式IntentQ仅当它能够通过l?件的qo器之一才能够传递给它?/p>
一个组件能够做的每一工作有独立的qo器,例如Q记事本中的NoteEditerzd有两个过滤器Q一个是启动一个指定的记录Q用户可以查看和~辑Q另一个是启动一个新的、空的记录,用户能够填充q保存?/p>
一 个intentqo器是一个IntentFiltercȝ实例。因为Androidpȝ在启动一个组件之前必ȝ道它的能力,但是intentqo器通常 不在java代码中设|,而是在应用程序的清单文g(AndroidManifest.xml)中设|。但是有一个例外,q播接收者的qo器通过调用 Context.registerReceiver()动态地注册Q它直接创徏一个IntentFilter对象?/p>
一 个过滤器有对应于Intent对象的动作、数据、种cȝ字段。过滤器要检隐式Intent的所有这三个字段Q其中Q何一个失败,Androidpȝ都不 会传逺ntentl组件。然而,因ؓ一个组件可以有多个Intentqo器,一个Intent通不q组件的qo器检,其它的过滤器可能通过?/p>
一个过滤器必须臛_包含一?lt;action>子元素,否则它将d所有的Intents?/p>
要通过,Intent对象中指定的动作必须匚wqo器的动作列表中的一个。如果对象或qo器没有指定一个动作,l果如下:
如果qo器没有指定动作,没有一个Intent匹配,所有的Intent检失败,x有intent能够通过qo器?/p>
如果Intent对象没有指定动作Q将自动通过查(只要qo器至有一个过滤器Q否则就是上面的情况了)
对于一个Intent要通过U类,Intent对象中的每个U类必须匚wq?/p>
滤器中的一个。即qo器能够列出额外的U类Q但是Intent对象中的U类都必能够在qo器中扑ֈQ只有一个种cdqo器列表中没有Q就种cL失?
因此原则上如果一个Intent对象中没有种c(即种cdDؓI)应该?/p>
?通过U类试Q而不过滤器中有什么种cR但是有个例外,Android对待所有传递给Context.startActivity()的隐?Intent好像它们臛_包含”android.intent.category.DEFAULT”(对应CATEGORY_DEFAULT帔R)。因 此,zd惌接收隐式Intent必须要在Intentqo器中包含”android.intent.category.DEFAULT”?/p>
Intents对照着Intentqo器匹配,不仅dC个目标组件去Ȁz,而且
?发现讑֤上的lg的其他信息。例如,Androidpȝ填充应用E序启动列表Q最高层屏幕昄用户能够启动的应用程序:是通过查找所有的包含指定 ?#8221;android.intent.action.MAIN”的动作和”android.intent.category.LAUNCHER” U?nbsp; cȝqo器的zdQ然后在zd列表中显C些活动的图标和标{。类似的Q?nbsp; 它通过查找”android.intent.category.HOME”qo器的zd发掘主菜单?/p>
¥ IntentCZ
要实C个Activity的蟩转,我们可以要跌{的Activitycdl定?/p>
Intent对象中,然后通过startActivityҎ(gu)ȀzIntent对象中所指定的ActivityQ关键代码如下: