Android Binder (可以直接写在项目中的写法)

Posted we1less

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Binder (可以直接写在项目中的写法)相关的知识,希望对你有一定的参考价值。

此篇为大家展示一个写在项目中的写法,native层的service注册和获取服务,加上回调。

首先展示一下项目目录

 binder通信是基于aidl接口实现的,使用aidl接口可以省略许多不必要的代码。


工程的基础mk

android.mk

include $(call all-subdir-makefiles)

Android.bp

subdirs = ["cmd","lib","service"]

cmd文件夹代表服务从这个文件夹启动,当然如果特别完整的需要把 .rc文件和SELINUX权限放开

Android.bp

cc_binary {

    srcs: ["main_godaservice.cpp"],

    shared_libs: [
        "libgodaservice",    //需要启动的动态库
        "liblog",
        "libutils",
        "libbinder",
    ],

    name: "godaservice",
    
    compile_multilib: "32",
    
    vendor: true,            //代表生成在vendor/bin/下
    //vendor_available: true,
    
    //LOCAL_INIT_RC := cameraserver.rc
}

main_godaservice.cpp     主要的启动类

//参考  frameworks/av/media/mediaserver/main_mediaserver.cpp
#define LOG_TAG "GodaService"

#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include "GodaService.h"
#include <utils/Log.h>

using namespace android;

int main(void)
{
    // 实际这个函数的目的就是防止程序收到SIGPIPE后自动退出
    signal(SIGPIPE, SIG_IGN);
    sp<ProcessState> proc(ProcessState::self());

    //获得BpServiceManager
    sp<IServiceManager> sm(defaultServiceManager());

    ALOGI("ServiceManager: %p", sm.get());
    android::hardware::GodaService::instantiate();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();

    return 0;
}


service文件夹存放着binder服务端  同时这里也存在者aidl文件

Android.bp

cc_library_shared {
    name: "libgodaservice",
    srcs: [
        "aidl/android/hardware/IGodaService.aidl",
        "aidl/android/hardware/IGodaServiceListener.aidl",
        "GodaService.cpp",
    ],
    aidl: {
            export_aidl_headers: true,   //这个代表可以被外部引用
            local_include_dirs: ["aidl"],
    },
    export_include_dirs: ["./"],         //在当前文件夹下导入头文件
    shared_libs: [
        "libcutils",
        "libutils",
        "liblog",
        "libbase",
        "libbinder",
    ],
    vendor: true,
    //vendor_available: true,
}

 IGodaService.aidl      基础接口类

对于aidl接口来讲编译后的接口文件路径

out/target/product/generic_x86_64/obj/SHARED_LIBRARIES/libgodaservice_intermediates

本来应该是这个路径但是其中包含了export_includes

所以最终的路径指向

out/soong/.intermediates/frameworks/av/goda/service/libgodaservice/android_x86_64_shared_core/gen/aidl/android/hardware/

out/soong/.intermediates/frameworks/av/goda/service/libgodaservice/android_x86_64_shared_core/gen/aidl/frameworks/av/goda/service/aidl/android/hardware/

这里面包含编译后的bnbp和 Ixxx 接口文件

 如果想了解其中的代码可参考

Android Binder(C++版本例子)_we1less的博客-CSDN博客

package android.hardware;

import android.hardware.IGodaServiceListener;

interface IGodaService
{
    const int ERROR_PERMISSION_DENIED = 9001;
    const int ERROR_DISCONNECTED = 9002;
    const int ERROR_TIMED_OUT = 9003;

    int getNumberOfGoda(int type);

    void registerListener(IGodaServiceListener listener);

    void removeListener(IGodaServiceListener listener);

    //oneway 客户端调用后立即返回
    //in 是对于服务端来讲的 站在服务端的角度上
    //in 代表数据流向服务端 并代表服务端无法修改传递进来的参数
    //out
    oneway void notifyMessage(int type, in String msg);
}

 IGodaServiceListener.aidl    回调类

package android.hardware;

