测试利用Binder进行双向通信

双向通信对于数据来说是很常见的,例如:
有service提供了数据服务功能,client可以通过该service的代理向service发送开始传输、停止传输或者相应的数据格式的要求。service可以据情况进行处理,这是属于service被动响应client的模式,那service如果有数据以后,该如何实时的传递回给client?
一种方式是由client不停的轮询,这个效率低了;
另一个方式是在client开辟一个数据接收服务,在service有数据的时候,主动发送到这个数据接收服务。

在基于binder机制的情况下,client在与service通信的时候,可以把这个数据接收服务的相关信息发给service,service在它那边构建代理,有数据的时候,通过这个数据代理将数据发给数据接收服务。
具体用到的技术是writestrongbinder。
注意,这个数据接收服务,也要基于binder的继承结构,就相当于是另一个service。这种service是没有发布的,不能通过servicemanager找到,是匿名service。

下面是测试情况:

这里写图片描述

代码如下:
要注意,在客户端也要有空闲线程可以处理来自service的数据回调。否则,那个回调会无法得到处理。看那个TestEchoClient.cpp的写法。

IEchoService.h

/*
 * IEchoService.h
 *
 *  Created on: Nov 27, 2015
 *      Author: zzz
 */

#ifndef BINDER_TESTS_ECHOSERVICE_IECHOSERVICE_H_
#define BINDER_TESTS_ECHOSERVICE_IECHOSERVICE_H_

#include <binder/IInterface.h>
#include <binder/IMemory.h>
#include <binder/Parcel.h>

#include <IEchoCallback.h>

namespace android {

class IEchoService: public IInterface
{
public:
    DECLARE_META_INTERFACE(EchoService);

    virtual void    sayhello(size_t size,const char* name)=0;

    virtual status_t connect(const sp<IEchoCallback>& echoCallback) = 0;

};

class BnEchoService: public BnInterface<IEchoService>
{
public:
    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                uint32_t flags = 0);
};

}   // namespace android


#endif /* BINDER_TESTS_ECHOSERVICE_IECHOSERVICE_H_ */

IEchoService.cpp

/*
 * IEchoService.cpp
 *
 *  Created on: Nov 27, 2015
 *      Author: zzz
 */



#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
#include <IEchoService.h>
#include <IEchoCallback.h>

namespace android {

enum {
    SAY_HELLO = IBinder::FIRST_CALL_TRANSACTION,
    SAY_GOODBYE,
    CONNECT,
};

class BpEchoService : public BpInterface<IEchoService>
{
public:
    BpEchoService(const sp<IBinder>& impl)
        : BpInterface<IEchoService>(impl)
    {
    }

    virtual void sayhello(size_t size,const char* name) {
         Parcel data, reply;
         data.writeInterfaceToken(IEchoService::getInterfaceDescriptor());
         data.writeInt64((int64_t) size);
         data.writeCString(name);
         status_t status  = remote()->transact(SAY_HELLO, data, &reply);
         size_t ret_size=(size_t)reply.readInt64();
         printf("in BpEchoService.ret_size=%d\n",ret_size);
         const char* ret_name=reply.readCString();
         printf("in BpEchoService.ret_name=%s\n",ret_name);
    }

    virtual status_t connect(const sp<IEchoCallback>& echoCallback) {
        Parcel data, reply;
        data.writeInterfaceToken(IEchoService::getInterfaceDescriptor());
        data.writeStrongBinder(IInterface::asBinder(echoCallback.get()));

        status_t status;
        status = remote()->transact(CONNECT, data, &reply);
        if (status != OK) return status;

        status = reply.readInt32();
        if (reply.readInt32() != 0) {
            printf("BpEchoService::connect status=%d\n",status);
        }
        return status;
    }

};

IMPLEMENT_META_INTERFACE(EchoService, "android.test.IEchoService");

// ----------------------------------------------------------------------

status_t BnEchoService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {

        case SAY_HELLO: {
            CHECK_INTERFACE(IEchoService, data, reply);
            size_t size = (size_t) data.readInt64();
            const char *name = data.readCString();
            sayhello(size, name);
            reply->writeInt64((int64_t)size);
            reply->writeCString(name);
            return NO_ERROR;
        }case CONNECT:{
            CHECK_INTERFACE(IEchoService, data, reply);
            //读取strongbinder
            sp<IEchoCallback> echoCallback =
                    interface_cast<IEchoCallback>(data.readStrongBinder());
            status_t status = connect(echoCallback);
            reply->writeInt32(status);
            reply->writeInt32(1);
            return NO_ERROR;
        }

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

// ----------------------------------------------------------------------------

} // namespace android

IEchoCallback.h

/*
 * IEchoCallback.h
 *
 *  Created on: Nov 27, 2015
 *      Author: zzz
 */

#ifndef BINDER_TESTS_ECHOSERVICE_IECHOCALLBACK_H_
#define BINDER_TESTS_ECHOSERVICE_IECHOCALLBACK_H_

#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/IMemory.h>

namespace android{

class IEchoCallback : public IInterface{
public:
        DECLARE_META_INTERFACE(EchoCallback);
         virtual void            notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
         virtual void            dataCallback(int32_t msgType, const sp<IMemory>& data) = 0;
};

class BnEchoCallback: public BnInterface<IEchoCallback>{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};

}

#endif /* BINDER_TESTS_ECHOSERVICE_IECHOCALLBACK_H_ */

IEchoCallback.cpp

/*
 * IEchoCallback.cpp
 *
 *  Created on: Nov 27, 2015
 *      Author: zzz
 */

#define LOG_TAG "IEchoCallback"
#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Timers.h>
#include "IEchoCallback.h"

namespace android {

enum {
    NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
    DATA_CALLBACK,
    DATA_CALLBACK_TIMESTAMP,
};

class BpEchoCallback: public BpInterface<IEchoCallback>
{
public:
    BpEchoCallback(const sp<IBinder>& impl)
        : BpInterface<IEchoCallback>(impl)
    {
    }

    // generic callback from camera service to app
    void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
    {
        ALOGV("BpEchoCallback::notifyCallback");
        Parcel data, reply;
        data.writeInterfaceToken(IEchoCallback::getInterfaceDescriptor());
        data.writeInt32(msgType);
        data.writeInt32(ext1);
        data.writeInt32(ext2);
        remote()->transact(NOTIFY_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
    }

    // generic data callback from camera service to app with image data
    void dataCallback(int32_t msgType, const sp<IMemory>& imageData)
    {
        ALOGV("dataCallback");
        Parcel data, reply;
        data.writeInterfaceToken(IEchoCallback::getInterfaceDescriptor());
        data.writeInt32(msgType);
        data.writeStrongBinder(IInterface::asBinder(imageData));
        remote()->transact(DATA_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
    }

    // generic data callback from camera service to app with image data
    void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& imageData)
    {
        ALOGV("dataCallbackTimestamp");
        Parcel data, reply;
        data.writeInterfaceToken(IEchoCallback::getInterfaceDescriptor());
        data.writeInt64(timestamp);
        data.writeInt32(msgType);
        data.writeStrongBinder(IInterface::asBinder(imageData));
        remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
    }
};

IMPLEMENT_META_INTERFACE(EchoCallback, "android.test.IEchoCallback");

// ----------------------------------------------------------------------

status_t BnEchoCallback::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        case NOTIFY_CALLBACK: {
            printf("--------------------BnEchoCallback::onTransact recv NOTIFY_CALLBACK!!!!!!!\n");
            ALOGV("NOTIFY_CALLBACK");
            CHECK_INTERFACE(IEchoCallback, data, reply);
            int32_t msgType = data.readInt32();
            int32_t ext1 = data.readInt32();
            int32_t ext2 = data.readInt32();
            notifyCallback(msgType, ext1, ext2);
            return NO_ERROR;
        } break;
        case DATA_CALLBACK: {
            ALOGV("DATA_CALLBACK");
            CHECK_INTERFACE(IEchoCallback, data, reply);
            int32_t msgType = data.readInt32();
            sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());

            dataCallback(msgType, imageData);

            return NO_ERROR;
        } break;
        case DATA_CALLBACK_TIMESTAMP: {
            ALOGV("DATA_CALLBACK_TIMESTAMP");
            CHECK_INTERFACE(IEchoCallback, data, reply);
            nsecs_t timestamp = data.readInt64();
            int32_t msgType = data.readInt32();
            sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());

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

// ----------------------------------------------------------------------------

}; // namespace android

EchoService.h

/*
 * EchoService.h
 *
 *  Created on: Nov 27, 2015
 *      Author: zzz
 */

#ifndef BINDER_TESTS_ECHOSERVICE_ECHOSERVICE_H_
#define BINDER_TESTS_ECHOSERVICE_ECHOSERVICE_H_


#include <binder/BinderService.h>
#include <IEchoService.h>

namespace android {

class EchoService : public BinderService<EchoService>, public BnEchoService
{
    friend class BinderService<EchoService>;    // for MediaLogService()
public:
    EchoService() : BnEchoService() { }
    virtual ~EchoService() { }
    virtual void onFirstRef() { }

    static const char*  getServiceName() { return "echo"; }

    virtual void        sayhello(size_t size, const char *name);
    virtual status_t connect(const sp<IEchoCallback>& echoCallback);
    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                uint32_t flags);

    sp<IEchoCallback> echoCallback;
private:

//    void test_fcn();
};

}   // namespace android



#endif /* BINDER_TESTS_ECHOSERVICE_ECHOSERVICE_H_ */

EchoService.cpp

/*
 * EchoService.cpp
 *
 *  Created on: Nov 27, 2015
 *      Author: zzz
 */

#define LOG_TAG "EchoServiceServer"
//#define LOG_NDEBUG 0

#include <sys/mman.h>
#include <utils/Log.h>
#include <binder/PermissionCache.h>
#include <private/android_filesystem_config.h>
#include "EchoService.h"

#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
#include <functional>
#include <atomic>

namespace android {



void* test_fcn(void* arg){
    std::this_thread::sleep_for(std::chrono::milliseconds(1000*3));
    EchoService * service=(EchoService * )arg;
    for (int i = 0; i < 5; ++i) {
        std::cout << ">>>>>>>>>>>>>>>>>>>Thread  executing :"<<i<<std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(1000*2));

        service->echoCallback->notifyCallback(1,1,1);
    }
}
void EchoService::sayhello(size_t size, const char *name){

     printf("in echoservice::sayhello.size=%d,name=%s\n",size,name);

}

status_t EchoService::connect(const sp<IEchoCallback>& echoCallback){

    //创建一个定时线程,定时回调接口
     printf("-----------------------------------------in echoservice::connect.will invoke notifyCallback\n");

     this->echoCallback=echoCallback;


     //创建新线程
//   std::thread t1(test_fcn,this);

     pthread_t tid;
     pthread_create(&tid,NULL,&test_fcn,this);
     return NO_ERROR;
}


status_t EchoService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
        uint32_t flags)
{
    return BnEchoService::onTransact(code, data, reply, flags);
}

}

EchoClient.h

/*
 * EchoClient.h
 *
 *  Created on: Dec 1, 2015
 *      Author: zzz
 */

#ifndef BINDER_TESTS_ECHOSERVICE_ECHOCLIENT_H_
#define BINDER_TESTS_ECHOSERVICE_ECHOCLIENT_H_


#include <IEchoCallback.h>
namespace android{
class EchoClient:public BnEchoCallback{
public:
    void            notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);
    void            dataCallback(int32_t msgType, const sp<IMemory>& data);
    void connect();
    void disconnect();

    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                uint32_t flags);
};



}


