Mctrain's Blog

What I learned in IT, as well as thought about life

getSystemService() in Android

| Comments

在之前研究了那么久的bindService()这个API,一直没搞清楚一个问题:

为什么我看到的基本上都是和AMS相关的代码,而之前所学到说如果application要和service打交道都是需要通过ServiceManager获得某个service的binder才可以。那么AMS和ServiceManager到底是什么关系呢?如果AMS是通过ServiceManager获得的service binder,那么相关的代码又是在哪里呢?

这个问题困扰了我很久,直到我看到一个博客,我才发现其实我把一个很重要的概念混起来了:

Android中主要通过2种方法来获得service binder:

  • 通过一些API如bindService,来获得application service的binder。因为app service都是直接和AMS注册的,AMS运行在system_server进程;
  • 通过ServiceManager.getService(String Descriptor)来获得Service Manager管理的service的binder,ServiceManager运行在servicemanager进程。

也就是说,尼玛bindService只是用来bind application level的service!!!

而我们更在意的system service应该是由ServiceManager.getService()来获得的!!!

发现这个问题之后我整个人都有些凌乱了。。。不过静下来想想其实自己从bindService这里入手也学到很多东西,也就不纠结了!

那么现在的问题是,应用程序到底是如何获得system service的binder的?

在这个问题的探索过程初期,我又一次惊奇地发现android.os.ServiceManager竟然是@hide的!!!!

尼玛hide的啊!!!也就是如果不是和framework一起编译的话是找不到的啊!我在网上看到一个很无语的解决方案,但是,我还是不知道应用程序到底是怎么调用system service的啊?总不可能每个人都懂得什么变态的“隐藏类的使用”吧?

后来不知道是怎么回事,我突然发现在android里面竟然有一个API叫getSystemService()!我问了下乃正,他竟然和我说“你们干嘛不问我,这不是很显然的吗?应用里面就是调用这个获得system service的啊”!尼玛伤不起啊,一个没写过android应用程序的还要研究android framework的人伤不起啊!!


getSystemService()

好了,还是言归正传吧,到底getSystemService()是如何得到system service的呢?其实这个也没有想象的那么好理解。而且我查了下网上的资料,大部分还是讲ServiceManager.getService()是如何得到system service的,而基本上都没有涉及到getSystemService()是怎么和ServiceManager.getService()搭上关系的。

于是经过一番研究,我终于搞清楚了这里面所涉及的种种“复杂而又充满基情”的关系,请听我娓娓道来:


在一个月黑风高的夜晚,一个郁郁不得志的少年Activity调用了一个具有扭转乾坤概率的大API—getSystemService()。

算了,没有写小说的潜质。。。还是老实点正常写着吧。。。早点写完早点洗洗睡吧。。。

在调用Activity.getSystemService()之后,就进入ContextImpl.getSystemService()。

至于是怎么进来的,其实也很简单,Activity继承ContextThemeWrapper,再继承ContextWrapper。里面会调用mBase.getSystemService()。这个mBase是一个ContextImpl实例变量,于是就调到了。

于是在ContextImpl.getSystemService()是这样的:

1
2
3
4
5
@Override
public Object getSystemService(String name) {
    ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
    return fetcher == null ? null : fetcher.getService(this);
}

话说这个SYSTEM_SERVICE_MAP是怎么来的呢?这就要扯得远点了:

在每个Activity启动的时候都要运行一大段的static的代码(在android.app.ContextImpl.java)里面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static {
    registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {
      public Object getService(ContextImpl ctx) {
      return AccessibilityManager.getInstance(ctx);
      }});

    registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
      public Object createService(ContextImpl ctx) {
      IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
      IAccountManager service = IAccountManager.Stub.asInterface(b);
      return new AccountManager(ctx, service);
      }});

    registerService(ACTIVITY_SERVICE, new ServiceFetcher() {
      public Object createService(ContextImpl ctx) {
      return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
      }});

    ...

它会在自己的SYSTEM_SERVICE_MAP为每一个系统服务注册一个ServiceFetcher的类,在这个类中,大部分的服务为重写一个函数叫createService(ContextImpl),这个方法之后会用到,现在只需要知道我们从SYSTEM_SERVICE_MAP获得了某个服务的ServiceFetcher对象fetcher,并通过fetcher.getService(this)获得了该服务的对象。

fetcher.getService(ContextImpl):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public Object getService(ContextImpl ctx) {
    ArrayList<Object> cache = ctx.mServiceCache;
    Object service;
    synchronized (cache) {
  if (cache.size() == 0) {
      // Initialize the cache vector on first access.
      // At this point sNextPerContextServiceCacheIndex
      // is the number of potential services that are
      // cached per-Context.
      for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
      cache.add(null);
      }
  } else {
      service = cache.get(mContextCacheIndex);
      if (service != null) {
      return service;
      }
  }
  service = createService(ctx);
  cache.set(mContextCacheIndex, service);
  return service;
    }
}

也就是说每个Activity都有一个mServiceCache,它cache了所有用到的service的ServiceFetcher类。如果hit了,那么直接返回该对象,否则会调用这个fetcher的createService()方法,这也就是我们刚才提到的每一个ServiceFetcher在注册的时候会重写的那个方法。

可以看到,大部分重写的方式都是类似于这样的:

1
2
3
4
5
public Object createService(ContextImpl ctx) {
    IBinder b = ServiceManager.getService(XXX_SERVICE);
    IXXXManager service = IXXXManager.Stub.asInterface(b);
    return new XXXManager(ctx, service);
}});

于是乎,getSystemService()就在这里和ServiceManager.getService()无缝地结合在了一起!


对于ServiceManager.getService(),在网上有很多关于它的说明和讨论,这里推荐其中两篇:

老罗的博客中两篇,

第一篇是这篇文章,主要介绍了怎么从java里面的ServiceManager.getService()开始的流程;

还有一篇是这篇文章,深入介绍了在C++和driver层是如何调用getService的

Comments