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

  • 相关阅读:
    HashMap源码解析
    深入理解Java字符串
    Netty粘包、半包
    Netty源码分析-Future和Promise
    Lock简介
    一、Netty中的EventLoop
    对象实例化内存布局与访问定位
    运行时数据区概述及线程
    TCP三次握手和四次挥手
    Redis线程IO模型-Redis 单线程为什么还能这么快?
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/6991254.html
Copyright © 2020-2023  润新知