博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 源码分析之旅2 1 IPC以及Service的启动过程
阅读量:7117 次
发布时间:2019-06-28

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

###前言

进程间通信十分重要,在Android Framework中随处可见。

进程间通信的时候,我们经常使用的是AIDL的方式,下面先给出一个简单的栗子:

首先定义我们的AIDL文件,在Android Studio创建一个AIDL文件:

定义如下:

package com.nan.testbinder;interface IAidlInterface {    String pay(int pwd);}复制代码

在这个AIDL里面,我们定义一个接口,里面有一个pay方法来模拟支付宝的支付。输入参数是支付密码,返回支付结果。然后我们rebuild一下项目,AS就会自动为我们定义的AIDL文件生成一个Java文件,这里我们先不详细介绍这个文件:

然后创建我么的远程服务:

import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import com.nan.testbinder.IAidlInterface;public class MyService3 extends Service {    public static final String TAG = MyService3.class.getSimpleName();    public MyService3() {        Log.e(TAG, "MyService3");    }    @Override    public IBinder onBind(Intent intent) {        Log.e(TAG, "onBind");        return new Interface();    }    @Override    public void onCreate() {        Log.e(TAG, "onCreate");    }    @Override    public boolean onUnbind(Intent intent) {        Log.e(TAG, "onUnbind");        return super.onUnbind(intent);    }    @Override    public void onDestroy() {        Log.e(TAG, "onDestroy");    }    public class Interface extends IAidlInterface.Stub {        @Override        public String pay(int pwd) throws RemoteException {            if (pwd == 123) {                return "支付成功";            }            return "支付失败";        }    }}复制代码

在这个服务里面,我们创建了一个接口类Interface,继承了自动生成的Java文件里面的Stub类。并且复写里面的pay方法。 最后在Service的onBind方法里面返回这个类的对象。

我们在清单文件中把这个服务定义为远程服务,即指定了服务所在的进程为:remote

复制代码

然后在Activity中定义一个ServiceConnection类,用于跟远程服务连接。这里通过Stub的asInterface方法把IBinder对象转换为AIDL的接口。 转换成功之后,我们就尝试调用接口的pay方法,成功/失败的时候通过一个Toast来打印支付结果。

