Android Binder进程间通信---注册Service组件---封装进程间通信数据

本文参考《Android系统源代码情景分析》,作者罗升阳

一、测试代码:

~/Android/external/binder/server

----FregServer.cpp

~/Android/external/binder/common

----IFregService.cpp

----IFregService.h

~/Android/external/binder/client

----FregClient.cpp

Binder库(libbinder)代码:

~/Android/frameworks/base/libs/binder

----BpBinder.cpp

----Parcel.cpp

----ProcessState.cpp

----Binder.cpp

----IInterface.cpp

----IPCThreadState.cpp

----IServiceManager.cpp

----Static.cpp

~/Android/frameworks/base/include/binder

----Binder.h

----BpBinder.h

----IInterface.h

----IPCThreadState.h

----IServiceManager.h

----IBinder.h

----Parcel.h

----ProcessState.h

驱动层代码:

~/Android//kernel/goldfish/drivers/staging/android

----binder.c

----binder.h

二、源码分析

程序首先开始从Service进程FregServer.cpp的main函数开始执行

~/Android/external/binder/server

----FregServer.cpp

class FregService : public BnFregService
{
        ...........
public:
	static void instantiate()
	{
		defaultServiceManager()->addService(String16(FREG_SERVICE), new FregService());//注册Service
	}
        ...........
};

int main(int argc, char** argv)
{
	FregService::instantiate();

	ProcessState::self()->startThreadPool();
	IPCThreadState::self()->joinThreadPool();
	return 0;
}

在Android Binder进程间通信---ServiceManager代理对象的获取过程http://blog.csdn.net/jltxgcy/article/details/25953361,一文中我们已经分析了defaultServiceManager()获取了ServiceManager代理对象。现在调用addService来注册Service组件。

~/Android/frameworks/base/libs/binder

----IServiceManager.cpp

class BpServiceManager : public BpInterface<IServiceManager>
{
public:
    .........
    virtual status_t addService(const String16& name, const sp<IBinder>& service)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());//写入一个Binder进程间通信请求头
        data.writeString16(name);//写入将要注册的Service组件的名称
        data.writeStrongBinder(service);//将要注册的Service组件封装成一个flat_binder_object结构体,写入data
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }
    ..........
};

将进程间通信数据写入到一个Parcel对象data中,然后将Parcel对象data的内容传递给Binder驱动程序。

首先调用Parcel对象data的成员函数writeInterfaceToken写入一个Binder进程间通信请求头,它的实现如下所示:

~/Android/frameworks/base/libs/binder

----Parcel.cpp

status_t Parcel::writeInterfaceToken(const String16& interface)
{
    writeInt32(IPCThreadState::self()->getStrictModePolicy() |
               STRICT_MODE_PENALTY_GATHER);//整数值,用来描述一个Strict Mode Policy
    // currently the interface identification token is just its name as a string
    return writeString16(interface);//用来描述所请求服务的接口描述符
}

Binder进程间通信请求头由两部分内容组成。第一部分内容是一个整数值,用来描述一个Strict Mode Policy,第二部分内容是一个字符串,用来描述所请求服务的接口描述符。

接着调用Parcel对象data的成员函数writeString16写入将要注册的Service组件的名称。

最后,调用Parcel对象data的成员函数writeStrongBinder将要注册的Service组件封装成一个flat_binder_object结构体,然后传递给Binder驱动程序。将一个Service组件封装成一个flat_binder_object结构体是Binder进程间通信过程的一个重要步骤,接下来我们就着重分析这个过程。

~/Android/frameworks/base/libs/binder

----Parcel.cpp

status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}

调用flatten_binder。

status_t flatten_binder(const sp<ProcessState>& proc,
    const sp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;

    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    if (binder != NULL) {
        IBinder *local = binder->localBinder();//Binder本地对象的
        if (!local) {
            .........
        } else {
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = local->getWeakRefs();//弱引用计数的地址
            obj.cookie = local;//binder本地对象指针
        }
    } else {
        .........
    }

    return finish_flatten_binder(binder, obj, out);//将flat_binder_object结构体obj写入到Parcel对象out中
}

