通过binder实现系统和app匿名内存共享

系统和app数据交互的方式有很多种,如:jni、socket、binder等
这个方法都各有优缺点
1、jni
优点:直接调用,访问快
缺点:代码量大,至少需要实现本地server、jni及java本地调用三部分的代码
2、socket
优点:基于C/S架构,代码量较少
缺点:需要两次内存拷贝,效率低下
3、binder
优点:基于C/S架构,代码量较少,只进行一次内存拷贝,相对于socket要高效
缺点:传输的数据量大小有限制(内核4M,上层1M-8k)
参考见:https://developer.android.com/reference/android/os/TransactionTooLargeException.html
如果又想使用binder,但传输的数据量又超出了1M,这时就得使用匿名内存共享了
直接上代码
系统本地代码
/getIFrame.h/

namespace android{
    enum {
        SRV_CODE=2002,
        CB_CODE=2003,
        SEND_DATA=2004,
        SHARE_MEM=3001
    };
    #define GETIFRAME_SERVICE_DES "MYServiceOsProtocol"
    #define GETIFRAME_ASHMEM "MYGetIFrameAshmem"
    struct GetIFrame:public BBinder
    {
        private:
        sp<IBinder> mBinder;
        int mSharedFd = 0;
        void* mSharedBuf;
        virtual status_t onTransact(uint32_t code, const Parcel & data, Parcel * reply, uint32_t flags = 0){
            switch(code){
                cose CB_CODE:
                return getIFrame();

                default:
                    return BBinder::onTransact(code, data, reply, flags);
            }
        }

        public:
        GetIFrame();
        ~GetIFrame();
        int allocAshmemBuffer(int size);
        void sendIframeToApp(int share_fd, int32_t size);
        status_t getIFrame();
    };
}

/getIFrame.cpp/

GetIFrame::GetIFrame(){
    sp<IServiceManager> sm = defaultServiceManager();
    mBinder = sm->getService(String16(GETIFRAME_SERVICE_DES));
    if(mBinder != NULL){
        Parcel data, reply;
        data.writeStrongBinder(this);
        mBinder->transace(SRV_CODE, data, &reply, 0);
    }
}
GetIFrame::~GetIFrame(){
    if(mSharedFd > 0){
        ::munmap(mSharedBuf, msize);
        ::close(mSharedFd);
    }
    if(mBinder != NULL){
        mBinder = NULL;
    }
}
void GetIFrame::sendIFrameToApp(int share_fd, int32_t size){
    if(mBinder != NULL){
        Parcel data, reply;
        data.writeInt32(size);
        data.writeFileDescriptor(share_fd);
        mBinder->transact(SHARE_MEM,data, &reply, 0);
    }
}
int GetIFrame::allocAshmemBuffer(int size){
    int result;
    int ashmemfd = ashmem_create_region(GETIFRAME_ASHMEM, size);

    if(ashmemfd > 0){
        result = ashmem_set_prot_reginon(ashmemfd, PROT_READ | PROT_WRITE);
        if(result >= 0){
            mSharedBuf = ::mmap(NULL, size, PROT_READ | PROT_WRITE, ashmemfd, 0);
            if(mSharedBuf == MAP_FAILED){
                ::close(ashmemfd);
                ashmemfd = -1;
            }
        }
    }
    return ashmemfd;
}
status_t GetIFrame::getIFrame(){
    status_t ret = -1;
    if(mHandle != NULL){
        saveIFrame(mHandle);
        mSharedFd = allocAshmemBuffer(msize);
        sendIFrameToApp(mSharedFd, msize);
    }   
}

app端关键代码

@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags){
    …………
    switch(code){
        case SRV_CODE:
            mBinder = data.readStrongBinder();
        break;
        case SHARE_MEM:
            int size = data.readInt();
            byte[] buffer= new byte[size];

            try{
                FileDescriptor fd = data.readFileDescriptor(); 
                if(fd != null){
                    mMemoryFile = new MemoryFile(fd, size, "r");
                }
            }catch(IOException ex){
                Log.e(TAG,"Failed to create memory file!");
                ex.printStrackTrace();
            }catch(RemoteException ex){
                Log.e(TAG,"Failed to get file descriptor from memory service!");
                ex.printStrackTrace();
            }
            mMemoryFile.readBytes(buffer, 0, 0, size);
        break;
    }
}

这样本地系统服务中的大块数据就直接传递给上层的app了,是不是很简单?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值