系统和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 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 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了,是不是很简单?