慕课网 android framework 笔记
2-3 三,怎么添加一个系统服务
1,了解如何使用系统服务
2,了解系统服务调用的基本原理,服务和应用的通信过程,如何跨进程调到服务的,
3,了解服务的注册原理,服务是注册制,不是绑定的。
service注册到service manager
client要用service要先拿到service的binder,然后发起binder调用,client要怎么拿到service的binder?
典型做法,service把binder注册到固定的地方--serviceMananger,client通过名字向ServiceManager查询service的binder,然后通过binder向Service发起binder调用。
所以添加系统服务要考虑,
别人怎么能用到你的服务,怎么能用的很方便
服务怎么开放出来,让人知道
服务要支持跨进程通信,无论是与AP还是与service manager,也就是IPC,
1)如何使用系统服务?
平时我们怎么用:通过context的getSystemService函数
@Overide
public Object getSystemService(String name){
return SystemServiceRegistry.getSystemService(this, name);
}
它传入服务的名称,函数会返回服务的接口对象,
函数的实现原理是什么:
它先通过名称拿到服务对应的service fetcher,再调用service fetcher的getService拿到服务对象,
static Object getSystemService(ContextImpl ctx, String name){
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null?fetcher.getService(ctx) : null;
}
SYSTEM_SERVICE_FETCHERS是一个hashmap:HashMap<String, ServiceFetcher<?>>
根据服务的名称,到hashmap里面,查到了这个service fetcher
serviceFetcher的getService的实现:
public final T getService(ContextImpl ctx){
//这有个缓存,context里面都有一个mServiceCache,是数组的形式,缓存与context挂钩,context有几个,Servicecache有几个
final Object[] cache = ctx.mServiceCache;
synchronized(cache){
//根据cacheIndex到缓存里面取service,这个service就是系统服务的接口对象。
Object service = cacher[mCacheIndex];
//如果service非空直接返回,如果没有service就创建一个保存到CacheIndex
if(service == null){
service = createService(ctx);
cache[mCacheIndex] = service;
}
return (T)service;
}
}
再看看createService的实现,以Power Service为例,它是用来管理电源的,
看看它的createService是怎么实现的
registerService(Context.POWER_SERVICE, PowerManager.class,
new CachedSericeFetcher<PowerManager>(){
@Override
public PowerManager createService(ContextImpl ctx){
//根据service名称拿到了IBinder对象,IBinder就是一个Binder proxy
IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
//用Binder proxy又封装了一个IPowerManager类,这个是它的业务类
IPowerManager service = IPowerManager.Stub.asInterface(b);
//这里又封装了一层,new了一个PowerManager对象,
//为什么多封装一层?直接用IPowerManager的对象去调用很麻烦,因为每个函数都要catch(RemoteException)
//这里就是一个静态代理,里面的所有调用还是交给了IPowerMananger
return new PowerManager(ctx.getOuterContext(),service, ctx.mMainThread.getHandler());
}
});
再看看Service Manager的getService实现
表面看不复杂,就是一个典型的缓存机制,
public static IBinder getService(String name){
try{
//在cache里通过name拿到IBinder对象
//scache就是一个HashMap,查到了直接返回,没有就拿到ServiceMananger的Binder对象,调用它的getService返回对应的Ibinder对象。
//HashMap<String, IBinder>
IBinder service = sCache.get(name);
if(service != null){
return service;
}else{
return getIServiceManager().getService(name);
}
}catch(RemoteException e){
Log.e(TAG, "error in getService", e);
}
return null;
}
//这里的getIServiceManager是什么?
ServiceManagerNative.asInterface(BinderInternal.getContextObject());
//它先通过BinderInternal.getContextObject()获得了ServiceManager的Binder proxy对象,
//再根据它的Binder proxy对象,封装了一层Service manager的业务类
表面看是缓存,但是这个缓存没什么用,回想平时怎么用缓存,如果它没东西,在获取了对象后要塞到缓存,但是这里没有这一步,
可以做一个实验,通过反射拿到sCache,然后把这个HashMaps的所有key打印出来,就是所有系统服务的名称,
这个缓存唯一的作用,就是AP启动时,预先预制一些系统服务的binder proxy对象放到这个缓存里,之后再取的这些系统服务的binder proxy都没有丢到这个cache里面
2,如何注册系统服务?
//name是系统服务的名称,service是系统服务的binder对象,
public static void addService(String name, IBinder service){
try{
//getIServiceMananger拿到ServiceManager的binder对象,
//addService是跨进程调用,把name和service传给serviceManager,
//这里传的是系统服务的binder实体,但是ServiceManager收到的是Binder proxy对象
getIServiceManager().addService(name, service, false);
}catch(RemoteException e){
Log.e(TAG,"errot in addService",e);
}
}
3,什么时候注册系统服务
是在system server启动时,
systemServer启动:
1)启用binder机制,
2)启动各类系统服务 //很重要一步是把这些系统服务的binder对象注册到service manager里面
3)进入Loop循环
所以如果要注册系统服务,可以放到2)这个位置来做。
不是所有服务都在system server进程,小部分单独开进程:service manager, surfaceflinger , media server,
但是他们也要注册到service manager,这样别人才可以找到他们
接下来说说单开进程的服务,以SurfaceFlinger为例,说说系统服务如何启动的,
4,独立进程的系统服务
SF是native实现的系统服务,如果想考清楚底层原理,直接看native服务的实现更清晰,java层的封装太好了,一层一层看很麻烦。
看看SF的启动配置文件,
service surfaceflinger /system/bin/surfacelinger
SF的入口函数:
int main(int, char**){
//PrecessState其实是进程的单利,构造函数会启动binder机制,打开binder驱动,映射内存,分配缓冲区
sp<ProcessState> ps(ProcessState::self());
//这里启动了binder线程
ps->startThreadPool();
//这是核心对象,重要的工作都在这处理
sp<SurfaceFlinger> flinger = new SurfaceFLinger();
//初始化
flinger->init();
//获取ServiceManager的binder句柄
sp<IServiceManager> sm(defaultServiceManager());
//调addService把flinger注册到service manager里面
sm->addService(serviceName, flinger, false);
//进入loop循环
flinger->run();
return 0;
}
再看看defaultServiceManager的实现
sp<IServiceManager> defaultServiceManager(){
if(gDefaultServiceManager != NULL)
return gDefaultServiceManager;
{
AutoMutex_I(gDefaultServiceManagerLock);
while(gDefaultServiceManager == NULL){
//看下是怎么赋值,通过ProcessState的getContextObjecct
//它是getStrongProxyForHandler(0);它根据handle值0去new了一个BpBinder,
//再根据BpBinder封装了一个IServiceManager对象给上层
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getCOntextObject(NULL);
//SF是单独进程,service mananger进程,他们都是被init拉起来的,
//可能出现,获取service manager的binder对象时,service mananger还没来得及向binder驱动注册。
//所以这里循环了下,
if(gDefaultServiceManager == NULL)
sleep(1);
)
}
}
return gDefaultServiceManager;
}
无论在system server的服务,还是单独进程的服务,都要向serivce manager注册,这样AP才能使用这个服务,这就是服务的开放,
服务要跨进程通信,所以要启动binder机制,
4,启动binder机制,
不讲代码,简单说:
打开binder驱动
映射内存,分配缓冲区
启动binder线程,进入binder loop。//binder线程可以是创建一个子线程然后注册成binder线程,也可以把主线程注册成binder线程。
回头看问题,你知道怎么添加一个系统服务吗?
注意是系统服务,不是应用服务,这两个区别不懂就太不应该了。
why - 为什么添加系统服务,目的就是给别人用的,
how,怎么让别人用? 启动binder机制,就可以IPC通信了。然后开放出去,别人就可以找到他了。
what,具体要做什么
添加系统服务的时机?
如果跑在system server,可以加到system server启动系统服务的部分
如果跑在单独进程,一方面要到init.rc填启动配置,另一方面要有入口函数main
服务端要做什么?3块:
启用binder机制,如果跑在system server中不用考虑,因为它做好了,
做服务自己的init工作
服务自己的binder注册到service manager
应用端做什么?
AP调用系统服务是通过context的getSystemService,我们自己添加的服务最好和其他服务调用方式一致,所以我们要注册一个Service Fetcher,//这点可以说明知识体系很完备
真正跑一个服务还要很多事情,如要修改编译,安全方面等,