• Android系统匿名共享内存(Anonymous Shared Memory)Java调用接口分析


    一、Ashmem驱动程序

          ~/Android/kernel/goldfish

          ----include

                  ----linux

                           ----ashmem.h

          ----mm

                  ----ashmem.c

          驱动程序具体解释请看《Android系统源码情景分析》。作者罗升阳。


    二、执行时库cutils的匿名共享内存訪问接口

          ~/Android/system/core

          ----libcutils

                   ----ashmem-dev.c

           具体解释请看《Android系统源码情景分析》,作者罗升阳。


    三、MemoryFile

          ~/Android/frameworks/base/core/java/android/os

          ----MemoryFile.java

          ~/Android/frameworks/base/core/jni

          ----android_os_MemoryFile.cpp

          具体解释请看《Android系统源码情景分析》,作者罗升阳。

          ~/Android/frameworks/base/core/java/android/os

          ----MemoryFile.java

        public ParcelFileDescriptor getParcelFileDescriptor() throws IOException {
            FileDescriptor fd = getFileDescriptor();
            return fd != null ?

    new ParcelFileDescriptor(fd) : null; } ....... public FileDescriptor getFileDescriptor() throws IOException { return mFD; }


    四、应用实例

          具体解释请看《Android系统源码情景分析》,作者罗升阳。

          在本节中。我们将创建一个Android应用程序Ashmem。它由一个Service组件Server和一个Activity组件Client组成。Server组件执行在一个独立的进程中,它内部有一个内存訪问服务MemoryService,后者通过MemoryFile类创建一块匿名共享内存。

    Client组件执行在还有一个进程中,它会将内存訪问服务MemoryService创建的那块匿名共享内存映射到本进程的地址空间,以便能够訪问它的内容,从而能够和Server组件共享一块匿名共享内存。

          ~/Android/packages/experimental/Ashmem

          ----AndroidManifest.java

          ----Android.mk

          ----src

                 ----shy/luo/ashmem

                                ----IMemoryService.java

                                ----MemoryService.java

                                ----Server.java

                                ----Client.java

          ----res

                 ----layout

                          ----main.xml

                 ----values

                          ----strings.xml

                 ----drawable

                          ----icon.png


          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;
    }

          MemoryService.java

    package shy.luo.ashmem;
    
    import java.io.FileDescriptor;
    import java.io.IOException;
    
    import android.os.Parcel;
    import android.os.MemoryFile;
    import android.os.ParcelFileDescriptor;
    import android.util.Log;
    
    public class MemoryService extends IMemoryService.Stub {
    	private final static String LOG_TAG = "shy.luo.ashmem.MemoryService";
    	private MemoryFile file = null;
    	
    	public MemoryService() {
    		try {
                            file = new MemoryFile("Ashmem", 4);
                            setValue(0);
                    }
                    catch(IOException ex) {
                            Log.i(LOG_TAG, "Failed to create memory file.");
                            ex.printStackTrace();
                    }
    	}
    
    	public ParcelFileDescriptor getFileDescriptor() {
    		Log.i(LOG_TAG, "Get File Descriptor.");
    
    		ParcelFileDescriptor pfd = null;
    
    		try {
    			pfd = file.getParcelFileDescriptor();
    		} catch(IOException ex) {
    			Log.i(LOG_TAG, "Failed to get file descriptor.");
    			ex.printStackTrace();
    		}
    
    		return pfd;
    	}
    	
    	public void setValue(int val) {
    		if(file == null) {
    			return;
    		}
    
    		byte[] buffer = new byte[4];   
    		buffer[0] = (byte)((val >>> 24) & 0xFF);
    		buffer[1] = (byte)((val >>> 16) & 0xFF);
    		buffer[2] = (byte)((val >>> 8) & 0xFF); 
    		buffer[3] = (byte)(val & 0xFF);
    		
    		try {
    			file.writeBytes(buffer, 0, 0, 4);
    			Log.i(LOG_TAG, "Set value " + val + " to memory file. ");
    		}
    		catch(IOException ex) {
    			Log.i(LOG_TAG, "Failed to write bytes to memory file.");
    			ex.printStackTrace();
    		}
    	}
    }

          Server.java

    package shy.luo.ashmem;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.util.Log;
    import android.os.ServiceManager;
    
    public class Server extends Service {
        private final static String LOG_TAG = "shy.luo.ashmem.Server";
    
        private MemoryService memoryService = null;
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public void onCreate() {
    	Log.i(LOG_TAG, "Create Memory Service...");
    
    	memoryService = new MemoryService();
    
            try {
                ServiceManager.addService("AnonymousSharedMemory", memoryService);
                Log.i(LOG_TAG, "Succeed to add memory service.");
            } catch (RuntimeException ex) {
                Log.i(LOG_TAG, "Failed to add Memory Service.");
                ex.printStackTrace();
            }
    
        }
    
        @Override
        public void onStart(Intent intent, int startId) {
            Log.i(LOG_TAG, "Start Memory Service.");
        }
    
        @Override
        public void onDestroy() {
    	Log.i(LOG_TAG, "Destroy Memory Service.");
        }
    }

          Client.java

    package shy.luo.ashmem;
    
    import java.io.FileDescriptor;
    import java.io.IOException;
    
    import shy.luo.ashmem.R;
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.MemoryFile;
    import android.os.ParcelFileDescriptor;
    import android.os.ServiceManager;
    import android.os.RemoteException;
    import android.util.Log;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.EditText;
    
    public class Client extends Activity implements OnClickListener {
    	private final static String LOG_TAG = "shy.luo.ashmem.Client";
    	
    	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 onCreate(Bundle savedInstanceState) {
            	super.onCreate(savedInstanceState);
            	setContentView(R.layout.main);
    
    		IMemoryService ms = getMemoryService();
    		if(ms == null) {        
            		startService(new Intent("shy.luo.ashmem.server"));
    		} else {
    			Log.i(LOG_TAG, "Memory Service has started.");
    		}
    
            	valueText = (EditText)findViewById(R.id.edit_value);
            	readButton = (Button)findViewById(R.id.button_read);
            	writeButton = (Button)findViewById(R.id.button_write);
            	clearButton = (Button)findViewById(R.id.button_clear);
    
    		readButton.setOnClickListener(this);
            	writeButton.setOnClickListener(this);
            	clearButton.setOnClickListener(this);
            
            	Log.i(LOG_TAG, "Client Activity Created.");
        	}
    
        	@Override
        	public void onResume() {
    		super.onResume();
    
    		Log.i(LOG_TAG, "Client Activity Resumed.");
        	}
    
        	@Override
        	public void onPause() {
    		super.onPause();
    
    		Log.i(LOG_TAG, "Client Activity Paused.");
        	}
        
        	@Override
        	public void onClick(View v) {
        		if(v.equals(readButton)) {
        			int val = 0;
        		
        			MemoryFile mf = getMemoryFile();
        			if(mf != null) {
    				try {
        					byte[] buffer = new byte[4];
        					mf.readBytes(buffer, 0, 0, 4);
        			
        					val = (buffer[0] << 24) | ((buffer[1] & 0xFF) << 16) | ((buffer[2] & 0xFF) << 8) | (buffer[3] & 0xFF);
    				} catch(IOException ex) {
    					Log.i(LOG_TAG, "Failed to read bytes from memory file.");
    					ex.printStackTrace();
    				}
        			}	
        		
        			String text = String.valueOf(val);
        			valueText.setText(text);
        		} else if(v.equals(writeButton)) {
        			String text = valueText.getText().toString();
        			int val = Integer.parseInt(text);
        		
        			IMemoryService ms = getMemoryService();
        			if(ms != null) {
    				try {
        					ms.setValue(val);
    				} catch(RemoteException ex) {
    					Log.i(LOG_TAG, "Failed to set value to memory service.");
    					ex.printStackTrace();
    				}
        			}
        		} else if(v.equals(clearButton)) {
        			String text = "";
        			valueText.setText(text);
        		}
        	}
        
        	private IMemoryService getMemoryService() {
        		if(memoryService != null) {
        			return memoryService;
        		}
        	
        		memoryService = IMemoryService.Stub.asInterface(
                    			ServiceManager.getService("AnonymousSharedMemory"));
    
    		Log.i(LOG_TAG, memoryService != null ? "Succeed to get memeory service." : "Failed to get memory service.");
        	
        		return memoryService;
        	}
        
        	private MemoryFile getMemoryFile() {
        		if(memoryFile != null) {
        			return memoryFile;
        		}
        		
        		IMemoryService ms = getMemoryService();
        		if(ms != null) {
    			try {
        				ParcelFileDescriptor pfd = ms.getFileDescriptor();
    				if(pfd == null) {
    					Log.i(LOG_TAG, "Failed to get memory file descriptor.");
    					return null;
    				}
    
    				try {
    					FileDescriptor fd = pfd.getFileDescriptor();
    					if(fd == null) {
    						Log.i(LOG_TAG, "Failed to get memeory file descriptor.");
    						return null;                      
    					}	
    
        					memoryFile = new MemoryFile(fd, 4, "r");
    				} catch(IOException ex) {
    					Log.i(LOG_TAG, "Failed to create memory file.");
    					ex.printStackTrace();
    				}
        			} catch(RemoteException ex) {
    				Log.i(LOG_TAG, "Failed to get file descriptor from memory service.");
    				ex.printStackTrace();
    			}
    		}
        	
        		return memoryFile;
        	}
    }

           首先開始在Activity,onCreate时开启了Service。然后点击读按钮,执行相应代码。

           进程间通信具体步骤,临时省略,仅仅看表明的步骤,见下图:


          接下来的分析,请看Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析http://blog.csdn.net/luoshengyang/article/details/6666491

           注意上文中的这句话,  这里, 我们须要关注的便是虚线框部分了,它在Binder驱动程序中实现了在两个进程中共享同一个打开文件的方法。我们知道。在Linux系统中,文件描写叙述符事实上就是一个整数。每个进程在内核空间都有一个打开文件的数组,这个文件描写叙述符的整数值就是用来索引这个数组的。并且,这个文件描写叙述符仅仅是在本进程内有效,也就是说。在不同的进程中,同样的文件描写叙述符的值。代表的可能是不同的打开文件。因此。在进程间传输文件描写叙述符时,不能简要地把一个文件描写叙述符从一个进程传给另外一个进程。中间必须做一过转换。使得这个文件描写叙述在目标进程中是有效的,并且它和源进程的文件描写叙述符所相应的打开文件是一致的。这样才干保证共享。

             也就是依据fd。得到的file结构,在两个进程是一样的。即使两个进程的fd不一样。

  • 相关阅读:
    常用资料管理
    IIC学习笔记
    博客的开始
    试用Markdown编辑器
    裁剪方法--layer.makesToBounds 和 clipsToBounds区别和联系
    block循环引用问题--内存泄露
    UITextFiled/UITextView---占位文字的设置
    使用KVC取得私有成员变量时报连线错误
    Xcode开发--运行时runtime
    Xcode开发--屏蔽警告
  • 原文地址:https://www.cnblogs.com/zsychanpin/p/6880295.html
Copyright © 2020-2023  润新知