Android native进程间通信实例-binder篇之——简单的单工通信
网上找了很多binder相关文章,大部分都是在跟踪binder实现源代码,然后再把框架代码贴出来,看着实在费力。
这篇文章从实际出发,直接用一个案例下手,后续想了解binder相关原理的话,可以参考《深入理解Android》或者其它博客。
如果有疑问可以在下方评论,博主会根据自己的认知程度来回复的。
(小提示:要会使用binder通信,其实只需要了解binder通信有一个服务端和客户端,服务端创建特定字符串,然后客户端通过这个特定字符串找到服务端,进行客户端对服务端的通信。)
1. 代码共享
话不多说直接贴上已经经过调试ok的代码,代码不过50行,看起来应该不那么费力吧!
a. 首先是服务端Android.mk代码:
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) #需要编译的cpp文件
LOCAL_SRC_FILES:= mybinderserver.cpp LOCAL_C_INCLUDES := \
external/skia/include/core \
bionic \
external/stlport/stlport #编译为可执行文件
LOCAL_MODULE:= mybinderserver LOCAL_MODULE_TAGS := optional #添加依赖库一定要有libbinder
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libgui \
libskia \
libui include $(BUILD_EXECUTABLE)
b. 然后是服务端mybinderserver.cpp代码:
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/IInterface.h> #include<stdio.h> #define LOG_TAG "binderserver" using namespace android; class MyBinderService : public BBinder{
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
printf("MyBinderService onTransact code = %d\n", code); if(code == 123)
{
int readInt = 0; readInt = data.readInt32(); printf("MyBinderService onTransact readInt = %d\n", readInt); reply->writeInt32(234);
}
printf("return NO_ERROR\n"); return NO_ERROR;
}
}; int main(int argc, char** argv)
{
sp<IBinder> serverBinder = new MyBinderService(); defaultServiceManager()->addService(String16("mybindertag"), serverBinder); printf("main addService \n"); sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool(); printf("never return!!! \n");
return 0;
}
c. 然后是客户端Android.mk:
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) #需要编译的cpp文件
LOCAL_SRC_FILES:= mybinderclient.cpp LOCAL_C_INCLUDES := \
external/skia/include/core \
bionic \
external/stlport/stlport #编译为可执行文件
LOCAL_MODULE:= mybinderclient #LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := optional #添加依赖库一定要有libbinder
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libgui \
libskia \
libui include $(BUILD_EXECUTABLE)
d. 最后是客户端mybinderclient.cpp代码:
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/IInterface.h>
#include<stdio.h> #define LOG_TAG "binderclient" using namespace android; int main(int argc, char** argv)
{
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->checkService(String16("mybindertag")); if (binder == 0)
{
printf("service is not found !\n");
return 0;
}
else
{
sp<IBinder> binder = defaultServiceManager()->getService(String16("mybindertag"));
}
while(1)
{
Parcel data, reply; int transCode = 0;
int writeInt = 0;
int replyInt = 0; printf("please input transCode : \n");
scanf("%d", &transCode);
getchar(); if(123 == transCode)
{
printf("please input int you need transfer: \n");
scanf("%d", &writeInt);
getchar();
data.writeInt32(writeInt);
}
binder->transact(transCode, data, &reply); replyInt = reply.readInt32();
printf("get reply data = %d\n", replyInt); }
return 0;
}
e. 编译这两个文件,把可执行文件mybinderserver和mybinderclient通过adb push 推入到设备的/system/bin目录下,
有的新手可能不了解怎么编译可执行文件,这里稍微科普一下操作方法,比如以mybinderserver为例吧,
在 frameworks\base\cmds 创建相应的文件夹mybinderserver,把Android.mk和mybinderserver.cpp拷贝进去
编译的时候
1. 执行. build/envsetup.sh
2. lunch 选择对应的版本
3. mmm frameworks/base/cmds/mybinderserver/
4. adb root
5. adb remount
6. adb push out/target/product/rk3368/system/bin/mybinderserver system/bin
同理mybinderclient 也是这样操作。
f. 打开两个终端,进入adb shell
首先服务端执行可执行文件:mybinderserver
然后客户端执行可执行文件:mybinderclient 输入相应指令,通过printf输出可知通信数据传输正常。

2. 源码分析
a. 服务端
从main函数开始看,这里会new一个继承BBinder的类,名字叫做MyBinderService,然后addService里面填参数,一个是标识服务的字符串mybindertag,还有一个就是传输数据会用到的MyBinderService类。
然后通过下面三行,加入到线程池中,让这个可执行文件不会返回退出。
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
MyBinderService类中,会实现onTransact,这个是标准接口来着,status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
1. code 是标识传输的标志,一般服务端会用switch语句来处理多个code数据处理请求,我这里就简单用if语句判断code然后做相关操作。
2. Parcel 这个数据类用于binder传输,它的实现在framework/native/libs/binder下面,后续会介绍实现大块数据传输的案例,目前只是做int类型的传输。
其中data里面包含了传输的数据,可以通过readInt32读出数据,reply用来反馈,这里用writeInt32来写数据。
3. flags 有多个,目前用默认的阻塞模式,这样能够保证数据传输的完整性,可以看我的客户端程序,没有传参数,一般可以传IBinder::FLAG_ONEWAY,这样保证了传输速度,但是有掉数据的风险。
b. 客户端
1. 首先确认能否在系统的binder服务列表中寻找到以 mybindertag 为标识的服务。用到了checkService。
2. 然后再getService,返回给一个本地创建的 binder 指针,接着就可以用这个 binder 指针做传输数据了。
3. 同样是用Parcel 这个数据类,writeInt32写数据,写完以后通过binder->transact(transCode, data, &reply);来传输数据。
刚才说了在onTransact的第四个参数可以默认不填,但是有些情况下要完成特地功能,比如传输要保证速度可以这样传 binder->transact(transCode, data, &reply, IBinder::FLAG_ONEWAY); 有掉数据的风险,慎用。
最后推荐一个调试 binder服务的命令:service 。

