进程间的通信-AIDL-IPC Binder的原理和源码阅读

  • 写一个两个进程间的通信demo
    要写两个进程间的通信,首先要分清楚服务端和客户端,服务端就是负责提供数据,客户端就是负责获取数据。话不多说,开始写!

1、写服务端进程:
(1)写一个Service服务类:

public class UserService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: ");
        return null;  // 绑定之后调用onBind方法
    }
}

客户端调用context.bindService方法之后,就会调用服务端的onBind方法。
跨进程通信,需要用aidl来进行数据传输。
所以在服务daunt新建aidl文件。IUserCache.aidl:

// IUserCache.aidl
package com.android.mybaselibrary;

// Declare any non-default types here with import statements

interface IUserCache {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    String getUserName();

    String getUserPassword();
}

(2)用AndroidStudio 编译一下或make project一下。就会自动生成aidl对应的java文件,即IUserCache.java。
有了IUserCache.java文件,就可以创建IBinder实例:

    private final IUserCache.Stub mBinder = new IUserCache.Stub() {
        @Override
        public String getUserName() throws RemoteException {
            Log.e(TAG, "getUserName: ");
            return "zhanweikai";
        }

        @Override
        public String getUserPassword() throws RemoteException {
            Log.e(TAG, "getUserPassword: ");
            return "12341234";
        }
    };

这个mBinder就是onBind方法要返回的IBinder实例:

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: ");
        return mBinder;  // 绑定之后调用onBind方法
    }

(3)在AndroidManifext.xml声明service标签,并定义action:

        <service
            android:name=".service.UserService"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.aidl.server" />
            </intent-filter>
        </service>

注意
到此服务端编写完成啦,开始写客户端进程

2、写客户端进程:
(1)在客户端bindService就可以调用服务端的onBind方法,并且返回IBinder实例,调用ServiceConnection的onServiceConnected方法,并且调用onServiceConnected把返回的IBinder实例作为参数进去

    public boolean bindService(Context context) {
        Intent intent = new Intent();
        intent.setAction("com.example.aidl.server");
        final Intent eintent = new Intent(createExplicitFromImplicitIntent(context,intent));
        return context.bindService(eintent,mServiceConn,Context.BIND_AUTO_CREATE);
    }
    private ServiceConnection mServiceConn = new ServiceConnection() {
        // 参数的这个IBinder参数就是服务端的onBind方法返回过来的
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected: ");
            mUserCache = IUserCache.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected: ");
            mUserCache = null;
        }
    };

(2)在onServiceConnected方法,拿到IBinder实例参数,调用IUserCache.Stub.asInterface方法,创建出IUserCache实例。这个IUserCache类也是要写一个aidl文件,包名和服务端创建的aidl包名一致:

package com.android.mybaselibrary;

// Declare any non-default types here with import statements

interface IUserCache {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    String getUserName();

    String getUserPassword();
}

然后make project 就可以自动生成IUserCache.java

回到(1)上面代码:

            mUserCache = IUserCache.Stub.asInterface(service);

这里拿到了mUserCache 实例就可以,获取服务端返回的数据了,比如我要getName:

    public String getName(){
        try {
            String userName = mUserCache.getUserName();
            Log.i(TAG, "getName: " + userName);
            return mUserCache == null ? "" : mUserCache.getUserName();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return "";
    }

只要调用了bindService绑定服务,就可以通过mUserCache实例调用getUserName方法,来调用服务端重写的getUserName方法,获取字符串“zhanweikai”。

  • 简单分析一下跨进程通信执行的流程:

1、首先客户端调用context.bindService方法,在intent里面设置action隐式意图绑定服务---->使指定action的Service调用onBind方法,onBind方法执行完,返回IBinder实例–>把返回的IBinder实例,同时调用客户端的onServiceConnected方法,把IBinder实例作为参数传递到客户端。。

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected: ");
            mUserCache = IUserCache.Stub.asInterface(service);
        }

