用android 模板,实现native service
来源:互联网 发布:linux uname -a 编辑:程序博客网 时间:2024/06/13 18:40
通过IInterface里定义的这些不太好理解的模板方法,使得编写一个Native Service的工作量也并不大.
http://blog.csdn.net/21cnbao/article/details/8087328
Proxy端:![微笑](http://static.blog.csdn.net/xheditor/xheditor_emot/default/smile.gif)
\frameworks\av\media\libmedia\IMediaPlayerService.cpp:
class BpMediaPlayerService: public BpInterface<IMediaPlayerService>{public: BpMediaPlayerService(const sp<IBinder>& impl) : BpInterface<IMediaPlayerService>(impl) { }
在frameworks\native\include\binder\IInterface.h中定义
template<typename INTERFACE>class BpInterface : public INTERFACE, public BpRefBase{public: BpInterface(const sp<IBinder>& remote);protected: virtual IBinder* onAsBinder();};class IInterface : public virtual RefBase{public: IInterface(); static sp<IBinder> asBinder(const IInterface*); static sp<IBinder> asBinder(const sp<IInterface>&);protected: virtual ~IInterface(); virtual IBinder* onAsBinder() = 0;};
在:frameworks\av\include\media\IMediaPlayerService.h中定义:
class IMediaPlayerService: public IInterface{public: DECLARE_META_INTERFACE(MediaPlayerService);
在:\frameworks\native\include\binder\Binder.h:
class BpRefBase : public virtual RefBase{protected: BpRefBase(const sp<IBinder>& o); virtual ~BpRefBase(); virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id); inline IBinder* remote() { return mRemote; } inline IBinder* remote() const { return mRemote; }private: BpRefBase(const BpRefBase& o); BpRefBase& operator=(const BpRefBase& o); IBinder* const mRemote; RefBase::weakref_type* mRefs; std::atomic<int32_t> mState;};
在:\frameworks\native\include\binder\IBinder.h:
class IBinder : public virtual RefBase{public:
在:frameworks\native\include\binder\BpBinder.h
class BpBinder : public IBinder{public: BpBinder(int32_t handle); inline int32_t handle() const { return mHandle; } virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
在:frameworks\native\libs\binder\BpBinder.cpp
status_t BpBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ // Once a binder has died, it will never come back to life. if (mAlive) { status_t status = IPCThreadState::self()->transact( mHandle, code, data, reply, flags); if (status == DEAD_OBJECT) mAlive = 0; return status; } return DEAD_OBJECT;}
在:frameworks\native\include\binder\IPCThreadState.h
class IPCThreadState{public: sp<ProcessState> process(); status_t transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
Stub端:
在:\frameworks\av\media\libmediaplayerservice\MediaPlayerService.h:
class MediaPlayerService : public BnMediaPlayerService{ class Client;
在:frameworks\av\include\media\IMediaPlayerService.h中定义:
class BnMediaPlayerService: public BnInterface<IMediaPlayerService>{public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);};
在frameworks\native\include\binder\IInterface.h中定义
template<typename INTERFACE>class BnInterface : public INTERFACE, public BBinder{public: virtual sp<IInterface> queryLocalInterface(const String16& _descriptor); virtual const String16& getInterfaceDescriptor() const;protected: virtual IBinder* onAsBinder();};
在:\frameworks\native\include\binder\Binder.h:
class BBinder : public IBinder{public: BBinder(); virtual const String16& getInterfaceDescriptor() const; virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
以MediaPlayerService为例子:
在Native Service的类的继承关系上,所有加了颜色标识的部分,IMediaPlayerService接口类、BpInteface<IMediaPlayerService>和BnInterface<IMediaPlayerService>模板类、以及进一步派出来的BpMediaPlayerService和BnMediaPlayerService,都是需要手动实现的。
这样实现最终得到的结果,就是我们可以通过一个继承自BnMediaPlayerService的可实例化的类MediaPlayerService构造一个对象,这一对象便可以在其生存期内响应与处理Binder命令的请求。
而通过中间引入的一层BpMediaPlayerService,也可以自动地将客户端代码通过BpRefBase的引用自动生成。
作为所有实现的源头,于是我们需要定义IMediaPlayerService接口类:
enum { CREATE = IBinder::FIRST_CALL_TRANSACTION, CREATE_MEDIA_RECORDER, CREATE_METADATA_RETRIEVER, GET_OMX, MAKE_HDCP, ADD_BATTERY_DATA, PULL_BATTERY_DATA, LISTEN_FOR_REMOTE_DISPLAY, GET_CODEC_LIST,};class IMediaPlayerService: public IInterface{public: DECLARE_META_INTERFACE(MediaPlayerService); virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName) = 0; virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0; virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId = AUDIO_SESSION_ALLOCATE) = 0; virtual sp<IOMX> getOMX() = 0; virtual sp<IHDCP> makeHDCP(bool createEncryptionModule) = 0; virtual sp<IMediaCodecList> getCodecList() const = 0; // Connects to a remote display. // 'iface' specifies the address of the local interface on which to listen for // a connection from the remote display as an ip address and port number // of the form "x.x.x.x:y". The media server should call back into the provided remote // display client when display connection, disconnection or errors occur. // The assumption is that at most one remote display will be connected to the // provided interface at a time. virtual sp<IRemoteDisplay> listenForRemoteDisplay(const String16 &opPackageName, const sp<IRemoteDisplayClient>& client, const String8& iface) = 0; virtual void addBatteryData(uint32_t params) = 0; virtual status_t pullBatteryData(Parcel* reply) = 0;};
作为兼用于Proxy与Stub的接口类定义的IInterface,实际上至少还需要定义Binder命令、asBinder()等基本方法。这时,我们就可以看到在IInterface定义里使用宏的好处了,我们这里只需要定义属于特性的部分,比如这一Native Service所需要的Binder命令,和支持这一Binder命令的远程接口方法,仅此而已。而其他部分的代码,并不需要我们直接实现,我们只需要使用DECLARE_META_INTERFACE和IMPLEMENT_META_INTERFACE这两个宏来自动化生成这些共性的部分。于是,实现一个远程接口类,会是通过继承IInterface接口类,然后得到具体的接口类,比如我们这里的IMediaPlayerService。剩下的部分,会是如下四路的基本套路:
- 1) 定义Binder命令,而且命令都以IBinder::FIRST_CALL_TRANSACTION,也就是1开始;
- 2) 定义接口方法,也就是一个纯虚方法,比如
createMediaRecorder();
- 3) 通过DECLARE_META_INTERFACE,从而自动生成这一接口类所需要的通用属性与方法;
#define DECLARE_META_INTERFACE(MediaPlayerService) \ static const android::String16 descriptor; \ static android::sp<IMediaPlayerService> asInterface( \ const android::sp<android::IBinder>& obj); \ virtual const android::String16& getInterfaceDescriptor() const; \ IMediaPlayerService(); \ virtual ~IMediaPlayerService(); \
- 4) 使用IMPLEMENT_META_INTERFACE,自动提供第3)里所缺少方法的实现。
#define IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService") \ const android::String16 IMediaPlayerService::descriptor("android.media.IMediaPlayerService"); \ const android::String16& \ IMediaPlayerService::getInterfaceDescriptor() const { \ return IMediaPlayerService::descriptor; \ } \ android::sp<IMediaPlayerService> IMediaPlayerService::asInterface( \ const android::sp<android::IBinder>& obj) \ { \ android::sp<IMediaPlayerService> intr; \ if (obj != NULL) { \ intr = static_cast<IMediaPlayerService*>( \ obj->queryLocalInterface( \ IMediaPlayerService::descriptor).get()); \ if (intr == NULL) { \ intr = new BpMediaPlayerService(obj); \ } \ } \ return intr; \ } \ IMediaPlayerService::IMediaPlayerService() { } \ IMediaPlayerService::~IMediaPlayerService() { } \
Proxy端:
有了具有共性的接口类定义之后,剩下的就是分别实现Proxy与Stub端了。我们可以先来看Proxy端的实现,从IInterface里的定义里可以看到,同样出于代码重用的目的,Proxy端的代码都将源自BpInterface模板类,只需要实现接口方法即可。我们通过BpInterface模板套用到接口IMediaPlayerService之上,就得到了我们需要的BpMediaPlayerService类,然后在BpMediaPlayerService类里实现具体的接口方法,把接口方法转换成Binder命令的发送操作,Proxy端的实现便完成了。
class BpMediaPlayerService: public BpInterface<IMediaPlayerService>{public: BpMediaPlayerService(const sp<IBinder>& impl) : BpInterface<IMediaPlayerService>(impl) { } virtual sp<IMediaMetadataRetriever> createMetadataRetriever() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); remote()->transact(CREATE_METADATA_RETRIEVER, data, &reply); return interface_cast<IMediaMetadataRetriever>(reply.readStrongBinder()); } virtual sp<IMediaPlayer> create( const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(client)); data.writeInt32(audioSessionId); remote()->transact(CREATE, data, &reply); return interface_cast<IMediaPlayer>(reply.readStrongBinder()); } virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); data.writeString16(opPackageName); remote()->transact(CREATE_MEDIA_RECORDER, data, &reply); return interface_cast<IMediaRecorder>(reply.readStrongBinder()); } virtual sp<IOMX> getOMX() { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); remote()->transact(GET_OMX, data, &reply); return interface_cast<IOMX>(reply.readStrongBinder()); } virtual sp<IHDCP> makeHDCP(bool createEncryptionModule) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); data.writeInt32(createEncryptionModule); remote()->transact(MAKE_HDCP, data, &reply); return interface_cast<IHDCP>(reply.readStrongBinder()); } virtual void addBatteryData(uint32_t params) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); data.writeInt32(params); remote()->transact(ADD_BATTERY_DATA, data, &reply); } virtual status_t pullBatteryData(Parcel* reply) { Parcel data; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); return remote()->transact(PULL_BATTERY_DATA, data, reply); } virtual sp<IRemoteDisplay> listenForRemoteDisplay(const String16 &opPackageName, const sp<IRemoteDisplayClient>& client, const String8& iface) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); data.writeString16(opPackageName); data.writeStrongBinder(IInterface::asBinder(client)); data.writeString8(iface); remote()->transact(LISTEN_FOR_REMOTE_DISPLAY, data, &reply); return interface_cast<IRemoteDisplay>(reply.readStrongBinder()); } virtual sp<IMediaCodecList> getCodecList() const { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); remote()->transact(GET_CODEC_LIST, data, &reply); return interface_cast<IMediaCodecList>(reply.readStrongBinder()); }};在BpMediaPlayerService类实现里,我们也可以拓展其构造或是析构方法来处理一些私有属性。但最重要的是,一定要在BpMediaPlayerService类里通过虚拟继承实现所有的接口方法,比如我们在IMediaPlayerService接口里定义的createMetadataRetriever(),并且在这一方法里将该方法转换成Binder命令的发送与返回值的处理。除此之外,其他具有共性的部分,都会由系统来完成,比如BpInterface会继承自BpRefBase,通过remote()方法返回的也是BpRefBase,但BpRefBase最终会引用到BpBinder对象,最终通过这一BpBinder命令将Binder命令发送出去。
Stub端:
对于Stub端的实现,无论是Java环境里还是C++实现的Native环境,所有的消息分发处理的接口都是onTransact()回调方法。于是,整个Stub端实现就会是基于BnInterface模板,然后再覆盖其onTransact()方法。对于我们例子里的BnMediaPlayerService,由会有如下的实现:
class BnMediaPlayerService: public BnInterface<IMediaPlayerService>{public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);};//覆盖OnTransact()方法status_t BnMediaPlayerService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ switch (code) { case CREATE: { CHECK_INTERFACE(IMediaPlayerService, data, reply); sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder()); audio_session_t audioSessionId = (audio_session_t) data.readInt32(); sp<IMediaPlayer> player = create(client, audioSessionId); reply->writeStrongBinder(IInterface::asBinder(player)); return NO_ERROR; } break; case CREATE_MEDIA_RECORDER: { CHECK_INTERFACE(IMediaPlayerService, data, reply); const String16 opPackageName = data.readString16(); sp<IMediaRecorder> recorder = createMediaRecorder(opPackageName); reply->writeStrongBinder(IInterface::asBinder(recorder)); return NO_ERROR; } break; case CREATE_METADATA_RETRIEVER: { CHECK_INTERFACE(IMediaPlayerService, data, reply); sp<IMediaMetadataRetriever> retriever = createMetadataRetriever(); reply->writeStrongBinder(IInterface::asBinder(retriever)); return NO_ERROR; } break; case GET_OMX: { CHECK_INTERFACE(IMediaPlayerService, data, reply); sp<IOMX> omx = getOMX(); reply->writeStrongBinder(IInterface::asBinder(omx)); return NO_ERROR; } break; case MAKE_HDCP: { CHECK_INTERFACE(IMediaPlayerService, data, reply); bool createEncryptionModule = data.readInt32(); sp<IHDCP> hdcp = makeHDCP(createEncryptionModule); reply->writeStrongBinder(IInterface::asBinder(hdcp)); return NO_ERROR; } break; case ADD_BATTERY_DATA: { CHECK_INTERFACE(IMediaPlayerService, data, reply); uint32_t params = data.readInt32(); addBatteryData(params); return NO_ERROR; } break; case PULL_BATTERY_DATA: { CHECK_INTERFACE(IMediaPlayerService, data, reply); pullBatteryData(reply); return NO_ERROR; } break; case LISTEN_FOR_REMOTE_DISPLAY: { CHECK_INTERFACE(IMediaPlayerService, data, reply); const String16 opPackageName = data.readString16(); sp<IRemoteDisplayClient> client( interface_cast<IRemoteDisplayClient>(data.readStrongBinder())); if (client == NULL) { reply->writeStrongBinder(NULL); return NO_ERROR; } String8 iface(data.readString8()); sp<IRemoteDisplay> display(listenForRemoteDisplay(opPackageName, client, iface)); reply->writeStrongBinder(IInterface::asBinder(display)); return NO_ERROR; } break; case GET_CODEC_LIST: { CHECK_INTERFACE(IMediaPlayerService, data, reply); sp<IMediaCodecList> mcl = getCodecList(); reply->writeStrongBinder(IInterface::asBinder(mcl)); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); }}
BnMediaPlayerService这个Stub实现,BnInterface模板套用到IMediaPlayerService接口类上得到的类,然后再实现自己的onTransact()。在我们这个例子里将BnMediaPlayerService定义与onTranscat()实现分开来,但把两者写到一起是一回事。
在前面的Binder底层分析里我们知道, IPCThreadState对象会捕获底层的Binder命令,然后回调到onTransact()方法处理这一命令,于是在onTranscat()里只需要根据传入的code进行命令的分发与处理即可。比如我们例子里,当检查到命令的code是CREATE_MEDIA_RECORDER,也就是我们在IMediaPlayerService接口类里定义的Binder命令,会根据这一命令调用到createMediaRecorder()方法,然后再将结果通过reply这一Parcel传回给调用端,这样就完成了远程调用的实现。最后,缕缕进行一次IoC反向调用到父类的onTransact(),从而可以处理一些通用的Binder命令。
但到此,我们的Native Service实现并不完整,我们在Stub端并没有提供createMediaRecorder()方法的实现,这样BnMediaPlayerService这个类是无法被实例化成具体的对象,从而响应远程请求。
于是,我们通过继承BnMediaPlayerService,然后再实现接口方法createMediaRecorder(),这一新的对象便可被实例化成为一个具体的对象。这样做的目的进一步将Binder处理相关代码与具体的实现拆分开,我们可以得到在命名和实现上更加清晰的MediaPlayerService:
class MediaPlayerService : public BnMediaPlayerService{ class Client; //...public: static void instantiate(); // IMediaPlayerService interface virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName); void removeMediaRecorderClient(wp<MediaRecorderClient> client); virtual sp<IMediaMetadataRetriever> createMetadataRetriever(); virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId); virtual sp<IMediaCodecList> getCodecList() const; virtual sp<IOMX> getOMX(); virtual sp<IHDCP> makeHDCP(bool createEncryptionModule); virtual sp<IRemoteDisplay> listenForRemoteDisplay(const String16 &opPackageName, const sp<IRemoteDisplayClient>& client, const String8& iface); virtual status_t dump(int fd, const Vector<String16>& args); void removeClient(wp<Client> client); bool hasClient(wp<Client> client);
MediaPlayerService继承自BnMediaPlayerService,又提供了所需要的接口方法,于是任何被系统调度到的可执行部分,无论是线程还是进程,都可以通过实例化一个MediaPlayerService对象响应远程的createMediaRecorder()的调用请求。在代码的实现角度,一般IMediaPlayerService会在一个独立的源文件存放,以标明这是一个接口类,而MediaPlayerService会列入到另一个MediaPlayerService.cpp以说明这一个Service的具体实现。虽然不是强制要求,但这样的实现会更符合android里的编码习惯,更容易维护。
但需要注意的是,IMediaPlayerService接口类会通过IMPLEMENT_META_INTERFACE()这个宏来设置descriptor,于是在整个系统环境里, 由某个descriptor来标识的Service必然会是唯一的。比如某个进程已经通过自己的ProcessState加入到了Binder域,则加入这一新加入的Binder处理只需要如下的简单两行,一行创建MediaPlayerService对象并加入到ServiceManager的管理,另一行启动MediaPlayerService的Binder线程:
void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService());}
frameworks\av\media\mediaserver\main_mediaserver.cpp:
int main(int argc __unused, char **argv __unused){ signal(SIGPIPE, SIG_IGN); sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm(defaultServiceManager()); ALOGI("ServiceManager: %p", sm.get()); InitializeIcuOrDie(); MediaPlayerService::instantiate(); ResourceManagerService::instantiate(); registerExtensions(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool();}
![](http://image.slidesharecdn.com/androidbinderipc-140625051612-phpapp02/95/overview-of-android-binder-ipc-implementation-21-638.jpg?cb=1403673439)
为了减小Native Service在编程上的工作量,在Binder里还会有另一个BinderService相关的实现,也会使用模板的方式进一步节省代码的工作量,见frameworks/base/include/binder/BinderService.h:
template<typename SERVICE>class BinderService{public: static status_t publish(bool allowIsolated = false) { sp<IServiceManager> sm(defaultServiceManager()); return sm->addService( String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated); } static void publishAndJoinThreadPool(bool allowIsolated = false) { publish(allowIsolated); joinThreadPool(); } static void instantiate() { publish(); } static status_t shutdown() { return NO_ERROR; }private: static void joinThreadPool() { sp<ProcessState> ps(ProcessState::self()); ps->startThreadPool(); ps->giveThreadPoolName(); IPCThreadState::self()->joinThreadPool(); }};
使用这一BinderService模板,便我们的代码进一步被简化,比如我们在Android系统内见到不会接触到IPCThreadState和ProcessState对象,在定义NativeService时,一般会使用这样的方式,比如AudioFlinger:
class AudioFlinger : public BinderService<AudioFlinger>, public BnAudioFlinger{ friend class BinderService<AudioFlinger>; // for AudioFlinger()}于是在某个进程里,我们就只需要最简单一行:
在:frameworks\av\media\audioserver\main_audioserver.cpp
int main(int argc __unused, char **argv){ signal(SIGPIPE, SIG_IGN); sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); ALOGI("ServiceManager: %p", sm.get()); AudioFlinger::instantiate(); AudioPolicyService::instantiate(); RadioService::instantiate(); SoundTriggerHwService::instantiate(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); }
NativeService是由libbinder提供的一种机制,相当于是Java环境Remote Service的底层”Hack”实现。而通过Native Service,我们得到Java环境所不具备的一些新的特质:
- 1) 性能更高。性能上的差异性取决于执行时的不同上下文环境,但通常来说,Native代码总会有比Java这种解释型语言高得多的执行效率。
- 2) 使用同一种语言编程,更加容易理解与调试。Java语言不能直接进行系统调用,必须透过JNI来调用C代码来访问系统功能。而NativeService则完全不同,C++具备直接进行系统调用的能力,于是在访问操作系统或是硬件功能时,不再需要JNI,可以直接进行调用,代码实现上会更加统一。
- 3) 自动化GC,Native态的Binder,与Java协作时被自动切入到Dalvik虚拟机的GC管理,也能使用类似于Java环境的自动化垃圾回收。同时,这种GC机制可以通过RefBase进行进一步拓展。
- 4) 缺点:不能使用AIDL,编码工作量更大。
- 5) 缺点:跟Java的Binder域编程环境功能重叠,也有可能会出错。比如Binder命令的定义,在Java与Native Service交互时,在Java环境与C++环境都要有各自一份拷贝。
综合所有的这些因素,虽然Native Service有一定的局限性,但带来的好处要更多。于是在Android的版本变更过程中,NativeService使用越来越普遍。
总结下:
- 用android 模板,实现native service
- android native Service(C++实现service)
- Android Native Service简单实现示例
- Native Service的实现
- 制作android native service
- 制作android native service
- android native service
- android native模板
- Android Native/Android service 详解
- 通过Binder实现 Native Service
- Android创建Native Binder Service
- Android添加一个Native Service
- Android添加一个Native Service
- 添加Android Native Service方法
- Android service 代码模板
- Native实现的service怎样加入ServiceManager
- Android native Socket实现
- 如何查看Android 中native的Service
- this指针与虚表
- 封装Okhttp(Gson一起封装在里面减少了解析的操作)
- ROS nodelet-----编写一个nodelet插件
- Sql语句复制表结构
- 2015
- 用android 模板,实现native service
- codevs 1055 气球(字符串处理)
- 一分钟教你知道乐观锁和悲观锁的区别
- Uva1595 Symmetry 【set集合】【习题5-6】
- 3. 深入理解递归
- 体验一把新的编辑器,注册这么久的第一篇
- JAVA中四种常见创建对象方法
- 使用NDK实现的Base64编/解码
- android log输出行位置和方法名 以及导出jar包