博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从Context说到Binder
阅读量:6980 次
发布时间:2019-06-27

本文共 7231 字,大约阅读时间需要 24 分钟。

前情提要

当我们在Android项目中,希望使用系统服务时,可以通过ContextgetSystemService ()方法来获得。例如,当我们想要判断当前网络状态是否可用,可以通过下面的代码实现:

public static boolean isNetworkAvailable(@NonNull Context context) {    // 获取系统服务(核心代码)    ConnectivityManager cm = (ConnectivityManager)context                            .getSystemService(Context.CONNECTIVITY_SERVICE);        if (cm != null) {            NetworkInfo info = cm.getActiveNetworkInfo();            if (info != null &&                info.isConnected() &&                info.getState() == NetworkInfo.State.CONNECTED) {                // 当前网络可用                return true;            }        }        // 当前网络不可用        return false;    }复制代码

上面的代码相对来说,还是比较简单的;核心代码就是通过getSystemService ()获取一个系统服务,后续只需调用ConnectivityManager提供的相关方法。下面我们将从getSystemService ()开始追溯,看看这个方法里面到底做了什么,竟有这样的魔力?

一. Context.getSystemService()

getSystemService()定义在\frameworks\base\core\java\android\content\Context.java文件中,方法声明如下:

public abstract Object getSystemService(@ServiceName @NonNull String name);复制代码

那么,该方法具体是在哪里实现的呢?

除了Activity中的getSystemService ()有所区别之外,其余所有的Context调用getSystemService ()时,最终都会调用ContextWrapper中的getSystemService ()

对此有疑问的小伙伴,可以参考我的另一篇文章:

1.1 Activity.getSystemService()

方法定义在\frameworks\base\core\java\android\app\Activity.java中,声明如下:

@Overridepublic Object getSystemService(@ServiceName @NonNull String name) {    // getBaseContext()获取的其实就是ContextWrapper中的成员变量mBase    if (getBaseContext() == null) {        throw new IllegalStateException(        "System services not available to Activities before onCreate()");    }​    if (WINDOW_SERVICE.equals(name)) { // 如果获取的是WindowManager,直接返回        return mWindowManager;    } else if (SEARCH_SERVICE.equals(name)) { // 如果获取的是SearchManager,直接返回        ensureSearchManager();        return mSearchManager;    }​    // 调用父类的方法    return super.getSystemService(name);}复制代码

从上面方法可以看出:

  • 当在Activity中的onCreate()生命周期之前调用getSystemService ()时,会抛出异常!因为,ContextWrapper中的成员变量mBase是在attach()方法中初始化的;

  • 当获取的是WindowManager或者SearchManager时,直接返回;

  • 最终调用父类ContextThemeWrapper中的getSystemService ()方法;

1.1.1 ContextThemeWrapper.getSystemService()

方法定义在\frameworks\base\core\java\android\view\ContextThemeWrapper.java中,声明如下:

@Override public Object getSystemService(String name) {    if (LAYOUT_INFLATER_SERVICE.equals(name)) { //如果获取的是LayoutInflater,直接返回        if (mInflater == null) {            mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);        }        return mInflater;    }    return getBaseContext().getSystemService(name);}复制代码

从上面的方法可以看出:

  • 作进一步校验,如果获取的是LayoutInflater,直接返回;

  • 调用getBaseContext()getSystemService ()方法,其实最终就是调用ContextWrapper中的成员变量mBasegetSystemService ()方法;

小结:

Activity中的getSystemService ()方法,最终会调用到ContextWrapper中的成员变量mBasegetSystemService ()方法;

1.2 ContextWrapper.getSystemService()

方法定义在\frameworks\base\core\java\android\content\ContextWrapper.java中,声明如下:

@Overridepublic Object getSystemService(String name) {    return mBase.getSystemService(name);}复制代码

由此我们发现:

  • 通过Context调用getSystemService ()时,最终都会调用到ContextWrapper中的成员变量mBasegetSystemService()方法;

  • mBase其实就是ContextImpl的实例;详见[]。

1.3 ContextImpl.getSystemService()

方法定义在\frameworks\base\core\java\android\app\ContextImpl.java中,声明如下:

@Overridepublic Object getSystemService(String name) {    return SystemServiceRegistry.getSystemService(this, name);}复制代码
1.3.1 SystemServiceRegistry.getSystemService()

方法定义在\frameworks\base\core\java\android\app\SystemServiceRegistry.java中,声明如下:

public static Object getSystemService(ContextImpl ctx, String name) {    ServiceFetcher
fetcher = SYSTEM_SERVICE_FETCHERS.get(name); // 最终调用ServiceFetcher的getService()方法 return fetcher != null ? fetcher.getService(ctx) : null;}复制代码

在该方法中,通过你传递过来的“name”,获取一个ServiceFetcher对象,最终调用的是ServiceFetcher中的getService()方法;

1.3.2 SystemServiceRegistry.SYSTEM_SERVICE_FETCHERS

SYSTEM_SERVICE_FETCHERS的定义如下:

private static final HashMap
> SYSTEM_SERVICE_FETCHERS = new HashMap
>();复制代码
1.3.3 SystemServiceRegistry.registerService()

通过搜索发现,该集合只在一个地方有存储元素的操作;代码如下:

private static 
void registerService(String serviceName, Class
serviceClass, ServiceFetcher
serviceFetcher) { SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName); SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);}复制代码

该方法把serviceName作为键,serviceFetcher作为值存储到集合当中。

1.3.4 SystemServiceRegistry.ServiceFetcher

ServiceFetcher其实是一个泛型接口,定义在SystemServiceRegistry类的内部,声明如下:

static abstract interface ServiceFetcher
{ T getService(ContextImpl ctx); }复制代码

接着搜索该方法的调用,发现该方法在静态代码块中被调用了很多次,用来注册不同的系统服务。我们以前面的Context.CONNECTIVITY_SERVICE为例,代码如下:

static {    ...    registerService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class,                    new StaticOuterContextServiceFetcher
() { @Override public ConnectivityManager createService(Context context) { // 终于发现跟Binder的身影了...泪崩...不容易呀 IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); IConnectivityManager service = IConnectivityManager.Stub.asInterface(b); return new ConnectivityManager(context, service); }}); ...}复制代码

在该方法的调用中:

  • serviceName就是Context.CONNECTIVITY_SERVICE

  • serviceClass就是ConnectivityManager.class

  • serviceFetcher就是StaticOuterContextServiceFetcher的一个匿名内部类。

1.3.5 SystemServiceRegistry.StaticOuterContextServiceFetcher

该类定义在SystemServiceRegistry类的内部,声明如下:

static abstract class StaticOuterContextServiceFetcher
implements ServiceFetcher
{ private T mCachedInstance;​ @Override public final T getService(ContextImpl ctx) { synchronized (StaticOuterContextServiceFetcher.this) { // 首次调用时,mCachedInstance = null;会调用createService(). if (mCachedInstance == null) { mCachedInstance = createService(ctx.getOuterContext()); } return mCachedInstance; } }​ public abstract T createService(Context applicationContext);}复制代码

由[1.3.1]可知,Context.getSystemService()最终返回的是ServiceFetchergetService()方法的返回值。而getService()返回的又是createService()方法的返回值;在本例中createService()的实现如下:

@Overridepublic ConnectivityManager createService(Context context) {    // IPC通信。通过getService()最终获取了指向目标Binder服务端的代理对象BinderProxy。    IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);    // IConnectivityManager是一个aidl文件,定义在\frameworks\base\core\java\android\net目录下    IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);    return new ConnectivityManager(context, service);}复制代码

追溯到这里,我们已然来到了一个重要拐点:再继续下去,就下探到Binder的领域啦;是否到此为止了呢?

你想拥有什么你就去追求什么!

在这里,我准备先抛出结论。不想继续下去的小伙伴可以就近下车啦!

Context.getSystemService()小结

  • 通过Context.getSystemService()方法的层层调用,最终会走到ContextImpl.getSystemService ()方法之中;

  • ContextImpl.getSystemService ()方法中,经过层层调用,最终返回的是ServiceFetcher接口中getService()方法的返回值;

  • 虽然,根据系统服务的不同,ServiceFetcher.getService()的返回值形式上有所差异;但是,底层都会调用到ServiceManager.getService()方法,最终会触发IPC(Inter-Process Communication )机制,返回一个指向目标Binder服务端的代理对象BinderProxy

  • 后续所有的调用都是通过这个BinderProxy来实现的;

二. ServiceManager.getService()

to be continued...

转载于:https://juejin.im/post/5af2b051f265da0b9f40456e

你可能感兴趣的文章
快节奏的多人游戏同步 - 示例代码和在线演示
查看>>
【分享】Java的几个重要词语
查看>>
symfony2的配置和welcome界面问题汇总
查看>>
选IDC房时,用脚本截取丢失包和rtt的值作比对
查看>>
TCP Wrappers
查看>>
mina
查看>>
kindle
查看>>
C# MoreLinq 扩展安装
查看>>
遍历查找指定文件
查看>>
域名年龄-SEO搜索引擎优化
查看>>
Qunee for HTML5 V2.5新版本发布
查看>>
<context-param>与<init-param>的区别与作用
查看>>
php中mkdir()函数的权限问题
查看>>
奇特的约会
查看>>
radio根据name 获取选中值及判断是否被选中
查看>>
LVM 类型的 Storage Pool - 每天5分钟玩转 OpenStack(8)
查看>>
[Nginx优化]分享nginx配置文件及优化说明
查看>>
TensorFlow入门
查看>>
Apache Spark 2.2.0 中文文档 翻译活动
查看>>
平面设计的软件太多了
查看>>