上面代码,是怎么把IBinder实例转成IUserCache实例的,看asInterface方法代码:

    public static com.android.mybaselibrary.IUserCache asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.android.mybaselibrary.IUserCache))) {
        return ((com.android.mybaselibrary.IUserCache)iin);
      }
      return new com.android.mybaselibrary.IUserCache.Stub.Proxy(obj);
    }
    private static class Proxy implements com.android.mybaselibrary.IUserCache
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
    }	

上面代码可以看到,asInterface方法,就是创建一个Proxy实例,而这个Proxy实例就是一个代理对象,它实现IUserCache这个接口。自然就是要重写IUserCache接口的两个方法getUserName和getUserPassowrd。(把aidl文件看成是一个接口也是阔以的)

拿到了mUserCache这个实例之后,我就可以在客户端调用getUserName方法。而这个方法调用的就是刚刚说的Proxy类实现IUserCache接口,重写的getUserName方法:

      @Override public java.lang.String getUserName() 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 {
          // 找指定的应用DESCRIPTOR
          _data.writeInterfaceToken(DESCRIPTOR);
          // 这里调用了mRemote.transact方法,很重要!
          boolean _status = mRemote.transact(Stub.TRANSACTION_getUserName, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getUserName();
          }
          _reply.readException();
          _result = _reply.readString();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }

上面Proxy类重写的getUserName方法中,mRemote就是IBinder对象。客户端调用了IBinder的transact方法,就会调用服务端的onTransact方法:

    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      ....
      switch (code)
      {
       ....
        case TRANSACTION_getUserName:
        {
          data.enforceInterface(descriptor);
          java.lang.String _result = this.getUserName();
          reply.writeNoException();
          reply.writeString(_result);
          return true;
        }
        case TRANSACTION_getUserPassword:
        {
          data.enforceInterface(descriptor);
          java.lang.String _result = this.getUserPassword();
          reply.writeNoException();
          reply.writeString(_result);
          return true;
        }
       ......
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }

可以看到客户端的transact和服务单的onTransact参数都是一致的。传入的TRANSACTION_getUserName。在onTransact对应的case调用:

  java.lang.String _result = this.getUserName();

这个this就是服务端在service里面创建mBinder实例时重写的getUserName。调用getUserName,并把返回值赋值给_result 变量。

reply.writeString(_result);

把_result数据写进_reply里面。然后返回true。

回到客户端,调用完transact返回true之后,则:

          _reply.readException();
          _result = _reply.readString();

把_reply读出来,赋值给_result。最终返回出来。

2、讲了这么多,我想捋一下,IUserCache.java这个接口、Stub类、Proxy类,这三者关系:

public interface IUserCache extends android.os.IInterface
{
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.android.mybaselibrary.IUserCache
  {

    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {

    }
   
    private static class Proxy implements com.android.mybaselibrary.IUserCache
    {
      @Override public java.lang.String getUserName() throws android.os.RemoteException
      {
       ....
        return _result;
      }
      @Override public java.lang.String getUserPassword() throws android.os.RemoteException
      {
        ....
        return _result;
      }      
    }
   }

  public java.lang.String getUserName() throws android.os.RemoteException;
  public java.lang.String getUserPassword() throws android.os.RemoteException;
}

总结:
在服务端创建Binder实例重写IUserCache的两个抽象方法getUserName和getUserPassword。客户端调用bindService方法—>服务端的onBind方法,返回IBinder实例—>IBinder实例作为参数回调客户端的onServiceConnected—>客户端拿到Proxy实例即IUserCache实例,拿到这个实例调用getUserName和getUserPassword,即可调用远程服务端的getUserName和getPassword。

  • Binder通信源码跟踪
    本次Binder通信的源码跟踪,很复杂,正好学习一下怎么阅读源码的步骤吧!
    1、为什么客户端调用bindService后会调用服务端的onBind方法,然后再调用客户端的onServiceConnected方法:

