android中非aidl實現進程間通信(編寫順序的parcel寫入與讀出)

在android中進程間通信(IPC)的基石是Binder系統,Binder系統的核心Binder驅動是C來實現的,對於應用開發人員來說無疑晦澀難懂,而整個android框架是基於面向對象思想的,對於底層Binder驅動的操作細節全部隱藏,framework層提供了一個牛逼無比的Binder對象, 所以我們要實現進程間通信(IPC)只需玩轉Binder對象即可。

在android源碼中基於Binder對象的通信隨處可見,幾乎可以認定爲以 I 打頭的class,都具有進程間通信能力,如:IServiceManager,IContentProvider等。

在源碼中實現的方式也可概括爲兩種:

1. 通過aidl來生成對Binder的操作。

2.手動調用IBinder.transact編寫按照順序寫入與讀出的parcel代碼實現。

第一種方法網上案例較多,不多說。第二種方法實現源碼參考:ActivityManagerNative,ActivityManagerProxy

關於第二種方法的實現本人做了一個demo,請看以下代碼。


package dw.test;

import java.util.HashMap;

import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
/**
 * 負責接收指令({@link CmdCode}),並將指令派發到相應的處理器({@link CmdDispatcher.Callback})
 */
public final class CmdDispatcher extends Binder implements IInterface{
 
	private static final String LOG_TAG = CmdDispatcher.class.getSimpleName();
	
	public static final String DESCRIPTOR = CmdDispatcher.class.getName();
	/**
	 * 存儲所有指令處理器
	 * map.key = {@link CmdCode}
	 */
	private HashMap<Integer,Callback> mCallbacks = new HashMap<Integer, Callback>();
	/**
	 * 針對某個指令的處理
	 * @see #addCallback
	 * @see #removeCallback
	 */
	public interface Callback {
		/**
		 * @param code 請求指令集{@link CmdCode.Request},響應 指令集{@link CmdCode.Response}
		 * @param data 數據 {@link Parcel}
		 * @param reply 處理data的結果 {@link Parcel}
		 * @return
		 */
		public boolean onTransact(int code, Parcel data, Parcel reply);
	}
	/**
	 * 當client端調用 {@link IBinder#transact(int, Parcel, Parcel, int)}時,將會回調本方法。
	 */
	@Override
	protected boolean onTransact(int code, Parcel data, Parcel reply,
			int flags) throws RemoteException {
		
		dispatch(code,data,reply);

		return true;
	}
	/**
	 * 得到某個指令處理器並調用
	 */
	private void dispatch(int code, Parcel data, Parcel reply) {
		Log.i(LOG_TAG, "dispatch reply enter");
		
		Callback callback = mCallbacks.get(code);
		
		if(callback!=null){
			callback.onTransact(code, data, reply);
		}
		
		Log.i(LOG_TAG, "dispatch reply exit");
	}
	
	@Override
	public IBinder asBinder() {
		return this;
	}
	
	@Override
	public String getInterfaceDescriptor() {
		return DESCRIPTOR;
	}
	
	@Override
	public IInterface queryLocalInterface(String descriptor) {
		return this;
	}
	/**
	 * 針對某一個指令,如:請求指令集{@link CmdCode.Request},響應 指令集{@link CmdCode.Response}
	 * 添加回調處理
	 * @param code 指令編碼
	 * @param callback 針對某一個指定的處理 {@link Callback}
	 */
	public void addCallback(int code,Callback callback) {
		mCallbacks.put(code, callback);
	}

	public void removeCallback(int code) {
		mCallbacks.remove(code);
	}
	
}

package dw.test;
/**
 * 定義指令集
 */
public interface CmdCode {
	
