android跨进程实现共享内存

该博客详细介绍了在Android系统中如何实现跨进程共享内存,包括A和B都是普通应用、都是native服务程序以及A是普通应用,B是系统服务程序三种场景。主要利用了binder和ashmem技术,通过binder传递文件描述符实现进程间通信。在B端创建共享内存后,A端通过获取的文件描述符进行mmap操作,从而达到快速数据交换的目的。提供了完整的代码示例和项目链接供参考。
摘要由CSDN通过智能技术生成

前言

业务场景:A进程需要拷贝大buffer到B进程,且需要快,越快越好!
业务方:A & B双方都是普通app;A是普通app,B是native服务程序(native c++实现,在android源码下编译的服务程序);A & B都是native服务程序

首先,创建一块共享内存ashmem,则不管是普通app,还是系统服务程序,都有权限创建。但是,创建好了,需要另一边做mmap,而做mmap,需要传递共享内存的文件句柄fd,这个fd虽然是一个int值,但是通过通过socket啥的传递过去,是没办法做mmap的,因为另一个进程B,根本不认识这个int。怎么办?靠binderbinder可以把文件句柄,跨进程传输,保证打开的是同一个文件!

所以,android要实现共享内存,需要基于binder + ashmem

场景1: A&B都是普通app

这种比较简单,可以参考https://github.com/dev-area/ashmem。

场景2: A&B都是native服务程序

这种比较简单,可以参考https://cloud.tencent.com/developer/article/1490314。

场景3: A是普通app,B是系统服务程序

方案:A请求B创建一块共享内存,B创建,通过binder返回文件句柄,A根据文件句柄做mmap,得到写入数据的指针。
A写入数据,通过binder通知B读取,B读取,返回读取结果。

A端请求的代码,得到文件句柄shmFd:

    public void createShm() {
        if (mService != null) {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            data.writeInt(ShareMemSize);
            data.writeString(ShareMemName);
            try {
                Log.i(TAG, "start request to create shm");
                mService.transact(CREATE_SHM, data, reply, 0);
                Log.i(TAG, "transact done");
                ParcelFileDescriptor pfd = reply.readFileDescriptor();
                shmFd = pfd.getFd();
                Log.e(TAG, "get shm file descriptor, shmFd: " + shmFd);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

A端根据shmFd做map,得到共享内存的写入地址:

shmWriteAddr = (char *) mmap(0, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, shmFd, 0);
        if (shmWriteAddr == (void *) -1) {
            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "do mmap fail %s", strerror(errno));
            return -1;
        }

B端响应的代码:

status_t BnDemoAPI::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
        //Here, to check the calling permissions
        IPCThreadState* self = IPCThreadState::self();
        ALOGE("Calling MSG: PID=%d, UID=%d",self->getCallingPid(),self->getCallingUid());

        //For Client Read exception code
        //reply->writeInt32(0);
        std::cout << "calling, code " << code << std::endl;


        switch(code)
        {
            case GET_SHM_FD: {
                    //CHECK_INTERFACE(IDemoAPI, data, reply);
                    int shmSize = data.readInt32();
                    String8 s8(data.readString16());
                    ALOGE("get shm name %s ", s8.string());
                    string shmName(s8.string());
                    if(shmName.empty()) {
                       shmName = "alphagame";
                    }
                    mShmInstance.reset(nullptr);
                    mShmInstance.reset(new ShmInstance(shmName, shmSize));
                    int fd = mShmInstance->getShmFd();
                    std::cout << "getShmFd: fd " << fd  << " size " << shmSize << " shmName " << shmName <<std::endl;
                    reply->writeFileDescriptor(fd);
                    return NO_ERROR;
                }
                break;
            case BUFFER_UPDATE:
                {
                    if(mShmInstance != nullptr) {
                        mShmInstance->readShmData();
                    }
                    return NO_ERROR;
                }break;
            default:break;
        }
        return NO_ERROR;
    }

B端创建SHM的关键代码:

int ShmInstance::getShmFd()
{
    int fd = open(DEVASHMEM, O_RDWR);
    if(fd < 0)
    {
        return -1;
    }

    int ret = ioctl(fd, ASHMEM_SET_NAME, SHNAME);
    if(ret < 0){
        close(fd);
        return -1;
    }

    ret = ioctl(fd, ASHMEM_SET_SIZE, shmSize);
    if(ret < 0){
        close(fd);
        return -1;
    }

    shmAddr = (char*)mmap(NULL, shmSize , PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(NULL == shmAddr)
    {
        return -1;
    }
    shmFd = fd;
    std::cout << "create shm success" << std::endl;
    return fd;
}

完整项目地址:
https://github.com/newchenxf/AshMemBaseBinder

[1]: Android Binder传递文件描述符原理分析
[2]: https://github.com/dev-area/ashmem
[3]: https://github.com/qianjigui/android_system_service_example

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

newchenxf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值