AIDL 服务的发布 publishBinderService 和 获取 getService

AIDL 服务的发布 publishBinderService 和 获取 getService,第1张

在 Framework 中使用 AIDL 服务,其发布和获取是两个重要方法,本文尝试探究其源码的实现。

我们知道手机在开机过程中,会启动一个 ServiceManger 的服务,它就是服务的大管家。AIDL 服务的发布和获取也是要通过这个大管家来 *** 作的,下面是大管家的路径。

/frameworks/native/cmds/servicemanager/ServiceManager.cpp

  • 1 AIDL 的发布方法
    • publishBinderService
  • 2 服务的获取方法
    • getService
  • 3 ServiceManger 相关类图

1 AIDL 的发布方法 publishBinderService

该方法定义在 SystemService.java 中,有多个重载方法,最后都调到了下面这个方法。

/frameworks/base/services/core/java/com/android/server/SystemService.java
429      /**
430       * Publish the service so it is accessible to other services and apps.
431       *
432       * @param name the name of the new service
433       * @param service the service object
434       * @param allowIsolated set to true to allow isolated sandboxed processes
435       * to access this service
436       * @param dumpPriority supported dump priority levels as a bitmask
437       *
438       * @hide
439       */
440      protected final void publishBinderService(String name, IBinder service,
441              boolean allowIsolated, int dumpPriority) {
442          ServiceManager.addService(name, service, allowIsolated, dumpPriority);
443      }

进一步调到 ServiceManager.addService,这里的 ServiceManager 还是 java 层的。我们继续看看它内部的实现

194      public static void addService(String name, IBinder service, boolean allowIsolated,
195              int dumpPriority) {
196          try {
197              getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
198          } catch (RemoteException e) {
199              Log.e(TAG, "error in addService", e);
200          }
201      }

接着 getIServiceManager 看下去,它最终会通过 binder 获得大管家 ServiceManger 的代理对象 ServiceManagerProxy。

110      private static IServiceManager getIServiceManager() {
111          if (sServiceManager != null) {
112              return sServiceManager;
113          }
114          //要获取一个binder服务,serviceManger
115          // Find the service manager
116          sServiceManager = ServiceManagerNative
117                  .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
118          return sServiceManager;
119      }

关于 ServiceManagerNative.asInterface(Binder.allowBlocking(BinderInternal.getContextObject())) 中的参数。十分重要的一点是 BinderInternal.getContextObject 函数最终返回的是一个BinderProxy 对象,该 BinderProxy 对象对应于 BpBinder(0),其作为 binder代理端,指向 native 层大管家 service Manager。这里一定要记住!!!

在这个对象中包含一个名称为 sProxyMap 的 ProxyMap 对象,Native 层的 BpBinder 对象作为 key,BinderProxy 对象作为Value,存入该ProxyMap对象中。BpBinder 和 BinderProxy 其实是一个东西:远程 binder 的实体,不同是前者 Native 层、后者 Java 层。至于 Binder.allowBlocking,一顿 *** 作后,返回的还是传入的 BinderProxy 对象,不用关注。

这部分内容具体可以看看下面这篇文章。https://juejin.cn/post/7058834333963911205#heading-2

我们继续关注 ServiceManagerNative.asInterface 的实现。

27  public final class ServiceManagerNative {
28      private ServiceManagerNative() {}
...
        //上面的代码就是调用到了这个方法
37      @UnsupportedAppUsage
38      public static IServiceManager asInterface(IBinder obj) {
39          if (obj == null) {
40              return null;
41          }
42  
43          // ServiceManager is never local
44          return new ServiceManagerProxy(obj);//new 一个代理对象,要代理我们的 ServiceManager
45      }
46  }
47  
48  // This class should be deleted and replaced with IServiceManager.Stub whenever
49  // mRemote is no longer used
50  class ServiceManagerProxy implements IServiceManager {
51      public ServiceManagerProxy(IBinder remote) {
52          mRemote = remote;
			//下面这行是不是很熟悉,这不就是我们获取 binder 服务的 *** 作嘛
			//所以这里是要获取 IServiceManager
53          mServiceManager = IServiceManager.Stub.asInterface(remote);
54      }
123  }

上面代码,是把在 ServiceManger.java 传入的 BinderProxy 对象,转化成 ServiceManger,从而获得 native 层的服务大管家。

经过以上分析,我们知道了,注册 AIDL 服务,也是一个跨进程通信的过程,通过 binder 调用的是 native 层的 ServiceManger。

不难发现 framework 层的调用工作实际都交给了 ServiceMangerProxy 来做;而 ServiceMangerProxy 又依靠它的成员变量 BinderProxy,BinderProxy 通过 jni 方式,走到了 native 层,最终完成调用。

详细过程请看这篇文章。
http://gityuan.com/2015/11/21/binder-framework/

2 服务的获取方法 getService

首先也是从 java 层的 ServiceManger 开始,返回的结果是一个 IBinder 类型对象,需要经过 .Stub.asInterface(IBinder) 的 *** 作转化成对应服务。

/frameworks/base/core/java/android/os/ServiceManager.java
121      /**
122       * Returns a reference to a service with the given name.
123       *
124       * @param name the name of the service to get
125       * @return a reference to the service, or null if the service doesn't exist
126       */
127      @UnsupportedAppUsage
128      public static IBinder getService(String name) {
129          try {
130              IBinder service = sCache.get(name);
131              if (service != null) {
132                  return service;
133              } else {
134                  return Binder.allowBlocking(rawGetService(name));
135              }
136          } catch (RemoteException e) {
137              Log.e(TAG, "error in getService", e);
138          }
139          return null;
140      }
141  

首先尝试从缓存中获取需要的 IBinder 对象。

38      /**
39       * Cache for the "well known" services, such as WM and AM.
40       */
41      @UnsupportedAppUsage
42      private static Map<String, IBinder> sCache = new ArrayMap<String, IBinder>();

当缓存中没有时,使用 Binder.allowBlocking(rawGetService(name)) 方法,重点是 rawGetService(name)

  private static IBinder rawGetService(String name) throws RemoteException {
...
334          
335          final IBinder binder = getIServiceManager().getService(name);
...
384          return binder;
385      }
386  }

这里走到了和发布服务同样的地方 getIServiceManager,一顿 *** 作后获得了服务大管家 ServiceManger 的客户端 binder,实现跨进程调用 getService 方法。

3 ServiceManger 相关类图

为了便于理解,我做了一个简单的类图,并不完全,主要是帮助理解上面内容的。

ServiceManagerProxy:只有这一个类实现了 ServiceManager 接口,所以 framework 层的相关调用最后都会找到它。他的 mRemote 是一个 BinderProxy 类型对象。
ServiceManagerNative: ServiceManagerProxy 类是放在这个类的包下的,对外不可见。因此需要通过这个类间接获得 ServiceManagerProxy 类对象。
ServiceManager:这个是 java 层的 ServiceManager,不是大管家,感觉就是负责接待的喽啰,有事就找他,他再找大佬。它通过 ServiceManagerNative 获得 ServiceManagerProxy 对象,BinderInternal.getContextObject() 这个获取真正大管家 IBinder 的 *** 作就是此时作为参数传入的。
BinderProxy:暂时只知道它能调用到 native 层,具体怎么实现的还未探究。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/794999.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-06
下一篇 2022-05-06

发表评论

登录后才能评论

评论列表(0条)

保存