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++代码实现共享内存。
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_DECLS
extern 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_shm
LOCAL_SRC_FILES := android_shm.cpp
include $(BUILD_SHARED_LIBRARY)
参考我另一篇博客:https://blog.csdn.net/liny000/article/details/83020530
利用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 JNICALL
Java_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 JNICALL
Java_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