Top Banner
Android 进程间通信机制(Binder)介绍 Author灯下野狐 E-mail[email protected] Date 2012-02 PS 欢迎交流,转载请务必注明出处。 先看下 Binder 相关的一个简单类图 以一个简单的 binder 应用示例来看 Android binder 这一进程间通信机制,文件结构: ~/MyFolder/ans/packages/apps/bitest$ tree . . |-- Android.mk // 同时生成 libdxyhservice.sodxyh_servicedxyh_client .mk |-- dxyhclient // 一可执行程序与 service 通信(当然也可是 java 通过 jni 来与服务通信) | `-- DxyhClient.cpp |-- dxyhservice // 服务程序(类似于 mediaserver 这一可执行程序) | |-- DxyhService.cpp | |-- DxyhService.h | `-- main_dxyhservice.cpp |-- include // 头文件 | `-- IDxyhService.h `-- libdxyhservice // 动态库 `-- IDxyhService.cpp 示例相关类图: 看到和上面一张很像,事实上就是参照 ServiceManager 而写的。 我们从 main_dxyhservice.cpp 这个文件开始,看一个 service 是如何注册到系统中的。 所有服务均挂在 service_manager.c 中的 struct svcinfo *svclist 这个链表中。 下面就进入到程序 main_dxyhservice.cpp 中的 main()函数: =============================================================== ==> 相关类 class RefBase { public: void incStrong(const void* id) const; void decStrong(const void* id) const; void forceIncStrong(const void* id) const;
93

Android 进程间通信机制(Binder)介绍

Mar 20, 2023

Download

Documents

Khang Minh
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Android 进程间通信机制(Binder)介绍

Android进程间通信机制(Binder)介绍

Author: 灯下野狐E-mail: [email protected] : 2012-02PS : 欢迎交流,转载请务必注明出处。

先看下 Binder相关的一个简单类图

以一个简单的 binder应用示例来看 Android中 binder这一进程间通信机制,文件结构:~/MyFolder/ans/packages/apps/bitest$ tree . . |-- Android.mk // 同时生成 libdxyhservice.so、dxyh_service、dxyh_client的.mk|-- dxyhclient // 一可执行程序与 service通信(当然也可是 java通过 jni来与服务通信)| `-- DxyhClient.cpp |-- dxyhservice // 服务程序(类似于 mediaserver这一可执行程序)| |-- DxyhService.cpp | |-- DxyhService.h | `-- main_dxyhservice.cpp |-- include // 头文件| `-- IDxyhService.h `-- libdxyhservice // 动态库 `-- IDxyhService.cpp 示例相关类图:

看到和上面一张很像,事实上就是参照 ServiceManager而写的。我们从 main_dxyhservice.cpp这个文件开始,看一个 service是如何注册到系统中的。

所有服务均挂在 service_manager.c中的 struct svcinfo *svclist这个链表中。

下面就进入到程序 main_dxyhservice.cpp中的 main()函数:=================================================================> 相关类class RefBase { public: void incStrong(const void* id) const; void decStrong(const void* id) const; void forceIncStrong(const void* id) const;

Page 2: Android 进程间通信机制(Binder)介绍

//! DEBUGGING ONLY: Get current strong ref count. int32_t getStrongCount() const;

class weakref_type { public: RefBase* refBase() const; void incWeak(const void* id); void decWeak(const void* id); bool attemptIncStrong(const void* id); //! This is only safe if you have set OBJECT_LIFETIME_FOREVER. bool attemptIncWeak(const void* id);

//! DEBUGGING ONLY: Get current weak ref count. int32_t getWeakCount() const;

//! DEBUGGING ONLY: Print references held on object. void printRefs() const;

//! DEBUGGING ONLY: Enable tracking for this object. // enable -- enable/disable tracking // retain -- when tracking is enable, if true, then we save a stack trace // for each reference and dereference; when retain == false, we // match up references and dereferences and keep only the // outstanding ones. void trackMe(bool enable, bool retain); }; weakref_type* createWeak(const void* id) const; weakref_type* getWeakRefs() const;

//! DEBUGGING ONLY: Print references held on object. inline void printRefs() const { getWeakRefs()->printRefs(); }

//! DEBUGGING ONLY: Enable tracking of object. inline void trackMe(bool enable, bool retain) { getWeakRefs()->trackMe(enable, retain); }

// used to override the RefBase destruction. class Destroyer { friend class RefBase; public: virtual ~Destroyer(); private: virtual void destroy(RefBase const* base) = 0; };

// Make sure to never acquire a strong reference from this function. The // same restrictions than for destructors apply. void setDestroyer(Destroyer* destroyer);

protected: RefBase(); virtual ~RefBase();

//! Flags for extendObjectLifetime() enum { OBJECT_LIFETIME_WEAK = 0x0001, OBJECT_LIFETIME_FOREVER = 0x0003 }; void extendObjectLifetime(int32_t mode); //! Flags for onIncStrongAttempted() enum { FIRST_INC_STRONG = 0x0001 }; virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id); virtual void onLastWeakRef(const void* id);

private: friend class weakref_type; class weakref_impl; RefBase(const RefBase& o);

Page 3: Android 进程间通信机制(Binder)介绍

RefBase& operator=(const RefBase& o); weakref_impl* const mRefs; };

class RefBase::weakref_impl : public RefBase::weakref_type { public: volatile int32_t mStrong; volatile int32_t mWeak; RefBase* const mBase; volatile int32_t mFlags; Destroyer* mDestroyer;

weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE) // 初始强指针引用计数 , mWeak(0) // 初始弱指针引用计数 , mBase(base) // 指向 RefBase类的指针 // 引用计数控制旗标,可以是: // OBJECT_LIFETIME_WEAK —— 对象受到弱指针引用控制 // OBJECT_LIFETIME_FOREVER —— 对象不受任何指针类型的控制,所以需用户手动 delete , mFlags(0) , mDestroyer(0) { }

void addStrongRef(const void* /*id*/) { } void removeStrongRef(const void* /*id*/) { } void addWeakRef(const void* /*id*/) { } void removeWeakRef(const void* /*id*/) { } void printRefs() const { } void trackMe(bool, bool) { } };

class ProcessState : public virtual RefBase{public: static sp<ProcessState> self(); // 返回 ProcessState全局单例(整个系统就此一个)

static void setSingleProcess(bool singleProcess);

void setContextObject(const sp<IBinder>& object); sp<IBinder> getContextObject(const sp<IBinder>& caller); void setContextObject(const sp<IBinder>& object, const String16& name); sp<IBinder> getContextObject(const String16& name, const sp<IBinder>& caller); bool supportsProcesses() const;

void startThreadPool(); typedef bool (*context_check_func)(const String16& name, const sp<IBinder>& caller, void* userData); bool isContextManager(void) const; bool becomeContextManager( context_check_func checkFunc, void* userData);

sp<IBinder> getStrongProxyForHandle(int32_t handle); wp<IBinder> getWeakProxyForHandle(int32_t handle); void expungeHandle(int32_t handle, IBinder* binder);

void setArgs(int argc, const char* const argv[]); int getArgC() const; const char* const* getArgV() const;

void setArgV0(const char* txt);

void spawnPooledThread(bool isMain); private: // IPCThreadState类是此类的友元类 friend class IPCThreadState; ProcessState();// 构造函数为私有,则不能在类体外用 new关键字生成对象 ~ProcessState();

ProcessState(const ProcessState& o); ProcessState& operator=(const ProcessState& o); struct handle_entry {

Page 4: Android 进程间通信机制(Binder)介绍

IBinder* binder; RefBase::weakref_type* refs; }; handle_entry* lookupHandleLocked(int32_t handle);

int mDriverFD; void* mVMStart; mutable Mutex mLock; // protects everything below. Vector<handle_entry>mHandleToObject;

bool mManagesContexts; context_check_func mBinderContextCheckFunc; void* mBinderContextUserData; KeyedVector<String16, sp<IBinder> > mContexts;

String8 mRootDir; bool mThreadPoolStarted; volatile int32_t mThreadPoolSeq;};===============================================================int main(int argc, char **argv) { // 创建单例的 ProcessState对象 sp<ProcessState> proc(ProcessState::self()); // 获得 ServiceManager这个服务管家 sp<IServiceManager> sm = defaultServiceManager(); // 将 DxyhService这个服务注册到系统中 sm->addService(String16("service.dxyh"), new DxyhService()); // 下面两个函数很重要,作为 Service的两个“ ”消息 循环 ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); return(0); }我们直接看第 2句(第 1句中的 ProcessState::self()这个成员函数会在下面一齐叙述): // 获得 ServiceManager对象 sp<IServiceManager> sm = defaultServiceManager(); 获得系统所有 service “ ”的 管家 ,ServiceManager,现在来看 defaultServiceManager()这个函数做了哪些事情:=================================================================> 相关全局变量Mutex gDefaultServiceManagerLock;sp<IServiceManager> gDefaultServiceManager;===============================================================sp<IServiceManager> defaultServiceManager() { // 开始 gDefaultServiceManager肯定为 NULL,会在下面 ProcessState::self()中创建 if (gDefaultServiceManager != NULL) return gDefaultServiceManager; { AutoMutex _l(gDefaultServiceManagerLock); if (gDefaultServiceManager == NULL) { // 下面这句甚为核心!! gDefaultServiceManager = interface_cast<IServiceManager>( // 调用全局唯一的 ProcessState对象的 getContextObject函数, // 注意这里传入的参数为 NULL,也就是 0 ProcessState::self()->getContextObject(NULL)); } } return gDefaultServiceManager; }看下 ProcessState类的 self()成员函数,用到了单例模式(使用全局锁来解决并发问题):=================================================================> 相关全局变量(frameworks/libs/binder/Static.cpp):sp<ProcessState> gProcess; // 全局 ProcessState对象,整个系统有且只有一个Mutex gProcessMutex; // 全局锁解决单例模式中的并发问题===============================================================sp<ProcessState> ProcessState::self(){ if (gProcess != NULL) return gProcess; AutoMutex _l(gProcessMutex); if (gProcess == NULL) gProcess = new ProcessState; return gProcess;}

这个 AutoMutex类很是特别,原理就是在该类对象的生命周期内锁住所传入的锁,在对象消亡时通过析构函数来解锁,具体看其类定义就清楚了:==> 代码路径:frameworks/base/libs/binder/ProcessState.cpp // Manages the mutex automatically. It'll be locked when Autolock is

Page 5: Android 进程间通信机制(Binder)介绍

// constructed and released when Autolock goes out of scope. class Autolock { public: inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); /* 构造锁住 */ } inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); /* 构造锁住 */ } inline ~Autolock() { mLock.unlock(); /* 析构解锁 */ } private: Mutex& mLock; };在使用时常看到将该类对象放在一个内部代码块中,例如: ... { Autolock _l(mutex); ... }这样从_l定义之初到下面一个右大括号结束之前,之间的代码就被 mutex锁住了。

开始 gProcess指针定然为 NULL,故需要 new一个 ProcessState对象,该类构造函数为:=================================================================> 相关全局变量#define MAP_FAILED ((void *)-1)

#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))===============================================================ProcessState::ProcessState() : mDriverFD(open_driver()) // 很重要的 open_driver函数,具体下面再看 , mVMStart(MAP_FAILED) // 共享内存起始地址(默认初始为-1) , mManagesContexts(false) // …… , mBinderContextCheckFunc(NULL) , mBinderContextUserData(NULL) , mThreadPoolStarted(false) , mThreadPoolSeq(1) { if (mDriverFD >= 0) { // XXX Ideally, there should be a specific define for whether we // have mmap (or whether we could possibly have the kernel module // availabla). #if !defined(HAVE_WIN32_IPC) // mmap the binder, providing a chunk of virtual address space to receive // transactions. // 开辟一块只读私有共享内存,大小为(1M-8K = 1016K) mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,

mDriverFD, 0); if (mVMStart == MAP_FAILED) { // *sigh* LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n"); close(mDriverFD); mDriverFD = -1; } #else mDriverFD = -1; #endif } if (mDriverFD < 0) { // Need to run without the driver, starting our own thread pool. } }先打开 binder设备,描述符存于 mDriverFD,然后就是关联该 fd至一块共享内存,属性为私有、只读,最后就是其他成员变量的初始化。打开 binder设备的 open_driver()函数如下:=================================================================> 相关结构体/* Use with BINDER_VERSION, driver fills in fields. */ struct binder_version {

/* driver protocol version -- increment with incompatible change */ signed long protocol_version;

};

==> 相关全局变量static bool gSingleProcess = false; // 系统是否仅能支持单进程(默认当然为 false了)

/* This is the current protocol version. */ #define BINDER_CURRENT_PROTOCOL_VERSION 7

#define BINDER_VERSION _IOWR('b', 9, struct binder_version)===============================================================static int open_driver() { if (gSingleProcess) { return -1; }

// 调用系统函数 open()来打开 binder驱动,驱动层对应的函数为 binder_open(),参见 ServiceManager分析 int fd = open("/dev/binder", O_RDWR); if (fd >= 0) {

Page 6: Android 进程间通信机制(Binder)介绍

// > if your call execv..., this fd will be automatically closed fcntl(fd, F_SETFD, FD_CLOEXEC); int vers; #if defined(HAVE_ANDROID_OS) // 获得当前 binder的版本,驱动层对应的函数为 binder_ioctl() status_t result = ioctl(fd, BINDER_VERSION, &vers); #else status_t result = -1; errno = EPERM; #endif if (result == -1) { LOGE("Binder ioctl to obtain version failed: %s", strerror(errno)); close(fd); fd = -1; } if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) { LOGE("Binder driver protocol does not match user space protocol!"); close(fd); fd = -1; } #if defined(HAVE_ANDROID_OS) // 最大线程数为 15 size_t maxThreads = 15; // 最终效果为给内核 proc变量中的 max_threads成员赋值为 15 result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); if (result == -1) { LOGE("Binder ioctl to set max threads failed: %s", strerror(errno)); } #endif } else { LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno)); } return fd; }打开 binder的驱动节点/dev/binder,并试图获取当前 binder驱动的版本号。看下 binder驱动函数 binder_ioctl()中对应的操作部分:=================================================================> 相关全局变量/* This is the current protocol version. */ #define BINDER_CURRENT_PROTOCOL_VERSION 7===============================================================static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {

int ret; struct binder_proc *proc = filp->private_data; // 取出私有数据struct binder_thread *thread; unsigned int size = _IOC_SIZE(cmd); void __user *ubuf = (void __user *)arg;

……

switch (cmd) { ……

case BINDER_VERSION: if (size != sizeof(struct binder_version)) {

ret = -EINVAL; goto err;

} if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,

&((struct binder_version *)ubuf)->protocol_version)) { ret = -EINVAL; goto err;

} break;

}……

}看到将 BINDER_CURRENT_PROTOCOL_VERSION返回给上层,反正作用就是来验证当前 binder驱动的版本是否正确。

接下来的会调用 ProcessState这个类中的 getContextObject()函数,具体如下:// 注意传入的参数 caller为 0sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller) { if (supportsProcesses()) { // 真机环境肯定支持多进程,所以走这里 return getStrongProxyForHandle(0); } else { return getContextObject(String16("default"), caller); } }所以接下来会调用 getStrongProxyForHandle()函数,看名字好像是获得参数 handle的强引用 binder代理:=================================================================> 相关的结构体struct handle_entry { IBinder* binder;

Page 7: Android 进程间通信机制(Binder)介绍

RefBase::weakref_type* refs; };===============================================================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)) { // 注意:这里传递进来的 handle的值为 0; // 当 e为新创建的或者是 e所对应的 IBinder(及其子类)对象还未有任何弱引用,表明 handle所对应 // 的 BpBinder还不存在,创建之,以供上层用户使用; 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; }接下来看 lookupHandleLocked()这个函数,它实际上很简单,根据 handle在 ProcessState中的成员变量mHandleToObject这个向量中查找,若找到对应的 handle_entry则返回,反之则创建一个新的 handle_entry加入到mHandleToObject中:ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle) { // mHandleToObject是一个向量(Vector) // 初始情况,N的值为 0 const size_t N=mHandleToObject.size(); if (N <= (size_t)handle) { handle_entry e; e.binder = NULL; e.refs = NULL; status_t err = mHandleToObject.insertAt(e, N, handle+1-N); if (err < NO_ERROR) return NULL; } return &mHandleToObject.editItemAt(handle); }

所以由上图可知,若 N为 3,handle为 4 “ ”时插入了两个 空 的 handle_entry对象,函数最后就返回 handle索引处的handle_entry对象。

接下来就会走到 e != NULL的 if语句中:=================================================================> 相关类/** * Base class and low-level protocol for a remotable object. * You can derive from this class to create an object for which other * processes can hold references to it. Communication between processes * (method calls, property get and set) is down through a low-level * protocol implemented on top of the transact() API. */ class IBinder : public virtual RefBase { public: enum { FIRST_CALL_TRANSACTION = 0x00000001, LAST_CALL_TRANSACTION = 0x00ffffff,

PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'), DUMP_TRANSACTION = B_PACK_CHARS('_','D','M','P'), INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),

Page 8: Android 进程间通信机制(Binder)介绍

// Corresponds to TF_ONE_WAY -- an asynchronous call. FLAG_ONEWAY = 0x00000001 };

IBinder();

/** * Check if this IBinder implements the interface named by * @a descriptor. If it does, the base pointer to it is returned, * which you can safely static_cast<> to the concrete C++ interface. */ virtual sp<IInterface> queryLocalInterface(const String16& descriptor);

/** * Return the canonical name of the interface provided by this IBinder * object. */ 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;

/** * This method allows you to add data that is transported through * IPC along with your IBinder pointer. When implementing a Binder * object, override it to write your desired data in to @a outData. * You can then call getConstantData() on your IBinder to retrieve * that data, from any process. You MUST return the number of bytes * written in to the parcel (including padding). */ class DeathRecipient : public virtual RefBase { public: virtual void binderDied(const wp<IBinder>& who) = 0; };

/** * Register the @a recipient for a notification if this binder * goes away. If this binder object unexpectedly goes away * (typically because its hosting process has been killed), * then DeathRecipient::binderDied() will be called with a referene * to this. * * The @a cookie is optional -- if non-NULL, it should be a * memory address that you own (that is, you know it is unique). * * @note You will only receive death notifications for remote binders, * as local binders by definition can't die without you dying as well. * Trying to use this function on a local binder will result in an * INVALID_OPERATION code being returned and nothing happening. * * @note This link always holds a weak reference to its recipient. * * @note You will only receive a weak reference to the dead * binder. You should not try to promote this to a strong reference. * (Nor should you need to, as there is nothing useful you can * directly do with it now that it has passed on.) */ virtual status_t linkToDeath(const sp<DeathRecipient>& recipient, void* cookie = NULL, uint32_t flags = 0) = 0;

/** * Remove a previously registered death notification. * The @a recipient will no longer be called if this object * dies. The @a cookie is optional. If non-NULL, you can * supply a NULL @a recipient, and the recipient previously * added with that cookie will be unlinked. */ virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient, void* cookie = NULL, uint32_t flags = 0, wp<DeathRecipient>* outRecipient = NULL) = 0;

virtual bool checkSubclass(const void* subclassID) const;

typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);

Page 9: Android 进程间通信机制(Binder)介绍

virtual void attachObject( const void* objectID, void* object, void* cleanupCookie, object_cleanup_func func) = 0; virtual void* findObject(const void* objectID) const = 0; virtual void detachObject(const void* objectID) = 0;

virtual BBinder* localBinder(); virtual BpBinder* remoteBinder();

protected: virtual ~IBinder();

private: };

class BpBinder : public IBinder { public: BpBinder(int32_t handle);

inline int32_t handle() const { return mHandle; }

virtual const String16& getInterfaceDescriptor() const; virtual bool isBinderAlive() const; virtual status_t pingBinder(); virtual status_t dump(int fd, const Vector<String16>& args);

virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);

virtual status_t linkToDeath(const sp<DeathRecipient>& recipient, void* cookie = NULL, uint32_t flags = 0); virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient, void* cookie = NULL, uint32_t flags = 0, wp<DeathRecipient>* outRecipient = NULL);

virtual void attachObject( const void* objectID, void* object, void* cleanupCookie, object_cleanup_func func); virtual void* findObject(const void* objectID) const; virtual void detachObject(const void* objectID);

virtual BpBinder* remoteBinder();

status_t setConstantData(const void* data, size_t size); void sendObituary();

class ObjectManager { public: ObjectManager(); ~ObjectManager();

void attach( const void* objectID, void* object, void* cleanupCookie, IBinder::object_cleanup_func func); void* find(const void* objectID) const; void detach(const void* objectID);

void kill();

private: ObjectManager(const ObjectManager&); ObjectManager& operator=(const ObjectManager&);

struct entry_t { void* object; void* cleanupCookie; IBinder::object_cleanup_func func; };

KeyedVector<const void*, entry_t> mObjects; };

protected: virtual ~BpBinder(); virtual void onFirstRef();

Page 10: Android 进程间通信机制(Binder)介绍

virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id);

private: const int32_t mHandle;

struct Obituary { wp<DeathRecipient> recipient; void* cookie; uint32_t flags; };

void reportOneDeath(const Obituary& obit); bool isDescriptorCached() const;

mutable Mutex mLock; volatile int32_t mAlive; volatile int32_t mObitsSent; Vector<Obituary>* mObituaries; ObjectManager mObjects; Parcel* mConstantData; mutable String16 mDescriptorCache; };=============================================================== // 注意:这里传递进来的 handle的值为 0; // 当 e为新创建的或者是 e所对应的 IBinder(及其子类)对象还未有任何弱引用,表明 handle所对应 // 的 BpBinder还不存在,创建之,以供上层用户使用; b = new BpBinder(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; 看到在这里创建了一个 BpBinder*对象,赋值给 handle_entry类中的 IBinder*,所以我们可知 BpBinder类必定继承于 IBinder类,所以这里有必要先来看下 IBinder类的构造函数是什么(对于 IBinder的父类 RefBase类的构造函数这里就不看了,只是用 new weakref_impl(this)来初始化成员变量 mRefs):IBinder::IBinder() : RefBase(){}再看 BpBinder它的构造函数是什么: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); }初始化 BpBinder的成员变量,并且将对象的生命周期设置为受弱引用控制,然后又出现了一个新类 IPCThreadState,调用其的 incWeakHandle()函数。看下 IPCThreadState类的 self()成员函数是什么:=================================================================> 相关的全局变量:(在 frameworks/base/libs/binder/IPCThreadState.cpp中定义)static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER; static bool gHaveTLS = false; static pthread_key_t gTLS = 0;static bool gShutdown = false;

==> 相关类class IPCThreadState{public: static IPCThreadState* self(); sp<ProcessState> process(); status_t clearLastError();

int getCallingPid(); int getCallingUid();

void setStrictModePolicy(int32_t policy); int32_t getStrictModePolicy() const;

void setLastTransactionBinderFlags(int32_t flags); int32_t getLastTransactionBinderFlags() const;

int64_t clearCallingIdentity(); void restoreCallingIdentity(int64_t token); void flushCommands();

void joinThreadPool(bool isMain = true);

Page 11: Android 进程间通信机制(Binder)介绍

// Stop the local process. void stopProcess(bool immediate = true); status_t transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);

void incStrongHandle(int32_t handle); void decStrongHandle(int32_t handle); void incWeakHandle(int32_t handle); void decWeakHandle(int32_t handle); status_t attemptIncStrongHandle(int32_t handle); static void expungeHandle(int32_t handle, IBinder* binder); status_t requestDeathNotification( int32_t handle, BpBinder* proxy); status_t clearDeathNotification( int32_t handle, BpBinder* proxy);

static void shutdown(); // Call this to disable switching threads to background scheduling when // receiving incoming IPC calls. This is specifically here for the // Android system process, since it expects to have background apps calling // in to it but doesn't want to acquire locks in its services while in // the background. static void disableBackgroundScheduling(bool disable); private: IPCThreadState(); ~IPCThreadState();

status_t sendReply(const Parcel& reply, uint32_t flags); status_t waitForResponse(Parcel *reply, status_t *acquireResult=NULL); status_t talkWithDriver(bool doReceive=true); status_t writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer); status_t executeCommand(int32_t command); void clearCaller(); static void threadDestructor(void *st); static void freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize, const size_t* objects, size_t objectsSize, void* cookie); const sp<ProcessState> mProcess; const pid_t mMyThreadId; Vector<BBinder*> mPendingStrongDerefs; Vector<RefBase::weakref_type*> mPendingWeakDerefs; Parcel mIn; Parcel mOut; status_t mLastError; pid_t mCallingPid; uid_t mCallingUid; int32_t mStrictModePolicy; int32_t mLastTransactionBinderFlags;};===============================================================IPCThreadState* IPCThreadState::self() { if (gHaveTLS) { restart: const pthread_key_t k = gTLS; IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); if (st) return st; return new IPCThreadState; } if (gShutdown) return NULL; pthread_mutex_lock(&gTLSMutex); if (!gHaveTLS) { if (pthread_key_create(&gTLS, threadDestructor) != 0) { pthread_mutex_unlock(&gTLSMutex); return NULL; } gHaveTLS = true;

Page 12: Android 进程间通信机制(Binder)介绍

} pthread_mutex_unlock(&gTLSMutex); goto restart; }开始 gHaveTLS为 false就跳过第一个 if语句,gShutdown也为 false就跳过第 2个 if语句。下面进入第 3个 if语句来创建线程相关数据(这里为主线程的),具体语句为: if (pthread_key_create(&gTLS, threadDestructor) != 0) { pthread_mutex_unlock(&gTLSMutex); return NULL; } 其中第 2个参数是一个 void xxx(void *)类型的函数指针,具体作用在线程退出时进行相应的处理,下面再看。上面 IPCThreadState::self()函数的执行流程很有意思,需要注意一下。这里可能会有一个疑问,就是当再次跳转到restart标签时,我们试图获取以 gTLS为标识的线程的私有数据,然后判断是否成功,若成功好理解,但若不成功时,我们又怎么去处理呢,你只有 pthread_getspecific()函数但并没有 pthread_setspecific()函数啊?对于这个问题,答案在 IPCThreadState类的构造函数中,具体如下:IPCThreadState::IPCThreadState() : mProcess(ProcessState::self()), mMyThreadId(androidGetTid()), mStrictModePolicy(0), mLastTransactionBinderFlags(0) { // 看到了,在这里设置了线程私有数据 pthread_setspecific(gTLS, this); clearCaller(); mIn.setDataCapacity(256); mOut.setDataCapacity(256); }大致流程图为:

“ ”接下来是一些 莫名奇妙 的函数调用: clearCaller(); // 将 mCallingPid和 mCallingUid分别设置为 getpid()和 getuid mIn.setDataCapacity(256); mOut.setDataCapacity(256); mIn、mOut跟 binder中数据的传输过程有关,而且特别重要。鉴于 Parcel类的定义很长,这里就不贴了,我们先看其构造函数:Parcel::Parcel(){ initState();}其中的 initState()成员函数也就是用来初始化一些成员变量:void Parcel::initState() { mError = NO_ERROR; mData = 0; mDataSize = 0; mDataCapacity = 0; mDataPos = 0; LOGV("initState Setting data size of %p to %d\n", this, mDataSize); LOGV("initState Setting data pos of %p to %d\n", this, mDataPos); mObjects = NULL; mObjectsSize = 0; mObjectsCapacity = 0; mNextObjectHint = 0; mHasFds = false; mFdsKnown = true; mOwner = NULL; }继续看 Parcel类中的 setDataCapacity()函数:

Page 13: Android 进程间通信机制(Binder)介绍

status_t Parcel::setDataCapacity(size_t size) { if (size > mDataSize) return continueWrite(size); return NO_ERROR; }其中的 continueWrite()函数定义如下:status_t Parcel::continueWrite(size_t desired){ // If shrinking, first adjust for any objects that appear // after the new data size. size_t objectsSize = mObjectsSize; if (desired < mDataSize) {

…… } if (mOwner) {

…… } else if (mData) {

…… } else { // 一开始走这里 // This is the first data. Easy! uint8_t* data = (uint8_t*)malloc(desired); if (!data) { mError = NO_MEMORY; return NO_MEMORY; } if(!(mDataCapacity == 0 && mObjects == NULL && mObjectsCapacity == 0)) { LOGE("continueWrite: %d/%p/%d/%d",

mDataCapacity, mObjects, mObjectsCapacity, desired); } mData = data; // 有个疑问:mDataSize是什么? // 更新 1:mDataSize就是记录你已经往 Parcel缓冲区写入了多少内容

// mDataPos为记录 Parcel缓冲区中的读/写位置 mDataSize = mDataPos = 0; LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize); LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos); mDataCapacity = desired; }

return NO_ERROR;}

到这里线程相关的数据结构也已正确设置了,接下来就是调用 IPCThreadState类中的 incWeakHandle()函数了:void IPCThreadState::incWeakHandle(int32_t handle) { LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle); // BC “为 binder command”的缩写,注意:当前已经往 mOut对象的缓冲区写入了数据了! mOut.writeInt32(BC_INCREFS); mOut.writeInt32(handle); // 2*4 = 8}IPCThreadState类中的 mOut、mIn两个 Parcel对象作为和 binder驱动通信的第一级数据载体,里面定义了很多设置具体数据的函数,例如 writeInt()、writeDouble()、readInt()等等。下面来看看 writeInt32()这个函数是什么:status_t Parcel::writeInt32(int32_t val){ return writeAligned(val);}其中 writeAligned()函数为:=================================================================> 相关宏定义// 将 s整成 4的倍数#define PAD_SIZE(s) (((s)+3)&~3)===============================================================template<class T> status_t Parcel::writeAligned(T val) { // T类型大小必需是 4的倍数(也就是说必需要 4字节对齐) COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));

