Binder是Android系统进程间通信(IPC)常用方式之一,client/service端是通过binder驱动作为通信介质的。Android系统中可以通过binder,实现JAVA/C++层的双向IPC通信,即JAVA - JAVA 、 JAVA - C++ 、 C++ - C++ 都可以通过Binder进行IPC双向通信。
在Android 系统中个,很多模块的service放到了native层,用C++去实现,例如CameraService、SurfaceFlinger等。Client端则可以通过ServiceManger去获取service对象,然后通过AIDL接口进行服务端的调用。至于为什么没有用到JNI,是因为Android系统以及都帮忙做好了,在此只谈应用。
下面举个例子,介绍 客户端(JAVA) 和 服务端(C++)通过 binder(AIDL)实现IPC双向通信用例。
1、创建AIDL文件,可以放在一个公共目录中,以方便client/service端都可以通过mk文件将其编译进去。
再test目录下面 新建aidl目录 aidl\com\test\evs\ ,然后新建两个aidl文件 IEvsTestInterface.aidl (调用) IEvsTestCallback.aidl (回调)
IEvsTestCallback.aidl
package com.test.evs;
interface IEvsTestCallback {
void onEvsStatus(int type, int arg0, int arg1);
void onErrorStatus(int type, int value);
}
IEvsTestInterface.aidl
package com.test.evs;
import com.test.evs.IEvsTestCallback;
interface IEvsTestInterface {
void setCmd(int type, int arg0);
int getStatus(int type, int arg0);
void registerEvsCallback(IEvsTestCallback callback);
}
2、JAVA client端实现
为方便测试,JAVA client端则直接编译成一个apk进行测试。
Test 目录下面创建一个 test_client目录,存放client端的code
MainActivity.java
package com.example.sampletest;
import android.content.Context;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.os.ServiceManager;
import android.app.Activity;
import com.test.evs.IEvsTestInterface;
import com.test.evs.IEvsTestCallback;
public class MainActivity extends Activity {
private static final String TAG = "sampleService";
private static final java.lang.String DESCRIPTOR = "evs.test";
private static final int FUNC_CALLFUNCTION = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
}
private void initData() {
Log.i(TAG, "client initData");
//Parcel _data = Parcel.obtain();
//Parcel _reply = Parcel.obtain();
IBinder binder = ServiceManager.getService(DESCRIPTOR); //服务端对象
if (binder == null) {
Log.d(TAG, "biner get is null");
}
IEvsTestInterface evsInterface = IEvsTestInterface.Stub.asInterface(binder);
if (evsInterface != null) {
try {
evsInterface.registerEvsCallback(callback); // 注册回调
evsInterface.setCmd(1, 100);
Log.d(TAG, "setCmd");
} catch (RemoteException e) {
}
}
Log.i(TAG, "client initData end");
}
private IEvsTestCallback callback = new IEvsTestCallback.Stub() {
@Override
public void onEvsStatus(int type, int arg0, int arg1)
throws RemoteException {
Log.i(TAG, "onEvsStatus " + type + " " + arg0 + " " + arg1);
}
@Override
public void onErrorStatus(int type, int value)
throws RemoteException {
}
};
}
Client 端 mk文件
Android.mk,需要将aidl 文件编译进去,以便生成 .java文件。
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13
LOCAL_STATIC_JAVA_LIBRARIES += android-ex-camera2-portability
LOCAL_STATIC_JAVA_LIBRARIES += xmp_toolkit
LOCAL_STATIC_JAVA_LIBRARIES += glide
LOCAL_STATIC_JAVA_LIBRARIES += guava
LOCAL_STATIC_JAVA_LIBRARIES += jsr305
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/../aidl
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
../aidl/com/test/evs/IEvsTestCallback.aidl \
../aidl/com/test/evs/IEvsTestInterface.aidl \
#LOCAL_SRC_FILES += $(call all-java-files-under, src_pd)
#LOCAL_SRC_FILES += $(call all-java-files-under, src_pd_gcam)
LOCAL_RESOURCE_DIR += \
$(LOCAL_PATH)/res \
LOCAL_PACKAGE_NAME := evsClient
LOCAL_CERTIFICATE := platform
3、native C++ 端
在test目录下面创建 test_server目录,并新建
EvsTestService.h EvsTestService.cpp main.cpp 三个文件
EvsTestService.h,会继承 BnEvsTestInterface 类,它是由AIDL文件在服务端编译生成的。
#ifndef _EVS_TEST_SERVICE_H
#define _EVS_TEST_SERVICE_H
#include
#include
#include
#include
#include
#include
#include
#include
using namespace android;
//using namespace android::notification;
using namespace android::binder;
using namespace std;
namespace android {
class EvsTestService :
public com::test::evs::BnEvsTestInterface,
public IBinder::DeathRecipient
{
public:
EvsTestService();
virtual ~EvsTestService();
virtual binder::Status setCmd(int type, int arg0) override;
virtual binder::Status getStatus(int type, int arg0, int32_t* _aidl_return) override;
virtual binder::Status registerEvsCallback(const ::android::sp<::com::test::evs::IEvsTestCallback>& callback) override;
void sendMsgToClient(int status, int arg0, int arg1);
private:
void binderDied(const wp& who) override;
android::sp<::com::test::evs::IEvsTestCallback> callback_;
std::mutex mutex_;
};
}
#endif
EvsTestService.cpp 文件
#include
#include
#include
#include "EvsTestService.h"
namespace android {
EvsTestService::EvsTestService() {
ALOGI("EvsTestService...");
}
EvsTestService::~EvsTestService() {
}
binder::Status EvsTestService:: setCmd(int type, int arg0) {
ALOGI("setCmd %d, %d\n", type, arg0);
//status_t res;
sendMsgToClient(type, arg0, 101);
return binder::Status::ok();
}
binder::Status EvsTestService::getStatus(int type, int arg0, int32_t* _aidl_return) {
ALOGI("getStatus %d, %d", type, arg0);
*_aidl_return = 1;
return binder::Status::ok();
}
binder::Status EvsTestService::registerEvsCallback(const ::android::sp<::com::test::evs::IEvsTestCallback>& callback) {
//mcallback = callback;
//callback = nullptr;
std::lock_guard < std::mutex > guard(mutex_);
if (callback_.get()) {
ALOGD("Notification>>Failed to register callback, already registered");
return binder::Status::fromStatusT(ALREADY_EXISTS);
}
ALOGD("Notification>>Success to register callback, already registered");
callback_ = callback;
IInterface::asBinder(callback_)->linkToDeath(this);
return binder::Status::ok();
}
void EvsTestService:: sendMsgToClient(int type, int arg0, int arg1) {
if (!callback_.get()) {
ALOGD("Notification>>INotificationGatewayCallback callback_ is null");
return;
}
ALOGD("SendMsgToClient %d, %d, %d", type, arg0, arg1);
binder::Status status = callback_->onEvsStatus(type, arg0, arg1);
}
void EvsTestService::binderDied(const wp& /* who */) {
std::lock_guard < std::mutex > guard(mutex_);
callback_ = nullptr;
}
}
Main.cpp
#include "EvsTestService.h"
#include
#include
#include
#include
#include
#include
#include
int main() {
sp server = new EvsTestService();
sp sm = defaultServiceManager();
EvsTestService* samServ = new EvsTestService();
status_t ret = sm->addService(String16("evs.test"), samServ); //注册服务
ALOGI("Service main addservice %d ", ret);
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool(true);
// while(1);
return 0;
}
Android.mk, 将服务端编译成可执行文件,也需要将aidl文件编译进去。
LOCAL_PATH:= $(call my-dir)
##################################
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13
LOCAL_STATIC_JAVA_LIBRARIES += android-ex-camera2-portability
LOCAL_STATIC_JAVA_LIBRARIES += xmp_toolkit
LOCAL_STATIC_JAVA_LIBRARIES += glide
LOCAL_STATIC_JAVA_LIBRARIES += guava
LOCAL_STATIC_JAVA_LIBRARIES += jsr305
#LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/../aidl \
LOCAL_SRC_FILES := \
EvsTestService.cpp \
main.cpp \
../aidl/com/test/evs/IEvsTestCallback.aidl \
../aidl/com/test/evs/IEvsTestInterface.aidl \
LOCAL_SHARED_LIBRARIES := \
libui \
libgui \
libEGL \
libGLESv2 \
libbase \
libbinder \
libcutils \
libhardware \
libhidlbase \
libhidltransport \
liblog \
libutils \
#LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq
LOCAL_C_INCLUDES += \
system/media/private/camera/include \
frameworks/native/include/media/openmax
#LOCAL_EXPORT_C_INCLUDE_DIRS := \
# frameworks/av/services/camera/libcameraservice
LOCAL_MODULE := evsServer
#LOCAL_MODULE_TAGS := optional
#LOCAL_STRIP_MODULE := keep_symbols
LOCAL_CFLAGS += -DLOG_TAG=\"EvsSample\"
#LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS +=
# NOTE: It can be helpful, while debugging, to disable optimizations
#LOCAL_CFLAGS += -O0 -g
include $(BUILD_EXECUTABLE)
#include $(BUILD_SHARED_LIBRARY)
4、测试
先将服务器进程运行起来,然后在将client的apk 跑起来,查看log。