【Android源码 栏目提醒】:文章导读:在新的一年中,各位网友都进入紧张的学习或是工作阶段。
网学会员整理了Android源码 -Android系统匿名共享内存Ashmem(Anonymous-Shared-Memory)简要介绍和学习计划 - 讲义教程的相关内容供大家参考,祝大家在新的一年里工作和学习顺利!
Android系统匿名共享内存AshmemAnonymous Shared Memory简要介绍和学习计划
Android系统匿名共享内存AshmemAnonymous Shared Memory简要介绍和学习计划 在
Android系统中提供了独特的匿名共享内存子系统AshmemAnonymous Shared Memory它以驱动程序的形式实现在内核空间中。
它有两个特点一是能够辅助内存管理系统来有效地管理不再使用的内存块二是它通过Binder进程间通信机制来实现进程间的内存共享。
本文中我们将通过实例来简要介绍
Android系统的匿名共享内存的使用方法使得我们对
Android系统的匿名共享内存机制有一个感性的认识为进一步学习它的源代码实现打下基础。
Android系统的匿名共享内存子系统的主体是以驱动程序的形式实现在内核空间的同时在系统运行时库层和应用程序框架层提供了访问接口其中在系统运行时库层提供了C/C调用接口而在应用程序框架层提供了Java调用接口。
这里我们将直接通过应用程序框架层提供的Java调用接口来说明匿名共享内存子系统Ashmem的使用方法毕竟我们在
Android开发应用程序时是基于Java语言的而实际上应用程序框架层的Java调用接口是通过JNI方法来调用系统运行时库层的C/C调用接口最后进入到内核空间的Ashmem驱动程序去的。
我们在这里举的例子是一个名为Ashmem的应用程序它包含了一个Server端和一个Client端实现其中Server端是以Service的形式实现的在这里Service里面创建一个匿名共享内存文件而Client是一个Activity这个Activity通过Binder进程间通信机制获得前面这个Service创建的匿名共享内存文件的句柄从而实现共享。
在
Android应用程序框架层提供了一个MemoryFile接口来封装了匿名共享内存文件的创建和使用它实现在frameworks/base/core/java/
android/os/MemoryFile.java文件中。
下面我们就来看看Server端是如何通过MemoryFile类来创建匿名共享内存文件的以及Client是如何获得这个匿名共享内存文件的句柄的。
在MemoryFile类中提供了两种创建匿名共享内存的方法我们通过MemoryFile类的构造函数来看看这两种使用方法 public class MemoryFile ...... / Allocates a new ashmem region. The region is initially not purgable. param name optional name for the file can be null. param length of the memory file in bytes. throws IOException if the memory file could not be created. / public MemoryFileString name int length throws IOException mLength length mFD native_openname length mAddress native_mmapmFD length PROT_READ PROT_WRITE mOwnsRegion true / Creates a reference to an existing memory file. Changes to the original file will be available through this reference. Calls to link allowPurgingboolean on the returned MemoryFile will fail. param fd File descriptor for an existing memory file as returned by link getFileDescriptor. This file descriptor will be closed by link close. param length Length of the memory file in bytes. param mode File mode. Currently only quotrquot for read-only access is supported. throws NullPointerException if ltcodegtfdlt/codegt is null. throws IOException If ltcodegtfdlt/codegt does not refer to an existing memory file or if the file mode of the existing memory file is more restrictive than ltcodegtmodelt/codegt. hide / public MemoryFileFileDescriptor fd int length String mode throws IOException if fd null throw new NullPointerExceptionquotFile descriptor is null.quot if isMemoryFilefd throw new IllegalArgumentExceptionquotNot a memory file.quot mLength length mFD fd mAddress native_mmapmFD length modeToProtmode mOwnsRegion false ...... 从注释中我们可以看出这两个构造函数的使用方法这里就不再详述了。
两个构造函数的主要区别是第一个参数第一种构造方法是以指定的字符串调用JNI方法native_open来创建一个匿名共享内存文件从而得到一个文件描述符接着就以这个文件描述符为参数调用JNI方法natvie_mmap把这个匿名共享内存文件映射在进程空间中然后就可以通过这个映射后得到的地址空间来直接访问内存数据了第二种构造方法是以指定的文件描述符来直接调用JNI方法natvie_mmap把这个匿名共享内存文件映射在进程空间中然后进行访问而这个文件描述符就必须要是一个匿名共享内存文件的文件描述符这是通过一个内部函数isMemoryFile来验证的而这个内部函数isMemoryFile也是通过JNI方法调用来进一步验证的。
前面所提到的这些JNI方法调用最终都是通过系统运行时库层进入到内核空间的Ashmem驱动程序中去不过这里我们不关心这些JNI方法、系统运行库层调用以及Ashmem驱动程序的具体实现在接下来的两篇文章中我们将会着重介绍这里我们只关注MemoryFile这个类的使用方法。
前面我们说到我们在这里举的例子包含了一个Server端和一个Client端实现其中 Server端就是通过前面一个构造函数来创建一个匿名共享内存文件接着Client端过Binder进程间通信机制来向Server请求这个匿名共享内存的文件描述符有了这个文件描述符之后就可以通过后面一个构造函数来共享这个内存文件了。
因为涉及到Binder进程间通信我们首先定义好Binder进程间通信接口。
Binder进程间通信机制的相关介绍请参考前面一篇文章
Android进程间通信IPC机制Binder简要介绍和学习计划这里就不详细介绍了直接进入主题。
首先在源代码工程的packages/experimental目录下创建一个应用程序工程目录Ashmem。
关于如何获得
Android源代码工程请参考在Ubuntu上下载、编译和安装
Android最新源代码一文关于如何在
Android源代码工程中创建应用程序工程请参考在Ubuntu上为
Android系统内置Java应用程序测试Application Frameworks层的硬件服务一文。
这里工程名称就是Ashmem了它定义了一个路径为shy.luo.ashmem的package这个例子的源代码主要就是实现在这里了。
下面将会逐一介绍这个package里面的文件。
这里要用到的Binder进程间通信接口定义在src/shy/luo/ashmem/IMemoryService.java文件中 package shy.luo.ashmemimport
android.util.Logimport
android.os.IInterfaceimport
android.os.Binderimport
android.os.IBinderimport
android.os.Parcelimport
android.os.ParcelFileDescriptorimport
android.os.RemoteExceptionpublic interface IMemoryService extends IInterface public static abstract class Stub extends Binder implements IMemoryService private static final String DESCRIPTOR quotshy.luo.ashmem.IMemoryServicequot public Stub attachInterfacethis DESCRIPTOR public static IMemoryService asInterfaceIBinder obj if obj null return null IInterface iin IInterfaceobj.queryLocalInterfaceDESCRIPTOR if iin null ampamp iin instanceof IMemoryService return IMemoryServiceiin return new IMemoryService.Stub.Proxyobj public IBinder asBinder return this Override public boolean onTransactint code Parcel data Parcel reply int flags throws
android.os.RemoteException switch code case INTERFACE_TRANSACTION: reply.writeStringDESCRIPTOR return true case TRANSACTION_getFileDescriptor: data.enforceInterfaceDESCRIPTOR ParcelFileDescriptor result this.getFileDescriptor reply.writeNoException if result null reply.writeInt1 result.writeToParcelreply 0 else reply.writeInt0 return true case TRANSACTION_setValue: data.enforceInterfaceDESCRIPTOR int val data.readInt setValueval reply.writeNoException return true return super.onTransactcode data reply flags private static class Proxy implements IMemoryService private IBinder mRemote ProxyIBinder 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.writeInterfaceTokenDESCRIPTOR mRemote.transactStub.TRANSACTION_getFileDescriptor data reply 0 reply.readException if 0 reply.readInt result ParcelFileDescriptor.CREATOR.createFromParcelreply else result null finally reply.recycle data.recycle return result public void setValueint val throws RemoteException Parcel data Parcel.obtain Parcel reply Parcel.obtain try data.writeInterfaceTokenDESCRIPTOR data.writeIntval mRemote.transactStub.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 setValueint val throws RemoteException 这里主要是定义了IMemoryService接口它里面有两个调用接口 public ParcelFileDescriptor getFileDescriptor throws RemoteException public void setValueint val throws RemoteException 同时还分别定义了用于Server端实现的IMemoryService.Stub基类和用于Client端使用的代理IMemoryService.Stub.Proxy类。
关于Binder进程间通信机制在应用程序框架层的Java接口定义请参考前面
Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析一文。
有了Binder进程间通信接口之后接下来就是要在Server端实现一个本地服务了。
这里Server端实现的本地服务名为MemoryService实现在src/shy/luo/ashmem/MemoryService.java文件中 package shy.luo.ashmemimport java.io.FileDescriptorimport java.io.IOExceptionimport
android.os.Parcelimport
android.os.MemoryFileimport
android.os.ParcelFileDescriptorimport
android.util.Logpublic class MemoryService extends IMemoryService.Stub private final static String LOG_TAG quotshy.luo.ashmem.MemoryServicequot private MemoryFile file null public MemoryService try file new MemoryFilequotAshmemquot 4 setValue0 catchIOException ex Log.iLOG_TAG quotFailed to create memory file.quot ex.printStackTrace public ParcelFileDescriptor getFileDescriptor Log.iLOG_TAG quotGet File Descriptor.quot ParcelFileDescriptor pfd null try pfd file.getParcelFileDescriptor catchIOException ex Log.iLOG_TAG quotFailed to get file descriptor.quot ex.printStackTrace return pfd public void setValueint val iffile null return byte buffer new byte4 buffer0 byteval gtgtgt 24 amp 0xFF buffer1 byteval gtgtgt 16 amp 0xFF buffer2 byteval gtgtgt 8 amp 0xFF buffer3 byteval amp 0xFF try file.writeBytesbuffer 0 0 4 Log.iLOG_TAG quotSet value quot val quot to memory file. quot catchIOException ex Log.iLOG_TAG quotFailed to write bytes to memory file.quot ex.printStackTrace 注意这里的MemoryService类实现了IMemoryService.Stub类表示这是一个Binder服务的本地实现。
在构造函数中通过指定文件名和文件大小来创建了一个匿名共享内存文件即创建MemoryFile的一个实例并保存在类成员变量file中。
这个匿名共享内存文件名为quotAshmemquot大小为4个节字刚好容纳一个整数我们这里举的例子就是要说明如果创建一个匿名共享内存来在两个进程间实现共享一个整数了。
当然在实际应用中可以根据需要创建合适大小的共享内存来共享有意义的数据。
这里还实现了IMemoryService.Stub的两个接口getFileDescriptor和setVal一个用来获取匿名共享内存文件的文件描述符一个来往匿名共享内存文件中写入一个整数其中接口getFileDescriptor的返回值是一个ParcelFileDescriptor。
在Java中是用FileDescriptor类来表示一个文件描述符的而ParcelFileDescriptor是用来序列化FileDescriptor的以便在进程间调用时传输。
定义好本地服务好就要定义一个Server来启动这个服务了。
这里定义的Server实现在src/shy/luo/ashmem/Server.java文件中 package shy.luo.ashmemimport
android.app.Serviceimport
android.content.Intentimport
android.os.IBinderimport
android.util.Logimport
android.os.ServiceManagerpublic class Server extends Service private final static String LOG_TAG quotshy.luo.ashmem.Serverquot private MemoryService memoryService null Override public IBinder onBindIntent intent return null Override public void onCreate Log.iLOG_TAG quotCreate Memory Service...quot memoryService new MemoryService try ServiceManager.addServicequotAnonymousSharedMemoryquot memoryService Log.iLOG_TAG quotSucceed to add memory service.quot catch RuntimeException ex Log.iLOG_TAG quotFailed to add Memory Service.quot ex.printStackTrace Override public void onStartIntent intent int startId Log.iLOG_TAG quotStart Memory Service.quot Override public void onDestroy Log.iLOG_TAG quotDestroy Memory Service.quot 这个Server继承了
Android系统应用程序框架层提供的Service类当它被启动时运行在一个独立的进程中。
当这个Server被启动时它的onCreate函数就会被调用然后它就通过ServiceManager的addService接口来添加MemoryService了 memoryService new MemoryService try ServiceManager.addServicequotAnonymousSharedMemoryquot memoryService Log.iLOG_TAG quotSucceed to add memory service.quot catch RuntimeException ex Log.iLOG_TAG quotFailed to add Memory Service.quot ex.printStackTrace 这样当这个Server成功启动了Client就可以通过ServiceManager的getService接口来获取这个MemoryService了。
接着我们就来看Client端的实现。
Client端是一个Activity实现在src/shy/luo/ashmem/Client.java文件中 package shy.luo.ashmemimport java.io.FileDescriptorimport java.io.IOExceptionimport shy.luo.ashmem.Rimport
android.app.Activityimport
android.content.Intentimport
android.os.Bundleimport
android.os.MemoryFileimport
android.os.ParcelFileDescriptorimport
android.os.ServiceManagerimport
android.os.RemoteExceptionimport
android.util.Logimport
android.view.Viewimport
android.view.View.OnClickListenerimport
android.widget.Buttonimport
android.widget.EditTextpublic class Client extends Activity implements OnClickListener private final static String LOG_TAG quotshy.luo.ashmem.Clientquot IMemoryService memoryService null MemoryFile memoryFile null private EditText valueText null private Button readButton null private Button writeButton null private Button clearButton null Override public void onCreateBundle savedInstanceState super.onCreatesavedInstanceState setContentViewR.layout.main IMemoryService ms getMemoryService ifms null startServicenew Intentquotshy.luo.ashmem.serverquot else Log.iLOG_TAG quotMemory Service has started.quot valueText EditTextfindViewByIdR.id.edit_value readButton ButtonfindViewByIdR.id.button_read writeButton ButtonfindViewByIdR.id.button_write clearButton ButtonfindViewByIdR.id.button_clear readButton.setOnClickListenerthis writeButton.setOnClickListenerthis clearButton.setOnClickListenerthis Log.iLOG_TAG quotClient Activity Created.quot Override public void onResume super.onResume Log.iLOG_TAG quotClient Activity Resumed.quot Override public void onPause super.onPause Log.iLOG_TAG quotClient Activity Paused.quot Override public void onClickView v ifv.equalsreadButton int val 0 MemoryFile mf getMemoryFile ifmf null try byte buffer new byte4 mf.readBytesbuffer 0 0 4 val buffer0 ltlt 24 buffer1 amp 0xFF ltlt 16 buffer2 amp 0xFF ltlt 8 buffer3 amp 0xFF catchIOException ex Log.iLOG_TAG quotFailed to read bytes from memory file.quot ex.printStackTrace String text String.valueOfval valueText.setTexttext else ifv.equalswriteButton String text valueText.getText.toString int val Integer.parseInttext IMemoryService ms getMemoryService ifms null try ms.setValueval catchRemoteException ex Log.iLOG_TAG quotFailed to set value to memory service.quot ex.printStackTrace else ifv.equalsclearButton String text quotquot valueText.setTexttext private IMemoryService getMemoryService ifmemoryService null return memoryService memoryService IMemoryService.Stub.asInterface ServiceManager.getServicequotAnonymousSharedMemoryquot Log.iLOG_TAG memoryService null quotSucceed to get memeory service.quot : quotFailed to get memory service.quot return memor.
上一篇:
android surfaceflinger研究
下一篇:
扛起年轻化大旗,哈弗F系玩转行业新风潮