现在的位置: 首页 > 综合 > 正文

系统的进程通信(aidl)的实现原理

2018年04月30日 ⁄ 综合 ⁄ 共 5275字 ⁄ 字号 评论关闭
系统的进程通信,我们平时也经常用到,比如使用WifiManager,TelephonyManager,ConnectivityManager等等,他们就是通过系统的进程通信获取到的,获取系统服务的时候,需要用到getSystemService方法,
比如:ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 
我们知道activity的继承关系为:
activity---------->ContextThemeWrapper---------->ContextWrapper---------->Context
Context是个抽象类,在这个类中有个抽象方法,
 public abstract Object getSystemService(String name);
那么继承Context的这些类必然要实现这个抽象方法,ContextWrapper中就实现了这个方法,
 @Override
    public Object getSystemService(String name) {
        return mBase.getSystemService(name);
    }

ContextThemeWrapper中又重写了这个方法,
    @Override 
    public Object getSystemService(String name) { 
        if (LAYOUT_INFLATER_SERVICE.equals(name)) {
            if (mInflater == null) {
                mInflater = LayoutInflater.from(mBase).cloneInContext(this);
            }
            return mInflater;
        }
        return mBase.getSystemService(name);
    }
Activity中是没有重写这个方法的,很显然,我们在Activity中调用的getSystemService方法是ContextThemeWrapper中的方法。

我们注意到,ContextThemeWrapper的getSystemService()里面,有个 return
mBase.getSystemService(name); 
我们知道,Activity组件在启动的过程中,系统会为它创建一个ContextImpl对象,这个对象也是继承与Context的,它用来描述它的运行上下文环境。这个ContextImpl对象首先是通过调用Acitivity类的成员函数attach传递到Acticity组件内部,接着再依次通过调用父类ContextThemeWrapper和
ContextWrapper的成员函数attachBaseContext来分别保存在它们的成员变量mBase中。因 此,ContextThemeWrapper和ContextWrapper类的成员变量mBase指向的实际上是一个ContextImpl对象,而在这里,才是真正实现了
getSystemService方法
    @Override
    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
        return fetcher == null ? null : fetcher.getService(this);
    }
到这里,就涉及到了android的进程通信(aidl),我们不介绍进程通信涉及到底层的东西,我们这里只看下在java层的实现,进程之间通信的介质是binder,只不过这个binder得实现一个接口,这个接口是系统定义的,另外一个进程拿到binder对象之后,用特定的方法把binder对象转化成接口类型的对象,然后把这个接口类型的对象传递给  xxxxxManager,xxxxxManager就是对接口类型对象的封装,而这就是我们所说的服务,它本质上就是一个binder。只是做了一层封装之后叫系统服务了。

我们以ConnectivityManager为例,介绍下系统是怎么实现进程通信的。
系统的进程通信牵扯到四个类,ServiceManager    ConnectivityService    SystemServer    ContextImpl
 

ServiceManager.java :   这个类主要用来添加和获取服务,也就是添加和获取binder,
        在介绍这个类之前,必须介绍下IServiceManager接口,这个接口定义了很多有关于服务的方法,比如:
public IBinder getService(String name) throws RemoteException; 
public IBinder checkService(String name) throws RemoteException;
public void addService(String name, IBinder service, boolean allowIsolated)  throws RemoteException; 
通过ServiceManagerNative.asInterface(BinderInternal.getContextObject()) 就获取到了IServiceManager对象,这里涉及到底层了,我们不做介绍,只需要知道通过他可以获取到 IServiceManager对象。
ServiceManager里面的方法,其实就用这个IServiceManager的方法对服务进行操作的,比如:

    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }

    public static IBinder getService(String name) {
        try {
            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;
    }

    public static void addService(String name, IBinder service) {
        try {
            getIServiceManager().addService(name, service, false);
        } catch (RemoteException e) {
            Log.e(TAG, "error in addService", e);
        }
    }

ConnectivityService
这个类ConnectivityService继承于IConnectivityManager.Stub,IConnectivityManager.Stub是IConnectivityManager.aidl文件经过通过系统编译生成的,IConnectivityManager就是系统定义接口的文件,IBluetoothManager.Stub继承于binder,所以ConnectivityService就是个binder对象,负责信息间的传送,

SystemServer.java: 
这个类用来启动ServerThread这个子线程,ServerThread才是添加系统服务的地方,系统服务一般在开机启动的时候,系统已经给我们添加上了,并且这些是不对外开放的。
    connectivity = new ConnectivityService( context, networkManagement, networkStats, networkPolicy); 
    ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);

ContextImpl.java:这个类只负责注册我们的服务,
 private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
            new HashMap<String, ServiceFetcher>();
    //注册我们的服务,
    private static void registerService(String serviceName, ServiceFetcher fetcher) {
        if (!(fetcher instanceof StaticServiceFetcher)) {
            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
        }
        SYSTEM_SERVICE_MAP.put(serviceName, fetcher); //把ServiceFetcher对象存起来
    }

registerService(CONNECTIVITY_SERVICE, new StaticServiceFetcher() {
                //createStaticService是抽象方法,这儿给实现了
                public Object createStaticService() {
                    IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
                    return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));
                }});

我们看到,在registerService方法中实现了匿名类StaticServiceFetcher,这个匿名类继承了ServiceFetcher类,通过这个类才能获取到我们想要的服务,我们看看它是怎么获取的,
    abstract static class StaticServiceFetcher extends ServiceFetcher {
        private Object mCachedInstance;

        @Override
        public final Object getService(ContextImpl unused) {
            synchronized (StaticServiceFetcher.this) {
                Object service = mCachedInstance;
                if (service != null) {
                    return service;
                }
                return mCachedInstance = createStaticService();  //这儿才是我们要看的地方,
            }
        }
        public abstract Object createStaticService(); //这是个抽象方法
    }

    @Override
    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);  //获取ServiceFetcher 对象
        return fetcher == null ? null : fetcher.getService(this);  //获取对应的服务。
    }

最后,我们就在activity中,获取到了ConnectivityManager服务
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 
到此,java层的系统服务的进程通信就到此结束了。

抱歉!评论已关闭.