if ((mDataPos+sizeof(val)) <= mDataCapacity) { restart_write: // Parcel缓冲区够写的情况,设置 val的值到 mData缓冲区中 mDataPos位置处 *reinterpret_cast<T*>(mData+mDataPos) = val; return finishWrite(sizeof(val)); } // 不够写的情况,调用 growData()函数,是用来增长 Parcel缓冲区的大小的,具体见下 status_t err = growData(sizeof(val)); if (err == NO_ERROR) goto restart_write; return err; }

Page 14: Android 进程间通信机制(Binder)介绍

使用 growData()函数来扩充 Parcel对象的缓冲区:status_t Parcel::growData(size_t len) { size_t newSize = ((mDataSize+len)*3)/2; // 看到下面实际下做事的是 continueWrite()函数,此时的分析情况要和上面不同了,具体见下 return (newSize <= mDataSize) ? (status_t) NO_MEMORY : continueWrite(newSize); }Parcel对象原有缓冲区已不够用,需扩充情况:status_t Parcel::continueWrite(size_t desired) { // If shrinking, first adjust for any objects that appear // after the new data size. size_t objectsSize = mObjectsSize; if (desired < mDataSize) { …… } if (mOwner) { …… } else if (mData) { if (objectsSize < mObjectsSize) { …… }

// We own the data, so we can just do a realloc(). if (desired > mDataCapacity) { // 扩充缓冲区的话走这里(此时我们应该走这里) uint8_t* data = (uint8_t*)realloc(mData, desired); if (data) { mData = data; mDataCapacity = desired; } else if (desired > mDataCapacity) { mError = NO_MEMORY; return NO_MEMORY; } } else { // 压缩缓冲区的话走这里 mDataSize = desired; LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize); if (mDataPos > desired) { mDataPos = desired; LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos); } } } else {

…… }

return NO_ERROR; }最后的 finishWrite()函数用来更新 Parcel对象缓冲区的读写位置、以及当前缓冲区所存入数据大小等:status_t Parcel::finishWrite(size_t len) { //printf("Finish write of %d\n", len); mDataPos += len; LOGV("finishWrite Setting data pos of %p to %d\n", this, mDataPos); if (mDataPos > mDataSize) { mDataSize = mDataPos; LOGV("finishWrite Setting data size of %p to %d\n", this, mDataSize); } //printf("New pos=%d, size=%d\n", mDataPos, mDataSize); return NO_ERROR; }

对于 PAD_SIZE这个宏,可能它到底是做什么的疑问?看下面这个示例就清楚了:#include <iostream> using namespace std;

#define PAD_SIZE(s) (((s)+3)&~3)

int main(int argc, const char **argv) { cout << "PAD_SIZE(sizeof(char)) = " << PAD_SIZE(sizeof(char)) << endl; cout << "sizeof(char) = " << sizeof(char) << endl;

cout << "PAD_SIZE(sizeof(unsigned)) = " << PAD_SIZE(sizeof(unsigned)) << endl; cout << "sizeof (unsigned) = " << sizeof(unsigned) << endl;

cout << "PAD_SIZE(sizeof(int)) = " << PAD_SIZE(sizeof(int)) << endl; cout << "sizeof (int) = " << sizeof(int) << endl;

Page 15: Android 进程间通信机制(Binder)介绍

return(0); }输出结果:PAD_SIZE(sizeof(char)) = 4 sizeof(char) = 1 PAD_SIZE(sizeof(unsigned)) = 4 sizeof (unsigned) = 4 PAD_SIZE(sizeof(int)) = 4 sizeof (int) = 4上面也有叙述:也就是将 s整成 4的倍数。

到这里 BpBinder算是构造完了,继续回到上面的 main()函数,所以上面的一条语句可以初步简化为:gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));现在就需要看 interface_cast它究竟是什么,可以使 BpBinder类型转换为 sp<IServiceManager>类型,但是在看之前,还是得需要看 IServiceManager “ ”这个 接口 类是什么:class IInterface : public virtual RefBase { public: IInterface(); sp<IBinder> asBinder(); sp<const IBinder> asBinder() const; protected: virtual ~IInterface(); virtual IBinder* onAsBinder() = 0; };

class IServiceManager : public IInterface { public: // 下面这个是一个宏,它和 interface_case相关,具体下面再看 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, }; };注意到 IServiceManager这个接口支持 getService()、checkService()、addService()以及 listServices()等,先看下 DECLARE_META_INTERFACE这个宏的具体定义:#define DECLARE_META_INTERFACE(INTERFACE) \ static const android::String16 descriptor; \ static android::sp<I##INTERFACE> asInterface( \ const android::sp<android::IBinder>& obj); \ virtual const android::String16& getInterfaceDescriptor() const; \ I##INTERFACE(); \ virtual ~I##INTERFACE();定义了一个每字符 16比特的字符串成员、一个方法 getInterfaceDescriptor()函数用以获得该字符串、以及一个很重要的成员函数 asInterface(),返回一个 I##INTERFACE对象。另外还有就是定义了 I##INTERFACE类的构造和析构函数。所以上面的 DECLARE_META_INTERFACE(ServiceManager);可以等效为: static const android::String16 descriptor; static android::sp<IServiceManager> asInterface( const android::sp<android::IBinder>& obj); virtual const android::String16& getInterfaceDescriptor() const; IServiceManager(); virtual ~IServiceManager();具体的实现部分在 IServiceManager.cpp中,就只有一行,具体如下:IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");来看下 IMPLEMENT_META_INTERFACE这个宏,就是用它来实现上面定义的宏:#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ const android::String16 I##INTERFACE::descriptor(NAME); \ const android::String16& \ I##INTERFACE::getInterfaceDescriptor() const { \ return I##INTERFACE::descriptor; \ } \ android::sp<I##INTERFACE> I##INTERFACE::asInterface( \

Page 16: Android 进程间通信机制(Binder)介绍

const android::sp<android::IBinder>& obj) \ { \ android::sp<I##INTERFACE> intr; \ if (obj != NULL) { \ intr = static_cast<I##INTERFACE*>( \ obj->queryLocalInterface( \ I##INTERFACE::descriptor).get()); \ if (intr == NULL) { \ intr = new Bp##INTERFACE(obj); \ } \ } \ return intr; \ } \ I##INTERFACE::I##INTERFACE() { } \ I##INTERFACE::~I##INTERFACE() { }所以将所有的 INTERFACE全部替换为 ServiceManager、NAME替换为"android.os.IServiceManager"后如下所示: const android::String16 IServiceManager::descriptor("android.os.IServiceManager"); const android::String16& IServiceManager::getInterfaceDescriptor() const { return IServiceManager::descriptor; } IServiceManager::IServiceManager() { } IServiceManager::~IServiceManager() { }初始化 IServiceManager类的成员变量 descriptor很容易,查询该名称也很容易,关键是 asInterface()这个成员函数,实际作用是将 IBinder对象转换为 IServiceManager对象。 // 这是一个核心函数,将 IBinder对象转换为 IServiceManager对象 android::sp<IServiceManager> IServiceManager::asInterface( const android::sp<android::IBinder>& obj) { android::sp<IServiceManager> intr; // intr为 interface的缩写 if (obj != NULL) { // 传入的 obj肯定不为 NULL,下面这条语句中的 queryLocalInterface()函数应该是 IBinder类中的 // queryLocalInterface()函数,但是其默认是返回的 NULL,这又是什么原因呢? // 更新 1:是不是每次调用 interface_cast函数时,都会创建一个相应的 BpXXX对象? intr = static_cast<IServiceManager*> ( obj->queryLocalInterface( IServiceManager::descriptor ).get() ); if (intr == NULL) { // 创建 BpServiceManager对象,这条语句最终实际上就是将 obj赋值给 // BpRefBase类中的 IBinder *const mRemote成员

// BpServiceMananger类的定义见下 intr = new BpServiceManager(obj); } } return intr; }最后看下 interface_case()函数定义到底是什么:template<typename INTERFACE> inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj) { return INTERFACE::asInterface(obj); }看到 interface_cast<IServiceManager>(new BpBinder(0))实际上调用的是 IServiceManager类的asInterface()函数而已,这个函数最后可以简化为将 BpServiceManager对象转换为 IServiceManager对象。下面来看一下 BpServiceManager这个类的构造函数是什么。=================================================================> 相关的类class BpRefBase : public virtual RefBase{protected: BpRefBase(const sp<IBinder>& o); virtual ~BpRefBase(); virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id);

inline IBinder* remote() { return mRemote; } inline IBinder* remote() const { return mRemote; }

private: BpRefBase(const BpRefBase& o); BpRefBase& operator=(const BpRefBase& o);

IBinder* const mRemote; RefBase::weakref_type* mRefs; volatile int32_t mState;};

template<typename INTERFACE> class BpInterface : public INTERFACE, public BpRefBase { public: BpInterface(const sp<IBinder>& remote);

protected:

Page 17: Android 进程间通信机制(Binder)介绍

virtual IBinder* onAsBinder(); };

class BpServiceManager : public BpInterface<IServiceManager> { public: BpServiceManager(const sp<IBinder>& impl) : BpInterface<IServiceManager>(impl) { }

// 注意到,在 IServiceManager中定义的几个重要的成员函数都是在这个类中实现的 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; LOGI("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(); }

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; }

// 列出所有已注册的 services virtual Vector<String16> listServices() { Vector<String16> res; int n = 0;

for (;;) { Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeInt32(n++); status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply); if (err != NO_ERROR) break; res.add(reply.readString16()); } return res; } };===============================================================BpServiceManager类的构造函数: BpServiceManager(const sp<IBinder>& impl) : BpInterface<IServiceManager>(impl) { } 这里的 impl实际上就是 new BpBinder(0),所以现在这里会先调用 BpServiceManager的父类 BpInterface类的构造函数,具体如下:template<typename INTERFACE> inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote) : BpRefBase(remote) { }看到这里又调用父类 BpRefBase类的构造函数,其余什么都没做,所以需要看 BpRefBase类的构造函数是什么:BpRefBase::BpRefBase(const sp<IBinder>& o) : mRemote(o.get()), mRefs(NULL), mState(0) { extendObjectLifetime(OBJECT_LIFETIME_WEAK);

if (mRemote) { // 增加强引用计数 1 // 注意:若 BpBinder对象是第一次受强引用时,会调用 onFirstRef()这个成员函数,而在这个函数中 // 会调用 IPCThreadState对象中的 incStrongHandle()成员函数,具体就只是往 mOut中写入了 // BC_ACQUIRE和 handle(此处为 0)

Page 18: Android 进程间通信机制(Binder)介绍

mRemote->incStrong(this); // Removed on first IncStrong(). // 所以,此时 IPCThreadState中的成员变量 mOut的 dataSize()值为 8 + 4 + 4 = 16 mRefs = mRemote->createWeak(this); // Held for our entire lifetime. } }这里的 mRemote也是 new BpBinder(0),将它设置为受弱引用控制,并分别增加强弱引用计数 1。所以现在就可以明白为什么 BpBinder类型的对象可以转换为 IServiceManager对象了,因为 asInterface()函数会通过 BpBinder对象来创建 BpServiceManager对象,而这个 BpServiceManager对象又继承于 IServiceManager对象,所以这种转换就可以完成。

下面再次转入到 main_dxyhservice.cpp的 main()函数中,执行如下语句: sm->addService(String16("service.dxyh"), new DxyhService());其中 DxyhService()这个类就是我们的服务了,看下该类及其相关类的声明:class IDxyhService: public IInterface { public: DECLARE_META_INTERFACE(DxyhService);

// declare what this service can do virtual status_t setUserName(const String16& name) = 0; virtual status_t setUserAge(uint32_t age) = 0;

virtual String16 getUserName() const = 0; virtual uint32_t getUserAge() const = 0;

enum { GET_USERNAME_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, GET_USERAGE_TRANSACTION, SET_USERNAME_TRANSACTION, SET_USERAGE_TRANSACTION, }; };

// ----------------------------------------------------------------------------

class BnDxyhService: public BnInterface<IDxyhService> { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel *reply, uint32_t flags = 0); };

class DxyhService : public BnDxyhService { public: DxyhService(); virtual status_t setUserName(const String16& name); virtual status_t setUserAge(uint32_t age);

virtual String16 getUserName() const; virtual uint32_t getUserAge() const;

private: String16 mName; uint32_t mAge; };DxyhService类的构造函数为空,略。

目前我们主要是看 DxyhService这个服务 “ ” “ ”是 怎么注册的 ,而不是 是什么 。

接下来看上面的 addService()这个函数: virtual status_t addService(const String16& name, const sp<IBinder>& service) { Parcel data, reply; // 注意:此时 data、reply中的 mDataCapacity数据成员初始化为 0,故需要考虑调用 growData()扩充 // 缓冲区的情况,而上面没有及时考虑,是因为 mOut、mIn已经调用了 setDataCapacity(256),也就是 // “它们还可以撑一会,还够用”

// 对于 writeInterfaceToken()函数会先用 writeInt32写入 // IPCThreadState::self()->getStrictModePolicy()|STRICT_MODE_PENALTY_GATHER, // 然后再使用 writeString16写入该所传入的参数 data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); // 此时 data.ipcDataSize() = 96 ( 4+PAD_SIZE( 4+(27+1)*2 )+PAD_SIZE((12+1)*2+4)) ) // 其中 27 = strlen("android.os.IServiceManager"),12 = strlen("dxyh.service")

// 下面这个函数甚为重要,见下! data.writeStrongBinder(service); // 调用 BpBinder(0)中的 transact()函数将该数据包传递给底层 binder驱动 status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); return err == NO_ERROR ? reply.readExceptionCode() : err; }

上面 writeString16(const String16& str)函数又会在内部调用转换为调用

Page 19: Android 进程间通信机制(Binder)介绍

writeString16(const char16_t *str, size_t len)函数,具体如下:status_t Parcel::writeString16(const char16_t* str, size_t len) { if (str == NULL) return writeInt32(-1); status_t err = writeInt32(len); if (err == NO_ERROR) { len *= sizeof(char16_t); uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t)); if (data) { memcpy(data, str, len); *reinterpret_cast<char16_t*>(data+len) = 0; return NO_ERROR; } err = mError; } return err; }其中 writeInplace()函数的具体定义如下:void* Parcel::writeInplace(size_t len) { const size_t padded = PAD_SIZE(len);

// sanity check for integer overflow if (mDataPos+padded < mDataPos) { return NULL; }

if ((mDataPos+padded) <= mDataCapacity) { // 空间够写,不需扩充restart_write: //printf("Writing %ld bytes, padded to %ld\n", len, padded); // 找到缓冲区的写入起始地址 uint8_t* const data = mData+mDataPos;

// Need to pad at end? if (padded != len) { #if BYTE_ORDER == BIG_ENDIAN static const uint32_t mask[4] = { 0x00000000, 0xffffff00, 0xffff0000, 0xff000000 }; #endif #if BYTE_ORDER == LITTLE_ENDIAN // 小端机器走着里 static const uint32_t mask[4] = { 0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff }; #endif //printf("Applying pad mask: %p to %p\n", (void*)mask[padded-len], // *reinterpret_cast<void**>(data+padded-4)); // 这里有点意思:假设 len = 6,则 padded = PAD_SIZE(6) = 8,则等效于: // data起始的缓冲区,最后 4个字节(正好和 1个 uint32_t 类型大小相同) &= 0x0000ffff // 由于是小端机器,0x0000ffff “ ”在内存中的 布局 是 0xff 0xff 0x00 0x00,这样效果就是只保留 // 从 data+padded-4开始后的 2个字节(padded-4+2正好等于 len),后面的 2个字节就设置为 0 *reinterpret_cast<uint32_t*>(data+padded-4) &= mask[padded-len]; }

finishWrite(padded); return data; }

status_t err = growData(padded); if (err == NO_ERROR) goto restart_write; return NULL; }

Parcel类中的 writeStrongBinder()成员函数具体如下:status_t Parcel::writeStrongBinder(const sp<IBinder>& val) { return flatten_binder(ProcessState::self(), val, this); }其中 flatten_binder()函数如下:=================================================================> 相关结构体enum { FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff, FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100, };

struct flat_binder_object {

unsigned long type; // 初始设置为 BINDER_TYPE_BINDER unsigned long flags; // 在 flatten_binder 函数中刚创建就将其添加 FLAT_BINDER_FLAG_ACCEPTS_FDS旗标

union {

Page 20: Android 进程间通信机制(Binder)介绍

void *binder; signed long handle; };

void *cookie; };===============================================================status_t flatten_binder(const sp<ProcessState>& proc, const sp<IBinder>& binder, Parcel* out) { // 所有的对象均以 flat_binder_object类型与驱动进行交互 flat_binder_object obj; obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; if (binder != NULL) { // 调用 BBinder类中的 localBinder(),在内部仅仅是返回 this IBinder *local = binder->localBinder(); if (!local) {

…… } else { obj.type = BINDER_TYPE_BINDER; obj.binder = local->getWeakRefs(); // cookie字段就装着我们的 service obj.cookie = local; } } else {

…… } return finish_flatten_binder(binder, obj, out); }接下来的 finish_flatten_binder()函数在里面仅仅是调用了 out->writeObject(obj, flase),直接去看writeObject()这个函数:status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData) { const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity; // false const bool enoughObjects = mObjectsSize < mObjectsCapacity; // false // 此时 mDataPos = mDataCapacity = 96, sizeof(val) = 16 // mObjectsSize = mObjectsCapacity = 0 if (enoughData && enoughObjects) { restart_write: // 写入这个 flat_binder_object对象 *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val; // Need to write meta-data? if (nullMetaData || val.binder != NULL) { // 记录刚刚添加的 flat_binder_object对象的偏移 mObjects[mObjectsSize] = mDataPos; acquire_object(ProcessState::self(), val, this); mObjectsSize++; } // remember if it's a file descriptor if (val.type == BINDER_TYPE_FD) { …… }

// 使用 finishWrite()函数来更新 mDataLen和 mDataPos的值 return finishWrite(sizeof(flat_binder_object)); }

if (!enoughData) { // 增涨数据区域,分析见上 const status_t err = growData(sizeof(val)); if (err != NO_ERROR) return err; } if (!enoughObjects) { // 下面这个 newSize的值的确定估计是根据实际效率调整后的结果 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数组用于存储在 Parcel数据缓冲区中各个 flat_binder_object对象的偏移量 mObjects = objects; mObjectsCapacity = newSize; } goto restart_write; }其中 acquire_object()函数具体如下:void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj, const void* who) { switch (obj.type) { case BINDER_TYPE_BINDER: if (obj.binder) {

Page 21: Android 进程间通信机制(Binder)介绍

LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie); // 上面 new DxyhService()对象的强引用数加 1 static_cast<IBinder*>(obj.cookie)->incStrong(who); } return;

…… }

……}

继续回到 addService() 函数中,执行如下 语句: // 调用 BpBinder(0)中的 transact()函数将该数据包传递给底层 binder驱动 remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);这里的 remote()函数就是返回在 BpServiceManager()在构造时,传入的参数 new BpBinder(0),下面就看看该类中的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) { // IPCThreadState对象是和 gTLS对应的,更改 gTLS就可以获得不同线程的 IPCThreadState对象; // 注意:此时 mHandle为 0; status_t status = IPCThreadState::self()->transact( mHandle, code, data, reply, flags); if (status == DEAD_OBJECT) mAlive = 0; return status; }

return DEAD_OBJECT; }看到刚进来,就转向调用 IPCThreadState类对象的 transact()函数,具体如下:status_t IPCThreadState::transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ status_t err = data.errorCheck();

// 看到这里有设置 TF_ACCEPT_FDS旗标(“allow replies with file descriptors”) 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"); // 将数据 data传递给 binder驱动,具体见下 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); } 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;}

IF_LOG_TRANSACTIONS()是一个宏,具体定义如下:#define IF_LOG_TRANSACTIONS() if (false)可知默认是不走这一段的,这其实也给了我们一种调试程序的手段,省得老是#if 0或者#define DEBUG等等,而且对于“ ”现在调试的是什么 这个问题可以有更清晰的描述。

Page 22: Android 进程间通信机制(Binder)介绍

LOG_ONEWAY “ ”正如其字面意思一样, 一种调试方式 ,具体被宏定义为:#define LOG_ONEWAY(...) LOG(LOG_DEBUG, "ipc", __VA_ARGS__)

“ ”所以这仅仅是一种 一次性的 调试方式,没有通用性,因为它里面将 log的 TAG定死了,为"ipc"。

使用 writeTransactionData()函数来将数据(Parcel对象)传递给 binder驱动:=================================================================> 相关结构体struct binder_transaction_data {

/* The first two are only used for bcTRANSACTION and brTRANSACTION, * identifying the target and contents of the transaction. */union {size_t handle; /* target descriptor of command transaction */void *ptr; /* target descriptor of return transaction */

} target;void *cookie; /* target object cookie */unsigned int code; /* transaction command */

/* General information about the transaction. */unsigned int flags;pid_t sender_pid;uid_t sender_euid;size_t data_size; /* number of bytes of data */size_t offsets_size;/* number of bytes of offsets */

/* If this transaction is inline, the data immediately * follows here; otherwise, it ends with a pointer to * the data buffer. */union {struct {

/* transaction data */const void *buffer;/* offsets from buffer to flat_binder_object structs */const void *offsets;

} ptr;uint8_t buf[8];

} data;};===============================================================status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer){ binder_transaction_data tr;

tr.target.handle = handle; // tr.code 字段填充的内容类似于: // ADD_SERVICE_TRANSACTION,增加这个服务的意思; // CHECK_SERVICE_TRANSACTION,查询某个 service是否存在等。 tr.code = code; tr.flags = binderFlags; // 已有设置了 TF_ACCEPT_FDS旗标 const status_t err = data.errorCheck(); if (err == NO_ERROR) { tr.data_size = data.ipcDataSize(); // mDataSize > mDataPos ? mDataSize : mDataPos; tr.data.ptr.buffer = data.ipcData(); // mData // mObjectsSize为 mObjects数组的大小,元素为记录传输给 binder驱动的对象在缓冲区 mData中的偏移 // 由于只写入了一个对象,故此时 data.ipcObjectsCount()值为 1 tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t); // mObjectsSize*sizeof(size_t) tr.data.ptr.offsets = data.ipcObjects(); // mObjects } else if (statusBuffer) {

…… } else {

…… } // 写入数据到 mOut对象的缓冲区中 mOut.writeInt32(cmd); mOut.write(&tr, sizeof(tr)); // 此时 mOut.ipcDataSize()的值应该为 16 + 4 + sizeof(tr) = 60 return NO_ERROR;}其中 mOut对象中的 write()函数具体如下:status_t Parcel::write(const void* data, size_t len) { void* const d = writeInplace(len); if (d) { memcpy(d, data, len); return NO_ERROR; } return mError; }

Page 23: Android 进程间通信机制(Binder)介绍

继续回到 IPCThreadState::transact()函数中,下面会进入到如下条件判断: if ((flags & TF_ONE_WAY) == 0) { if (reply) { // 走这里 err = waitForResponse(reply); } else { …… } …… } else { …… }貌似一路下来,没有设置什么 TF_ONE_WAY这个旗标(表示异步的传递此次信息,async),所以会进入第 1个 if,我们传递进来的 relay也因该是非空的,所以紧接着就是调用 err = waitForResponse(reply);语句,所以需要看下waitForResponse()函数的具体定义是什么:status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) { int32_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 = 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: { LOG_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)); LOG_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 size_t*>(tr.data.ptr.offsets), tr.offsets_size/sizeof(size_t), freeBuffer, this); } else { err = *static_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 size_t*>(tr.data.ptr.offsets), tr.offsets_size/sizeof(size_t), this); } } else { freeBuffer(NULL, 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), this); continue;

Page 24: Android 进程间通信机制(Binder)介绍

} } 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; }咦,终于看到了一个循环代码体,它先调用了 talkWithDriver()函数,然后仅仅是判断一下返回值其他什么都没做,估计

“是一个作用类似于 喂,binder ”驱动在吗? 之类的(后面证明这种想法是错误的),具体定义如下(调试信息已删除):status_t IPCThreadState::talkWithDriver(bool doReceive){ LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened"); binder_write_read bwr; // 这里的 needRead布尔量的究竟是怎么个条件,下面再看。 // 先猜测下,估计应该是 true,因为在下面有一个 outAvail应该不为 0,因为需要写入数据给 binder驱动 // Is the read buffer empty? const bool needRead = mIn.dataPosition() >= mIn.dataSize(); // 事实上目前是两者相等为 0 // We don't want to write anything if we are still reading // from data left in the input buffer and the caller // has requested to read the next data. const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0; // 设置要写入的缓冲区大小,也就是将前面的 mOut中的数据都写入到 binder驱动中 bwr.write_size = outAvail; bwr.write_buffer = (long unsigned int)mOut.data();

// This is what we'll read. if (doReceive && needRead) { // 这里也需要读取从 binder返回的信息的,具体读取到的是什么下面再看 bwr.read_size = mIn.dataCapacity(); // mIn.dataCapacity()初始被设置为 256 // 注意下面这条语句,将从 binder驱动返回的消息直接存储到 mIn对象的 mData所指向的空间中 // 所以也就可以解释了 mIn是怎么和 binder驱动联系起来的! bwr.read_buffer = (long unsigned int)mIn.data(); } else { bwr.read_size = 0; } // Return immediately if there is nothing to do. if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR; bwr.write_consumed = 0; bwr.read_consumed = 0; status_t err; do {#if defined(HAVE_ANDROID_OS) // 绕来绕去,终于要调用 ioctl()函数来进行写入动作了 // 从这里可以看出,写入和读取是放在一起做的,这样就省了一次系统调用开销

// 看到上面的 Parcel对象 mOut、mIn都是最初一级的对要和 binder驱动进行通信的数据封装, // 实际做数据传输的是 binder_write_read结构体对象 if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) err = NO_ERROR; else err = -errno;#else err = INVALID_OPERATION;#endif // 之所以需要用 while循环是放置 ioctl()写入信息到 binder驱动时被中断,而这种中断本身并不是错误, // 所以遇到这种情况的话,需要再写一次 } while (err == -EINTR);

if (err >= NO_ERROR) { // 写入成功 if (bwr.write_consumed > 0) { // 若判断到有数据写入到 binder驱动,则需判断是否写入完全 if (bwr.write_consumed < (ssize_t)mOut.dataSize()) mOut.remove(0, bwr.write_consumed); else mOut.setDataSize(0);

Page 25: Android 进程间通信机制(Binder)介绍

} // 有读取到数据,设置对应数据长度,初始化读取指针(索引)为读 buffer开头 if (bwr.read_consumed > 0) { mIn.setDataSize(bwr.read_consumed); mIn.setDataPosition(0); } return NO_ERROR; } return err;}注意:看到 talkWithDriver()函数有 1 个参数,而在上面的 waitForResponse()函数中又是以无参方式调用了该函数,为什么可以这样呢?原来这是 C++中的默认参数的效果,看下 talkWithDriver()函数在 IPCThreadState中的声明: status_t talkWithDriver(bool doReceive=true);所以无参形式调用的话,默认下面的 doReceive是为 true的。

下面转入到驱动部分,看下在 binder_ioctl()函数中 BINDER_WRITE_READ分支是怎么做的:static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {

int ret; struct binder_proc *proc = filp->private_data; // 取出私有数据struct binder_thread *thread; unsigned int size = _IOC_SIZE(cmd); void __user *ubuf = (void __user *)arg;

……

switch (cmd) { // 这个分支是最常执行的一个,用来从 binder读取信息或是写入内容case BINDER_WRITE_READ: { struct binder_write_read bwr; // 从用户空间传来的正是 struct binder_write_read结构体// 这里之所以将 binder_write_read组成在一个结构体中,就是为了在进行一种操作的同时(写/读),就可以// 通过该结构体变量附带另一种操作(读/写)。所以 binder驱动就省去了传统的 write和 read方法if (size != sizeof(struct binder_write_read)) {

ret = -EINVAL; goto err;

} // 传入的参数处于用户空间,将之拷贝到内核空间if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {

ret = -EFAULT; goto err;

} // 需要写入内容,具体会调用 binder_thread_write()函数,下面会有详细说明if (bwr.write_size > 0) {

ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer,bwr.write_size, &bwr.write_consumed);

if (ret < 0) { bwr.read_consumed = 0; if (copy_to_user(ubuf, &bwr, sizeof(bwr)))

ret = -EFAULT; goto err;

} } // 需要读取内容,具体会调用 binder_thread_read()函数,下面会有详细说明if (bwr.read_size > 0) {

ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer,bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);

if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait);

if (ret < 0) { if (copy_to_user(ubuf, &bwr, sizeof(bwr)))

ret = -EFAULT; goto err;

} } if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {

ret = -EFAULT; goto err;

} break;

} ……

err: ……return ret;

}

1、把 switch..case语句中最常分支放在最前面可以提高效率,例如这里的 BINDER_WRITE_READ分支;2、此时 bwr.write_size的值因该为 60,因为:一路下来,往 mOut中写入的东西为:BC_INCREFS、handle、BC_ACUQIRE、handle、BC_TRANSACTION、tr 4 4 4 4 4 40 = 60

在写入时,调用的函数是 binder_thread_write()。函数比较大,我们只分析现在关联的部分(调试信息已删除):int

Page 26: Android 进程间通信机制(Binder)介绍

binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, void __user *buffer, int size, signed long *consumed)

{uint32_t cmd;// 要写入的数据此时还处于用户空间void __user *ptr = buffer + *consumed;void __user *end = buffer + size;

while (ptr < end && thread->return_error == BR_OK) {// 下面的这个 get_user实际上是一个宏,从用户空间获得一个 uint32_t类型的整型量if (get_user(cmd, (uint32_t __user *)ptr))

return -EFAULT;// 跳过命令字节长度ptr += sizeof(uint32_t);// _IOC_NR这个宏我们前面已说明过,作用是取得 bit0~bit7的值;// ARRAY_SIZE的作用是取得 binder_stats.bc这个数组的大小// 总之,作用就是:判断当前的这个 cmd是否是一个合法的 cmd(数值不能超过 BC_DEAD_BINDER_DONE// 的值,因为它是在 BinderDriverCommandProtocol中定义的最后的一个枚举成员)if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {

binder_stats.bc[_IOC_NR(cmd)]++;proc->stats.bc[_IOC_NR(cmd)]++;thread->stats.bc[_IOC_NR(cmd)]++;

}// 目前我们需要分析的命令有:BC_INCREFS、BC_ACQUIRE、BC_TRANSACTIONswitch (cmd) {case BC_INCREFS: case BC_ACQUIRE: case BC_RELEASE: case BC_DECREFS: {

uint32_t target;struct binder_ref *ref; const char *debug_string;

// 这里 target就等效于上层中的 handleif (get_user(target, (uint32_t __user *)ptr))

return -EFAULT; ptr += sizeof(uint32_t); if (target == 0 && binder_context_mgr_node && (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {

ref = binder_get_ref_for_node(proc, binder_context_mgr_node);

// 可以看到 binder_ref结构体中的 desc字段就是上层中的 handleif (ref->desc != target) {

binder_user_error("binder: %d:" "%d tried to acquire " "reference to desc 0, " "got %d instead\n", proc->pid, thread->pid, ref->desc);

} } else

ref = binder_get_ref(proc, target); if (ref == NULL) {

binder_user_error("binder: %d:%d refcou" "nt change on invalid ref %d\n", proc->pid, thread->pid, target);

break; } switch (cmd) { case BC_INCREFS:

debug_string = "IncRefs"; binder_inc_ref(ref, 0, NULL); break;

case BC_ACQUIRE: debug_string = "Acquire"; binder_inc_ref(ref, 1, NULL); break;

case BC_RELEASE: debug_string = "Release"; binder_dec_ref(ref, 1); break;

case BC_DECREFS: default:

debug_string = "DecRefs"; binder_dec_ref(ref, 0); break;

} if (binder_debug_mask & BINDER_DEBUG_USER_REFS)

printk(KERN_INFO"binder: %d:%d %s ref %d desc %d s %d w %d for node %d\n",

proc->pid, thread->pid, debug_string, ref->debug_id, ref->desc,ref->strong, ref->weak, ref->node->debug_id);

break; }

……

Page 27: Android 进程间通信机制(Binder)介绍

// 上层使用 binder_transaction_data结构体变量作为载体往驱动传递数据,最初的源头实在上层// IPCThreadState::transact()函数中设置,这里为:BC_TRANSACTIONcase BC_TRANSACTION:case BC_REPLY: {

struct binder_transaction_data tr;// 注意:上层会先创建 binder_transaction_data对象,然后将之关联到 mOut的数据域,然后再// 创建 binder_write_read对象,再将 mOut 的数据域关联到该对象的 write_buffer字段,所以// 下层只要对 bwr.write_buffer字段强制转换为 binder_transaction_data后就可直接使用了if (copy_from_user(&tr, ptr, sizeof(tr)))

return -EFAULT;ptr += sizeof(tr);// 做进一步处理,具体定义见下,注意,最后一个参数为 0binder_transaction(proc, thread, &tr, cmd == BC_REPLY);break;

}……}// 计算已经写入的字节数*consumed = ptr - buffer;

}return 0;

}上面 binder_get_ref_for_node()函数用于在 proc中的 refs_by_node树中查找 node,若没找到则创建之,具体如下:=================================================================> 相关结构体struct binder_node {

int debug_id; struct binder_work work; union { struct rb_node rb_node; struct hlist_node dead_node;

}; struct binder_proc *proc; struct hlist_head refs; // 挂载与之相关的 binder_ref对象(可能成存在其他的进程中)int internal_strong_refs; // 此 node被系统中的其他进程所引用int local_weak_refs; // 此 node被当前进程所弱引用int local_strong_refs; // 此 node被当前进程所强引用void __user *ptr; void __user *cookie; unsigned has_strong_ref : 1; unsigned has_weak_ref : 1; unsigned has_async_transaction : 1; unsigned accept_fds : 1; int min_priority : 8; struct list_head async_todo;

};

struct binder_ref_death { struct binder_work work; void __user *cookie;

};

struct binder_ref { /* Lookups needed: */ /* node + proc => ref (transaction) */ /* desc + proc => ref (transaction, inc/dec ref) */ /* node => refs + procs (proc exit) */ int debug_id; struct rb_node rb_node_desc; struct rb_node rb_node_node; struct hlist_node node_entry; struct binder_proc *proc; // 所属 binder_procstruct binder_node *node; // 所关联的 binder_nodeuint32_t desc; // 就是上层中的 handleint strong; // 强引用数int weak; // 弱引用数(注:这两者都是针对和该 binder_ref相关的 binder_node的引用计数)struct binder_ref_death *death;

};===============================================================static struct binder_ref * binder_get_ref_for_node(struct binder_proc *proc, struct binder_node *node) {

struct rb_node *n; struct rb_node **p = &proc->refs_by_node.rb_node; struct rb_node *parent = NULL; struct binder_ref *ref, *new_ref;

// 在 proc->refs_by_node树中查找和参数 node相对应的 binder_ref对象while (*p) { parent = *p; ref = rb_entry(parent, struct binder_ref, rb_node_node);

if (node < ref->node) p = &(*p)->rb_left;

else if (node > ref->node)

Page 28: Android 进程间通信机制(Binder)介绍

p = &(*p)->rb_right; else

// 找到就直接返回return ref;

} new_ref = kzalloc(sizeof(*ref), GFP_KERNEL); if (new_ref == NULL) return NULL;

binder_stats.obj_created[BINDER_STAT_REF]++; new_ref->debug_id = ++binder_last_id; new_ref->proc = proc; new_ref->node = node; rb_link_node(&new_ref->rb_node_node, parent, p); rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node);

// 此时 new_ref->desc值应该为 0new_ref->desc = (node == binder_context_mgr_node) ? 0 : 1; // 开始 proc->refs_by_desc树为空,略过下面的 for循环for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { ref = rb_entry(n, struct binder_ref, rb_node_desc); if (ref->desc > new_ref->desc) {

// 往左边挂在 proc->refs_by_desc树中break;

}// 最小程度地增加 new_ref中的 desc的值,往右边挂在 proc->refs_by_desc树中new_ref->desc = ref->desc + 1;

}

p = &proc->refs_by_desc.rb_node; while (*p) { parent = *p; ref = rb_entry(parent, struct binder_ref, rb_node_desc);

if (new_ref->desc < ref->desc) p = &(*p)->rb_left;

else if (new_ref->desc > ref->desc) p = &(*p)->rb_right;

elseBUG(); // new_ref中的 desc不可能与原树中的所有节点的 desc重复!

} rb_link_node(&new_ref->rb_node_desc, parent, p); rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc); if (node) { // 将创建的 new_ref挂载到 node中的 refs链表中hlist_add_head(&new_ref->node_entry, &node->refs); if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS)

printk(KERN_INFO "binder: %d new ref %d desc %d for " "node %d\n", proc->pid, new_ref->debug_id, new_ref->desc, node->debug_id);

} else { ……

} return new_ref;

}

接下来对于 BC_INCREFS、BC_ACQUIRE命令,都会调用 binder_inc_ref()函数来管理引用计数:static int binder_inc_ref(

struct binder_ref *ref, int strong, struct list_head *target_list) {

int ret; if (strong) { // BC_ACQUIRE走这里if (ref->strong == 0) {

ret = binder_inc_node(ref->node, 1, 1, target_list); if (ret)

return ret; } ref->strong++;

} else { // BC_INCREFS走这里if (ref->weak == 0) {

ret = binder_inc_node(ref->node, 0, 1, target_list); if (ret)

return ret; } ref->weak++;

} return 0;

}看到上面实际做事的是 binder_inc_node()函数,用来增加此 node的引用计数(暂时逻辑有些混乱,后面再看):static int binder_inc_node(struct binder_node *node, int strong, int internal,

struct list_head *target_list) {

Page 29: Android 进程间通信机制(Binder)介绍

// 注意:对于 binder_context_mgr_node,其 has_strong_ref和 node->has_weak_ref字段应该都为 1if (strong) { if (internal) {

if (target_list == NULL && node->internal_strong_refs == 0 && !(node == binder_context_mgr_node && node->has_strong_ref)) {

printk(KERN_ERR "binder: invalid inc strong " "node for %d\n", node->debug_id);

return -EINVAL; } node->internal_strong_refs++;

} else node->local_strong_refs++;

if (!node->has_strong_ref && list_empty(&node->work.entry)) list_add_tail(&node->work.entry, target_list);

} else { if (!internal)

node->local_weak_refs++; if (!node->has_weak_ref && list_empty(&node->work.entry)) {

if (target_list == NULL) { printk(KERN_ERR "binder: invalid inc weak node "

"for %d\n", node->debug_id); return -EINVAL;

} list_add_tail(&node->work.entry, target_list);

} } return 0;

}

接下来继续回到上面 binder_thread_write()函数中,现在来看 BC_TRANSACTION分支后的处理部分。其中会调用到 binder_transaction()这个函数,作用是对上层传递来的 binder_transaction_data结构体做进一步处理:=================================================================> 相关结构体struct binder_work {

struct list_head entry; enum { BINDER_WORK_TRANSACTION = 1, BINDER_WORK_TRANSACTION_COMPLETE, BINDER_WORK_NODE, BINDER_WORK_DEAD_BINDER, BINDER_WORK_DEAD_BINDER_AND_CLEAR, BINDER_WORK_CLEAR_DEATH_NOTIFICATION,

} type; };

struct binder_buffer { struct list_head entry; /* free and allocated entries by addesss */ struct rb_node rb_node; /* free entry by size or allocated entry */

/* by address */ unsigned free : 1; unsigned allow_user_free : 1; unsigned async_transaction : 1; unsigned debug_id : 29;

struct binder_transaction *transaction;

struct binder_node *target_node; size_t data_size; size_t offsets_size; uint8_t data[0];

};

// 用于内核中不同进程之间用 binder进行通信的数据载体struct binder_transaction {

int debug_id; struct binder_work work; struct binder_thread *from; struct binder_transaction *from_parent; struct binder_proc *to_proc; struct binder_thread *to_thread; struct binder_transaction *to_parent; unsigned need_reply : 1; /*unsigned is_dead : 1;*/ /* not used at the moment */

struct binder_buffer *buffer; unsigned int code; unsigned int flags; long priority; long saved_priority; uid_t sender_euid;

};===============================================================

Page 30: Android 进程间通信机制(Binder)介绍

static voidbinder_transaction(struct binder_proc *proc, struct binder_thread *thread,

struct binder_transaction_data *tr, int reply){

struct binder_transaction *t;struct binder_work *tcomplete;size_t *offp, *off_end;struct binder_proc *target_proc;struct binder_thread *target_thread = NULL;struct binder_node *target_node = NULL;struct list_head *target_list;wait_queue_head_t *target_wait;struct binder_transaction *in_reply_to = NULL;struct binder_transaction_log_entry *e;uint32_t return_error;

……

// 对于是 BC_TRANSACTION动作,reply为 0if (reply) {……

} else {if (tr->target.handle) {

// 获得其他服务……

} else {// 获得 ServiceManager服务target_node = binder_context_mgr_node;if (target_node == NULL) {

return_error = BR_DEAD_REPLY;goto err_no_context_mgr_node;

}}……target_proc = target_node->proc;if (target_proc == NULL) {

return_error = BR_DEAD_REPLY;goto err_dead_binder;

}if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {

struct binder_transaction *tmp; tmp = thread->transaction_stack; // 下面这段作用就是在目标进程中,若含有工作线程的话,就将其赋值给 target_threadwhile (tmp) {

if (tmp->from && tmp->from->proc == target_proc) target_thread = tmp->from;

tmp = tmp->from_parent; }

}}if (target_thread) {// 若有工作线程的话,target_list及 target_wait均设置为工作线程的……target_list = &target_thread->todo;target_wait = &target_thread->wait;

} else {// 若没有工作线程,只有主线程,则所有工作都挂到主线程头上target_list = &target_proc->todo;target_wait = &target_proc->wait;

}……

/* TODO: reuse incoming transaction for reply */t = kzalloc(sizeof(*t), GFP_KERNEL);if (t == NULL) {return_error = BR_FAILED_REPLY;goto err_alloc_t_failed;

}binder_stats.obj_created[BINDER_STAT_TRANSACTION]++;

tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);if (tcomplete == NULL) {return_error = BR_FAILED_REPLY;goto err_alloc_tcomplete_failed;

}binder_stats.obj_created[BINDER_STAT_TRANSACTION_COMPLETE]++;

……

if (!reply && !(tr->flags & TF_ONE_WAY))// 走这里t->from = thread;

elset->from = NULL;

t->sender_euid = proc->tsk->euid;

Page 31: Android 进程间通信机制(Binder)介绍

t->to_proc = target_proc;t->to_thread = target_thread;t->code = tr->code; // tr->code就是诸如 ADD_SERVICE_TRANSACTION等类似的东西t->flags = tr->flags;t->priority = task_nice(current);// 下面这条语句很重要,具体见下t->buffer = binder_alloc_buf(target_proc, tr->data_size,tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));

if (t->buffer == NULL) {return_error = BR_FAILED_REPLY;goto err_binder_alloc_buf_failed;

}t->buffer->allow_user_free = 0;t->buffer->debug_id = t->debug_id;t->buffer->transaction = t;t->buffer->target_node = target_node;if (target_node) {// 增加 target_node的引用计数binder_inc_node(target_node, 1, 0, NULL);

}

offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));

// 将用户空间中传递过来的 buffer(Parcel类 mData数据成员)拷贝至 t->buffer->data处if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {binder_user_error("binder: %d:%d got transaction with invalid "

"data ptr\n", proc->pid, thread->pid);return_error = BR_FAILED_REPLY;goto err_copy_data_failed;

}// 紧接着再次拷贝 Parcel类中 mObjects对应的数据if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {binder_user_error("binder: %d:%d got transaction with invalid "

"offsets ptr\n", proc->pid, thread->pid);return_error = BR_FAILED_REPLY;goto err_copy_data_failed;

}// 定位到传递对象的末地址// 注意:在 binder系统中,对象是以 struct flat_binder_object类型传递的off_end = (void *)offp + tr->offsets_size;for (; offp < off_end; offp++) {// 由于在上层有传输过一个 flat_binder_object对象,在这里便会取出之struct flat_binder_object *fp;// 检查偏移地址的合法性,似乎用*offp+sizeof(*fp) > t->buffer->data_size等效一下会更好理解一些if (*offp > t->buffer->data_size - sizeof(*fp)) {

binder_user_error("binder: %d:%d got transaction with ""invalid offset, %d\n",proc->pid, thread->pid, *offp);

return_error = BR_FAILED_REPLY;goto err_bad_offset;

}// 找到这个等效传递对象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;struct binder_node *node = binder_get_node(proc, fp->binder);if (node == NULL) {

// 刚开肯定找不到,走这里,binder_new_node()函数具体见下node = binder_new_node(proc, fp->binder);if (node == NULL) {

return_error = BR_FAILED_REPLY;goto err_binder_new_node_failed;

}node->cookie = fp->cookie;node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);

}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;

}if (fp->type == BINDER_TYPE_BINDER)

fp->type = BINDER_TYPE_HANDLE;else

fp->type = BINDER_TYPE_WEAK_HANDLE;fp->handle = ref->desc;// 增加 ref对应的这个新创建的 node的引用计数,注意:此时 node->has_strong_ref为 0// 故要在 binder_inc_ref中会执行 list_add_tail(&node->work.entry, &thread->todo);// 也就是会往 thread->todo链表中加入工作binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo);if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)

printk(KERN_INFO " node %d u%p -> ref %d desc %d\n",

Page 32: Android 进程间通信机制(Binder)介绍

node->debug_id, node->ptr, ref->debug_id, ref->desc);} break;……

}if (reply) {BUG_ON(t->buffer->async_transaction != 0);binder_pop_transaction(target_thread, in_reply_to);

} else if (!(t->flags & TF_ONE_WAY)) {BUG_ON(t->buffer->async_transaction != 0);t->need_reply = 1;t->from_parent = thread->transaction_stack;thread->transaction_stack = t;

} else {BUG_ON(target_node == NULL);BUG_ON(t->buffer->async_transaction != 1);if (target_node->has_async_transaction) {

target_list = &target_node->async_todo;target_wait = NULL;

} elsetarget_node->has_async_transaction = 1;

}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;……

}用 binder_alloc_buf()函数来为 binder_buffer结构体变量申请空间,当然,这个空间应该申请在参数 proc所属的共享内存中,具体如下:=================================================================> 相关宏定义// 将 x整成 4的倍数#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1))

1、ALIGN宏使用示例:ALIGN(5, 8) = 8ALIGN(9, 8) = 162、BUG_ON宏的作用:BUG_ON宏在参数为真时,打印内核信息,调用 panic()函数使系统发声严重错误===============================================================上下文环境:

t->buffer = binder_alloc_buf(target_proc, tr->data_size,tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));

static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, size_t data_size, size_t offsets_size, int is_async)

{ struct rb_node *n = proc->free_buffers.rb_node; struct binder_buffer *buffer; size_t buffer_size; struct rb_node *best_fit = NULL; void *has_page_addr; void *end_page_addr; size_t size;

// proc没有共享内存(上层木有使用过 mmap()来创建共享内存)if (proc->vma == NULL) { printk(KERN_ERR "binder: %d: binder_alloc_buf, no vma\n", proc->pid); return NULL;

}

// 将 data_size、offsets_size先调整 4字节对齐然后相加size = ALIGN(data_size, sizeof(void *)) + ALIGN(offsets_size, sizeof(void *));

if (size < data_size || size < offsets_size) { binder_user_error("binder: %d: got transaction with invalid "

"size %d-%d\n", proc->pid, data_size, offsets_size); return NULL;

}

if (is_async && proc->free_async_space < size + sizeof(struct binder_buffer)) { ……

}

while (n) { // 在 proc->free_buffers可用 buffer树中找到最适合的 binder_buffer来使用// 所谓最适合的条件是:找到等于或大于所需大小的 binder_buffer节点buffer = rb_entry(n, struct binder_buffer, rb_node); BUG_ON(!buffer->free);

Page 33: Android 进程间通信机制(Binder)介绍

buffer_size = binder_buffer_size(proc, buffer);

if (size < buffer_size) { best_fit = n; n = n->rb_left;

} else if (size > buffer_size) n = n->rb_right;

else { best_fit = n; break;

} } if (best_fit == NULL) { printk(KERN_ERR "binder: %d: binder_alloc_buf size %d failed, " "no address space\n", proc->pid, size); return NULL;

} if (n == NULL) { // “找来找去,没有找到相同 buffer_size ”的,将就用稍微大一点的吧buffer = rb_entry(best_fit, struct binder_buffer, rb_node); buffer_size = binder_buffer_size(proc, buffer);

} if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) printk(KERN_INFO "binder: %d: binder_alloc_buf size %d got buff" "er %p size %d\n", proc->pid, size, buffer, buffer_size);

// 调整从 buffer->data开始的缓冲区大小必需在一页内has_page_addr = (void *)(((size_t)buffer->data + buffer_size) & PAGE_MASK);

if (n == NULL) { // 之所以要加 4是为结构体中的柔性数组指针大小(虽然在使用 sizeof()不会参与计算,但存在就会占用空间)// 之所以是>=是因为在等于的情况下,binder_buffer的数据域不能装下任何其他的数据,所以也就是 no roomif (size + sizeof(struct binder_buffer) + 4 >= buffer_size)

buffer_size = size; /* no room for other buffers */ else

buffer_size = size + sizeof(struct binder_buffer); } end_page_addr = (void *)PAGE_ALIGN((size_t)buffer->data + buffer_size); if (end_page_addr > has_page_addr) {// 超出了一页的大小end_page_addr = has_page_addr;

}// 分配一个页,同时映射于内核空间和用户空间if (binder_update_page_range(proc, 1, (void *)PAGE_ALIGN((size_t)buffer->data), end_page_addr, NULL)) return NULL;

// 清理工作rb_erase(best_fit, &proc->free_buffers); // 该 buffer欲被分配使用,free标志设置为 0buffer->free = 0; // 将已分配供使用的 binder_buffer插入到 proc对象中的 allocated_buffers树中binder_insert_allocated_buffer(proc, buffer); if (buffer_size != size) { // 真是一点空闲内存空间都不放过!struct binder_buffer *new_buffer = (void *)buffer->data + size; // 将此 new_buffer挂载到 buffer中的 entry字段下(free and allocated)list_add(&new_buffer->entry, &buffer->entry); new_buffer->free = 1; // “将这个 姑且还可能算是一个可用的 binder_buffer”挂载到 proc中的 free_buffers中binder_insert_free_buffer(proc, new_buffer);

} if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) printk(KERN_INFO "binder: %d: binder_alloc_buf size %d got " "%p\n", proc->pid, size, buffer);

// 设置相应信息,后面会继续处理buffer->data_size = data_size; buffer->offsets_size = offsets_size; buffer->async_transaction = is_async; if (is_async) { ……

}

return buffer; }binder_buffer_size()这个函数也挺有意思的,用来获得在 proc->buffer缓冲区中指定 binder_buffer数据域大小:static size_t binder_buffer_size(

struct binder_proc *proc, struct binder_buffer *buffer) {

if (list_is_last(&buffer->entry, &proc->buffers)) // 缓冲区结尾地址减去 binder_buffer数据区域开始的地址就是 binder_buffer中数据 buffer的大小return proc->buffer + proc->buffer_size - (void *)buffer->data;

else // 找到该 binder_buffer后面的一个 binder_buffer对象的起始地址减去当前数据 buffer的起始地址return (size_t)list_entry(buffer->entry.next,

Page 34: Android 进程间通信机制(Binder)介绍

struct binder_buffer, entry) - (size_t)buffer->data; }总而言之,binder_alloc_buf()函数就是在内核空间找到一块适合的空闲 binder_buffer来存储从用户空间所传递过来的参数;若没有空闲空间的,那么就再创建一个了。

继续上面的 binder_transaction()函数,执行if (target_node)binder_inc_node(target_node, 1, 0, NULL);

其中 binder_inc_node()函数用来增加指定 node的引用计数(上已分析过):static int binder_inc_node(struct binder_node *node, int strong, int internal,

struct list_head *target_list) {

if (strong) { if (internal) {

……} else

node->local_strong_refs++; if (!node->has_strong_ref && list_empty(&node->work.entry))

list_add_tail(&node->work.entry, target_list); } else { ……

} return 0;

}

继续上面的 binder_transaction()函数,执行// 从缓冲区开始,定位到缓冲区中数据的末尾地址,也就是第 1个对象在缓冲区中的偏移地址offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));

// 将用户空间中传递过来的数据内容拷贝至 t->buffer->data处,大小应该是 tr->data_sizeif (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {binder_user_error("binder: %d:%d got transaction with invalid "

"data ptr\n", proc->pid, thread->pid);return_error = BR_FAILED_REPLY;goto err_copy_data_failed;

}// 紧接着再次拷贝 Parcel类中 mObjects对应的数据,大小应该是 tr->offsets_size// 一定要理解 mObjects这个数组里面装的是什么!// 里面的每个元素是用户空间传递到 binder驱动的每个对象的对应的起始地址 “ ”(距离缓冲区开头的 距离 )// (注:所有对象以 struct flat_binder_object结构体传递)if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {binder_user_error("binder: %d:%d got transaction with invalid "

"offsets ptr\n", proc->pid, thread->pid);return_error = BR_FAILED_REPLY;goto err_copy_data_failed;

}// 定位到从用户空间传递下来的所有数据的末尾off_end = (void *)offp + tr->offsets_size;

for (; offp < off_end; offp++) {// 由于在上层有传输过一个 flat_binder_object对象,在这里便会取出之struct flat_binder_object *fp;// 检查偏移地址的合法性,似乎用*offp+sizeof(*fp) > t->buffer->data_size等效一下会更好理解一些if (*offp > t->buffer->data_size - sizeof(*fp)) {

binder_user_error("binder: %d:%d got transaction with ""invalid offset, %d\n",proc->pid, thread->pid, *offp);

return_error = BR_FAILED_REPLY;goto err_bad_offset;

}// 找到这个等效传递对象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;struct binder_node *node = binder_get_node(proc, fp->binder);if (node == NULL) {

// 刚开肯定找不到,走这里,binder_new_node()函数具体见下node = binder_new_node(proc, fp->binder);if (node == NULL) {

return_error = BR_FAILED_REPLY;goto err_binder_new_node_failed;

}node->cookie = fp->cookie; // 这个就是上层的 service对象了node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;// 下面的这个 accept_fds应该为 1 , FLAT_BINDER_FLAG_ACCEPTS_FDS旗标在// flat_binder_object刚创建时就设置了node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);

}// 下面的 binder_get_ref_for_node()函数用以获得参数 node所对应的 binder_ref对象(见上)ref = binder_get_ref_for_node(target_proc, node);if (ref == NULL) {

return_error = BR_FAILED_REPLY;

Page 35: Android 进程间通信机制(Binder)介绍

goto err_binder_get_ref_for_node_failed;}if (fp->type == BINDER_TYPE_BINDER) {

// 走这里 , 注意下面这条语句!fp->type = BINDER_TYPE_HANDLE;

}else

fp->type = BINDER_TYPE_WEAK_HANDLE;// 注意下面这条语句!fp->handle = ref->desc;// 增加引用计数// 注意:此时 thread->todo应该是 empty,执行完下面这条语句后,thread->todo只有一个类型为// BINDER_WORK_NODE的 binder_work对象binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo);if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)

printk(KERN_INFO " node %d u%p -> ref %d desc %d\n", node->debug_id, node->ptr, ref->debug_id, ref->desc);

} break;……

}if (reply) {……

} else if (!(t->flags & TF_ONE_WAY)) {BUG_ON(t->buffer->async_transaction != 0);t->need_reply = 1;// 保存 t当前正在处理的事务// from_parent意思很好理解:就是这个 transaction_data的来源 thread的父 threadt->from_parent = thread->transaction_stack;// 又来了新事物(这里就是 t),先处理它,也就是有事务要处理了就压栈(当然后面肯定有一个退栈的动作)thread->transaction_stack = t;

} else {……

}// 任务挂到 target_list中t->work.type = BINDER_WORK_TRANSACTION;list_add_tail(&t->work.entry, target_list);// 未尽任务挂到本进程相关线程对象程中// “下面这条语句作用就是将 BINDER_WORK_TRANSACTION_COMPLETE这条消息告知上层,你所请求的动作已经完// ”成,返回给你,你自己做后续处理 ,而在上层,我们确实会看到在一个 while “ ”循环中来处理底层传上来的 消息tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;list_add_tail(&tcomplete->entry, &thread->todo);// 唤醒被阻塞的 ServiceManager进程if (target_wait)wake_up_interruptible(target_wait);

return;……

上面 binder_new_node()函数定义如下:static struct binder_node *binder_new_node(struct binder_proc *proc, void __user *ptr){

struct rb_node **p = &proc->nodes.rb_node;struct rb_node *parent = NULL;struct binder_node *node;

while (*p) {parent = *p;node = rb_entry(parent, struct binder_node, rb_node);

if (ptr < node->ptr)p = &(*p)->rb_left;

else if (ptr > node->ptr)p = &(*p)->rb_right;

else// 需要注意这种情况:当找到 ptr和 node->ptr相同时,表明已经有了我们想要的 binder_node。// “也就是: 喔,你叫我创建一个新的 binder_node,但是你原来本身却已存在,你这是什么意思?// 返回一个 NULL ”给你得了return NULL;

}

// 为 binder_node分配空间node = kzalloc(sizeof(*node), GFP_KERNEL);if (node == NULL)return NULL;

binder_stats.obj_created[BINDER_STAT_NODE]++;// 将新创建的 node挂接到 proc中的 nodes树中rb_link_node(&node->rb_node, parent, p);rb_insert_color(&node->rb_node, &proc->nodes);// binder_last_id为一全局变量,初始值为 0node->debug_id = ++binder_last_id;node->proc = proc;// 这个 ptr字段很重要,就是上层中 this.getWeakRefs()函数的返回值(this为 BBinder类型)node->ptr = ptr;// 设置该 node的类型node->work.type = BINDER_WORK_NODE;INIT_LIST_HEAD(&node->work.entry);

Page 36: Android 进程间通信机制(Binder)介绍

INIT_LIST_HEAD(&node->async_todo);return node;

}

!!的作用就是:将非零值转换为 1,零值还是零。这个适合用作“ ”开关变量 的设置。

到这里,我们看到需要唤醒 ServiceManager进程了,但同时本进程还是需要继续往下执行的,猜想一下下面应该还会有一个同步,具体应该是本进程执行到一定程度会阻塞,后面会由 ServiceManager来唤醒,然后本进程继续执行。

继续回到上面的 binder_ioctl()函数,执行如下语句:// 上面 talkWithDriver()函数中有设置 bwr.read_size为 mIn.dataCapacity(),所以进入下面 if语句if (bwr.read_size > 0) {

ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer,bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);

if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait);

if (ret < 0) { if (copy_to_user(ubuf, &bwr, sizeof(bwr)))

ret = -EFAULT; goto err;

} }

具体的读取过程由 binder_thread_read()函数来处理(部分调试信息已删除):static intbinder_thread_read(struct binder_proc *proc, struct binder_thread *thread,

void __user *buffer, int size, signed long *consumed, int non_block){

void __user *ptr = buffer + *consumed;void __user *end = buffer + size;

int ret = 0;int wait_for_proc_work;

if (*consumed == 0) {// 下面的这个 put_user宏的作用就是将 BR_NOOP的值存到用户空间中的 ptr中// 注:这个函数只能拷贝简单类型

// BR_NOOP命令表示神马都不做if (put_user(BR_NOOP, (uint32_t __user *)ptr))

return -EFAULT;ptr += sizeof(uint32_t);

}

retry:// wait_for_proc_work:// 0 —— 线程还有未处理完的事情// 1 —— 线程可以开始工作了// 显然对于这里,应该是为 0,因为// 1、在 binder_transaction()函数中已有设置 thread->transaction_stack = t;// 2、tcomplete已挂在 thread->todo中;wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);

if (thread->return_error != BR_OK && ptr < end) {// 线程状态有错误,并且还未读取完用户所需要的信息if (thread->return_error2 != BR_OK) {

// 线程状态码 2有错误,将之返回给用户进程if (put_user(thread->return_error2, (uint32_t __user *)ptr))

return -EFAULT;ptr += sizeof(uint32_t);if (ptr == end)

// 已读取到指定字节数的数据goto done;

// 复位错误码(说明:可能在这里比较迷糊这些错误码是在做什么,继续往下看就会逐渐清晰了)thread->return_error2 = BR_OK;

}// 返回错误码 1if (put_user(thread->return_error, (uint32_t __user *)ptr))

return -EFAULT;ptr += sizeof(uint32_t);// 复位错误码 1thread->return_error = BR_OK;goto done;

}// 小结一下上面的错误码设置:// 首先判断当前的这个处理线程的状态码 1 错误 并且 用户进程需要读取的信息长度未满足// 在这里先判断错误码 2是否有错误,若有的话,先返回错误码 2// 再返回错误码 1(这个是必需返回的)

// 设置当前 binder处理线程的状态(等待)thread->looper |= BINDER_LOOPER_STATE_WAITING;if (wait_for_proc_work)proc->ready_threads++;

mutex_unlock(&binder_lock);if (wait_for_proc_work) {……

Page 37: Android 进程间通信机制(Binder)介绍

} else {// 线程有事可做if (non_block) {

// 非阻塞情况,正有线程在处理 binderif (!binder_has_thread_work(thread))

// thread正忙,返回-EAGAIN,意思就是你再试一下ret = -EAGAIN;

} else// 目前 thread肯定是有事可干,则不会阻塞状态,继续执行ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));

}mutex_lock(&binder_lock);if (wait_for_proc_work)proc->ready_threads--;

// 消除线程的等待标志thread->looper &= ~BINDER_LOOPER_STATE_WAITING;

// 这个 ret返回值判断很重要,若上面的 wait_event_interruptible..语句运行正确,则返回 0,// 不然则是一个很严重的内核等待错误,直接返回了错误码if (ret)return ret;

while (1) {uint32_t cmd;struct binder_transaction_data tr;struct binder_work *w;struct binder_transaction *t = NULL;

if (!list_empty(&thread->todo))// 我们看到会优先处理的是 thread的 todo工作链表w = list_first_entry(&thread->todo, struct binder_work, entry);

else if (!list_empty(&proc->todo) && wait_for_proc_work)// 然后再处理 proc的 todo工作链表w = list_first_entry(&proc->todo, struct binder_work, entry);

else {/* no data added */if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))

goto retry;// 第 2次从这里退出 whilebreak;

}

if (end - ptr < sizeof(tr) + 4)break;

switch (w->type) {……

case BINDER_WORK_TRANSACTION_COMPLETE: {cmd = BR_TRANSACTION_COMPLETE;// 先返回一个 BR_TRANSACTION_COMPLETE命令给上层用户if (put_user(cmd, (uint32_t __user *)ptr))

return -EFAULT;ptr += sizeof(uint32_t);

// 下面语句等效为:// binder_stats.br[_IOC_NR(cmd)]++; // proc->stats.br[_IOC_NR(cmd)]++; // thread->stats.br[_IOC_NR(cmd)]++;binder_stat_br(proc, thread, cmd);

if (binder_debug_mask & BINDER_DEBUG_TRANSACTION_COMPLETE)printk(KERN_INFO "binder: %d:%d BR_TRANSACTION_COMPLETE\n", proc->pid, thread->pid);

// 清除这个工作节点list_del(&w->entry);kfree(w);binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++;

} break;case BINDER_WORK_NODE: {

// 下面部分需要注意!// 这个 BINDER_WORK_NODE是在 binder_transaction()函数的最后添加到 thread->todo中!struct binder_node *node = container_of(w, struct binder_node, work); uint32_t cmd = BR_NOOP; const char *cmd_name; int strong = node->internal_strong_refs || node->local_strong_refs; int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong; // 此时 strong和 weak都为 1if (weak && !node->has_weak_ref) {

// 一开始 node->has_weak_ref为 0,走这里cmd = BR_INCREFS; cmd_name = "BR_INCREFS"; node->has_weak_ref = 1; node->local_weak_refs++;

} else if (strong && !node->has_strong_ref) {

Page 38: Android 进程间通信机制(Binder)介绍

// 第二次 node->has_strong_ref为 0,走这里cmd = BR_ACQUIRE; cmd_name = "BR_ACQUIRE"; node->has_strong_ref = 1; node->local_strong_refs++;

} else if (!strong && node->has_strong_ref) { cmd = BR_RELEASE; ……

} else if (!weak && node->has_weak_ref) { cmd = BR_DECREFS; ……

} if (cmd != BR_NOOP) {

// 此部分的处理流程见上层中的 executeCommand()函数if (put_user(cmd, (uint32_t __user *)ptr))

return -EFAULT; // ptr指向的就是上层 service的引用计数 mRefsptr += sizeof(uint32_t); if (put_user(node->ptr, (void * __user *)ptr))

return -EFAULT; // cookie就是该 service对象ptr += sizeof(void *); if (put_user(node->cookie, (void * __user *)ptr))

return -EFAULT; ptr += sizeof(void *);

binder_stat_br(proc, thread, cmd); if (binder_debug_mask & BINDER_DEBUG_USER_REFS)

printk(KERN_INFO "binder: %d:%d %s %d u%p c%p\n", proc->pid, thread->pid, cmd_name, node->debug_id,

node->ptr, node->cookie); } else {

// 第三次走这里list_del_init(&w->entry); // 将该 BINDER_WORK_NODE从 thread->todo中删除if (!weak && !strong) {

……} else {

if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS) printk(KERN_INFO

"binder: %d:%d node %d u%p c%p state unchanged\n", proc->pid, thread->pid, node->debug_id, node->ptr,node->cookie);

} }

} break;……}

// 第一次 t为空,再次循环if (!t)

continue;

BUG_ON(t->buffer == NULL);if (t->buffer->target_node) {

struct binder_node *target_node = t->buffer->target_node;tr.target.ptr = target_node->ptr;tr.cookie = target_node->cookie;t->saved_priority = task_nice(current);if (t->priority < target_node->min_priority && !(t->flags & TF_ONE_WAY))

binder_set_nice(t->priority);else if (!(t->flags & TF_ONE_WAY) ||

t->saved_priority > target_node->min_priority)binder_set_nice(target_node->min_priority);

cmd = BR_TRANSACTION;} else {

tr.target.ptr = NULL;tr.cookie = NULL;cmd = BR_REPLY;

}tr.code = t->code;tr.flags = t->flags;tr.sender_euid = t->sender_euid;

if (t->from) {struct task_struct *sender = t->from->proc->tsk;tr.sender_pid = task_tgid_nr_ns(sender, current->nsproxy->pid_ns);

} else {tr.sender_pid = 0;

}

tr.data_size = t->buffer->data_size;tr.offsets_size = t->buffer->offsets_size;tr.data.ptr.buffer = (void *)((void *)t->buffer->data + proc->user_buffer_offset);tr.data.ptr.offsets = tr.data.ptr.buffer +

Page 39: Android 进程间通信机制(Binder)介绍

ALIGN(t->buffer->data_size, sizeof(void *));

if (put_user(cmd, (uint32_t __user *)ptr))return -EFAULT;

ptr += sizeof(uint32_t);if (copy_to_user(ptr, &tr, sizeof(tr)))

return -EFAULT;ptr += sizeof(tr);

binder_stat_br(proc, thread, cmd);

list_del(&t->work.entry);t->buffer->allow_user_free = 1;if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {

t->to_parent = thread->transaction_stack;t->to_thread = thread;thread->transaction_stack = t;

} else {t->buffer->transaction = NULL;kfree(t);binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++;

}break;

}

done:

// 返回了 BR_NOOP 和 BR_TRANSACTION_COMPLETE,共 8个字节,故*consumed = 8*consumed = ptr - buffer;// 看下接下来的几个值就好理解了:// proc->requested_threads = 0 // proc->requested_threads_started = 0 // proc-> = 15 // thread->looper = 0// 由于 thread->looper = 0,所以不会进入下面的 if语句if (proc->requested_threads + proc->ready_threads == 0 && proc->requested_threads_started < proc->max_threads && (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ /*spawn a new thread if we leave this out */) {proc->requested_threads++;if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))

return -EFAULT;}return 0;

}上面的 binder_has_proc_work()用来判断 proc是否有事可干,或是和当前这个 proc有相同 pid的线程被要求退出,若是则返回 true,否则返回 false,实现如下:static intbinder_has_proc_work(struct binder_proc *proc, struct binder_thread *thread){

return !list_empty(&proc->todo) || (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);}上面的 binder_has_thread_work()用来判断 thread是否有事可干,或者要求其退出,或者状态错误,若是则返回true,否则返回 false,实现如下:static int binder_has_thread_work(struct binder_thread *thread) {

return !list_empty(&thread->todo) || thread->return_error != BR_OK || (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);

}

再次回到 binder_ioctl()函数,接下来执行如下语句:……if (!list_empty(&proc->todo)) {

// 此时 proc->todo暂时还为空,故跳过此 if而不会调用下面的wake_up_interruptible()函数wake_up_interruptible(&proc->wait);

}if (ret < 0) {

if (copy_to_user(ubuf, &bwr, sizeof(bwr))) ret = -EFAULT;

goto err; }

} // 将结果返回给上层if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {

ret = -EFAULT; goto err;

} break;

继续返回到上层 IPCThreadState::waitForResponse()函数中: while (1) { // 上面所说的while() “ ”循环来处理从底层传递上来的 消息 就是这个 if ((err=talkWithDriver()) < NO_ERROR) break; err = mIn.errorCheck();

Page 40: Android 进程间通信机制(Binder)介绍

if (err < NO_ERROR) break; if (mIn.dataAvail() == 0) continue; // 目前只考虑 BR_NOOP、BR_INCREFS、BR_ACQUIRE和 BR_TRANSACTION_COMPLETE命令 cmd = mIn.readInt32(); ……

switch (cmd) { case BR_TRANSACTION_COMPLETE: // 由于 reply非空,故神马都没做就 break,继续外层循环 if (!reply && !acquireResult) goto finish; break; ……

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; }其中 executeCommand()函数用以处理其他命令,具体如下(目前只看 BR_NOOP、BR_INCREFS、BR_ACQUIRE的处理):status_t IPCThreadState::executeCommand(int32_t cmd){ BBinder* obj; RefBase::weakref_type* refs; status_t result = NO_ERROR; switch (cmd) {

……

case BR_ACQUIRE: // 处理流程和下面的 BR_INCREFS类似 refs = (RefBase::weakref_type*)mIn.readInt32(); obj = (BBinder*)mIn.readInt32(); // 验证此 refs所属的对象是否是 obj LOG_ASSERT(refs->refBase() == obj, "BR_ACQUIRE: object %p does not match cookie %p (expected %p)", refs, obj, refs->refBase()); obj->incStrong(mProcess.get()); IF_LOG_REMOTEREFS() { LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj); obj->printRefs(); } mOut.writeInt32(BC_ACQUIRE_DONE); mOut.writeInt32((int32_t)refs); mOut.writeInt32((int32_t)obj); break;

……

case BR_INCREFS: refs = (RefBase::weakref_type*)mIn.readInt32(); // 获得该 service对象的 mRefs obj = (BBinder*)mIn.readInt32(); // 获得该 service对象 refs->incWeak(mProcess.get()); // 该 service对象的弱引用数加 1 // 返回结果给驱动(具体是通过 talkWithDriver()这个函数完成的) // 注意:此时虽然往 mOut中写入数据,但从驱动来的数据还未全部处理完,故下面走 case BR_ACQUIRE流程 mOut.writeInt32(BC_INCREFS_DONE); mOut.writeInt32((int32_t)refs); mOut.writeInt32((int32_t)obj); break; case BR_NOOP: break; …… }

if (result != NO_ERROR) { mLastError = result; } return result;}

Page 41: Android 进程间通信机制(Binder)介绍

目前这里几乎是木有做任何事情-_-!

好,到此,上层一直执行 while循环,等待从底层传输过来命令。

下面 ServiceManager准备从阻塞中退出(被唤醒),看下它正在处理的流程(binder_thread_read()函数中)://////////////////////////////////////////////////////////////////////////////////////// 实际上对于 ServiceManager的一阶段分析应该到此结束了,它会等待其他进/ 线程的要求然后进行相应处理 ////////////////////////////////////////////////////////////////////////////////////////

mutex_lock(&binder_lock);if (wait_for_proc_work)proc->ready_threads--;

// 消除线程的等待标志thread->looper &= ~BINDER_LOOPER_STATE_WAITING;

// 这个 ret返回值判断很重要,若上面的 wait_event_interruptible..语句运行正确,则返回 0,// 不然则是一个很严重的内核等待错误,直接返回了错误码if (ret)return ret;

// 有任务了,let's rock

while (1) {uint32_t cmd;// 驱动层组装这个 binder_transaction_data对象,然后将其返回给用户空间。struct binder_transaction_data tr;struct binder_work *w;struct binder_transaction *t = NULL;

if (!list_empty(&thread->todo))// 我们看到会优先处理 thread中的 todo队列w = list_first_entry(&thread->todo, struct binder_work, entry);

else if (!list_empty(&proc->todo) && wait_for_proc_work)w = list_first_entry(&proc->todo, struct binder_work, entry);

else {/* no data added */if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))

goto retry;break;

}

if (end - ptr < sizeof(tr) + 4)break;

switch (w->type) {case BINDER_WORK_TRANSACTION: {

// 走此分支// 注意:BINDER_WORK_TRANSACTION在上面 binder_transaction()函数中设置,此处取出的// t也在该函数中设置,此时 t不为 NULL,故下面的 if语句略过t = container_of(w, struct binder_transaction, work);

} break;……

}

if (!t) {continue;

}

BUG_ON(t->buffer == NULL);if (t->buffer->target_node) {

// 下面的这个 target_node应该就是对应于 ServiceManager的了struct binder_node *target_node = t->buffer->target_node;tr.target.ptr = target_node->ptr; // 0tr.cookie = target_node->cookie;t->saved_priority = task_nice(current);if (t->priority < target_node->min_priority && !(t->flags & TF_ONE_WAY))

binder_set_nice(t->priority);else if (!(t->flags & TF_ONE_WAY) ||

t->saved_priority > target_node->min_priority)binder_set_nice(target_node->min_priority);

cmd = BR_TRANSACTION;} else {

tr.target.ptr = NULL;tr.cookie = NULL;cmd = BR_REPLY;

}tr.code = t->code;tr.flags = t->flags;tr.sender_euid = t->sender_euid;

if (t->from) {struct task_struct *sender = t->from->proc->tsk;tr.sender_pid = task_tgid_nr_ns(sender, current->nsproxy->pid_ns);

} else {

Page 42: Android 进程间通信机制(Binder)介绍

……}

tr.data_size = t->buffer->data_size;tr.offsets_size = t->buffer->offsets_size;// 返回给用户空间的 tr对象,其缓冲区地址应将其从内核空间转换为用户空间tr.data.ptr.buffer = (void *)((void *)t->buffer->data + proc->user_buffer_offset);// offsets存储空间是紧接着 buffer的,这里就是定位到该位置tr.data.ptr.offsets = tr.data.ptr.buffer +

ALIGN(t->buffer->data_size, sizeof(void *));

// 将信息返回给用户空间(bwr的读缓冲区)if (put_user(cmd, (uint32_t __user *)ptr))

return -EFAULT;ptr += sizeof(uint32_t);// 将 tr返回给用户空间(bwr的读缓冲区)if (copy_to_user(ptr, &tr, sizeof(tr)))

return -EFAULT;ptr += sizeof(tr);

binder_stat_br(proc, thread, cmd);

list_del(&t->work.entry);t->buffer->allow_user_free = 1;if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {

// 事务栈t->to_parent = thread->transaction_stack;t->to_thread = thread;thread->transaction_stack = t;

} else {……

}break;

}

done:

*consumed = ptr - buffer;if (proc->requested_threads + proc->ready_threads == 0 && proc->requested_threads_started < proc->max_threads && (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ /*spawn a new thread if we leave this out */) {proc->requested_threads++;if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))

return -EFAULT;}return 0;

ServiceManager进程对应的驱动函数 binder_thread_read()退出后,继续执行 binder_ioctl()中的如下语句:(说明:代码虽然在上面已经分析过了,但现在处于不同情况)

if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait);

……// 将 bwr重新拷贝回用户空间// 注意:成员 readbuf所对应的数据已经在 binder_thread_read中先行返回了if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {

ret = -EFAULT; goto err;

}

至此,已将数据返回给 ServiceManager用户进程空间,然后将由其处理,先看下上下文环境(binder_loop()函数中): for (;;) { // 设置我们需要读取什么,这里为一个 cmd,类型为 unsigned bwr.read_size = sizeof(readbuf); bwr.read_consumed = 0; bwr.read_buffer = (unsigned) readbuf;

// 从 binder驱动读取信息 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; }

Page 43: Android 进程间通信机制(Binder)介绍

}=================================================================> 相关结构体struct binder_txn { void *target; void *cookie; uint32_t code; uint32_t flags;

uint32_t sender_pid; uint32_t sender_euid;

uint32_t data_size; uint32_t offs_size; void *data; void *offs; };

struct binder_io { char *data; /* pointer to read/write from */ uint32_t *offs; /* array of offsets */ uint32_t data_avail; /* bytes available in data buffer */ uint32_t offs_avail; /* entries available in offsets array */

char *data0; /* start of data buffer */ uint32_t *offs0; /* start of offsets buffer */ uint32_t flags; uint32_t unused; }; ===============================================================int binder_parse(struct binder_state *bs, struct binder_io *bio, uint32_t *ptr, uint32_t size, binder_handler func){ int r = 1; uint32_t *end = ptr + (size / 4);

while (ptr < end) { // 获得从驱动层传来的命令 uint32_t cmd = *ptr++;#if TRACE fprintf(stderr,"%s:\n", cmd_name(cmd));#endif switch(cmd) { case BR_NOOP: // 还记得在 binder_thread_read驱动函数中,当*consumed=0时,有设置 BR_NOOP么,看到这里什么都没做 break;

…… case BR_TRANSACTION: { // 将 binder_transaction_data结构体强制转换为 binder_txn来处理 struct binder_txn *txn = (void *) ptr; if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) { LOGE("parse: txn too small!\n"); return -1; } // 调试函数 binder_dump_txn(txn); if (func) { // func为传递进来的函数指针,指向 svcmgr_handler unsigned rdata[256/4]; struct binder_io msg; struct binder_io reply; int res;

bio_init(&reply, rdata, sizeof(rdata), 4); bio_init_from_txn(&msg, txn); res = func(bs, txn, &msg, &reply); binder_send_reply(bs, &reply, txn->data, res); }

// 更新 ptr读取指针位置。。。 ptr += sizeof(*txn) / sizeof(uint32_t); break; }

…… } }

return r;}

上面用 cmd_name这个函数配合宏来获得 switch case后面分支的名称于调试比较有用:例如(BC_XXX等均为整型量):#define NAME(n) case n : return #n const char *cmd_name(uint32_t cmd)

Page 44: Android 进程间通信机制(Binder)介绍

{ switch(cmd) { NAME(BC_TRANSACTION); NAME(BC_REPLY); NAME(BC_ACQUIRE_RESULT); NAME(BC_FREE_BUFFER); NAME(BC_INCREFS); NAME(BC_ACQUIRE); NAME(BC_RELEASE); NAME(BC_DECREFS); NAME(BC_INCREFS_DONE); NAME(BC_ACQUIRE_DONE); NAME(BC_ATTEMPT_ACQUIRE); NAME(BC_REGISTER_LOOPER); NAME(BC_ENTER_LOOPER); NAME(BC_EXIT_LOOPER); NAME(BC_REQUEST_DEATH_NOTIFICATION); NAME(BC_CLEAR_DEATH_NOTIFICATION); NAME(BC_DEAD_BINDER_DONE); default: return "???"; } }然后在程序中直接使用 cmd_name(cmd)即可打印出 cmd对应的名称。(实际上也就是'#'符号在宏中的用法,字符串化)

上面 bio_init()函数具体如下:void bio_init(struct binder_io *bio, void *data, uint32_t maxdata, uint32_t maxoffs) { uint32_t n = maxoffs * sizeof(uint32_t);

if (n > maxdata) { bio->flags = BIO_F_OVERFLOW; bio->data_avail = 0; bio->offs_avail = 0; return; }

bio->data = bio->data0 = data + n; bio->offs = bio->offs0 = data; bio->data_avail = maxdata - n; bio->offs_avail = maxoffs; bio->flags = 0; }bio_init_from_txn()函数具体如下:void bio_init_from_txn(struct binder_io *bio, struct binder_txn *txn) { bio->data = bio->data0 = txn->data; bio->offs = bio->offs0 = txn->offs; bio->data_avail = txn->data_size; bio->offs_avail = txn->offs_size / 4; bio->flags = BIO_F_SHARED; }

调试函数 binder_dump_txn()及其相关函数如下:=================================================================> 相关结构体(将这个结构体和 flat_binder_object结构体类看)struct binder_object { uint32_t type; uint32_t flags; void *pointer; // “ ”驱动已经将所有对象 搬动 到本进程中,故只需要获得该对象的地址就可以了 void *cookie; };===============================================================#if TRACE void hexdump(void *_data, unsigned len) { unsigned char *data = _data; unsigned count;

for (count = 0; count < len; count++) { if ((count & 15) == 0) fprintf(stderr,"%04x:", count); fprintf(stderr," %02x %c", *data, (*data < 32) || (*data > 126) ? '.' : *data); data++; if ((count & 15) == 15) fprintf(stderr,"\n"); } if ((count & 15) != 0) fprintf(stderr,"\n"); }

void binder_dump_txn(struct binder_txn *txn) { struct binder_object *obj;

Page 45: Android 进程间通信机制(Binder)介绍

unsigned *offs = txn->offs; // 定位到数据缓冲区中记录所传输对象的偏移的起始地址 unsigned count = txn->offs_size / 4; // 获得数据缓冲区中所传输的对象的个数

fprintf(stderr," target %p cookie %p code %08x flags %08x\n", txn->target, txn->cookie, txn->code, txn->flags); fprintf(stderr," pid %8d uid %8d data %8d offs %8d\n", txn->sender_pid, txn->sender_euid, txn->data_size, txn->offs_size); // 打印输出而已 hexdump(txn->data, txn->data_size); while (count--) { // obj定位到具体传输的各个对象的起始地址 obj = (void*) (((char*) txn->data) + *offs++); fprintf(stderr," - type %08x flags %08x ptr %p cookie %p\n", obj->type, obj->flags, obj->pointer, obj->cookie); } }

#define NAME(n) case n: return #n const char *cmd_name(uint32_t cmd) { switch(cmd) { NAME(BR_NOOP); NAME(BR_TRANSACTION_COMPLETE); NAME(BR_INCREFS); NAME(BR_ACQUIRE); NAME(BR_RELEASE); NAME(BR_DECREFS); NAME(BR_TRANSACTION); NAME(BR_REPLY); NAME(BR_FAILED_REPLY); NAME(BR_DEAD_REPLY); NAME(BR_DEAD_BINDER); default: return "???"; } } #else #define hexdump(a,b) do{} while (0) #define binder_dump_txn(txn) do{} while (0) #endif

接下来执行如下语句: res = func(bs, txn, &msg, &reply);也就是说使用 svcmgr_handler()函数来处理:int svcmgr_handler(struct binder_state *bs, struct binder_txn *txn, struct binder_io *msg, struct binder_io *reply) { struct svcinfo *si; uint16_t *s; unsigned len; void *ptr; uint32_t strict_policy;

// LOGI("target=%p code=%d pid=%d uid=%d\n", // txn->target, txn->code, txn->sender_pid, txn->sender_euid);

// 检测 txn->target为 0,否则传递错误 if (txn->target != svcmgr_handle) return -1;

// Equivalent to Parcel::enforceInterface(), reading the RPC // header with the strict mode policy mask and the interface name. // Note that we ignore the strict_policy and don't propagate it // further (since we do no outbound RPCs anyway). strict_policy = bio_get_uint32(msg); // 说明:这个 strict_policy最初的源头是在 addService()函数中写入的 // IPCThreadState::self()->getStrictModePolicy()|STRICT_MODE_PENALTY_GATHER s = bio_get_string16(msg, &len); // svcmgr_id的定义如下: // uint16_t svcmgr_id[] = { // 'a','n','d','r','o','i','d','.','o','s','.', // 'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r' // };

// 下面这句所要检验的就是在上面 addService()函数中如下语句所执行的内容 // data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); if ((len != (sizeof(svcmgr_id) / 2)) || memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { fprintf(stderr,"invalid id %s\n", str8(s)); return -1; }

switch(txn->code) { case SVC_MGR_GET_SERVICE:

Page 46: Android 进程间通信机制(Binder)介绍

case SVC_MGR_CHECK_SERVICE: s = bio_get_string16(msg, &len); // 查找 service动作 ptr = do_find_service(bs, s, len); if (!ptr) break; bio_put_ref(reply, ptr); return 0;

case SVC_MGR_ADD_SERVICE: s = bio_get_string16(msg, &len); ptr = bio_get_ref(msg); if (do_add_service(bs, s, len, ptr, txn->sender_euid)) return -1; break;

…… } // 返回结果给驱动,然后驱动反馈给上层 bio_put_uint32(reply, 0); return 0;}其中 bio_get_uint32()函数具体如下:uint32_t bio_get_uint32(struct binder_io *bio) { uint32_t *ptr = bio_get(bio, sizeof(*ptr)); return ptr ? *ptr : 0; }上面的 bio_get()函数定义如下:static void *bio_get(struct binder_io *bio, uint32_t size) { // 将 size整成 4的倍数 size = (size + 3) & (~3);

if (bio->data_avail < size){ bio->data_avail = 0; bio->flags |= BIO_F_OVERFLOW; return 0; } else { // 获得数据缓冲区起始位置 void *ptr = bio->data; // 更新读取之后的位置 bio->data += size; // 可用(读)字节数相应减少 bio->data_avail -= size; return ptr; } }

再来看看 bio_get_string16()这个函数:uint16_t *bio_get_string16(struct binder_io *bio, unsigned *sz) { unsigned len; len = bio_get_uint32(bio); if (sz) *sz = len; return bio_get(bio, (len + 1) * sizeof(uint16_t)); }说明:这个函数可以和 Parcel类中的 writeString16()成员函数对应着来看,每每在写入字符串时,都会先写入字符串的长度,然后才是具体的数据,所以,我们在读取时,要先获得字符串的长度,然后取你对应的长度的数据内容即可。

继续回到 svcmgr_handler()函数,接下来执行如下语句: ptr = bio_get_ref(msg);bio_get_ref()函数及其所涉及函数具体如下:=================================================================> 相关结构体struct binder_object { uint32_t type; uint32_t flags; void *pointer; void *cookie; };===============================================================static struct binder_object *_bio_get_obj(struct binder_io *bio) { unsigned n; unsigned off = bio->data - bio->data0;

/* TODO: be smarter about this? */ for (n = 0; n < bio->offs_avail; n++) { // 找到这个对象在数据缓冲区中的位置,然后与 offs数组中记录的位置相比较,若相同,则说明它确实是一个 // 被传输的对象 (谷歌表示对这种做法不大满意) if (bio->offs[n] == off) return bio_get(bio, sizeof(struct binder_object)); }

Page 47: Android 进程间通信机制(Binder)介绍

bio->data_avail = 0; bio->flags |= BIO_F_OVERFLOW; return 0; }

void *bio_get_ref(struct binder_io *bio) { struct binder_object *obj;

// “ ”做所以这种转换 有用 ,可参照 struct flat_binder_object “ ”的定义,发现两者定义的 结构 是相同的 obj = _bio_get_obj(bio); if (!obj) return 0;

if (obj->type == BINDER_TYPE_HANDLE) return obj->pointer; // 这里虽然名为 pointer,但其实是一个整型值(在 binder_transaction()函数中 // 有执行如下语句:fp->handle = ref->desc;)

return 0; }

继续回到 svcmgr_handler()函数,接下来执行如下语句: if (do_add_service(bs, s, len, ptr, txn->sender_euid)) return -1; do_add_service()函数具体如下:=================================================================> 相关结构体struct binder_death { void (*func)(struct binder_state *bs, void *ptr); void *ptr; };

struct svcinfo { struct svcinfo *next; void *ptr; // 或者是 handle(目前是这个),或者是其它(还未知可以是什么) struct binder_death death; unsigned len; uint16_t name[0]; // 上层传递下来的服务名称}; ===============================================================int do_add_service(struct binder_state *bs, uint16_t *s, unsigned len, void *ptr, unsigned uid) { struct svcinfo *si; // LOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid);

if (!ptr || (len == 0) || (len > 127)) return -1;

if (!svc_can_register(uid, s)) { // 判定是否有权限添加此 service LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n", str8(s), ptr, uid); return -1; }

si = find_svc(s, len); if (si) { if (si->ptr) { LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n", str8(s), ptr, uid); return -1; } si->ptr = ptr; } else { // 显然不会找到,走这里 si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); if (!si) { LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n", str8(s), ptr, uid); return -1; } si->ptr = ptr; si->len = len; memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); si->name[len] = '\0'; si->death.func = svcinfo_death; si->death.ptr = si; // 将这个新创建的 svcinfo对象加到全局 svclist链表头 si->next = svclist; svclist = si; }

Page 48: Android 进程间通信机制(Binder)介绍

binder_acquire(bs, ptr); binder_link_to_death(bs, ptr, &si->death); return 0; }其中 find_svc()函数如下:=================================================================> 相关全局变量struct svcinfo *svclist = 0; // 所有的 service就挂在上面===============================================================struct svcinfo *find_svc(uint16_t *s16, unsigned len) { struct svcinfo *si;

for (si = svclist; si; si = si->next) { if ((len == si->len) && !memcmp(s16, si->name, len * sizeof(uint16_t))) { return si; } } return 0; }再看下面的 binder_acquire()函数,用来增加新增加的这个服务的引用计数,具体如下:void binder_acquire(struct binder_state *bs, void *ptr) { // 对于 BC_ACQUIRE的流程上已看过 uint32_t cmd[2]; cmd[0] = BC_ACQUIRE; cmd[1] = (uint32_t) ptr; binder_write(bs, cmd, sizeof(cmd)); }接下来的 binder_link_to_death()函数如下:void binder_link_to_death(struct binder_state *bs, void *ptr, struct binder_death *death) { uint32_t cmd[3]; cmd[0] = BC_REQUEST_DEATH_NOTIFICATION; cmd[1] = (uint32_t) ptr; cmd[2] = (uint32_t) death; binder_write(bs, cmd, sizeof(cmd)); }先走一下 binder_thread_write()函数中的 BC_ACUQIRE分支,具体如下:

……switch (cmd) { case BC_INCREFS: case BC_ACQUIRE: case BC_RELEASE: case BC_DECREFS: {

uint32_t target; struct binder_ref *ref; const char *debug_string;

if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT;

ptr += sizeof(uint32_t); if (target == 0 && binder_context_mgr_node && (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {

……} else {

// 现在 target不为 0(就是上层设置的 si->ptr),走这里ref = binder_get_ref(proc, target);

} // 这里 ref一定不(能)为 NULL,因为在上面的 binder_transaction()函数中有执行如下语句:// ref = binder_get_ref_for_node(target_proc, node);if (ref == NULL) {

binder_user_error("binder: %d:%d refcou" "nt change on invalid ref %d\n", proc->pid, thread->pid, target);

break; } switch (cmd) { ……// 下面的 BC_ACQUIRE分支流程见上case BC_ACQUIRE:

debug_string = "Acquire"; binder_inc_ref(ref, 1, NULL); break;

……} ……break;

}……

对于 binder_link_to_death()函数中的 BC_REQUEST_DEATH_NOTIFICATION这个命令在 binder_ioctl()中的分支具体如下:

……

Page 49: Android 进程间通信机制(Binder)介绍

case BC_REQUEST_DEATH_NOTIFICATION:case BC_CLEAR_DEATH_NOTIFICATION: {

uint32_t target; void __user *cookie; struct binder_ref *ref; struct binder_ref_death *death;

if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT;

ptr += sizeof(uint32_t); // cookie指向的是上层中的 struct binder_death对象if (get_user(cookie, (void __user * __user *)ptr))

return -EFAULT; ptr += sizeof(void *); // 在 proc->refs_by_desc树中查找指定 desc(target)的 ref,肯定存在,原因见上ref = binder_get_ref(proc, target); if (ref == NULL) {

binder_user_error("binder: %d:%d %s " "invalid ref %d\n", proc->pid, thread->pid, cmd == BC_REQUEST_DEATH_NOTIFICATION ? "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", target);

break; }

……

if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { if (ref->death) {

binder_user_error("binder: %d:%" "d BC_REQUEST_DEATH_NOTI" "FICATION death notific" "ation already set\n", proc->pid, thread->pid);

break; } death = kzalloc(sizeof(*death), GFP_KERNEL); if (death == NULL) {

thread->return_error = BR_ERROR; if (binder_debug_mask & BINDER_DEBUG_FAILED_TRANSACTION)

printk(KERN_INFO "binder: %d:%d " "BC_REQUEST_DEATH_NOTIFICATION failed\n", proc->pid, thread->pid);

break; } binder_stats.obj_created[BINDER_STAT_DEATH]++; INIT_LIST_HEAD(&death->work.entry); death->cookie = cookie; // 此 cookie就是上层中的 si->deathref->death = death; if (ref->node->proc == NULL) {

// 肯定不为 NULL,下面忽略……

} } else {

……}

} break;……

现在这个命令的作用不大清楚,后面再看。

继续回到 svcmgr_handler函数,下面执行如下语句: bio_put_uint32(reply, 0); 上面 bio_put_uint32()函数具体如下:void bio_put_uint32(struct binder_io *bio, uint32_t n) { uint32_t *ptr = bio_alloc(bio, sizeof(n)); if (ptr) *ptr = n; } 其中 bio_alloc()函数如下:static void *bio_alloc(struct binder_io *bio, uint32_t size) { size = (size + 3) & (~3); if (size > bio->data_avail) { bio->flags |= BIO_F_OVERFLOW; return 0; } else { void *ptr = bio->data; bio->data += size; bio->data_avail -= size; return ptr; } }

Page 50: Android 进程间通信机制(Binder)介绍

说明:这里的*bio对应的就是上面 binder_parse中的 reply变量,它通过 bio_init()这个函数进行了初始化。

回到上面的 binder_parse()函数,继续执行如下语句(res为 0): binder_send_reply(bs, &reply, txn->data, res);其中 binder_send_reply()函数具体如下:void binder_send_reply(struct binder_state *bs, struct binder_io *reply, void *buffer_to_free, int status) { struct { uint32_t cmd_free; void *buffer; uint32_t cmd_reply; struct binder_txn txn; } __attribute__((packed)) data;

// 传送两个命令给 binder驱动,分别为 BC_FREE_BUFFER、BC_REPLY data.cmd_free = BC_FREE_BUFFER; data.buffer = buffer_to_free; data.cmd_reply = BC_REPLY; data.txn.target = 0; data.txn.cookie = 0; data.txn.code = 0; if (status) {

…… } else { data.txn.flags = 0; data.txn.data_size = reply->data - reply->data0; data.txn.offs_size = ((char*) reply->offs) - ((char*) reply->offs0); data.txn.data = reply->data0; data.txn.offs = reply->offs0; } binder_write(bs, &data, sizeof(data)); }

__attribute__ ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是 GCC特有的语法。参考:http://www.cnblogs.com/dongzhiquan/archive/2011/03/17/1986614.html

可以看到 binder_io结构体中对于数据和偏移信息的结构和 binder底层数据的存放正好相反。binder驱动的存储方式是:data在前,offs在后;而 binder_io正好相反。

看到上面 binder_send_reply()函数的最后使用 binder_write()函数来和 binder驱动进行通信,里面通过 ioctl()系统调用来和驱动进行通信,传递的参数为 binder_write_read变量,具体如下(上面已分析过):int binder_write(struct binder_state *bs, void *data, unsigned len) { struct binder_write_read bwr; int res; bwr.write_size = len; bwr.write_consumed = 0; bwr.write_buffer = (unsigned) data; bwr.read_size = 0; bwr.read_consumed = 0; bwr.read_buffer = 0; res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); if (res < 0) { fprintf(stderr,"binder_write: ioctl failed (%s)\n", strerror(errno)); } return res; }下面就转入到 binder驱动中 binder_ioctl()函数的相应部分:static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {

int ret; struct binder_proc *proc = filp->private_data; // 取出私有数据struct binder_thread *thread; unsigned int size = _IOC_SIZE(cmd); void __user *ubuf = (void __user *)arg;

……

switch (cmd) { // 这个分支是最常执行的一个,用来从 binder读取信息或是写入内容case BINDER_WRITE_READ: { struct binder_write_read bwr; // 从用户空间传来的正是 struct binder_write_read结构体// 这里之所以将 binder_write_read组成在一个结构体中,就是为了在进行一种操作的同时(写/读),就可以// 通过该结构体变量附带另一种操作(读/写)。所以 binder驱动就省去了传统的 write和 read方法if (size != sizeof(struct binder_write_read)) {

ret = -EINVAL; goto err;

} // 传入的参数处于用户空间,将之拷贝到内核空间

Page 51: Android 进程间通信机制(Binder)介绍

if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { ret = -EFAULT; goto err;

} // 需要写入内容,具体会调用 binder_thread_write()函数,下面会有详细说明if (bwr.write_size > 0) {

ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer,bwr.write_size, &bwr.write_consumed);

if (ret < 0) { bwr.read_consumed = 0; if (copy_to_user(ubuf, &bwr, sizeof(bwr)))

ret = -EFAULT; goto err;

} } ……

} ……

err: ……return ret;

}在写入时,调用的函数是 binder_thread_write()。函数比较大,我们只分析现在关联的部分(部分调试信息已删除):intbinder_thread_write(struct binder_proc *proc, struct binder_thread *thread,

void __user *buffer, int size, signed long *consumed){

uint32_t cmd;// 要写入的数据此时还处于用户空间void __user *ptr = buffer + *consumed;void __user *end = buffer + size;

while (ptr < end && thread->return_error == BR_OK) {// 下面的这个 get_user实际上是一个宏,具体定义我们也不用去管它,只要知道用它来获得在// binder_loop()函数中填入的命令,例如 BC_ENTER_LOOPER等if (get_user(cmd, (uint32_t __user *)ptr))

return -EFAULT;// 跳过命令字节长度ptr += sizeof(uint32_t);// _IOC_NR这个宏我们前面已说明过,作用是取得 bit0~bit7的值;// ARRAY_SIZE的作用是取得 binder_stats.bc这个数组的大小// 总之,作用就是:判断当前的这个 cmd是否是一个合法的 cmd(数值不能超过 BC_DEAD_BINDER_DONE// 的值,因为它是在 BinderDriverCommandProtocol中定义的最后的一个枚举成员)if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {

binder_stats.bc[_IOC_NR(cmd)]++;proc->stats.bc[_IOC_NR(cmd)]++;thread->stats.bc[_IOC_NR(cmd)]++;

}switch (cmd) {case BC_FREE_BUFFER: {

// 释放驱动层为进行 binder通信所分配的空间void __user *data_ptr; struct binder_buffer *buffer;

if (get_user(data_ptr, (void * __user *)ptr)) return -EFAULT;

// ptr继续往后,掠过该分配空间的起始地址ptr += sizeof(void *);

// 在 proc中 allocated_buffers树中判断欲释放的 binder_buffer是否存在buffer = binder_buffer_lookup(proc, data_ptr); if (buffer == NULL) {

binder_user_error("binder: %d:%d " "BC_FREE_BUFFER u%p no match\n", proc->pid, thread->pid, data_ptr);

break; } // 判断是否允许用户释放此 binder_bufferif (!buffer->allow_user_free) {

binder_user_error("binder: %d:%d " "BC_FREE_BUFFER u%p matched " "unreturned buffer\n", proc->pid, thread->pid, data_ptr);

break; } if (binder_debug_mask & BINDER_DEBUG_FREE_BUFFER)

printk(KERN_INFO"binder: %d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n",

proc->pid, thread->pid, data_ptr, buffer->debug_id, buffer->transaction ? "active" : "finished");

if (buffer->transaction) { // 走这里,buffer->transaction为 t(在 binder_transaction()函数中设置)buffer->transaction->buffer = NULL; buffer->transaction = NULL;

Page 52: Android 进程间通信机制(Binder)介绍

} if (buffer->async_transaction && buffer->target_node) {

// 不是异步传输,此 if部分暂略……

} // 具体的释放动作binder_transaction_buffer_release(proc, buffer, NULL); binder_free_buf(proc, buffer); break;

}case BC_TRANSACTION: // 上层使用 binder_transaction_data结构体变量作为载体往驱动传递数据case BC_REPLY: {

struct binder_transaction_data tr;

if (copy_from_user(&tr, ptr, sizeof(tr)))return -EFAULT;

ptr += sizeof(tr);// 做进一步处理,具体定义见下binder_transaction(proc, thread, &tr, cmd == BC_REPLY);break;

}……}// 计算已经写入的字节数*consumed = ptr - buffer;

}return 0;

}其中 binder_buffer_lookup()函数如下,作用为在 proc相关的空间红黑分配树中,找到对应的 buffer:static struct binder_buffer *binder_buffer_lookup(

struct binder_proc *proc, void __user *user_ptr) {

struct rb_node *n = proc->allocated_buffers.rb_node; struct binder_buffer *buffer; struct binder_buffer *kern_ptr;

kern_ptr = user_ptr - proc->user_buffer_offset - offsetof(struct binder_buffer, data);

while (n) { buffer = rb_entry(n, struct binder_buffer, rb_node); BUG_ON(buffer->free);

if (kern_ptr < buffer) n = n->rb_left;

else if (kern_ptr > buffer) n = n->rb_right;

else return buffer;

} return NULL;

}其中 kern_ptr的求法比较有意思,分两步来看:1、user_ptr - proc->user_buffer_offset结果就是将用户空间地址转换为内核空间地址;2、offsetof宏的定义如下:#define offsetof(TYPE, MEMBER) (size_t)&(((TYPE *)0)->MEMBER)作用为:获得 MEMBER字段在 TYPE结构体中的偏移注意:此处的 user_ptr为原先传递给上层的数据缓冲区的首地址,也就是对应着 binder_buffer结构体中的最后一个data字段,所以 user_ptr - proc->user_buffer_offset - offsetof(struct binder_buffer, data); 语句的作用就是获得表示该数据缓冲区的 binder_buffer结构体变量。

了解内核空间中是怎么组织这一个一个的数据缓冲区的,实际上就是一个个连续的 binder_buffer变量。

继续上面的 binder_thread_write()函数,接下来会调用 binder_transaction_buffer_release()函数,具体如下:static void binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer *buffer, size_t *failed_at) {

size_t *offp, *off_end; int debug_id = buffer->debug_id;

……

if (buffer->target_node) {binder_dec_node(buffer->target_node, 1, 0);

}

offp = (size_t *)(buffer->data + ALIGN(buffer->data_size, sizeof(void *))); if (failed_at) ……

else off_end = (void *)offp + buffer->offsets_size;

for (; offp < off_end; offp++) { struct flat_binder_object *fp; if (*offp > buffer->data_size - sizeof(*fp)) {

Page 53: Android 进程间通信机制(Binder)介绍

printk(KERN_ERR "binder: transaction release %d bad offset %d, size %d\n",debug_id, *offp, buffer->data_size); continue;

} // 找到这个对象fp = (struct flat_binder_object *)(buffer->data + *offp); switch (fp->type) { case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: {

// 现在走此分支,在前面已经将 fp->type从 BINDER_TYPE_BINDER更新为 BINDER_TYPE_HANDLEstruct binder_ref *ref = binder_get_ref(proc, fp->handle); if (ref == NULL) {

printk(KERN_ERR "binder: transaction release %d bad handle %ld\n",debug_id, fp->handle);

break; } ……// 减少此对象的引用计数binder_dec_ref(ref, fp->type == BINDER_TYPE_HANDLE);

} break; ……

} }

} 其中 binder_dec_ref()函数如下:

static int binder_dec_ref(struct binder_ref *ref, int strong) {

if (strong) { if (ref->strong == 0) {

binder_user_error("binder: %d invalid dec strong, " "ref %d desc %d s %d w %d\n", ref->proc->pid, ref->debug_id, ref->desc, ref->strong, ref->weak);

return -EINVAL; } ref->strong--; // 强引用计数减 1if (ref->strong == 0) {

int ret; ret = binder_dec_node(ref->node, strong, 1); if (ret)

return ret; }

} else { if (ref->weak == 0) {

……}ref->weak--;

} if (ref->strong == 0 && ref->weak == 0) {// 皮之不存,毛将焉附?把 binder_ref也删除喽binder_delete_ref(ref);

}return 0;

}上面 binder_dec_node()函数具体如下:(作用暂时还不大清楚,可能是会删除无用的 binder_node,但对于 binder_context_mgr_node肯定是不会被删除的)static int binder_dec_node(struct binder_node *node, int strong, int internal) {

if (strong) { if (internal)

node->internal_strong_refs--; else

node->local_strong_refs--; if (node->local_strong_refs || node->internal_strong_refs)

return 0; } else { if (!internal)

node->local_weak_refs--;if (node->local_weak_refs || !hlist_empty(&node->refs))

return 0;} if (node->proc && (node->has_strong_ref || node->has_weak_ref)) { if (list_empty(&node->work.entry)) {

list_add_tail(&node->work.entry, &node->proc->todo); wake_up_interruptible(&node->proc->wait);

} } else { list_del_init(&node->work.entry); if (hlist_empty(&node->refs) && !node->local_strong_refs && !node->local_weak_refs) {

if (node->proc) { rb_erase(&node->rb_node, &node->proc->nodes); if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS)

Page 54: Android 进程间通信机制(Binder)介绍

printk(KERN_INFO "binder: refless node %d deleted\n",node->debug_id);

} else { hlist_del(&node->dead_node); if (binder_debug_mask & BINDER_DEBUG_INTERNAL_REFS)

printk(KERN_INFO "binder: dead node %d deleted\n",node->debug_id);

} kfree(node); binder_stats.obj_deleted[BINDER_STAT_NODE]++;

} }

return 0; }

在 BC_FREE_BUFFER分支的最后调用 binder_free_buf()将该 binder_buffer给释放掉,具体如下:static void binder_free_buf(

struct binder_proc *proc, struct binder_buffer *buffer) {

size_t size, buffer_size;

buffer_size = binder_buffer_size(proc, buffer);

size = ALIGN(buffer->data_size, sizeof(void *)) + ALIGN(buffer->offsets_size, sizeof(void *));

if (binder_debug_mask & BINDER_DEBUG_BUFFER_ALLOC) printk(KERN_INFO "binder: %d: binder_free_buf %p size %d buffer" "_size %d\n", proc->pid, buffer, size, buffer_size);

// 一连几个 BUG_ON(),所以嘛,内存操作要小心BUG_ON(buffer->free); BUG_ON(size > buffer_size); BUG_ON(buffer->transaction != NULL); BUG_ON((void *)buffer < proc->buffer); BUG_ON((void *)buffer > proc->buffer + proc->buffer_size);

if (buffer->async_transaction) { ……

}

// 下面这个函数在上面有说过,根据第 2个参数,表示是创建一个页同时映射到内核和用户空间的对应位置,还是// 删除一个页,显然这里应该是后者binder_update_page_range(proc, 0, (void *)PAGE_ALIGN((size_t)buffer->data), (void *)(((size_t)buffer->data + buffer_size) & PAGE_MASK), NULL);

// 将之从 proc->allocated_buffers(已分配 buffers链表)中删除rb_erase(&buffer->rb_node, &proc->allocated_buffers); buffer->free = 1; // 表示现在这个 binder_buffer可以被重新回收利用了if (!list_is_last(&buffer->entry, &proc->buffers)) { // 若此 binder_buffer不是 proc->buffers中的最后一个元素// 那就找到该 binder_buffer的下一个元素struct binder_buffer *next = list_entry(buffer->entry.next,

struct binder_buffer, entry); if (next->free) {

// 若发现它下一个元素也是可用的 binder_buffer,那就先将之删除rb_erase(&next->rb_node, &proc->free_buffers); binder_delete_free_buffer(proc, next);

} } if (proc->buffers.next != &buffer->entry) { // 若发现此 buffer不是 proc->buffers链表中的第一个元素,则判断它前一个元素是否也为空闲的,若是// 则也将之删除struct binder_buffer *prev = list_entry(buffer->entry.prev,

struct binder_buffer, entry); if (prev->free) {

binder_delete_free_buffer(proc, buffer); rb_erase(&prev->rb_node, &proc->free_buffers); buffer = prev;

} } // 上面做了这么多,说白了就是将相邻两个连续空闲的 binder_buffer合并起来而已(这就是内存处理的技巧了)binder_insert_free_buffer(proc, buffer);

}

接下来会执行 binder_thread_write()函数中的 BC_REPLY 分支,然后调用 binder_transaction()函数做进一步处理,具体如下(此时 reply为 1):static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread,

struct binder_transaction_data *tr, int reply) {

struct binder_transaction *t; struct binder_work *tcomplete; size_t *offp, *off_end;

Page 55: Android 进程间通信机制(Binder)介绍

struct binder_proc *target_proc; struct binder_thread *target_thread = NULL; struct binder_node *target_node = NULL; struct list_head *target_list; wait_queue_head_t *target_wait; struct binder_transaction *in_reply_to = NULL; struct binder_transaction_log_entry *e; uint32_t return_error;

……

if (reply) { // 获得 ServiceManager自唤醒后,正在处理的事物in_reply_to = thread->transaction_stack; if (in_reply_to == NULL) {

binder_user_error("binder: %d:%d got reply transaction " "with no transaction stack\n", proc->pid, thread->pid);

return_error = BR_FAILED_REPLY; goto err_empty_call_stack;

} binder_set_nice(in_reply_to->saved_priority); // 接收者必需是 ServiceManager// 意思就是:发出查询信息的 thread,它的请求对象就应该是现在的 ServiceManager对应的 thread。我们知// 道,在 Android中,对某个 service的查询必需通过 ServiceManager才可以。if (in_reply_to->to_thread != thread) {

binder_user_error("binder: %d:%d got reply transaction " "with bad transaction stack," " transaction %d has target %d:%d\n", proc->pid, thread->pid, in_reply_to->debug_id, in_reply_to->to_proc ? in_reply_to->to_proc->pid : 0, in_reply_to->to_thread ? in_reply_to->to_thread->pid : 0);

return_error = BR_FAILED_REPLY; in_reply_to = NULL; goto err_bad_call_stack;

} // ServiceManager接下来会继续去做 in_replay_to所对应的 thread中的 “未完成的 parent ”事物thread->transaction_stack = in_reply_to->to_parent; // 获得欲发送反馈信息的 target_threadtarget_thread = in_reply_to->from; if (target_thread == NULL) {

return_error = BR_DEAD_REPLY; goto err_dead_binder;

} if (target_thread->transaction_stack != in_reply_to) {

binder_user_error("binder: %d:%d got reply transaction " "with bad target transaction stack %d, " "expected %d\n", proc->pid, thread->pid, target_thread->transaction_stack ? target_thread->transaction_stack->debug_id : 0, in_reply_to->debug_id);

return_error = BR_FAILED_REPLY; in_reply_to = NULL; target_thread = NULL; goto err_dead_binder;

} // 获得欲发送反馈信息的 target_proctarget_proc = target_thread->proc;

} else { ……

} // 获得 target_list和 target_waitif (target_thread) { ……target_list = &target_thread->todo; target_wait = &target_thread->wait;

} else { ……

} ……

/* TODO: reuse incoming transaction for reply */ t = kzalloc(sizeof(*t), GFP_KERNEL); if (t == NULL) { return_error = BR_FAILED_REPLY; goto err_alloc_t_failed;

} binder_stats.obj_created[BINDER_STAT_TRANSACTION]++;

tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); if (tcomplete == NULL) { return_error = BR_FAILED_REPLY;

Page 56: Android 进程间通信机制(Binder)介绍

goto err_alloc_tcomplete_failed; } binder_stats.obj_created[BINDER_STAT_TRANSACTION_COMPLETE]++;

t->debug_id = ++binder_last_id; e->debug_id = t->debug_id;

if (binder_debug_mask & BINDER_DEBUG_TRANSACTION) { if (reply)

printk(KERN_INFO "binder: %d:%d BC_REPLY %d -> %d:%d, " "data %p-%p size %d-%d\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_thread->pid, tr->data.ptr.buffer, tr->data.ptr.offsets, tr->data_size, tr->offsets_size);

else ……

}

if (!reply && !(tr->flags & TF_ONE_WAY)) ……

else {// 作为 REPLY的 binder_transaction,其来源(t->from)就忽略了t->from = NULL;

}t->sender_euid = proc->tsk->euid; t->to_proc = target_proc; t->to_thread = target_thread; t->code = tr->code; t->flags = tr->flags; t->priority = task_nice(current); t->buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));

if (t->buffer == NULL) { return_error = BR_FAILED_REPLY; goto err_binder_alloc_buf_failed;

} t->buffer->allow_user_free = 0; t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; // 注意:从上面一路下来,我们并没有对 target_node的初始值有所改动,// 故此时 t->buffer->target_node也为 NULLt->buffer->target_node = target_node; if (target_node) ……

offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));

if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) { binder_user_error("binder: %d:%d got transaction with invalid "

"data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed;

} if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) { binder_user_error("binder: %d:%d got transaction with invalid "

"offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed;

} off_end = (void *)offp + tr->offsets_size; for (; offp < off_end; offp++) { // 上层并未返回任何对象,略过此 for循环……

} if (reply) { BUG_ON(t->buffer->async_transaction != 0); binder_pop_transaction(target_thread, in_reply_to);

} else if (!(t->flags & TF_ONE_WAY)) { ……

} else { ……

} t->work.type = BINDER_WORK_TRANSACTION; list_add_tail(&t->work.entry, target_list); // 目标进程(service)将会处理此事务tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; list_add_tail(&tcomplete->entry, &thread->todo); // 本进程(ServiceManager)将会处理此事务if (target_wait) // “唤醒目标进程, kick it to work..”wake_up_interruptible(target_wait);

return;

// error handle……

}

Page 57: Android 进程间通信机制(Binder)介绍

其中 binder_pop_transaction()函数用于从指定 target_thread中的 transaction_stack事物栈中退出栈顶事务:注意:此时栈顶事物就必需应该就是参数 t所表示。static void binder_pop_transaction(

struct binder_thread *target_thread, struct binder_transaction *t) {

if (target_thread) { BUG_ON(target_thread->transaction_stack != t); BUG_ON(target_thread->transaction_stack->from != target_thread); target_thread->transaction_stack =

target_thread->transaction_stack->from_parent; t->from = NULL;

} t->need_reply = 0; if (t->buffer) t->buffer->transaction = NULL;

kfree(t); binder_stats.obj_deleted[BINDER_STAT_TRANSACTION]++;

}

注意:上面说本进程(ServiceManager)还会执行一个 BINDER_WORK_TRANSACTION_COMPLETE的事务,然后在驱动层中处理之后会返回一个 BR_TRANSACTION_COMPLETE的返回码给上层 ServiceManager,而 ServiceManager对于这个命令的处理和 BR_NOOP一样,神马都没做,具体可参照上面流程。

使用 wake_up_interruptible()函数来唤醒目标进程(假如目标进程原本被阻塞的话),但本进程仍会继续往下执行。这里先接着分析本进程的执行情况:我们可以看到接下来本进程退出 binder_transaction()函数,进而退出 binder_thread_write()函数,然后退出binder_ioctl()函数,接下来就会回退到上层中的 binder_parse()函数。

注意:上面 binder_parse()函数中,struct binder_io reply;虽然是一个局部变量,但它会传递给驱动层,然后驱动层会执行 copy_from_user(&tr, ptr, sizeof(tr))这条语句 “ ”,也就是说已从用户空间 搬到 了内核空间了,所以就无需考虑其生存周期了。

还记得前面目标进程(service进程)有往 mOut中写入 BC_INCREFS_DONE、BC_ACQUIRE_DONE命令么,都还未传递给binder驱动,所以在 IPCThreadState::waitForResponse()函数中,再次 while循环时,会在 talkWithDriver()函数传递之,直接去看一下这两个命令的处理:

switch (cmd) {……case BC_INCREFS_DONE: case BC_ACQUIRE_DONE: {

void __user *node_ptr; void *cookie; struct binder_node *node;

if (get_user(node_ptr, (void * __user *)ptr)) // mRefsreturn -EFAULT;

ptr += sizeof(void *); if (get_user(cookie, (void * __user *)ptr)) // service对象

return -EFAULT; ptr += sizeof(void *); node = binder_get_node(proc, node_ptr); if (node == NULL) {

binder_user_error("binder: %d:%d " "%s u%p no match\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", node_ptr);

break; } // 减少 node的本地强弱引用计数值binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0); if (binder_debug_mask & BINDER_DEBUG_USER_REFS)

printk(KERN_INFO "binder: %d:%d %s node %d ls %d lw %d\n", proc->pid, thread->pid,

cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE",node->debug_id, node->local_strong_refs, node->local_weak_refs);

break; }……

}

现在我们继续绕回去,回到在上层一直处于 while循环的 IPCThreadState::waitForResponse()函数:这里大部分逻辑上面已经分析过了,在 waitForResponse()函数中先调用 talkWithDriver()函数来于底层的 binder驱动进行通信,然后会获得两个命令:BR_NOOP、BR_REPLY,所以这里我们来看 BR_REPLY分支。status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) { int32_t cmd; int32_t err;

while (1) { if ((err=talkWithDriver()) < NO_ERROR) break; err = mIn.errorCheck(); if (err < NO_ERROR) break;

Page 58: Android 进程间通信机制(Binder)介绍

if (mIn.dataAvail() == 0) continue; cmd = mIn.readInt32();

……

switch (cmd) { …… case BR_REPLY: { binder_transaction_data tr; err = mIn.read(&tr, sizeof(tr)); LOG_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 size_t*>(tr.data.ptr.offsets), tr.offsets_size/sizeof(size_t), freeBuffer, this); } else { …… } } else { …… } } 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; }其中 Parcel类中的 ipcSetDataReference()函数具体如下:void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie) { freeDataNoInit(); mError = NO_ERROR; mData = const_cast<uint8_t*>(data); mDataSize = mDataCapacity = dataSize;

…… mDataPos = 0; // 更新读取位置为 0 LOGV("setDataReference Setting data pos of %p to %d\n", this, mDataPos); mObjects = const_cast<size_t*>(objects); // 设置对象索引偏移数组 mObjectsSize = mObjectsCapacity = objectsCount; // 多少个对象 mNextObjectHint = 0; mOwner = relFunc; // 此处 mOwner已设置为了 refFunc(在下面看时注意这点) mOwnerCookie = relCookie; scanForFds(); }

其中 freeDataNoInit()函数如下:void Parcel::freeDataNoInit() { if (mOwner) {

mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie); } else { // 开始 mOwner为 NULL,走这里 releaseObjects(); if (mData) free(mData); if (mObjects) free(mObjects); } }看下 releaseObjects()这个函数做了什么:void Parcel::releaseObjects() { const sp<ProcessState> proc(ProcessState::self()); size_t i = mObjectsSize;

Page 59: Android 进程间通信机制(Binder)介绍

uint8_t* const data = mData; size_t* const objects = mObjects; while (i > 0) { // i = 0,略过此循环,因为从 binder驱动返回过来仅仅是一个状态码而已,并没有对象! // …… } }

最后看一下 ipcSetDataReference()函数中的 scanForFds()函数:void Parcel::scanForFds() const { bool hasFds = false; for (size_t i=0; i<mObjectsSize; i++) { …… } mHasFds = hasFds; mFdsKnown = true; // 仅仅是更新了 mFdsKnown这个成员变量,其余神马都没做}

好,继续回到 addService()函数中,最后仅仅是返回了一个状态码而已。至此,整个 addService()的流程就差不多了。

回到 DxyhService服务的 main()函数中,接下来执行如下两条语句: ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); 看字面意思是说“好,service ”也建立其起来了,该是进入消息循环的时候了 ,还记得我们在某处设置了该 service支持的最大线程数是 15么(ProcessState成员函数 open_driver()中),所以它是对于线程池而言的,看下 ProcessState类中的 startThreadPool()函数,具体如下:void ProcessState::startThreadPool() { AutoMutex _l(mLock); if (!mThreadPoolStarted) { mThreadPoolStarted = true; spawnPooledThread(true); } }实际做事的是 spawnPooledThread()函数:void ProcessState::spawnPooledThread(bool isMain) { if (mThreadPoolStarted) { // 下面的这个 mThreadPoolSeq成员变量在 ProcessState类构造时初始为 1 // 所以执行完下面这条语句时 s为 1,mThreadPoolSeq为 2 int32_t s = android_atomic_add(1, &mThreadPoolSeq); char buf[32]; sprintf(buf, "Binder Thread #%d", s); LOGV("Spawning new pooled thread, name=%s\n", buf); // 定义了一个强引用,退出下面的那个右大括号时自动调用 PoolThread对象的析构函数 // 注意:PoolThread类继承于 Thread类,而 Thread的析构函数又是虚函数,所以在析构时会先析构 // PoolThread,再析构 Thread // // 从下面 PoolThread类的定义可以看出,它连析构函数都没有显示定义,所以只要调用 Thread类的析构函数即可 sp<Thread> t = new PoolThread(isMain); t->run(buf); } }这里又涉及到 PoolThread这个类以及其成员函数 run(),具体如下:=================================================================> 相关类/* * This is our spiffy thread object! */

class Thread : virtual public RefBase { public: // Create a Thread object, but doesn't create or start the associated // thread. See the run() method. Thread(bool canCallJava = true); virtual ~Thread();

// Start the thread in threadLoop() which needs to be implemented. virtual status_t run( const char* name = 0, int32_t priority = PRIORITY_DEFAULT, size_t stack = 0); // Ask this object's thread to exit. This function is asynchronous, when the // function returns the thread might still be running. Of course, this // function can be called from a different thread. virtual void requestExit();

// Good place to do one-time initializations virtual status_t readyToRun(); // Call requestExit() and wait until this object's thread exits. // BE VERY CAREFUL of deadlocks. In particular, it would be silly to call // this function from this object's thread. Will return WOULD_BLOCK in

Page 60: Android 进程间通信机制(Binder)介绍

// that case. status_t requestExitAndWait();

protected: // exitPending() returns true if requestExit() has been called. bool exitPending() const; private: // Derived class must implement threadLoop(). The thread starts its life // here. There are two ways of using the Thread object: // 1) loop: if threadLoop() returns true, it will be called again if // requestExit() wasn't called. // 2) once: if threadLoop() returns false, the thread will exit upon return. virtual bool threadLoop() = 0;

private: Thread& operator=(const Thread&); static int _threadLoop(void* user); const bool mCanCallJava; thread_id_t mThread; Mutex mLock; Condition mThreadExitedCondition; status_t mStatus; volatile bool mExitPending; volatile bool mRunning; sp<Thread> mHoldSelf; #if HAVE_ANDROID_OS int mTid; #endif };

class PoolThread : public Thread { public: PoolThread(bool isMain) : mIsMain(isMain) { } protected: virtual bool threadLoop() { IPCThreadState::self()->joinThreadPool(mIsMain); return false; } const bool mIsMain; };===============================================================在其构造函数中,只是初始化了一下成员变量,其余嘛都没做。我们知道在构建子类对象时,会优先构建父类对象,在这里,PoolThread类的父类为 Thread,而它的构造函数又很简单,只是初始化一些成员变量而已,并没有实际上的开辟线程的动作(这个也可 Java中的线程很像,你 new一个 Thread对象后若是不调用 start()函数的话是不会创建线程的,而在Android中的 Thread类,你不调用 run()方法是不会创建线程的)。虽然仅仅是初始化一些成员变量,但是每个成员变量本身是什么却很重要:canCallJava —— 和上面的 isMain “参数值一致,那是不是说只有主线程才可以 can call java”,那么怎么 call?thread_id_t —— 一个 void*变量(下面可以看到),初始为-1mLock —— 这个好理解一些,一个成员锁mStatus —— 线程的状态mExitPending—— “ ”这个字面意思是 退出阻塞 ,那又是什么意思呢?更新 “ ”:表示 我已请求你线程退出了,你最好快点结束mRunning —— 是否运行,由于还未创建新线程执行,故这里初始为 falseThread::Thread(bool canCallJava) : mCanCallJava(canCallJava), mThread(thread_id_t(-1)), mLock("Thread::mLock"), mStatus(NO_ERROR), mExitPending(false), mRunning(false){}

由于 PoolThread中并没有自定义 run()函数,所以会执行 Thread类中的 run(),先看其在 Thread类中的声明是什么(又是默认参数的使用): // Start the thread in threadLoop() which needs to be implemented. virtual status_t run( const char* name = 0, int32_t priority = PRIORITY_DEFAULT, size_t stack = 0);那上面 t->run(buf);语句中仅仅将 buf传递给了 name,其余全是默认值,即线程优先级为默认,线程相关堆栈大小为 0。之所以在下面的 run()函数中使用 mLock来锁定是为了防止一个 Thread对象为多个线程使用,避免它们同时调用 run()方法来创建新线程时所带来的冲突。status_t Thread::run(const char* name, int32_t priority, size_t stack) { Mutex::Autolock _l(mLock);

if (mRunning) { // thread already started return INVALID_OPERATION;

Page 61: Android 进程间通信机制(Binder)介绍

}

// reset status and exitPending to their default value, so we can // try again after an error happened (either below, or in readyToRun()) mStatus = NO_ERROR; mExitPending = false; mThread = thread_id_t(-1); // hold a strong reference on ourself // mHoldSelf的定义如下: // sp<Thread> mHoldSelf; // 所以在退出 run()函数时,会自动调用当前这个对象的析构函数,类似于自毁行为。 // 之所以这样是因为:我们在使用线程时的方式可能会是(new Thread()).run();所以这个 new出来的线程对象没有 // 办法获得它(因为并没有将其存储于返回值中),所以只好用这种自毁方法提前释放了(相对于其本身的生命周期) mHoldSelf = this;

// 置线程运行标志为 true mRunning = true;

bool res; if (mCanCallJava) { // mCanCallJava此时为 true,走这里 “ ”,但实际上 绕来绕去 之后,它最终还是会用的下面的 // androidCreateRawThreadEtc函数来创建新的线程 res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } else { res = androidCreateRawThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } if (res == false) { mStatus = UNKNOWN_ERROR; // something happened! mRunning = false; mThread = thread_id_t(-1); mHoldSelf.clear(); // "this" may have gone away after this.

return UNKNOWN_ERROR; } // Do not refer to mStatus here: The thread is already running (may, in fact // already have exited with a valid mStatus result). The NO_ERROR indication // here merely indicates successfully starting the thread and does not // imply successful termination/execution. return NO_ERROR; }上面创建新线程的函数是 createThreadEtc()函数,具体定义如下:// Create thread with lots of parameters inline bool createThreadEtc(thread_func_t entryFunction, void *userData, const char* threadName = "android:unnamed_thread", int32_t threadPriority = PRIORITY_DEFAULT, size_t threadStackSize = 0, thread_id_t *threadId = 0) { return androidCreateThreadEtc(entryFunction, userData, threadName, threadPriority, threadStackSize, threadId) ? true : false; }里面实际做事的是 androidCreateThreadEtc()函数,它里面也就是直接调用 gCreateThreadFn()“ ”函数 。之所以加引号是因为 gCreateThreadFn是一个函数指针,初始化指向的函数体是 androidCreateRawThreadEtc()。当然,你还可以通过 Thread类中的 androidSetCreateThreadFunc()成员函数来设置自己的创建线程函数,传入的参数类型需要是:// Used by the Java Runtime to control how threads are created, so that // they can be proper and lovely Java threads. typedef int (*android_create_thread_fn)(android_thread_func_t entryFunction, void *userData, const char* threadName, int32_t threadPriority, size_t threadStackSize, android_thread_id_t *threadId);

来看下 androidCreateRawThreadEtc()函数,在其中你可以看到熟悉的 pthread线程库函数了,具体如下:=================================================================> 相关结构体struct thread_data_t { // thread_func_t是一个型为 int (*fn)(void *);类型的函数指针 thread_func_t entryFunction; void* userData; int priority; char * threadName;

// we use this trampoline when we need to set the priority with // nice/setpriority. static int trampoline(const thread_data_t* t) { thread_func_t f = t->entryFunction; void* u = t->userData; int prio = t->priority;

Page 62: Android 进程间通信机制(Binder)介绍

char * name = t->threadName; delete t; setpriority(PRIO_PROCESS, 0, prio); pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup); if (gDoSchedulingGroup) { if (prio >= ANDROID_PRIORITY_BACKGROUND) { set_sched_policy(androidGetTid(), SP_BACKGROUND); } else { set_sched_policy(androidGetTid(), SP_FOREGROUND); } } if (name) { #if defined(HAVE_PRCTL) // Mac OS doesn't have this, and we build libutil for the host too int hasAt = 0; int hasDot = 0; char *s = name; while (*s) { if (*s == '.') hasDot = 1; else if (*s == '@') hasAt = 1; s++; } int len = s - name; if (len < 15 || hasAt || !hasDot) { s = name; } else { s = name + len - 15; } prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0); #endif free(name); } return f(u); }};===============================================================int androidCreateRawThreadEtc(android_thread_func_t entryFunction, void *userData, const char* threadName, int32_t threadPriority, size_t threadStackSize, android_thread_id_t *threadId) { // 创建的是 detach属性的线程,也就是创建伊始后就不管其生死了。 pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

#ifdef HAVE_ANDROID_OS /* valgrind is rejecting RT-priority create reqs */ // 这个预编译的条件显然会是成立的,走这里 if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) { // 虽然 threadPriority是 PRIORITY_DEFAULT,但是 threadName却不是 NULL,所以会进入这个 if判断

// We could avoid the trampoline if there was a way to get to the // android_thread_id_t (pid) from pthread_t // translate: 若有办法从 pthread_t得到 android_thread_id_t的话,我们就可以避免 trampoline函数了 // 具体 trampoline()函数是什么,做了什么事情,下面再看 // // 说明:trampoline()函数在设置线程优先级的时候调用 thread_data_t* t = new thread_data_t; t->priority = threadPriority; t->threadName = threadName ? strdup(threadName) : NULL; t->entryFunction = entryFunction; // entryFunction指向_threadLoop函数 t->userData = userData; // 这里的 userData就是当前的这个 PoolThread对象 // 更新 entryFunction的值,表示此线程的入口函数就是 trampoline函数 entryFunction = (android_thread_func_t)&thread_data_t::trampoline; // 更新 userData的值为 t userData = t; } #endif

if (threadStackSize) { // 设置线程相关的栈大小(假如需要的话),默认是不设置的 pthread_attr_setstacksize(&attr, threadStackSize); } // 下面这个 errno变量存在于 errno.h中,为 linux系统全局错误标志 errno = 0; pthread_t thread; // 具体的创建线程的动作 int result = pthread_create(&thread, &attr, (android_pthread_entry)entryFunction, userData); if (result != 0) { LOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n"

Page 63: Android 进程间通信机制(Binder)介绍

"(android threadPriority=%d)", entryFunction, result, errno, threadPriority); return 0; }

// 下面的 threadId默认为 0,故不会走下面的 if语句 if (threadId != NULL) { *threadId = (android_thread_id_t)thread; // XXX: this is not portable } return 1; }

这里有必要看一下这个 trampoline()是什么(上面已贴出): // we use this trampoline when we need to set the priority with // nice/setpriority. static int trampoline(const thread_data_t* t) { thread_func_t f = t->entryFunction; // f就是指向上面的_threadLoop()函数了 void* u = t->userData; int prio = t->priority; char * name = t->threadName; delete t; // 线程优先级调整 setpriority(PRIO_PROCESS, 0, prio); pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup); if (gDoSchedulingGroup) { if (prio >= ANDROID_PRIORITY_BACKGROUND) { set_sched_policy(androidGetTid(), SP_BACKGROUND); } else { set_sched_policy(androidGetTid(), SP_FOREGROUND); } } if (name) { #if defined(HAVE_PRCTL) // Mac OS doesn't have this, and we build libutil for the host too int hasAt = 0; int hasDot = 0; char *s = name; while (*s) { if (*s == '.') hasDot = 1; else if (*s == '@') hasAt = 1; s++; } int len = s - name; if (len < 15 || hasAt || !hasDot) { s = name; } else { s = name + len - 15; } prctl(PR_SET_NAME, (unsigned long) s, 0, 0, 0); #endif free(name); } // 主要看这里,相当于会执行_threadLoop(u)函数 return f(u); }

下面看下_threadLoop()函数,具体如下:int Thread::_threadLoop(void* user){ Thread* const self = static_cast<Thread*>(user); sp<Thread> strong(self->mHoldSelf); wp<Thread> weak(strong); // 删除此对象自身的强引用,只保留弱引用 self->mHoldSelf.clear();

#if HAVE_ANDROID_OS // this is very useful for debugging with gdb self->mTid = gettid();#endif

bool first = true;

do { bool result; if (first) { first = false; // 调用 readyToRun()函数,里面仅仅就是返回了一个 NO_ERROR,所以说这个函数是给用户使用的 // 需要在线程启动前做一些事情,只要自己写类继承 Thread类,然后重载 readyToRun()函数即可。 self->mStatus = self->readyToRun(); result = (self->mStatus == NO_ERROR);

if (result && !self->mExitPending) { // 奥,到这里就清楚了这个 mExitPending “成员变量是作为: 我要求该线程自动退出,但是它还没到时候, // ”所以,等其先做完手头上的事,然后退出即可

Page 64: Android 进程间通信机制(Binder)介绍

// // Binder threads (and maybe others) rely on threadLoop // running at least once after a successful ::readyToRun() // (unless, of course, the thread has already been asked to exit // at that point). // 割断翻译:Binder线程(可能还有其他线程)依赖于在成功调用::readyToRun()函数之后至少要调用 // 一次 threadLoop()函数。(除非该线程已被要求停止执行) // This is because threads are essentially used like this: // (new ThreadSubclass())->run(); // 割断翻译:这是因为线程的使用通常以如下的方式: // (new ThreadSubclass())->run(); // The caller therefore does not retain a strong reference to // the thread and the thread would simply disappear after the // successful ::readyToRun() call instead of entering the // threadLoop at least once. // 割断翻译:调用者不能获得该线程的一个强引用,而且该线程只是在成功调用了::readyToRun()之后简单 // 的消失,而不是进入 threadLoop函数至少一次。 result = self->threadLoop(); } } else { result = self->threadLoop(); }

if (result == false || self->mExitPending) { self->mExitPending = true; self->mLock.lock(); self->mRunning = false; // clear thread ID so that requestExitAndWait() does not exit if // called by a new thread using the same thread ID as this one. self->mThread = thread_id_t(-1); self->mThreadExitedCondition.broadcast(); self->mThread = thread_id_t(-1); // thread id could be reused self->mLock.unlock(); break; } // Release our strong reference, to let a chance to the thread // to die a peaceful death. strong.clear(); // And immediately, re-acquire a strong reference for the next loop strong = weak.promote(); } while(strong != 0); return 0;}

这里的工作线程调用了 threadLoop()函数做后续处理。这个函数在 PoolThread类中定义,为虚函数。这个函数的源头是在 Thread类里面定义的一个纯虚函数。里面就是直接调用了 IPCThreadState类的 joinThreadPool()函数,传入的参数为 PoolThread类的成员变量 mIsMain,这里是为 true。看下 threadLoop()的具体定义(上已贴出): virtual bool threadLoop() { // 注意:下面的 IPCThreadState::self()会新创建一个 IPCThreadState对象与当前线程关联! IPCThreadState::self()->joinThreadPool(mIsMain); return false; }暂时不忙去分析 joinThreadPool()函数具体是什么,现在转入 DxyhService的 main()函数中,还有一条语句未执行: IPCThreadState::self()->joinThreadPool();看到这条语句和新创建的线程中执行的是同样的函数,先看该函数在 IPCThreadState类中的声明: void joinThreadPool(bool isMain = true);说明默认参数是 true,所以这里子线程和本进程都以 true调用了 joinThreadPool()函数,在看该函数的具体定义之前,还得先看 IPCThreadState类中的 self()成员函数(上面已介绍过)。到目前为止,和本进程相关的 IPCThreadState对象还没有存在过,则会创建这个单例对象。接下来看下 joinThreadPool()函数做了什么:void IPCThreadState::joinThreadPool(bool isMain){ LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());

// 对于主线程,此时 mOut.dataSize()的值为 8(目前存在有一个 BC_FREE_BUFFER的命令)

// mOut根据 isMain来决定发送给 binder驱动的命令 // 若 isMain为 true,则是 BC_ENTER_LOOPER;反之就是 BC_REGISTER_LOOPER 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 default/foreground // one to avoid performing an initial transaction in the background. // // 将当前线程组设置为默认线程(假如是后台线程的话) androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT); status_t result; do { int32_t cmd;

Page 65: Android 进程间通信机制(Binder)介绍

// When we've cleared the incoming command queue, process any pending derefs if (mIn.dataPosition() >= mIn.dataSize()) { size_t numPending = mPendingWeakDerefs.size(); if (numPending > 0) { for (size_t i = 0; i < numPending; i++) { RefBase::weakref_type* refs = mPendingWeakDerefs[i]; refs->decWeak(mProcess.get()); } mPendingWeakDerefs.clear(); }

numPending = mPendingStrongDerefs.size(); if (numPending > 0) { for (size_t i = 0; i < numPending; i++) { BBinder* obj = mPendingStrongDerefs[i]; obj->decStrong(mProcess.get()); } mPendingStrongDerefs.clear(); } }

// now get the next command to be processed, waiting if necessary // 下面的这个 talkWithDriver()函数默认是以 true传递的,也就是说需要从 binder驱动返回信息 result = talkWithDriver(); if (result >= NO_ERROR) { size_t IN = mIn.dataAvail(); if (IN < sizeof(int32_t)) continue; cmd = mIn.readInt32(); IF_LOG_COMMANDS() { alog << "Processing top-level Command: " << getReturnString(cmd) << endl; }

result = executeCommand(cmd); } // After executing the command, ensure that the thread is returned to the // default cgroup before rejoining the pool. The driver takes care of // restoring the priority, but doesn't do anything with cgroups so we // need to take care of that here in userspace. Note that we do make // sure to go in the foreground after executing a transaction, but // there are other callbacks into user code that could have changed // our group so we want to make absolutely sure it is put back. androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);

// 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);

// 不同类型的 log调试开关,比单纯的使用诸如 DEBUG_THREADPOOL等类似宏定义要良好一些 LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n", (void*)pthread_self(), getpid(), (void*)result); // 告诉底层 binder可以退出了 // 要有一个概念就是,我们往 mOut中写入内容或是从 mIn “ ” “ ”中读取内容,它实际上只是进行了 填充 和 准备 , // 真正做事的是下面的 talkWithDriver()函数,若参数为 false表示不需要从 binder驱动获得返回信息 mOut.writeInt32(BC_EXIT_LOOPER); talkWithDriver(false);}

看到其中会通过 talkWithDriver()函数来和底层驱动进行通信,我们先来看新创建的线程中的流程,进程中的后面再看。子线程中会传递一个 BINDER_ENTER_LOOPER命令给 binder驱动,看下 talkWithDriver()函数中的处理流程:status_t IPCThreadState::talkWithDriver(bool doReceive){ LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened"); binder_write_read bwr; // Is the read buffer empty? const bool needRead = mIn.dataPosition() >= mIn.dataSize(); // 事实上目前是两者相等为 0 // We don't want to write anything if we are still reading // from data left in the input buffer and the caller // has requested to read the next data. const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0; bwr.write_size = outAvail; bwr.write_buffer = (long unsigned int)mOut.data();

// This is what we'll read. if (doReceive && needRead) {

Page 66: Android 进程间通信机制(Binder)介绍

bwr.read_size = mIn.dataCapacity(); bwr.read_buffer = (long unsigned int)mIn.data(); } else { bwr.read_size = 0; } // Return immediately if there is nothing to do. if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR; bwr.write_consumed = 0; bwr.read_consumed = 0; status_t err; do {#if defined(HAVE_ANDROID_OS) // 绕来绕去,终于要调用 ioctl()函数来进行写入动作 if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) err = NO_ERROR; else err = -errno;#else err = INVALID_OPERATION;#endif // 之所以需要用 while循环是放置 ioctl()写入信息到 binder驱动时被中断,而这种中断本身并不是错误, // 所以遇到这种情况的话,需要再写一次 } while (err == -EINTR);

if (err >= NO_ERROR) { // 写入成功 if (bwr.write_consumed > 0) { // 若判断到有数据写入到 binder驱动,则需判断是否写入完全 if (bwr.write_consumed < (ssize_t)mOut.dataSize()) mOut.remove(0, bwr.write_consumed); else mOut.setDataSize(0); } // 有读取到数据,设置对应数据长度,初始化读取指针(索引)为读 buffer开头 if (bwr.read_consumed > 0) { mIn.setDataSize(bwr.read_consumed); mIn.setDataPosition(0); } return NO_ERROR; } return err;}上面系统掉用 ioctl()对应的驱动函数为 binder_ioctl(),目前的处理流程如下:static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {

int ret; struct binder_proc *proc = filp->private_data; // 取出私有数据struct binder_thread *thread; unsigned int size = _IOC_SIZE(cmd); void __user *ubuf = (void __user *)arg;

ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); if (ret) return ret;

mutex_lock(&binder_lock); // 注意:这里对应于这新线程还是会再创建一个 binder_thread对象的!thread = binder_get_thread(proc); if (thread == NULL) { ret = -ENOMEM; goto err;

}

switch (cmd) { // 这个分支是最常执行的一个,用来从 binder读取信息或是写入内容case BINDER_WRITE_READ: { struct binder_write_read bwr; // 从用户空间传来的正是 struct binder_write_read结构体// 这里之所以将 binder_write_read组成在一个结构体中,就是为了在进行一种操作的同时(写/读),就可以// 通过该结构体变量附带另一种操作(读/写)。所以 binder驱动就省去了传统的 write和 read方法if (size != sizeof(struct binder_write_read)) {

ret = -EINVAL; goto err;

} // 传入的参数处于用户空间,将之拷贝到内核空间if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {

ret = -EFAULT; goto err;

} // 需要写入内容,具体会调用 binder_thread_write()函数if (bwr.write_size > 0) {

ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer,

Page 67: Android 进程间通信机制(Binder)介绍

bwr.write_size, &bwr.write_consumed); if (ret < 0) {

bwr.read_consumed = 0; if (copy_to_user(ubuf, &bwr, sizeof(bwr)))

ret = -EFAULT; goto err;

} } // 需要读取内容,具体会调用 binder_thread_read()函数if (bwr.read_size > 0) {

ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer,bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);

if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait);

if (ret < 0) { if (copy_to_user(ubuf, &bwr, sizeof(bwr)))

ret = -EFAULT; goto err;

} } if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {

ret = -EFAULT; goto err;

} break;

} ……

err: ……return ret;

}下面看下 binder_thread_write()函数中的 BC_ENTER_LOOPER分支流程:

switch (cmd) {……case BC_ENTER_LOOPER: // 上层 isMain为 true流程,目前两个都走这里

if (binder_debug_mask & BINDER_DEBUG_THREADS) printk(KERN_INFO "binder: %d:%d BC_ENTER_LOOPER\n", proc->pid, thread->pid);

if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) { // 状态错误thread->looper |= BINDER_LOOPER_STATE_INVALID; binder_user_error("binder: %d:%d ERROR:"

" BC_ENTER_LOOPER called after " "BC_REGISTER_LOOPER\n", proc->pid, thread->pid);

} thread->looper |= BINDER_LOOPER_STATE_ENTERED; // 更新线程状态break;

……}

然后驱动层再执行 binder_thread_read()函数,目前处理流程如下:static intbinder_thread_read(struct binder_proc *proc, struct binder_thread *thread,

void __user *buffer, int size, signed long *consumed, int non_block){

void __user *ptr = buffer + *consumed;void __user *end = buffer + size;

int ret = 0;int wait_for_proc_work;

if (*consumed == 0) {// 开始*consumed肯定为 0,走这里if (put_user(BR_NOOP, (uint32_t __user *)ptr))

return -EFAULT;ptr += sizeof(uint32_t);

}

retry:// 此时 wait_for_proc_work值为 1wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);

if (thread->return_error != BR_OK && ptr < end) {// 线程状态有错误,并且还未读取完用户所需要的信息if (thread->return_error2 != BR_OK) {

// 线程状态码 2有错误,将之返回给用户进程if (put_user(thread->return_error2, (uint32_t __user *)ptr))

return -EFAULT;ptr += sizeof(uint32_t);if (ptr == end)

// 已读取到指定字节数的数据goto done;

// 复位错误码(说明:可能在这里比较迷糊这些错误码是在做什么,继续往下看就会逐渐清晰了)thread->return_error2 = BR_OK;

}// 返回错误码 1

Page 68: Android 进程间通信机制(Binder)介绍

if (put_user(thread->return_error, (uint32_t __user *)ptr))return -EFAULT;

ptr += sizeof(uint32_t);// 复位错误码 1thread->return_error = BR_OK;goto done;

}// 小结一下上面的错误码设置:// 首先判断当前的这个处理线程的状态码 1 错误 并且 用户进程需要读取的信息长度未满足// 在这里先判断错误码 2是否有错误,若有的话,先返回错误码 2// 再返回错误码 1(这个是必需返回的)

// 设置当前 binder处理线程的状态(等待)thread->looper |= BINDER_LOOPER_STATE_WAITING;if (wait_for_proc_work)proc->ready_threads++;

mutex_unlock(&binder_lock);if (wait_for_proc_work) {if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |

BINDER_LOOPER_STATE_ENTERED))) { // 上面已有设置了 BINDER_LOOPER_STATE_ENTERED状态,故略过……

} binder_set_nice(proc->default_priority); if (non_block) {

if (!binder_has_proc_work(proc, thread)) ret = -EAGAIN;

} else ret = wait_event_interruptible_exclusive(proc->wait,

binder_has_proc_work(proc, thread));} else {……

}mutex_lock(&binder_lock);if (wait_for_proc_work)proc->ready_threads--;

// 消除线程的等待标志thread->looper &= ~BINDER_LOOPER_STATE_WAITING;

// 这个 ret返回值判断很重要,若上面的 wait_event_interruptible..语句运行正确,则返回 0,// 不然则是一个很严重的内核等待错误,直接返回了错误码if (ret)return ret;

while (1) {uint32_t cmd;struct binder_transaction_data tr;struct binder_work *w;struct binder_transaction *t = NULL;

// 目前 thread->todo和 proc->todo均为空if (!list_empty(&thread->todo))

……else if (!list_empty(&proc->todo) && wait_for_proc_work)

……else {

/* no data added */if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))

goto retry;// 从这里退出 while循环break;

}……

}done:

// 返回了 BR_NOOP*consumed = ptr - buffer;// thread->looper = 0x22(BINDER_LOOPER_STATE_ENTERED|BINDER_LOOPER_STATE_NEED_RETURN)if (proc->requested_threads + proc->ready_threads == 0 && proc->requested_threads_started < proc->max_threads && (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ /*spawn a new thread if we leave this out */) {proc->requested_threads++;// 这里直接将 BR_SPAWN_LOOPER填充到 buffer处,所以前面的 BR_NOOP就被覆盖了if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))

return -EFAULT;}return 0;

}

接下来上层 executeCommand()函数中处理 BR_SPAWN_LOOPER命令的过程很简单,就只是调用了mProcess->spawnPooledThread(false);语句,和上面介绍的类似,只是参数为 false而已。所以,现在的状况是:新创建的线程在执行 BC_ENTER_LOOPER命令后,又创建了一个线程(传 spawnPooledThread()函数的参数为 false)。

Page 69: Android 进程间通信机制(Binder)介绍

接下来我们看这个再次新创建的线程的流程,应该和上面类似,也会创建一个线程相关的 IPCThreadState对象,只是在后面传递给驱动层的命令是 BC_REGISTER_LOOPER,然后驱动层又会创建一个和此线程相关的 binder_thread对象,看下在驱动层中对于 BC_REGISTER_LOOPER命令的处理:

switch (cmd) {……case BC_REGISTER_LOOPER:

if (binder_debug_mask & BINDER_DEBUG_THREADS) printk(KERN_INFO "binder: %d:%d BC_REGISTER_LOOPER\n", proc->pid, thread->pid);

if (thread->looper & BINDER_LOOPER_STATE_ENTERED) { // 状态错误thread->looper |= BINDER_LOOPER_STATE_INVALID; binder_user_error("binder: %d:%d ERROR:"

" BC_REGISTER_LOOPER called " "after BC_ENTER_LOOPER\n", proc->pid, thread->pid);

} else if (proc->requested_threads == 0) { // 不请自来,但此时 proc->requested_threads是不为 0的(详解上面在// binder_thread_read()函数最后 BR_SPAWN_LOOPER部分),故略过thread->looper |= BINDER_LOOPER_STATE_INVALID; binder_user_error("binder: %d:%d ERROR:"

" BC_REGISTER_LOOPER called " "without request\n", proc->pid, thread->pid);

} else { // 走这里proc->requested_threads--; proc->requested_threads_started++;

} thread->looper |= BINDER_LOOPER_STATE_REGISTERED; break;

……}

然后在接下来的 binder_thread_read()函数中,看下现在的处理流程:static intbinder_thread_read(struct binder_proc *proc, struct binder_thread *thread,

void __user *buffer, int size, signed long *consumed, int non_block){

void __user *ptr = buffer + *consumed;void __user *end = buffer + size;

int ret = 0;int wait_for_proc_work;

if (*consumed == 0) {// 开始*consumed肯定为 0,走这里if (put_user(BR_NOOP, (uint32_t __user *)ptr))

return -EFAULT;ptr += sizeof(uint32_t);

}

retry:// 此时 wait_for_proc_work值为 1wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);

if (thread->return_error != BR_OK && ptr < end) {// 线程状态有错误,并且还未读取完用户所需要的信息if (thread->return_error2 != BR_OK) {

// 线程状态码 2有错误,将之返回给用户进程if (put_user(thread->return_error2, (uint32_t __user *)ptr))

return -EFAULT;ptr += sizeof(uint32_t);if (ptr == end)

// 已读取到指定字节数的数据goto done;

// 复位错误码(说明:可能在这里比较迷糊这些错误码是在做什么,继续往下看就会逐渐清晰了)thread->return_error2 = BR_OK;

}// 返回错误码 1if (put_user(thread->return_error, (uint32_t __user *)ptr))

return -EFAULT;ptr += sizeof(uint32_t);// 复位错误码 1thread->return_error = BR_OK;goto done;

}// 小结一下上面的错误码设置:// 首先判断当前的这个处理线程的状态码 1 错误 并且 用户进程需要读取的信息长度未满足// 在这里先判断错误码 2是否有错误,若有的话,先返回错误码 2// 再返回错误码 1(这个是必需返回的)

// 设置当前 binder处理线程的状态(等待)thread->looper |= BINDER_LOOPER_STATE_WAITING;if (wait_for_proc_work)

Page 70: Android 进程间通信机制(Binder)介绍

proc->ready_threads++;mutex_unlock(&binder_lock);if (wait_for_proc_work) {if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |

BINDER_LOOPER_STATE_ENTERED))) { // 上面已有设置了 BINDER_LOOPER_STATE_REGISTERED状态,故略过……

} binder_set_nice(proc->default_priority); if (non_block) {

if (!binder_has_proc_work(proc, thread)) ret = -EAGAIN;

} else ret = wait_event_interruptible_exclusive(proc->wait,

binder_has_proc_work(proc, thread));} else {……

}mutex_lock(&binder_lock);if (wait_for_proc_work)proc->ready_threads--;

// 消除线程的等待标志thread->looper &= ~BINDER_LOOPER_STATE_WAITING;

// 这个 ret返回值判断很重要,若上面的 wait_event_interruptible..语句运行正确,则返回 0,// 不然则是一个很严重的内核等待错误,直接返回了错误码if (ret)return ret;

while (1) {uint32_t cmd;struct binder_transaction_data tr;struct binder_work *w;struct binder_transaction *t = NULL;

// 目前 thread->todo和 proc->todo均为空if (!list_empty(&thread->todo))

……else if (!list_empty(&proc->todo) && wait_for_proc_work)

……else {

/* no data added */if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))

goto retry;// 从这里退出 while循环break;

}……

}done:

// 返回了 BR_NOOP*consumed = ptr - buffer;//thread->looper=0x21(BINDER_LOOPER_STATE_REGISTERED|BINDER_LOOPER_STATE_NEED_RETURN)// 由于此时的 proc->read_threads为 2(刚创建的线程、主线程),故不会进入下面的 ifif (proc->requested_threads + proc->ready_threads == 0 && proc->requested_threads_started < proc->max_threads && (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ /*spawn a new thread if we leave this out */) {proc->requested_threads++;// 这里直接将 BR_SPAWN_LOOPER填充到 buffer处,所以前面的 BR_NOOP就被覆盖了if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))

return -EFAULT;}return 0;

}

特别注意:上面是以一个 debug的流程为基础,因为涉及到多线程问题,实际运行可能不一样,上面的情况就是:在创建第 1个线程时,主线程正在忙其他的事情,所以 proc->read_threads值为 0;在创建第 2个线程时,正巧主线程和刚刚创建的那个线程都闲下来了(主线程不一定,而新创建的线程则一定会空闲),故第 2个线程不会在上层收到BR_SPAWN_LOOPER的命令,而仅仅是一个 BR_NOOP。和线程池模型关联起来想可能会好一点。

服务端介绍得差不多了,下面来看 DxyhClient这个 C++层的客户程序是怎么与 DxyhService进行通信的(当然,你也可以通过 JNI来提供接口给 java层使用)。DxyhClient入口 main()函数如下:int main(int argc, char **argv) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder = sm->getService(String16("service.dxyh")); if (binder == NULL) { aout << "service.dxyh cannot found!" << endl; return(-1); } sp<IDxyhService> dxyhService = interface_cast<IDxyhService>(binder);

