android binder 机制二(client和普通server)
在讲它们之间的通信之前,我们先以MediaServer为例看看普通Server进程都在干些什么。
int main()
{
……
// 获得ProcessState实例
sp<ProcessState> proc(ProcessState::self());
// 得到ServiceManager的Binderclient实例
sp<IServiceManager> sm = defaultServiceManager();
……
// 通过ServiceManager的Binderclient向系统注冊MediaPlayer服务
MediaPlayerService::instantiate();
……
// start run
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
defaultServiceManager()在上一篇中已经有介绍。
MediaPlayerService::instantiate()的实现例如以下,就是addService到ServiceManager。和上一篇的getService类似,故不作介绍。
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
接下来看ProcessState::self()->startThreadPool()的实现
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());
}
}
class PoolThread : public Thread
{
public:
PoolThread(bool isMain)
: mIsMain(isMain)
{
} protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
} const bool mIsMain;
};
实际上。这个函数只是是创建了一个新的线程,然后在线程中又创建了一个IPCThreadState。并调用了joinThreadPool函数。
void IPCThreadState::joinThreadPool(bool isMain)
{
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); set_sched_policy(mMyThreadId, SP_FOREGROUND); status_t result;
do {
processPendingDerefs();
// 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); mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd; result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
result = executeCommand(cmd); set_sched_policy(mMyThreadId, SP_FOREGROUND);
} return result;
}
我们能够看到。主线程和新创建的线程。都在做一件事,talkWithDriver读取Binder驱动,然后就executeCommand处理请求。这就是普通Server进程启动后一直都在干的事:等待client请求。处理请求。然后返回给client。
既然Server进程已经准备就绪了。那么如今就应该要轮到Client端闪亮登场,Client端将通过Binder来请求Server做一些事情。接下来看代码:
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
status_t err = UNKNOWN_ERROR;
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(fd, offset, length))) {
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
getMediaPlayerService()之前分析过。返回一个BpMediaPlayerService,这里问一个问题:为什么这个BpMediaPlayerService就能和MediaPlayerService进程进行Binder通信,而不是和别的什么Server进程?
再回想一下代码:
/*static*/const sp<IMediaPlayerService>&
IMediaDeathNotifier::getMediaPlayerService()
{
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
ALOGW("Media player service not published, waiting...");
usleep(500000); // 0.5 s
} while (true); if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
ALOGE_IF(sMediaPlayerService == 0, "no media player service!? ");
return sMediaPlayerService;
}
答案应该在binder = sm->getService(String16("media.player"))这句话里面,返回值binder将会作为BpMediaPlayerService构造函数的參数。以下来看getService
virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
for (n = 0; n < 5; n++){
sp<IBinder> svc = checkService(name);
if (svc != NULL) return svc;
ALOGI("Waiting for service %s...\n", String8(name).string());
sleep(1);
}
return NULL;
} virtual sp<IBinder> checkService( const String16& name) const
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder();
}
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 = 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;
}
unflatten_binder函数中。flat->type和flat->handle在ServiceManager中被赋值,当中flat->type的值是BINDER_TYPE_HANDLE,flat->handle的值是所查询Service相应的Handle值,中间过程涉及到binder底层驱动的代码,不在这里阐述。
这样binder = sm->getService(String16("media.player"))运行后。binder=BpBinder(Handle),当中Handle的值为所查询Service相应的Handle值。这样。client端和service端之间的通信就建立了。
分析完getMediaPlayerService()。建立了通信的通路,接下来正式进入通信。
sp<IMediaPlayer>player(service->create(this, mAudioSessionId));
进入IMediaPlayerService.cpp看看create的实现。
virtual sp<IMediaPlayer> create(
const sp<IMediaPlayerClient>& client, int audioSessionId) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeStrongBinder(client->asBinder());
data.writeInt32(audioSessionId); remote()->transact(CREATE, data, &reply);
return interface_cast<IMediaPlayer>(reply.readStrongBinder());
}
经过之前的分析,我们能够非常easy的指导remote()返回的是BpBinder(handle), transact(CREATE,data, &reply)将数据写入到Binder驱动,并唤醒Service进程。接下来我们就来看Server将作何反应。
如今我们已经知道,Server进程一直都在读取Binder驱动。然后executeCommand。以下就直接看executeCommand的实现。
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR; switch (cmd) {
……
case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(result == NO_ERROR,
"Not enough command data for brTRANSACTION");
if (result != NO_ERROR) break; Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t), freeBuffer, this); const pid_t origPid = mCallingPid;
const uid_t origUid = mCallingUid; mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid; int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
if (gDisableBackgroundScheduling) {
if (curPrio > ANDROID_PRIORITY_NORMAL) {
// We have inherited a reduced priority from the caller, but do not
// want to run in that state in this process. The driver set our
// priority already (though not our scheduling class), so bounce
// it back to the default before invoking the transaction.
setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
}
} else {
if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
// We want to use the inherited priority from the caller.
// Ensure this thread is in the background scheduling class,
// since the driver won't modify scheduling classes for us.
// The scheduling group is reset to default by the caller
// once this method returns after the transaction is complete.
set_sched_policy(mMyThreadId, SP_BACKGROUND);
}
} //ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid); Parcel reply;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_TRANSACTION thr " << (void*)pthread_self()
<< " / obj " << tr.target.ptr << " / code "
<< TypeCode(tr.code) << ": " << indent << buffer
<< dedent << endl
<< "Data addr = "
<< reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
<< ", offsets addr="
<< reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
}
if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error); } else {
const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error);
} //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
// mCallingPid, origPid, origUid); if ((tr.flags & TF_ONE_WAY) == 0) {
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
sendReply(reply, 0);
} else {
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
} mCallingPid = origPid;
mCallingUid = origUid; IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
<< tr.target.ptr << ": " << indent << reply << dedent << endl;
} }
break;
……
default:
printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
result = UNKNOWN_ERROR;
break;
} if (result != NO_ERROR) {
mLastError = result;
} return result;
}
看这里:
if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error); } else {
const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error);
}
这里的b实际上就是我们在addService时创建的MediaPlayerService对象,经过包含Binder驱动在内的传输和转换,就成这么个数据类型了。
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
看以下的继承关系,
classMediaPlayerService : public BnMediaPlayerService
MediaPlayerService本身没有实现transact方法,因此。b->transact(tr.code,buffer, &reply, tr.flags)是调用了BnMediaPlayerService的transact方法。
进入IMediaPlayerService.cpp中找到BnMediaPlayerService的transact方法,例如以下:
status_t BnMediaPlayerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch (code) {
case CREATE: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<IMediaPlayerClient> client =
interface_cast<IMediaPlayerClient>(data.readStrongBinder());
int audioSessionId = data.readInt32();
sp<IMediaPlayer> player = create(client, audioSessionId);
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
} break;
……
}
sp<IMediaPlayer> player = create(client,audioSessionId)这里调用的create方法在MediaPlayerService类中实现。进入MediaPlayerService.cpp中:
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
int audioSessionId)
{
pid_t pid = IPCThreadState::self()->getCallingPid();
int32_t connId = android_atomic_inc(&mNextConnId); sp<Client> c = new Client(
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getCallingUid()); ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
IPCThreadState::self()->getCallingUid());
/* add by Gary. start {{----------------------------------- */
c->setScreen(mScreen);
/* add by Gary. end -----------------------------------}} */
c->setSubGate(mGlobalSubGate); // 2012-03-12, add the global interfaces to control the subtitle gate wp<Client> w = c;
{
Mutex::Autolock lock(mLock);
mClients.add(w);
}
return c;
}
到这里为止,Server处理完了事务。接下来将处理结果返回给client,看这里:
if ((tr.flags & TF_ONE_WAY) == 0) {
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
sendReply(reply, 0);
} else {
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
} status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
{
status_t err;
status_t statusBuffer;
err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
if (err < NO_ERROR) return err; return waitForResponse(NULL, NULL);
}
调用sendReply将结果写回Binder驱动,从而得以返回client进程。
通信完毕。
android binder 机制二(client和普通server)的更多相关文章
- Android Binder机制彻底梳理二
根据AIDL了解整体调用流程[重点分析AIDL流程]: 在上一次https://www.cnblogs.com/webor2006/p/11741743.html中我们已经对Android Binde ...
- Android Binder机制(一) Binder的设计和框架
这是关于Android中Binder机制的一系列纯技术贴.花了一个多礼拜的时间,才终于将其整理完毕.行文于此,以做记录:也是将自己所得与大家分享.和以往一样,介绍Binder时,先讲解框架,然后再从设 ...
- 【转】Android - Binder机制
以下几篇文章是分析binder机制里讲得还算清楚的 目录 1. Android - Binder机制 - ServiceManager 2. Android - Binder机制 - 普通servic ...
- Android Binder机制简单了解
Binder -- 一种进程间通信(IPC)机制, 基于OpenBinder来实现 毫无疑问, 老罗的文章是不得不看的 Android进程间通信(IPC)机制Binder简要介绍和学习计划 浅谈Ser ...
- Android Binder机制原理(史上最强理解,没有之一)(转)
原文地址: http://blog.csdn.net/universus/article/details/6211589 Binder是Android系统进程间通信(IPC)方式之一.Linux已经拥 ...
- ANDROID BINDER机制浅析
Binder是Android上一种IPC机制,重要且较难理解.由于Linux上标准IPC在灵活和可靠性存在一定不足,Google基于OpenBinder的设计和构想实现了Binder. 本文只简单介绍 ...
- 浅谈android binder机制
binder机制 是谷歌优化在android上更适合终端的IPC(多进程通信方式),满足系统对通信方式,传输性能和安全性的要求. 特性: 1. 用驱动程序来推进进程间的通信.2. 通过共享内存来提高性 ...
- Android Binder机制详解:手写IPC通信
想要掌握一样东西,最好的方式就是阅读理解它的源码.想要掌握Android Binder,最好的方式就是写一个AIDL文件,然后查看其生成的代码.本文的思路也是来自于此. 简介 Binder是Andro ...
- Android binder机制---概述
1.进程间通讯的原因 目前操作系统都使用虚拟存储技术,管理内存. 假设是32位机器,0-3G是用户空间,3-4G是系统使用.虚拟内存和逻辑内存都按4K分页.这样虚拟内存和逻辑内存就存在对应关系. 一个 ...
随机推荐
- Android -- 自定义标题栏,背景颜色填充满
设置标题栏背景 1> 准备背景图片: background_pix.png 注:用背景图片比用颜色好处,可以让背景看起来有凹凸感. 2> drawable文件夹下放xml文件 bitmap ...
- SecureRandom-随机数的生成
随机数:算法+种子 随机数据不随机 学习了:https://www.cnblogs.com/deng-cc/p/8064481.html StringBuffer buffer = new Strin ...
- Java的泛型中,通配符可以设置上限和下限
上限:<? extends T> ?是T和T的子类 下限:<? super T> ?是T和T的父类 怎么看待这个上限和下限呢 首先应该想 其实对于Java来说 <? ex ...
- 你使用 Web 平台安装程序命令行工具
你使用 Web 平台安装程序命令行工具 获取的软件由其所有者授权给你.Microsoft 未授予你第三方软件的任何权利.已成功加载主源: https://go.microsoft.com/?linki ...
- 鼠标增强软件StrokeIt使用方法
1 可以从以下网址下载该软件,解压之后有两个文件 http://dl.pconline.com.cn/html_2/1/65/id=7185&pn=0.html 2 先安装英文版的,再安装中文 ...
- STL - 容器 - UnorderedSet(一)
一些简单操作 UnorderedSetTest.cpp #include <unordered_set> #include <numeric> #include ". ...
- 笔记本样式的EditText控件(每行均带下划虚线)
package com.zongyi.trip.ui; import com.zongyi.trip.R; import android.annotation.SuppressLint; import ...
- Websocket——Websocket原理
偶然在知乎上看到一篇回帖,瞬间认为之前看的那么多资料都不及这一篇回帖让我对 websocket 的认识深刻有木有.所以转到我博客里,分享一下.比較喜欢看这样的博客,读起来非常轻松.不枯燥,没有布道师的 ...
- linux安装JDK环境,JDK6.0即java 1.6.0
下载 (1)更改权限:# chmod 755 jdk-1.6.0_23-linux-i586.rpm.bin 执行安装:# ./ jdk-1.6.0_23-linux-i586.rpm.bin 此步完 ...
- 在命令行上 使用 mutt, fetchmail, maildrop, msmtp 收发邮件
基于shell 现在已经有了 Mail.app, Thunderbird, Outlook 这些图形化工具能很方便的处理邮件,为啥还需要 mutt 这种命令行文本方式的邮件工具呢?mutt 的一个优势 ...