Android framework 如何添加系统服务

慕课网 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,//这点可以说明知识体系很完备

 

真正跑一个服务还要很多事情,如要修改编译,安全方面等,

 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值