從AILD與bindService談Binder進程間通信原理(上)
前言
Android進程間通信可以分爲三種方式:Binder機制,文件讀寫,Socket機制。這篇文章主要就是來談談Binder機制實現進程間通信的原理,主要分析AIDL進程間通信和bindService方法涉及的進程間數據傳輸相關邏輯。
AIDL實現進程間通信:
通過AIDL具體如何實現進程間通信,我推薦閱讀以下文章:
Android:學習AIDL,這一篇文章就夠了(上)
Android:學習AIDL,這一篇文章就夠了(下)
這兩篇文章把AIDL進程間通信的具體實現和代碼原理進行了詳細的講解。
但是,我看到這裏產生了2個疑惑:
1,服務端進程並沒有開啓一個線程去處理遠程服務請求,如何服務?
2,與系統服務的Binder通信方式比較,並沒有發現向ServiceManager註冊服務和請求服務的過程,如何註冊和獲取服務?且AIDL中遠程數據是如何跨進程傳輸的
1-答:Android進程本身就支持Binder進程間通信機制。因爲安卓進程通過Zygote創建的時候,已經在AppRuntime的onZygoteInit()方法中調用了startThreadPool()方法。
2-答:Binder通信並非必須通過ServiceManager.addService(String name, IBinder service)來向ServiceManager進程註冊服務,還可以通過Parcel中的writeStrongBinder方法把JavaBBinder類型Binder實體添加到ServiceManager中;而且並非必須使用ServiceManager.getService(String name)獲得BpBinder對象,還可以通過Parcel中的readStrongBinder獲取一個BpBinder對象用於請求遠程服務。
就以上二個問題詳細分析AIDL實現的具體邏輯:
1 Android進程本身就支持Binder進程間通信機制。安卓進程通過Zygote創建的時候,已經在AppRuntime的onZygoteInit()方法中調用了startThreadPool()方法創建了一個用於Binder通信的線程,因此,我們自己創建的遠程服務不需要再額外創建一個新的線程去處理遠程請求。
具體的android進程啓動,推薦查看下面的文章:
Android應用程序進程啓動過程的源代碼分析
2 結合AIDL實際來說明這個問題
首先,我們看看AIDL實現的關鍵代碼:
1,Binder核心代碼:
public static abstract class Stub extends android.os.Binder implements MyAIDL
{
public static MyAIDL asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof MyAIDL))) {
return ((MyAIDL)iin);
}
return new MyAIDL.Stub.Proxy(obj);
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getValue:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getValue();
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
2,BinderProxy核心代碼:
private static class Proxy implements MyAIDL
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
@Override public java.lang.String getValue() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getValue, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
3,客戶端關鍵代碼:
public class MainActivity extends Activity {
MyAIDL aidlMain;
@Override
protected void onCreate(Bundle savedInstanceState) {
…………………………
ServiceConnection mServiceConnection=new ServiceConnection() {
…………………………
@Override
public void onServiceConnected(ComponentName name, IBinder service){
// TODO Auto-generated method stub
aidlMain=AIDL_TESTInterface.Stub.asInterface(service);
}
};
……………………………………
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
4,服務端核心代碼:
public class AIDLtestService extends Service{
MyAIDL.Stub mainAIDL=new MyAIDL.Stub() {
@Override
public String getValue() throws RemoteException {
return "hello world~~";
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mainAIDL;
}
}
這裏我們主要是分析Client如何通過bindService方法獲取到Server的BinderProxy對象實現進程間通信的。主流程圖:
1,首先我們在客戶端關鍵代碼中可以發現,客戶端通過bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)方法來啓動和請求遠程服務。
2,Activity實際上調用的是ContextImpl中的bindService方法
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, Process.myUserHandle());
}
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,UserHandle user) {
IServiceConnection sd;
……………………………………
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
} else {
throw new RuntimeException("Not supported in system context");
}
……………………
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, user.getIdentifier());
……………………
}
這裏需要注意的是,IServiceConnection sd = mPackageInfo.getServiceDispatcher(conn,……),通過客戶端自定義的ServiceConnection對象創建了一個關鍵的Binder,該Binder會被保存在AMS中,最後當遠程服務準備好的時候,最終通過該Binder來與客戶端通信。mMainThread.getApplicationThread()返回的是Client進程用於與AMS所在進程進行遠程通信的Binder對象。
3,通過ActivityManagerNative.getDefault()獲取ActivityManagerNative的BinderProxy對象(這裏其實是通過與ServiceMangaer進程通信獲取的),並且調用其bindService方法。
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType, IServiceConnection connection,
int flags, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeStrongBinder(token);
service.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(connection.asBinder());
data.writeInt(flags);
data.writeInt(userId);
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
data.recycle();
reply.recycle();
return res;
}
4,這裏調用了三次writeStrongBinder方法,即在Parcel包中寫入了3個Binder對象,分別是caller.asBinder代表客戶端的Binder對象(用於AMS與客戶端通信),token代表什麼我暫時沒搞明白(^ ^),connection.asBinder()代表2中所述的,將被保存在AMS中,最終用於Client和Server遠程通信。
5,writeStrongBinder會調用原生層的android_os_Parcel_writeStrongBinder方法,該方法中首先調用ibinderForJavaObject方法把Binder對象轉換成一個JavaBBinder對象,然後調用parcel->writeStrongBinder,把Binder打包到Parcel中。
6,ibinderForJavaObject方法把Binder對象轉換成一個JavaBBinder對象,因爲傳入的是一個Binder所以調用的是jbh->get(env, obj)方法創建JavaBBinder(其中還會創建JavaBBinderHolder,這個好像就是包裝了一下JavaBBinder),如果傳入的是一個BinderProxy對象則會調用下面半段的代碼。
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetLongField(obj, gBinderOffsets.mObject);
return jbh != NULL ? jbh->get(env, obj) : NULL;
}
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
}
ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
return NULL;
}
7,parcel->writeStrongBinder會調用方法flatten_binder,該方法把binder寫入一個flat_binder_object 對象中,因爲Binder是一個JavaBBinder對象,因此local不爲空,該對象類型申明是obj.type = BINDER_TYPE_BINDER;
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (binder != NULL) {
IBinder *local = binder->localBinder();
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
ALOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
obj.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;
obj.cookie = 0;
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = 0;
obj.cookie = 0;
}
return finish_flatten_binder(binder, obj, out);
}
finish_flatten_binder方法會調用out->writeObject(flat, false);把該對象寫入Parcel。writeStrongBinder方法就結束了。writeStrongBinder方法主要就是把Binder寫入了Parcel中去,爲了遠程服務器從該Parcel中獲取BinderProxy對象,從而可以與對應的Binder客戶端遠程通信
8,mRemote是ServiceManager.getService(“activity”)的返回值,是一個BinderProxy對象。因此,mRemote.transact將會進入原生層的方法調用。
9,將調用BinderProxy的transactNative方法,進入原生層的android_os_BinderProxy_transact方法,該方法把java層的Parcel轉換成Native層的Pacel對象,把java層的BinderProxy對象轉換成Native層的BpBinder對象。
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 = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
status_t err = target->transact(code, *data, reply, flags);
}
10-11,然後調用BpBinder的transact方法,將會調用IPCThreadState的transact方法。
12,在IPCThreadState的transact方法中通過writeTransactionData方法把傳入的Parcel數據先轉換成專用於Binder數據傳輸的binder_transaction_data實例,然後將其與指令BC_TRANSACTION寫入到IPCThreadState專門用於與BinderDriver交互的Parcel對象mOut中。
13-15,調用waitForResponse方法,該方法首先調用talkWithDriver方法,該方法此時是把數據寫入BinderDriver中,而當服務端讀取時,該方法則是從BinderDriver獲取數據。接着,方法將調用ioctl方法與BinderDriver驅動交互,交互的指令是BINDER_WRITE_READ。
16,在kernel中的BinderDriver,通過binder_ioctl獲取ioctl傳入的數據,並根據指令進一步響應。BinderDriver是一塊共享內存,可以通過文件/dev/binder訪問,所有的進程都可以讀取這塊內存(不知道這麼理解是不是有點問題。。。)。
17,在kernel中主要是在binder_transaction方法中做了一些事情,在第7步中,我們的Binder對象類型是BINDER_TYPE_BINDER,如果待通信的進程是自身進程,那麼該值不變,如果待通信的進程是遠程進程,則該值變爲BINDER_TYPE_HANDLE。並且在該方法中會爲Binder對象的handle賦值,進程通信就是通過這個handle來區分不同的BpBinder對象(XXX.asInterface(new BpBinder(handle)))。
通過16-17步,Client的進程通信請求已經寫入BinderDriver中了,客戶端操作暫時告以段落,此時,服務端進程開始準備獲取該請求並響應。
接下來進入到系統服務system_Server進程中的ActivityManagerService服務的過程,因此
18-19,服務端在 IPCThreadState::joinThreadPool方法中,處於無限循環,不斷的調用getAndExecuteCommand方法來獲取BD中的數據,並執行命令。
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing top-level Command: "
<< getReturnString(cmd) << endl;
}
result = executeCommand(cmd);
set_sched_policy(mMyThreadId, SP_FOREGROUND);
}
return result;
}
同之前一樣,也是通過talkWithDriver方法從BD獲取數據,然後執行executeCommand方法。
20,在executeCommand方法中,把之前第11步中創建的binder_transaction_data 對象重新寫入IPCThreadState專用的Parcel對象mIn中,然後調用Parcel的ipcSetDataReference方法重新構造mRemote.transact中傳遞的Parcel對象。最後創建AMS的Binder對象,並調用其transact方法。
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
switch (cmd) {
……………………………………//僅保留關鍵代碼
case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
error = b->transact(tr.code, buffer, &reply, tr.flags);
}
}
}
21,BBinder->transact方法會最終調用ActivityManagerNative的onTransact方法。
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
//僅關鍵代碼,下面不在贅述,代碼基本上都只保留了關鍵的。。
case BIND_SERVICE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
IBinder token = data.readStrongBinder();
Intent service = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
b = data.readStrongBinder();
int fl = data.readInt();
int userId = data.readInt();
IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
int res = bindService(app, token, service, resolvedType, conn, fl, userId);
reply.writeNoException();
reply.writeInt(res);
return true;
}
}
在該方法中,解包獲取了之前Client中打包進入Parcel中的數據,包括Intent,三個Binder對象和其他數據。但是這裏的Binder對象已經變成了BinderProxy對象。對象的轉變發生在readStrongBinder函數中。然後分別將的BinderProxy對象封裝成自己的遠程服務代理,
22,readStrongBinder會調用原生層的android_os_Parcel_readStrongBinder方法,該方法首先把java層的Parcel轉換成Native層的Parcel,然後通過該parcel去讀取哭護短傳來的Binder
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return NULL;
}
24-25,Parcel::readStrongBinder()方法調用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 = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
由於我們是跨進程調用,在kernel的binder_transaction方法中,binder的類型被修改成了BINDER_TYPE_HANDLE,並且binder被賦予了唯一的handle數值,因此,通過proc->getStrongProxyForHandle(flat->handle)方法,獲得了這個BpBinder對象。
26,通過javaObjectForIBinder把Native層的BpBinder對象轉換成java層的BinderProxy對象。
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
if (val == NULL) return NULL;
if (val->checkSubclass(&gBinderOffsets)) {
// One of our own!
jobject object = static_cast<JavaBBinder*>(val.get())->object();
LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
return object;
}
// For the rest of the function we will hold this lock, to serialize
// looking/creation of Java proxies for native Binder proxies.
AutoMutex _l(mProxyLock);
// Someone else's... do we know about it?
jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
if (object != NULL) {
jobject res = jniGetReferent(env, object);
if (res != NULL) {
ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
return res;
}
LOGDEATH("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
android_atomic_dec(&gNumProxyRefs);
val->detachObject(&gBinderProxyOffsets);
env->DeleteGlobalRef(object);
}
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
if (object != NULL) {
LOGDEATH("objectForBinder %p: created new proxy %p !\n", val.get(), object);
// The proxy holds a reference to the native object.
env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
val->incStrong((void*)javaObjectForIBinder);
// The native object needs to hold a weak reference back to the
// proxy, so we can retrieve the same proxy if it is still active.
jobject refObject = env->NewGlobalRef(
env->GetObjectField(object, gBinderProxyOffsets.mSelf));
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);
// Also remember the death recipients registered on this proxy
sp<DeathRecipientList> drl = new DeathRecipientList;
drl->incStrong((void*)javaObjectForIBinder);
env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));
// Note that a new object reference has been created.
android_atomic_inc(&gNumProxyRefs);
incRefsCreated(env);
}
return object;
}
在該方法中首先通過val->findObject查找BpBinder對象是否已經創建並保存過了,這裏的val是一個BpBinder對象,因此findObject是定義在BpBinder.cpp文件中,在BpBinder內通過一個ObjectManager對象來管理存儲BpBinder對象的。
jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
如果找到則返回該BpBinder對象對應的BinderProxy對象。如果沒有則通過BinderProxy的類型和構造函數,創建一個BinderProxy對象
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
gBinderProxyOffsets保存的是Java層的BinderProxy的類信息,就像是Java層的BindProxy類在Native層類的映射,gBinderProxyOffsets是在Binder初始化時的int_register_android_os_BinderProxy方法創建的,通過gBinderProxyOffsets對象把Native層的BpBinder轉換成BinderProxy對象,BpBinder的實例保存在BinderProxy的mObject成員中。
env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
最後通過BpBinder的attachObject方法,把這個創建的BinderProxy對象加入到BpBinder的ObjectManager對象中進行管理,下次就可以直接通過findObject來找到該對象了。
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);
通過上述方法AMS所在進程就把Client發送過來的Binder對象對應的BpBinder對象轉換成BinderProxy對象傳遞到了框架層。
回到第21步中,在框架層的onTransact中取回了transact中的三個Binder對象對應的BinderProxy對象,並封裝成各自的通信代理對象XXXXProxy,例如app的類型是ApplicationThreadProxy。
IApplicationThread app = ApplicationThreadNative.asInterface(b);
IBinder token = data.readStrongBinder();
IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
這樣子,AMS就可以通過app對象與Client進程遠程通信;conn 對象將被保存在AMS中也是爲了AMS與Client遠程通信,conn 對象最後會用於傳輸Server的BpBinder對象回Client進程中。
27,開始了真正的bindService操作,具體實現是在ActivityManagerService類中。
通過1-27步驟,我們就可以解決一般的問題了,爲什麼不需要通過ServiceManager.addService註冊服務,不需要通過ServiceManager.getService請求遠程服務就可以進行進程間通信了。因爲,ServiceManager.getService返回的是遠程服務的BinderProxy,所以只要能獲得遠程服務的BinderProxy就可以與該遠程服務通信了。就像Client進程與AMS所在進程通信一樣,Client進程把自身用於進程間通信的Binder對象和遠程服務請求,同時通過AMS的遠程代理髮送給了AMS服務,AMS服務就擁有了Client進程的遠程服務代理對象BinderProxy。通過該對象,AMS就可以向Client發出遠程請求。
看到這裏,大家會發現,AMS是通過ServiceManager.addService註冊了服務的,這樣子Client才能向他通信啊,向他發送自己的BinderProxy對象。那麼自己定義的Server並沒有通過ServiceManager.addService註冊服務。那麼還是無法遠程通信啊。
其實不然,仔細思考一下,只要他們能夠互相知道並擁有對方的BinderProxy,那麼他們就能夠進行遠程通信。大家可以猜測一下Client與Server是如何完成進程間通信的,具體分析,留在下一篇文章中。下一篇文章將分析剩下的:………………………………
本文上半部分總結
僅對問題具體邏輯分析部分總結
1-2,Client進程發送bindService請求前的數據準備;
3-7,調用AMS的遠程代理準備發送請求前,將Binder等數據打包到Parcel中;
8-17,程代理向共享內存的BD寫入請求,並對當前Client進程打包到Parcel中的Binder做相關處理;
18-21,遠程進程從BD獲取遠程請求和數據
22-26, 解包數據,並獲取Client進程傳遞過來的所有BinderProxy代理,將用於與Client進程通信。
27, 正式調用遠程請求的方法bindService
其中1-17是在Client進程中完成,18-27是在AMS所在的進程中完成。
本文上半部分主要講解了Client向AMS發送請求的具體過程,中間涉及到一個概念就是Client把自身的Binder對象通過Parcel包發送給遠程進程AMS的onTransact方法的時候,Binder對象變成了BinderProxy對象。Java層的Binder對象與C層的BBinder對象對應,Java層的BinderProxy對象與C層的BpBinder對應。
另一個概念就是進程間通信的關鍵就在於,A進程擁有B進程的BinderProxy(BpBinder),A進程通過B進程的遠程代理就可以向B進程發送請求和信息。