(1)先从客户端调用的bindService方法开始:

context.bindService(eintent,mServiceConn,Context.BIND_AUTO_CREATE);

bindService是Context的抽象方法

    public abstract boolean bindService(@RequiresPermission Intent service,
            @NonNull ServiceConnection conn, @BindServiceFlags int flags);

那就找Context的实现类,我们熟悉的ContextImpl:

    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        warnIfCallingFromSystemProcess();
        // 跟踪
        return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), getUser());
    }

看bindServiceCommon方法:

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
           ......
           // 跟踪!   
            int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
         .....
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

上面代码可以看到调用了ActivityManager.getService()的bindService方法。要怎么找到这个bindService的实现呢?看bindService方法所在的类在哪里定义的:

    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

这里额外提一下,ServiceManager是用来管理Binder驱动的:

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    // binder驱动调用底层的服务 IPC通信
                    // ServiceManager用来管理Binder驱动。  已经注册了服务。统一由ServiceManager管理
                    // AMS的Binder都存在ServiceManager列表里面。
                   final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };
}

上面ActivityManager.getService().bindService();就是进行跨进程通信,从ServiceManager拿到AMS的IBinder对象,然后通过转成对应的ActivityManagerService代理类,通过这个代理类就可以调用AMS的bindService方法。(IPC跨进程通信!)




回过头来,
所以bindService就是跨进程通信,调用Proxy的bindService方法,所以
要找到IActivityManager的实现类,就可以找到bindService方法的实现,这里不卖关子,直接说,ActivityManagerService就是ActivityManager的实现类,所以去里面找bindService方法吧:

    // IActivityManager的实现类就是ActivityManagerService
    public int bindService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String callingPackage,
            int userId) throws TransactionTooLargeException {
       .....
        synchronized(this) {
            // 调到这里!
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, callingPackage, userId);
        }
    }

跟踪bindServiceLocked方法:

// bindServiceLocked方法内容颇多 我们只关注代码最后一部分
// ActiveServices.java
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {
    ...
    if (s.app != null && b.intent.received) {
      .......
                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);
            }
    ...
    }

跟踪requestServiceBindingLocked:

    private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
               .....
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                // thread是什么东西???thread是 IApplicationThread类的实例
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
             .....
        return true;
    }

上面r.app.thread.scheduleBindService又是一次跨进程通信,就是AMS拿到另一个App进程的IBinder(服务端进程),这个thread就是IBinder对象,通过这个thread跨进程调用服务端进程的scheduleBindService方法。(第二次跨进程通信!)

这里要跟踪scheduleBindService方法。thread报红,点不进去看这个方法呀。那就看看这个thread是什么东西。先看app是什么东西:

    ProcessRecord app;
final class ProcessRecord {
    // 这个类重要!实现类 在ActivityThread里面找!!!
    IApplicationThread thread;
}

thread是IApplicationThread类型。这个IApplicationThread一看就是接口,要找到它的实现类,才能看到scheduleBindService方法。
直接说,ApplicationThread就是IApplicationThread的实现类,而ApplicationThread是ActivityThread的一个内部类。

public final class ActivityThread extends ClientTransactionHandler {
......
    private class ApplicationThread extends IApplicationThread.Stub {
        public final void scheduleBindService(IBinder token, Intent intent,
                boolean rebind, int processState) {
            updateProcessState(processState, false);
            BindServiceData s = new BindServiceData();
            s.token = token;
            s.intent = intent;
            s.rebind = rebind;

            if (DEBUG_SERVICE)
                Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
                        + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
            sendMessage(H.BIND_SERVICE, s);  // 发送一个消息BIND_SERVICE
        }
    }

}

因为Binder执行是多线程,所以scheduleBindService是运行在子线程,sendMessage最终会转到主线程进行消息处理!

上面代码可以看到发送一个消息BIND_SERVICE。转到主线程,找到接收消息的代码:

                    // 在这里接收到BIND_SERVICE消息
                case BIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                    handleBindService((BindServiceData)msg.obj);  // 重点!
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;

