Java接口源码--System和应用程序进程间通信
本文參考《Android系统源代码情景分析》。作者罗升阳
一、架构代码:
~/Android/frameworks/base/core/java/android/os
----IInterface.java (Interface)
----IServiceManager.java (IServiceManager)
----IBinder.java (IBinder)
----Binder.java (BinderProxy。Binder)
----ServiceManagerNative.java (ServiceManagerProxy,ServiceManagerNative)
----ServiceManager.java (ServiceManager)
~/Android/frameworks/base/core/jni
----android_util_Binder.cpp
測试代码:(參考实现硬件訪问服务和开发Android应用程序来使用硬件訪问服务两篇文章)
~/Android/frameworks/base/services/java/com/android/server
----SystemServer.java
~/Android/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os
----IFregService.java
~/Android/frameworks/base/services/java/com/android/server
----FregService.java
~/Android/packages/experimental/Freg
----src----shy/luo/freg----Freg.java
二、源代码分析
上面介绍的Freg这个Activity获得了FregService的远程接口后,就能够使用它的服务了。我们以使用IFregService.getVal函数为例具体说明。在Freg::onClick函数中调用了IFregService.getVal函数:
~/Android/packages/experimental/Freg
----src----shy/luo/freg----Freg.java
public class Freg extends Activity implements OnClickListener {
...... @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); fregService = IFregService.Stub.asInterface(
ServiceManager.getService("freg")); ...... Log.i(LOG_TAG, "Freg Activity Created");
}
@Override
public void onClick(View v) {
if(v.equals(readButton)) {
int val = fregService.getVal();
......
}
else if(v.equals(writeButton)) {
......
}
else if(v.equals(clearButton)) {
......
}
} ......
}
1、应用程序进程,获得实现了IFregService接口的IFregService.Stub.Proxy对象
參考http://blog.csdn.net/jltxgcy/article/details/29861583。Android应用程序进程和Service Manager进程通信。
2、应用程序进程,封装进程间通信数据
通知前面的分析,我们知道,这里的fregService接口实际上是一个IFregService.Stub.Proxy对象,因此。我们进入到IFregService.Stub.Proxy类的getVal函数中:
public interface IFregService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.os.IFregService
{ ...... private static class Proxy implements android.os.IFregService
{
private android.os.IBinder mRemote;//BinderProxy对象(当中mObject成员变量记录了这个Android应用程序进程代理对象BpBinder对象的地址) ...... public int getVal() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);//android.os.IFregService
mRemote.transact(Stub.TRANSACTION_getVal, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
} ......
static final int TRANSACTION_getVal = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
} ......
}
此时没有对象要传递,仅仅有字符串。
參考FregClient和FregServer进程间通信http://blog.csdn.net/jltxgcy/article/details/28428853一文中的第2点。
3、应用程序进程,发送BC_TRANSACTION,唤醒SystemServer进程。返回BR_TRANSACTION_COMPLETE,睡眠等待主线程thread->wait
再參考FregClient和FregServer进程间通信http://blog.csdn.net/jltxgcy/article/details/28428853一文中的第3点。
依据应用程序进程代理对象的句柄值。首先找到应用程序进程代理对象。通过应用程序代理对象再找到System进程的实体对象,通过System进程的实体对象,找到System进程。也就是目标进程。
传递内容中是android.os.IFregService。
4、System进程。从睡眠中被唤醒。返回BR_TRANSACTION,运行真正意义的getVal
參考FregClient和FregServer进程间通信http://blog.csdn.net/jltxgcy/article/details/28428853一文中的第4点。
通过System实体对象,读取的tr.target.ptr为System进程的本地对象的弱引用计数的地址。tr.cookie为System进程的本地对象地址(BBinder)。
~/Android/frameworks/base/libs/binder
----IPCThreadState.cpp
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR; switch (cmd) {//BR_TRANSACTION
......
case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));//读取出传递过来的binder_transaction_data结构体
......
if (result != NO_ERROR) break; Parcel buffer;//把数据放入buffer中
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t), freeBuffer, this); ..... Parcel reply;
.....
if (tr.target.ptr) {//System进程的本地对象的弱引用计数的地址
sp<BBinder> b((BBinder*)tr.cookie);//tr.cookie原来为IBinder向下转型为BBinder。System进程的本地对象地址
const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);//code为Stub.TRANSACTION_getVal
if (error < NO_ERROR) reply.setError(error);
} else {
......
} ....... if ((tr.flags & TF_ONE_WAY) == 0) {
.......
sendReply(reply, 0);
} else {
......
} ...... }
break; ......
return result;
}
首先,读取出传递过来的binder_transaction_data结构体,并把当中的数据放入buffer中,调用BBinder的transact方法,实现例如以下:
~/Android/frameworks/base/libs/binder
----Binder.cpp
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(0); status_t err = NO_ERROR;
switch (code) {
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
err = onTransact(code, data, reply, flags);//code为Stub.TRANSACTION_getVal
break;
} if (reply != NULL) {
reply->setDataPosition(0);
} return err;
}
BBinder的onTransact方法。因为子类JavaBBinder复写了onTransact方法,所以调用该方法。实现例如以下:
class JavaBBinder : public BBinder
{
JavaBBinder(JNIEnv* env, jobject object)
: mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
{
......
} ...... virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
{
JNIEnv* env = javavm_to_jnienv(mVM); ...... jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, (int32_t)&data, (int32_t)reply, flags); ...... return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
} ...... JavaVM* const mVM;
jobject const mObject;//Java层中创建的硬件訪问服务FregService
};
JavaBBinder类里面的成员变量mObject就是FregService类的一个实例对象了。因此,这里通过语句:
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, (int32_t)&data, (int32_t)reply, flags);
FregService类集成了IFregService.Stub。它又集成了Binder。这里调用的是
~/Android/frameworks/base/core/java/android/os
----Binder.java
public class Binder implements IBinder {
...... // Entry point from android_util_Binder.cpp's onTransact
private boolean execTransact(int code, int dataObj, int replyObj, int flags) {
Parcel data = Parcel.obtain(dataObj);
Parcel reply = Parcel.obtain(replyObj);
// theoretically, we should call transact, which will call onTransact,
// but all that does is rewind it, and we just got these from an IPC,
// so we'll just call it directly.
boolean res;
try {
res = onTransact(code, data, reply, flags);//data为android.os.IFregService。code为Stub.TRANSACTION_getVal
} catch (RemoteException e) {
reply.writeException(e);
res = true;
} catch (RuntimeException e) {
reply.writeException(e);
res = true;
} catch (OutOfMemoryError e) {
RuntimeException re = new RuntimeException("Out of memory", e);
reply.writeException(re);
res = true;
}
reply.recycle();
data.recycle();
return res;
}
}
这里又调用了onTransact函数来作进一步处理。因为FregService类继承了IFregService.Stub类,而IFregService.Stub类实现了onTransact函数,FregService类没有实现,因此,终于调用了IFregService.Stub.onTransact函数:
~/Android/fout/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os中。
IFregService.java
public interface IFregService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.os.IFregService
{
...... @Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
......
case TRANSACTION_getVal:
{
data.enforceInterface(DESCRIPTOR);//data为android.os.IFregService。也是在C/C++层比較数据。上层Parcel仅仅是底层的一个引用
int _result = this.getVal();
reply.writeNoException();
reply.writeInt(_result);//写入reply,也是在C/C++层写入数据
return true;//返回到IPCThreadState::executeCommand,运行sendReply
}
}
return super.onTransact(code, data, reply, flags);
} ...... }
}
函数终于又调用了FregService.getVal函数:
public class FregService extends IFregService.Stub {
...... public int getVal() {
return getVal_native();
} ......
private static native int getVal_native();
}
5、System进程。发送BC_REPLY。唤醒应用程序进程,返回BR_TRANSACTION_COMPLETE。睡眠等待在proc->wait
參考FregClient和FregServer进程间通信http://blog.csdn.net/jltxgcy/article/details/28428853一文中的第5点。
依据thread->transaction_stack->from找到目标进程,即应用程序进程。传递的数据返回值是getVal获取的值。
6、应用程序进程,返回BR_REPLY。
參考FregClient和FregServer进程间通信http://blog.csdn.net/jltxgcy/article/details/28428853一文中的第6点。
7、应用程序进程进程,返回到IFregService.Stub.Proxy类的getVal方法。
终于,经过层层返回,就回到IFregService.Stub.Proxy.getVal函数中来了。从以下语句返回:
mRemote.transact(Stub.TRANSACTION_getVal, _data, _reply, 0);
并将结果读出来:
_result = _reply.readInt();
最后将这个结果返回到Freg.onClick函数中。
Java接口源码--System和应用程序进程间通信的更多相关文章
- 程序兵法:Java String 源码的排序算法(一)
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第103篇原创 <程序兵法:Java Str ...
- 编译哈工大语言技术平台云LTP(C++)源码及LTP4J(Java)源码
转自:编译哈工大语言技术平台云LTP(C++)源码及LTP4J(Java)源码 JDK:java version “1.8.0_31”Java(TM) SE Runtime Environment ( ...
- java集合源码分析(三):ArrayList
概述 在前文:java集合源码分析(二):List与AbstractList 和 java集合源码分析(一):Collection 与 AbstractCollection 中,我们大致了解了从 Co ...
- Java集合源码分析(四)Vector<E>
Vector<E>简介 Vector也是基于数组实现的,是一个动态数组,其容量能自动增长. Vector是JDK1.0引入了,它的很多实现方法都加入了同步语句,因此是线程安全的(其实也只是 ...
- Java集合源码分析(二)ArrayList
ArrayList简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线 ...
- Java集合源码学习(一)集合框架概览
>>集合框架 Java集合框架包含了大部分Java开发中用到的数据结构,主要包括List列表.Set集合.Map映射.迭代器(Iterator.Enumeration).工具类(Array ...
- 【转】Java HashMap 源码解析(好文章)
.fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wra ...
- Java Reference 源码分析
@(Java)[Reference] Java Reference 源码分析 Reference对象封装了其它对象的引用,可以和普通的对象一样操作,在一定的限制条件下,支持和垃圾收集器的交互.即可以使 ...
- 自学Java HashMap源码
自学Java HashMap源码 参考:http://zhangshixi.iteye.com/blog/672697 HashMap概述 HashMap是基于哈希表的Map接口的非同步实现.此实现提 ...
随机推荐
- 贰、js的基础(二)类型转换
JS 数据类型转换 方法主要有三种 转换函数.强制类型转换.利用js变量弱类型转换. 1. 转换函数: js提供了parseInt()和parseFloat()两个转换函数.前者把值转换成整数,后者把 ...
- 使用了未经检查或不安全的操作。有关详细信息, 请使用 -Xlint:unchecked 重新编译。
警告信息如下:
- SP10628 COT - Count on a tree 主席树
Code: #include<cstdio> #include<cstring> #include<algorithm> #include<string> ...
- 简洁的MVC思想框架——Nancy(环境配置与Get操作)
Nancy官网——https://github.com/NancyFx/Nancy 概述:Nancy是一个开源的Web轻型框架内核符合MVC思想,有开发方便,路由简单的特点,而且功能齐全 起步:Hel ...
- SpringBoot实战(四)获取接口请求中的参数(@PathVariable,@RequestParam,@RequestBody)
上一篇SpringBoot实战(二)Restful风格API接口中写了一个控制器,获取了前端请求的参数,现在我们就参数的获取与校验做一个介绍: 一:获取参数 SpringBoot提供的获取参数注解包括 ...
- POJ——T3259 Wormholes
http://poj.org/problem?id=3259 Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 50692 ...
- vim 常用变量
为了vim更好的支持python写代码,修改tab默认4个空格有两种设置方法: 1. vim /etc/vimrc 1 set ts=4 2 set sw = 4 2. vim /etc/vimrc ...
- HDU 1022 Train Problem I 模拟栈题解
火车进站,模拟一个栈的操作,额外的栈操作,查看能否依照规定顺序出栈. 数据量非常少,故此题目非常easyAC. 直接使用数组模拟就好. #include <stdio.h> const i ...
- Java (JDK7)中的String常量和String.intern的实现
在java中有constantPool常量池,常量池里存放的是类,方法,接口的等常量,而对于存放字符串常量通常存放的符号链接Symbol 或者真实的String的对象的引用. 我们来看一段简单的代码和 ...
- ★★★【卡法 常用js库】: js汇合 表单验证 cookie设置 日期格式 电话手机号码 email 整数 小数 金额 检查参数长度
[卡法 常用js库]: js汇合 表单验证 cookie设置 日期格式 电话手机号码 email 整数 小数 金额 检查参数长度 // +---------------------- ...