Binder系统分析之SM大管家的获取流程

之前介绍了Binder跨进程通信中AIDL文件的具体实现流程,之后又实现Native层、framework层Binder框架的具体使用范例。其使用规范都是基于底层设计好的框架之上,本章节就针对其框架,步步分析其实现流程背后的原理,对着代码一步一步追溯到源头,废话不多说,Fucking Code!

ServiceManager的获取流程

对于上层应用来说,获取ServiceManager大管家的方式无非两种,一种是framework层获取,一种是Native层获取,具体对应方式如下

framework层获取SM

原生API获取服务流程浅析

对于Java层获取SM方式,相信对于应用层开发来说非常熟悉了,我们可以通过类ServiceManager.getService()方法,通过传入服务名称来获取对应的远程代理服务对象。例如获取闹钟服务时,调用代码 getSystemService(Context.ALARM_SERVICE) 即可获取相应服务,然而其内部获取的流程是如何实现的呢?下面我们追溯代码看一下具体调用流程。

  • 通过Activity的getSystemService()方法,我们追溯下去

    @Override
    public Object getSystemService(@ServiceName @NonNull String name) {
        if (getBaseContext() == null) {
            throw new IllegalStateException(
                    "System services not available to Activities before onCreate()");
        }
    
        if (WINDOW_SERVICE.equals(name)) {
            return mWindowManager;
        } else if (SEARCH_SERVICE.equals(name)) {
            ensureSearchManager();
            return mSearchManager;
        }
        return super.getSystemService(name);
    }
    

    通过super.getSystemService(name)调用父类的getSystemService

  • ContextThemeWrapper的getSystemService

    @Override
    public Object getSystemService(String name) {
        if (LAYOUT_INFLATER_SERVICE.equals(name)) {
            if (mInflater == null) {
                mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
            }
            return mInflater;
        }
        return getBaseContext().getSystemService(name);
    }
    
  • 通过getBaseContext()调用父类的方法

    public Context getBaseContext() {
        return mBase;
    }
    
    @Override
    public Object getSystemService(String name) {
        return mBase.getSystemService(name);
    }
    

    其中的mBase实际指向Context类

  • Context的具体方法实现

    public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);
    

    貌似到这里就停下来,其提供一个抽象方法由子类实现,最后是谁来实现呢?Context类有一个实现类ContextImp,我们来看一下里面的内容。

  • ContextImp的getSystemService方法

    @Override
    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }
    

    间接调用了SystemServiceRegistry类的getSystemService()方法

  • SystemServiceRegistry具体方法

    public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }
    

    由类名SystemServiceRegistry可知,此类和服务注册有关,其内部有两个重要的静态私有成员常量(final修饰的变量)中保存了Hash列表,如下:

    private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
            new HashMap<Class<?>, String>();
    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();
    

    其中ServiceFetcher为一个接口,其返回一个范性T,SystemServiceRegistry内部有三个具体类实现了此接口

    static abstract interface ServiceFetcher<T> {
        T getService(ContextImpl ctx);
    }
    
    // 其中的一个实现类如下
    static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
        private final int mCacheIndex;
    
        public CachedServiceFetcher() {
            mCacheIndex = sServiceCacheSize++;
        }
    
        @Override
        @SuppressWarnings("unchecked")
        public final T getService(ContextImpl ctx) {
            final Object[] cache = ctx.mServiceCache;
            synchronized (cache) {
                // Fetch or create the service.
                Object service = cache[mCacheIndex];
                if (service == null) {
                    service = createService(ctx);
                    cache[mCacheIndex] = service;
                }
                return (T)service;
            }
        }
    
        public abstract T createService(ContextImpl ctx);
    }
    

    在类的前面有一大片的静态代码块,其中涉及到了服务的初始化注册代码。

  • SystemServiceRegistry静态代码块

    static {
    
        ...
    
        registerService(Context.ALARM_SERVICE, AlarmManager.class,
            new CachedServiceFetcher<AlarmManager>() {
        @Override
        public AlarmManager createService(ContextImpl ctx) {
            IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
            IAlarmManager service = IAlarmManager.Stub.asInterface(b);
            return new AlarmManager(service, ctx);
        }});
    
        ...
    
    }
    
  • 通过registerService()方法,缓存系统相关服务,方便用户获取

    private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }
    
    1. 参数一:服务名称
    2. 参数二:服务具体类文件
    3. 参数三:服务对应的ServiceFetcher对象

到这里基本就可以看到最终的调用结果,即通过SM获取IBinder远程服务代理对象,然后通过IAlarmManager.Stub.asInterface()方法将IBinder对象转换成可以使用的IAlarmManager服务对象

IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
IAlarmManager service = IAlarmManager.Stub.asInterface(b);

到这里,是不是和AIDL中流程分析很相似呢?不错,其调用获取、转换方式基本都是一致的。下面我们来具体分析真正的SM获取流程。

framework层获取sm分析

上面小结分析得出最终调用的方式为IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);,我们就由此开始分析。

  • ServiceManager.getService()

    //getService()最终获取了指向目标Binder服务端的代理对象BinderProxy
    public static IBinder getService(String name) {
        try {
            //其中sCache = new HashMap<String, IBinder>() 以hashmap格式缓存已组成的名称
            // 请求获取服务过程中,先从缓存中查询是否存在,如果缓存中不存在的话,再通过binder交互来查询相应的服务
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                //调用的是ServiceManagerNative的ServiceManagerProxy的getService()
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
    

    代码注释很详细,sCache为一个HashMap,键值分别为服务名、IBinder对象。首先从缓存中获取服务的IBinder对象,不存在,就调用getIServiceManager().getService(name)来获取。

  • getIServiceManager().getService()

    //返回的是ServiceManagerProxy对象
    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }
    
        // Find the service manager
        // ServiceManagerNative.asInterface(BinderInternal.getContextObject()) == new ServiceManagerProxy(new BinderProxy())
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }
    

    getIServiceManager获取到类内部的静态的IServiceManager对象,IServiceManager接口继承自IInterface接口,是不是又是很亲切,哈哈!其最终对应的是SM的远程代理对象ServiceManagerProxy。这里首先透露一下,ServiceManagerNative.asInterface(BinderInternal.getContextObject())方法通过jni调用c层代码,获取位于c层的handle值为0的binder引用对象,其对应的正是ServiceManager对象大管家。
    获取到了SM大管家,通过传入的服务名称即可获取相应的远程代理服务对象了。由于IServiceManager继承自IInterface接口,所以我们需要找到实现IServiceManager接口的类即可找到具体的实现方法。

  • BinderInternal.getContextObject()

  • ServiceManagerNative.getService()
    ServiceManagerProxy实际上在ServiceManagerNative文件中,ServiceManagerProxy类有一个IBinder对象mRemote,其是Binder驱动为服务分配的远程服务代理对象,这个和AIDL中分析的相一致,而mRemote对象就是和Binder驱动进行通信的关键。

    /**
     * 其成员变量mRemote指向BinderProxy对象
     * ServiceManagerProxy的addService, getService方法最终是交由mRemote来完成
     */
    class ServiceManagerProxy implements IServiceManager {
    
        //mRemote是BinderProxy的对象,该BinderProxy对象对应于BpBinder(0)
        //其作为binder代理管家,指向native层的大管家Service Manager
        public ServiceManagerProxy(IBinder remote) {
            mRemote = remote;
        }
    
        public IBinder asBinder() {
            return mRemote;
        }
    
        //getService()最终获取了指向目标Binder服务端的代理对象BinderProxy
        public IBinder getService(String name) throws RemoteException {
    
            //此处需要将java层的Parcel转成Native层的Parcel
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            data.writeInterfaceToken(IServiceManager.descriptor);
            data.writeString(name);
    
            //mRemote为BinderProxy对象
            mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
    
            //从replay里面解析出获取的IBinder对象,调用Parcel.java中native方法
            //最终创建了指向Binder服务端的BpBinder代理对象
            IBinder binder = reply.readStrongBinder();
            reply.recycle();
            data.recycle();
            return binder;
        }
    
        public IBinder checkService(String name) throws RemoteException {
            ...
         }
    
        public void addService(String name, IBinder service, boolean allowIsolated)
                throws RemoteException {
            ...
        }
    
        public String[] listServices() throws RemoteException {
            ...
        }
    
        public void setPermissionController(IPermissionController controller)
                throws RemoteException {
            ...
        }
    
        private IBinder mRemote;
    }
    

    由上代码可以看出getService()方法,最终由Parcel数据封装服务信息,调用mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0)方法与Binder驱动进行交互。
    在AIDL分析文章中介绍类Binder和IBinder的作用,现在我们查看一下其具体的代码。

  • Binder文件一览分析

    public class Binder implements IBinder {
    
        public IInterface queryLocalInterface(String descriptor) {
            ...
        }
    
        protected boolean onTransact(int code, Parcel data, Parcel reply,
                int flags) throws RemoteException {
            if (code == INTERFACE_TRANSACTION) {
                reply.writeString(getInterfaceDescriptor());
                return true;
            } else if (code == DUMP_TRANSACTION) {
                ParcelFileDescriptor fd = data.readFileDescriptor();
                String[] args = data.readStringArray();
                if (fd != null) {
                    try {
                        dump(fd.getFileDescriptor(), args);
                    } finally {
                        try {
                            fd.close();
                        } catch (IOException e) {
                            // swallowed, not propagated back to the caller
                        }
                    }
                }
                // Write the StrictMode header.
                if (reply != null) {
                    reply.writeNoException();
                } else {
                    StrictMode.clearGatheredViolations();
                }
                return true;
            }
            return false;
        }
    
        public final boolean transact(int code, Parcel data, Parcel reply,
                int flags) throws RemoteException {
            if (false) Log.v("Binder", "Transact: " + code + " to " + this);
            if (data != null) {
                data.setDataPosition(0);
            }
            boolean r = onTransact(code, data, reply, flags);
            if (reply != null) {
                reply.setDataPosition(0);
            }
            return r;
        }
    
        private boolean execTransact(int code, long dataObj, long replyObj,
                int flags) {
            Parcel data = Parcel.obtain(dataObj);
            Parcel reply = Parcel.obtain(replyObj);
            boolean res;
             try {
                res = onTransact(code, data, reply, flags);
            } catch (RemoteException e) {
                if ((flags & FLAG_ONEWAY) != 0) {
                    Log.w(TAG, "Binder call failed.", e);
                } else {
                    reply.setDataPosition(0);
                    reply.writeException(e);
                }
                res = true;
            } catch (RuntimeException e) {
                if ((flags & FLAG_ONEWAY) != 0) {
                    Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
                } else {
                    reply.setDataPosition(0);
                    reply.writeException(e);
                }
                res = true;
            } catch (OutOfMemoryError e) {
                RuntimeException re = new RuntimeException("Out of memory", e);
                reply.setDataPosition(0);
                reply.writeException(re);
                res = true;
            }
            checkParcel(this, code, reply, "Unreasonably large binder reply buffer");
            reply.recycle();
            data.recycle();
    
            ...
    
            StrictMode.clearGatheredViolations();
            return res;
        }
    }
    
    final class BinderProxy implements IBinder {
        public native boolean pingBinder();
        public native boolean isBinderAlive();
    
        public IInterface queryLocalInterface(String descriptor) {
            return null;
        }
    
        //最终交由Native层的BpBinder::transact()完成
        //另外,该方法可抛出RemoteException
        public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            //用于检测Parcel大小是否大于800k
            Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
            return transactNative(code, data, reply, flags);
        }
    
        public native String getInterfaceDescriptor() throws RemoteException;
        //对应android_util_Binder.cpp下android_os_BinderProxy_transact具体方法
        public native boolean transactNative(int code, Parcel data, Parcel reply,
                int flags) throws RemoteException;
        public native void linkToDeath(DeathRecipient recipient, int flags)
                throws RemoteException;
        public native boolean unlinkToDeath(DeathRecipient recipient, int flags);
    
        public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            data.writeFileDescriptor(fd);
            data.writeStringArray(args);
            try {
                transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY);
            } finally {
                data.recycle();
                reply.recycle();
            }
        }
    
        BinderProxy() {
            mSelf = new WeakReference(this);
        }
    
        @Override
        protected void finalize() throws Throwable {
            try {
                destroy();
            } finally {
                super.finalize();
            }
        }
    
        private native final void destroy();
    
        private static final void sendDeathNotice(DeathRecipient recipient) {
            if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient);
            try {
                recipient.binderDied();
            }
            catch (RuntimeException exc) {
                Log.w("BinderNative", "Uncaught exception from death notification",
                        exc);
            }
        }
    
        final private WeakReference mSelf;
        private long mObject;
        private long mOrgue;
    }
    

    代码比较多,这里知识贴出来大概通览一遍,如果是对AIDL文件实现流程很清晰的话,便会很快的找到共同点。这里作一个大概的解读。

    1. BinderProxy实现IBinder接口,ServiceManagerProxy内的IBinder对象mRemote即是SM远程代理实例,mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0)便是通过BinderProxy类的transact方法,继而进入jni通过c调用与Binder驱动进行交互。
    2. Binder也实现了IBinder接口,但是其对应的是Server端的对象,是本地Binder服务。其接受远程mRemote代理对象通过Binder驱动传来请求,处理并返回。此期间Client端处于堵塞状态。自定义的Server端服务可以通过继承Binder,实现其onTransact方法即可,此方法由于驱动支持,会自动调用。
    3. 进程间数据均由Parcel封装,data.***方法由底层jni实现,便于与驱动交互。
坚持原创技术分享,您的支持将鼓励我继续创作!