跟踪handlerBindService方法:

    private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);  // 拿到服务对象
       ......
                        // 调用onBind方法
                        IBinder binder = s.onBind(data.intent);
                        // 发布服务 把binder实例以参数形式传入
                        // 这个publishService是在ActivityManagerService实现的
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);
               .....
    }

拿到服务对象,调用服务端的onBind方法。然后再进行跨进程通信,拿到AMS的IBinder驱动,调用AMS的publishService方法,发布服务。(第三次跨进程调用)。

publishService又是向ServiceMangaer拿到AMS的Binder驱动,进行跨进程通信,把调用onBind返回的binder对象回传给客户端。

(此时一直还在ActivityThread的内部类ApplicationThread )
这里终于看到s.onBind方法,调用了Service的onBind方法!这个服务对象就是服务端的service,具体怎么远程调用的,这我也不太清楚。
再看怎么在调用onBind方法之后,调用onServiceConnected方法。

    // 发布服务 把binder实例以参数形式传入
    // 这个publishService是在ActivityManagerService实现的
    ActivityManager.getService().publishService(
    data.token, data.intent, binder);
    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

publishService方法原来是在IActiivtyManager接口的方法,刚刚在找bindService实现方法时,也提到了。IActivityManager的实现类ActivityManagerService:

// ActivityManagerService.java
    /**
     * 调完onBind方法就会调用publishService
     * @param token
     * @param intent
     * @param service
     */
    public void publishService(IBinder token, Intent intent, IBinder service) {

            // 调到这里
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }

跟踪publishServiceLocked方法:

    void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
                              ...... 
       // 这个service是binder   找到connected方法在哪实现的
       c.conn.connected(r.name, service, false);

                          .......
    }

connected这个方法报红,要怎么找到该方法,那就看conn是什么

    final IServiceConnection conn;  // The client connection.

它是IServiceConnection,这个类在哪有见过呢,在刚刚bindServiceCommon是有见过的,通过这个方法可以找到它的实现类:

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
            ......
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;
        ....
        if (mPackageInfo != null) 
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
    }

这个方法里面sd就是IServiceConnection看它怎么赋值的,跟踪getServiceDispatcher方法:

    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
            LoadedApk.ServiceDispatcher sd = null;
            .....
            return sd.getIServiceConnection();
    }

这个sd就是LoadedApk.ServiceDispatcher类。可以直接点getIServiceConnection方法进去。

        IServiceConnection getIServiceConnection() {
            return mIServiceConnection;
        }
 private final ServiceDispatcher.InnerConnection mIServiceConnection;

 mIServiceConnection = new InnerConnection(this);

这不很清楚了嘛,IServiceConnection sd;的实现类就是InnerConnection是LoadedApk的内部类。点进去看

        private static class InnerConnection extends IServiceConnection.Stub {
          .....   
            // connected在这里实现    ActiveServices调用了该方法
            public void connected(ComponentName name, IBinder service, boolean dead)
                    throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service, dead);
                }
            }
        }

这不就看到了c.conn.connected(r.name, service, false);的方法了嘛。继续跟踪sd.connected方法:

        public void connected(ComponentName name, IBinder service, boolean dead) {
            if (mActivityThread != null) {
                mActivityThread.post(new RunConnection(name, service, 0, dead));
            } else {
                doConnected(name, service, dead);
            }
        }

跟踪doConnected方法:

        public void doConnected(ComponentName name, IBinder service, boolean dead) {
            .....
            // If there is a new viable service, it is now connected.
            if (service != null) {
                // 最终调用了ServiceConnection的onServiceConnected方法
                // 在这里就被调用到啦!!!! 结束!!!
                mConnection.onServiceConnected(name, service);
            }
          .....
        }

AIDL的执行流程,大致是这样,我现在只是走马观花,跟着视频来走一遍流程而已。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值