Android 8.0系統原始碼分析--Binder程序間通訊(一)
開始我們的沉澱之路,老羅的書中第二章講的是Android HAL層的知識,而且直接自己實現了一個虛擬的freg驅動程式,後面的幾節是分別從native、java層如何訪問這個虛擬的驅動程式介面,我這裡沒有這樣的環境,所以就不分析這節了,第三章的智慧指標我對比8.0系統原始碼和老羅的書,基本修改很小,大家如果要學習的話,就直接看老羅的書吧,這也反映出一個問題,就是我們學到的知識肯定是有用的,老羅在自己部落格下面回答博友的提問時也一直在強調這點,我們學過的、學會的知識不可能浪費,沒有用,肯定是有用的,即使上層再如何變化,但是涉及到核心的東西,變化也是很小的。老羅書中的第四章講的是Log驅動的實現,對比Log來說,我們一般也就是會使用就可以了,所以也不打算在這一章節上花時間。
那麼我們就進入第五章--Binder程序間通訊。這是最有分量的一節,難度也非常大,之前自己也看過老羅的Binder系列部落格很久了,但是對其中的各各環節還是理解的不透,我們就從這裡開始學習吧。
老羅分析Binder程序間通訊的實現時,開始講解了很多Binder的結構體,我個人講不清這個,我就按照自己的思路來學吧。如果大家搞過應用層的開發,相信大家都很清楚,我們使用的最多的就是Activity,它的啟動過程就是一個完整的Binder呼叫,那麼我們就以這個過程為學習路線,來分析一下startActivity的過程中Application應用層是怎麼通過Binder程序間通訊呼叫到ActivityManagerServie當中的。
我們的入口函式當然就是Activity類的startActivity方法了。Activity類的startActivity方法實現很簡單,就是直接呼叫兩個引數的startActivity方法,此時傳入的第二個引數options為空,該方法的實現如下:
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
按照我們正常的啟動邏輯,第二個引數options為空,所以進入else分支,呼叫startActivityForResult來進一步處理,再次呼叫三個引數的同名方法,mParent變數一般為空,所以會進入第一個if分支,這裡最重要的就是mInstrumentation.execStartActivity、mMainThread.sendActivityResult這兩句邏輯了。mInstrumentation.execStartActivity這句就會進入到我們的目標,將Activity的啟動資料封裝完成後,通過binder機制傳送到Server端,也就是ActivityManagerService;mMainThread.sendActivityResult這句在判斷呼叫正常的情況下,通知應用主執行緒ActivityThread來處理啟動後的結果,mMainThread是一個ActivityThread型別的成員變數,它是在當前的Activity啟動成功後,通過應用程式主執行緒ActivityThread類的performLaunchActivity方法來賦值的。我們就追蹤mInstrumentation.execStartActivity的實現就可以了。mInstrumentation是Activity類的成員變數,它的型別是Instrumentation,它有三個execStartActivity重名方法,而當前的呼叫是第四個引數為Activity型別的,該方法的實現如下:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
return result;
} else if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
這個方法中最重要的就是最後的try/catch了,通過呼叫ActivityManager.getService().startActivity來啟動目標Activity,然後呼叫checkStartActivityResult方法來檢查啟動結果。我們繼續跟蹤ActivityManager.getService().startActivity,它需要分兩段來分析。
第一段呼叫ActivityManager.getService()來獲取binder代理物件,它的實現如下:
/**
* @hide
*/
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
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;
}
};
IActivityManagerSingleton是ActivityManager類中型別為Singleton<IActivityManager>的靜態成員變數,get()方法是單例模式Singleton來實現的,當呼叫get()方法時,就會執行範型 T 的create()方法,Singleton類的程式碼如下:
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
ActivityManager這裡以Context.ACTIVITY_SERVICE為key值獲取到一個IBinder物件,然後呼叫IActivityManager.Stub.asInterface(b)進行轉換,就會得到一個BinderProxy物件,IActivityManager.aidl檔案經過編譯後就會生成IActivityManager.java,但是原始碼中沒有,我就自己寫了一個ICameraService.aidl檔案,然後生成對應的ICameraService.java,我們可以用它來對比分析一下,ICameraService.java原始碼如下:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D:\\Work\\Project\\workstudio\\CameraService\\app\\src\\main\\aidl\\com\\huawei\\cameraservice\\ICameraService.aidl
*/
package com.huawei.cameraservice;
// Declare any non-default types here with import statements
public interface ICameraService extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.huawei.cameraservice.ICameraService {
private static final java.lang.String DESCRIPTOR = "com.huawei.cameraservice.ICameraService";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.huawei.cameraservice.ICameraService interface,
* generating a proxy if needed.
*/
public static com.huawei.cameraservice.ICameraService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.huawei.cameraservice.ICameraService))) {
return ((com.huawei.cameraservice.ICameraService) iin);
}
return new com.huawei.cameraservice.ICameraService.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@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_getMainCameraId: {
data.enforceInterface(DESCRIPTOR);
int _result = this.getMainCameraId();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_openCamera: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _result = this.openCamera(_arg0);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.huawei.cameraservice.ICameraService {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public int getMainCameraId() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getMainCameraId, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public int openCamera(int id) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(id);
mRemote.transact(Stub.TRANSACTION_openCamera, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getMainCameraId = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_openCamera = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public int getMainCameraId() throws android.os.RemoteException;
public int openCamera(int id) throws android.os.RemoteException;
}
DESCRIPTOR就是當前Server的描述符,比如ActivityManagerService的描述符就是“activity”,queryLocalInterface方法會在本程序中查詢,假如我們想要獲取到ActivityManagerService,而且我們是在SystemServer程序當中 ,那肯定就直接找到了,我們當前的宣告中,啟動Activity時本程序肯定是找不到,所以 iin 結果為空,那麼就以obj對引數建立一個Proxy物件返回給我們,實際上這個Proxy物件就是BinderProxy,它定義在frameworks\base\core\java\android\os\Binder.java檔案當中。好,這裡我們獲取到BinderProxy物件之後,繼續往下讀程式碼。那麼就呼叫它的startActivity方法,因為沒有IActivityManager編譯出來的java檔案,我們就以openCamera方法為例來繼續我們的流程。Proxy類的程式碼如下:
private static class Proxy implements com.huawei.cameraservice.ICameraService {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public int getMainCameraId() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getMainCameraId, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public int openCamera(int id) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(id);
mRemote.transact(Stub.TRANSACTION_openCamera, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
像這樣的aidl生成的方法全部都是這種格式:1、獲取到兩個Parcel物件,一個用於儲存我們呼叫方法時的資料,一個用於儲存方法執行完成後的返回結果;2、依次寫入我們的通訊資料;3、執行transact方法;4、讀取返回結果,如果有異常,則丟擲異常,如果沒有異常,則說明通訊成功,將結果返回到Client端。這裡要特別說明的就是,Parcel用於儲存通訊資料和取返回結果時,一定完全按照伺服器定義好的順序,否則資料就會出錯。這是為什麼呢?要查這個原因,就要看看Parcel這個資料載體的實現了。
首先來看一下Parcel.obtain()方法的實現,原始碼如下:
/**
* Retrieve a new Parcel object from the pool.
*/
public static Parcel obtain() {
final Parcel[] pool = sOwnedPool;
synchronized (pool) {
Parcel p;
for (int i=0; i<POOL_SIZE; i++) {
p = pool[i];
if (p != null) {
pool[i] = null;
if (DEBUG_RECYCLE) {
p.mStack = new RuntimeException();
}
return p;
}
}
}
return new Parcel(0);
}
這裡就是用了池的概念,sOwnedPool是Parcel類的成員變數,它的型別是Parcel[]陣列,初始化長度為6,首次執行Parcel類的obtain方法時,sOwnedPool中的成員全部為空,所以直接新建物件返回,但是從這裡看不出來和物件池有什麼關係,sOwnedPool中每個元素是怎麼賦值的?奇妙的地方就在recycle()方法當中了,我們來看一下recycle()方法的實現:
/**
* Put a Parcel object back into the pool. You must not touch
* the object after this call.
*/
public final void recycle() {
if (DEBUG_RECYCLE) mStack = null;
freeBuffer();
final Parcel[] pool;
if (mOwnsNativeParcelObject) {
pool = sOwnedPool;
} else {
mNativePtr = 0;
pool = sHolderPool;
}
synchronized (pool) {
for (int i=0; i<POOL_SIZE; i++) {
if (pool[i] == null) {
pool[i] = this;
return;
}
}
}
}
從註釋也可以看出來,是將一個即將要回收的物件放入物件池中,而釋放的只是它所佔用的記憶體空間而已,這裡最奇妙的就是第一個if分支給區域性變數pool賦值了,因為pool在宣告時沒有初始化,所以直接將成員變數sOwnedPool賦值給區域性變數pool之後,那麼它們兩個就是同一個物件了,而且hashcode值也相同,所以接下來給pool的元素賦值時就相當於為sOwnedPool元素賦值了,這樣sOwnedPool中的6個元素就會依次在回收6個新建物件時依次被填充上了!!真是非常巧妙,但是寫法上不容易理解!
好,我們繼續回到主流程中,當新建一個Parcel物件時,傳入的引數nativePtr為0,表示該物件還沒有在native層建立,於是接著呼叫nativeCreate來執行native層的建立。native層的建立很簡單,就是直接新建了一個Parcel的物件,然後將該物件的指標返回來,我們隨便來看一下nativeWriteString方法的實現,以更好的理解Parcel寫入資料時必須按照順序的原因。nativeWriteString方法的JNI定義是由android_os_Parcel_writeString來執行的,android_os_Parcel_writeString的實現程式碼如下:
static void android_os_Parcel_writeString(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
status_t err = NO_MEMORY;
if (val) {
const jchar* str = env->GetStringCritical(val, 0);
if (str) {
err = parcel->writeString16(
reinterpret_cast<const char16_t*>(str),
env->GetStringLength(val));
env->ReleaseStringCritical(val, str);
}
} else {
err = parcel->writeString16(NULL, 0);
}
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}
nativePtr就是在建立C++層物件時的指標,首先將我們傳入的String字串轉換為char陣列,然後呼叫parcel類的writeString16方法進行寫入。writeString16方法的實現在frameworks\native\libs\binder\Parcel.cpp檔案當中,原始碼如下:
status_t Parcel::writeString16(const String16& str)
{
return writeString16(str.string(), str.size());
}
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;
}
看到這裡我們就非常清楚了,當寫入一個String字串時,會先寫入該字串的長度len,然後才呼叫memcpy系統函式將字串內容複製申請好的記憶體空間中,所以千萬不能亂讀亂寫,否則讀出來的資料肯定就是錯誤的資料了。
Parcel的分析就暫時到這裡,我們繼續回到主流程當中。mRemote獲取到的就是一個BinderProxy的物件,那我們就繼續看它的transact方法的實現邏輯。BinderProxy類的定義在frameworks\base\core\java\android\os\Binder.java檔案中,它的transact方法的實現如下:
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)) {
// For now, avoid spamming the log by disabling after we've logged
// about this interface at least once
mWarnOnBlocking = false;
Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
new Throwable());
}
final boolean tracingEnabled = Binder.isTracingEnabled();
if (tracingEnabled) {
final Throwable tr = new Throwable();
Binder.getTransactionTracker().addTrace(tr);
StackTraceElement stackTraceElement = tr.getStackTrace()[1];
Trace.traceBegin(Trace.TRACE_TAG_ALWAYS,
stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName());
}
try {
return transactNative(code, data, reply, flags);
} finally {
if (tracingEnabled) {
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
}
}
}
該方法首先對輸入資料data的大小進行檢查,是通過呼叫checkParcel方法來完成的,它當中執行if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) 判斷,也就是說Binder程序間通訊的傳輸資料最大為800K,如果超過800K,就會打印出Unreasonably large binder buffer異常。所以我們在使用Binder程序間通訊時,如果資料量過大,就要考慮其他方案來實現我們的目的。第一個引數code就指我們呼叫Server端的方法請求碼,它是以android.os.IBinder.FIRST_CALL_TRANSACTION為基數遞增的,最後一個引數flags的意思是此次請求是否同步。比如我們現在分析的場景,啟動Activity時,不僅要求ActivityManagerService完成Activity的啟動,而且還要等待它給我們返回結果才能繼續往下執行,也就是同步的,因此它的值為0;而假如我們要使用音樂播放器播放一段音樂,不需要它給我們返回結果,我們只需要將命令傳送給MediaServer就直接返回繼續處理我們的邏輯了,這種場景下就是非同步的,那麼它的值就是1。最後繼續呼叫transactNative來處理我們的請求。
transactNative方法的實現在frameworks\base\core\jni\android_util_Binder.cpp檔案中,原始碼如下:
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
if (dataObj == NULL) {
jniThrowNullPointerException(env, NULL);
return JNI_FALSE;
}
Parcel* data = parcelForJavaObject(env, dataObj);
if (data == NULL) {
return JNI_FALSE;
}
Parcel* reply = parcelForJavaObject(env, replyObj);
if (reply == NULL && replyObj != NULL) {
return JNI_FALSE;
}
IBinder* target = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
if (target == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
return JNI_FALSE;
}
ALOGV("Java code calling transact on %p in Java object %p with code %" PRId32 "\n",
target, obj, code);
bool time_binder_calls;
int64_t start_millis;
if (kEnableBinderSample) {
// Only log the binder call duration for things on the Java-level main thread.
// But if we don't
time_binder_calls = should_time_binder_calls();
if (time_binder_calls) {
start_millis = uptimeMillis();
}
}
//printf("Transact from Java code to %p sending: ", target); data->print();
status_t err = target->transact(code, *data, reply, flags);
//if (reply) printf("Transact from Java code to %p received: ", target); reply->print();
if (kEnableBinderSample) {
if (time_binder_calls) {
conditionally_log_binder_call(start_millis, target, code);
}
}
if (err == NO_ERROR) {
return JNI_TRUE;
} else if (err == UNKNOWN_TRANSACTION) {
return JNI_FALSE;
}
signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/, data->dataSize());
return JNI_FALSE;
}
該方法先對data資料進行判斷,如果data為空,就直接丟擲空指標異常。緊接著將我們從Java層傳進來的物件轉換為C++層的指標,如果轉換出錯,則中斷執行,直接返回JNI_FALSE,下一步獲取到C++層的Binder代理物件指標,實際是一個BpBinder物件,然後將封裝好的C++層的四個物件作為引數,呼叫BpBinder物件的transact方法。
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);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
首先檢查當前的Binder代理物件是否還存活,只有在存活的狀態下才能進行後續的邏輯。IPCThreadState和ProcessState兩個類就是Binder通訊的介面卡,中轉邏輯都是在它們兩個類中完成的,它的self()方法獲取到的就是一個IPCThreadState物件,我們繼續分析它的transact方法的實現。
IPCThreadState類的transact方法實現在frameworks\native\libs\binder\IPCThreadState.cpp檔案中,原始碼如下:
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck();
flags |= TF_ACCEPT_FDS;
IF_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");
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 0
if (code == 4) { // relayout
ALOGI(">>>>>> CALLING transaction 4");
} else {
ALOGI(">>>>>> CALLING transaction %d", code);
}
#endif
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
#if 0
if (code == 4) { // relayout
ALOGI("<<<<<< RETURNING transaction 4");
} else {
ALOGI("<<<<<< RETURNING transaction %d", code);
}
#endif
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;
}
該方法首先仍然會進行資料檢查,TF_ACCEPT_FDS表示是否可以攜帶檔案描述符,接下來呼叫writeTransactionData將資料進一步封裝成binder_transaction_data結構體,老羅的書中對所有Binder通訊的結構體有非常詳細的分析說明,大家可以去Android
8.0系統原始碼分析--開篇下載老羅的Android系統原始碼情景分析【羅昇陽著】PDF版本電子書。下一步繼續呼叫waitForResponse來執行Binder通訊。
waitForResponse方法的實現原始碼如下:
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_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 = (uint32_t)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:
{
ALOG_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));
ALOG_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 binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t),
freeBuffer, this);
} else {
err = *reinterpret_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 binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
}
} else {
freeBuffer(NULL,
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), this);
continue;
}
}
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;
}
這裡就是Binder通訊比較核心的地方了,其中的BR_TRANSACTION_COMPLETE、BR_DEAD_REPLY、BR_ACQUIRE_RESULT、BR_REPLY都是Binder的通訊協議,talkWithDriver方法就是最終和Binder驅動進行互動了,它是通過呼叫ioctl系統函式,將封裝好的資料傳送到Binder驅動中,然後由Binder驅動進行解析以實現和Server端的通訊的。Binder通訊協議定義在bionic\libc\kernel\uapi\linux\android\binder.h檔案當中,包括了binder_transaction_data資料互動協議、binder_write_read資料結構體、binder_driver_return_protocol返回協議、binder_driver_command_protocol命令協議,該檔案的整個原始碼如下:
/****************************************************************************
****************************************************************************
***
*** This header was automatically generated from a Linux kernel header
*** of the same name, to make information necessary for userspace to
*** call into the kernel available to libc. It contains only constants,
*** structures, and macros generated from the original header, and thus,
*** contains no copyrightable information.
***
*** To edit the content of this header, modify the corresponding
*** source file (e.g. under external/kernel-headers/original/) then
*** run bionic/libc/kernel/tools/update_all.py
***
*** Any manual change here will be lost the next time this script will
*** be run. You've been warned!
***
****************************************************************************
****************************************************************************/
#ifndef _UAPI_LINUX_BINDER_H
#define _UAPI_LINUX_BINDER_H
#include <linux/types.h>
#include <linux/ioctl.h>
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define B_PACK_CHARS(c1,c2,c3,c4) ((((c1) << 24)) | (((c2) << 16)) | (((c3) << 8)) | (c4))
#define B_TYPE_LARGE 0x85
enum {
BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
enum {
FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
#ifdef BINDER_IPC_32BIT
typedef __u32 binder_size_t;
typedef __u32 binder_uintptr_t;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#else
typedef __u64 binder_size_t;
typedef __u64 binder_uintptr_t;
#endif
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
struct flat_binder_object {
__u32 type;
__u32 flags;
union {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
binder_uintptr_t binder;
__u32 handle;
};
binder_uintptr_t cookie;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
struct binder_write_read {
binder_size_t write_size;
binder_size_t write_consumed;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
binder_uintptr_t write_buffer;
binder_size_t read_size;
binder_size_t read_consumed;
binder_uintptr_t read_buffer;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
};
struct binder_version {
__s32 protocol_version;
};
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#ifdef BINDER_IPC_32BIT
#define BINDER_CURRENT_PROTOCOL_VERSION 7
#else
#define BINDER_CURRENT_PROTOCOL_VERSION 8
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#endif
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32)
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
enum transaction_flags {
TF_ONE_WAY = 0x01,
TF_ROOT_OBJECT = 0x04,
TF_STATUS_CODE = 0x08,
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
TF_ACCEPT_FDS = 0x10,
};
struct binder_transaction_data {
union {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
__u32 handle;
binder_uintptr_t ptr;
} target;
binder_uintptr_t cookie;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
__u32 code;
__u32 flags;
pid_t sender_pid;
uid_t sender_euid;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
binder_size_t data_size;
binder_size_t offsets_size;
union {
struct {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
binder_uintptr_t buffer;
binder_uintptr_t offsets;
} ptr;
__u8 buf[8];
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
} data;
};
struct binder_ptr_cookie {
binder_uintptr_t ptr;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
binder_uintptr_t cookie;
};
struct binder_handle_cookie {
__u32 handle;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
binder_uintptr_t cookie;
} __packed;
struct binder_pri_desc {
__s32 priority;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
__u32 desc;
};
struct binder_pri_ptr_cookie {
__s32 priority;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
binder_uintptr_t ptr;
binder_uintptr_t cookie;
};
enum binder_driver_return_protocol {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
BR_ERROR = _IOR('r', 0, __s32),
BR_OK = _IO('r', 1),
BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
BR_ACQUIRE_RESULT = _IOR('r', 4, __s32),
BR_DEAD_REPLY = _IO('r', 5),
BR_TRANSACTION_COMPLETE = _IO('r', 6),
BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),
BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),
BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie),
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
BR_NOOP = _IO('r', 12),
BR_SPAWN_LOOPER = _IO('r', 13),
BR_FINISHED = _IO('r', 14),
BR_DEAD_BINDER = _IOR('r', 15, binder_uintptr_t),
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, binder_uintptr_t),
BR_FAILED_REPLY = _IO('r', 17),
};
enum binder_driver_command_protocol {
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
BC_ACQUIRE_RESULT = _IOW('c', 2, __s32),
BC_FREE_BUFFER = _IOW('c', 3, binder_uintptr_t),
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
BC_INCREFS = _IOW('c', 4, __u32),
BC_ACQUIRE = _IOW('c', 5, __u32),
BC_RELEASE = _IOW('c', 6, __u32),
BC_DECREFS = _IOW('c', 7, __u32),
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
BC_REGISTER_LOOPER = _IO('c', 11),
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
BC_ENTER_LOOPER = _IO('c', 12),
BC_EXIT_LOOPER = _IO('c', 13),
BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_handle_cookie),
BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_handle_cookie),
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
BC_DEAD_BINDER_DONE = _IOW('c', 16, binder_uintptr_t),
};
#endif
剩下的就到了Binder程序間通訊最核心的地方了,也就是waitForResponse之後的流程,我們下次繼續分析。
如果想詳細瞭解Binder程序間通訊內容,可以檢視老羅的系列部落格,講的非常好,地址如下: