Android 四大组件 - bindService 的通信过程

Posted HongChengDarren

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 四大组件 - bindService 的通信过程相关的知识,希望对你有一定的参考价值。

相关文章链接:

1. Android Framework - 学习启动篇
2. Android Binder 驱动 - Media 服务的添加过程
3. Android Binder 驱动 - 启动 ServiceManager 进程
4. Android Binder 驱动 - 内核驱动层源码分析
5. Android Binder 驱动 - 从驱动层来分析服务的添加过程
6. Android Binder 驱动 - 从 Java 层来跟踪服务的查找过程
7. Android 四大组件 - 进程的 fork 创建过程

相关源码文件:

/frameworks/base/core/java/android/app/ContextImpl.java
/frameworks/base/core/java/android/app/ActivityManagerNative.java

/frameworks/base/core/jni/android_util_Binder.cpp
/frameworks/base/core/jni/android_os_Parcel.cpp
/frameworks/native/libs/binder/Parcel.cpp
/drivers/staging/android/binder.c

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
/frameworks/base/core/java/android/app/ActivityThread.java

1. 代码示例

本文主要从 bindService 的跨进程通信与数据交互来入手分析,关于其具体的创建和绑定流程,大家可以看看之前的内容。aidl 一直都是一个晦涩难懂的内容,笔者在几年前也曾反复尝试去了解其原理,其过程至今想想仍然是心有余悸,因此建议大家如果是刚入手 Android ,只需要了解开发套路就可以了。但还是倡导大家,等有了一定技术沉淀之后,要尝试着去理解其内部实现原理。我们先来看一个简单的示例代码

// 客户端
public class MainActivity extends AppCompatActivity 
    // 客户端一定要获取aidl的实例
    private UserAidl mUserAidl;
    private ServiceConnection mServiceConn = new ServiceConnection() 
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) 
            // 链接好了  service就是服务端给我们的 IBinder
            mUserAidl = UserAidl.Stub.asInterface(service);
        

        @Override
        public void onServiceDisconnected(ComponentName name) 
            // 断开链接
        
    ;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this,MessageService.class);
        bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
    

    public void testClick(View view) 
        try 
            Log.e("TAG","userName = "+mUserAidl.getUserName());
         catch (RemoteException e) 
            e.printStackTrace();
        
    


// 服务端
public class MessageService extends Service 

    @Override
    public IBinder onBind(Intent intent) 
        // 绑定
        return mBinder;
    
    
    private final UserAidl.Stub mBinder = new UserAidl.Stub()
    

        @Override
        public String getUserName() throws RemoteException 
            return "Darren@163.com";
        

        @Override
        public String getUserPassword() throws RemoteException 
            return "19940223";
        
    ;

2. Binder 对象初始化

服务端返回的是 Aidl.Stub 服务对象,这个对象是我们自定义 aidl 后,编译器帮我们自动生成的一个对象,该对象继承自 Binder.java 对象,子类在构建对象时默认会执行父类的构造函数,也就是说会执行 Binder.java 的构造函数:

    public Binder() 
        // 调用初始化方法
        init();
    

    // 调用 native 方法
    private native final void init();

    static void android_os_Binder_init(JNIEnv* env, jobject obj)
    
      JavaBBinderHolder* jbh = new JavaBBinderHolder();
      ...
      env->SetLongField(obj, gBinderOffsets.mObject, (jlong)jbh);
    

由上面的源码可以看出,Stub 对象在构建的时候,会对应绑定 native 层的一个 JavaBBinderHolder 对象,至于为什么要创建 native 层对象,是因为跨进程通信的核心是要基于 binder 驱动。

