前面我们说到,我们在这里举的例子包含了一个Server端和一个Client端实现,其中, Server端就是通过前面一个构造函数来创建一个匿名共享内存文件,接着,Client端过Binder进程间通信机制来向Server请求这个匿名共享内存的文件描述符,有了这个文件描述符之后,就可以通过后面一个构造函数来共享这个内存文件了。
因为涉及到Binder进程间通信,我们首先定义好Binder进程间通信接口。Binder进程间通信机制的相关介绍,请参考前面一篇文章,这里就不详细介绍了,直接进入主题。
首先在源代码工程的packages/experimental目录下创建一个应用程序工程目录Ashmem。关于如何获得Android源代码工程,请参考一文;关于如何在Android源代码工程中创建应用程序工程,请参考一文。这里,工程名称就是Ashmem了,它定义了一个路径为shy.luo.ashmem的package,这个例子的源代码主要就是实现在这里了。下面,将会逐一介绍这个package里面的文件。这里要用到的Binder进程间通信接口定义在src/shy/luo/ashmem/IMemoryService.java文件中:
- package shy.luo.ashmem;
- import android.util.Log;
- import android.os.IInterface;
- import android.os.Binder;
- import android.os.IBinder;
- import android.os.Parcel;
- import android.os.ParcelFileDescriptor;
- import android.os.RemoteException;
- public interface IMemoryService extends IInterface {
- public static abstract class Stub extends Binder implements IMemoryService {
- private static final String DESCRIPTOR = "shy.luo.ashmem.IMemoryService";
- public Stub() {
- attachInterface(this, DESCRIPTOR);
- }
- public static IMemoryService asInterface(IBinder obj) {
- if (obj == null) {
- return null;
- }
- IInterface iin = (IInterface)obj.queryLocalInterface(DESCRIPTOR);
- if (iin != null && iin instanceof IMemoryService) {
- return (IMemoryService)iin;
- }
- return new IMemoryService.Stub.Proxy(obj);
- }
- public IBinder asBinder() {
- return this;
- }
- @Override
- public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws android.os.RemoteException {
- switch (code) {
- case INTERFACE_TRANSACTION: {
- reply.writeString(DESCRIPTOR);
- return true;
- }
- case TRANSACTION_getFileDescriptor: {
- data.enforceInterface(DESCRIPTOR);
- ParcelFileDescriptor result = this.getFileDescriptor();
- reply.writeNoException();
- if (result != null) {
- reply.writeInt(1);
- result.writeToParcel(reply, 0);
- } else {
- reply.writeInt(0);
- }
- return true;
- }
- case TRANSACTION_setValue: {
- data.enforceInterface(DESCRIPTOR);
- int val = data.readInt();
- setValue(val);
- reply.writeNoException();
- return true;
- }
- }
- return super.onTransact(code, data, reply, flags);
- }
- private static class Proxy implements IMemoryService {
- private IBinder mRemote;
- Proxy(IBinder remote) {
- mRemote = remote;
- }
- public IBinder asBinder() {
- return mRemote;
- }
- public String getInterfaceDescriptor() {
- return DESCRIPTOR;
- }
- public ParcelFileDescriptor getFileDescriptor() throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- ParcelFileDescriptor result;
- try {
- data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_getFileDescriptor, data, reply, 0);
- reply.readException();
- if (0 != reply.readInt()) {
- result = ParcelFileDescriptor.CREATOR.createFromParcel(reply);
- } else {
- result = null;
- }
- } finally {
- reply.recycle();
- data.recycle();
- }
- return result;
- }
- public void setValue(int val) throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- try {
- data.writeInterfaceToken(DESCRIPTOR);
- data.writeInt(val);
- mRemote.transact(Stub.TRANSACTION_setValue, data, reply, 0);
- reply.readException();
- } finally {
- reply.recycle();
- data.recycle();
- }
- }
- }
- static final int TRANSACTION_getFileDescriptor = IBinder.FIRST_CALL_TRANSACTION + 0;
- static final int TRANSACTION_setValue = IBinder.FIRST_CALL_TRANSACTION + 1;
- }
- public ParcelFileDescriptor getFileDescriptor() throws RemoteException;
- public void setValue(int val) throws RemoteException;
- }
- package shy.luo.ashmem;
- import android.util.Log;
- import android.os.IInterface;
- import android.os.Binder;
- import android.os.IBinder;
- import android.os.Parcel;
- import android.os.ParcelFileDescriptor;
- import android.os.RemoteException;
- public interface IMemoryService extends IInterface {
- public static abstract class Stub extends Binder implements IMemoryService {
- private static final String DESCRIPTOR = "shy.luo.ashmem.IMemoryService";
- public Stub() {
- attachInterface(this, DESCRIPTOR);
- }
- public static IMemoryService asInterface(IBinder obj) {
- if (obj == null) {
- return null;
- }
- IInterface iin = (IInterface)obj.queryLocalInterface(DESCRIPTOR);
- if (iin != null && iin instanceof IMemoryService) {
- return (IMemoryService)iin;
- }
- return new IMemoryService.Stub.Proxy(obj);
- }
- public IBinder asBinder() {
- return this;
- }
- @Override
- public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws android.os.RemoteException {
- switch (code) {
- case INTERFACE_TRANSACTION: {
- reply.writeString(DESCRIPTOR);
- return true;
- }
- case TRANSACTION_getFileDescriptor: {
- data.enforceInterface(DESCRIPTOR);
- ParcelFileDescriptor result = this.getFileDescriptor();
- reply.writeNoException();
- if (result != null) {
- reply.writeInt(1);
- result.writeToParcel(reply, 0);
- } else {
- reply.writeInt(0);
- }
- return true;
- }
- case TRANSACTION_setValue: {
- data.enforceInterface(DESCRIPTOR);
- int val = data.readInt();
- setValue(val);
- reply.writeNoException();
- return true;
- }
- }
- return super.onTransact(code, data, reply, flags);
- }
- private static class Proxy implements IMemoryService {
- private IBinder mRemote;
- Proxy(IBinder remote) {
- mRemote = remote;
- }
- public IBinder asBinder() {
- return mRemote;
- }
- public String getInterfaceDescriptor() {
- return DESCRIPTOR;
- }
- public ParcelFileDescriptor getFileDescriptor() throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- ParcelFileDescriptor result;
- try {
- data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_getFileDescriptor, data, reply, 0);
- reply.readException();
- if (0 != reply.readInt()) {
- result = ParcelFileDescriptor.CREATOR.createFromParcel(reply);
- } else {
- result = null;
- }
- } finally {
- reply.recycle();
- data.recycle();
- }
- return result;
- }
- public void setValue(int val) throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- try {
- data.writeInterfaceToken(DESCRIPTOR);
- data.writeInt(val);
- mRemote.transact(Stub.TRANSACTION_setValue, data, reply, 0);
- reply.readException();
- } finally {
- reply.recycle();
- data.recycle();
- }
- }
- }
- static final int TRANSACTION_getFileDescriptor = IBinder.FIRST_CALL_TRANSACTION + 0;
- static final int TRANSACTION_setValue = IBinder.FIRST_CALL_TRANSACTION + 1;
- }
- public ParcelFileDescriptor getFileDescriptor() throws RemoteException;
- public void setValue(int val) throws RemoteException;
- }
package shy.luo.ashmem;import android.util.Log;import android.os.IInterface;import android.os.Binder;import android.os.IBinder;import android.os.Parcel;import android.os.ParcelFileDescriptor;import android.os.RemoteException;public interface IMemoryService extends IInterface { public static abstract class Stub extends Binder implements IMemoryService { private static final String DESCRIPTOR = "shy.luo.ashmem.IMemoryService"; public Stub() { attachInterface(this, DESCRIPTOR); } public static IMemoryService asInterface(IBinder obj) { if (obj == null) { return null; } IInterface iin = (IInterface)obj.queryLocalInterface(DESCRIPTOR); if (iin != null && iin instanceof IMemoryService) { return (IMemoryService)iin; } return new IMemoryService.Stub.Proxy(obj); } public IBinder asBinder() { return this; } @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_getFileDescriptor: { data.enforceInterface(DESCRIPTOR); ParcelFileDescriptor result = this.getFileDescriptor(); reply.writeNoException(); if (result != null) { reply.writeInt(1); result.writeToParcel(reply, 0); } else { reply.writeInt(0); } return true; } case TRANSACTION_setValue: { data.enforceInterface(DESCRIPTOR); int val = data.readInt(); setValue(val); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements IMemoryService { private IBinder mRemote; Proxy(IBinder remote) { mRemote = remote; } public IBinder asBinder() { return mRemote; } public String getInterfaceDescriptor() { return DESCRIPTOR; } public ParcelFileDescriptor getFileDescriptor() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); ParcelFileDescriptor result; try { data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getFileDescriptor, data, reply, 0); reply.readException(); if (0 != reply.readInt()) { result = ParcelFileDescriptor.CREATOR.createFromParcel(reply); } else { result = null; } } finally { reply.recycle(); data.recycle(); } return result; } public void setValue(int val) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(DESCRIPTOR); data.writeInt(val); mRemote.transact(Stub.TRANSACTION_setValue, data, reply, 0); reply.readException(); } finally { reply.recycle(); data.recycle(); } } } static final int TRANSACTION_getFileDescriptor = IBinder.FIRST_CALL_TRANSACTION + 0; static final int TRANSACTION_setValue = IBinder.FIRST_CALL_TRANSACTION + 1; } public ParcelFileDescriptor getFileDescriptor() throws RemoteException; public void setValue(int val) throws RemoteException;}
这里主要是定义了IMemoryService接口,它里面有两个调用接口:
- public ParcelFileDescriptor getFileDescriptor() throws RemoteException;
- public void setValue(int val) throws RemoteException;
- public ParcelFileDescriptor getFileDescriptor() throws RemoteException;
- public void setValue(int val) throws RemoteException;
public ParcelFileDescriptor getFileDescriptor() throws RemoteException; public void setValue(int val) throws RemoteException;
同时,还分别定义了用于Server端实现的IMemoryService.Stub基类和用于Client端使用的代理IMemoryService.Stub.Proxy类。关于Binder进程间通信机制在应用程序框架层的Java接口定义,请参考前面一文。