如果是系统服务还可以直接命令行通信service call xxx 具体用法可以参考网上其它案例,我写的服务是临时创建的服务,没有注册到系统服务中,所以不能用service call来调试。
基本实现就是这样了,希望大家多多吐槽,大家一起共同进步!!
Android native进程间通信实例-binder篇之——简单的单工通信的更多相关文章
- Android native进程间通信实例-binder篇之——HAL层访问JAVA层的服务
有一天在群里聊天的时候,有人提出一个问题,怎样才能做到HAL层访问JAVA层的接口?刚好我不会,所以做了一点研究. 之前的文章末尾部分说过了service call 可以用来调试系统的binder服务 ...
- Android native进程间通信实例-binder篇之——解决实际问题inputreader内建类清楚缓存
我在实际开发中,遇到一个问题,在电容屏驱动中没有发送input_sync 给上层,导致电容屏有的数据缓存在inputreader 中,会导致系统一系列奇怪问题发生, 至于为什么驱动不发送input_s ...
- Android native进程间通信实例-binder篇之——用parcel传输数组
和之前稍微不同,这次要稍微分析一下 Parce.cpp 和 android_os_Parcel.cp p的源码,为的是能够掌握调试技巧,后续传输其它类型数据就能举一反三了! 1. 代码共享 这次 ...
- Android native进程间通信实例-binder结合共享内存
在android源码的驱动目录下,一般会有共享内存的相关实现源码,目录是:kernel\drivers\staging\android\ashmem.c.但是本篇文章不是讲解android共享内存的功 ...
- Android native进程间通信实例-socket本地通信篇之——服务端进程异常退出解决办法
导读: 好难受啊,为什么服务端说挂就挂,明明只是客户端关闭而已,服务端怎么能挂呢? 想想,如果手机上使用一个聊天程序的时候,手机端关闭了聊天程序,那么远端服务器程序总不能说挂就挂吧!所以一定要查明真相 ...
- Android native进程间通信实例-socket本地通信篇之——基本通信功能
导读: 网上看了很多篇有关socket本地通信的示例,很多都是调通服务端和客户端通信功能后就没有下文了,不太实用,真正开发中遇到的问题以及程序稳定性部分没有涉及,代码健壮性不够,本系列(socket本 ...
- 【Android】进程间通信IPC——Binder
Binder是Android中的跨进程通信方式,bindService的时候,服务端返回Binder对象,通过该对象客户端可以从服务端获取数据.在进程间通信IPC——AIDL中创建了ICustomAi ...
- python网络编程之最简单的单工通信
tcp_server.py from socket import * server = socket(AF_INET, SOCK_STREAM) server.bind(('',12345)) ser ...
- Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6642463 在前面几篇文章中,我们详细介绍了A ...
随机推荐
- Android 平台下Ftp 使用模拟器需要注意的问题
以下代码在pc上测试通过,可是在android模拟器上就不工作,不过还可以链接到服务器但不能得到文件 纠结了半天,原来是模式的问题,具体请Google 模拟器中采用建议被动模式 public void ...
- 图像处理与计算机视觉的 topics
光学图像(optical image): the apparent reproduction of an object, formed by a lens or mirror system from ...
- C#中正则表达式使用介绍
摘要:本文给出了在C#下利用正则表达式实现字符串搜索功能的方法,通过对.NET框架下的正则表达式的研究及实例分析,总结了正则表达式的元字符.规则.选项等. 关键字:正则表达式.元字符.字符串.匹配 1 ...
- MySQL复制slave服务器死锁案例
原文:MySQL复制slave服务器死锁案例 MySQL复制刚刚触发了一个bug,该bug的触发条件是slave上Xtrabackup备份的时候执行flushs tables with read lo ...
- python 教程 第二十章、 数据库编程
第二十章. 数据库编程 环境设置 1).安装MySQL-python http://www.lfd.uci.edu/~gohlke/pythonlibs/ MySQL-python-1.2.3.win ...
- WPF 自定义的图表(适用大量数据绘制)下
原文:WPF 自定义的图表(适用大量数据绘制)下 上一篇文章中讲了WPF中自定义绘制大量数据的图标,思路是先将其绘制在内存,然后一次性加载到界面,在后续的调试过程中,发现当数据量到达10W时,移动鼠标 ...
- INCORRECT PERMISSIONS ON /USR/LIB/PO1KIT-AGENT-HELPER-1(NEEDS TO BE SETUID ROOT)
INCORRECT PERMISSIONS ON /USR/LIB/PO1KIT-AGENT-HELPER-1(NEEDS TO BE SETUID ROOT) # sudo chmod +s /us ...
- Delphi中返回类型为string的函数的一个陷阱(不是很懂)
如果类的一个成员函数的返回值是string类型,需要注意一个问题 其返回值可能是错误的 例如函数的实现如下 function GetString( s: string ): string;begin ...
- 深入理解Amazon Alexa Skill(四)
本节利用三星Smartthings Classic物联网平台的web service smartapp,实现了一个Alexa智能家居skill的例子,由此来了解Alexa是如何控制其他云的智能家居设备 ...
- CentOS7下Docker安装
Docker现在有CE和EE版本 , CE版本是免费版本 , 该文档安装的就是CE版本 1.删除旧版本docker 保险起见 , 走流程 yum remove docker \ docker-clie ...