3. Stub 对象传递

    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) 
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, Process.myUserHandle());
    

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            UserHandle user) 
        IServiceConnection sd;
        ...
        if (mPackageInfo != null) 
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                    mMainThread.getHandler(), flags);
         else 
            throw new RuntimeException("Not supported in system context");
        
        validateServiceIntent(service);
        try 
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) 
                flags |= BIND_WAIVE_PRIORITY;
            
            service.prepareToLeaveProcess();
            // 像 AMS 发起 bind 请求
            int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
            if (res < 0) 
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            
            return res != 0;
         catch (RemoteException e) 
            throw new RuntimeException("Failure from system", e);
        
    

由于 ServiceConnection 是一个普通对象,并不能用来做跨进程传递,所以在 bindService 的源码底层,系统帮我包装了一个可以跨进程传递的 IServiceConnection 对象,该对象是一个 Stub 对象。

    public int bindService(IApplicationThread caller, IBinder token,
            Intent service, String resolvedType, IServiceConnection connection,
            int flags,  String callingPackage, int userId) throws RemoteException 
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeStrongBinder(token);
        service.writeToParcel(data, 0);
        data.writeString(resolvedType);
        // asBinder 返回的是 connection 自身
        data.writeStrongBinder(connection.asBinder());
        data.writeInt(flags);
        data.writeString(callingPackage);
        data.writeInt(userId);
        mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
        reply.readException();
        int res = reply.readInt();
        data.recycle();
        reply.recycle();
        return res;
    

    static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
    
      Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
      if (parcel != NULL) 
          const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
          if (err != NO_ERROR) 
              signalExceptionForError(env, clazz, err);
          
      
    

    sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
    
      if (obj == NULL) return NULL;
      // 返回的其实是一个 JavaBBinder
      if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) 
          JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject);
          return jbh != NULL ? jbh->get(env, obj) : NULL;
      
      ...
      return NULL;
    
    // 这个之前的文章有讲就不再贴代码了
    status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
    
      return flatten_binder(ProcessState::self(), val, this);
    

上面会调用 writeStrongBinder 方法将 IServiceConnection 对象写入到 Parcel 内存中,其实也就是将 native 层的 JavaBBinder 对象写入到 native 层的 Parcel 中,关于 flatten_binder 方法的实现原理大家可以参考之前的文章。

4. 客户端驱动层处理过程

我们向 ServiceManager 查询到的 AMS 对象,其实是一个 BindProxy.java 对象,对应 native 层的 BpBinder 对象,也就是说 mRemote.transact 最后会调用 BpBinder.cpp 的 transact 方法。

static void binder_transaction(struct binder_proc *proc,
			       struct binder_thread *thread,
			       struct binder_transaction_data *tr, int reply)

	if (reply) 
		...
	 else 
		if (tr->target.handle) 
			struct binder_ref *ref;
            // 找到 AMS 目标进程的 binder_node 和 binder_proc
			ref = binder_get_ref(proc, tr->target.handle);
			target_node = ref->node;
		 else 
			...
		
                ...
		
	...
	off_end = (void *)offp + tr->offsets_size;
	for (; offp < off_end; offp++) 
		struct flat_binder_object *fp;
        ...
		fp = (struct flat_binder_object *)(t->buffer->data + *offp);
		switch (fp->type) 
		case BINDER_TYPE_BINDER:
		case BINDER_TYPE_WEAK_BINDER: 
			struct binder_ref *ref;
            // 先通过 fp->binder 从自己进程找 binder_node 
			struct binder_node *node = binder_get_node(proc, fp->binder);
            // 刚开始第一次是找不到的
			if (node == NULL) 
                // 把他添加到当前进程
				node = binder_new_node(proc, fp->binder, fp->cookie);
				...
			
			// 添加到目标进程
			ref = binder_get_ref_for_node(target_proc, node);
			if (ref == NULL) 
				return_error = BR_FAILED_REPLY;
				goto err_binder_get_ref_for_node_failed;
			
            // 替换 type 和 handle 值 
			if (fp->type == BINDER_TYPE_BINDER)
				fp->type = BINDER_TYPE_HANDLE;
			else
				fp->type = BINDER_TYPE_WEAK_HANDLE;
			fp->handle = ref->desc;
		 break;
		...
		
	
	
	t->work.type = BINDER_WORK_TRANSACTION;
	list_add_tail(&t->work.entry, target_list);
	tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
	list_add_tail(&tcomplete->entry, &thread->todo);
        // 唤醒目标进程的等待队列
	if (target_wait)
		wake_up_interruptible(target_wait);
	return;

5. AMS 服务端处理 bind 过程

AMS 接收到 bindService 请求后会去读取 IServiceConnection 对象,注意这里读取到的 IServiceConnection 其实已经是本地的一个 BpBinder 了,只不过我们可以通过 BpBinder 对象回调到客户端的 onServiceConnected 绑定方法。

case BIND_SERVICE_TRANSACTION: 
  data.enforceInterface(IActivityManager.descriptor);
  IBinder b = data.readStrongBinder();
  IApplicationThread app = ApplicationThreadNative.asInterface(b);
  IBinder token = data.readStrongBinder();
  Intent service = Intent.CREATOR.createFromParcel(data);
  String resolvedType = data.readString();
  b = data.readStrongBinder();
  int fl = data.readInt();
  String callingPackage = data.readString();
  int userId = data.readInt();
  IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
  int res = bindService(app, token, service, resolvedType, conn, fl, callingPackage, userId);
  reply.writeNoException();
  reply.writeInt(res);
  return true;


static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)

    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) 
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    
    return NULL;


sp<IBinder> Parcel::readStrongBinder() const

    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);
    return val;


status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)

    const flat_binder_object* flat = in.readObject(false);

    if (flat) 
        switch (flat->type) 
            case BINDER_TYPE_BINDER:
                *out = reinterpret_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        
    
    return BAD_TYPE;

6. 进程循环等待处理请求

服务端处理客户端的请求,肯定会有一个等待执行处理的过程,但整个交互逻辑流程分析下来,并没有发现服务端有等待的过程。那服务端到底是怎样进入等待的呢?这个得追溯到 Zygote 创建进程的流程去。

    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller 
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
        redirectLogStreams();

        commonInit();
        nativeZygoteInit();
        applicationInit(targetSdkVersion, argv, classLoader);
    

    private static final native void nativeZygoteInit();

    static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
    
      gCurRuntime->onZygoteInit();
    

    virtual void onZygoteInit()
    
        // 初始化 binder 驱动
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\\n");
        // 启动一个线程进入循环处理客户端 binder 请求
        proc->startThreadPool();
    
    
    void ProcessState::spawnPooledThread(bool isMain)
    
      if (mThreadPoolStarted) 
          String8 name = makeBinderThreadName();
          ALOGV("Spawning new pooled thread, name=%s\\n", name.string());
          sp<Thread> t = new PoolThread(isMain);
          t->run(name.string());
      
    

    class PoolThread : public Thread
    
    public:
        PoolThread(bool isMain)
            : mIsMain(isMain)
        
        
    
    protected:
        virtual bool threadLoop()
        
            IPCThreadState::self()->joinThreadPool(mIsMain);
            return false;
        
    
        const bool mIsMain;
    ;

    void IPCThreadState::joinThreadPool(bool isMain)
    
      ...
      status_t result;
      do 
          ...
          // 进入 binder 驱动的 wait 队列上进行等待
          result = getAndExecuteCommand();
          ...
       while (result != -ECONNREFUSED && result != -EBADF);
      ...
    

视频地址:https://pan.baidu.com/s/1qd2UafSGELpKwBsT30IuHw
视频密码:0tgv

以上是关于Android 四大组件 - bindService 的通信过程的主要内容,如果未能解决你的问题,请参考以下文章

Android之四大组件六大布局五大存储 总结

Android N 四大组件的工作原理

Android组件-1-四大组件

Android四大组件

Android 四大组件

Android之四大组件六大布局五大存储