Android 12(S) Binder(三)


學以致用,這一節來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中時比較麻煩一點

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM