如何从Python代码中直接访问Android的Service
在Kivy中,通过pyjnius扩展可以间接调用Java代码,而pyjnius利用的是Java的反射机制。但是在Python对象和Java对象中转来转去总让人感觉到十分别扭。好在Android提供了binder这个进程间通信的功能,Java中的Service也是基于Binder的C++代码封装来实现进程间通信的,这也为从Python代码中绕开pyjnius直接访问Java代码提供了可能,既然Java的Service是基于C++的封装来实现的,也同样可以在Python中封装同样的C++代码,这篇文章讲解了如何通过binder在Python代码中直接访问Java的Service,如WifiService。
binder_wrap.h
#ifndef BINDER_WRAP_H
#define BINDER_WRAP_H
#ifdef __cplusplus
extern "C" {
#endif
typedef int (*vector_visitor)(const char16_t* str16,int length,void *data);
typedef int (*fnOnTransact)(uint32_t code,const void *data,void *reply,uint32_t flags,void *userData);
int server_create(const char *name,const char *descriptor,fnOnTransact onTrans,void *data);
void* binder_getbinder(const char *name);
int binder_releasebinder(void* binder);
int binder_listServices(vector_visitor visitor,void *data);
int binder_getInterfaceDescriptor(void *binder,char16_t *descriptor,size_t size);
int binder_transact(void* binder,int code,const void *data,void* reply,int flags);
void* parcel_new();
int parcel_destroy(void* parcel);
int parcel_writeInterfaceToken(void* parcel,const char *interface);
int parcel_writeInt32(void *parcel,int val);
int parcel_writeCString(void *parcel,const char* str);
int parcel_writeString16(void *parcel,const char16_t* str, size_t len);
int parcel_readInt32(void *parcel);
long parcel_readInt64(void *parcel);
int parcel_readString16(void *parcel,char16_t* str, size_t len);
int parcel_readInplace(void *parcel,void* data, int len);
int parcel_readExceptionCode(void *parcel);
int parcel_dataAvail(void *parcel);
#ifdef __cplusplus
}
#endif
#endif
binder_wrap.cpp
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <binder/Parcel.h>
#include "binder_wrap.h"
using namespace android;
void* binder_getbinder(const char *name)
{
android::sp<android::IServiceManager> sm = android::defaultServiceManager();
sp<IBinder> *binder = new sp<IBinder>();
do {
*binder = sm->getService(android::String16(name));
if (binder != 0)
{
break;
}
usleep(500000); // 0.5 s
} while(true);
return reinterpret_cast<void *>(binder);
}
int binder_releasebinder(void* binder)
{
sp<IBinder> *bp = reinterpret_cast<sp<IBinder> *>(binder);
if(bp == 0)
{
return 0;
}
delete bp;
return 1;
}
//Vector<String16> listServices() = 0;
int binder_listServices(vector_visitor visitor,void *data)
{
android::sp<android::IServiceManager> sm = android::defaultServiceManager();
Vector<String16> list = sm->listServices();
for (int i=0;i<list.size();i++)
{
visitor(list[i].string(),list[i].size(),data);
}
return list.size();
}
int binder_getInterfaceDescriptor(void *binder,char16_t *descriptor,size_t size)
{
sp<IBinder> *bp = reinterpret_cast<sp<IBinder> *>(binder);
if(bp == 0)
{
return 0;
}
if (descriptor == NULL || size <= 0)
{
return 0;
}
String16 des = (*bp)->getInterfaceDescriptor();
if (size > des.size())
{
size = des.size();
}
memcpy(descriptor,des.string(),size*2);
return size;
}
//int binder_transact(void* binder,int code,const Parcel& data,Parcel* reply,int flags = 0)
int binder_transact(void* binder,int code,const void *data,void* reply,int flags)
{
sp<IBinder> *bp = reinterpret_cast<sp<IBinder> *>(binder);
if(bp == 0 || data == 0 || reply == 0)
{
return 0;
}
return (*bp)->transact(code,*(Parcel*)data,(Parcel*)reply,flags);
}
void* parcel_new()
{
return (void*)new Parcel();
}
int parcel_destroy(void* parcel)
{
if(parcel == 0)
{
return 0;
}
delete (Parcel*)parcel;
return 1;
}
int parcel_writeInterfaceToken(void* parcel,const char *interface)
{
Parcel *p = reinterpret_cast<Parcel *>(parcel);
if(p == 0)
{
return 0;
}
return p->writeInterfaceToken(String16(interface));
}
int parcel_writeInt32(void *parcel,int val)
{
Parcel *p = reinterpret_cast<Parcel *>(parcel);
if(p == 0)
{
return 0;
}
return p->writeInt32(val);
}
int parcel_writeCString(void *parcel,const char* str)
{
Parcel *p = reinterpret_cast<Parcel *>(parcel);
if(p == 0)
{
return 0;
}
return p->writeCString(str);
}
int parcel_writeString16(void *parcel,const char16_t* str, size_t len)
{
Parcel *p = reinterpret_cast<Parcel *>(parcel);
if(p == 0)
{
return 0;
}
if (str == 0 || len <= 0)
{
return 0;
}
return p->writeString16(str,len);
}
int parcel_readInt32(void *parcel)
{
Parcel *p = reinterpret_cast<Parcel *>(parcel);
if(p == 0)
{
return 0;
}
return p->readInt32();
}
long parcel_readInt64(void *parcel)
{
Parcel *p = reinterpret_cast<Parcel *>(parcel);
if(p == 0)
{
return 0;
}
return p->readInt64();
}
int parcel_readString16(void *parcel,char16_t* str, size_t len)
{
Parcel *p = reinterpret_cast<Parcel *>(parcel);
if(p == 0)
{
return 0;
}
if (str == NULL || len <= 0)
{
return 0;
}
String16 str16 = p->readString16();
if (len > str16.size())
{
len = str16.size();
}
memcpy(str,str16.string(),len*2);
return len;
}
int parcel_readExceptionCode(void *parcel)
{
Parcel *p = reinterpret_cast<Parcel *>(parcel);
if(p == 0)
{
return 0;
}
return p->readExceptionCode();
}
int parcel_readInplace(void *parcel,void* data, int len)
{
Parcel *p = reinterpret_cast<Parcel *>(parcel);
if(p == 0)
{
return 0;
}
if (len >= 0 && len <= (int32_t)p->dataAvail())
{
const void *d = p->readInplace(len);
memcpy(data,d,len);
return len;
}
return 0;
}
int parcel_dataAvail(void *parcel)
{
Parcel *p = reinterpret_cast<Parcel *>(parcel);
if(p == 0)
{
return 0;
}
return p->dataAvail();
}