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函数中。