继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Android源码分析之--IPC以及Service的启动过程

繁华开满天机
关注TA
已关注
手记 134
粉丝 15
获赞 68

前言

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

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

5ba3a6bc000132a904140459.jpg

创建AIDL文件.png

定义如下:

package com.nan.testbinder;

interface IAidlInterface {
    String pay(int pwd);
}

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

5ba3a6bc0001bbd105420469.jpg

自动生成的java文件.png

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

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

<service
    android:name=".service.MyService3"
    android:enabled="true"
    android:exported="true"
    android:process=":remote">
</service>

然后在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是英语,假设中国人和日本人都懂英语,那么两者之间就可以间接地沟通了。

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

5ba3a6bd00014b2b07880219.jpg

进程间通信模型.png

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写数据的。

5ba3a6be0001342e06170244.jpg

自动生成的接口类结构.png

其中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方法:

@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);
}

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

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

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

@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 {
        //把描述和数据写到一个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<POOL_SIZE; i++) {
            p = pool[i];
            if (p != null) {
                pool[i] = null;
                if (DEBUG_RECYCLE) {
                    p.mStack = new RuntimeException();
                }
                return p;
            }
        }
    }
    return new Parcel(0);
}

远程Stub的onTransact方法实现:

@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: {
            //把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。

@Override
public 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。与系统服务进行通信。

5ba3a6be0001583904780429.jpg

ActivityManagerNative.png

继续分析:

static public IActivityManager getDefault() {
    return gDefault.get();
}

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

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    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<ConnectionRecord> clist = s.connections.get(binder);
        if (clist == null) {
            clist = new ArrayList<ConnectionRecord>();
            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!!!

5ba3a6bf0001a90103650480.jpg

ApplicationThread.png

因此调用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<? extends Binder> 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里面的,例如我们刚刚看过的代码:

@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);
        //把数据写到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等)

原文链接:http://www.apkbus.com/blog-0-65634.html

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP