前言
Binder 從java到c++到kernel,涉及的內容很多,很難在一篇文章中說清楚。這篇主要是自我記錄,方便后續查詢並拆分總結的。
因為涉及的的確非常多,不能面面俱到,所以可能一些地方感覺比較模糊、沒說明白的。這需要自己去閱讀了解。文章很長,需要耐心。
關於基礎部分,並不是都要了解了才行,而是要完全弄清楚Binder各個層次需要,列出的一些需要多關注的知識點。
另外,該篇文章着重在注冊服務和獲取服務的過程,有詳細的代碼流程(這個有點復雜、占篇幅很大部分)輔助理解 注冊和獲取服務過程的整體思想把握。
基礎
不做詳細介紹,只是列出。
如前言所說,基礎部分並非都要全部了解才可理解Binder。只是列出的需要多關注的地方。
進程空間
這里的進程空間就是進程在內存中的空間。在linux中,有
- 進程分為內核空間和用戶空間。 內核空間存放內核的代碼和數據,用戶空間存放用戶程序的代碼和數據。
- 每個進程通過系統調用進入內核空間。 進程通過系統調用進入內核運行,這時被稱為內核態 。當進程執行程序自己的代碼時,稱為用戶態。
- 所有進程共享同一個內核空間。
- 內核空間為內核保留,一直駐存在內存中。 不允許應用讀寫該區域或者直接調用內核代碼方法。
- 用戶空間不能直接訪問硬件設備。
Binder跨進程通信,就是借用了這個。
示意圖:
進程了解 可以參考下:淺談進程&線程
IPC基礎
需要清楚:進程是獨立的,一個進程不能直接訪問另一個進程。
進程間如果需要交換數據、進行通信,這個就是IPC(進程間通信/跨進程通信)。可以參考相關文章大致了解下:
隨筆分類 - Android_系統_進程線程
內存映射(mmap)
這里簡單將,就是將用戶空間一段內存地址映射到內核空間,映射關系建立后,任一修改都能反應到另一方。
Parcel
一個容器對象,包含數據和對象引用,支持序列化和跨進程后的反序列化。這里主要用於binder的跨進程通信。
AIDL
Android Interface definition language,接口定義語言,可以了解下。
Binder
IPC在Android中很多:如顯然四大組件都需要進行IPC。
Andriod沒有使用Linux中的各種IPC機制(進程間通信概述),通過基於OpenBinder的定制修改,實現了自己的一套輕量級的IPC機制---Binder。
在Android中,Binder幾乎用於所有核心的跨進程事件中。
相對於Linux中其他IPC機制,那么Binder有什么優點呢?
優點
- Binder只需進行1次數據拷貝。
共享內存不需數據拷貝但控制復雜;其他方式一般需要進行兩次數據拷貝;Binder只需1次,通過內存映射機制進行數據傳遞。 - 穩定性好。
C/S架構,職責分明。 - 安全。
加入了強大的安全機制。
Binder概述
Binder是基於C/S模式。主要有這幾個部分:
角色 | 作用 |
---|---|
Server進程 | 服務端,提供服務的進程。 |
Client進程 | 客戶端,使用服務的進程。上層應用。 |
ServerManager進程 | 管理服務。Server需要向它注冊自己提供的服務。Client向它查詢、獲取需要的服務。 |
Binder驅動 | 核心部分,Client通過它發送請求到Server,Server通過它返回結果到Client。內核中的驅動設備/dev/binder。 |
下面詳述中會具體說到。
Binder---IPC
首先,總體上就如上述進程空間描述。Binder通過內核進行跨進程。
具體點,如下圖:
服務通過binder驅動注冊到ServiceManager,ServiceManager保存了服務的名稱、handle等信息 並加入svclist列表中。客戶端通過binder驅動向ServiceManager進程查詢獲取到對應的服務的handle,然后binder將信息返回給客戶端,客戶端獲取得到相應的服務Binder。
詳述Binder的流程
詳述Binder的流程 主要是服務注冊、獲取、ServiceManager相關的代碼流程,這段很長,如果不需要看 可以直接跳到最后一塊:簡單總結。
下面AMS的注冊和獲取為例說明。Binder過程比較復雜,其中最需注意的是各個層次(java層/c++/kernel) IBinder對象具體是什么。
Binder源碼,java層和c++層在 framework/下。驅動層在 kernel/下。
Android AOSP沒有kernel源碼,得單獨下載。這里閱讀的源碼是AndroidQ的,AOSP部分是android-10.0.0_r40;kernel部分是MTK的,主要兩個文件路徑在kernel-4.9/drivers/android/binder.c和kernel-4.9/include/uapi/linux/android/binder.h。
另外,下面的過程很多地方 很多方法都需要詳細研究的。下面盡量簡化了,即使這樣(也是水平有限),內容也很長。
主要是一個進程如何與另一個進程通信。圍繞這 下面主要介紹了幾點:
- Service是如何注冊的
- ServerManager的創建,這里涉及到Service的注冊和獲取。
- Client是如何獲取服務的
服務注冊
AMS注冊過程概述
服務是Context.ACTIVITY_SERVICE。
下面是畫的一個注冊過程的相對完整的流程(不是類圖。文章是MD的,可以直接查看文本看到圖片地址,該圖片地址。使用wps畫的 由於非會員,圖形個數有限制帶了水印。),再結合代碼詳細說明下。
這是一個理想的狀態流程,比如實際中很多對象從保存好的地方直接獲取不需重新創建。
簡述:
注冊傳入了兩個主要參數(服務名:activity,Binder:this)。通過一系列調用,最終將服務的名稱和Binder等寫入到了數據包Parcel(data)中,最終進入了Binder驅動。Binder驅動為AMS創建了binder結點binder_node。最后Binder驅動將相關信息給到ServerManager進程,ServiceManager將其封裝加入svclist列表完成注冊。
注冊詳細過程
系統啟動后,這個服務即開始注冊。這個很簡單,注意傳入的服務名是Context.ACTIVITY_SERVICE(即activity),以及this(AMS本身,也是繼承了IBinder的Binder實體)。
SystemServer.java:
private void startBootstrapServices() {
......
mActivityManagerService.setSystemProcess();
......
}
ActivityManagerService.java:
public void setSystemProcess() {
......
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
......
}
ServiceManager.java:
@UnsupportedAppUsage
public static void addService(String name, IBinder service, boolean allowIsolated,
int dumpPriority) {
......
getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
......
}
getIServiceManager().addService(),這里需要弄清楚的就是getIServiceManager()和addService()兩個方法,下面正式開始注冊流程。
getIServiceManager()
ServiceManager.java:
@UnsupportedAppUsage
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
關鍵的一句,這里有幾個需要依次弄清楚的。
- BinderInternal.getContextObject()
- Binder.allowBlocking()
- ServiceManagerNative.asInterface()
- getIServiceManager().addService():獲取的是IServiceManager,這也是個接口。需要弄清楚getIServiceManager()獲取的sServiceManager實際對象是什么在來看addService()方法。
-----回顧點1: getIServiceManager()具體是什么對象;addService()具體是什么
詳細來看下這4點:
先看第一點(1/4)
BinderInternal.getContextObject()
BinderInternal.java:
@UnsupportedAppUsage
public static final native IBinder getContextObject();
frameworks/base/core/jni/android_util_Binder.cpp:
{ "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}
getContextObject()是native修飾的方法,通過jni,進入了C++。
下面主要來看下ProcessState::self()->getContextObject(NULL)和javaObjectForIBinder(env, b)。
-----回顧點2: getContextObject()具體獲取的是什么
先看下ProcessState::self()
ProcessState.java:
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endif
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
#define DEFAULT_MAX_BINDER_THREADS 15
sp<ProcessState> ProcessState::self()
{
......
gProcess = new ProcessState(kDefaultDriver);
return gProcess;
}
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))
, mDriverFD(open_driver(driver))
......
{
......
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
......
}
static int open_driver(const char *driver)
{
int fd = open(driver, O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
......
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
......
}
從代碼能夠看到最終通過open_driver()方法打開了/dev/binder或者/dev/vndbinder驅動。通過ioctl進入binder內核並建立聯系,在binder內核中創建了binder_proc並設置進程的最大線程數。
注意兩個個設置:
- DEFAULT_MAX_BINDER_THREADS:這個fd最大線程數為15
- BINDER_VM_SIZE:ProcessState初始話的內存映射大小:1G-8k(注:這個值也又不同的情況,這里不擴展)
在接着看ProcessState::self()->getContextObject(NULL)
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
......
handle_entry* e = lookupHandleLocked(handle);
if (e != nullptr) {
IBinder* b = e->binder;
if (b == nullptr || !e->refs->attemptIncWeak(this)) {
.......
b = BpBinder::create(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
回到回顧點2,getContextObject()獲取了句柄為0的BpBinder。先lookupHandleLocked()嘗試獲取,沒有則創建了一個BpBinder對象。
BpBinder的handle,如果是0 則該BpBinder是servicemanager的binder引用,如果非0 其handle值就是不同Service的hanlde 關聯了各個Service。也就是說任何的系統service都可以通過BpBinder(0)就能知道servicemanager的地址。
-----注意點1: 這個handle為0的BpBinder很重要,binder驅動等地方都有關聯。
在來看return的方法,javaObjectForIBinder(env, b):
frameworks/base/core/jni/android_util_Binder.cpp:
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
......
if (val->checkSubclass(&gBinderOffsets)) {
// It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
jobject object = static_cast<JavaBBinder*>(val.get())->object();
LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
return object;
}
BinderProxyNativeData* nativeData = new BinderProxyNativeData();
nativeData->mOrgue = new DeathRecipientList;
nativeData->mObject = val;
jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
......
return object;
}
在注冊過程,返回的是BinderProxy。前面知道傳入的是BpBinder對象,這是native層的對象在Java層無法使用,轉換成BinderProxy。
接着看第二點(2/4)
Binder.allowBlocking()
Binder.java:
public static IBinder allowBlocking(IBinder binder) {
try {
if (binder instanceof BinderProxy) {
((BinderProxy) binder).mWarnOnBlocking = false;
} else if (binder != null && binder.getInterfaceDescriptor() != null
&& binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
Log.w(TAG, "Unable to allow blocking on interface " + binder);
}
} catch (RemoteException ignored) {
}
return binder;
}
這個沒什么好說的。
再看第三點(3/4)
ServiceManagerNative.asInterface()
ServiceManagerNative.java:
@UnsupportedAppUsage
static public IServiceManager asInterface(IBinder obj)
{
......
IServiceManager in =
(IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
.......
return new ServiceManagerProxy(obj);
}
前面傳遞的參數obj是一個保存着BpBinder的BinderProxy對象,這個BpBinder的handle是0(即關聯servicemanager,后續通過transact傳入binder驅動 找到目標進程)。
queryLocalInterface獲取本地binder,此時in返回是null,所以這里返回了一個ServiceManagerProxy對象,並傳入了BinderProxy對象。后續就通過這個BinderProxy代理對象進行通信。
回到回顧點1,從上面一系列可以看出getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
這句話:
getIServiceManager()獲取的是ServiceManagerProxy對象,參數obj是BinderProxy。
addService()
接着看最后一點(4/4),addService()
最后來看下ServiceManagerProxy中的相關方法(ServiceManagerProxy是ServiceManagerNative內部類),即getIServiceManager().addService():
ServiceManagerNative.java:
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service);
data.writeInt(allowIsolated ? 1 : 0);
data.writeInt(dumpPriority);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
}
注意data.writeStrongBinder(service);
這里寫入的IBinder對象是AMS最初傳入的this,是Binder的實例,而不是BinderProxy。
這里的mRemote即創建ServiceManagerProxy對象時傳入的BinderProxy。
下面就是開始進入binder驅動了,得耐心接着看了。
先看下writeStrongBinder()
這個寫入過程稍微注意下。
Parcel:
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
frameworks/base/core/jni/android_os_Parcel.cpp:
{"nativeWriteStrongBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}
frameworks/base/core/jni/android_util_Binder.cpp:
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
// Instance of Binder?
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetLongField(obj, gBinderOffsets.mObject);
return jbh->get(env, obj);
}
// Instance of BinderProxy?
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return getBPNativeData(env, obj)->mObject;
}
ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
return NULL;
}
class JavaBBinderHolder
{
public:
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
b = new JavaBBinder(env, obj);
......
};
class JavaBBinder : public BBinder
{
.....
}
上面已經說過,這里的service就是AMS對象,即Binder實例。所以writeStrongBinder()寫入的service通過ibinderForJavaObject(env, object)封裝成JavaBBinder(也即BBinder)。即服務Service對象轉換成BBinder,傳入到binder驅動了。
parcel->writeStrongBinder(ibinderForJavaObject(env, object));
-->
Parcel.cpp:
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
......
if (binder != nullptr) {
BBinder *local = binder->localBinder();
if (!local) {
.......
} else {
obj.hdr.type = BINDER_TYPE_BINDER;
.....
上面看到這里binder是BBinder對象,注意這里的hdr.type = BINDER_TYPE_BINDER ,在binder驅動中有使用。
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0)
接着Java層從此開始向binder驅動傳遞
BinderProxy:
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
......
try {
return transactNative(code, data, reply, flags);
......
}
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
frameworks/base/core/jni/android_util_Binder.cpp:
{"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{......
Parcel* data = parcelForJavaObject(env, dataObj);
Parcel* reply = parcelForJavaObject(env, replyObj);
......
IBinder* target = getBPNativeData(env, obj)->mObject.get();
......
status_t err = target->transact(code, *data, reply, flags);
......
}
parcelForJavaObject將data、reply兩個Parcel由Java對象轉換成C++。
getBPNativeData()獲取的是BpBinder對象。
接下來看BpBinder中的transact()。
frameworks/native/libs/binder/BpBinder.cpp:
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
......
}
frameworks/native/libs/binder/IPCThreadState.cpp:
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
......
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
err = waitForResponse(??);
......
}
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
tr.target.handle = handle;
tr.code = code;
......
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
......
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
......
cmd = (uint32_t)mIn.readInt32();
.......
}
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
......
do {
......
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
......
} while (err == -EINTR);
......
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
......
}
transact()中關鍵兩步,writeTransactionData()和waitForResponse()。
writeTransactionData()將要傳遞的數據及命令寫入到mOut。這里要發送的命令是BC_TRANSACTION。 在注意的是,handle標識的是目標端,這里是0。即注冊中目標是Servicemanager(handle 0 對應 binder_context_mgr_node對象)。
waitForResponse()中while(1)死循環,通過talkWithDriver()中ioctl進入binder,這里傳入到binder_ioctl的參數cmd是BINDER_WRITE_READ。
waitForResponse()很重要,在死循環中會對binder返回的應答進行處理,cmd = (uint32_t)mIn.readInt32();
獲取應答的命令類型。
另外,注意下傳入transact()中的flag為0(即非TF_ONE_WAY)。
進入binder驅動
通過ioctl(),進入了binder內核
{kernel}/drivers/android/binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
.....
switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
......
}
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
......
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
......
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
......
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
......
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
......
}
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
......
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
......
if (get_user(cmd, (uint32_t __user *)ptr))
......
switch (cmd) {
......
case BC_TRANSACTION:
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, 0);
break;
}
......
}
}
通過系統調用,進入binder驅動的binder_ioctl()方法,這里傳入的cmd是BINDER_WRITE_READ(),上面 BpBinder中的transact()有說。
上面 BpBinder中的transact()也說過發送命令在mOut中是BC_TRANSACTION,這時通過copy_from_user()從用戶空間拷貝數據到了內核空間。最終進入到binder_transaction()事務處理。
注意第四個參數cmd==BC_REPLY為false 。
最重要的binder_transaction()
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply,
binder_size_t extra_buffers_size)
{
.....
if(reply){
......
}else {
if (tr->target.handle) {
......
} else {
......
target_node = context->binder_context_mgr_node;
......
}
}
......
switch (hdr->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
struct flat_binder_object *fp;
fp = to_flat_binder_object(hdr);
#ifdef BINDER_WATCHDOG
ret = binder_translate_binder(tr, fp, t, thread);
#else
ret = binder_translate_binder(fp, t, thread);
#endif
......
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
t->work.type = BINDER_WORK_TRANSACTION;
......
if (!binder_proc_transaction(t, target_proc,
}
#ifdef BINDER_WATCHDOG
static int binder_translate_binder(struct binder_transaction_data *tr,
......
{
struct binder_node *node;
node = binder_get_node(proc, fp->binder);
if (!node) {
node = binder_new_node(proc, fp);
if (!node)
return -ENOMEM;
#ifdef BINDER_WATCHDOG
parse_service_name(tr, proc, node->name);
#endif
......
ret = binder_inc_ref_for_node(target_proc, node,
fp->hdr.type == BINDER_TYPE_BINDER,
&thread->todo, &rdata);
......
if (fp->hdr.type == BINDER_TYPE_BINDER)
fp->hdr.type = BINDER_TYPE_HANDLE;
fp->binder = 0;
fp->handle = rdata.desc;
}
/* this is an addService() transaction identified by:
* fp->type == BINDER_TYPE_BINDER && tr->target.handle == 0
*/
void parse_service_name(struct binder_transaction_data *tr,
binder_transaction()這個事務處理方法很長,這里主要說下幾個注意點。
reply:前面流程傳入的為false,cmd是BC_TRANSACTION。說明這是一個Client發給Server的請求事務,在Client端線程上。若為true,即是BC_REPLY說明這是一個Server發給Client的事務處理回復。在server端的線程上。
tr->target.handle:如果是BC_TRANSACTION(這里注冊中是這個),接着判斷tr->target.handle。如果>0,即目標為普通Service,如果為0,則目標service是ServiceManager。從而獲取目標結點target_node,進一步獲取目標進程、目標線程及相關信息。
前面有講到傳遞的BBinder對象中hdr.type = BINDER_TYPE_BINDER。最終有走到binder_translate_binder,為注冊服務創建了binder_node結點,保存了服務的進程及相關信息。
向servicemanager添加BINDER_WORK_TRANSACTION事務,接下來進入ServiceManager進程。
handle值(也待詳細了解//TODO):
binder_get_node()->binder_new_node()->binder_inc_ref_for_node()->binder_get_ref_for_node_olocked(),不詳述。
new_ref->data.desc,data.desc即handle。
handle值計算方法規律:
每個進程binder_proc所記錄的binder_ref的handle值是從1開始遞增的;
所有進程binder_proc所記錄的handle=0的binder_ref都指向service manager;
同一個服務的binder_node在不同進程的binder_ref的handle值可以不同;
接下來的注冊過程進入ServiceManager,從下面ServiceManager的創建過程了解。
ServiceManager的創建
ServiceManager本身也是Binder服務,但它通過自身的binder.c與Binder驅動直接通信。通過循環binder_loop進行讀取和處理事務。
主要關注兩個文件:frameworks/native/cmds/servicemanager/service_manager.c
和frameworks/native/cmds/servicemanager/binder.c
。
系統啟動通過init.rc創建並啟動servicemanager。直接看其中main()方法。
frameworks/native/cmds/servicemanager/service_manager.c:
int main(int argc, char** argv)
{
......
//打開binder驅動,申請128k字節大小的內存空間
bs = binder_open(driver, 128*1024);
......
if (binder_become_context_manager(bs)) {
......
binder_loop(bs, svcmgr_handler);
......
}
重點需要關注的是上述3個方法,依次來看:
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
......
bs->fd = open(driver, O_RDWR | O_CLOEXEC);
......
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
......
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
......
}
frameworks/native/cmds/servicemanager/binder.c:
int binder_become_context_manager(struct binder_state *bs)
{
int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj);
// fallback to original method
if (result != 0) {
android_errorWriteLog(0x534e4554, "121035042");
result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
}
void binder_loop(struct binder_state *bs, binder_handler func)
{
......
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
......
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
......
}
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func)
{
while (ptr < end) {
uint32_t cmd = *(uint32_t *) ptr;
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION: {
......
res = func(bs, &txn, &msg, &reply);
if (txn.transaction_data.flags & TF_ONE_WAY) {
binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer);
} else {
binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res);
}
......
}
void binder_send_reply(struct binder_state *bs,
......
{
......
data.cmd_reply = BC_REPLY;
......
binder_write(bs, &data, sizeof(data));
}
binder_open():這個比較簡單,通過系統調用在binder驅動中創建binder_proc對象,調用mmap()內存映射分配了128K的內存空間。
binder_become_context_manager():使servicemanager成為上下文的管理者,創建了全局的binder_node對象binder_context_mgr_node。
binder_loop();這個是最重要的方法,進入死循環,等待Client端的請求。解析binder信息,此處參數ptr指向BC_ENTER_LOOPER,func指向svcmgr_handler。故有請求到來(如BR_TRANSACTION),則調用svcmgr_handler處理,處理完成后會發送BC_REPLY。
看看svcmgr_handler
frameworks/native/cmds/servicemanager/service_manager.c:
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data_secctx *txn_secctx,
struct binder_io *msg,
struct binder_io *reply)
{
......
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid,
(const char*) txn_secctx->secctx);
bio_put_ref(reply, handle);
case SVC_MGR_ADD_SERVICE:
if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
txn->sender_pid, (const char*) txn_secctx->secctx))
......
bio_put_uint32(reply, 0);
......
}
SVC_MGR_ADD_SERVICE就是從addService那拆解來的。SVC_MGR_GET_SERVICE類似。
ServiceManager最核心的兩個功能為查詢和注冊服務:
注冊服務:do_add_service(),記錄服務名和handle信息,保存到svclist列表;
查詢服務:do_find_service(),根據服務名查詢相應的的handle信息。
這樣,服務就注冊到ServiceManager。能夠被客戶端獲取。
客戶端獲取服務
獲取服務概述
同服務注冊一樣,先看下大致的流程圖。
簡述:
客戶端通過binder驅動從servicemanager進程查詢到服務的handle,servicemanager進程同樣應答binder驅動,binder驅動通過處理,向客戶端返回正確的數據命令,客戶端從而獲取到服務的Binder對象。完成獲取服務的的操作。
獲取服務詳細過程
直接來看
ActivityManager.getService():
ActivityManager:
@UnsupportedAppUsage
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
@UnsupportedAppUsage
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
ServiceManager.getService(Context.ACTIVITY_SERVICE):
ServiceManager:
@UnsupportedAppUsage
private static Map<String, IBinder> sCache = new ArrayMap<String, IBinder>();
@UnsupportedAppUsage
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(rawGetService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
private static IBinder rawGetService(String name) throws RemoteException {
......
final IBinder binder = getIServiceManager().getService(name);
......
}
getIServiceManager()與注冊時的流程差不多,返回的是ServiceManagerProxy對象,不在依次贅述了。
直接看下getService()
ServiceManagerNative.java->
class ServiceManagerProxy:
@UnsupportedAppUsage
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
進入binder驅動的也與注冊類似。不多贅述。
這里過程大致是,通過transact進入binder驅動,同樣找到的目標端是servicemanager,向servicemanager發送請求(BR_TRANSACTION)查詢服務(上述ServiceManager創建中),servicemanager查詢服務獲得服務的handle,通過BC_REPLY返回到binder驅動。binder驅動獲得服務的handle,最終同樣走到binder_transaction()。binder_thread_read()。
mRemote.transact()
下面是一些信息(do_find_service()查詢到服務handle后通過bio_put_ref回應的一些信息,binder中進行處理的重要信息):
void bio_put_ref(struct binder_io *bio, uint32_t handle)
{
......
obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
obj->hdr.type = BINDER_TYPE_HANDLE;
obj->handle = handle;
obj->cookie = 0;
}
最終進入binder_transaction()
static void binder_transaction(struct binder_proc *proc,
......
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
struct flat_binder_object *fp;
fp = to_flat_binder_object(hdr);
ret = binder_translate_handle(fp, t, thread);
.....
binder_alloc_copy_to_buffer(&target_proc->alloc,
t->buffer, object_offset,
fp, sizeof(*fp));
}
static int binder_translate_handle(struct flat_binder_object *fp,
......
if (node->proc == target_proc) {
......
if (fp->hdr.type == BINDER_TYPE_HANDLE)
fp->hdr.type = BINDER_TYPE_BINDER;
else
fp->hdr.type = BINDER_TYPE_WEAK_BINDER;
fp->binder = node->ptr;
fp->cookie = node->cookie;
......
} else {
......
ret = binder_inc_ref_for_node(target_proc, node,
fp->hdr.type == BINDER_TYPE_HANDLE,
NULL, &dest_rdata);
}
}
通過上述方法依次走下去。在binder_translate_handle()
中,node->proc == target_proc
,當前是在servicemanager進程的,而目標進程是請求服務所在進程,所以等於判斷不成立。
這個過程非常重要,分兩種情況來說:
當請求服務的進程與服務屬於不同進程,則為請求服務所在進程創建binder_ref對象,指向服務進程中的binder_node;
當請求服務的進程與服務屬於同一進程,則不再創建新對象,只是引用計數加1,並且修改type為BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。
通過binder_thread_read進行一些處理。binder向客戶端發送BR_REPLY。
reply.readStrongBinder()
sp<IBinder> Parcel::readStrongBinder() const
{
ALOGW("BINDER_DEBUG Parcel->readStrongBinder()");
sp<IBinder> val;
......
readNullableStrongBinder(&val);
return val;
}
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
ALOGW("BINDER_DEBUG Parcel->readNullableStrongBinder() val=%p", val);
return unflatten_binder(ProcessState::self(), *this, val);
}
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
ALOGW("BINDER_DEBUG Parcel->unflatten_binder() sp<IBinder> begin");
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->hdr.type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(nullptr, *flat, in);
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
由上面分析知道,servicemanager傳入的是BINDER_TYPE_HANDLE。請求服務與服務不在同一進程,這個值未變,仍是BINDER_TYPE_HANDLE。getStrongProxyForHandle()注冊時有講過,這里不再單獨列出。這里就獲取到了對應服務的BpBinder(handle)。handle是從servicemanager查到對應服務的handle。這樣服務獲取就完成了。
簡單總結
簡單回顧總結下幾個點
服務注冊與獲取大致過程
開始在 Binder---IPC 中所說的,服務注冊與獲取的大致過程:
服務通過binder驅動注冊到ServiceManager,ServiceManager保存了服務的名稱、handle等信息 並加入svclist列表中。客戶端通過binder驅動向ServiceManager進程查詢獲取到對應的服務的handle,然后binder將信息返回給客戶端,客戶端獲取得到相應的服務Binder。
與binder的交互命令
總結下 一個完整的服務注冊過程與binder交互命令大致如下圖:
服務的注冊和獲取基本類似,兩個過程,服務端都是ServiceManager。
Client端(BC_TRANSACTION)--->binder驅動(BR_TRANSACTION_COMPLETE)--->Client端; binder驅動(BR_TRANSACTION)--->Service端(BC_REPLY)--->binder驅動(BR_TRANSACTION_COMPLETE)--->Service端;binder驅動(BR_REPLY)--->Client端。
關於BpBinder、BBinder
總結下readStrongBinder():
請求服務進程與服務進程不在同一進程(如這個服務獲取),返回的是BpBinder對象。如果在同一進程,則不在創建新對象 只是引用加1,返回的是BBinder對象。
我們通過handle去獲取遠程端的Binder對象,如handle為0 就能獲取到servicemanager的BpBinder對象,通過查詢到的某個服務的handle獲取到對應服務的BpBinder對象(本地則是BBinder對象)。
在注冊時data.writeStrongBinder(service);
,通過ibinderForJavaObject()將service實體binder對象轉換成BBinder,然后傳入binder驅動,完成服務注冊到servicemanager。
這里的BBinder和BpBinder都是native層的Binder對象。 BBinder是本地Binder(Native Binder),BpBinder即遠程端Binder。
BpBinder提供transact()方法來發送請求;BBinder提供了onTransact()接口來接收請求。
BpBinder時客戶端創建用於消息發送的代理;BBinder是服務端用於接收消息的。當通信時,Client端通過BinderProxy 經由Bpbinder的transact()方法最終發送請求到binder驅動。binder驅動接收到經過處理,發送給目標進程JavaBBinder,最終經由服務實體的onTransact()接受處理。
在注冊過程,servicemanager中svcmgr_handler()相當於服務端Java層的onTransact()。下面是普通服務接收到請求的過程:
frameworks/native/libs/binder/IPCThreadState.cpp
sp<BBinder> the_context_object;
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
......
default:
err = executeCommand(cmd);
......
}
status_t IPCThreadState::executeCommand(int32_t cmd)
{
......
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION:
{
......
if (tr.target.ptr) {
......
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
......
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
......
}
frameworks/native/libs/binder/Binder.cpp
status_t BBinder::transact(
......
err = onTransact(code, data, reply, flags);
}
frameworks/base/core/jni/android_util_Binder.cpp
status_t onTransact(
......
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
......
}
gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
frameworks/base/core/java/android/os/Binder.java
// Entry point from android_util_Binder.cpp's onTransact
@UnsupportedAppUsage
private boolean execTransact(int code, long dataObj, long replyObj,
......
return execTransactInternal(code, dataObj, replyObj, flags, callingUid);
}
private boolean execTransactInternal(int code, long dataObj, long replyObj, int flags,
......
res = onTransact(code, data, reply, flags);
}
這里onTransact()最終調用到子類實現的onTransact(),即具體服務實現的onTransact()方法。
從上又有一般這樣的一個結構層次圖(網絡中很多,上述理解供參考):
binder驅動中的幾個常用量
struct binder_node {
......
struct binder_proc *proc;
struct hlist_head refs;
}
binder_node--->binder結點,即binder的實體。服務注冊就會創建一個binder_node。
proc: binder_proc,這里是binder實體對應的進程,相當於某個服務在哪進程。
refs: binder實體的引用對象列表,相當於所有使用某個服務的客戶端鏈表。
struct binder_ref {
struct binder_ref_data data;
struct binder_proc *proc;
struct binder_node *node;
}
struct binder_ref_data {
int debug_id;
uint32_t desc;
int strong;
int weak;
};
binder_ref--->跟蹤結點的引用,binder_node的引用的信息
proc:引用對象進程,使用服務的進程
node:引用的binder_node,即引用的目標結點
desc:該引用對象的句柄(handle)
struct binder_proc {
struct hlist_node proc_node;
struct list_head todo;
}
binder_proc--->binder進程的上下文信息,每個使用binder的進程都會創建一個binder_proc對象。在打開/dev/binder時就創建了。
proc_node:將該對象鏈接到全局binder_procs對象中。
todo:該進程的待處理事務隊列。
binder驅動結構體很多,需要多注意,不過都有注釋,理解不難。