Binder IPC通信中,Binder是通信的媒介,Parcel是通信的內容。远程调用过程中,其参数都被打包成Parcel的形式来传递。

在IPC通信的Proxy端,我们经常可以看到下面类似的代码,一些参数都会打包到Parcel中。看下面的data和reply。

public void publishService(IBinder token,
Intent intent, IBinder service) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
intent.writeToParcel(data, 0);
data.writeStrongBinder(service);
mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}

在IPC通信里,android是通过Parcel类的成员函数writeStrongBinder()向Parcel写入IBinder,再通过mRemote发送出去。

2.writeStrongBinder()

接下來就看一下writeStrongBinder()这个函数里做了什么。
/frameworks/base/core/java/android/os/Parcel.java

public final class Parcel {

/**
* Write an object into the parcel at the current dataPosition(),
* growing dataCapacity() if needed.
*/
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
private static native void nativeWriteStrongBinder(int nativePtr, IBinder val);

}

看,这里又调用了native方法,我们会发现Java 层的一些Parcel其实只是对C/C++层的一个封裝,大部分操作还是依靠JNI去调用Native的操作。
那看一下C++里对应的方法:

/frameworks/base/core/jni/android_os_Parcel.cpp

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}

最主要的就是ibinderForJavaObject 这个函数,继续跟踪代码:

/frameworks/base/core/jni/android_util_Binder.cpp

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL; if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { //mClass指向Java层中的Binder class
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetIntField(obj, gBinderOffsets.mObject);
return jbh != NULL ? jbh->get(env, obj) : NULL; //get() 返回一個JavaBBinder,继承自BBinder
} if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) { //mClass 指向Java层的BinderProxy class
return (IBinder*)
env->GetIntField(obj, gBinderProxyOffsets.mObject); //返回一个BpBinder,mObject是它的地址值
}
ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
return NULL;
}

这个函数呢,就是根据传进来的Java对象找到对应的C++对象,这里的参数obj,可能会指向两种对象:Binder对象或者BinderProxy对象。这两个对象我们在RemoteService那一篇里其实就遇到过了,Binder对象呢就是Service里实现的那个mRemoteBinder,BinderProxy对象呢就是Activity里回调传进来的那个service。

接着说,如果传进來的是Binder对象,那么就会把gBinderOffsets.mObject转化成JavaBBinderHolder, 并从中获得一个JavaBBinder对象。JavaBBinder继承自BBinder。(在RemoteService那一篇,Service会在onBind回调里把mRemoteBinder传给AMS,这里传递的就是Binder对象)

如果传进來的是BinderProxy对象。就会返回一个BpBinder,这个BpBinder的地址值就保存在gBinderProxyOffsets.mObject中。(在RemoteService那一篇,AMS要传递给Acticity的就是BinderProxy对象)。

到这里,你可能会奇怪,为什么Service把Binder对象传递给AMS,后面AMS却是把BinderProxy对象传递给Activity呢?这个我们后面再说,(可以先说一下,其实是因为这些Binder对象都会经过底层传输,那在传输的过程中,Binder模块就会根据不同的情况对这些对象进行转化)

3.readStrongBinder()

同样也是JNI调用:

/frameworks/base/core/jni/android_os_Parcel.cpp

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)
{
...
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
/frameworks/base/core/jni/android_util_Binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) (1)
{
if (val == NULL) return NULL;
if (val->checkSubclass(&gBinderOffsets)) { (2)12 // One of our own!
jobject object = static_cast<JavaBBinder*>(val.get())->object();
LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
return object;
}
...
jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
if (object != NULL) {
jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet); (3)
if (res != NULL) {
ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
return res;
}
...
}
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); (4)
if (object != NULL) {
….
}
return object;
}

(1):这里的val和writeStrongBinder类似,不过是反过来,指向的可能是JavaBBinder或者BpBinder。

(2):如果是JavaBBinder,就会通过成员函数object(),返回一个Java对象,这个对象就是Java层的Binder对象。

(3):如果是BpBinder,那就先查找是否已经存在需要使用的BinderProxy对象,如果找到就返回引用

(4):如果沒找到可用的引用,就new 一个BinderProxy对象。

