Android调用C++实现共享内存(Native层)
Android下匿名共享内存java层接口利用MemoryFile实现进程间内存共享;利用MemoryFile可以参考这篇文章:https://blog.csdn.net/qq_24451593/article/details/80514566
MemoryFile是java层封装的接口,它实现共享内存主要调用了如下函数:
int fd = open("/dev/ashmem",O_RDWR);ioctl(fd, ASHMEM_SET_NAME,name);ioctl(fd,ASHMEM_SET_SIZE, size);//addr为共享内存地址addr = (char*)mmap(NULL, size , PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
创建出来的fd转换成ParcelFileDescriptor通过AIDL传递给另一个进程;另一个进程将ParcelFileDescriptor转换成该进程对应fd,调用mmap来使用该共享内存。
注:进程A的fd与进程B的fd是不一样的,但是都对应同一文件
既然知道了MemoryFile实际调用函数,那么我们就可以在native层用C++代码实现共享内存。
(1)C++代码实现
android_shm.cpp
#include "android_shm.h"#define ASHMEM_DEVICE "/dev/ashmem"//ret= 0 创建成功;ret=-1,失败;//注:ret =1,共享内存已经存在,但是目前这个没用,暂时放这int create_shared_memory(const char* name, U64 size, int node, char*& addr, U64& shm_id){ U64 fd = open(ASHMEM_DEVICE, O_RDWR); if(fd < 0){ return -1; } U64 len = ioctl(fd, ASHMEM_GET_SIZE, NULL); if(len > 0){ addr = (char*)mmap(NULL, size , PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); shm_id = fd; return 1; }else{ int ret = ioctl(fd, ASHMEM_SET_NAME,name); if(ret < 0){ close(fd); return -1; } ret = ioctl(fd,ASHMEM_SET_SIZE, size); if(ret < 0){ close(fd); return -1; } addr = (char*)mmap(NULL, size , PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); shm_id = fd; } return 0;}int open_shared_memory(const char* name, int node, char*& addr, U64& shm_id){ U64 size = ioctl(shm_id, ASHMEM_GET_SIZE,NULL); if(size > 0){ addr = (char*)mmap(NULL, size , PROT_READ | PROT_WRITE, MAP_SHARED, shm_id, 0); }else{ return -1; } return 0;}int close_shared_memory(U64& shm_id, char*& addr){ U64 size = ioctl(shm_id, ASHMEM_GET_SIZE, NULL); if(size <0){ return -1; } int ret = munmap((void*)addr, size); if(ret == -1){ return -1; } ret = close(shm_id); if(ret == -1){ return -1; } return 0;}
android_shm.h
#ifndef _SYS_SHM_H#define _SYS_SHM_H 1#include #define SHM_HUGETLB 04000#include #include #include #include #include /* Get common definition of System V style IPC. */#include /* Get system dependent definition of `struct shmid_ds' and more. */#include typedef unsigned long long U64;__BEGIN_DECLSextern int create_shared_memory(const char* name, U64 size, int node, char*& addr, U64& shm_id);extern int open_shared_memory(const char* name, int node, char*& addr, U64& shm_id);extern int close_shared_memory(U64& shm_id, char*& addr);__END_DECLS#endif /* sys/shm.h */
Android.mk
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := libandroid_shmLOCAL_SRC_FILES := android_shm.cppinclude $(BUILD_SHARED_LIBRARY)
(2)ndk-build编译C++
参考我另一篇博客:https://blog.csdn.net/liny000/article/details/83020530
(3)将进程A的fd传给进程B
利用binder跨进程通信
1)服务类实现binder onTransact函数(两个进程传递ParcelFileDescriptor)
MainService.java
public class MainService extends Service { ParcelFileDescriptor pfd; @Override public IBinder onBind(Intent arg0) { return new MyBinder(); } class MyBinder extends Binder { @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case 0: //pfd = data.readParcelable(null); // 或者 pfd = data.readFileDescriptor(); break; case 1: //reply.writeParcelable(pfd,0); // 或者 reply.writeFileDescriptor(pfd.getFileDescriptor()); break; default: break; } return true; } }}
2)MainActivity 调用C++代码创建共享内存并写入内容,得到fd,转换为ParcelFileDescriptor 传递给MainActivity2
MainActivity.java
package com.example.linyuan.shared_memory;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Binder;import android.os.Bundle;import android.os.IBinder;import android.os.MemoryFile;import android.os.ParcelFileDescriptor;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.support.design.widget.FloatingActionButton;import android.support.design.widget.Snackbar;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.view.View;import android.view.Menu;import android.view.MenuItem;import java.io.FileDescriptor;import java.io.IOException;import java.lang.reflect.Method;public class MainActivity extends AppCompatActivity { // Used to load the 'native-lib' library on application startup. static { System.loadLibrary("native-lib"); } Binder mBinder; private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { mBinder = (Binder) service; } public void onServiceDisconnected(ComponentName className) { mBinder = null; } }; @Override protected void onDestroy() { unbindService(mConnection); mConnection = null; super.onDestroy(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent it = new Intent(MainActivity.this, MainService.class); startService(it); bindService(it, mConnection, Context.BIND_AUTO_CREATE); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); // Example of a call to a native method TextView tv = (TextView) findViewById(R.id.sample_text); Button button1 = (Button)findViewById(R.id.button1); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(MainActivity.this,MainActivity2.class)); } }); } android.os.Parcel data = android.os.Parcel.obtain(); android.os.Parcel reply = android.os.Parcel.obtain(); public void write(View v){ try { if(mBinder!=null){ // data.writeParcelable(pfd, 0); // 或者 int fd = fdFromJNI(); TextView tv = (TextView) findViewById(R.id.sample_text); tv.setText("fd:"+ new String(String.valueOf(fd))); ParcelFileDescriptor cfd = ParcelFileDescriptor.fromFd(fd); FileDescriptor fileDescriptor2 = cfd.getFileDescriptor(); data.writeFileDescriptor(fileDescriptor2); mBinder.transact(0, data, reply, 0); } } catch (Exception e) { e.printStackTrace();// Toast.makeText(this, "写失败", 0).show(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } /** * A native method that is implemented by the 'native-lib' native library, * which is packaged with this application. */ public native int fdFromJNI();}
3)获取ParcelFileDescriptor,转换为fd,读取共享内存上内容
MainActivity2.java
public class MainActivity2 extends AppCompatActivity { static { System.loadLibrary("native-lib"); } private byte[] buffer = new byte[20]; IBinder mBinder; private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // 非服务创建进程,获取的Binder只是一个代理Binder对象,不能直接转换 // mBinder = (Binder) service; mBinder = service; } public void onServiceDisconnected(ComponentName className) { mBinder = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_2); Intent it = new Intent(MainActivity2.this,MainService.class); startService(it); bindService(it, mConnection, Context.BIND_AUTO_CREATE); } public void read(View v) { TextView tv = (TextView) findViewById(R.id.tv); try { if (mBinder != null) { android.os.Parcel data = android.os.Parcel.obtain(); android.os.Parcel reply = android.os.Parcel.obtain(); mBinder.transact(1, data, reply, 0); //ParcelFileDescriptor pfd = reply.readParcelable(null); // 或者 ParcelFileDescriptor pfd = reply.readFileDescriptor(); if(pfd==null){ buffer = "ParcelFileDescriptor 空指针".getBytes(); tv.setText(new String(buffer)); return; } int fd = pfd.getFd(); String buf; buf = read(fd); tv.setText(new String(buf)); } } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onDestroy() { unbindService(mConnection); mConnection = null; super.onDestroy(); } public static native String read(int fd);}
native-lib.cpp 调用C++代码
#include #include #include "android_shm.h"extern "C" JNIEXPORT jint JNICALLJava_com_example_linyuan_shared_1memory_MainActivity_fdFromJNI( JNIEnv *env, jobject /* this */) { char* buf; U64 ufd = 0; int ret = create_shared_memory("test1",1024,-1,buf,ufd); strcpy(buf,"shared_test你好"); return ufd;}extern "C" JNIEXPORT jstring JNICALLJava_com_example_linyuan_shared_1memory_MainActivity2_read( JNIEnv *env, jobject /* this */,jint fd) { std::string hello = "进程2 "; U64 ufd = (U64)fd; char* buf; open_shared_memory("test1",-1,buf,ufd); char c[20]; sprintf(c,"%D",ufd); hello = hello +buf +" fd:" +c; close_shared_memory(ufd,buf); return env->NewStringUTF(hello.c_str());}
需要在AndroidManifest.xml里添加如下,android:process=":activity_2"是确保另一个进程读取共享内存
整个工程文件(Android studio)下载:https://download.csdn.net/download/liny000/10763992
更多相关文章
- Android的底层库libutils介绍
- Android——使用 Broastcast 实现进程间通讯
- Android(安卓)进程间通信 实例分析
- android 常见死机问题--log分析
- Android的Btimap处理大图片解决方法
- 《Android系统开发》笔记
- Android(安卓)Dalvik 内存管理学习
- Android(安卓)OOM内存溢出解决方案之一
- 如何使Android应用程序获取系统权限【转】