interface IGodaServiceListener
{
    const int STATUS_NOT_PRESENT      = 0;
    const int STATUS_PRESENT          = 1;
    const int STATUS_UNKNOWN = -1;

    oneway void onStatusChanged(int status, String msg);
}

 GodaService.h

#ifndef ANDROID_GODASERVICE_H
#define ANDROID_GODASERVICE_H

#include <android/hardware/BnGodaService.h>
#include <android/hardware/IGodaService.h>
#include <android/hardware/IGodaServiceListener.h>
#include <binder/BinderService.h>
#include <utils/String16.h>
#include <android/log.h>

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

namespace android {

namespace hardware {

class GodaService :
    public ::android::BinderService<GodaService>,
    public BnGodaService
{
friend class BinderService<GodaService>;
public:
    GodaService();
    ~GodaService();
    static const char* getServiceName() { return "goda"; }
    //_aidl_return 这里我理解就是aidl中的返回
    ::android::binder::Status getNumberOfGoda(int32_t type, int32_t* _aidl_return) override;
    ::android::binder::Status registerListener(const sp<IGodaServiceListener>& listener) override;
    ::android::binder::Status removeListener(const sp<IGodaServiceListener>& listener) override;
    ::android::binder::Status notifyMessage(int32_t type, const String16& msg) override;

// RefBase
    virtual     void        onFirstRef();

public:
    sp<IGodaServiceListener> igsl;

};
}
}

#endif //ANDROID_GODASERVICE_H

GodaService.cpp

#define LOG_TAG "GodaService"

#include "GodaService.h"

using namespace android;

#define STATUS_ERROR(errorCode, errorString) \\
    binder::Status::fromServiceSpecificError(errorCode, \\
            String8::format("%s:%d: %s", __FUNCTION__, __LINE__, errorString))

#define STATUS_ERROR_FMT(errorCode, errorString, ...) \\
    binder::Status::fromServiceSpecificError(errorCode, \\
            String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, \\
                    __VA_ARGS__))


//errorCode
/*
    const int ERROR_PERMISSION_DENIED = 9001;
    const int ERROR_DISCONNECTED = 9002;
    const int ERROR_TIMED_OUT = 9003;
*/

namespace android {
namespace hardware {

void GodaService::onFirstRef()
{
    LOGD("onFirstRef");
}

GodaService::GodaService()
{
    LOGD("GodaService");
}

GodaService::~GodaService()
{
    LOGD("~GodaService");
}

binder::Status GodaService::getNumberOfGoda(int32_t type, int32_t* _aidl_return)
{
    //
    LOGD("service::getNumberOfGoda type == %d", type);
    if(type == ERROR_PERMISSION_DENIED) {
        * _aidl_return = ERROR_PERMISSION_DENIED;
    } else if(type == ERROR_DISCONNECTED) {
        * _aidl_return = ERROR_DISCONNECTED;
    } else {
       return STATUS_ERROR(ERROR_TIMED_OUT, "godv666");
    }
    return binder::Status::ok();
}

binder::Status GodaService::registerListener(const sp<IGodaServiceListener>& listener)
{
    LOGD("service::registerListener");
    if(listener == NULL){
        LOGD("registerListener == null");
        return STATUS_ERROR(ERROR_DISCONNECTED, "registerListener == null");
    }
    igsl = listener;
    return binder::Status::ok();
}

binder::Status GodaService::removeListener(const sp<IGodaServiceListener>& listener)
{
    if(igsl == NULL){
        LOGD("igsl already is null");
        return STATUS_ERROR(ERROR_TIMED_OUT, "igsl already is null");
    }
    if(listener == NULL){
        LOGD("removeListener == null");
        return STATUS_ERROR(ERROR_PERMISSION_DENIED, "removeListener == null");
    }
    igsl = NULL;
    return binder::Status::ok();
}

binder::Status GodaService::notifyMessage(int32_t type, const String16& msg)
{
    String8 msg8 = String8(msg);
    const char *c_msg = msg8.string();
    LOGD("service::notifyMessage msg =  %s", c_msg);
    if(igsl == NULL){
        LOGD("igsl == null");
        return STATUS_ERROR(ERROR_PERMISSION_DENIED, "igsl == null");
    }
    if(type == IGodaServiceListener::STATUS_NOT_PRESENT){
        LOGD("service::STATUS_NOT_PRESENT");
        igsl->onStatusChanged(666, msg);
        LOGD("service::onStatusChanged end");

    } else {
        LOGD("service::else");
        igsl->onStatusChanged(777777, msg);
    }
    return binder::Status::ok();
}

}
}

lib目录准备是用来让java层调用和示范在native层如何使用binder通信

Android.bp

cc_binary {
    name: "libgodaclient",
    srcs: [
        "GodaClients.cpp",
    ],
    shared_libs: [
        "libcutils",
        "libutils",
        "liblog",
        "libbinder",
        "libgodaservice",
    ],

    include_dirs: [
        "./", //用户值定的头文件查找路径
    ],
    vendor: true,
    export_shared_lib_headers: ["libgodaservice"],
    //vendor_available: true,

}

GodaClients.cpp    native层客户端的示例代码

#define LOG_TAG "GodaService"

#include <binder/IBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <android/hardware/IGodaService.h>
#include <android/hardware/BnGodaServiceListener.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>

using namespace android;

namespace android {
namespace hardware {

class GodaServiceListener :public BnGodaServiceListener {
    public :
        bool hasMsg;
    virtual ::android::binder::Status onStatusChanged(int32_t status,
                        const ::android::String16& msg) {
            String8 msg8 = String8(msg);
            const char *c_msg = msg8.string();
            ALOGI("GodaServiceListener onStatusChanged status == %d , msg = %s\\n",status,c_msg);
            hasMsg = true;
            return binder::Status::ok();
    }
};

}
}


int main(int argc,char **argv)
{
    ALOGI("Usage:\\n");
    if(argc < 2){
        ALOGI("Usage:\\n");
        ALOGI("%s hello\\n",argv[0]);
    }

    //getService
    //打开驱动 mmap
    sp<ProcessState> proc(ProcessState::self());

    //获得BpServiceManager
    sp<IServiceManager> sm(defaultServiceManager());
    sp<IBinder> binder =
        sm->getService(String16("goda"));

    if(binder == 0)
    {
        ALOGI("can not get goda service\\n");
        return -1;
    }


    sp<android::hardware::IGodaService> service =
        interface_cast<android::hardware::IGodaService>(binder);

    sp<android::hardware::GodaServiceListener> gsl(new android::hardware::GodaServiceListener());

    if(argc == 2){
        int res;
        ALOGI("client call getNumberOfGoda\\n");
        service->getNumberOfGoda(android::hardware::IGodaService::ERROR_PERMISSION_DENIED, &res);
        ALOGI("client call getNumberOfGoda == %d\\n", res);

    } else if(argc == 3){
        //void registerListener(IGodaServiceListener listener);
        //oneway void notifyMessage(int type, in String msg);

        ALOGI("client call registerListener\\n");
        service->registerListener(gsl);
        ALOGI("client call notifyMessage\\n");
        String16 msg = String16("goda666");
        service->notifyMessage(android::hardware::IGodaServiceListener::STATUS_NOT_PRESENT, msg);
    }

    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    ALOGI("client exit\\n");

    return 0;
};



build/target/product/core_base.mk   还要在对应的包文件中加入这几个库

# godv modules
PRODUCT_PACKAGES += \\
    libgodaservice \\
    libgodaclient \\
    godaservice

最后附上执行效果 

 

以上是关于Android Binder (可以直接写在项目中的写法)的主要内容,如果未能解决你的问题,请参考以下文章

Android 使用binder访问service的方式

Android binder学习一:主要概念

Binder机制概述

基于binder的跨进程通讯之使用AIDL实现Demo

Android Binder机制完全解析

Android aidl Binder框架浅析