Android系统--ServiceManager服务

最近在学习Android内核设计思想,看书的过程中将一些小知识点积累了一下。

需要解决的问题

  1. 因为发送请求的Binder client可能是应用程序,所以必须提供Java层的==接口==(需要找出这个接口是什么)
  2. 每个调用binder服务的程序,不需要亲自去执行如下步骤,所以需要封装如下功能
    • 打开binder设备
    • 执行mmap
    • 通过binder驱动向ServiceManager发送请求
    • 返回结果
  3. 如果每次调用都必须打开servicemanager服务,那么将会消耗很多资源,所以每个进程只能打开一次Binder设备,且只做一次内存映射,所有需要使用binder驱动的线程共享这一资源

相关类的解析

序号相关内容作用
1ProcessState专门管理每个应用进程当中对应的Binder操作
2IPCThreadState与Bnder驱动进行实际命令通信
3ServiceManagerProxy接口,用来封装ServiceManeger提供的服务
4ServiceManager.java封装了3的类

1. 采用1和2两个类,已经可以实现与Binder驱动进行通信
2. 为了实现这个接口,实现对服务的获取,有以下两步要做:
- 与Binder建立联系
因为已经有了1,2两个类,所以与Binder驱动的通信实际上是通过他们来实现,因此称他们为BpBinder
- 向Binder发送命令

Binder机制的简要说明图

实现图例

ServiceManagerProxy

  1. 当想要调用getService的时候,需要先查询缓存,再向SM发送请求
    public static IBinder getService(String name) {    
        try {
            //cache结构为:private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
            //这部分的代码是8.0的代码与书上的不太一致
                return Binder.allowBlocking(getIServiceManager().getService(name));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
  1. 可以看到,当缓存里没有的时候,需要使用getIServiceManager().getService(name)来获取,而这个方法,返回的也是一个Ibinder对象
private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        sServiceManager = ServiceManagerNative
                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
        return sServiceManager;
    }

在这里可以看到,也是先检查时候已经有了IServiceManager,否则也要获取一个新的。这里又出现了一个新的类IserviceManagerNative来获取一个IserviceManager,可以看到,他传入的参数是一个BinderInternal.getContextObject()是一个IBinder的变量,通过这个变量来获取一个IserviceManager,或者再借用这个来使用ServiceManagerProxy()

static public IServiceManager asInterface(IBinder obj)
    {
        if (obj == null) {
            return null;
        }
        IServiceManager in =
            (IServiceManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }

        return new ServiceManagerProxy(obj);
    }

可以看到,作为与Binder进行交互的接口,需要使用IBinder作为SerivceManagerProxy初始化的一个参数。

public ServiceManagerProxy(IBinder remote) {
        mRemote = remote;
    }
  1. 以getService为例:
public IBinder getService(String name) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }

可以看到,主要分为三步:
- 准备数据 利用Parcel进行封装传递
- IBinder.transact 这个函数就实现了在内部使用ProcessState以及IPCThreadState与Binder进行通信
- 获取结果
4. 最后需要注意的一点就是,客户端与服务端所使用的业务代码必须一致,比如:
在IBinder当中定义的业务码为:

int FIRST_CALL_TRANSACTION  = 0x00000001;

在ISerivceManager当中定义的业务码为:

    int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
    int CHECK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
    int ADD_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
    int LIST_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
    int CHECK_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
    int SET_PERMISSION_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+5;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值