Android native Binder使用实例

Android native Binder使用实例

这篇我们在上节Android native进程的创建实例
建立的native进程中运行一个native服务并使用binder 开放接口给其他进程。

工程目录如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-odEVxLjP-1655887253268)(..\image\企业微信截图_16558809893308.png)]

创建一个模块用作构建共享库,我们的功能主要放在共享库中提供给外部进程

1.首先编写共享库的Android.mk

#vendor/yuwei/NativeProcessDemo/libtestservice/Android.mk
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
	$(call all-cpp-files-under)

LOCAL_SHARED_LIBRARIES := \
	liblog \
	libutils \
	libbinder #由于我们需要使用binder 所以需要libbinder的库

LOCAL_MODULE := libtestservice

#将共享库中的ITestService.h 和 TestService.h 开放出去
LOCAL_EXPORT_C_INCLUDE_DIRS:= vendor/yuwei/NativeProcessDemo/libtestservice

include $(BUILD_SHARED_LIBRARY)

2.定义我们的服务需要提供的接口

// vendor/yuwei/NativeProcessDemo/libtestservice/ITestService.h
#ifndef ITESTSERVICE_H
#define ITESTSERVICE_H

#include <stdio.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/IBinder.h>
#include <binder/Binder.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
using namespace android;
namespace android
{
    class ITestService : public IInterface
    {
    public:
        DECLARE_META_INTERFACE(TestService); // declare macro
        
        enum MessageCodeBits{
            kMessageCodeStart = 0x01,
            kMessageCodeStop = 0x02,
        };

        //这里的 = 0 很关键
        virtual void sendMessage(int32_t message_code,int64_t arg1,int64_t arg2) = 0;
    };
 
    class BnTestService : public BnInterface<ITestService>{

        public:
        virtual status_t onTransact(uint32_t code, 
                                    const Parcel& data, 
                                    Parcel* reply,
                                    uint32_t flags = 0);
    };
}
#endif

我们这里的接口只定义了一个sendMessage可以发送消息给服务端。

3.实现客户端到服务端的数据传输的流程

// vendor/yuwei/NativeProcessDemo/libtestservice/ITestService.h
#include "ITestService.h"
#include <utils/Errors.h>  // for status_t

namespace android{
	//这里的enum 是ITestService.h中定义的接口的大写
	enum
    {
        SENDMESSAGE = IBinder::FIRST_CALL_TRANSACTION,
    };

    //客户端对象
    class BpTestService : public BpInterface<ITestService>{
    	public:
    		//必须有的初始化
			explicit BpTestService(const sp<IBinder>& impl):BpInterface<ITestService>(impl){}
			
			virtual void sendMessage(int32_t message_code,int64_t arg1,int64_t arg2){
			 Parcel data, reply;
			 data.writeInterfaceToken(ITestService::getInterfaceDescriptor());
			 //客户端把传入的数据写到data中
			 data.writeInt32(message_code);
			 data.writeInt64(arg1);
			 data.writeInt64(arg2);
			 ALOGD("data write end");
			 remote()->transact(SENDMESSAGE, data, &reply);
			}
    };

    IMPLEMENT_META_INTERFACE(TestService, "android.ITestService");

    //服务端对象的实现 类是在ITestService.h中定义的

    status_t BnTestService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,uint32_t flags)
	{
		switch(code){
			case SENDMESSAGE:{
				//这里对应上面的writeInterfaceToken
				CHECK_INTERFACE(ITestService,data,reply);
				//服务端将数据从data中读出来
				int32_t message_code = data.readInt32();
				int64_t arg1 = data.readInt64();
				int64_t arg2 = data.readInt64();
				//调用服务端的对应的函数
				sendMessage(message_code,arg1,arg2);
				return NO_ERROR;
			}break;

			default:{
				return BBinder::onTransact(code, data, reply, flags);
			}
		}

	}
}

到这里Binder的架子就打起来了,剩下的就是去实现服务端的功能了

4.实现服务端的功能

// vendor/yuwei/NativeProcessDemo/libtestservice/TestService.h
#ifndef TESTSERVICE_H
#define TESTSERVICE_H

#include "ITestService.h"
namespace android{
	// 实现服务端功能的类
	class TestService : public BnTestService
	{
	public:
		static void instantiate();

		TestService();
		~TestService();

		void sendMessage(int32_t message_code,int64_t arg1,int64_t arg2);
	private:
		void start();
		void stop();
	};

}

#endif


//vendor/yuwei/NativeProcessDemo/libtestservice/TestService.cpp
#define LOG_TAG "TestService"
#define LOG_NDEBUG 0

#include "TestService.h"
#include <binder/IServiceManager.h>

using namespace android;

TestService::TestService(){

}

TestService::~TestService(){
	stop();
}

void TestService::instantiate(){
	defaultServiceManager()->addService(
            String16("myservice"), new TestService());
}

void TestService::sendMessage(int32_t message_code,int64_t arg1,int64_t arg2){
	ALOGD("sendMessage called sendMessage message_code= %02X arg1 = %zu arg2 = %zu",message_code,arg1,arg2);

    if(message_code == ITestService::MessageCodeBits::kMessageCodeStart){
        start();
    }

    if(message_code == ITestService::MessageCodeBits::kMessageCodeStop){
        stop();
    }
}