Page 71: Android 进程间通信机制(Binder)介绍

dxyhService->setUserName(String16("dengxiayehu")); dxyhService->setUserAge(99); aout << "UserName: " << dxyhService->getUserName() << endl; aout << "UserAge : " << dxyhService->getUserAge() << endl; return(0); }

对于 checkService() “流程,可参照相关的 checkService() ” “未找到流程 的文章,我们这里就从该篇文章中 假设能够查找到指定的 service”开始接着往下看。

先看下 ServiceManager中的上下文环境,使用 svcmgr_handler()函数来处理请求:int svcmgr_handler(struct binder_state *bs, struct binder_txn *txn, struct binder_io *msg, struct binder_io *reply) { struct svcinfo *si; uint16_t *s; unsigned len; void *ptr; uint32_t strict_policy;

// LOGI("target=%p code=%d pid=%d uid=%d\n", // txn->target, txn->code, txn->sender_pid, txn->sender_euid);

if (txn->target != svcmgr_handle) return -1;

// Equivalent to Parcel::enforceInterface(), reading the RPC // header with the strict mode policy mask and the interface name. // Note that we ignore the strict_policy and don't propagate it // further (since we do no outbound RPCs anyway). strict_policy = bio_get_uint32(msg);

s = bio_get_string16(msg, &len);

if ((len != (sizeof(svcmgr_id) / 2)) || memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { fprintf(stderr,"invalid id %s\n", str8(s)); return -1; }

switch(txn->code) { case SVC_MGR_GET_SERVICE: case SVC_MGR_CHECK_SERVICE: s = bio_get_string16(msg, &len); // 查找 service动作 ptr = do_find_service(bs, s, len); if (!ptr) break; bio_put_ref(reply, ptr); return 0;

…… }

bio_put_uint32(reply, 0); return 0;}

在 svcmgr_handler()函数中,使用 do_find_service()函数来超找指定名称的 service:void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len) { struct svcinfo *si; si = find_svc(s, len);

// LOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0); if (si && si->ptr) { return si->ptr; } else { return 0; } }其中 find_svc()函数如下:=================================================================> 相关全局变量struct svcinfo *svclist = 0; // 所有的 service就挂在上面===============================================================struct svcinfo *find_svc(uint16_t *s16, unsigned len) { struct svcinfo *si;

for (si = svclist; si; si = si->next) { if ((len == si->len) && !memcmp(s16, si->name, len * sizeof(uint16_t))) {

// 若能找到的话,走这里

Page 72: Android 进程间通信机制(Binder)介绍

return si; } } return 0; }

回到 do_find_service()函数中,若指定 service能找到,则返回 si->ptr。由上面 addService()的流程可知,这个si->ptr就是 handle(对应于内核中的 desc)。

在 svcmgr_handler中在找到的情况下, 接着调用 bio_put_ref()函数来进一步处理,如下:void bio_put_ref(struct binder_io *bio, void *ptr) { struct binder_object *obj;

if (ptr) obj = bio_alloc_obj(bio); else obj = bio_alloc(bio, sizeof(*obj));

if (!obj) return;

// 走这里 obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; obj->type = BINDER_TYPE_HANDLE; obj->pointer = ptr; obj->cookie = 0; }其中 bio_alloc_obj()函数及其相关函数定义如下:static void *bio_alloc(struct binder_io *bio, uint32_t size) { size = (size + 3) & (~3); if (size > bio->data_avail) { bio->flags |= BIO_F_OVERFLOW; return 0; } else { void *ptr = bio->data; bio->data += size; bio->data_avail -= size; return ptr; } }static struct binder_object *bio_alloc_obj(struct binder_io *bio) { struct binder_object *obj;

obj = bio_alloc(bio, sizeof(*obj)); // 此时 obj指向数据域起始地址 if (obj && bio->offs_avail) { bio->offs_avail--; *bio->offs++ = ((char*) obj) - ((char*) bio->data0); // 更新存放对象偏移的数组元素 return obj; } bio->flags |= BIO_F_OVERFLOW; return 0; }

然后回到上层的 binder_parse()函数,继续执行 binder_send_reply()函数以将结果返回给 client,流程也差不多,主要是现在多传送了一个 binder_object “对象而已,和 checkService()未找到流程”中不同的部分在于checkService()函数中的最后一条语句: return reply.readStrongBinder();现在来看 readStrongBinder()函数做了什么事情: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: // 在 ServiceManager中设置的是 BINDER_TYPE_HANDLE,走这里 *out = proc->getStrongProxyForHandle(flat->handle); return finish_unflatten_binder( static_cast<BpBinder*>(out->get()), *flat, in); } }

Page 73: Android 进程间通信机制(Binder)介绍

return BAD_TYPE; }看下 readObject()这个函数是什么:const flat_binder_object* Parcel::readObject(bool nullMetaData) const { const size_t DPOS = mDataPos; if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) { // 将 struct binder_object指针强制转换为 flat_binder_object指针(两者结构类似,故转换可进行) const flat_binder_object* obj = reinterpret_cast<const flat_binder_object*>(mData+DPOS); // 更新 mDataPos的位置 mDataPos = DPOS + sizeof(flat_binder_object); if (!nullMetaData && (obj->cookie == NULL && obj->binder == NULL)) { // When transferring a NULL object, we don't write it into // the object list, so we don't want to check for it when // reading. LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos); return obj; } // Ensure that this object is valid... size_t* const OBJS = mObjects; const size_t N = mObjectsSize; size_t opos = mNextObjectHint; // mNextObjectHint成员作为下一次读取对象的位置的一种暗示 if (N > 0) { // 走这里 LOGV("Parcel %p looking for obj at %d, hint=%d\n", this, DPOS, opos); // Start at the current hint position, looking for an object at // the current data position. if (opos < N) { // 暗示位置还靠谱(在数组的合法范围内),从当前位置往后找找 while (opos < (N-1) && OBJS[opos] < DPOS) { opos++; } } else { // 超出了数组范围,将之设置为数组的最后位置处 opos = N-1; } if (OBJS[opos] == DPOS) { // Found it! 找到了 LOGV("Parcel found obj %d at index %d with forward search", this, DPOS, opos); mNextObjectHint = opos+1; LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos); return obj; } // 从当前位置往后找木找到,往前看看 // Look backwards for it... while (opos > 0 && OBJS[opos] > DPOS) { opos--; } if (OBJS[opos] == DPOS) { // Found it! 找到了 LOGV("Parcel found obj %d at index %d with backward search", this, DPOS, opos); mNextObjectHint = opos+1; LOGV("readObject Setting data pos of %p to %d\n", this, mDataPos); return obj; } } LOGW( "Attempt to read object from Parcel %p at offset %d that is not in the object list", this, DPOS); } return NULL; }

继续回到 unflatten_binder()函数中,走 BINDER_TYPE_HANDLE: *out = proc->getStrongProxyForHandle(flat->handle); 看到 getStrongProxyForHandle()熟悉了不,对了,我们就是通过它来获得系统服务管家 ServiceManager的,当然这里传入的参数肯定不能再为 0了,具体流程可参照上面的介绍。下面执行如下语句: return finish_unflatten_binder( static_cast<BpBinder*>(out->get()), *flat, in); 上面的这个 finish_unflatten_binder()函数仅仅是返回了一个 NO_ERROR,其余神马都没做。

到这里,我们已经获得了 DxyhService服务了,就如同我们获得了 sp<IServiceManager>一样,然后你就可以使用IDxyhService类中的函数了。在使用时,在 binder_transaction()驱动函数中挑选目标进程(service进程)中的工作线程(假如有的话,若没有,则全部由主线程去做),然后在 binder_thread_read()函数中,我们看到也是会优先处理工作线程中的任务(两个 list_empty(&xxx->todo)判断先判断的是 thread的)。

Page 74: Android 进程间通信机制(Binder)介绍

附录一 示例源码:

===============================================================>>> Android.mk===============================================================############################################################################ # For libdxyhservice.so ############################################################################ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS)

LOCAL_MODULE:= libdxyhservice LOCAL_MODULE_TAGS:= optional

DEBUG_INCLUDE:=~/CommonLib/AndroidUtil/CPlusPlusUtil DXYHBINDER_INCLUDE:=~/MyFolder/ans/packages/apps/bitest/include LOCAL_C_INCLUDES+= \ $(DEBUG_INCLUDE) $(DXYHBINDER_INCLUDE)

LOCAL_SRC_FILES:= \ libdxyhservice/IDxyhService.cpp

LOCAL_PRELINK_MODULE := false

LOCAL_SHARED_LIBRARIES:= libutils libcutils libbinder include $(BUILD_SHARED_LIBRARY)

############################################################################ # For dxyh_service ############################################################################ include $(CLEAR_VARS)

LOCAL_MODULE:= dxyh_service LOCAL_MODULE_TAGS:= optional

DEBUG_INCLUDE:=~/CommonLib/AndroidUtil/CPlusPlusUtil DXYHBINDER_INCLUDE:=~/MyFolder/ans/packages/apps/bitest/include LOCAL_C_INCLUDES+= \ $(DEBUG_INCLUDE) $(DXYHBINDER_INCLUDE)

LOCAL_SRC_FILES:= \ dxyhservice/DxyhService.cpp \ dxyhservice/main_dxyhservice.cpp

LOCAL_PRELINK_MODULE := false

LOCAL_SHARED_LIBRARIES:= libutils libcutils libbinder libdxyhservice include $(BUILD_EXECUTABLE)

############################################################################ # For dxyh_client ############################################################################ include $(CLEAR_VARS)

LOCAL_MODULE:= dxyh_client LOCAL_MODULE_TAGS:= optional

DEBUG_INCLUDE:=~/CommonLib/AndroidUtil/CPlusPlusUtil DXYHBINDER_INCLUDE:=~/MyFolder/ans/packages/apps/bitest/include LOCAL_C_INCLUDES+= \ $(DEBUG_INCLUDE) $(DXYHBINDER_INCLUDE)

LOCAL_SRC_FILES:= \ dxyhclient/DxyhClient.cpp

LOCAL_PRELINK_MODULE := false

LOCAL_SHARED_LIBRARIES:= libutils libcutils libbinder libdxyhservice include $(BUILD_EXECUTABLE) ===============================================================

===============================================================>>> include/IDxyhService.h===============================================================#ifndef _IDXYHSERVICE_H_ #define _IDXYHSERVICE_H_

#include <utils/Errors.h> // for status_t #include <utils/RefBase.h> #include <binder/IInterface.h> #include <binder/Parcel.h>

namespace android {

Page 75: Android 进程间通信机制(Binder)介绍

class IDxyhService: public IInterface { public: DECLARE_META_INTERFACE(DxyhService);

// declare what this service can do virtual status_t setUserName(const String16& name) = 0; virtual status_t setUserAge(uint32_t age) = 0;

virtual String16 getUserName() const = 0; virtual uint32_t getUserAge() const = 0;

enum { GET_USERNAME_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, GET_USERAGE_TRANSACTION, SET_USERNAME_TRANSACTION, SET_USERAGE_TRANSACTION, }; };

// ----------------------------------------------------------------------------

class BnDxyhService: public BnInterface<IDxyhService> { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel *reply, uint32_t flags = 0); };

};

#endif /* end of _IDXYHSERVICE_H_ */ ===============================================================

===============================================================>>> libdxyhservice/IDxyhService.cpp===============================================================#include <binder/IServiceManager.h> #include <binder/IPCThreadState.h> #include <binder/Parcel.h>

#include <utils/String8.h>

#include "IDxyhService.h"

namespace android {

// ----------------------------------------------------------------------

class BpDxyhService : public BpInterface<IDxyhService> { public: BpDxyhService(const sp<IBinder> &impl) : BpInterface<IDxyhService>(impl) { }

virtual status_t setUserName(const String16& name) { Parcel data, reply; data.writeInterfaceToken(IDxyhService::getInterfaceDescriptor()); data.writeString16(name); remote()->transact(SET_USERNAME_TRANSACTION, data, &reply); return reply.readInt32(); }

virtual status_t setUserAge(uint32_t age) { Parcel data, reply; data.writeInterfaceToken(IDxyhService::getInterfaceDescriptor()); data.writeInt32(age); remote()->transact(SET_USERAGE_TRANSACTION, data, &reply); return reply.readInt32(); }

virtual String16 getUserName() const { Parcel data, reply; data.writeInterfaceToken(IDxyhService::getInterfaceDescriptor()); remote()->transact(GET_USERNAME_TRANSACTION, data, &reply); return reply.readString16(); }

virtual uint32_t getUserAge() const

Page 76: Android 进程间通信机制(Binder)介绍

{ Parcel data, reply; data.writeInterfaceToken(IDxyhService::getInterfaceDescriptor()); remote()->transact(GET_USERAGE_TRANSACTION, data, &reply); return reply.readInt32(); } };

IMPLEMENT_META_INTERFACE(DxyhService, "android.os.IDxyhService");

// ----------------------------------------------------------------------

String16 dxyhServiceID("android.os.IDxyhService");

status_t BnDxyhService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { String16 interfaceDescriptorName; uint32_t strictPolicy;

strictPolicy = data.readInt32(); interfaceDescriptorName = data.readString16(); if (interfaceDescriptorName != dxyhServiceID) { fprintf(stderr, "invalid id %s\n", String8(interfaceDescriptorName).string()); return(-1); }

switch (code) { case GET_USERNAME_TRANSACTION: return(reply->writeString16(getUserName())); case GET_USERAGE_TRANSACTION: return(reply->writeInt32(getUserAge())); case SET_USERNAME_TRANSACTION: setUserName(data.readString16()); return(reply->writeInt32(NO_ERROR)); case SET_USERAGE_TRANSACTION: setUserAge(data.readInt32()); return(reply->writeInt32(NO_ERROR)); default: return(BBinder::onTransact(code, data, reply, flags)); } }

}; ===============================================================

===============================================================>>> dxyhservice/DxyhService.h===============================================================#ifndef _DXYHSERVICE_H_ #define _DXYHSERVICE_H_

#include "IDxyhService.h"

namespace android {

class DxyhService : public BnDxyhService { public: DxyhService(); virtual status_t setUserName(const String16& name); virtual status_t setUserAge(uint32_t age);

virtual String16 getUserName() const; virtual uint32_t getUserAge() const;

private: String16 mName; uint32_t mAge; };

};

#endif /* end of _DXYHSERVICE_H_ */ ===============================================================

===============================================================>>> dxyhservice/DxyhService.cpp===============================================================#include "DxyhService.h"

namespace android {

DxyhService::DxyhService()

Page 77: Android 进程间通信机制(Binder)介绍

{}

status_t DxyhService::setUserName(const String16& name){ mName = name; return(NO_ERROR);}

status_t DxyhService::setUserAge(uint32_t age){ mAge = age; return(NO_ERROR);}

String16 DxyhService::getUserName() const{ return(mName);}

uint32_t DxyhService::getUserAge() const{ return(mAge);}

};===============================================================

===============================================================>>> dxyhservice/main_dxyhservice.cpp===============================================================#include <binder/IPCThreadState.h>#include <binder/ProcessState.h>#include <binder/IServiceManager.h>#include <utils/Log.h>

#include "DxyhService.h"

using namespace android;

int main(int argc, char **argv){ sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); sm->addService(String16("service.dxyh"), new DxyhService()); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); return(0);}===============================================================

===============================================================>>> dxyhclient/DxyhClient.cpp===============================================================#include <binder/IServiceManager.h>#include <utils/TextOutput.h>

#include "IDxyhService.h"

using namespace android;

int main(int argc, char **argv){ sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder = sm->getService(String16("service.dxyh")); if (binder == NULL) { aout << "service.dxyh cannot found!" << endl; return(-1); } sp<IDxyhService> dxyhService = interface_cast<IDxyhService>(binder); dxyhService->setUserName(String16("dengxiayehu")); dxyhService->setUserAge(99); aout << "UserName: " << dxyhService->getUserName() << endl; aout << "UserAge : " << dxyhService->getUserAge() << endl; return(0);}===============================================================

一个 Android.mk可以生成 libdxyhservice.so、dxyh_service、dxyh_client,先将.so推入到机器/system/lib下,然后在机器中先执行 dxyh_service、最后是 dxyh_client,出现如下结果就算成功了:UserName: dengxiayehuUserAge : 99

附录 二 简易调试函数:

Page 78: Android 进程间通信机制(Binder)介绍

在看流程时一般需要打印一些调试信息,也是一般最先想到的就是用宏,例如:===============================================================>>> xdebug.h===============================================================#ifndef _XDEBUG_H_ #define _XDEBUG_H_

#ifdef DXYH_DEBUG #include <stdio.h> #include <stdarg.h> #include <limits.h> // PATH_MAX(4096)

#undef LOG_NDDEBUG #define LOG_NDDEBUG 0 #include <cutils/log.h>

#undef MAXLINE #define MAXLINE 2048

static char __buff[PATH_MAX]; // global buff for __basename static char __line[MAXLINE];

static const char *__basename(const char *filename) { const char *p = NULL; strncpy(__buff, filename, sizeof(__buff)); return(NULL == (p = strrchr(__buff, '/')) ? filename : (p + 1)); }

static const char *msgHandle(const char *filename, const char *func, int lineno, const char *fmt, ...) { va_list ap; int n; n = snprintf(__line, sizeof(__line),\ "%s %s(%d): ", filename, func, lineno); va_start(ap, fmt); vsnprintf(__line + n, sizeof(__line) - n, fmt, ap); va_end(ap); return(__line); }

static const char *removeTrailingCRs(char str[]) { if (!str) { return(0); } else { int len = strlen(str); while (len > 0 && '\n' == str[len - 1]) { str[len-- - 1] = '\0'; } return(str); } }

#define PDEBUG(fmt, ...) \ do { \ printf("%s", msgHandle(__basename(__FILE__), __FUNCTION__, __LINE__, \ fmt, ##__VA_ARGS__)); \ fflush(stdout); \ } while (0)

#define ADEBUG(fmt, ...) \ do { \ msgHandle(__basename(__FILE__), __FUNCTION__, __LINE__,\ fmt, ##__VA_ARGS__); \ LOG(LOG_DEBUG, DXYH_LOG_TAG, "%s", removeTrailingCRs(__line)); \ } while (0)

#define PADEBUG(fmt, ...) \ do { \ PDEBUG(fmt, ##__VA_ARGS__); \ ADEBUG(fmt, ##__VA_ARGS__); \ } while (0) #else #define PDEBUG(fmt, ...) #define ADEBUG(fmt, ...) #define PADEBUG(fmt, ...) #endif

#endif /* end of _XDEBUG_H_ */ ===============================================================

可以将其保存为 xdebug.h,然后在 Android.mk中加入如下内容:

Page 79: Android 进程间通信机制(Binder)介绍

LOCAL_SHARED_LIBRARIES := liblog libcutils libutils #> LOCAL_C_INCLUDES+=\ ~/CommonLib/AndroidUtil/CPlusPlusUtil # 执行存放 xdebug.h文件夹路径####################################

然后在源文件中可以类似于如下使用:1)包含 xdebug头文件//> #define DXYH_DEBUG // 调试开关,不需调试时将其注释掉即可#define DXYH_LOG_TAG "YourLogTAG" // log TAG#include <xdebug.h> //--------------------------------------2)打印PADEBUG("Your debug %s\n", "info");

当然在调试内核时,上面这个 xdebug.h是不能工作的,你可以将其中的 printf()换成 printk(),然后再调整下,kdebug.h内容也差不多,不贴了。

附录三 源码查看工具:

在查看源码时,可选的工具很多,例如 source insight就不错,但是对于庞大的 Android源码来就有点太...,推荐一下“ ” “ ”我的 工具 。(当然,这是 萝卜白菜,各有所爱 的问题)

边看,边编辑,用的是 vim;源码之间的跳转,用 ctags;符号的查看用 cscope。有用的 vim插件:1)MiniBuf —— 方便在多个文件中切换2)Taglist —— 显示当前源文件中的函数、全局变量、类、结构体等等的概览3)ConqueTerm —— 在 vim中就可以使用终端4)SnipMate —— 自动生成源码片段(上面的//> ... //----等等用于标记的都是其自动生成的)5)manpageview —— 在 vim中显示 man帮助文档(在 gvim中特别有效,默认的 K命令可能会产生转义符号错乱)6)NERD_commenter —— 自动注释工具(特别方便)……

附录四 Slient Acceleration:

在 Android源码中编写程序,一般是先进入根目录,然后就是 source ../build/envsetup.sh,然后就是无休止的cd命令,目录切换来切换去的。最头疼的就是回退目录,退到父目录还好,但若是回退多层,那就是 cd ../../../...。

……一般我们是打开多个终端,然后就是不同终端之间的切换

那有神马办法可以稍微改善一点这种情况呢?对了,就是写写 bash脚本,以及一些 alias,这里介绍一下我常用的脚本及命令,不吝指正。

大概有以下几个文件,分别为:~/.bash_alias.sh、~/.g_util.sh、Android根目录/util.sh===============================================================>>> ~/.bash_aliash.sh说明:可能原本系统就自带,那就直接在里面添加相应内容即可。这个文件里面放全局的 alias命令,bash启动时会自动读取之。===============================================================#--------------------------------- # "android" about stuff #--------------------------------- alias ak='sudo adb kill-server' alias as='sudo adb start-server' alias ash='adb shell' alias ar='sudo adb remount' alias ai='adb install' alias air='adb install -r' alias apush='adb push' alias apull='adb pull' alias auni='adb uninstall' alias logcat='adb shell logcat'

#--------------------------------- # for safety #--------------------------------- alias cp='cp -i' alias rm='rm -i'

#--------------------------------- # convinience aliases #--------------------------------- alias ll='ls -alF' alias la='ls -A' alias l='ls -CF'

alias cls='clear'

alias vi='vim' alias i='vim'

# 回退到父目录直接 .. 就可以了

Page 80: Android 进程间通信机制(Binder)介绍

alias ..='cd ..' ===============================================================

===============================================================>>> ~/.g_util.sh说明:全局功能函数定义===============================================================#!/bin/bash# g_util.sh# global util for convinience

# Yes, global variables, need improving.__CFG__="F_BLACK"__CBG__="B_WHITE"

# +--------------------------------+# | Function definition |# +--------------------------------+# Change terminal's color-set.# Usage: textattr <fgcolor> <bgcolor># 这个函数是仿 TC中的 textattr()函数的,定义字符前/背景色,用于提示信息function textattr() {

if [ $# -lt 2 ]; thenreturn 1

filocal _fgcolor=30local _bgcolor=49local _parse_error=0# get fgcolorcase "$1" in"F_BLACK") _fgcolor=30; __CFG__="F_BLACK" ;;"F_RED") _fgcolor=31; __CFG__="F_RED" ;;"F_GREEN") _fgcolor=32; __CFG__="F_GREEN" ;;"F_YELLOW") _fgcolor=33; __CFG__="F_YELLOW" ;;"F_BLUE") _fgcolor=34; __CFG__="F_BLUE" ;;"F_MAGENTA") _fgcolor=35; __CFG__="F_MAGENTA";;"F_CYAN") _fgcolor=36; __CFG__="F_CYAN" ;;"F_GRAY"|\"F_WHITE") _fgcolor=37; __CFG__="F_WHITE" ;;*) _parse_error=1;;

esacif [ "$_parse_error" -ne 0 ]; thenreturn 1

fi# get bgcolorcase "$2" in"B_BLACK") _bgcolor=40; __CBG__="B_BLACK" ;;"B_RED") _bgcolor=41; __CBG__="B_RED" ;;"B_GREEN") _bgcolor=42; __CBG__="B_GREEN" ;;"B_YELLOW") _bgcolor=43; __CBG__="B_YELLOW" ;;"B_BLUE") _bgcolor=44; __CBG__="B_BLUE" ;;"B_MAGENTA") _bgcolor=45; __CBG__="B_MAGENTA";;"B_CYAN") _bgcolor=46; __CBG__="B_CYAN" ;;"B_GRAY") _bgcolor=47; __CBG__="B_GRAY" ;;"B_WHITE") _bgcolor=49; __CBG__="B_WHITE" ;;*) _parse_error=1;;

esacif [ "$_parse_error" -ne 0 ]; thenreturn 1

fiecho -n -e "\033[${_fgcolor};${_bgcolor}m"

}

# Output error msg with color "WHITE on RED"(For convinience).# Usage: err_msg [msg]# 白底红字,表示错误function err_msg() {

local ___CFG___bak=$__CFG__local ___CBG___bak=$__CBG__textattr F_RED B_WHITEecho "$@"textattr $___CFG___bak $___CBG___bak

}

# wrapped cd# 用于 alias 的函数,以后可使用例如 "c 5.." 回退 5级目录等等function w_cd() { if [ $# -lt 1 ]; then cd else local _dest_dir= if `echo $1 | grep -q -E '^[0-9]?\.\.$' 2>/dev/null`; then local _n= _n=${1%%\.*} _dest_dir=".."

Page 81: Android 进程间通信机制(Binder)介绍

if [ -n "$_n" ]; then while [ "$_n" -gt 1 ] do _dest_dir=$_dest_dir/.. _n=`expr $_n - 1` done fi cd $_dest_dir else cd "$@" fi fi}

# tee log: view the log as well as dump it to a file# usage: tl <log-file> [whether-empty-log]# 查看 log时将之同时导入到指定文件,第 2个参数表示查看 log时是否先清空机器中 logcat的缓存function tl() { if [ $# -lt 1 ]; then err_msg "E/$FUNCNAME($LINENO): "\ "usage: tl <log-file> [whether-empty-log]" return 1 fi if [ $# -gt 1 ]; then if [ $2 = "1" -o $2 = "y" -o $2 = "Y" ]; then adb shell logcat -c else err_msg "E/$FUNCNAME($LINENO): "\ "usage: tl <log-file> [1|y]" return 1 fi fi local _log_file="$1" adb logcat | tee "$_log_file"}

# gs: grep certain string in specified dir# usage: gs '<str>' [dir]"# grep的封装function gs() { if [ $# -lt 1 ]; then err_msg "E/$FUNCNAME($LINENO): "\ "usage: gs <str> [dir]" return 1 fi local _str="$1" local _dir="." if [ $# -gt 1 ]; then _dir="$2" if [ ! -d "$_dir" ]; then err_msg "E/$FUNCNAME($LINENO): "\ "dir \"$_dir\" doesn't exist" return 1 fi fi # call grep -E to search certain string grep -E "$_str" "$_dir" -R -n return $?}

# find certail file in specified dir(s)# usage: ff '<filename>' [[dir1] [dir2] ... [dirn]]# find的封装,查找指定目录中是否包含文件(默认从当前目录开始找起)function ff() { if [ $# -lt 1 ]; then err_msg "E/$FUNCNAME($LINENO): "\ "usage: ff <filename> [[dir1] [dir2] ... [dirn]]" return 1 fi local _filename="$1" # get dest dir list local _tmpdir="." if [ $# -eq 1 ]; then # call find cmd to search the file find "$_tmpdir" -name "$_filename" return 0 fi shift while [ $# -gt 0 ] do _tmpdir=$1 if [ ! -d "$_tmpdir" ]; then err_msg "E/$FUNCNAME($LINENO): "\ "dir \"$_tmpdir\" doesn't exist" return 1

Page 82: Android 进程间通信机制(Binder)介绍

fi find "$_tmpdir" -name "$_filename" shift done return 0}

# find all source files in current dir,# you can also specify the subdirs you do NOT want to include.# usage: fsrc [dir1_not_included] [dir2_not_included] ...# 查找指定后缀名称的文件(例如.c、.cpp),一般用于生成 cscope数据库的文件列表文件function fsrc() { local _pwd=`pwd` local _dir="" local _item _j _found _under_cur_dir=1 _len=0 declare -a _dirs2ignore