class MyRemoteServiceConnection implements ServiceConnection {    @Override    public void onServiceConnected(ComponentName name, IBinder service) {    	//通过Stub的asInterface把拿到的IBinder引用转换为AIDL接口的实现类        mRemoteInterface = IAidlInterface.Stub.asInterface(service);        if (mRemoteInterface != null) {            String result;            try {                result = mRemoteInterface.pay(123);                Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();            } catch (RemoteException e) {                e.printStackTrace();            }        }    }    @Override    public void onServiceDisconnected(ComponentName name) {        //连接因为异常而终止才会调用    }}复制代码

最后在Activity中绑定服务/解绑服务:

mRemoteConn = new MyRemoteServiceConnection();Intent intent4 = new Intent(MainActivity.this, MyService3.class);//绑定bindService(intent4, mRemoteConn, BIND_AUTO_CREATE);//解绑unbindService(mRemoteConn);复制代码

###为什么要使用AIDL?

我们在进行进程间通信的时候,我们是无法拿到另外一个进程的类的对象,因为两个进程不在一个内存里面,它们都分配在不同的虚拟机中。这样的话,即使我们的类使用了静态变量,编译通过了,也无法进行通信。

如下图所示,两个进程就像是一个中国人跟一个日本人,假设双方都不懂对方的语言。比如现在中国人要发送一句话”不要“给日本人,但是在日语里面”不要“就是”雅蠛蝶“,因此正常情况下是不能正常沟通的(程序直接不能直接通过变量、函数来访问)。那么AIDL就是我们的中间者,比如说AIDL是英语,假设中国人和日本人都懂英语,那么两者之间就可以间接地沟通了。

下图是跨进程通信的基本架构:

Android系统会单独地分配一块内存,这块内存专门用于进程间的通信的。一旦我们的远程进程(服务)启动以后,就会在这块内存注册一个IBinder的引用。但是这个引用跟两个进程没有程序上的关系,不能直接把对象扔进来,他只保存了服务的包名、类名、这个服务有哪些变量等等。IBinder的引用的出现也就代表着客户端可以与该服务进行通信了。

进程间通信是类似于C/S架构的,一个AIDL的接口包括Stub以及Proxy,分别叫做存根,代理。Stub主要跟服务端交互,Proxy主要跟客户端交互。进程间通信最基本的概念就是数据的读写,客户端向IBinder中写数据,Stub从IBinder读数据。IBinder就相当于即时通信中的中间服务器。

###自动生成的接口类分析

package com.nan.testbinder;public interface IAidlInterface extends android.os.IInterface {    public static abstract class Stub extends android.os.Binder implements com.nan.testbinder.IAidlInterface {    	//包名        private static final java.lang.String DESCRIPTOR = "com.nan.testbinder.IAidlInterface";        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        public static com.nan.testbinder.IAidlInterface asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.nan.testbinder.IAidlInterface))) {                return ((com.nan.testbinder.IAidlInterface) iin);            }            return new com.nan.testbinder.IAidlInterface.Stub.Proxy(obj);        }        @Override        public android.os.IBinder asBinder() {            return this;        }        @Override        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {            switch (code) {                case INTERFACE_TRANSACTION: {                    reply.writeString(DESCRIPTOR);                    return true;                }                case TRANSACTION_pay: {                    data.enforceInterface(DESCRIPTOR);                    int _arg0;                    _arg0 = data.readInt();                    java.lang.String _result = this.pay(_arg0);                    reply.writeNoException();                    reply.writeString(_result);                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }        private static class Proxy implements com.nan.testbinder.IAidlInterface {            private android.os.IBinder mRemote;            Proxy(android.os.IBinder remote) {                mRemote = remote;            }            @Override            public android.os.IBinder asBinder() {                return mRemote;            }            public java.lang.String getInterfaceDescriptor() {                return DESCRIPTOR;            }            @Override            public java.lang.String pay(int pwd) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                java.lang.String _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeInt(pwd);                    mRemote.transact(Stub.TRANSACTION_pay, _data, _reply, 0);                    _reply.readException();                    _result = _reply.readString();                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }        }        static final int TRANSACTION_pay = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);    }    public java.lang.String pay(int pwd) throws android.os.RemoteException;}复制代码

下面开始分析,如下图所示,这是Android Studio给出的整个类的结构图,这个接口有两个内部类Stub和Proxy。其中Stub是将来要从IBinder读数据的,Proxy将要从IBinder写数据的。

其中DESCRIPTOR是本类的包名。因为要保证两边能够通信,需要确保两边要知道对方的类名。 private static final java.lang.String DESCRIPTOR = "com.nan.testbinder.IAidlInterface";

下面是Stub的构造函数,里面调用了父类的attachInterface函数:

public Stub() {    this.attachInterface(this, DESCRIPTOR);}public void attachInterface(IInterface owner, String descriptor) {    mOwner = owner;    mDescriptor = descriptor;}复制代码

这里把this(IAidlInterface AIDL的引用,也就是自己)以及DESCRIPTOR描述绑定到Binder里面, 如果是同一个进程之间的通信的话,比如说Activity与同一个进程的Service通信,那么就会直接利用本地的接口引用。

当我们的远程服务启动的时候,就会注册一个IBinder引用,一旦Service绑定成功以后就会回传IBinder引用。但是拿到IBinder并不能马上通信,实际上最终还要拿到AIDL实现类的对象,这样才能通信。也就是说,拿到IBinder并且根据描述DESCRIPTOR来产生我们需要的AIDL的实现类。

例如上述栗子中的代码:

//通过Stub的asInterface把拿到的IBinder引用转换为AIDL接口的实现类mRemoteInterface = IAidlInterface.Stub.asInterface(service);复制代码

下面我们看asInterface的源码,刚刚已经解释过了,如果是同一个进程之间的通信的话,那么就直接使用本地的AIDL实现类引用,因此下面的代码是先通过IBinder的queryLocalInterface方法去找本地的引用。

public static com.nan.testbinder.IAidlInterface asInterface(android.os.IBinder obj) {   if ((obj == null)) {        return null;    }    //先通过IBinder的queryLocalInterface方法去找本地的引用    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);    if (((iin != null) && (iin instanceof com.nan.testbinder.IAidlInterface))) {        return ((com.nan.testbinder.IAidlInterface) iin);    }    return new com.nan.testbinder.IAidlInterface.Stub.Proxy(obj);}复制代码

由于IBinder只是一个接口,那么如果要看queryLocalInterface的实现的话,就需要去看Binder的源码:

public IInterface queryLocalInterface(String descriptor) {    if (mDescriptor.equals(descriptor)) {        return mOwner;    }    return null;}复制代码

这段代码很明确了,就是如果Stub构造的时候保存的DESCRIPTOR与我们需要的descriptor是一致的话,说明是同一个进程的,那就直接返回本地的AIDL实现类(mOwner)。

如果本地没有,那么就是不同进程的,那么这时候就需要通过IBinder引用去初始化我们的AIDL对象:

return new com.nan.testbinder.IAidlInterface.Stub.Proxy(obj);复制代码

下面就需要去看Proxy的构造函数:

Proxy(android.os.IBinder remote) {    mRemote = remote;}复制代码

再来看一下Proxy的类,它并没有继承Binder,而是直接实现了AIDL的接口:

private static class Proxy implements com.nan.testbinder.IAidlInterface复制代码

也就是说,Proxy构造的时候,就是通过IBinder引用转换为AIDL的接口的实现类的过程。

下面继续分析Stub的onTransact方法:

@Overridepublic boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {    switch (code) {        case INTERFACE_TRANSACTION: {            reply.writeString(DESCRIPTOR);            return true;        }        case TRANSACTION_pay: {            data.enforceInterface(DESCRIPTOR);            int _arg0;            _arg0 = data.readInt();            java.lang.String _result = this.pay(_arg0);            reply.writeNoException();            reply.writeString(_result);            return true;        }    }    return super.onTransact(code, data, reply, flags);}复制代码

Stub相当于服务端,以后IBinder要向Stub进行写数据。通信的时候会回调onTransact方法。

进程间通信无非就是“函数的间接调用”,下面这是我在AIDL里面定义的pay方法,如果客户端的pay方法被调用,那么远程的相应的方法也会被调用。

整个过程是这样的,先是客户端通过Proxy向IBinder写数据,Parcel与序列化有关。

@Overridepublic java.lang.String pay(int pwd) throws android.os.RemoteException {    android.os.Parcel _data = android.os.Parcel.obtain();    android.os.Parcel _reply = android.os.Parcel.obtain();    java.lang.String _result;    try {		//把描述和数据写到一个Parcel对象,描述用于控制将来数据发送到哪个对象。        _data.writeInterfaceToken(DESCRIPTOR);        _data.writeInt(pwd);        //写数据,但是不知道是哪一个函数,只知道是第几个函数,先去调用IBinder的transact        //然后IBinder去连接远程Stub对象,最后回调远程Stub的onTransact方法        mRemote.transact(Stub.TRANSACTION_pay, _data, _reply, 0);        //读取是否有异常        _reply.readException();        //读取结果(返回值),同步读取的        _result = _reply.readString();    } finally {        _reply.recycle();        _data.recycle();    }    return _result;}复制代码

下面我们看Binder中transact方法的实现

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;}复制代码

池的概念,先进先出的队列的方法:

public static Parcel obtain() {    final Parcel[] pool = sOwnedPool;    synchronized (pool) {        Parcel p;        for (int i=0; i

远程Stub的onTransact方法实现:

@Overridepublic boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {    switch (code) {        case INTERFACE_TRANSACTION: {            reply.writeString(DESCRIPTOR);            return true;        }        case TRANSACTION_pay: {        	//把DESCRIPTOR传进来作为验证,如果与本地的描述一样的话,下面继续执行。            data.enforceInterface(DESCRIPTOR);            int _arg0;            _arg0 = data.readInt();            //回调自己的pay方法            java.lang.String _result = this.pay(_arg0);            //把结果返回IBinder,然后再回传给客户端            reply.writeNoException();            reply.writeString(_result);            return true;        }    }    return super.onTransact(code, data, reply, flags);}复制代码

###bindService的全过程源码分析

要看bindService的话,先要找到Context的实现类ContextImpl。

@Overridepublic boolean bindService(Intent service, ServiceConnection conn,        int flags) {    warnIfCallingFromSystemProcess();//与系统的安全有关,如果你从系统调用的话,就需要关注这个方法    return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),            Process.myUserHandle());}复制代码

######Android Studio中可以通过Ctrl+H 打开类的继承关系图。

bindService调用了bindServiceCommon,核心代码:

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler        handler, UserHandle user) {    try {        service.prepareToLeaveProcess(this);        //核心代码,开始了进程间通信        int res = ActivityManagerNative.getDefault().bindService(            mMainThread.getApplicationThread(), getActivityToken(), service,            service.resolveTypeIfNeeded(getContentResolver()),            sd, flags, getOpPackageName(), user.getIdentifier());        return res != 0;    } catch (RemoteException e) {        throw e.rethrowFromSystemServer();    }}复制代码

ActivityManagerNative继承了Binder,并且实现了IActivityManager接口,因此与进程通信有关。

public abstract class ActivityManagerNative extends Binder implements IActivityManager{}复制代码

对比

public static abstract class Stub extends android.os.Binder implements com.nan.testbinder.IAidlInterface{}复制代码

发现ActivityManagerNative就是一个Stub对象,仔细观察这个类就会发现下面的Proxy。与系统服务进行通信。

继续分析:

static public IActivityManager getDefault() {    return gDefault.get();}复制代码

拿到系统服务IBinder的引用,通过asInterface方法把IBinder引用转换为需要的IActivityManager接口(实质上是AIDL接口):

private static final Singleton
gDefault = new Singleton
() { protected IActivityManager create() { //通过 IBinder b = ServiceManager.getService("activity"); IActivityManager am = asInterface(b); return am; }};复制代码

所以说,下面这句代码实际上是通过进程间通信,向ServiceManager获取名字为"activity"的系统服务,并且通过asInterface方法把IBinder引用转换为需要的IActivityManager接口的引用,然后调用这个引用的bindService方法。

ActivityManagerNative.getDefault()//这就是一个ActivityManagerService(AMS)	.bindService();复制代码

######系统服务,进程之间的通信

ServiceManager--管理所有系统服务。ServiceManager相当于总台,我们通过打电话(我们的进程与系统进程进行进程间通信)的方式,就可以拿到对应的服务的AIDL引用。

所有系统服务启动的时候都需要向ServiceManager注册自己的引用:就是把自己的IBinder引用给ServiceManager。在AIDL创建Stub的时候会通过调用父类Binder的构造函数,通过NDK的方式去注册。

而IActivityManager的实现类是ActivityManagerService(AMS),AMS是四大组件进行进程间通信的一个比较重要的类。(因为他实现类AIDL接口:ActivityManagerNative)

public final class ActivityManagerService extends ActivityManagerNative implements ... {}复制代码

而AMS里面bindService是这样实现的,注意:现在已经是在系统服务(AMS)的进程里面了。由系统进程继续后续操作:

public int bindService(IApplicationThread caller, IBinder token, Intent service,        String resolvedType, IServiceConnection connection, int flags, String callingPackage,        int userId) throws TransactionTooLargeException {    enforceNotIsolatedCaller("bindService");    synchronized(this) {    	//最后是通过mServices(ActiveService)对象的bindServiceLocked,这里开始了进程间通信        return mServices.bindServiceLocked(caller, token, service,                resolvedType, connection, flags, callingPackage, userId);    }}复制代码

最后是通过mServices(ActiveServices)对象的bindServiceLocked,这里开始了进程间通信,这个方法比较长,只看核心的代码:

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,        String resolvedType, final IServiceConnection connection, int flags,        String callingPackage, final int userId) throws TransactionTooLargeException {	//判断进程    final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);	//ActivityRecord用于记录Activity,然后是为了方便处理    ActivityRecord activity = null;    if (token != null) {        activity = ActivityRecord.isInStackLocked(token);        if (activity == null) {            Slog.w(TAG, "Binding with unknown activity: " + token);            return 0;        }    }    int clientLabel = 0;    PendingIntent clientIntent = null;    final boolean isCallerSystem = callerApp.info.uid == Process.SYSTEM_UID;	//判断是不是在本进程    if (isCallerSystem) {        service.setDefusable(true);        clientIntent = service.getParcelableExtra(Intent.EXTRA_CLIENT_INTENT);        if (clientIntent != null) {            clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);            if (clientLabel != 0) {                service = service.cloneFilter();            }        }    }	//一些权限的检测    if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {        mAm.enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,                "BIND_TREAT_LIKE_ACTIVITY");    }	//这个跟Service的生命周期有关    ServiceLookupResult res =        retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),                Binder.getCallingUid(), userId, true, callerFg, isBindExternal);    try {        AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);        ConnectionRecord c = new ConnectionRecord(b, activity,                connection, flags, clientLabel, clientIntent);		//把我们的connection对象保存(注册)起来,服务绑定成功以后用于回调        IBinder binder = connection.asBinder();        ArrayList
clist = s.connections.get(binder); if (clist == null) { clist = new ArrayList
(); s.connections.put(binder, clist); } clist.add(c); if (s.app != null && b.intent.received) { try { //连接回调给MainActivity c.conn.connected(s.name, b.intent.binder); } catch (Exception e) { } //如果是第一次绑定的时候,就会调用这里 if (b.intent.apps.size() == 1 && b.intent.doRebind) { requestServiceBindingLocked(s, b.intent, callerFg, true); } } else if (!b.intent.requested) { requestServiceBindingLocked(s, b.intent, callerFg, false); } getServiceMap(s.userId).ensureNotStartingBackground(s); } finally { Binder.restoreCallingIdentity(origId); } return 1;}复制代码

然后我们看ActiveServices中的requestServiceBindingLocked的实现,先通过forceProcessStateUpTo去启动另外一个进程的ActivityThread的进程(即通过C++的方式反射调用了ActivityThread的main方法,并且启动了消息循环)。(先启动进程,然后启动进程里面的服务,没毛病!ApplicationThread的启动代表APP的启动,即Application的启动)

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,        boolean execInFg, boolean rebind) throws TransactionTooLargeException {    if ((!i.requested || rebind) && i.apps.size() > 0) {        try {            bumpServiceExecutingLocked(r, execInFg, "bind");            //启动ActivityThread            r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);            //r是ServiceRecord对象,专门用来保存Service的记录,与ActivityRecord类似            //app是ServiceRecord的一个成员变量ProcessRecord,专门用来保存进程的记录            //thread是ProcessRecord的一个成员变量IApplicationThread,是整个Android组件启动的核心类            r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,                    r.app.repProcState);            if (!rebind) {                i.requested = true;            }            i.hasBound = true;            i.doRebind = false;        } catch (TransactionTooLargeException e) {        } catch (RemoteException e) {        }    }    return true;}复制代码

IApplicationThread的实现类ApplicationThread是整个Android组件启动的核心类,也是跟进程间通信有关的类,根据下面的类的关系分析:

public interface IApplicationThread extends IInterface {}public abstract class ApplicationThreadNative extends Binder implements IApplicationThread {}private class ApplicationThread extends ApplicationThreadNative {}复制代码

最终发现IApplicationThread的实现类是ActivityThread的一个内部类:ApplicationThread!!!

因此调用ApplicationThread的bindService的时候就会启动另外一个ActivityThread,并且发送消息给系统Handler(H),启动Service:

public final void scheduleBindService(IBinder token, Intent intent,        boolean rebind, int processState) {    updateProcessState(processState, false);    //保存关于Service的一些参数    BindServiceData s = new BindServiceData();    s.token = token;    s.intent = intent;    s.rebind = rebind;	//发送消息给系统Handler,启动Service    sendMessage(H.BIND_SERVICE, s);}复制代码

系统Handler接受消息以后:

case BIND_SERVICE:    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");    handleBindService((BindServiceData)msg.obj);    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);    break;复制代码

handleBindService:

private void handleBindService(BindServiceData data) {	//mServices是在handleCreateService的时候通过反射创建的    Service s = mServices.get(data.token);    if (s != null) {        try {            data.intent.setExtrasClassLoader(s.getClassLoader());            data.intent.prepareToEnterProcess();            try {                if (!data.rebind) {                	//绑定一个Service,回调onBind方法                    IBinder binder = s.onBind(data.intent);                    ActivityManagerNative.getDefault().publishService(                            data.token, data.intent, binder);                } else {                    s.onRebind(data.intent);                    //然后又通过进程间通信,把这个服务的IBinder对象放到Binder驱动里面                    ActivityManagerNative.getDefault().serviceDoneExecuting(                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);                }                ensureJitEnabled();            } catch (RemoteException ex) {                throw ex.rethrowFromSystemServer();            }        } catch (Exception e) {            if (!mInstrumentation.onException(s, e)) {                throw new RuntimeException(                        "Unable to bind to service " + s                        + " with " + data.intent + ": " + e.toString(), e);            }        }    }}复制代码

来到这里,就会回调ServiceConnection的onServiceConnected方法,拿到IBinder引用以后,就需要去创建用于通信的AIDL接口的引用。

class MyRemoteServiceConnection implements ServiceConnection {    @Override    public void onServiceConnected(ComponentName name, IBinder service) {        mRemoteInterface = IAidlInterface.Stub.asInterface(service);        if (mRemoteInterface != null) {            String result;            try {                result = mRemoteInterface.pay(123);                Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();            } catch (RemoteException e) {                e.printStackTrace();            }        }    }    @Override    public void onServiceDisconnected(ComponentName name) {        //连接因为异常而终止才会调用    }}复制代码

首先去初始化Stub,在Stub构造的时候,并且把描述保存起来。

public Stub() {    this.attachInterface(this, DESCRIPTOR);}public void attachInterface(IInterface owner, String descriptor) {    mOwner = owner;    mDescriptor = descriptor;}复制代码

我们bindService的时候,先会找到系统服务,由系统服务创建相应的进程和服务,然后回调的时候传回IBinder。 Service的创建是通过反射的方式的,当AIDL引用被创建的时候,首先会调用Stub的构造函数创建Stub,因为Stub继承了Binder,根据Java的语法,这时候先会调用Binder的构造init方法,注册IBinder引用到专门用于进程通信的内存里面:

public Binder() {    init();    if (FIND_POTENTIAL_LEAKS) {        final Class
klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Binder class should be static or leaks might occur: " + klass.getCanonicalName()); } }}复制代码

其中这里的init方法是一个native方法:

private native final void init();复制代码

在这个init方法里面就会进行IBinder的注册。

然后通过我们手动调用Stub的asInterface把拿到的IBinder引用转换为AIDL接口的实现类:

//通过Stub的asInterface把拿到的IBinder引用转换为AIDL接口的实现类mRemoteInterface = IAidlInterface.Stub.asInterface(service);复制代码

先在自己的进程找IBinder引用,如果有,就直接返回自身,没有的话,就创建代理Proxy:

public static com.nan.testbinder.IAidlInterface asInterface(android.os.IBinder obj) {   if ((obj == null)) {        return null;    }    //先通过IBinder的queryLocalInterface方法去找本地的引用    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);    if (((iin != null) && (iin instanceof com.nan.testbinder.IAidlInterface))) {        return ((com.nan.testbinder.IAidlInterface) iin);    }    return new com.nan.testbinder.IAidlInterface.Stub.Proxy(obj);}复制代码

我们在MainActivity拿到引用以后,就可以调用我们自己实现的pay方法进行进程间通信了。

###数据是怎么写倒IBinder里面的呢?

我们知道数据是通过Proxy写到IBinder里面的,例如我们刚刚看过的代码:

@Overridepublic java.lang.String pay(int pwd) throws android.os.RemoteException {    android.os.Parcel _data = android.os.Parcel.obtain();    android.os.Parcel _reply = android.os.Parcel.obtain();    java.lang.String _result;    try {        _data.writeInterfaceToken(DESCRIPTOR);        _data.writeInt(pwd);        //把数据写到IBinder驱动里面        mRemote.transact(Stub.TRANSACTION_pay, _data, _reply, 0);        _reply.readException();        _result = _reply.readString();    } finally {        _reply.recycle();        _data.recycle();    }    return _result;}复制代码

这是我们自定义AIDL类里面的自定义pay方法,这里我们深入分析mRemote.transact(...)这个方法。 首先从上面的分析知道,mRemote是在Proxy构造的时候传进来的(在不同进程里的时候)。 ######这里再强调一次,如果是同一个进程的话,Binder就是自身,因为Stub这个类本身就是继承了Binder。

public Stub() {    this.attachInterface(this, DESCRIPTOR);}public static com.nan.testbinder.IAidlInterface asInterface(android.os.IBinder obj) {    //...    return new com.nan.testbinder.IAidlInterface.Stub.Proxy(obj);}复制代码

所以说我们要看transact的实现,实际上就要看他的实现类Binder内部类的BinderProxy的transact:

public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {    Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");    if (Binder.isTracingEnabled()) {        Binder.getTransactionTracker().addTrace();    }    return transactNative(code, data, reply, flags);}复制代码

里面调用了native方法transactNative,也就是说IBinder的底层驱动是通过C++来实现的,通过底层代码把数据写到IBinder驱动里面。

返回的时候通过Binder的onTransact函数,通过dump方法把数据拿回来:

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方法把数据拿回来                dump(fd.getFileDescriptor(), args);            } finally {                IoUtils.closeQuietly(fd);            }        }        // Write the StrictMode header.        if (reply != null) {            reply.writeNoException();        } else {            StrictMode.clearGatheredViolations();        }        return true;    } else if (code == SHELL_COMMAND_TRANSACTION) {        ParcelFileDescriptor in = data.readFileDescriptor();        ParcelFileDescriptor out = data.readFileDescriptor();        ParcelFileDescriptor err = data.readFileDescriptor();        String[] args = data.readStringArray();        ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data);        try {            if (out != null) {                shellCommand(in != null ? in.getFileDescriptor() : null,                        out.getFileDescriptor(),                        err != null ? err.getFileDescriptor() : out.getFileDescriptor(),                        args, resultReceiver);            }        } finally {            IoUtils.closeQuietly(in);            IoUtils.closeQuietly(out);            IoUtils.closeQuietly(err);            // Write the StrictMode header.            if (reply != null) {                reply.writeNoException();            } else {                StrictMode.clearGatheredViolations();            }        }        return true;    }    return false;}复制代码

###IBinder引用什么时候放到共享内存时候?

AIDL中Stub构造的时候,就会调用父类Binder的构造,调用NDK的init方法,进行注册。

###源码分析相关

源码分析的两种方法:架构上面分析(类的关系)、流程上面的分析

源码分析的时候需要不断去找接口的实现类 源码分析的推荐学习顺序: Binder、Handler消息机制、VIew、事件分发、系统服务(ServiceManager代表着系统服务、AMS代表着应用程序启动流程)、四大组件的架构 、WindowManager、学习系统应用源码(Launcher等)

如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:

我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)

转载地址:http://gwbel.baihongyu.com/

你可能感兴趣的文章
[Command] alias - 别名
查看>>
Fedora 10编程开发工具
查看>>
paip..禁用mmseg 的默认词库. . 仅仅使用自定义词库from数据库.
查看>>
C# 仿金山毒霸启动和关闭淡入淡出效果
查看>>
[转载][Groovy] Groovy与Java的区别(一)
查看>>
使用mysqladmin ext了解MySQL运行状态【转】
查看>>
使用Bootstrap3和Ladda UI实现的多种按钮“加载中”效果体验
查看>>
[译]MVC网站教程(三):动态布局和站点管理
查看>>
CSS侧边栏宽度不动(更改页面宽度时),内容区宽度自适应
查看>>
传统媒体:广告都去哪儿了?
查看>>
排列生成算法注意事项
查看>>
Java核心知识点学习----多线程 倒计时记数器CountDownLatch和数据交换的Exchanger
查看>>
那些最好的轮子 - PHP篇
查看>>
采用Unity快速开发高质量游戏的若干优化建议
查看>>
10 001st prime number
查看>>
C#-MessageBox全部函数重载形式及举例
查看>>
滑板控制器
查看>>
oracle中LAG()和LEAD()等分析统计函数的使用方法(统计月增长率)
查看>>
hibernate建表 一对多 多的一方控制一的一方
查看>>
OpenCL 获取Program信息
查看>>