Parcel在binder通信readStrongBinder和writeStrongBinder的更多相关文章

  1. 笔记:Binder通信机制

    TODO: 待修正 Binder简介 Binder是android系统中实现的一种高效的IPC机制,平常接触到的各种XxxManager,以及绑定Service时都在使用它进行跨进程操作. 它的实现基 ...

  2. C++实例讲解Binder通信

    binder是android里面的通信机制,这就不说它如何如何好了,Goog已经说过了,这里不多说.binder是一个面向对象的编程方法,大量使用虚函数类.最近研究binder看到一网友写的,就借鉴一 ...

  3. 从AIDL开始谈Android进程间Binder通信机制

    转自: http://tech.cnnetsec.com/585.html 本文首先概述了Android的进程间通信的Binder机制,然后结合一个AIDL的例子,对Binder机制进行了解析. 概述 ...

  4. android的Binder通信机制java层浅谈-android学习之旅(88)

    1.Service Manager的Java代理对象 在Java层中,Service Manager的代理对象类型为ServiceManagerProxy.它继承并且实现了IServiceManage ...

  5. 「Android」 基于Binder通信的C/S架构体系认知

    C/S架构(Client/Server,即客户机/服务器模式)分为客户机和服务器两层:第一层是在客户机系统上结合了表示与业务逻辑,第二层是通过网络结合了数据库服务器.简单的说就是第一层是用户表示层,第 ...

  6. Android系统是一个基于BInder通信的C/S架构

    Android系统基本上可以看作是一个基于Binder通信的C/S架构.他有服务器端和客户端.比如自己开发一个程序,肯定是基于Activity的而Activity就是作为客户端,他的服务器端就是Act ...

  7. Binder通信机制介绍

    1.Binder通信机制介绍 这篇文章会先对比Binder机制与Linux的通信机制的差别,了解为什么Android会另起炉灶,采用Binder.接着,会根据 Binder的机制,去理解什么是Serv ...

  8. 图文详解 Android Binder跨进程通信机制 原理

    图文详解 Android Binder跨进程通信机制 原理 目录 目录 1. Binder到底是什么? 中文即 粘合剂,意思为粘合了两个不同的进程 网上有很多对Binder的定义,但都说不清楚:Bin ...

  9. Android 进阶8:进程通信之 Binder 机制浅析

    读完本文你将了解: IBinder Binder Binder 通信机制 Binder 驱动 Service Manager Binder 机制跨进程通信流程 Binder 机制的优点 总结 Than ...

随机推荐

  1. Vue 数据持久化

    方法一:使用 localStorage 存储数据 window.localStorage.setItem(key,value) 方法二:使用 vuex-persistedstate插件 vuex 存在 ...

  2. Date与String互相转换及日期的大小比较

    private static final String PATTERN = "yyyy-MM-dd HH:mm:ss"; /** * String转Date * * @param ...

  3. VB中IIF函数

    IIf 函数语法:IIf(表达式, 真值部分, 假值部分)根据表达式的值,表达式为真时,返回真值部分,表达式为假时,返回假部分.如:iif(a>0, "对","错& ...

  4. PHP简单的爬虫–原型

    1.PHP简单的爬虫–原型 爬虫的原理: 给定原始的url: 分析链接,根据设置的正则表达式获取链接中的内容: 有的会更新原始的url再进行分析链接,获取特定内容,周而复始. 将获取的内容保存在数据库 ...

  5. pycharm设置SDK

    1.一看到这个提示,就知道Pycharm中尚未配置Python解释器,此时不用慌,并不是Pycharm没有安装成功,而是因为有个配置尚未完成,只需要配置好Python解释器之后,一切都会正常.其实Py ...

  6. bzoj3011 [Usaco2012 Dec]Running Away From the Barn 左偏树

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3011 题解 复习一下左偏树板子. 看完题目就知道是左偏树了. 结果这个板子还调了好久. 大概已 ...

  7. Git整理[1] git cherry-pick的使用

    简单地说 git cherry-pick为”挑拣”提交 ,挑取某次提交合并到其他分支上,而不用合并整个分支. 参数: git cherry-pick [<options>] <com ...

  8. react native之使用AsyncStorage 进行数据持久化存储

    新建AsncStorageDemoPage.js import React, {Component} from 'react'; import { StyleSheet, View, Text, Bu ...

  9. 使用mongodb

    1.安装 yarn add moogose 2.启动 在命令行 mongod --dbpath D:\data//这是最后出现 waiting for connections on port 2701 ...

  10. PHP入门培训教程 php动态网页怎么转换成html

       当动态网页遇上搜索引擎 虽然动态网页相比于静态页面拥有许多优势,但它在搜索引擎的检索上却碰了个大钉子.无论任何一家网站,尤其是那些以营销为目的的企业网站,没有谁会希望自己的网页无法被搜索引擎检索 ...