网上找了很多binder相关文章,大部分都是在跟踪binder实现源代码,然后再把框架代码贴出来,看着实在费力。

这篇文章从实际出发,直接用一个案例下手,后续想了解binder相关原理的话,可以参考《深入理解Android》或者其它博客。

如果有疑问可以在下方评论,博主会根据自己的认知程度来回复的。

(小提示:要会使用binder通信,其实只需要了解binder通信有一个服务端和客户端,服务端创建特定字符串,然后客户端通过这个特定字符串找到服务端,进行客户端对服务端的通信。)

1. 代码共享

话不多说直接贴上已经经过调试ok的代码,代码不过50行,看起来应该不那么费力吧!

a. 首先是服务端Android.mk代码:

  1. LOCAL_PATH:= $(call my-dir)
  2.  
  3. include $(CLEAR_VARS)
  4.  
  5. #需要编译的cpp文件
  6. LOCAL_SRC_FILES:= mybinderserver.cpp
  7.  
  8. LOCAL_C_INCLUDES := \
  9. external/skia/include/core \
  10. bionic \
  11. external/stlport/stlport
  12.  
  13. #编译为可执行文件
  14. LOCAL_MODULE:= mybinderserver
  15.  
  16. LOCAL_MODULE_TAGS := optional
  17.  
  18. #添加依赖库一定要有libbinder
  19. LOCAL_SHARED_LIBRARIES := \
  20. libcutils \
  21. libutils \
  22. libbinder \
  23. libgui \
  24. libskia \
  25. libui
  26.  
  27. include $(BUILD_EXECUTABLE)

b. 然后是服务端mybinderserver.cpp代码:

  1. #include <binder/IServiceManager.h>
  2. #include <binder/IPCThreadState.h>
  3. #include <binder/Parcel.h>
  4. #include <binder/IInterface.h>
  5.  
  6. #include<stdio.h>
  7.  
  8. #define LOG_TAG "binderserver"
  9.  
  10. using namespace android;
  11.  
  12. class MyBinderService : public BBinder{
  13. status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
  14. {
  15. printf("MyBinderService onTransact code = %d\n", code);
  16.  
  17. if(code == 123)
  18. {
  19. int readInt = 0;
  20.  
  21. readInt = data.readInt32();
  22.  
  23. printf("MyBinderService onTransact readInt = %d\n", readInt);
  24.  
  25. reply->writeInt32(234);
  26. }
  27. printf("return NO_ERROR\n");
  28.  
  29. return NO_ERROR;
  30. }
  31. };
  32.  
  33. int main(int argc, char** argv)
  34. {
  35. sp<IBinder> serverBinder = new MyBinderService();
  36.  
  37. defaultServiceManager()->addService(String16("mybindertag"), serverBinder);
  38.  
  39. printf("main addService \n");
  40.  
  41. sp<ProcessState> proc(ProcessState::self());
  42. ProcessState::self()->startThreadPool();
  43. IPCThreadState::self()->joinThreadPool();
  44.  
  45. printf("never return!!! \n");
  46. return 0;
  47. }

  

c. 然后是客户端Android.mk:

  1. LOCAL_PATH:= $(call my-dir)
  2.  
  3. include $(CLEAR_VARS)
  4.  
  5. #需要编译的cpp文件
  6. LOCAL_SRC_FILES:= mybinderclient.cpp
  7.  
  8. LOCAL_C_INCLUDES := \
  9. external/skia/include/core \
  10. bionic \
  11. external/stlport/stlport
  12.  
  13. #编译为可执行文件
  14. LOCAL_MODULE:= mybinderclient
  15.  
  16. #LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
  17. LOCAL_MODULE_TAGS := optional
  18.  
  19. #添加依赖库一定要有libbinder
  20. LOCAL_SHARED_LIBRARIES := \
  21. libcutils \
  22. libutils \
  23. libbinder \
  24. libgui \
  25. libskia \
  26. libui
  27.  
  28. include $(BUILD_EXECUTABLE)

 

d. 最后是客户端mybinderclient.cpp代码:

  1. #include <binder/IServiceManager.h>
  2. #include <binder/IPCThreadState.h>
  3. #include <binder/Parcel.h>
  4. #include <binder/IInterface.h>
  5. #include<stdio.h>
  6.  
  7. #define LOG_TAG "binderclient"
  8.  
  9. using namespace android;
  10.  
  11. int main(int argc, char** argv)
  12. {
  13. sp<IServiceManager> sm = defaultServiceManager();
  14. sp<IBinder> binder = sm->checkService(String16("mybindertag"));
  15.  
  16. if (binder == 0)
  17. {
  18. printf("service is not found !\n");
  19. return 0;
  20. }
  21. else
  22. {
  23. sp<IBinder> binder = defaultServiceManager()->getService(String16("mybindertag"));
  24. }
  25. while(1)
  26. {
  27. Parcel data, reply;
  28.  
  29. int transCode = 0;
  30. int writeInt = 0;
  31. int replyInt = 0;
  32.  
  33. printf("please input transCode : \n");
  34. scanf("%d", &transCode);
  35. getchar();
  36.  
  37. if(123 == transCode)
  38. {
  39. printf("please input int you need transfer: \n");
  40. scanf("%d", &writeInt);
  41. getchar();
  42. data.writeInt32(writeInt);
  43. }
  44. binder->transact(transCode, data, &reply);
  45.  
  46. replyInt = reply.readInt32();
  47. printf("get reply data = %d\n", replyInt);
  48.  
  49. }
  50. return 0;
  51. }

 

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 。

