I will use call IAudioFlinger::setMode API as a sample scenario to show how the Android IPC
system works. AudioFlinger is a service in the media_server program
Service Manager Run
service_manager provide service manager service to other process. It must be started before any
other service gets running.
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)) {
LOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
svcmgr_handle = svcmgr;
binder_loop(bs, svcmgr_handler);
return 0;
}
It first open “/dev/binder” driver and then call BINDER_SET_CONTEXT_MGR ioctl to let
binder kernel driver know it acts as a manager. Then it enters into a loop to wait for any data from
other process.
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
unsigned readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(unsigned));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (unsigned) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
LOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
if (res == 0) {
LOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
LOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}
Pay attention to BINDER_SERVICE_MANAGER.
/* the one magic object */
#define BINDER_SERVICE_MANAGER ((void*) 0)
BINDER_SERVICE_MANAGER is the registered handle for service_manager. The other process
must use this handle to talk with service_manager.
Get IServiceManager
To get an IServiceManager instance the only method is to call defaultServiceManager
implemented in IServiceManager.cpp.
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
if (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
}
}
return gDefaultServiceManager;
}
gDefaultServiceManager is defined in libutil, so any program or library which included libutil will
have this symbol, it’s unique in one process. The first time gDefaultServiceManager is NULL, so
it will first get a ProcessState instance through ProcessState::self(). One process has only one
ProcessState instance. ProcessState will open “/dev/binder” driver for IPCThreadState use.
ProcessState::ProcessState()
: mDriverFD(open_driver())
Now we have an instance of ProcessState, let’s look at the getContextObject.
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
{
if (supportsProcesses()) {
return getStrongProxyForHandle(0);
} else {
return getContextObject(String16("default"), caller);
}
}
The board support binder driver, so we will get into getStrongProxyForHandle. (Handle 0 is
reserved for service manager, which will be explained later.)
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)) {
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;
}
The first time b will be NULL, so the code will new an BpBinder instance. BpBinder is a base
proxy class for remote binder object.
BpBinder::BpBinder(int32_t handle)
: mHandle(handle)
, mAlive(1)
, mObitsSent(0)
, mObituaries(NULL)
{
LOGV("Creating BpBinder %p handle %d\n", this, mHandle);
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
IPCThreadState::self()->incWeakHandle(handle);
}
IPCThreadState::incWeakHandle will add a BC_INCREFS command in output buffer.
void IPCThreadState::incWeakHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
mOut.writeInt32(BC_INCREFS);
mOut.writeInt32(handle);
}
Now getContextObject returns a BpBinder instance, it will be interface_cast to IServiceManager.
interface_cast is defined in IInterface.h. It will be extended as:
inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj)
{
return IServiceManager::asInterface(obj);
}
Now let’s take a look at definition of IServiceManager.
class IServiceManager : public IInterface
{
public:
DECLARE_META_INTERFACE(ServiceManager);
/**
* Retrieve an existing service, blocking for a few seconds
* if it doesn't yet exist.
*/
virtual sp<IBinder> getService( const String16& name) const = 0;
/**
* Retrieve an existing service, non-blocking.
*/
virtual sp<IBinder> checkService( const String16& name) const = 0;
/**
* Register a service.
*/
virtual status_t addService( const String16& name,
const sp<IBinder>& service) = 0;
/**
* Return list of all existing services.
*/
virtual Vector<String16> listServices() = 0;
enum {
GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION,
};
};
DECLARE_META_INTERFACE macro is defined as follows in IInterface.h. And it will be
extended to the following code:
static const String16 descriptor;
static sp<IServiceManager> asInterface(const sp<IBinder>& obj);
virtual String16 getInterfaceDescriptor() const;
As you can see, DECLARE_META_INTERFACE macro declares two functions which are
implemented by IMPLEMENT_META_INTERFACE macro in IServiceManager.cpp.
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
The code will be extended like this.
const String16 IServiceManager::descriptor(NAME);
String16 IServiceManager::getInterfaceDescriptor() const {
return IServiceManager::descriptor;
}
sp<IServiceManager> IServiceManager::asInterface(const sp<IBinder>& obj)
{
sp<IServiceManager> intr;
if (obj != NULL) {
intr = static_cast<IServiceManager*>(
obj->queryLocalInterface(
IServiceManager::descriptor).get());
if (intr == NULL) {
intr = new BpServiceManager(obj);
}
}
return intr;
}
So IServiceManager::asInterface will finally new a BpServiceManager instance and return it to
user. BpServiceManager works as a proxy for remote BnServiceManager. Any operation on
IServiceManager now actually is to call the corresponding virtual functions in BpServiceManager.
Summary:
This section gives out details in how to get a proxy object for remote object.
Assume you want to implement your own service IFunnyTest, you must do the following:
Put DECLARE_META_INTERFACE(FunnyTest) macro in your interface header file.
Put IMPLEMENT_META_INTERFACE(Funnytest, “your unique name”) macro in your
interface source file.
Implement your own BpFunnyTest class.
Generate AudioFlinger Service
media_server program will start the AudioFlinger service. Here is the code.
int main(int argc, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
LOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
AudioFlinger will call IServiceManager::addService, which is a RPC call.
void AudioFlinger::instantiate() {
defaultServiceManager()->addService(
String16("media.audio_flinger"), new AudioFlinger());
}
AudioFlinger inherits from BnAudioFlinger, which is a template BnInterface class.
class BnAudioFlinger : public BnInterface<IAudioFlinger>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
BnInterface inherits from BBinder.
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
virtual String16 getInterfaceDescriptor() const;
protected:
virtual IBinder* onAsBinder();
};
template<typename INTERFACE>
IBinder* BnInterface<INTERFACE>::onAsBinder()
{
return this;
}
According to BnInterface’m implementation we know that the parameter passed to
IServiceManager::addService is the address of new AudioFlinger instance. BBinder derives from
IBinder, its transact function is to call virtual function onTransact.
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(0);
status_t err = NO_ERROR;
switch (code) {
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
err = onTransact(code, data, reply, flags);
break;
}
if (reply != NULL) {
reply->setDataPosition(0);
}
return err;
}
The most important virtual functions is onTransact. BnAudioFlinger implemented the virtual
function. For the scenario, we just need to focus on SET_MODE branch.
status_t BnAudioFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case SET_MODE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int mode = data.readInt32();
reply->writeInt32( setMode(mode) );
return NO_ERROR;
} break;
media_server will enter into a loop through IPCThreadState::joinThreadPool, just like
service_manager, it will be waited data from other process in talkWithDriver.
void IPCThreadState::joinThreadPool(bool isMain)
{
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
status_t result;
do {
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) continue;
cmd = mIn.readInt32();
result = executeCommand(cmd);
}
// 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);
}
Assume you want to implement your own service IFunnyTest, you must do the following:
Implement your own BnFunnyTest class.
In the process your service running, call IPCThreadState::joinThreadPool to start the loop for
binder.
RPC Call IServiceManager::addService
We called IServiceManager::addService, which means call BpServiceManager::addService.
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.readInt32() : err;
}
Parcel is simple. We can think it as a continuous buffer. Pay attention here, service parameter
points to BBinder object(AudioFlinger derived from Bn)
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
flatten_binder will generate a Binder command. Because BBinder is a local binder object, so the
code branch to the lines marked red.
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();
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
LOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
obj.type = BINDER_TYPE_HANDLE;
obj.handle = handle;
obj.cookie = NULL;
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = local->getWeakRefs();
obj.cookie = local;
}
}
return finish_flatten_binder(binder, obj, out);
}
Pay attention to the red lines, local’s address is put into the packet(It will be used later). After the
packet for addService RPC call is made, BpServiceManager::addService will call BpBinder’s
transact.
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
BpBinder calls IPCThreadState::transact to start a transaction to the binder object corresponding
to mHandle. For this scenario, mHandle is 0.
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck();
flags |= TF_ACCEPT_FDS;
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 (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
err = waitForResponse(NULL, NULL);
}
dis
分享到:
相关推荐
本文档标题为《经济机器是如何工作的--雷·达里奥》,由雷·达里奥撰写,其内容旨在阐述作者对经济体系的理解和工作原理。雷·达里奥是著名的投资者和桥水基金(Bridgewater Associates)的创始人,他的经济模型被...
大脑是如何工作的 How the mind works 可以为你的某些工作找到科学依据
The Illustrated Network How TCPIP Works in a Modern Network(2nd) 英文无水印原版pdf 第2版 pdf所有页面使用FoxitReader、PDF-XChangeViewer、SumatraPDF和Firefox测试都可以打开 本资源转载自网络,如有侵权...
How Google WorksHow Google WorksHow Google WorksHow Google WorksHow Google WorksHow Google WorksHow Google WorksHow Google WorksHow Google WorksHow Google Works
How Software Works
You’ll learn how to write apps from scratch, ensure interoperability, choose the best solutions for common problems, and avoid development pitfalls. Coverage includes: Implementing threads, ...
[互联网工作原理].Que,.How.the.Internet.Works.(2006),8Ed.chm
标题中提到的"IPC MJPEG Stream via HTTP Commands"指的是如何通过HTTP命令获取网络摄像机(IPC, Internet Protocol Camera)的Motion JPEG(MJPEG)视频流。MJPEG是一种视频格式,它将每一帧单独编码为JPEG图像,...
applications developers can learn effectively and efficiently how to interface to the system; system administrators can learn how to maintain, tune, and configure the system; and systems programmers ...
In this new book, you'll learn how the module system improves reliability and maintainability, and how it can be used to reduce tight coupling of system components. Foreword by Kevlin Henney. ...
Written by a Silicon Graphics X Window System and OpenGL expert, OpenGL Programming for the X Window System uses the OpenGL Utility Toolkit (GLUT) to show how OpenGL programs can be constructed ...
The Android Developer's Cookbook Building Applications with the Android SDK and Source Project Code 源书(pdf)及源代码12章全都有(rar) Book Description Want to get started building applications for ...
《How Tomcat Works》中文版一书详细剖析了Tomcat服务器的内部工作机制。该书基于Tomcat 4.1.12和5.0.18两个版本,深入讲解了其servlet容器的架构和运作原理,尤其是代号为Catalina的核心组件。 Tomcat是一个开源的...
But to truly master Linux, you need to understand its internals, like how the system boots, how networking works, and what the kernel actually does. In this completely revised second edition of the ...