Android == 簡單的binder通信

    這個月初開始入職實習了,經過這幾天的熟悉,大概瞭解了將來負責的方向了,然後就是開始學習。主要學習Android的Framwork一層,爲上層的UI寫一些接口封裝,涉及到Android不同的service之間的通信,以及上層Java和底下native(C/C++)之間通信,也就是JNI技術(Java Native Interface的縮寫)。

    剛開始給了一份binder的簡單程序理解理解,昨天看了一天,沒有什麼頭緒,今天看了一位大神的文章纔有了寫思路,文章我轉載了,鏈接爲:http://blog.csdn.net/hjf161105/article/details/79482549 。接下來我將講述一下我對這一份簡單的binder程序的理解,首先看一下整個的項目結構,如下圖所示:


    這個目錄結構是我這個測試模塊的結構,最終還是需要放到Android源碼結構中去編譯的。這個目錄中包含四個文件夾,分別是client、service、include和TestService。這裏需要說明下TestService目錄,其餘三個目錄都是一眼就是明白的,client是客戶端程序,service是服務器程序,include是本項目中使用到的頭文件,TestService目錄其實是client和service之間通信binder處理的目錄。

    我們先看下這兩個頭文件以及他們相對應的cpp文件:

TestService.h文件

#ifndef _TEST_SERVICE_
#define _TEST_SERVICE_

#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <cutils/atomic.h>
#include <binder/Parcel.h>
#include "ITestService.h"
namespace android {

	//具體的服務操作類,繼承於BnTestService,由BnTestService代理,
	//可由客戶端的代理BpTestService調用
	class TestService:public BnTestService {
		public:
			virtual void	print(String8 str);		//虛函數,實現BnTestService的接口
	};

}
#endif

ITestService.h

#ifndef _ITEST_SERVICE_
#define _ITEST_SERVICE_

#include <utils/Errors.h>  // for status_t
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>

namespace android {
	
	//一個抽象類,是接口,可以被客戶端的代理和服務器的代理實現
	class ITestService:public IInterface 
	{
	public:
		//這個宏裏面定義了asInterface(),在ITestService.cpp中的
		//IMPLEMENT_META_INTERFACE具體實現這個asInterface()
		DECLARE_META_INTERFACE( TestService );
		//純虛函數,被不同的代理繼承後實現不同的功能
		virtual void	print(String8 str) = 0;
	};

	//服務器的代理類,繼承於BnInterface接口和ITestService接口,
	//此類還會調用其派生類的此基類ITestService中的print方法
	class BnTestService: public BnInterface<ITestService>
	{
	public:
		//接收到客戶端BpTestService的通信請求,根據code命令來決定操作
		virtual status_t    onTransact( uint32_t code,				//操作的code命令
									const Parcel& data,				//客戶端請求發送的數據包
									Parcel* reply,					//可能是用於返回的數據包
									uint32_t flags = 0 );			//標誌位
	};
}

#endif

TestService.cpp

#define LOG_TAG "TestService"
#include <utils/Log.h>

#include "TestService.h"

namespace android {

	//TestService中print方法的具體實現
	void TestService::print(String8 str)
	{
		LOGI("TestService::print   %s...\n", str.string());
	}

}

ITestService.cpp

#define LOG_TAG "TestService"

#include <stdint.h>
#include <sys/types.h>

#include <binder/Parcel.h>
#include <binder/IMemory.h>
#include <utils/Errors.h> 

#include "ITestService.h"

namespace android {

	//定義的操作命令
	enum {
		PRINT = IBinder::FIRST_CALL_TRANSACTION,
	};

	//客戶端的代理類,用於響應客戶端對ITestService的print方法的請求
	class BpTestService: public BpInterface<ITestService>
	{
	public:
		//構造函數,首先在參數列表中將IBinder參數傳遞給BpInterface
		BpTestService( const sp<IBinder>& impl )
			: BpInterface<ITestService>( impl ) {
		}

		//實現了其基類ITestService的print方法,響應客戶端的請求
		virtual void	print(String8 str) {
			LOGD( "BpTestService print\n" );
			Parcel data, reply;				//用於傳遞的數據data和返回的數據reply
			data.writeInterfaceToken( ITestService::getInterfaceDescriptor() );
			data.writeString8( str );
			remote()->transact( PRINT, data, &reply );		//請求通信
		}
	};

	//在這個宏裏面具體實現了asInterface()這個函數,在這個函數裏面有一個new Bp##INTERFACE(obj)
	//相當於在這個函數中把TestService轉化成了它的父類BpTestService並返回
	IMPLEMENT_META_INTERFACE( TestService, "test.service" );

	//響應客戶端代理類的請求
	status_t BnTestService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags )
	{
		switch( code ) {
			case PRINT:{						//得到的操作命令爲定義的PRINT,做出相應判斷
				CHECK_INTERFACE( ITestService, data, reply );
				LOGD( "BnTestService print\n" );
				print(data.readString8());		//調用其子類TestService的print方法
			}break;

			default:{							//code和定義的PRINT不匹配,交給BBinder處理
				return BBinder::onTransact( code, data, reply, flags );
			}break;
		}

		return NO_ERROR;
	}


}

    以上這四個文件其實就是binder通信的主要實現,客戶端和服務器其實只需要調用一下接口就可以實現通信了。這四個文件這涉及到了幾個類,乍一看其實挺繞的,我才採用了UML圖的方式梳理了一下這幾個類的關係:


這幾個類其實很多都是內部封裝了,對於客戶端程序來說,只需要瞭解ITestService和BpTestService類,對於服務器來說也是一樣,只需瞭解ITestService和BnTestService類。我在上述的程序中做了比較詳細的註釋,可能會有一些地方還不瞭解而導致註釋錯誤,還請多多包涵。下面把服務器程序和客戶端程序也展示一下:

服務器main_TestService.cpp:

#define LOG_TAG "TestService"

#include <sys/types.h>
#include <unistd.h>
#include <grp.h>

#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <private/android_filesystem_config.h>
#include "ITestService.h"
#include "TestService.h"

using namespace android;

int main(int argc, char** argv)
{
	//???暫時不明白
    sp<ProcessState> proc(ProcessState::self());
    	
    //獲取servicemanager對象
    sp<IServiceManager> sm = defaultServiceManager();
    
    //向servicemanager添加service,TestService,取名爲test.service
	sm->addService(String16("test.service"), new TestService());

	//???暫時不明白
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    return 0;
}

客戶端程序test_TestService.cpp:

#define LOG_TAG "TestService"

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <private/android_filesystem_config.h>

#include "ITestService.h"

using namespace android;

class TestServiceDeath:public IBinder::DeathRecipient
{
	public:
		virtual void binderDied(const wp<IBinder>& who)
		{
			LOGD("TestService died notification");
		}
};


int main(int argc, char** argv)
{
	sp<ProcessState> proc(ProcessState::self());
	ProcessState::self()->startThreadPool();

	sp<IBinder> binder = defaultServiceManager()->getService(String16("test.service"));


	sp<TestServiceDeath> dethNotify = new TestServiceDeath();
	binder->linkToDeath( dethNotify );


	if ( binder != NULL ) {
	//interface_cast<ITestService>(binder) 直接把IBinder類型對象binder轉化成了ITestService
	sp<ITestService> testServiceProxy = interface_cast<ITestService>( binder );
	testServiceProxy->print(String8("hello world"));
	}

	IPCThreadState::self()->joinThreadPool();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章