#endif /* BINDER_TESTS_ECHOSERVICE_ECHOCLIENT_H_ */

EchoClient.cpp

/*
 * EchoClient.cpp
 *
 *  Created on: Dec 1, 2015
 *      Author: zzz
 */




#include <EchoClient.h>
#include <binder/IServiceManager.h>
#include <EchoService.h>

namespace android{
void            EchoClient::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {

    printf("---------------------------EchoClient::notifyCallback....\n");
}
void            EchoClient::dataCallback(int32_t msgType, const sp<IMemory>& data) {
    printf("-------------------------------------------EchoClient::dataCallback....\n");
}


void EchoClient::connect(){
    printf("--------------------------EchoClient::connect begin\n");
    sp<IServiceManager> sm(defaultServiceManager());

        sp<IBinder> binder = sm->getService(String16(EchoService::getServiceName()));
        if (binder == nullptr) {
            printf("get null binder !!!! \n");
            return ;
        }
        sp<IEchoService> proxyBinder = interface_cast<IEchoService>(binder);

        printf("------------------------------before EchoClient::connect proxyBinder->connect(client);...\n");
        sp<EchoClient> client=new EchoClient();
        proxyBinder->connect(client);
        printf("------------------------------after EchoClient::connect proxyBinder->connect(client);...\n");


}

void EchoClient::disconnect(){

}
status_t EchoClient::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
        uint32_t flags)
{
    printf("--------------------- EchoClient::onTransact\n");
    return BnEchoCallback::onTransact(code, data, reply, flags);
}

}

EchoMain.cpp

/*
 * EchoMain.cpp
 *
 *  Created on: Nov 27, 2015
 *      Author: zzz
 */



#include <EchoService.h>

using namespace android;


int main(int argc,char** argv){
    EchoService echoService;
    echoService.instantiate();

    printf("---------------------------------------------------after instantiate...\n");


//  while(1){
//      sleep(1);
//  }

    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}

Makefile


ROOT_DIR=$(PWD)
CC = $(ARCH)gcc
LD = $(ARCH)ld
AS = $(ARCH)as
CPP = $(ARCH)g++
AR = $(ARCH)ar


OUT_TARGET_DIR:=/home/zzz/workspace/practice/out/

LOCAL_PATH := `PWD`


##-------libecho---------------------##

LOCAL_SRC_FILES :=IEchoService.cpp IEchoCallback.cpp

LOCAL_SHARED_LIBRARIES := libbinder libutils liblog 

LOCAL_32_BIT_ONLY := true


CPPFLAGS:=-I. -I../../../../include

OBJS:=$(patsubst %.cpp,%.o,$(LOCAL_SRC_FILES))

$(OBJS):%.o:%.cpp
    $(CPP) -c -o $@ -c $< $(LOCAL_CFLAGS) $(CPPFLAGS)  -std=c++11

shared_lib:IEchoService.o IEchoCallback.o
    $(CPP) -fPIC -o libecho.so $(OBJS) -shared 
    @cp libecho.so $(OUT_TARGET_DIR)
    @cp libecho.so /nfs/bindertest/


#---------echoservice---------------------##
LOCAL_SERVER_FILES :=EchoService.cpp EchoMain.cpp
CPPFLAGS:=-I. -I../../../../include
SERVER_OBJS:=$(patsubst %.cpp,%.o,$(LOCAL_SERVER_FILES))
$(SERVER_OBJS):%.o:%.cpp
    $(CPP) -c -o $@ -c $< $(LOCAL_CFLAGS) $(CPPFLAGS) -std=c++11 

echoserver:$(SERVER_OBJS)
    $(CPP) -o $@ $(SERVER_OBJS)  -lpthread  -L$(OUT_TARGET_DIR) -lecho -lbinder -llog -lcutils -lutils -lcorebase  
    @cp $@ /nfs/bindertest

