匿名共享内存Ashmem实例--C++

ashmem主要 用于两个进程 的内存共享.

使用步骤:

1、server端调用ashmem_create_region创建一个共享内存,调用mmap进行内存映射,并把这个fd通过binder返回给client端面

2、client使用从server端拿到的句柄fd,调用mmap进行内存映射,这样client和server端 就映射到了同一块内存区域,从而实现共享。

相关代码实现

首先看一下binder基类

#ifndef ANDROID_ITESTBINDERSERVICE_H_
#define ANDROID_ITESTBINDERSERVICE_H_

#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>


namespace android {

class Parcel;

class ITestBinderService: public IInterface {
public:
	DECLARE_META_INTERFACE(TestBinderService);
	virtual int allocbuf(int pipe_fd, const char* name, int bs) = 0;
};

class BnTestBinderService: public BnInterface<ITestBinderService> {
public:
	virtual status_t onTransact(uint32_t code, const Parcel& data,
			Parcel* reply, uint32_t flags = 0);
};

}

#endif /* ANDROID_ITESTBINDERSERVICE_H_ */

定义一个ITestBinderService的基类,还有一个BnTestBinderService实现binder的Bn服务端,这里定义了一个方法allocbuf,传入一个管道的一端面,还有共享内存的名字,长度。

现来看一下Bp的实现

#include <utils/Log.h>

#include "../TestBinderServer_new/ITestBinderService.h"

namespace android {

enum {
	TEST_ALLOCBUF = IBinder::FIRST_CALL_TRANSACTION,
};

class BpTestBinderService: public BpInterface<ITestBinderService> {
public:
	BpTestBinderService(const sp<IBinder>& impl) :
		BpInterface<ITestBinderService> (impl) {
	}

