Android下在C++环境实现native层binder服务

此文章主要目的:在Android 6.0 arm 64位环境下使用C++编程实现binder通讯服务端和客户端

即native层binder服务通讯实现

此例子同时实现了int和string数据通讯接口

Android下在C++环境实现native层binder服务_第1张图片

程序框架图

1.在Android源码目录下存放代码树形结构

development目录下创建相关文件列表

jack_server/
├── Android.mk
├── log.h
├── service
│   ├── Android.mk
│   ├── JACK_Service.cpp
│   └── JACK_Service.h
├── svcclient
│   ├── Android.mk
│   ├── JACK_Client.cpp
│   └── JACK_Client.h
├── svcserver
│   ├── Android.mk
│   └── JACK_server.cpp
└── svctest
    ├── Android.mk
    └── test.cpp

2.首先实现服务端

创建目录service 再创建如下三个文件

JACK_Service.h

#ifndef ANDROID_JACK_SERVICE_H
#define ANDROID_JACK_SERVICE_H

#include 
#include 
#include 

namespace android
{
    class JACK_Service : public BBinder
    {
    private:
        //mutable Mutex m_Lock;
        //int32_t m_NextConnId;

    public:
        static int Instance();
        JACK_Service();
        virtual ~JACK_Service();
        virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);
    };
}

#endif


JACK_Service.cpp

#include 
#include 
#include "JACK_Service.h"
#include "../log.h"

namespace android
{
    //static struct sigaction oldact;
    static pthread_key_t sigbuskey;
    
    int JACK_Service::Instance()
    {
        DebugPrint("JACK_Service Instantiate\n");
        int ret = defaultServiceManager()->addService(
                String16("jack.svc"), new JACK_Service());
        DebugPrint(" JACK_Service ret = %d\n", ret);
        return ret;
    }

    JACK_Service::JACK_Service()
    {
        DebugPrint(" JACK_Service create\n");
        //m_NextConnId = 1;
        pthread_key_create(&sigbuskey,NULL);
    }

    JACK_Service::~JACK_Service()
    {
        pthread_key_delete(sigbuskey);
        DebugPrint(" JACK_Service destory\n");
    }

    status_t JACK_Service::onTransact(uint32_t code, 
                                 const Parcel& data, 
                                 Parcel* reply,
                                 uint32_t flags)
    {
        switch(code)
        {
        case 0: 
            {
                pid_t pid = data.readInt32();
                int num = data.readInt32();
                num += 1000;
                reply->writeInt32(num);
                return NO_ERROR;
            } break;
		case 1: 
            {
                pid_t pid = data.readInt32();
                String8 str = data.readString8();
				DebugPrint(" case 1 = %s \n",str.string());
				String8 add_str = String8("jack_service get ")+str;
                //str = add_str + str;
                reply->writeString8(add_str);
                return NO_ERROR;
            } break;
        default:
            return BBinder::onTransact(code, data, reply, flags);
        }
    }
}
Android.mk

LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=JACK_Service.cpp
LOCAL_SHARED_LIBRARIES:=libutils libbinder
LOCAL_MODULE_TAGS:=optional
LOCAL_MODULE:=libJACK_Service
LOCAL_PRELINK_MODULE:=false
include $(BUILD_SHARED_LIBRARY)


即可通过当前目录下mm 生成 out目录/system/lib64/下libJACK_Service.so 服务端


3.接下来就是启动服务端的应用程序

创建目录svcserver 再创建如下文件

JACK_server.cpp

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "../service/JACK_Service.h"
#include "../log.h"

using namespace android;


int main(int arg, char** argv)
{
    DebugPrint(" server - ain() begin\n");
    sp proc(ProcessState::self());
    sp sm = defaultServiceManager();
    //LOGI("ServiceManager: %p\n", sm.get());
    DebugPrint(" server - erviceManager: %p\n", sm.get());
    int ret = JACK_Service::Instance();
    DebugPrint(" server - JACK_Service::Instance return %d\n", ret);
    ProcessState::self()->startThreadPool();
	IPCThreadState::self()->joinThreadPool();

	return 0;
}

Android.mk

LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=JACK_server.cpp
LOCAL_SHARED_LIBRARIES:=libutils libbinder libJACK_Service
LOCAL_MODULE_TAGS:=optional
LOCAL_MODULE:=JACK_server
include $(BUILD_EXECUTABLE)

当前目录执行mm即可生成out目录/system/bin/下  JACK_server可执行bin文件,在开发板上直接执行即可启动binder服务端

ps进程列表可以看到相关进程


4.客户端的实现

创建目录svcclient再创建相关文件

JACK_Client.h

#ifndef ANDROID_JACK_CLIENT_H
#define ANDROID_JACK_CLIENT_H
#include 

namespace android
{
    class JACK_Client
    {
    public:
        int setN(int n);
		String8 setString8(String8 str);
    private:
        static void getJACK_Service();
    };
}

#endif


JACK_Client.cpp

#include 
#include 
#include "JACK_Client.h"
#include "../log.h"
#include 
namespace android
{
    sp binder;
    
    int JACK_Client::setN(int n)
    {
        getJACK_Service();
        Parcel data, reply;
        data.writeInt32(getpid());
        data.writeInt32(n);
        
        DebugPrint(" client - binder->transact()\n");
        binder->transact(0, data, &reply);
        int r = reply.readInt32();
        return r;
    }
    String8 JACK_Client::setString8(String8 str)
    {
        getJACK_Service();
        Parcel data, reply;//获取或创建Parcel对象
        data.writeInt32(getpid());//写入Parcel数据
        data.writeString8(str);
        //ALOGE("chyj send %s",str.string());
        DebugPrint(" client - binder->transact() send %s \n",str.string());
        binder->transact(1, data, &reply);//通过Binder传递数据 1是函数顺序号,必须对应
        String8 r = reply.readString8();//reply接收数据
		DebugPrint(" setString8 reply %s \n",r.string());
		//ALOGE("chyj reply %s",r.string());
        return r;
    }
    void JACK_Client::getJACK_Service()
    {
        sp sm = defaultServiceManager();
        binder = sm->getService(String16("jack.svc"));
        DebugPrint(" client - etService: %p\n", sm.get());
        if(binder == 0)
        {
            DebugPrint(" JACK_Service not published, waiting...");
            return;
        }
    }

}

Android.mk

LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=JACK_Client.cpp
LOCAL_SHARED_LIBRARIES:=libutils libbinder 
LOCAL_LDLIBS    := -lm -llog #解决undefined reference to `__android_log_print'
LOCAL_MODULE_TAGS:=optional
LOCAL_MODULE:=libJACK_Client
LOCAL_PRELINK_MODULE:=false
include $(BUILD_SHARED_LIBRARY)


当前目录mm编译out目录/system/lib64/下生成 libJACK_Client.so

5.客户端的应用程序实现

创建目录svctest和相关文件

test.cpp

#include 
#include "../svcclient/JACK_Client.h"
#include "../log.h"
#include 

using namespace android;

int main(int argc, char** argv)
{
    JACK_Client client;
	DebugPrint(" start test");
    int ret = client.setN(2017);
    DebugPrint("setN return: %d\n", ret);
	String8 send = String8("hello I'm string");
	String8 str = client.setString8(send);
	DebugPrint("setString8 return: %s\n",str.string());
	//ALOGE("chyj setString8 return %s",str.string());
    return 0;
}

Android.mk

LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=test.cpp
LOCAL_SHARED_LIBRARIES:=libJACK_Client libutils
LOCAL_LDLIBS    := -lm -llog #解决undefined reference to `__android_log_print'
LOCAL_MODULE_TAGS:=optional
LOCAL_MODULE:=JACK_svctest
include $(BUILD_EXECUTABLE)

当前目录mm生成out目录/system/bin/下 JACK_svctest,在板子上执行可执行文件即可和服务端实现通讯

6.最后是整体编译的文件

在最外层目录jack_server创建

log.h用于打印控制调试用

log.h

#define __DEBUG__ 
#define TAG "chyj" 
#ifdef __DEBUG__ //改进方法
#define DebugPrint(fmt,args...) printf("[file:%s fun:%s line:%d tag:%s]: "  fmt  "\n",  __FILE__, __FUNCTION__, __LINE__, TAG, ##args);
#else
#define DebugPrint(fmt,args...) 
#endif

Android.mk

include $(call all-subdir-makefiles)



至此全部代码源码已准备齐全,对应生成文件编译即可实现binder服务在C++环境通讯访问

如果希望开机启动binder服务

可以在init.rc下实现service

service JACK_server /system/bin/JACK_server
     class main
	 oneshot




你可能感兴趣的:(android)