#---------client---------------------------------##
LOCAL_TEST_CLIENT_FILES:=TestEchoClient.cpp EchoClient.cpp

TEST_CLIENT_OBJS:=$(patsubst %.cpp,%.o,$(LOCAL_TEST_CLIENT_FILES))
$(TEST_CLIENT_OBJS):%.o:%.cpp
    $(CPP) -c -o $@ -c $< $(LOCAL_CFLAGS) $(CPPFLAGS) -std=c++11 


testechoclient:$(TEST_CLIENT_OBJS)
    $(CPP) -o $@ $(TEST_CLIENT_OBJS) -L$(OUT_TARGET_DIR) -lecho -lbinder -llog -lcutils -lutils -lcorebase
    @cp $@ /nfs/bindertest

.PHONY:clean
clean:
    rm *.o *.so

TestEchoClient.cpp

/*
 * EchoClient.cpp
 *
 *  Created on: Nov 27, 2015
 *      Author: zzz
 */



#include <EchoService.h>

#include <EchoClient.h>
using namespace android;

int main(int argc,char** argv){

//  sp<IServiceManager> sm(defaultServiceManager());
//
//  sp<IBinder> binder = sm->getService(String16(EchoService::getServiceName()));
//  if (binder == nullptr) {
//      printf("get null binder !!!! \n");
//      return -1;
//  }
//  sp<IEchoService> proxyBinder = interface_cast<IEchoService>(binder);
//
//  char* msg="messsage";
//    proxyBinder->sayhello(strlen(msg),msg);


    ///持有一个callback,持续接收来自service的数据

    printf("------------------------------before client.connect()\n");
    EchoClient client;
    client.connect();


    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();


    printf("\nclient quit...\n");
}


正常的输出结果为:

binder: 1098:1102 BC_TRANSACTION 80 -> 1101 - node 74, data 00cf6510-  (null) size 76-0
binder_transaction::reply=0. before loop:  for (; offp(0xe1600074) < off_end(0xe1600074); offp++) {
binder: 1101:1103 BR_TRANSACTION 80 0:0, cmd -2144833022size 76-0 ptr b6b8a028-b6b8a074
>>>>>>>>>>>>>>>>>>>Thread  executing :4binder: 1101 buffer release 80, size 76-0, failed at   (null)

--------------------- EchoClient::onTransact
--------------------BnEchoCallback::onTransact recv NOTIFY_CALLBACK!!!!!!!
---------------------------EchoClient::notifyCallback....



binder: 1098:1102 BC_TRANSACTION 81 -> 1101 - node 74, data 00cf6510-  (null) size 76-0
binder_transaction::reply=0. before loop:  for (; offp(0xe1600074) < off_end(0xe1600074); offp++) {
binder: 1101:1101 BR_TRANSACTION 81 0:0, cmd -2144833022size 76-0 ptr b6b8a028-b6b8a074
binder_free_thread begin
binder_release_work  begin...
--------------------- EchoClient::onTranbinder: 1101 buffer release 81, size 76-0, failed at   (null)
sact
--------------------BnEchoCallback::onTransact recv NOTIFY_CALLBACK!!!!!!!
---------------------------EchoClient::notifyCallback....

如果是客户端线程不足(只有主线程在那里sleep的话),则是这样的:binder: undelivered transaction 48


>>>>>>>>>>>>>>>>>>>Thread  executing :0
binder: 1088:1093 BC_TRANSACTION 48 -> 1092 - node 45, data 01ee9138-  (null) size 76-0
binder_transaction::reply=0. before loop:  for (; offp(0xe13000a4) < off_end(0xe13000a4); offp++) {
binder_free_thread begin
binder_release_work  begin...

client quit...
binder_deferred_release begin...
binder_free_thread begin
binder_release_work  begin...
binder_release_work  begin...
binder_release_work  begin...
binder: undelivered transaction 48
binder_release_work  begin...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值