	int allocbuf(int pipe_fd, const char* name, int bs) {
			Parcel data, reply;
		LOGI("Enter BpTestBinderService allocbuf,pipe_fd = %d , bs = %d", pipe_fd, bs);
		data.writeInterfaceToken(ITestBinderService::getInterfaceDescriptor());
		data.writeFileDescriptor(pipe_fd);
		data.writeCString(name);
		data.writeInt32(bs);
		remote()->transact(TEST_ALLOCBUF, data, &reply);
		int fd = reply.readFileDescriptor();
		LOGI("BpTestBinderService fd = %d", fd);
		 int fd2 = dup(fd);
		 LOGI("fd2 = %d", fd2);
		 perror("3dup: ");
		return fd2;
		
	}
};

IMPLEMENT_META_INTERFACE(TestBinderService, "android.test.ITestBinderService");

// ----------------------------------------------------------------------

status_t BnTestBinderService::onTransact(uint32_t code, const Parcel& data,
		Parcel* reply, uint32_t flags) {
	switch (code) {


	case TEST_ALLOCBUF: {
		
		CHECK_INTERFACE(ITestBinderService, data, reply);
		int pipe_fd = data.readFileDescriptor();
		const char *name = data.readCString();
		int bs = data.readInt32();
		
		LOGI("Enter BnTestBinderService add,pipe_fd = %d , bs = %d", pipe_fd, bs);
		int sum = 0;
		int fd  = allocbuf(pipe_fd, name, bs);
		LOGI("2BnTestBinderService fd = %d", fd);
		 reply->writeFileDescriptor(fd);
		 int fd2= dup(fd);
		  LOGI("fd2 = %d", fd2);
		 perror("2dup: ");
		return sum;
	}
	default:
		return BBinder::onTransact(code, data, reply, flags);
	}
}
Bp端调用writeFileDescriptor把管道句柄写进去,然后和Server端面通信后读出共享内存的句柄,注意这里是调用writeFileDescriptor和readFileDescriptor,还有一个就是在Server端返回后,读到的句柄要dup,否则直接使用会报错,而且好像必须这里返回之后就必须 dup,如果直接返回fd再dup好像也是会有问题

BnTestBinderService则恰好相反,读到相关参数,调用allocbuf函数,再把结果返回给Client端

再来看一下TestBinderService,主要是实现了BnTestBinderService

#include <utils/KeyedVector.h>
#include "ITestBinderService.h"

namespace android {

class TestBinderService: public BnTestBinderService {
public:
	static void instantiate();
	int add(int a,int b);
	int allocbuf(int pipe_fd, const char* name, int bs);
	static void* test_proc(void*a);

	
private:
	TestBinderService();
	virtual ~TestBinderService();
};

}

#include <utils/Log.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/mman.h>
#include <cutils/ashmem.h>

#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "binderservice.h"
#include "TestBinderService.h"


static int m_fd ;
static int m_pipe_fd;
char *m_buf;
namespace android {



void TestBinderService::instantiate() {
	LOGI("Enter TestBinderService::instantiate");
	status_t st = defaultServiceManager()->addService(
			String16("my.test.binder"), new TestBinderService());
	LOGD("ServiceManager addService ret=%d", st);
	LOGD("instantiate> end");
}

TestBinderService::TestBinderService() {
	m_fd = -1;
	m_buf = NULL;
	m_pipe_fd = -1;
	LOGD(" TestBinderServicet");
}

TestBinderService::~TestBinderService() {
	LOGD("TestBinderService destroyed,never destroy normally");
}

void* TestBinderService::test_proc(void*a) {
	char buf[100];
	int len = 100;
	int read_len = -1;
	int write_len = -1;
	while(1)
	{
		read_len = read(m_pipe_fd, buf, 12);
		LOGI("TestBinderService::read_len = %d.buf = %s",read_len, buf);	
		sleep(1);
		if(read_len > 0)
		{
			//write_len = write(m_fd, "from server", 12);
			strncpy(m_buf, "from server", 12);
		}
		LOGI("TestBinderService::write_len = %d.",write_len);
	}
	
	return NULL;
}

int TestBinderService::allocbuf(int pipe_fd, const char* name, int bs) {
	int result = -1;
	pthread_t th;
	
	LOGI("TestBinderService::allocbuf pipe_fd = %d, bs = %d.", pipe_fd , bs);	
	m_pipe_fd = dup(pipe_fd);
	LOGI("m_pipe_fd = %d", m_pipe_fd);
	m_fd = ashmem_create_region(name, bs);
	if(m_fd > 0)
	{
		m_buf = (char *)mmap(0, bs, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd , 0);
		if(m_buf == (void*)-1)
			LOGI("TestBinderService mmap fail");
	}
	LOGI("TestBinderService::m_fd = %d. m_buf = 0x%x",m_fd, m_buf);	
	 int fd2 = dup(m_fd);
	 LOGI("fd2 = %d", fd2);
	 perror("1dup: ");
	pthread_create(&th, NULL, test_proc, NULL);
	return m_fd;
} 


}

这里调用ashmem_create_region 创建匿名共享内存,然后调用mmap进行内存映射,创建一个线程,从管道读数据,并拷贝数据到共享内存

接下来就要启动这个Service

#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>


#include "TestBinderService.h"

using namespace android;

int main(int argc, char** argv)
 {
	
	sp<ProcessState> proc(ProcessState::self());
	sp<IServiceManager> sm = defaultServiceManager();
	LOGI("TestBinderService before");
	TestBinderService::instantiate();
	LOGI("TestBinderService End");
	ProcessState::self()->startThreadPool();
	IPCThreadState::self()->joinThreadPool();
	return 0;

}

再就是测试case

#include <binder/IServiceManager.h>
#include "../TestBinderServer_new/ITestBinderService.h"
//#include	"testBinder.h"

#include "TestBinderService.h"

using namespace android;


int write_pipe_fd = -1;
int m_fd = -1;
char *m_buf = NULL;
static void* test_proc(void*a) {
	char buf[100];
	int len = 100;
	int read_len = -1;
	int write_len = -1;
	while(1)
	{
		write_len = write(write_pipe_fd, "from client", 12);
		
		LOGI("TestBinderClient::write_len = %d.",write_len);	
		sleep(1);
		if(write_len > 0)
		{
			
		}
		if(m_buf != (void*)-1)
			LOGI("TestBinderClient::read_len = %d.m_buf = %s",read_len, m_buf);
	}
	
	return NULL;
}
int main()
{
	int sum = 0;
	pthread_t th;	
	sp<ITestBinderService> mTestBinserService;
	if (mTestBinserService.get() == 0) {
		sp<IServiceManager> sm = defaultServiceManager();
		sp<IBinder> binder;
		do {
			binder = sm->getService(String16("my.test.binder"));
			if (binder != 0)
				break;
				LOGI("getService fail");
			usleep(500000); // 0.5 s
		} while (true);
		mTestBinserService = interface_cast<ITestBinderService> (binder);
		LOGE_IF(mTestBinserService == 0, "no ITestBinserService!?");
	}
	
	sum = mTestBinserService->add(3, 4);
	int pipe_fd[2];
	pipe(pipe_fd);
	write_pipe_fd = pipe_fd[1];
	LOGI("pipe_fd[0] = %d, pipe_fd[1] = %d", pipe_fd[0], pipe_fd[1]);
	 m_fd = mTestBinserService->allocbuf(pipe_fd[0], "test", 1024);
	 close(pipe_fd[0]);
	 LOGI("m_fd = %d", m_fd);
	 m_fd = dup(m_fd);
	 perror("dup: ");
	 LOGI("m_fd = %d", m_fd);
	m_buf = (char *)mmap(0, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd , 0);
	if(m_buf == (void*)-1){
			LOGI("TestBinderService mmap fail");
			perror("mmap: ");}
	 LOGI("m_fd = %d m_buf = 0x%x", m_fd, m_buf);
	pthread_create(&th, NULL, test_proc, NULL);
	close(pipe_fd[0]);
	while(1)
		sleep(1);
	
	return 0;

}

首先获取Service,然后调用allocbuf把管道的读端传过去,返回一个共享内在的句柄后,调用mmap进行内存映射,同样也是新建一个进程,不断的往管道里面写数据,然后把映射的共享内存的值打印出来,这个值是Service端写进去的。

相应log:

I/        ( 1433): TestBinderService before
I/TestBinderService( 1433): Enter TestBinderService::instantiate
D/TestBinderService( 1433):  TestBinderServicet
D/TestBinderService( 1433): ServiceManager addService ret=0
D/TestBinderService( 1433): instantiate> end
I/        ( 1433): TestBinderService End
D/KeyguardUpdateMonitor( 1058): received broadcast android.intent.action.TIME_TICK
D/KeyguardUpdateMonitor( 1058): handleTimeUpdate
I/        ( 1436): int the main function
I/ITeeveePlayerService( 1436): Enter BpTestBinderService add,a = 3 , b = 4
I/ITeeveePlayerService( 1433): Enter BnTestBinderService add,a = 3 , b = 4
I/TestBinderService( 1433): TestBinderService::add a = 3, b = 4.
D/        ( 1433):  sum2 a = 3, b = 4
I/TestBinderService( 1433): TestBinderService::result = 7.
I/ITeeveePlayerService( 1433): BnTestBinderService sum = 7
I/ITeeveePlayerService( 1436): BpTestBinderService sum = 7
I/TestBinserService( 1436): pipe_fd[0] = 28, pipe_fd[1] = 29
I/ITeeveePlayerService( 1436): Enter BpTestBinderService allocbuf,pipe_fd = 28 , bs = 1024
I/ITeeveePlayerService( 1433): Enter BnTestBinderService add,pipe_fd = 28 , bs = 1024
I/TestBinderService( 1433): TestBinderService::allocbuf pipe_fd = 28, bs = 1024.
I/TestBinderService( 1433): m_pipe_fd = 29
I/TestBinderService( 1433): TestBinderService::m_fd = 30. m_buf = 0x40107000
I/TestBinderService( 1433): fd2 = 31
I/ITeeveePlayerService( 1433): 2BnTestBinderService fd = 30
I/ITeeveePlayerService( 1433): fd2 = 32
I/ITeeveePlayerService( 1436): BpTestBinderService fd = 30
I/ITeeveePlayerService( 1436): fd2 = 31
I/TestBinserService( 1436): m_fd = 31
I/TestBinserService( 1436): m_fd = 28
I/TestBinserService( 1436): m_fd = 28 m_buf = 0x40107000
I/TestBinserService( 1436): TestBinderClient::write_len = 12.
I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
I/TestBinderService( 1433): TestBinderService::write_len = -1.
I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
I/TestBinserService( 1436): TestBinderClient::write_len = 12.
I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
I/TestBinserService( 1436): TestBinderClient::write_len = 12.
I/TestBinderService( 1433): TestBinderService::write_len = -1.
I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
I/TestBinserService( 1436): TestBinderClient::write_len = 12.
I/TestBinderService( 1433): TestBinderService::write_len = -1.
I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
I/TestBinserService( 1436): TestBinderClient::write_len = 12.
I/TestBinderService( 1433): TestBinderService::write_len = -1.
I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
I/TestBinserService( 1436): TestBinderClient::write_len = 12.
I/TestBinderService( 1433): TestBinderService::write_len = -1.
I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
I/TestBinserService( 1436): TestBinderClient::write_len = 12.
I/TestBinderService( 1433): TestBinderService::write_len = -1.
I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
I/TestBinserService( 1436): TestBinderClient::write_len = 12.
I/TestBinderService( 1433): TestBinderService::write_len = -1.
I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
I/TestBinserService( 1436): TestBinderClient::write_len = 12.
I/TestBinderService( 1433): TestBinderService::write_len = -1.
I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
I/TestBinserService( 1436): TestBinderClient::write_len = 12.
I/TestBinderService( 1433): TestBinderService::write_len = -1.
I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
I/TestBinserService( 1436): TestBinderClient::write_len = 12.
I/TestBinderService( 1433): TestBinderService::write_len = -1.
I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
I/TestBinserService( 1436): TestBinderClient::write_len = 12.
I/TestBinderService( 1433): TestBinderService::write_len = -1.
I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
init: untracked pid 1436 exited
I/TestBinderService( 1433): TestBinderService::write_len = -1.
I/TestBinderService( 1433): TestBinderService::read_len = 0.buf = from client
init: untracked pid 1433 exited
I/ServiceManager(  766): service 'my.test.binder' died


实例代码:

http://download.csdn.net/download/new_abc/4744981

### 回答1: Android C的共享内存是一种高效的IPC机制,它允许不同的进程共享内存区域,从而实现数据共享和数据传输。在Android系统中,使用共享内存有两种基本方法:POSIX共享内存Ashmem。 POSIX共享内存(shm_open系统调用)是基于文件的IPC机制,它可以在不同的进程间共享文件系统中的内存块。在使用该方法时,首先创建并打开一个共享内存对象以便其他进程能够在其中写入或读取数据。与普通文件不同的是,该对象可以被多个进程同时访问,从而实现内存共享和数据传输。 Ashmem是Android专有的共享内存机制,它通过匿名内存映射(mmap系统调用)来创建共享内存,使多个进程可以共享相同的内存区域。在使用Ashmem时,首先在一个进程中分配一块内存区域,并将其标记为共享内存。其他进程可以通过Binder接口来获取该内存区域所对应的Ashmem文件描述符,并进一步映射内存区域,以便共享数据。 正如所见,Android C的共享内存机制提供了一种高效的IPC方法,可以在不同的进程之间实现数据共享和数据传输。但是由于共享内存存在并发访问、内存泄露等问题,因此在应用中使用时需要格外小心。 ### 回答2: Android C共享内存是一种在Android系统中用于不同进程间共享数据的机制。在多进程应用程序中,进程之间共享数据允许各个进程共同访问数据,从而提高系统的整体性能。C共享内存实现了这种数据共享的方式,允许多个进程可以同步地访问相同的内存区域,从而实现数据共享。 C共享内存操作需要用到管道和信号量等Linux中的IPC技术。进程可以通过信号量来控制对共享内存区域的访问,从而实现数据同步。同时,通过管道机制,同步地向共享内存区域写入和读出数据。在Android开发中,通常会使用NDK库和底层C语言来实现共享内存操作,可以对共享内存区域进行读写操作和管理。 通常情况下,在Android的多进程应用程序中,可以使用C共享内存来实现不同进程之间的数据共享,从而提高应用程序的整体性能和响应速度。C共享内存也可以被用于进程间的通信,例如在游戏和音视频应用程序中,可以使用共享内存来实现不同进程的交互与协作。总的来说,Android C共享内存提供了一种能够优化应用程序性能和提高用户体验的底层机制。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值