本文參考《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和应用程序进程间通信的更多相关文章

  1. 程序兵法:Java String 源码的排序算法(一)

    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第103篇原创 <程序兵法:Java Str ...

  2. 编译哈工大语言技术平台云LTP(C++)源码及LTP4J(Java)源码

    转自:编译哈工大语言技术平台云LTP(C++)源码及LTP4J(Java)源码 JDK:java version “1.8.0_31”Java(TM) SE Runtime Environment ( ...

  3. java集合源码分析(三):ArrayList

    概述 在前文:java集合源码分析(二):List与AbstractList 和 java集合源码分析(一):Collection 与 AbstractCollection 中,我们大致了解了从 Co ...

  4. Java集合源码分析(四)Vector<E>

    Vector<E>简介 Vector也是基于数组实现的,是一个动态数组,其容量能自动增长. Vector是JDK1.0引入了,它的很多实现方法都加入了同步语句,因此是线程安全的(其实也只是 ...

  5. Java集合源码分析(二)ArrayList

    ArrayList简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线 ...

  6. Java集合源码学习(一)集合框架概览

    >>集合框架 Java集合框架包含了大部分Java开发中用到的数据结构,主要包括List列表.Set集合.Map映射.迭代器(Iterator.Enumeration).工具类(Array ...

  7. 【转】Java HashMap 源码解析(好文章)

    ­ .fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wra ...

  8. Java Reference 源码分析

    @(Java)[Reference] Java Reference 源码分析 Reference对象封装了其它对象的引用,可以和普通的对象一样操作,在一定的限制条件下,支持和垃圾收集器的交互.即可以使 ...

  9. 自学Java HashMap源码

    自学Java HashMap源码 参考:http://zhangshixi.iteye.com/blog/672697 HashMap概述 HashMap是基于哈希表的Map接口的非同步实现.此实现提 ...

随机推荐

  1. Java中hashCode与equal方法详解

    转载自http://blog.csdn.net/jiangwei0910410003/article/details/22739953 Java中的equals方法和hashCode方法是Object ...

  2. WebKit.NET-0.5简单应用(2)——音量解决方案

    查找WebKit.NET相关文档,没有找到音量控制解决方法.换思路进行解决,尝试用Win32 API进行解决 [DllImport("winmm.dll")] public sta ...

  3. Mac OS X10.10_xcode6.1_ios8.1环境下,编译lame静态库libmp3lame.a,支持arm64 armv7s x86_64 i386 armv7指令集

    近期升级了系统到Mac OS X 10.10 而且更新了XCode6.1和iOS 8.1 之前app用到的libmp3lame.a静态库.也要支持64位的模拟器(x86_64)和64位的真机(arm6 ...

  4. [MST] Loading Data from the Server using lifecycle hook

    Let's stop hardcoding our initial state and fetch it from the server instead. In this lesson you wil ...

  5. Hdu4786

    Fibonacci Tree Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  6. hdoj 1719 Friend

    Friend Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  7. springMVC之拦截器

    有两种方法配置spring的拦截器 1. 实现接口: HandleInterceptor public class MyInterceptor1 implements HandlerIntercept ...

  8. rest_framework_HyperlinkedIdentityField

    #生成链接 HyperlinkedIdentityField class UserInfoSerializer(serializers.ModelSerializer): group = serial ...

  9. 替换默认debug.keystore文件

    最近在开发过程中需要频繁的为测试的同事签名apk,感觉非常很麻烦,于是就想把Intellij或是Eclipse使用的默认debug.keystore文件替换成发布用(生产环境)的签名文件,这样就可以直 ...

  10. 关于iOS适配问题

    大家都知道在iOS开发当中对于UI适配问题可以从如下两个方面去考虑: 1.比例适配 2.利用autolayout自动布局 通常情况来说,利用auto自动布局是一个比较好的方案,开发者可以利用story ...