第一. Binder可以很好的实现Client-Server架构
第二. Binder的传输效率和可操做性很好
第三. Binder机制的安全性很高android
ServiceManager是用户空间的一个守护进程,它一直运行在后台。它的职责是管理Binder机制中的各个Server。
当Server启动时,Server会将"Server对象的名字"连同"Server对象的信息"一块儿注册到ServiceManager中,
而当Client须要获取Server接入点时,则经过"Server的名字"来从ServiceManager中找到对应的Server。安全
int main(int argc, char **argv)
{
struct binder_state *bs;
void *svcmgr = BINDER_SERVICE_MANAGER;
bs = binder_open(128*1024);
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
svcmgr_handle = svcmgr;
binder_loop(bs, svcmgr_handler);
return 0;
}cookie
MediaServer是系统诸多重要service的栖息地,如架构
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;框架
}ide
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
{
return getStrongProxyForHandle(0);
}函数
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
// Special case for context manager...
// The context manager is the only object for which we create
// a BpBinder proxy without already holding a reference.
// Perform a dummy transaction to ensure the context manager
// is registered before we create the first local reference
// to it (which will occur when creating the BpBinder).
// If a local reference is created for the BpBinder when the
// context manager is not present, the driver will fail to
// provide a reference to the context manager, but the
// driver API does not return status.
//
// Note that this is not race-free if the context manager
// dies while this code runs.
//
// TODO: add a driver API to wait for context manager, or
// stop special casing handle 0 for context manager and add
// a driver API to get a handle to the context manager with
// proper reference counting.
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}oop
android::sp<IServiceManager> IServiceManager::asInterface(const android::sp<android::IBinder>& obj)
{
android::sp<IServiceManager> intr;
if (obj != NULL) {
intr = static_cast<IServiceManager*>(
obj->queryLocalInterface(
IServiceManager::descriptor).get());
if (intr == NULL) {
intr = new BpServiceManager(obj);
}
}
return intr;
}ui
终于要开始讲解Client-Server交互了
MediaPlayerService服务经过addService请求注册到ServiceManager中
在这个addService请求中MediaPlayerService是Client,而ServiceManager是Serverthis
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// mAlive的初始值为1
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
satus_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
//++[Debug][mark_chen][2014/07/11][Binder] Binder transaction bad command issue
if (!mCanTransact) {
#if (HTC_SECURITY_DEBUG_FLAG == 1)
TextOutput::Bundle _b(alog);
alog << "Invalid BC_TRANSACTION " << (void*)pthread_self() << " / hand "
<< handle << " / code " << TypeCode(code) << ": "
<< indent << data << dedent << endl;
#endif
}
//--[Debug][mark_chen][2014/07/11][Binder] Binder transaction bad command issue
status_t err = data.errorCheck();
flags |= TF_ACCEPT_FDS;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
<< handle << " / code " << TypeCode(code) << ": "
<< indent << data << dedent << endl;
}
if (err == NO_ERROR) {
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
(flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}
if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}
if ((flags & TF_ONE_WAY) == 0) {
#if 0
if (code == 4) { // relayout
ALOGI(">>>>>> CALLING transaction 4");
} else {
ALOGI(">>>>>> CALLING transaction %d", code);
}
#endif
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
#if 0
if (code == 4) { // relayout
ALOGI("<<<<<< RETURNING transaction 4");
} else {
ALOGI("<<<<<< RETURNING transaction %d", code);
}
#endif
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
<< handle << ": ";
if (reply) alog << indent << *reply << dedent << endl;
else alog << "(none requested)" << endl;
}
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = (uint32_t)mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing waitForResponse Command: "
<< getReturnString(cmd) << endl;
}
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
case BR_DEAD_REPLY:
err = DEAD_OBJECT;
goto finish;
case BR_FAILED_REPLY:
err = FAILED_TRANSACTION;
goto finish;
case BR_ACQUIRE_RESULT:
{
ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
const int32_t result = mIn.readInt32();
if (!acquireResult) continue;
*acquireResult = result ? NO_ERROR : INVALID_OPERATION;
}
goto finish;
case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish;
if (reply) {
if ((tr.flags & TF_STATUS_CODE) == 0) {
reply->ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t),
freeBuffer, this);
} else {
err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
}
} else {
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
continue;
}
}
goto finish;
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
if (err != NO_ERROR) {
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
}
return err;
}
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
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());
}
}
void IPCThreadState::joinThreadPool(bool isMain)
{
LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
// This thread may have been spawned by a thread that was in the background
// scheduling group, so first we will make sure it is in the foreground
// one to avoid performing an initial transaction in the background.
set_sched_policy(mMyThreadId, SP_FOREGROUND);
status_t result;
do {
//++[Debug][mark_chen][2014/07/11][Binder] Binder transaction bad command issue
mCanTransact = false;
processPendingDerefs();
mCanTransact = true;
//--[Debug][mark_chen][2014/07/11][Binder] Binder transaction bad command issue
// now get the next command to be processed, waiting if necessary
result = getAndExecuteCommand();
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
abort();
}
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
//++[Debug][mark_chen][2015/05/27][Binder] Add log for debug
//LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
// (void*)pthread_self(), getpid(), (void*)result);
ALOGD("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p, fd: %d\n",
(void*)pthread_self(), getpid(), (void*)(intptr_t)result, mProcess->mDriverFD);
//--[Debug][mark_chen][2015/05/27][Binder] Add log for debug
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
// 和Binder驱动交互
result = talkWithDriver();
if (result >= NO_ERROR) {
...
// 读取mIn中的数据
cmd = mIn.readInt32();
...
// 调用executeCommand()对数据进行处理。
result = executeCommand(cmd);
...
}
return result;
}
前面,以MediaPlayerService为例,介绍了Server服务是如何经过addService请求添加到ServiceManager中的。
下面,将以MediaPlayer获取MediaPlayerService服务为例,介绍Client是如何经过getService请求从ServiceManager中获取到Server接入点的。
sp<IMediaPlayerService> IMediaDeathNotifier::sMediaPlayerService;
...
const sp<IMediaPlayerService>& IMediaDeathNotifier::getMediaPlayerService()
{
...
if (sMediaPlayerService == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.player"));
...
usleep(500000); // 0.5 s
} while (true);
...
1.建立你的.aidl文件
package com.cao.android.demos.binder.aidl;
import com.cao.android.demos.binder.aidl.AIDLActivity;
interface AIDLService {
void registerTestCall(AIDLActivity cb);
void invokCallBack();
}
2.实现服务端
private final AIDLService.Stub mBinder = new AIDLService.Stub() {
@Override
public void invokCallBack() throws RemoteException {
Log("AIDLService.invokCallBack");
Rect1 rect = new Rect1();
rect.bottom=-1;
rect.left=-1;
rect.right=1;
rect.top=1;
callback.performAction(rect);
}
3.实现代理端
AIDLService mService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
Log("connect service");
mService = AIDLService.Stub.asInterface(service);
try {
mService.registerTestCall(mCallback);
} catch (RemoteException e) {
}
}
public void onServiceDisconnected(ComponentName className) {
Log("disconnect service");
}
基类IInterface
为server 端提供接口,它的子类声明了service 可以实现的全部的方法;
基类IBinder
BBinder 与BpBinder 均为IBinder 的子类,所以能够看出IBinder 定义了binder IPC 的通讯协议,BBinder 与BpBinder 在这个协议框架内进行的收和发操做,构建了基本的binder IPC 机制。
基类BpRefBase
client 端在查询SM 得到所需的的BpBinder 后,BpRefBase 负责管理当前得到的BpBinder 实例。
1.BpINTERFACE
若是client 想要使用binder IPC 来通讯,那么首先会从SM 出查询并得到server 端service 的BpBinder ,在client 端,这个对象被认为是server 端的远程代理。为了可以使client 可以像本地调用同样调用一个远程server ,server 端须要向client 提供一个接口,client 在在这个接口的基础上建立一个BpINTERFACE ,使用这个对象,client 的应用可以想本地调用同样直接调用server 端的方法。而不用去关心具体的binder IPC 实现。
下面看一下BpINTERFACE 的原型:
class BpINTERFACE : public BpInterface<IINTERFACE>
顺着继承关系再往上看
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
BpINTERFACE 分别继承自INTERFACE ,和BpRefBase ;
2.BnINTERFACE
在定义android native 端的service 时,每一个service 均继承自BnINTERFACE(INTERFACE 为service name) 。BnINTERFACE 类型定义了一个onTransact 函数,这个函数负责解包收到的Parcel 并执行client 端的请求的方法。
顺着BnINTERFACE 的继承关系再往上看,
class BnINTERFACE: public BnInterface<IINTERFACE>
IINTERFACE 为client 端的代理接口BpINTERFACE 和server 端的BnINTERFACE 的共同接口类,这个共同接口类的目的就是保证service 方法在C-S 两端的一致性。
再往上看
class BnInterface : public INTERFACE, public BBinder
同时咱们发现了BBinder 类型,这个类型又是干什么用的呢?既然每一个service 都可视为一个binder ,那么真正的server 端的binder 的操做及状态的维护就是经过继承自BBinder 来实现的。可见BBinder 是service 做为binder 的本质所在。
class IBinder : public virtual RefBase
{
public:
...
virtual sp<IInterface> queryLocalInterface(const String16& descriptor); //返回一个IInterface对象
...
virtual const String16& getInterfaceDescriptor() const = 0;
virtual bool isBinderAlive() const = 0;
virtual status_t pingBinder() = 0;
virtual status_t dump(int fd, const Vector<String16>& args) = 0;
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0) = 0;
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = NULL,
uint32_t flags = 0) = 0;
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
void* cookie = NULL,
uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = NULL) = 0;
...
virtual BBinder* localBinder(); //返回一个BBinder对象
virtual BpBinder* remoteBinder(); //返回一个BpBinder对象
};
其实它们的区别很简单,BpBinder 是client 端建立的用于消息发送的代理,而BBinder 是server 端用于接收消息的通道。查看各自的代码就会发现,虽然两个类型均有transact 的方法,可是二者的做用不一样,BpBinder 的transact 方法是向IPCThreadState 实例发送消息,通知其有消息要发送给BD ;而BBinder 则是当IPCThreadState 实例收到BD 消息时,经过BBinder 的transact 的方法将其传递给它的子类BnSERVICE 的onTransact 函数执行server 端的操做。
Parcel 是binder IPC 中的最基本的通讯单元,它存储C-S 间函数调用的参数. 可是Parcel 只能存储基本的数据类型,
若是是复杂的数据类型的话,在存储时,须要将其拆分为基本的数据类型来存储。
简单的Parcel 读写再也不介绍,下面着重介绍一下2 个函数
1.writeStrongBinder
当client 须要将一个binder 向server 发送时,能够调用此函数。例如
virtual status_t addService(const String16& name, const sp<IBinder>& service)
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
看一下writeStrongBinder 的实体
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
接着往里看flatten_binder
仍是拿addService 为例,它的参数为一个BnINTERFACE 类型指针,BnINTERFACE 又继承自BBinder ,
BBinder* BBinder::localBinder()
{
return this;
}
因此写入到Parcel 的binder 类型为BINDER_TYPE_BINDER ,同时你在阅读SM 的代码时会发现若是SM 收到的service 的binder 类型不为BINDER_TYPE_HANDLE 时,SM 将不会将此service 添加到svclist ,可是很显然每一个service 的添加都是成功的,addService 在开始传递的binder 类型为BINDER_TYPE_BINDER ,SM 收到的binder 类型为BINDER_TYPE_HANDLE ,那么这个过程中究竟发生了什么?
为了搞明白这个问题,花费我不少的事件,最终发现了问题的所在,原来在BD 中作了以下操做(drivers/staging/android/Binder.c) :
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
..........................................
if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
fp->handle = ref->desc;
..........................................
}
阅读完addService 的代码,你会发现SM 只是保存了service binder 的handle 和service 的name ,那么当client 须要和某个service 通讯了如何得到service 的binder 呢?看下一个函数
2.readStrongBinder
当server 端收到client 的调用请求以后,若是须要返回一个binder 时,能够向BD 发送这个binder ,当IPCThreadState 实例收到这个返回的Parcel 时,client 能够经过这个函数将这个被server 返回的binder 读出。
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
unflatten_binder(ProcessState::self(), *this, &val);
return val;
}
往里查看unflatten_binder
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 = static_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;
}
发现若是server 返回的binder 类型为BINDER_TYPE_BINDER 的话,也就是返回一个binder 引用的话,直接获取这个binder ;若是server 返回的binder 类型为BINDER_TYPE_HANDLE 时,也就是server 返回的仅仅是binder 的handle ,那么须要从新建立一个BpBinder 返回给client 。