學以致用,這一節來native binder實戰!
android 12中的service用到的Bp、Bn文件多由aidl生成,所以實戰中也用aidl來生成。
1、文件目錄結構

文件目錄結構如上,偷懶沒有把頭文件放到include目錄當中去
2、aidl文件
package android.test; interface IHello { void sayHello(); void sayHelloTo(String people); String getName(); }
這里有要注意的地方,路徑名文件名要對應包名,文件名對應接口名稱,否則編譯時會遇到錯誤。aidl文件的編寫是用java來編寫的。
有了aidl,要如何編譯aidl呢?給個最簡單的例子:
// test cc_library { name: "libhello", srcs:[ ":hello_aidl" ], shared_libs: [ "libbinder", "libutils", ], } filegroup { name: "hello_aidl", srcs: [ "binder/android/test/IHello.aidl" ], path: "binder" }
filegroup中的path對應的是src的第一級文件路徑,如果沒有的話會發生編譯錯誤;如果我們的src路徑直接是android/test/IHello.aidl,那就不需要path了。
編譯完成之后就可以到out/soong/.intermediates 這個路徑下的對應工程路徑下找到生成文件了。
3、編寫Bn實現
自己手寫binder service需要寫Ixxx,Bnxxx,Bpxxx等文件,用aidl會顯得方便很多,因為編譯器會幫我們生成這些文件,我們只要寫一個類來繼承Bn。
// IHello.h #pragma once #include <binder/IBinder.h> #include <binder/IInterface.h> #include <binder/Status.h> #include <utils/String16.h> #include <utils/StrongPointer.h> namespace android { namespace test { class IHello : public ::android::IInterface { public: DECLARE_META_INTERFACE(Hello) virtual ::android::binder::Status sayHello() = 0; virtual ::android::binder::Status sayHelloTo(const ::android::String16& people) = 0; virtual ::android::binder::Status getName(::android::String16* _aidl_return) = 0; }; // class IHello class IHelloDefault : public IHello { public: ::android::IBinder* onAsBinder() override { return nullptr; } ::android::binder::Status sayHello() override { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status sayHelloTo(const ::android::String16&) override { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status getName(::android::String16*) override { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } }; // class IHelloDefault } // namespace test } // namespace android
生成文件IHello.h中用的都是String16,定義在system/core/libutils/中,返回值都是狀態Status,通過參數返回我們要的值。
下面看看Bn的實現:
#ifndef __HELLO_SERVICE_H__ #define __HELLO_SERVICE_H__ #include <android/test/BnHello.h> // HelloService.h class HelloService : public android::test::BnHello { public: HelloService(const char*); ~HelloService(); ::android::binder::Status sayHello() override; ::android::binder::Status sayHelloTo(const ::android::String16&) override; ::android::binder::Status getName(::android::String16*) override; private: const char* name; }; #endif
// HelloService.cpp #define LOG_TAG "HelloService" #include "HelloService.h" using ::android::binder::Status; HelloService::HelloService(const char* s) :name(s) { ALOGD("String16 = %s", ::android::String8(name_s).c_str()); } HelloService::~HelloService() { delete name; name = NULL; } Status HelloService::sayHello() { ALOGD("pid = %d, %s", getpid(), __func__); return Status::ok(); } Status HelloService::sayHelloTo(const ::android::String16& s) { ALOGD("pid = %d, %s, %s", getpid(), __func__, ::android::String8(s).c_str()); return Status::ok(); } Status HelloService::getName(::android::String16* aidl_return) { ALOGD("pid = %d, %s", getpid(), __func__); *aidl_return = ::android::String16(name);return Status::ok(); }
頭文件中的函數直接從IHello.h中抄出來就好,要注意命名空間的使用!
4、Server端
// main_server.cpp #include "HelloService.h" #include "binder/IServiceManager.h" #include "binder/IPCThreadState.h" #include "binder/ProcessState.h" using namespace android; int main(int argc, char** argv) { sp<HelloService> hello = new HelloService("APLLE"); sp<IServiceManager> sm = defaultServiceManager(); sm->addService(String16("hello.service"), hello, false, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); return 0; }
5、Client端
// main_client.cpp #define LOG_TAG "HelloService_Client" #include <android/test/IHello.h> #include "binder/IServiceManager.h" #include "binder/IPCThreadState.h" #include "binder/ProcessState.h" using namespace android::test; using namespace android; int main(int argc, char** argv) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> b = sm->getService(String16("hello.service")); sp<IHello> hello(interface_cast<IHello>(b)); ALOGD("pid = %d, sayHello", getpid()); hello->sayHello(); ALOGD("pid = %d, sayHelloTo ABC", getpid()); hello->sayHelloTo(String16("ABC")); ::android::String16 aidl_return; hello->getName(&aidl_return); ALOGD("pid = %d, name = %s", getpid(), ::android::String8(aidl_return).c_str()); return 0; }
6、Android.bp
// server cc_binary { name: "hello_server", srcs:[ "HelloService.cpp", "main_server.cpp" ], shared_libs: [ "libbinder", "libutils", "liblog", ], static_libs: [ "libhello", ], include_dirs: [ "frameworks/native/libs/binder/include", ], cflags: [ "-Wno-unused-parameter" ] } // client cc_binary { name: "hello_client", srcs:[ "main_client.cpp" ], shared_libs: [ "libbinder", "libutils", "liblog", ], static_libs: [ "libhello", ], include_dirs: [ "frameworks/native/libs/binder/include", ], cflags: [ "-Wno-unused-parameter" ], } // lib cc_library_static { name: "libhello", srcs: [ ":hello_aidl", ], shared_libs: [ "libbinder", "libutils", ], aidl: { export_aidl_headers: true, }, } filegroup { name: "hello_aidl", srcs: [ "binder/android/test/IHello.aidl" ], path: "binder" }
7、執行結果
執行時要關掉selinux,不然會找不到服務的
03-31 16:19:27.945 9325 9325 D HelloService: String16 = APLLE
03-31 16:19:27.945 9325 9325 D HelloService: pid = 9325, HelloService, name = APLLE, create HelloService 03-31 16:19:33.639 9327 9327 D HelloService_Client: pid = 9327, sayHello 03-31 16:19:33.640 9325 9326 D HelloService: pid = 9325, sayHello 03-31 16:19:33.640 9327 9327 D HelloService_Client: pid = 9327, sayHelloTo ABC 03-31 16:19:33.640 9325 9326 D HelloService: pid = 9325, sayHelloTo, ABC 03-31 16:19:33.640 9325 9326 D HelloService: pid = 9325, getName
03-31 16:19:33.640 9327 9327 D HelloService_Client: pid = 9327, name = APPLE
結果中可以看到server端的進程號為9325,client端進程號為9327,client端調用函數之后,server端執行的線程是9326。
binder如何傳遞自定義類,callback等也要再看看。
8、手寫binder service
如果要手寫binder其實也很簡單,這里貼一張我們師兄畫的UML類圖,以及其博客主頁 二的次方 - 博客園 (cnblogs.com)
按照這個類來寫就好了,自己手寫可以自由傳參,就是封裝到parcel中時比較麻煩一點