首先定义了一个flat_binder_object结构体obj,然后将它的标志值设置为0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS,其中,0x7f用来描述将要注册的Service组件在处理一个进程间通信请求时,它所使用的Server线程的优先级不能低于0x7f;而FLAT_BINDER_FLAG_ACCEPTS_FDS表示可以将包含文件描述符的进程间通信数据给将要注册的Service组件处理。

接下来调用binder->localBinder(),分析此函数前,我们先看一个uml类图。

参数binder指向的是一个FregService组件,它继承了BBinder类,BBinder类是用来描述一个Binder本地对象的,它的成员函数localBinder用来返回一个Binder本地对象接口。对应实现代码如下:

~/Android/frameworks/base/libs/binder

----Binder.cpp

BBinder* BBinder::localBinder()
{
    return this;//BBinder对象指针
}

接下来分别设置type为BINDER_TYPE_BINDER,binder为其内部的一个弱引用计数对象的地址值,cookie为上面返回的Binder本地对象指针。

最后调用全局函数finish_flatten_binder将flat_binder_object结构体obj写入到Parcel对象out中,它的实现如下所示:

~/Android/frameworks/base/libs/binder

---- Parcel.cpp

inline static status_t finish_flatten_binder(
    const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out)
{
    return out->writeObject(flat, false);//将flat_binder_object结构体flat写入到内部
}

它调用Parcel对象out的成员函数writeObject将flat_binder_object结构体flat写入到内部。Parcel类的成员函数writeObject的实现如下所示:

~/Android/frameworks/base/libs/binder

---- Parcel.cpp

status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
{
    const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;//数据缓冲区如果有足够空间,enoughData为1
    const bool enoughObjects = mObjectsSize < mObjectsCapacity;//偏移数组如果有足够空间,enoughObjects为1
    if (enoughData && enoughObjects) {
restart_write:
        *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;//flat_binder_object结构体存入数据缓冲区mData

        // Need to write meta-data?
        if (nullMetaData || val.binder != NULL) {
            mObjects[mObjectsSize] = mDataPos;//flat_binder_object结构体在mData中偏移写入偏移数组mObjects
            acquire_object(ProcessState::self(), val, this);
            mObjectsSize++;//偏移数组mObjects下一个用于写入数据的位置加一
        }

        // remember if it‘s a file descriptor
        if (val.type == BINDER_TYPE_FD) {
            mHasFds = mFdsKnown = true;
        }

        return finishWrite(sizeof(flat_binder_object));//调整缓冲区mData下一个用来写入数据的位置
    }

    if (!enoughData) {//如果没有足够的空间,那么扩展后重新写入
        const status_t err = growData(sizeof(val));
        if (err != NO_ERROR) return err;
    }
    if (!enoughObjects) {//如果没有足够的空间,那么扩展后重新写入
        size_t newSize = ((mObjectsSize+2)*3)/2;
        size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));
        if (objects == NULL) return NO_MEMORY;
        mObjects = objects;
        mObjectsCapacity = newSize;
    }

    goto restart_write;
}

Parcel类内部有mData和mObjects两个缓冲区,其中,mData是一个数据缓冲区,它里面的内容可能包含有整数、字符串或者Binder对象,即flat_binder_object结构体;mObjects是一个偏移数组,它保存了数据缓冲区中所有Binder对象的位置。Binder驱动程序就是可以通过这个偏移数组找到进程间通信数据中的Binder对象的,以便对它们进行特殊处理。

Parcel类的成员变量mDataPos记录了数据缓冲区mData下一个用来写入数据的位置,而成员变量mDataCapacity则记录了数据缓冲区mData的总大小。成员变量mObjectSize记录了偏移数组mObjects下一个用于写入数据的位置,mObjectCapacity则记录了偏移数组mObjects的总大小。

如果有足够的缓冲区,那么要将flat_binder_object结构体存入数据缓冲区mData,flat_binder_object结构体在mData中偏移写入偏移数组mObjects。

如果数据缓冲区mData和偏移数组mObjects没有足够的空间来写入一个Binder对象,首先扩展他们的空间,然后再写入。

Android Binder进程间通信---注册Service组件---封装进程间通信数据

时间: 2024-08-25 01:53:30

Android Binder进程间通信---注册Service组件---封装进程间通信数据的相关文章

Android Binder进程间通信---注册Service组件---发送和处理BC_TRANSACTION

本文参考<Android系统源代码情景分析>,作者罗升阳 一.测试代码: -/Android/external/binder/server ----FregServer.cpp ~/Android/external/binder/common ----IFregService.cpp ----IFregService.h ~/Android/external/binder/client ----FregClient.cpp Binder库(libbinder)代码: ~/Android/fra

Android Binder进程间通信---注册Service组件---发送和处理BC_REPLY返回协议

本文参考<Android系统源代码情景分析>,作者罗升阳 一.测试代码: -/Android/external/binder/server ----FregServer.cpp ~/Android/external/binder/common ----IFregService.cpp ----IFregService.h ~/Android/external/binder/client ----FregClient.cpp Binder库(libbinder)代码: ~/Android/fra

Android Binder进程间通信---注册Service组件---Server处理BC_TRANSACTION

这是我参照之前在iOS项目中用过的一个不规则形状按钮的第三方Button,这里用Cocos2d-x实现一个相似功能的按钮. 原文地址:http://blog.csdn.net/qqmcy/article/details/26161339 代码下载:http://download.csdn.net/detail/qqmcy/7365843 使用方法: .h // // TestScene.h // maptest // // Created by 杜甲 on 14-5-18. // // #ifn

Android Binder进程间通信---注册Service组件---启动Binder线程池

本文参考<Android系统源代码情景分析>,作者罗升阳 一.测试代码: -/Android/external/binder/server ----FregServer.cpp ~/Android/external/binder/common ----IFregService.cpp ----IFregService.h ~/Android/external/binder/client ----FregClient.cpp Binder库(libbinder)代码: ~/Android/fra

Android笔记二十七.Service组件入门(一).什么是Service?

转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 一.Service 1.Service简介 Service为Android四大组件之一,Service与Activity组件相似,都代表可执行的程序且有自己的生命周期,唯一的区别是Activity组件提供界面方便人机交互而Service只在后台运行且没有交互界面.Service是android 系统中的一种组件,它们都是从Context派生出来的,但是它不能自己运行,只能在后台运行,并且可以和其

Android Binder进程间通信---Service代理对象的获取过程

本文参考<Android系统源代码情景分析>,作者罗升阳 一.测试代码: -/Android/external/binder/server ----FregServer.cpp ~/Android/external/binder/common ----IFregService.cpp ----IFregService.h ~/Android/external/binder/client ----FregClient.cpp Binder库(libbinder)代码: ~/Android/fra

【转】Android - Binder机制

以下几篇文章是较深入分析binder机制. 目录 1. Android - Binder机制 - ServiceManager 2. Android - Binder机制 - 普通service注册 3. Android - Binder机制 - 获得普通service 4. Android - Binder机制 - client和普通service交互 5. Android - Binder机制 - Binder框架总结 6. Android - Binder机制 - ProcessState

android binder 进程间通信机制5-Service注册和代理对象的获取

ServiceManager,其实也是一个Service,不过它的Server端实现并未使用Binder库的结构实现,而是直接打开binder/dev进行通信的,不具有普遍性. 下面以MediaServer中的MediaPlayService为例,说明更加普遍的使用binder通信机制的Service的实现. 一.Service组件的启动 Service组件是在Server进程中运行的,Server进程通常从其main函数启动,启动时通常做两件事: 1.首先将它里面的Service组件注册到Se

android binder 进程间通信机制6-Binder进程间通信机制的JAVA接口

Binder间进程通信的JAVA层接口,主要是通过JNI方法来调用Binder库的C/C++接口 在JAVA层,将Service组件称为JAVA服务,Service组件的代理称为JAVA服务代理. 一.ServiceManager的Java层代理对象(ServiceManagerProxy)的获取过程. 个人感觉JAVA层的ServiceManager的Java服务和Java服务代理的实现结构还是很像的,如下: Java服务类关系图: java服务代理的类关系图: ServiceManager代