就拿 mybinderserver 为例,打开两个终端。其中一个终端运行 mybinderserver。
另一个终端在adb shell 下执行命令:
service list | grep my
发现不用输入完整的 mybinderserver 就筛选出了已经注册的服务mybindertag,下图说明服务已经在运行了。而且这个命令会填写code = 1598968902,应该和命令的实现方式有关,这里不做深究。

如果是系统服务还可以直接命令行通信service call xxx 具体用法可以参考网上其它案例,我写的服务是临时创建的服务,没有注册到系统服务中,所以不能用service call来调试。

基本实现就是这样了,希望大家多多吐槽,大家一起共同进步!!

Android native进程间通信实例-binder篇之——简单的单工通信的更多相关文章

  1. Android native进程间通信实例-binder篇之——HAL层访问JAVA层的服务

    有一天在群里聊天的时候,有人提出一个问题,怎样才能做到HAL层访问JAVA层的接口?刚好我不会,所以做了一点研究. 之前的文章末尾部分说过了service call 可以用来调试系统的binder服务 ...

  2. Android native进程间通信实例-binder篇之——解决实际问题inputreader内建类清楚缓存

    我在实际开发中,遇到一个问题,在电容屏驱动中没有发送input_sync 给上层,导致电容屏有的数据缓存在inputreader 中,会导致系统一系列奇怪问题发生, 至于为什么驱动不发送input_s ...

  3. Android native进程间通信实例-binder篇之——用parcel传输数组

     和之前稍微不同,这次要稍微分析一下 Parce.cpp 和 android_os_Parcel.cp p的源码,为的是能够掌握调试技巧,后续传输其它类型数据就能举一反三了!   1. 代码共享 这次 ...

  4. Android native进程间通信实例-binder结合共享内存

    在android源码的驱动目录下,一般会有共享内存的相关实现源码,目录是:kernel\drivers\staging\android\ashmem.c.但是本篇文章不是讲解android共享内存的功 ...

  5. Android native进程间通信实例-socket本地通信篇之——服务端进程异常退出解决办法

    导读: 好难受啊,为什么服务端说挂就挂,明明只是客户端关闭而已,服务端怎么能挂呢? 想想,如果手机上使用一个聊天程序的时候,手机端关闭了聊天程序,那么远端服务器程序总不能说挂就挂吧!所以一定要查明真相 ...

  6. Android native进程间通信实例-socket本地通信篇之——基本通信功能

    导读: 网上看了很多篇有关socket本地通信的示例,很多都是调通服务端和客户端通信功能后就没有下文了,不太实用,真正开发中遇到的问题以及程序稳定性部分没有涉及,代码健壮性不够,本系列(socket本 ...

  7. 【Android】进程间通信IPC——Binder

    Binder是Android中的跨进程通信方式,bindService的时候,服务端返回Binder对象,通过该对象客户端可以从服务端获取数据.在进程间通信IPC——AIDL中创建了ICustomAi ...

  8. python网络编程之最简单的单工通信

    tcp_server.py from socket import * server = socket(AF_INET, SOCK_STREAM) server.bind(('',12345)) ser ...

  9. Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6642463 在前面几篇文章中,我们详细介绍了A ...

随机推荐

  1. session_start()的逻辑

    //session_start -Start new or resume existing session session_start(); print_r($_SESSION); //看有没有ses ...

  2. .NET 即时通信,WebSocket

    .NET 即时通信,WebSocket 即时通信常用手段 1.第三方平台 谷歌.腾讯 环信等多如牛毛,其中谷歌即时通信是免费的,但免费就是免费的并不好用.其他的一些第三方一般收费的,使用要则限流(1s ...

  3. wpf控件设计时支持(3)

    原文:wpf控件设计时支持(3) wpf设计时调试 编辑模型 装饰器 1.wpf设计时调试 为了更好的了解wpf设计时框架,那么调试则非常重要,通过以下配置可以调试控件的设计时代码 (1)将启动项目配 ...

  4. Windows安装Linux子系统--安装GUI界面

    原文:Windows安装Linux子系统--安装GUI界面   前段时间发现Windows可以安装Linux子系统了,恰逢电脑换了固态,还没装Linux,不如趁机体验一番! 1.准备工作 1.1.打开 ...

  5. Domain adaptation:连接机器学习(Machine Learning)与迁移学习(Transfer Learning)

    domain adaptation(域适配)是一个连接机器学习(machine learning)与迁移学习(transfer learning)的新领域.这一问题的提出在于从原始问题(对应一个 so ...

  6. WPF 自定义图片剪切器 - 头像剪切(扩展与完善、实时截图)

    原文:WPF 自定义图片剪切器 - 头像剪切(扩展与完善.实时截图) 一.说明:上一次写的"WPF 自定义图片剪切器 - 头像剪切.你懂得"存在明显的缺陷,由于篇幅较长.重新写了一 ...

  7. php 二维数组相同值 相加

    array(3) { [0]=> array(2) { ["sourcesid"]=> int(1) ["addusernum"]=> str ...

  8. 1. linux系统简介

    一.Linux是什么 linux位于系统调用和内核的那两层,直观上来看,我们使用的操作系统还包含一些在其上运行的应用程序,包含文本编译器,浏览器,电子邮件. 二.Linux与windows的区别 1. ...

  9. Win10《芒果TV》更新v3.6.0秋收版:新增追剧磁贴、记忆续播、跳转列表

    热血青春,唱响革命战歌,<秋收起义>正在芒果TV热播,Win10版<芒果TV>更新v3.6.0秋收版,新增追剧磁贴.记忆续播.跳转列表. Win10版<芒果TV>V ...

  10. vs2010 编译release没问题debug编译不通过

    ------ 已启动全部重新生成: 项目: VM661JTcpDLL, 配置: Debug Win32 ------生成启动时间为 2018-12-29 14:07:20.项目文件包含 ToolsVe ...