这个例子源自ActivityManagerService,我们试图通过它揭示Java层Binder的工作原理。先来描述一下该例子的分析步骤:
- 首先分析AMS如何将自己注册到ServiceManager。
- 然后分析AMS如何响应客户端的Binder调用请求。
本例的起点是setSystemProcess,其代码如下所示:
**ActivityManagerService.java-->ActivityManagerService.setSystemProcess()**
```
public static void setSystemProcess() {
try {
ActivityManagerService m = mSelf;
// 将ActivityManagerService服务注册到ServiceManager中
ServiceManager.addService("activity", m);......
} catch {... }
return;
}
```
上面所示代码行的目的是将ActivityManagerService服务(以后简称AMS)加到ServiceManager中。
在整个Android系统中有一个Native的ServiceManager(以后简称SM)进程,它统筹管理Android系统上的所有Service。成为一个Service的首要条件是先在SM中注册。下面来看Java层的Service是如何向SM注册的。
#### 1. 向ServiceManager注册服务
##### (1)创建ServiceManagerProxy
向SM注册服务的函数叫addService,其代码如下:
**ServiceManager.java-->ServiceManager.addService()**
```
public static void addService(String name, IBinderservice) {
try {
//getIServiceManager返回什么
getIServiceManager().addService(name, service);
}
......
}
```
首先需要搞清楚getIServiceManager()方法返回的是一个什么对象呢?参考其实现:
**ServiceManager.java-->ServiceManager.getIServiceManager()**
```
private static IServiceManagergetIServiceManager() {
......
// 调用asInterface,传递的参数类型为IBinder
sServiceManager = ServiceManagerNative.asInterface(
BinderInternal.getContextObject());
returnsServiceManager;
}
```
asInterface()方法的参数为BinderInternal.getContextObject()的返回值。于是这个简短的方法中有两个内容值得讨论:BinderInternal.getContextObject()以及asInterface()。
BinderInternal.getContextObject()方法是一个native的函数,参考其实现:
**android_util_Binder.cpp-->android_os_BinderInternal_getContextObject()**
```
static jobjectandroid_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
/* 下面这句代码在卷I第6章详细分析过,它将返回一个BpProxy对象,其中
NULL(即0,用于标识目的端)指定Proxy通信的目的端是ServiceManager*/
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
// 由Native对象创建一个Java对象,下面分析该函数
returnjavaObjectForIBinder(env, b);
}
```
可见,Java层的ServiceManager需要在Native层获取指向Native进程中ServiceManager的BpProxy。这个BpProxy不能由Java层的ServiceManager直接使用,于是android\_os\_BinderInteral\_getContextObject()函数通过javaObjectForIBinder()函数将创建一个封装了这个BpProxy的一个Java对象并返回给调用者。ServiceManager便可一通过这个Java对象实现对BpProxy的访问。参考这个Java对象的创建过程:
**android_util_Binder.cpp-->javaObjectForIBinder()**
```
jobject javaObjectForIBinder(JNIEnv* env, constsp<IBinder>& val)
{
//mProxyLock是一个全局的静态CMutex对象
AutoMutex _l(mProxyLock);
/* val对象实际类型是BpBinder,读者可自行分析BpBinder.cpp中的findObject函数。
事实上,在Native层的BpBinder中有一个ObjectManager,它用来管理在Native BpBinder
上创建的Java BpBinder对象。下面这个findObject用来判断gBinderProxyOffsets
是否已经保存在ObjectManager中。如果是,那就需要删除这个旧的object */
jobjectobject = (jobject)val->findObject(&gBinderProxyOffsets);
if(object != NULL) {
jobject res = env->CallObjectMethod(object,gWeakReferenceOffsets.mGet);
android_atomic_dec(&gNumProxyRefs);
val->detachObject(&gBinderProxyOffsets);
env->DeleteGlobalRef(object);
}
// **① 创建一个新的BinderProxy对象。**并将它注册到Native BpBinder对象的ObjectManager中
object =env->NewObject(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mConstructor);
if(object != NULL) {
/* ② 把Native层的BpProxy的指针保存到BinderProxy对象的成员字段mObject中。
于是BinderProxy对象的Native方法可以通过mObject获取BpProxy对象的指针。
这个操作是将BinderProxy与BpProxy联系起来的纽带 */
env->SetIntField(object, gBinderProxyOffsets.mObject,(int)val.get());
val->incStrong(object);
jobject refObject = env->NewGlobalRef(
env->GetObjectField(object, gBinderProxyOffsets.mSelf));
/* 将这个新创建的BinderProxy对象注册(attach)到BpBinder的ObjectManager中,
同时注册一个回收函数proxy_cleanup。当BinderProxy对象撤销(detach)的时候,
该函数会被调用,以释放一些资源。读者可自行研究proxy_cleanup函数*/
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);
//DeathRecipientList保存了一个用于死亡通知的list
sp<DeathRecipientList> drl = new DeathRecipientList;
drl->incStrong((void*)javaObjectForIBinder);
//将死亡通知list和BinderProxy对象联系起来
env->SetIntField(object, gBinderProxyOffsets.mOrgue,
reinterpret_cast<jint>(drl.get()));
// 增加该Proxy对象的引用计数
android_atomic_inc(&gNumProxyRefs);
/*下面这个函数用于垃圾回收。创建的Proxy对象一旦超过200个,该函数
将调用BinderInter类的ForceGc做一次垃圾回收 */
incRefsCreated(env);
}
returnobject;
}
```
BinderInternal.getContextObject的代码有点多,简单整理一下,可知该函数完成了以下两个工作:
- 创建了一个Java层的BinderProxy对象。
- 通过JNI,该BinderProxy对象和一个Native的BpProxy对象挂钩,而该BpProxy对象的通信目标就是ServiceManager。
接下来讨论asInterface()方法,大家还记得在Native层Binder中那个著名的interface\_cast宏吗?在Java层中,虽然没有这样的宏,但是定义了一个类似的函数asInterface。下面来分析ServiceManagerNative类的asInterface函数,其代码如下:
**ServiceManagerNative.java-->ServiceManagerNative.asInterface()**
```
static public IServiceManager asInterface(IBinderobj)
{
......// 以obj为参数,创建一个ServiceManagerProxy对象
returnnew ServiceManagerProxy(obj);
}
```
上面代码和Native层interface\_cast非常类似,都是以一个BpProxy对象为参数构造一个和业务相关的Proxy对象,例如这里的ServiceManagerProxy对象。ServiceManagerProxy对象的各个业务函数会将相应请求打包后交给BpProxy对象,最终由BpProxy对象发送给Binder驱动以完成一次通信。
**说明** 实际上BpProxy也不会直接和Binder驱动交互,真正和Binder驱动交互的是IPCThreadState。
##### (2)addService函数分析
现在来分析ServiceManagerProxy的addService函数,其代码如下:
**ServcieManagerNative.java-->ServiceManagerProxy.addService()**
```
public void addService(String name, IBinderservice)
throwsRemoteException {
Parceldata = Parcel.obtain();
Parcelreply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
// 注意下面这个writeStrongBinder函数,后面我们会详细分析它
data.writeStrongBinder(service);
/*mRemote实际上就是BinderProxy对象,调用它的transact,将封装好的请求数据
发送出去 *
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
```
BinderProxy的transact,是一个native函数,其实现函数的代码如下所示:
**android_util_Binder.cpp-->android_os_BinderProxy_transact()**
```
static jbooleanandroid_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj,
jobject replyObj, jint flags)
{
......
// 从Java的Parcel对象中得到作为参数的Native的Parcel对象
Parcel*data = parcelForJavaObject(env, dataObj);
if (data== NULL) {
return JNI_FALSE;
}
// 得到一个用于接收回复的Parcel对象
Parcel*reply = parcelForJavaObject(env, replyObj);
if(reply == NULL && replyObj != NULL) {
return JNI_FALSE;
}
// 从Java的BinderProxy对象中得到之前已经创建好的那个Native的BpBinder对象
IBinder*target = (IBinder*)
env->GetIntField(obj, gBinderProxyOffsets.mObject);
......
// 通过Native的BpBinder对象,将请求发送给ServiceManager
status_terr = target->transact(code, *data, reply, flags);
......
signalExceptionForError(env,obj, err);
returnJNI_FALSE;
}
```
看了上面的代码会发现,Java层的Binder最终还是要借助Native的Binder进行通信的。
* * * * *
**说明** 从架构的角度看,在Java中搭建了一整套框架,如IBinder接口,Binder类和BinderProxy类。但是从通信角度看,不论架构的编写采用的是Native语言还是Java语言,只要把请求传递到Binder驱动就可以了,所以通信的目的是向binder发送请求和接收回复。在这个目的之上,考虑到软件的灵活性和可扩展性,于是编写了一个架构。反过来说,也可以不使用架构(即没有使用任何接口、派生之类的东西)而直接和binder交互,例如ServiceManager作为Binder的一个核心程序,就是直接读取/dev/binder设备,获取并处理请求。从这一点上看,Binder的目的虽是简单的(即打开binder设备,然后读请求和写回复),但是架构是复杂的(编写各种接口类和封装类等)。我们在研究源码时,一定要先搞清楚目的。实现只不过是达到该目的的一种手段和方式。脱离目的的实现,如缘木求鱼,很容易偏离事物本质。
* * * * *
在对addService进行分析时曾提示writeStrongBinder是一个特别的函数。那么它特别在哪里呢?下面将给出解释。
##### (3)三人行之Binder、JavaBBinderHolder和JavaBBinder
ActivityManagerService从ActivityManagerNative类派生,并实现了一些接口,其中和Binder的相关的只有这个ActivityManagerNative类,其原型如下:
**ActivityManagerNative.java-->ActivityManagerNative**
```
public abstract class ActivityManagerNative
extends Binder
implementsIActivityManager
```
ActivityManagerNative从Binder派生,并实现了IActivityManager接口。下面来看ActivityManagerNative的构造函数:
**ActivityManagerNative.java-->ActivityManagerNative.ActivityManagerNative()**
```
public ActivityManagerNative() {
attachInterface(this, descriptor);// 该函数很简单,读者可自行分析
}
```
而ActivityManagerNative父类的构造函数则是Binder的构造函数:
**Binder.java-->Binder.Binder()**
```
public Binder() {
init();
}
```
Binder构造函数中会调用native的init函数,其实现的代码如下:
**android_util_Binder.cpp-->android_os_Binder_init()**
```
static void android_os_Binder_init(JNIEnv* env,jobject obj)
{
// 创建一个JavaBBinderHolder对象
JavaBBinderHolder* jbh = new JavaBBinderHolder();
bh->incStrong((void*)android_os_Binder_init);
// 将这个JavaBBinderHolder对象保存到Java Binder对象的mObject成员中
env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
}
```
从上面代码可知,Java的Binder对象将和一个Native的JavaBBinderHolder对象相关联。那么,JavaBBinderHolder是何方神圣呢?其定义如下:
**android_util_Binder.cpp-->JavaBBinderHolder**
```
class JavaBBinderHolder : public RefBase
{
public:
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if(b == NULL) {
// 创建一个JavaBBinder,obj实际上是Java层中的Binder对象
b = new JavaBBinder(env, obj);
mBinder = b;
}
return b;
}
......
private:
Mutex mLock;
wp<JavaBBinder> mBinder;
};
```
从派生关系上可以发现,JavaBBinderHolder仅从RefBase派生,所以它不属于Binder家族。Java层的Binder对象为什么会和Native层的一个与Binder家族无关的对象绑定呢?仔细观察JavaBBinderHolder的定义可知:JavaBBinderHolder类的get函数中创建了一个JavaBBinder对象,这个对象就是从BnBinder派生的。
那么,这个get函数是在哪里调用的?答案在下面这句代码中:
```
//其中,data是Parcel对象,service此时还是ActivityManagerService
data.writeStrongBinder(service);
```
writeStrongBinder会做一个替换工作,下面是它的native代码实现:
**android_util_Binder.cpp-->android_os_Parcel_writeStrongBinder()**
```
static voidandroid_os_Parcel_writeStrongBinder(JNIEnv* env,
jobject clazz, jobject object)
{
/*parcel是一个Native的对象,writeStrongBinder的真正参数是
ibinderForJavaObject()的返回值*/
conststatus_t err = parcel->writeStrongBinder(
ibinderForJavaObject(env, object));
}
[android_util_Binder.cpp-->ibinderForJavaObject()]
sp<IBinder> ibinderForJavaObject(JNIEnv*env, jobject obj)
{
/* 如果Java的obj是Binder类,则首先获得JavaBBinderHolder对象,然后调用
它的get()函数。而这个get将返回一个JavaBBinder */
if(env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)env->GetIntField(obj,
gBinderOffsets.mObject);
return jbh != NULL ? jbh->get(env, obj) : NULL;
}
// 如果obj是BinderProxy类,则返回Native的BpBinder对象
if(env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return (IBinder*)
env->GetIntField(obj, gBinderProxyOffsets.mObject);
}
returnNULL;
}
```
根据上面的介绍会发现,addService实际添加到Parcel的并不是AMS本身,而是一个叫JavaBBinder的对象。正是将它最终传递到Binder驱动。
读者此时容易想到,Java层中所有的Binder对应的都是这个JavaBBinder。当然,不同的Binder对象对应不同的JavaBBinder对象。
图2-2展示了Java Binder、JavaBBinderHolder和JavaBBinder的关系。
:-: ![](http://img.blog.csdn.net/20150806154325282?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图 2 - 2 Java Binder 、JavaBBinderHolder和JavaBBinder三者的关系
从图2-2可知:
- Java层的Binder通过mObject指向一个Native层的JavaBBInderHolder对象。
- Native层的JavaBBinderHolder对象通过mBinder成员变量指向一个Native的JavaBBinder对象。
- Native的JavaBBinder对象又通过mObject变量指向一个Java层的Binder对象。
为什么不直接让Java层的Binder对象指向Native层的JavaBBinder对象呢?由于缺乏设计文档,这里不便妄加揣测,但从JavaBBinderHolder的实现上来分析,估计和垃圾回收(内存管理)有关,因为JavaBBinderHolder中的mBinder对象的类型被定义成弱引用wp了。
>[info] **建议** 对此有更好的解释的读者,不妨与大家分享一下。
#### 2. ActivityManagerService响应请求
初见JavaBBinde时,多少有些吃惊。回想一下Native层的Binder架构:虽然在代码中调用的是Binder类提供的接口,但其对象却是一个实际的服务端对象,例如MediaPlayerService对象,AudioFlinger对象。
而在Java层的Binder架构中,JavaBBinder却是一个和业务完全无关的对象。那么,这个对象如何实现不同业务呢?
为回答此问题,我们必须看它的onTransact函数。当收到请求时,系统会调用这个函数。
说明 关于这个问题,建议读者阅读卷I第6章“深入理解Binder”。
**android_util_Binder.cpp-->JavaBBinder::onTransact()**
```
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags =0)
{
JNIEnv*env = javavm_to_jnienv(mVM);
IPCThreadState* thread_state = IPCThreadState::self();
.......
// 调用Java层Binder对象的execTranscat函数
jbooleanres = env->CallBooleanMethod(mObject,
gBinderOffsets.mExecTransact,code,
(int32_t)&data, (int32_t)reply, flags);
......
returnres != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}
```
就本例而言,上面代码中的mObject就是ActivityManagerService,现在调用它的execTransact()方法,该方法在Binder类中实现,具体代码如下:
**Binder.java-->Binder.execTransact()**
```
private boolean execTransact(int code, intdataObj, int replyObj,int flags) {
Parceldata = Parcel.obtain(dataObj);
Parcelreply = Parcel.obtain(replyObj);
booleanres;
try {
//调用onTransact函数,派生类可以重新实现这个函数,以完成业务功能
res= onTransact(code, data, reply, flags);
} catch{ ... }
reply.recycle();
data.recycle();
returnres;
}
```
ActivityManagerNative类实现了onTransact函数,代码如下:
**ActivityManagerNative.java-->ActivityManagerNative.onTransact()**
```
public boolean onTransact(int code, Parcel data,Parcel reply, int flags)
throws RemoteException {
switch(code) {
caseSTART_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
......
//再由ActivityManagerService实现业务函数startActivity
intresult = startActivity(app, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded, debug, profileFile,
profileFd, autoStopProfiler);
reply.writeNoException();
reply.writeInt(result);
return true;
}
.... // 处理其他请求的case
}
}
```
由此可以看出,JavaBBinder仅是一个传声筒,它本身不实现任何业务函数,其工作是:
- 当它收到请求时,只是简单地调用它所绑定的Java层Binder对象的exeTransact。
- 该Binder对象的exeTransact调用其子类实现的onTransact函数。
- 子类的onTransact函数将业务又派发给其子类来完成。请读者务必注意其中的多层继承关系。
通过这种方式,来自客户端的请求就能传递到正确的Java Binder对象了。图2-3展示AMS响应请求的整个流程。
:-: ![](http://img.blog.csdn.net/20150806154338652?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图 2 - 3 AMS响应请求的流程
在图2-3中,右上角的大方框表示AMS这个对象,其间的虚线箭头表示调用子类重载的函数。
- 前言
- 推荐序
- 第1章 开发环境部署
- 1.1获取Android源代码
- 1.2Android的编译
- 1.3在IDE中导入Android源代码
- 1.3.1将Android源代码导入Eclipse
- 1.3.2将Android源代码导入SourceInsight
- 1.4调试Android源代码
- 1.4.1使用Eclipse调试Android Java源代码
- 1.4.2使用gdb调试Android C/C 源代码
- 1.5本章小结
- 第2章 深入理解Java Binder和MessageQueue
- 2.1概述
- 2.2Java层中的Binder分析
- 2.2.1Binder架构总览
- 2.2.2初始化Java层Binder框架
- 2.2.3窥一斑,可见全豹乎
- 2.2.4理解AIDL
- 2.2.5Java层Binder架构总结
- 2.3心系两界的MessageQueue
- 2.3.1MessageQueue的创建
- 2.3.2提取消息
- 2.3.3nativePollOnce函数分析
- 2.3.4MessageQueue总结
- 2.4本章小结
- 第3章 深入理解AudioService
- 3.1概述
- 3.2音量管理
- 3.2.1音量键的处理流程
- 3.2.2通用的音量设置函数setStreamVolume()
- 3.2.3静音控制
- 3.2.4音量控制小结
- 3.3音频外设的管理
- 3.3.1 WiredAccessoryObserver 设备状态的监控
- 3.3.2AudioService的外设状态管理
- 3.3.3音频外设管理小结
- 3.4AudioFocus机制的实现
- 3.4.1AudioFocus简单的例子
- 3.4.2AudioFocus实现原理简介
- 3.4.3申请AudioFocus
- 3.4.4释放AudioFocus
- 3.4.5AudioFocus小结
- 3.5AudioService的其他功能
- 3.6本章小结
- 第4章 深入理解WindowManager-Service
- 4.1初识WindowManagerService
- 4.1.1一个从命令行启动的动画窗口
- 4.1.2WMS的构成
- 4.1.3初识WMS的小结
- 4.2WMS的窗口管理结构
- 4.2.1理解WindowToken
- 4.2.2理解WindowState
- 4.2.3理解DisplayContent
- 4.3理解窗口的显示次序
- 4.3.1主序、子序和窗口类型
- 4.3.2通过主序与子序确定窗口的次序
- 4.3.3更新显示次序到Surface
- 4.3.4关于显示次序的小结
- 4.4窗口的布局
- 4.4.1从relayoutWindow()开始
- 4.4.2布局操作的外围代码分析
- 4.4.3初探performLayoutAndPlaceSurfacesLockedInner()
- 4.4.4布局的前期处理
- 4.4.5布局DisplayContent
- 4.4.6布局的阶段
- 4.5WMS的动画系统
- 4.5.1Android动画原理简介
- 4.5.2WMS的动画系统框架
- 4.5.3WindowAnimator分析
- 4.5.4深入理解窗口动画
- 4.5.5交替运行的布局系统与动画系统
- 4.5.6动画系统总结
- 4.6本章小结
- 第5章 深入理解Android输入系统
- 5.1初识Android输入系统
- 5.1.1getevent与sendevent工具
- 5.1.2Android输入系统简介
- 5.1.3IMS的构成
- 5.2原始事件的读取与加工
- 5.2.1基础知识:INotify与Epoll
- 5.2.2 InputReader的总体流程
- 5.2.3 深入理解EventHub
- 5.2.4 深入理解InputReader
- 5.2.5原始事件的读取与加工总结
- 5.3输入事件的派发
- 5.3.1通用事件派发流程
- 5.3.2按键事件的派发
- 5.3.3DispatcherPolicy与InputFilter
- 5.3.4输入事件的派发总结
- 5.4输入事件的发送、接收与反馈
- 5.4.1深入理解InputChannel
- 5.4.2连接InputDispatcher和窗口
- 5.4.3事件的发送
- 5.4.4事件的接收
- 5.4.5事件的反馈与发送循环
- 5.4.6输入事件的发送、接收与反馈总结
- 5.5关于输入系统的其他重要话题
- 5.5.1输入事件ANR的产生
- 5.5.2 焦点窗口的确定
- 5.5.3以软件方式模拟用户操作
- 5.6本章小结
- 第6章 深入理解控件系统
- 6.1 初识Android的控件系统
- 6.1.1 另一种创建窗口的方法
- 6.1.2 控件系统的组成
- 6.2 深入理解WindowManager
- 6.2.1 WindowManager的创建与体系结构
- 6.2.2 通过WindowManagerGlobal添加窗口
- 6.2.3 更新窗口的布局
- 6.2.4 删除窗口
- 6.2.5 WindowManager的总结
- 6.3 深入理解ViewRootImpl
- 6.3.1 ViewRootImpl的创建及其重要的成员
- 6.3.2 控件系统的心跳:performTraversals()
- 6.3.3 ViewRootImpl总结
- 6.4 深入理解控件树的绘制
- 6.4.1 理解Canvas
- 6.4.2 View.invalidate()与脏区域
- 6.4.3 开始绘制
- 6.4.4 软件绘制的原理
- 6.4.5 硬件加速绘制的原理
- 6.4.6 使用绘图缓存
- 6.4.7 控件动画
- 6.4.8 绘制控件树的总结
- 6.5 深入理解输入事件的派发
- 6.5.1 触摸模式
- 6.5.2 控件焦点
- 6.5.3 输入事件派发的综述
- 6.5.4 按键事件的派发
- 6.5.5 触摸事件的派发
- 6.5.6 输入事件派发的总结
- 6.6 Activity与控件系统
- 6.6.1 理解PhoneWindow
- 6.6.2 Activity窗口的创建与显示
- 6.7 本章小结
- 第7章 深入理解SystemUI
- 7.1 初识SystemUI
- 7.1.1 SystemUIService的启动
- 7.1.2 状态栏与导航栏的创建
- 7.1.3 理解IStatusBarService
- 7.1.4 SystemUI的体系结构
- 7.2 深入理解状态栏
- 7.2.1 状态栏窗口的创建与控件树结构
- 7.2.2 通知信息的管理与显示
- 7.2.3 系统状态图标区的管理与显示
- 7.2.4 状态栏总结
- 7.3 深入理解导航栏
- 7.3.1 导航栏的创建
- 7.3.2 虚拟按键的工作原理
- 7.3.3 SearchPanel
- 7.3.4 关于导航栏的其他话题
- 7.3.5 导航栏总结
- 7.4 禁用状态栏与导航栏的功能
- 7.4.1 如何禁用状态栏与导航栏的功能
- 7.4.2 StatusBarManagerService对禁用标记的维护
- 7.4.3 状态栏与导航栏对禁用标记的响应
- 7.5 理解SystemUIVisibility
- 7.5.1 SystemUIVisibility在系统中的漫游过程
- 7.5.2 SystemUIVisibility发挥作用
- 7.5.3 SystemUIVisibility总结
- 7.6 本章小结
- 第8章 深入理解Android壁纸
- 8.1 初识Android壁纸
- 8.2深入理解动态壁纸
- 8.2.1启动动态壁纸的方法
- 8.2.2壁纸服务的启动原理
- 8.2.3 理解UpdateSurface()方法
- 8.2.4 壁纸的销毁
- 8.2.5 理解Engine的回调
- 8.3 深入理解静态壁纸-ImageWallpaper
- 8.3.1 获取用作静态壁纸的位图
- 8.3.2 静态壁纸位图的设置
- 8.3.3 连接静态壁纸的设置与获取-WallpaperObserver
- 8.4 WMS对壁纸窗口的特殊处理
- 8.4.1 壁纸窗口Z序的确定
- 8.4.2 壁纸窗口的可见性
- 8.4.3 壁纸窗口的动画
- 8.4.4 壁纸窗口总结
- 8.5 本章小结