while [ $# -gt 0 ] do # if [ $_len -eq 0 ]; then # # show the 'README' # # echo "Remember: params are the dirs which will NOT be included." # : # fi # check the param(s) if [ ! -d "$1" ]; then err_msg "E/$FUNCNAME($LINENO): "\ "dir \"$1\" doesn't exist" return 1 fi if [ "$1" = '.' ]; then # err_msg "Warning: files in current dir will be ignored." _under_cur_dir=0 fi # add ignored dirs to array _dirs2ignore[((_len++))]="$1" shift done for _item in `ls` do if [ -d "$_item" ]; then # handle dir _j=0 _found=0 # to see whether this dir is in the ignore list while [ $_j -lt $_len ] do if [ "${_dirs2ignore[$_j]}" = "$_item" ]; then _found=1 break fi ((_j++)) done if [ $_found -eq 0 ]; then _dir="$_pwd/$_item" # use the wrapped cmd 'find' find "$_dir" \ -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o \ -name '*.h' -o -name '*.java' -o -name '*.cxx' -o \ -name '*.hxx' fi else if [ $_under_cur_dir -eq 1 ]; then # handle file local _file_suffix=${_item##*.} if [ $_file_suffix = 'c' ] || [ $_file_suffix = 'cc' ] || [ $_file_suffix = 'cpp' ] || [ $_file_suffix = 'h' ] || [ $_file_suffix = 'java' ] || [ $_file_suffix = 'cxx' ] || [ $_file_suffix = 'hxx' ]; then # avoid certain files such as "c" "cc" ... if [ "$_file_suffix" != "$_item" ]; then echo "$_pwd"/"$_item" fi fi fi fi done}

# create_anr_tags: create the tags for android project# usage: create_anr_tags <ans|ics># 用于在 external、hardware等等目录下创建 tags 文件,当然你也可以直接在源码根目录下执行 ctags -R,但是生

Page 83: Android 进程间通信机制(Binder)介绍

# 成的 tags文件会很大,你用 ctrl+]跳转时慢的有点接受不了# 注:这个函数需要你自己的定制化,比如说 Android源码根目录路径,以及参数名称。function create_anr_tags() { if [ $# -ne 1 ]; then err_msg "E/$FUNCNAME($LINENO): "\ "usage: create_anr_tags <ans|ics>" return 1 fi

local _anr="" if [ "$1" = "ans" ]; then # 下面你可能需要自己改一下,将_anr设置为你 Android源码根目录 _anr="~/MyFolder/ans" # 我这里有两个参数是因为一个是 2.3的源码,另一个是 ics4.0的, elif [ "$1" = "ics" ]; then # 自定义一下啦 _anr="~/ics" else err_msg "E/$FUNCNAME($LINENO): "\ "usage: create_anr_tags <ans|ics>" return 1 fi local _dir _pwd _subdirs="\ external \ hardware \ packages \ bionic \ frameworks \ libcore \ bootable \ system" # save current working directory _pwd=`pwd` for _dir in $_subdirs do local _tmp_dir="$_anr"/"$_dir" echo "Enter $_tmp_dir, creating.." cd "$_tmp_dir" > /dev/null 2>&1 if [ $? -ne 0 ]; then err_msg "E/$FUNCNAME($LINENO): "\ "$_tmp_dir doesn't exist." return 1 fi ctags -R --languages=C++,C,Java done # restore where we were cd "$_pwd"}

# some aliasalias fsrc='fsrc 2>&1'alias c='w_cd'===============================================================说明:1、要使以上两个文件中的内容有效,你还需在~/.bashrc文件中添加如下内容(可将其加在该文件最后):source ~/.bash_aliasessource ~/.g_util.sh2、上面的 create_anr_tags()函数会生成很多的 tags文件,然后在.vimrc中使用 set tags+=tags文件路径即可,当然,若是嫌麻烦,可用 vim脚本帮忙。

===============================================================>>> Android根目录/util.sh说明:1、请将该文件放到 Android根目录下,并且将开头的 ANR_PATH变量的值设置为正确的 Android源码根目录路径;2、不保证在你的机器上能有效工作,可能需要 fix ……一些小错误===============================================================#!/bin/bash# util.sh

# +--------------------------------+# | Global variables |# +--------------------------------+# Your root-path of android project.ANR_PATH="/home/xxx/MyFolder/ans" # 改成你自己的 Android源码根目录!# Error codes:E_BADARGS=65E_FILE_NOT_FOUND=66E_BAD_DEST_DIR=67E_DEL_FILE=68RETURN_SUCCESS=0RETURN_FAILURE=1

# JUMP_TABLE: set your "jumps" below.# 跳转表,4部分分别为:标签、目标路径、标签是否大小写敏感、跳转到该目录后执行的命令# 例如:你执行 j b 时就会跳转到源码根目录,同时会用 ls显示一下# 这里你可以自行添加,但务必保持格式一致,不然下面的 jump()函数解析可能会出错JUMP_TABLE="[oapp#$ANR_PATH/out/debug/target/product/generic/system/app#0#NA]\

Page 84: Android 进程间通信机制(Binder)介绍

[olib#$ANR_PATH/out/debug/target/product/generic/system/lib#0#NA]\[obin#$ANR_PATH/out/debug/target/product/generic/system/bin#0#NA]\[ojar#$ANR_PATH/out/debug/target/product/generic/system/framework#0#NA]\[app#$ANR_PATH/packages/apps#0#ls]\[b#$ANR_PATH#0#ls]\[log#~/LOG#0#NA]\[libbinder#$ANR_PATH/frameworks/base/libs/binder#0#ls]"

# +--------------------------------+# | util functions |# +--------------------------------+# Output string, sth like printf.# Usage: cprintf <fgcolor> <bgcolor> [[fmt] [[val1] [val2] [val3] ...]]# ToKnow: For good looking, please do NOT print string in multi-lines.# 也是仿得 TC中的 cprintf() “ ”函数,注意: 美观 起见,最好不要多行显示function cprintf() { if [ $# -lt 2 ]; then err_msg "E/$FUNCNAME($LINENO): "\ "Usage: cprintf <fgcolor> <bgcolor>" return 1 fi local ___CFG___bak=$__CFG__ local ___CBG___bak=$__CBG__ textattr $1 $2 if [ $? -ne 0 ]; then err_msg "E/$FUNCNAME($LINENO): "\ "Usage: cprintf <fgcolor> <bgcolor>" return 1 fi shift 2 local _original_fmt="$1" local _fmt=${_original_fmt%%\\n*} shift local _retval=0 printf "$_fmt" "$@" 2>/dev/null || _retval=1 textattr $___CFG___bak $___CBG___bak if [ $_retval -ne 0 ]; then err_msg "E/$FUNCNAME($LINENO): "\ "Usage: cprintf <fg> <bg> [fmt val1 val2 ...]" return 1 fi local _lines=`expr \( ${#_original_fmt} - ${#_fmt} \) / 2` while [ $_lines -gt 0 ] do echo "" _lines=`expr $_lines - 1` done}

# cp2pad: copy file form pc to pad.# usage: cp2pad <file> <dest># 将文件拷贝到机器中的指定路径function cp2pad() {

if [ $# -lt 2 ]; thenerr_msg "E/$FUNCNAME($LINENO): "\

"usage: cp2pad <file> <dest> [override]"return $E_BADARGS

filocal _file="$1"local _dest="$2"if [ ! -f "$_file" ]; thenerr_msg "E/$FUNCNAME($LINENO): "\

"file \"$_file\" doesn't exist."return $E_FILE_NOT_FOUND

fiadb push "$_file" "$_dest" 2>&1 \| grep 'failed to copy.*Read-only.*' > /dev/null 2>&1if [ $? -eq 0 ]; thenecho "Need to do \"adb remount\"."adb remountsleep 0.2adb push "$_file" "$_dest"

fireturn $RETURN_SUCCESS

}

# +--------------------------------+# | Function definition |# +--------------------------------+# envsetup: setup compiling environment.# Usage: envsetup# 我们常使用的 source build/envsetup.sh命令的包装function envsetup() {

if [ ! -f "$ANR_PATH/build/envsetup.sh" ]; then

Page 85: Android 进程间通信机制(Binder)介绍

err_msg "E/$FUNCNAME($LINENO): "\"$ANR_PATH/build/envsetup.sh not found!"

return $E_FILE_NOT_FOUNDfiif ! `declare -F 'mm' > /dev/null 2>&1`; thencprintf F_BLACK B_WHITE "Sourcing $ANR_PATH/build/envsetup.sh"source $ANR_PATH/build/envsetup.sh > /dev/null 2>&1if [ $? -ne 0 ]; then

err_msg " ---> Failed."return $RETURN_FAILURE

elsecprintf F_GREEN B_WHITE " ---> Ok.\n"

fifi

}

# Jump between dirs.# Usage: j <dest-dir [subdir1] [subdir2] ... ># 大致说下这个函数的处理流程:# 1 、优先判定是否是 n.. 类型(n为数字),若是,则执行和 w_cd一样的动作;# 2、j - 效果和 cd - 效果相同;# 3 、根据 dest-dir 参数查找跳转表(若标签重复,就需自行选择),若匹配则记下跳转目标及所需执行的命令# 4、若目标路径是在 packages/apps/xxx 目录下(xxx为项目路径),则判定是否有第 2个参数,若有,则进一步判断:# a、若参数 2 为 src ,则尽可能往 xxx/src子目录下走,可能一直跳转到源码位置处(中途出现多个子目录时停止)# b、若参数为 res、drawable、layout、raw...等时,进行相应跳转# 5、执行跳转# 6、执行命令(可以执行多个命令,以分号分割)function j() {

if [ $# -lt 1 ]; thenerr_msg "E/$FUNCNAME($LINENO): "\

"Usage: j <dest-dir>"return $E_BADARGS

filocal _dest_dir=if `echo $1 | grep -q -E '^[0-9]?\.\.$' 2>/dev/null`; thenlocal _n=_n=${1%%\.*}_dest_dir=".."if [ -n "$_n" ]; then

while [ "$_n" -gt 1 ]do

_dest_dir=$_dest_dir/.._n=`expr $_n - 1`

doneficd $_dest_dirif [ $? -ne 0 ]; then

err_msg "Change dir failed(1)." >&2return $RETURN_FAILURE

fireturn $RETURN_SUCCESS

elif [ $1 = "-" ]; thencd -if [ $? -ne 0 ]; then

err_msg "Change dir failed(2)." >&2return $RETURN_FAILURE

fireturn $RETURN_SUCCESS

filocal _param1="$1"local _param1_bak="$_param1"local _num=0declare -a _jump_labeldeclare -a _possible_resdeclare -a _possible_cmdlocal _tmp _i _j _flag=0 _jump_table="$JUMP_TABLE"while [ -n "$_jump_table" ]dolocal _item=$(echo $_jump_table | sed -e 's/^\[\([^]]*\)\].*/\1/g')_tmp=$(echo $_item | cut -d# -f1)_i=0while $(echo $_tmp | grep -q '|')do

_jump_label[$_i]=${_tmp%%|*}_tmp=${_tmp#*|}((_i++))

done_jump_label[((_i++))]=$_tmp_dest_dir=$(echo $_jump_table | cut -d# -f2)local _case_sensitive=$(echo $_jump_table | cut -d# -f3)local _cmd=$(echo $_jump_table | cut -d# -f4 | cut -d] -f1)_j=0while [ $_j -lt $_i ]do

Page 86: Android 进程间通信机制(Binder)介绍

if [ $_case_sensitive -eq 0 ]; then_jump_label[$_j]=$(echo ${_jump_label[$_j]} | tr 'A-Z' 'a-z')_param1=$(echo $_param1 | tr 'A-Z' 'a-z')

fiif [ "${_jump_label[$_j]}" = "$_param1" ]; then

_possible_res[$_num]="$_dest_dir"_possible_cmd[((_num++))]="$_cmd"

fi((_j++))

done_jump_table=${_jump_table#\[*\]}

doneif [ $_num -lt 1 ]; thencd "$_param1_bak" 2>/dev/nullif [ $? -ne 0 ]; then

# TODO: to see whether it is under packages/apps, if so, jump there for _tmp in `ls "$ANR_PATH/packages/apps/"` do if [ -d "$ANR_PATH/packages/apps/$_tmp" ] && \ [ $_param1_bak = $_tmp ]; then _flag=1 break fi done if [ $_flag -eq 0 ]; then unset_array_in_j err_msg "Invalid dest-dir(1)." >&2 return $RETURN_FAILURE fi

fi if [ $_flag -eq 0 ]; then unset_array_in_j return $RETURN_SUCCESS fi

fi if [ $_flag -ne 1 ]; then local _chosen=0 while [ $_num -gt 1 ] do _j=0 while [ $_j -lt $_num ] do cprintf F_BLACK B_WHITE "[%d] %s\n" $_j ${_possible_res[$_j]} ((_j++)) done cprintf F_BLACK B_WHITE \ "Please choose(0~$(expr $_num - 1), q-->quit): " read -n1 _chosen if [ "$_chosen" = 'q' ]; then echo "" unset_array_in_j return $RETURN_SUCCESS else _chosen=$(echo $_chosen | tr -d 'a-z') if [ -z "$_chosen" ] || \ [ "$_chosen" -gt $(expr $_num - 1) ]; then echo "" err_msg "Invalid item, please again(0~$(expr $_num - 1))." echo "" continue fi echo "" break fi done _dest_dir=${_possible_res[$_chosen]} else _dest_dir="$ANR_PATH/packages/apps/$_param1_bak" fi

if [ $# -gt 1 ]; then if $(echo "$_dest_dir" | grep -q '/packages/apps/'); then local _tmp_bak _subdir=$(echo $2 | tr 'A-Z' 'a-z') case "$_subdir" in "src") # go as far as possible _dest_dir=$_dest_dir/src while true do _j=0 for _tmp in `ls "$_dest_dir"` do if [ -d "$_dest_dir"/"$_tmp" ] && \ ! $(echo "$_tmp" | grep -q '\..*') ; then _tmp_bak="$_tmp" ((++_j))

Page 87: Android 进程间通信机制(Binder)介绍

fi done if [ $_j -ne 1 ]; then break fi _dest_dir="$_dest_dir/$_tmp_bak" done ;; "res") _dest_dir=$_dest_dir/res;; "drawable") _dest_dir=$_dest_dir/res/drawable;; "layout") _dest_dir=$_dest_dir/res/layout;; "raw") _dest_dir=$_dest_dir/res/raw;; "values") _dest_dir=$_dest_dir/res/values;; "xml") _dest_dir=$_dest_dir/res/xml;; *) err_msg "Invalid subdir \"$2\", ignore it and continue.." >&2 ;; esac else err_msg "Warning: param \"$2\" was ignored." >&2 fi

fi # echo "_dest_dir is: $_dest_dir"

cd "$_dest_dir" 2>/dev/nullif [ $? -ne 0 ]; thenerr_msg "Invalid dest-dir(2)." >&2

unset_array_in_jreturn $RETURN_FAILURE

fi_tmp="${_possible_cmd[$_chosen]}"_i=0while $(echo "$_tmp" | grep -q ';')do_possible_cmd[$_i]=${_tmp%%;*}_tmp=${_tmp#*;}((_i++))

done_possible_cmd[((_i++))]=$_tmp_j=0while [ $_j -lt $_i ]doif [ "${_possible_cmd[$_j]}" != "NA" ]; then

if [ $_i -gt 1 ]; thenecho -n "Do cmd($(expr $_j + 1)): "cprintf F_GREEN B_WHITE "${_possible_cmd[$_j]}\n"

fi if [ "${_possible_cmd[$_j]}" = "ls" ] || [ "${_possible_cmd[$_j]}" = "dir" ]; then ${_possible_cmd[$_j]} --color=auto else ${_possible_cmd[$_j]} fi

if [ $? -ne 0 ]; thenerr_msg "Do cmd: ${_possible_cmd[$_j]} failed." >&2

unset_array_in_jreturn $RETURN_FAILURE

fifi((++_j))

done unset_array_in_j}

# unset the array declared in function j# NOTE: this is a "inner" function, just called by jfunction unset_array_in_j() {

unset _jump_labelunset _possible_resunset _possible_cmd

}

# used for function j's completion# 用于 j 函数的补全,补全目标为:标签 + packages/apps下目录名# 之所以加上 packages/apps下目录名是方便我们在写 apk时的跳转function _j() { local _tmp _item _i=0 _jump_table="$JUMP_TABLE" declare -a _jump_label_all while [ -n "$_jump_table" ]

do_item=$(echo $_jump_table | sed -e 's/^\[\([^]]*\)\].*/\1/g')_tmp=$(echo $_item | cut -d# -f1)

_jump_label_all[((_i++))]=$_tmp _jump_table=${_jump_table#\[*\]} done # as well as the folders in packages/apps for _tmp in `ls "$ANR_PATH/packages/apps"`

Page 88: Android 进程间通信机制(Binder)介绍

do if [ -d "$ANR_PATH/packages/apps/$_tmp" ] && \ ! $(echo "$_tmp" | grep -q '\..*') ; then _jump_label_all[((_i++))]="$_tmp" fi done # set the completion items local _cur COMPREPLY=() _cur="${COMP_WORDS[COMP_CWORD]}" COMPREPLY=( $(compgen -W "${_jump_label_all[*]}" -- ${_cur}) )

unset _jump_label_all}complete -F _j j

# fresh dir, usually used when you want to rebuild the app.# Warning! Do NOT use this cmd when you are in project root dir,# otherwise you will have to rebuild the whole project, -_-!# usage: fresh_d [dir]# touch一下指定目录下的所有文件,若不在 packages/apps下执行该命令则会报出警告(不要在根目录下执行,否则# 悲剧了,下次源码可能会要重新编译)function fresh_d() {

local _dir="."if [ $# -eq 1 ]; then_dir="$1"if [ ! -d "$_dir" ]; then

err_msg "E/$FUNCNAME($LINENO): "\"$1 isn't a directory."

return $E_BADARGSfi

filocal _cur_path=$(pwd)local _top="$_cur_path"local _top_file="build/core/envsetup.mk"if [ ! -f "$_top/$_top_file" ]; thenlocal _cur_dir=$PWD_top=while [ \( ! \( -f $_top_file \) \) -a \( $PWD != "/" \) ]do

cd .. > /dev/null_top=$(PWD= pwd)

donecd $_cur_dir > /dev/null

filocal _chosen=local _warn=0if ! [ -z "$_top" -o "$_top" = "/" ]; thenlocal _tmp=${_cur_path#$_top}local _slash_num=$(echo $_tmp | tr '/' '\n' | wc -l)if [ $_slash_num -lt 4 ]; then

cprintf F_RED B_WHITE "Sure to fresh $_cur_path(y/n)? "read -n1 _chosenecho ""if [ $_chosen != 'y' ]; then

return $RETURN_SUCCESSfi_warn=1

fielsecprintf F_RED B_WHITE "Not in project subdir, sure(y/n)? "read -n1 _chosenecho ""if [ $_chosen != 'y' ]; then

return $RETURN_SUCCESSfi_warn=1

fiif [ $_warn -ne 0 ]; thencprintf F_RED B_WHITE "Confirm again, sure to fresh $_cur_path(y/n)? "read -n1 _chosenecho ""if [ $_chosen != 'y' ]; then

return $RETURN_SUCCESSfi

fifind "$_dir" -name \* -exec touch {} \;return $?

}

# start the emulator.# usage: start_emulator# TODO: add params specified.# 启动模拟器,这个需要自己定义了

Page 89: Android 进程间通信机制(Binder)介绍

function se() {local _emulator="$ANR_PATH/out/host/linux-x86/bin/emulator"# local _kernel="$ANR_PATH/prebuilt/android-arm/kernel/kernel-qemu"local _kernel="$ANR_PATH/kernel/arch/arm/boot/zImage"local _sysdir="$ANR_PATH/out/debug/target/product/generic/"local _system_img="$ANR_PATH/out/debug/target/product/generic/system.img"local _ramdisk_img="$ANR_PATH/out/debug/target/product/generic/ramdisk.img"local _userdata_img="$ANR_PATH/out/debug/target/product/generic/userdata.img"local _sdcard="$ANR_PATH/mysdcard.img"

$_emulator \-kernel $_kernel \-sysdir $_sysdir \-system $_system_img \-data $_userdata_img \-ramdisk $_ramdisk_img \-partition-size 512 \-sdcard $_sdcard \

-memory 512 \ -no-boot-anim \ -prop net.dns1=10.0.2.3 \

-bootchart 120}

# +--------------------------------+# | Temp acceleration actions |# +--------------------------------+# 关闭模拟器function ce() { if $(ps -ef | \ grep -v grep | grep -q "linux-x86/bin/emulator"); then killall emulator sleep 2 fi}

# NOTE: Please do NOT add the duplicated item into this list.# Acceleration target list# 常用命令的集合,主要是提供一个思路,具体就仁者见仁了# “ ”比如说我将一些常用的动作整合成一系列 命令# 注意:只是抛砖引玉,其中很多路径都是写死的,对你应该没有多大用处,但有参考价值ACCEL_TARGET_LIST="\ hello upbinder upkernal remake upsystem_img client service"# x: acceleration function# usage: x [target]function x() { if [ $# -lt 1 ]; then # no param passed # add your most commonly used here, temp is empty # well, give a tip echo "No param passed." elif [ "$1" = "hello" ]; then local _pwd=$PWD if [ "$_pwd" != "~/MyFolder/ans/packages/apps/Hello" ]; then j Hello fi if ! $(echo "$PWD" | grep -q '/packages/apps'); then err_msg "Not in \"packages/apps/..\", danger!" return $RETURN_FAILURE fi mm if [ $? -eq 0 ]; then cprintf F_GREEN B_WHITE "[Running hello..]\n" cd "$ANR_PATH"/out/debug/target/product/generic/system/bin cp2pad hello /system/bin sleep 0.2 adb shell /system/bin/hello cd "$_pwd" OLDPWD="~/MyFolder/ans/packages/apps/Hello" else cprintf F_RED B_WHITE "mm make failed -_-!\n" fi elif [ "$1" = "upbinder" ]; then # 重新编译 libbinder.so库,调试时这个动作很常做 local _pwd=`pwd` if [ "$_pwd" != "~/MyFolder/ans/packages/apps/Hello" ]; then j libbinder fi mm if [ $? -eq 0 ]; then cd "$ANR_PATH"/out/debug/target/product/generic/system/lib cp2pad libbinder.so /system/lib cd "$_pwd" OLDPWD="$ANR_PATH/frameworks/base/libs/binder" cprintf F_GREEN B_WHITE "Updating libbinder.so ok.\n" else

Page 90: Android 进程间通信机制(Binder)介绍

cprintf F_RED B_WHITE "mm make failed -_-!\n" fi elif [ "$1" = "upkernal" ]; then # 重新编译内核 #TODO: support multi-emulator handling local _pwd=`pwd` cd ~/MyFolder/ans/kernel/ make if [ $? -eq 0 ]; then if [ "$2" = "1" ]; then # restart the emulator if $(ps -ef | \ grep -v grep | grep -q "linux-x86/bin/emulator"); then killall emulator # not so scaring. sleep 2 se& sleep 2 else #TODO: Ask whether to start it? cprintf F_RED B_WHITE "emulator is not started.\n" return fi fi cd "$_pwd" else cprintf F_RED B_WHITE "make kernal failed -_-!\n" fi elif [ "$1" = "remake" ]; then # 整个系统重新 make一下 local _generic_dir="~/MyFolder/ans/out/debug/target/product/generic" rm -rf $_generic_dir/obj/EXECUTABLES/hello_intermediates rm -rf $_generic_dir/obj/EXECUTABLES/hello_intermediates/hello rm -rf $_generic_dir/obj/EXECUTABLES/hello_intermediates/LINKED/hello rm -rf $_generic_dir/symbols/system/bin/hello rm -rf $_generic_dir/system/bin/hello j Hello if [ -f "Android.mk" ]; then mv Android.mk Android.mk.bak fi j b if [ -f templ_folder/Android.mk ]; then mv templ_folder/Android.mk templ_folder/Android.mk.bak fi if [ $# -gt 1 ]; then # TODO: param check cprintf F_GREEN B_WHITE "make -j$2 ..\n" make -j$2 else cprintf F_GREEN B_WHITE "make -j8 ..\n" make -j8 fi if [ $? -eq 0 ]; then j Hello if [ -f "Android.mk.bak" ]; then mv Android.mk.bak Android.mk fi fi elif [ "$1" = "upsystem_img" ]; then # 更新一下 system.img镜像文件 local _generic_dir="~/MyFolder/ans/out/debug/target/product/generic" rm -rf $_generic_dir/obj/EXECUTABLES/hello_intermediates rm -rf $_generic_dir/obj/EXECUTABLES/hello_intermediates/hello rm -rf $_generic_dir/obj/EXECUTABLES/hello_intermediates/LINKED/hello rm -rf $_generic_dir/symbols/system/bin/hello rm -rf $_generic_dir/system/bin/hello ~/MyFolder/ans/out/host/linux-x86/bin/mkyaffs2image -f \ ~/MyFolder/ans/out/debug/target/product/generic/system \ ~/MyFolder/ans/out/debug/target/product/generic/xxx.img if [ $? -eq 0 ]; then ce mv ~/MyFolder/ans/out/debug/target/product/generic/xxx.img \ ~/MyFolder/ans/out/debug/target/product/generic/system.img sleep 1 se& fi elif [ "$1" = "client" ]; then # 编译并执行 dxyh_client(连带 libdxyhservice.so假如需要的话) local _pwd=$PWD if [ "$_pwd" != "~/MyFolder/ans/packages/apps/bitest/" ];then j bitest fi if ! $(echo "$PWD" | grep -q '/packages/apps'); then err_msg "Not in \"packages/apps/..\", danger!" return $RETURN_FAILURE fi mm if [ $? -eq 0 ]; then cprintf F_GREEN B_WHITE "[Running dxyh_client..]\n"

Page 91: Android 进程间通信机制(Binder)介绍

cd "$ANR_PATH"/out/debug/target/product/generic/system/bin cp2pad dxyh_client /system/bin if [ "$2" = "1" ]; then j olib cp2pad libdxyhservice.so /system/lib/ fi adb shell /system/bin/dxyh_client cd "$_pwd" OLDPWD="~/MyFolder/ans/packages/apps/bitest/" else cprintf F_RED B_WHITE "mm make failed -_-!\n" fi elif [ "$1" = "service" ]; then 编译并执行 dxyh_service(连带 libdxyhservice.so假如需要的话) local _pwd=$PWD if [ "$_pwd" != "~/MyFolder/ans/packages/apps/bitest/" ];then j bitest fi if ! $(echo "$PWD" | grep -q '/packages/apps'); then err_msg "Not in \"packages/apps/..\", danger!" return $RETURN_FAILURE fi mm if [ $? -eq 0 ]; then cprintf F_GREEN B_WHITE "[Running dxyh_service..]\n" cd "$ANR_PATH"/out/debug/target/product/generic/system/bin cp2pad dxyh_service /system/bin cd "$_pwd" OLDPWD="~/MyFolder/ans/packages/apps/bitest/" else cprintf F_RED B_WHITE "mm make failed -_-!\n" fi if $(adb shell ps | \ grep -v grep | grep -q "dxyh_service"); then adb shell busybox killall dxyh_service fi if [ "$2" = "1" ]; then j olib cp2pad libdxyhservice.so /system/lib/ fi adb shell /system/bin/dxyh_service& fi}# just for function x's completionfunction _x() { local _cur COMPREPLY=() _cur="${COMP_WORDS[COMP_CWORD]}" COMPREPLY=( $(compgen -W "$ACCEL_TARGET_LIST" -- ${_cur}) )}complete -F _x x

# +--------------------------------+# | Auto test movements |# +--------------------------------+# 自动测试脚本 ,大致思想是通过 sendevent 命令来模拟用户的操作。# sendevent: send key event manually {{{ # usage: sendevent <home|h|menu|m|back|b|pos|p> [<x-axis> <y-axis>] [press-time] function sendevent() {

if [ $# -lt 1 ]; then err_msg "E/$FUNCNAME($LINENO): "\

"Usage: sendevent <info>" return $E_BADARGS

fi local _input_dev_name="/dev/input/event2" # 这里需要自定义local _type=$(echo $1 | tr 'A-Z' 'a-z') local _sleep_time=0 if [ "$_type" = "home" -o "$_type" = "h" ]; then # 模拟 home事件if [ $# -gt 1 ]; then

_sleep_time="$2" if ! $(echo $_sleep_time | grep -q -E '[0-9][0-9.]*'); then

err_msg "E/$FUNCNAME($LINENO): "\ "Usage: sendevent <home|h> [<press-time>]"

return $E_BADARGS fi

fi # “ ”下面的 信号 值(比如 102等等)可能需要自己手动改( 以 getevent 命令的返回结果为依据)# 请将一系列的 sendevent “ ”命令放在一个命令中,不然可能会由于命令延时而造成 我明明是点击,却变成长按!adb shell "sendevent "$_input_dev_name" 1 102 1;\

sendevent "$_input_dev_name" 0 0 0;\ sleep $_sleep_time;\ sendevent "$_input_dev_name" 1 102 0;\ sendevent "$_input_dev_name" 0 0 0"

elif [ "$_type" = "menu" -o "$_type" = "m" ]; then # 模拟 menu事件adb shell "sendevent "$_input_dev_name" 1 139 1;\

sendevent "$_input_dev_name" 0 0 0;\

Page 92: Android 进程间通信机制(Binder)介绍

sendevent "$_input_dev_name" 1 139 0;\ sendevent "$_input_dev_name" 0 0 0"

elif [ "$_type" = "back" -o "$_type" = "b" ]; then # 模拟 back事件if [ $# -gt 1 ]; then

_sleep_time="$2" if ! $(echo $_sleep_time | grep -q -E '[0-9][0-9.]*'); then

err_msg "E/$FUNCNAME($LINENO): "\ "Usage: sendevent <home|h> [<press-time>]"

return $E_BADARGS fi

fi adb shell "sendevent "$_input_dev_name" 1 158 1;\

sendevent "$_input_dev_name" 0 0 0;\ sleep $_sleep_time;\ sendevent "$_input_dev_name" 1 158 0;\ sendevent "$_input_dev_name" 0 0 0"

elif [ "$_type" = "pos" -o "$_type" = "p" ]; then # 模拟指定位置点击事件if [ $# -lt 3 ]; then

err_msg "E/$FUNCNAME($LINENO): "\ "Usage: sendevent <pos> <x-axis> <y-axis> [press-time]"

return $E_BADARGS fi local _x="$2" local _y="$3" local _max_x=2047 local _max_y=2047 if [ "$_x" -lt 0 -o "$_x" -gt "$_max_x" ] ||\ [ "$_y" -lt 0 -o "$_y" -gt "$_max_y" ]; then

err_msg "E/$FUNCNAME($LINENO): "\ "Error touch position."

return $RETURN_FAILURE fi if [ $# -gt 3 ]; then

_sleep_time="$4" if ! $(echo $_sleep_time | grep -q -E '[0-9][0-9.]*'); then

err_msg "E/$FUNCNAME($LINENO): "\ "Usage: sendevent <home|h> [<press-time>]"

return $E_BADARGS fi

fi # 还是那句:下面的数值需要你自己更改!adb shell "sendevent "$_input_dev_name" 3 57 0;\

sendevent "$_input_dev_name" 3 48 1;\ sendevent "$_input_dev_name" 3 53 $_x;\ sendevent "$_input_dev_name" 3 54 $_y;\ sendevent "$_input_dev_name" 3 50 0;\ sendevent "$_input_dev_name" 0 2 0;\ sendevent "$_input_dev_name" 0 0 0;\ sleep $_sleep_time;\ sendevent "$_input_dev_name" 3 57 0;\ sendevent "$_input_dev_name" 3 48 0;\ sendevent "$_input_dev_name" 3 53 $_x;\ sendevent "$_input_dev_name" 3 54 $_y;\ sendevent "$_input_dev_name" 3 50 0;\ sendevent "$_input_dev_name" 0 2 0;\ sendevent "$_input_dev_name" 0 0 0"

fi } # }}}

# 使用示例# test xxx in camera {{{# usage: tgfunction tg() {

sendevent hsleep 0.8sendevent pos 2022 1048sleep 0.5sendevent pos 198 1095sleep 1sendevent pos 1961 197sleep 2sendevent pos 66 3sleep 0.1sendevent pos 66 3sleep 0.1sendevent pos 66 3sleep 2sendevent bsleep 1.5sendevent bsleep 0.5sendevent b

}# }}}

Page 93: Android 进程间通信机制(Binder)介绍

# +--------------------------------+# | Some "useful" alias |# +--------------------------------+# alias j='jump'

alias cls='clear'alias vi='vim'

alias ak='sudo adb kill-server'alias as='sudo adb start-server'alias ar='sudo adb remount'alias ash='adb shell'alias ai='adb install'alias air='adb install -r'alias apush='adb push'alias apull='adb pull'alias auni='adb uninstall'alias r='adb shell reboot'alias clslog='adb shell logcat -c'alias clsdmesg='adb shell dmesg -c > /dev/null'alias catkmsg='adb shell cat /proc/kmsg'

# >>> Shell script starts here.if [ -n "$1" ]; then

if [ "$1" = 1 -o "$1" = "y" -o "$1" = "Y" ]; then# Set up our compile environment.envsetup

elseerr_msg 'Bad flag, use ". util.sh 1" or ". util.sh y"'return $E_BADARGS

fifi# Format the "jump-table" if needed.JUMP_TABLE=`echo $JUMP_TABLE | sed -e 's/\][[:space:]*]\[/][/g'`# Add your's below.# ...

======================================== END ========================================