	public interface BaseCode {
		/**
		 * 每個parcel的頭
		 */
		public static final int PARCEL_HEAD = 0xffff;
		public static final int RESULT_SUCCESS = 0x0001;
		public static final int RESULT_ERROR = 0x0002;
	}
	/**
	 * 請求指令集
	 */
	public interface Request extends BaseCode{
		public static final int REQUEST = 0x0001;
	}
	/**
	 * 響應指令集
	 */
	public interface Response extends BaseCode {
		public static final int RESPONSE = 0x0001;
	}
	
}

package dw.test;

import dw.test.CmdDispatcher.Callback;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Parcel;
import android.util.Log;

/**
 * RemoteService作爲一個獨立進程存在.
 */
public class RemoteCmdService extends Service implements Callback,CmdCode.Request{
	
	private static final String LOG_TAG = RemoteCmdService.class.getSimpleName();
	
	private final CmdDispatcher mCmdDispatcher = new CmdDispatcher();
	
	@Override
	public IBinder onBind(Intent intent) {
		mCmdDispatcher.addCallback(REQUEST, this);
		return mCmdDispatcher;
	}
	
	@Override
	public void onCreate() {
		super.onCreate();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		
		Log.i(LOG_TAG, "onStartCommand enter");
		
		return super.onStartCommand(intent, flags, startId);
	}
	
	@Override
	public boolean onTransact(int code, Parcel data, Parcel reply) {
		Log.i(LOG_TAG, "remove service handle Reply enter");
		data.enforceInterface(CmdDispatcher.DESCRIPTOR);
		//讀取包頭
		int head = data.readInt();
		if(head==PARCEL_HEAD) {
			String handeResult = data.readString();
			reply.writeInt(RESULT_SUCCESS);
			Log.i(LOG_TAG, handeResult);
		} else {
			reply.writeInt(RESULT_ERROR); 
		}
		Log.i(LOG_TAG, "remove service handle Reply exit");
		return true;
	}

}


package dw.test.activity;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import dw.test.CmdCode;
import dw.test.CmdDispatcher;
import dw.test.R;
import dw.test.RemoteCmdService;

public class MainActivity extends Activity implements OnClickListener , CmdCode.Request,CmdCode.Response{

	private static final String LOG_TAG = MainActivity.class.getSimpleName();
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.findViewById(R.id.test_remote_binder_btn).setOnClickListener(this);
    }
    
	/**
     * 連接並調用遠程服務
     */
    private void testRemote(){
    	Intent intent = new Intent(MainActivity.this,RemoteCmdService.class);
    	//綁定遠程服務
    	bindService(intent, new ServiceConnection() {
			
			@Override
			public void onServiceDisconnected(ComponentName name) {
				
			}
			
			@Override
			public void onServiceConnected(ComponentName name, IBinder service) {
				
				replyTo(service);
				
			}
		}, BIND_AUTO_CREATE);
    }
    
	private void replyTo(IBinder service) {
		Parcel data = Parcel.obtain();
		Parcel reply = Parcel.obtain();
		
		data.writeInterfaceToken(CmdDispatcher.DESCRIPTOR);
		//寫入包頭
		data.writeInt(PARCEL_HEAD);
		//寫入要發送的字符數據
		data.writeString("serviceConnected");
		
		//當然你也可以傳遞一個binder對象過去作爲callback,這樣兩個進程間就可以交互了。
//		data.writeStrongBinder(IBinder binder); 
		
		try {
			//調用遠程MESSAGE_REQUEST服務
			service.transact(REQUEST, data, reply,0);
		} catch (RemoteException e) {
			//ignore
		}
		
		//MESSAGE_REQUEST服務所返回的結果 
		int result = reply.readInt();
		
		if(RESULT_SUCCESS==result) {
			Log.i(LOG_TAG, "ok");
		}
		
		data.recycle();
		reply.recycle();
	}

	@Override
	public void onClick(View v) {
		int id = v.getId();
		if(R.id.test_remote_binder_btn==id){
			testRemote();
		}
	}

    
}

代碼工程:http://download.csdn.net/detail/hacker686ok/5810399


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章