void TestService::start(){
	ALOGD("TestService start");
}

void TestService::stop(){
	ALOGD("TestService stop");
}

5.将服务运行到我们的进程中

首先需要将我们的共享库加到创建进程中Android.mk中

# vendor/yuwei/NativeProcessDemo/src/Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
       $(call all-cpp-files-under) #使用宏定义Android.mk所在文件夹下所有的cpp文件
LOCAL_SHARED_LIBRARIES := \
          libtestservice \   #我们上面创建的共享库
          libbase \
          libbinder\
	   	  liblog \
	      libutils  # 添加系统的log相关的共享库
	   
LOCAL_MODULE:= myserver # 模块的名称
LOCAL_INIT_RC := myserver.rc # 设置init rc
LOCAL_CFLAGS := -Werror -Wall
include $(BUILD_EXECUTABLE) #编译可执行文件

接着需要在进程中创建服务并将其加到service mananager中

// vendor/yuwei/NativeProcessDemo/src/main_myserver.cpp
#define LOG_TAG "main_myserver"
#define LOG_NDEBUG 0
#include <utils/Log.h>

#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>

#include <TestService.h>


int main(int argc __unused, char **argv __unused)
{
    ALOGD("ir_rtspserver started (pid=%d)", getpid());
    
    signal(SIGPIPE, SIG_IGN);

    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm(defaultServiceManager());
    ALOGD("ServiceManager: %p", sm.get());
    //将binder服务加入service manager的管理
    TestService::instantiate();

    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    ALOGE("main_myserver exit");
}

6.创建一个客户端进程来测试我们的接口

首先新建一个目录 test

接着编写客户端测试进程的Android.mk和cpp文件如下:

# vendor/yuwei/NativeProcessDemo/test/Android.mk
LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := \
	libcutils \
	libutils \
	libbinder \
	liblog \
	libtestservice
 
#生成binder native service的客户端
LOCAL_MODULE := TestServiceClient
LOCAL_SRC_FILES := \
	TestServiceClient.cpp
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)

TestServiceClient.cpp如下:

// vendor/yuwei/NativeProcessDemo/test/TestServiceClient.cpp
#define LOG_TAG "TestServiceClient"
#define LOG_NDEBUG 0
#include <ITestService.h>
#include <utils/Log.h>

#include <binder/Binder.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>

int main()
{
	sp < IServiceManager > sm = defaultServiceManager();
	sp < IBinder > binder = sm->getService(String16("myservice"));
	sp<ITestService> cs = interface_cast <ITestService> (binder);
	ALOGD("Hello test service client\n");
	cs->sendMessage(ITestService::MessageCodeBits::kMessageCodeStart,0,0);
	cs->sendMessage(ITestService::MessageCodeBits::kMessageCodeStop,0,0);
	return 0;
}

这时我们执行 mmm vendor/yuwei/NativeProcessDemo 如果编译成功 那么会有下面这些文件生成

out/target/product/xxxx/system/bin/myserver

out/target/product/xxxx/system/bin/TestServiceClient

out/target/product/xxxx/system/lib/libtestservice.so

out/target/product/xxxx/system/lib64/libtestservice.so

接着把 out/target/product/xxxx/system/lib/libtestservice.so push到system/lib下面

把 out/target/product/xxxx/system/lib64/libtestservice.so push到system/lib64下面

把 out/target/product/xxxx/system/bin/myserver和 out/target/product/xxxx/system/bin/TestServiceClient push到system/bin下面

接着分别运行myserver和TestServiceClient

当运行myserver时会有下面的log出现:

08-03 20:43:26.596  4399  4399 D main_myserver: ir_rtspserver started (pid=4399)
08-03 20:43:26.597  4399  4399 D main_myserver: ServiceManager: 0x7c2643d140

08-03 20:43:27.526  4209  4209 W ServiceManagement: Waited one second for android.hardware.radio@1.0::IRadio/slot1
08-03 20:43:27.528  4209  4209 I ServiceManagement: getService: Trying again for android.hardware.radio@1.0::IRadio/slot1...

当运行TestServiceClient时会有下面的log:

08-03 20:44:40.548  4511  4511 D TestServiceClient: Hello test service client
08-03 20:44:40.548  4511  4511 D         : data write end
08-03 20:44:40.548  4399  4400 D TestService: sendMessage called sendMessage message_code= 01 arg1 = 0 arg2 = 0
08-03 20:44:40.548  4399  4400 D TestService: TestService start
08-03 20:44:40.548  4511  4511 D         : data write end
08-03 20:44:40.548  4399  4400 D TestService: sendMessage called sendMessage message_code= 02 arg1 = 0 arg2 = 0
08-03 20:44:40.548  4399  4400 D TestService: TestService stop

证明代码编写的是没问题的

7.令我们的进程随系统的启动运行

需要我们将上面的编译的两个 可执行文件和共享库都加入到Android的工程项目中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jm3upGej-1655887253269)(..\image\image-20220622153652700.png)]

接着需要设置selinux 按照之前创建native 进程的实例去设置即可 配置完selinux后整编完成后烧到设备上,使用下面的命令查看服务是否启动

adb shell service list 

在这里插入图片描述

出现上面的myservice后就证明你的服务成功启动了,接着可以去 设备的system/bin下找到TestServiceClient 执行以下看是否有对应的log打印

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值