Android 6.0一个完整的native service
来源:互联网 发布:淘宝网买的学车模拟器 编辑:程序博客网 时间:2024/05/21 07:13
上一篇博客《Android 6.0 如何添加完整的系统服务(app-framework-kernel)》http://www.cnblogs.com/hackfun/p/7418902.html
介绍了如何添加一个系统服务,客户端和服务端都是基于JAVA实现的OpersysService。经过进一步的学习,我将
演示如何使用C++实现一个相同功能的系统服务hfnativeservice。为了兼容OpersysService,将保留Opersys-
Service服务端中的HAL和driver,供hfnativeservice使用,即OpersysService和hfnativeservice这两个Service
都是用相同的HAL和driver。其中,hfnativeservice增加了一个服务端死亡通知机制,即hfnative-service的服
务端进程被杀掉时,客户端会收到这个通知,并做相应的清理工作。
主要围绕以下几个步骤添加一个完整的C++系统服务:
(A) 添加HAL和Driver
(B) 添加服务接口,生成动态库
(C) 添加服务端
(D) 注册服务端
(E) 添加客户端
(F) 测试
(A) 添加HAL和Driver
这部分参考上一篇博客《Android 6.0 如何添加完整的系统服务(app-framework-kernel)》的
(A) 添加circular-char驱动
(B) 添加opersyshw_qemu HAL
(B) 添加服务接口,生成动态库
为了对外只提供服务端或客户端的接口,这里把客户端和服务端之间的通信实现细节放在一起,生成动态库so
文件,服务端和客户端在使用的时候,加载这个so就可以了。IHfNativeService.cpp对客户端和服务端提供了相同
的接口,并实现了proxy和native之间的Binder通信细节。HfNativeManager.cpp根据IHfNativeService.cpp提供的
接口,进一步封装,隐藏了客户端的是操作细节,如服务的获取,注册死亡通知等。
相关头文件:
frameworks/native/include/hfnative/HfNativeManager.h
1 #ifndef ANDROID_HACKFUN_HACKFUN_NATIVE_SERVICE_H 2 #define ANDROID_HACKFUN_HACKFUN_NATIVE_SERVICE_H 3 4 #include <stdint.h> 5 #include <sys/types.h> 6 7 #include <binder/IBinder.h> 8 9 #include <utils/RefBase.h>10 #include <utils/Singleton.h>11 #include <utils/threads.h>12 #include <hfnative/IHfNativeService.h> 13 14 namespace android {15 // ---------------------------------------------------------------------------16 17 class HfNativeManager : public Singleton<HfNativeManager>18 {19 public:20 HfNativeManager();21 ~HfNativeManager();22 23 int init_hfnative(void);24 void deinit_hfnative(void);25 int read_queue(char *buff, int len);26 int write_queue(char *buff, int len);27 int test_hfnative(int value);28 29 status_t assertState();30 bool checkService() const;31 void resetServiceStatus();32 33 private:34 bool isDied;35 // DeathRecipient interface36 void hfNativeServiceDied();37 38 mutable sp<IHfNativeService> mHfNativeServer;39 mutable sp<IBinder::DeathRecipient> mDeathObserver;40 };41 42 }; // namespace android43 44 #endif // ANDROID_HACKFUN_HACKFUN_NATIVE_SERVICE_H
frameworks/native/include/hfnative/IHfNativeService.h
1 #ifndef ANDROID_HACKFUN_HACKFUN_COMPOSER_CLIENT_H 2 #define ANDROID_HACKFUN_HACKFUN_COMPOSER_CLIENT_H 3 4 #include <stdint.h> 5 #include <sys/types.h> 6 7 #include <utils/Errors.h> 8 #include <utils/RefBase.h> 9 10 #include <binder/IInterface.h>11 12 namespace android {13 // ----------------------------------------------------------------------------14 15 class IHfNativeService : public IInterface16 {17 public:18 DECLARE_META_INTERFACE(HfNativeService);19 20 virtual int init_native(void) = 0;21 virtual void finalize_native(void) = 0;22 virtual int read_native(char *Buff, int Len) = 0;23 virtual int write_native(char *Buff, int Len) = 0;24 virtual int test_native(int value) = 0;25 };26 27 // ----------------------------------------------------------------------------28 29 class BnHfNativeService: public BnInterface<IHfNativeService> {30 public:31 virtual status_t onTransact(uint32_t code, const Parcel& data,32 Parcel* reply, uint32_t flags = 0);33 };34 35 // ----------------------------------------------------------------------------36 37 }; // namespace android38 39 #endif // ANDROID_HACKFUN_HACKFUN_COMPOSER_CLIENT_H
源文件:
frameworks/native/libs/hfnative/IHfNativeService.cpp
1 #define LOG_TAG "HfNativeService" 2 3 #include <stdio.h> 4 #include <stdint.h> 5 #include <malloc.h> 6 #include <sys/types.h> 7 8 #include <binder/Parcel.h> 9 #include <binder/IMemory.h> 10 #include <binder/IPCThreadState.h> 11 #include <binder/IServiceManager.h> 12 #include <hfnative/IHfNativeService.h> 13 14 namespace android { 15 16 enum { 17 INIT_NATIVE = IBinder::FIRST_CALL_TRANSACTION, 18 FINALIZE_NATIVE, 19 READ_NATIVE, 20 WRITE_NATIVE, 21 TEST_NATIVE 22 }; 23 24 class BpHfNativeService : public BpInterface<IHfNativeService> 25 { 26 public: 27 BpHfNativeService(const sp<IBinder>& impl) 28 : BpInterface<IHfNativeService>(impl) 29 { 30 } 31 32 int init_native(void) 33 { 34 Parcel data, reply; 35 36 data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor()); 37 remote()->transact(INIT_NATIVE, data, &reply); 38 39 return (int)reply.readInt32(); 40 } 41 42 void finalize_native(void) 43 { 44 Parcel data, reply; 45 46 data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor()); 47 remote()->transact(FINALIZE_NATIVE, data, &reply); 48 } 49 50 int read_native(char *Buff, int Len) 51 { 52 Parcel data, reply; 53 54 data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor()); 55 data.writeInt32(Len); 56 remote()->transact(READ_NATIVE, data, &reply); 57 reply.read((void *)Buff, (size_t)Len); 58 return (int) reply.readInt32(); 59 } 60 61 62 int write_native(char *Buff, int Len) 63 { 64 Parcel data, reply; 65 66 data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor()); 67 data.writeInt32(Len); 68 data.write((const void *)Buff, (size_t)Len); 69 remote()->transact(WRITE_NATIVE, data, &reply); 70 return (int) reply.readInt32(); 71 } 72 73 int test_native(int value) 74 { 75 Parcel data, reply; 76 77 data.writeInterfaceToken(IHfNativeService::getInterfaceDescriptor()); 78 data.writeInt32(value); 79 remote()->transact(TEST_NATIVE, data, &reply); 80 return (int) reply.readInt32(); 81 } 82 }; 83 84 IMPLEMENT_META_INTERFACE(HfNativeService, "android.hfnative.HfNativeService"); 85 86 status_t BnHfNativeService::onTransact( 87 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 88 { 89 char *buff; 90 int len, retval; 91 status_t status; 92 93 switch(code) { 94 case INIT_NATIVE: 95 CHECK_INTERFACE(IHfNativeService, data, reply); 96 retval = init_native(); 97 reply->writeInt32(retval); 98 return NO_ERROR; 99 100 case FINALIZE_NATIVE:101 CHECK_INTERFACE(IHfNativeService, data, reply); 102 finalize_native();103 return NO_ERROR; 104 105 case READ_NATIVE: {106 CHECK_INTERFACE(IHfNativeService, data, reply);107 len = data.readInt32();108 buff = (char *)malloc(len);109 retval = read_native(buff, len);110 reply->write((const void *)buff, (size_t)len);111 free(buff);112 reply->writeInt32(retval);113 return NO_ERROR;114 } break;115 116 case WRITE_NATIVE: {117 CHECK_INTERFACE(IHfNativeService, data, reply);118 len = data.readInt32(); 119 buff = (char *)malloc(len);120 status = data.read((void *)buff, (size_t)len); 121 retval = write_native(buff, len);122 free(buff);123 reply->writeInt32(retval);124 return NO_ERROR;125 } break;126 127 case TEST_NATIVE:128 CHECK_INTERFACE(IHfNativeService, data, reply);129 retval = test_native(data.readInt32());130 reply->writeInt32(retval);131 return NO_ERROR;132 133 default:134 return BBinder::onTransact(code, data, reply, flags);135 }136 }137 138 }; // namespace android
frameworks/native/libs/hfnative/HfNativeManager.cpp
1 #define LOG_TAG "HfNative" 2 3 #include <stdint.h> 4 #include <sys/types.h> 5 6 #include <utils/Errors.h> 7 #include <utils/RefBase.h> 8 #include <utils/Singleton.h> 9 10 #include <binder/IBinder.h> 11 #include <binder/IServiceManager.h> 12 13 #include <hfnative/IHfNativeService.h> 14 #include <hfnative/HfNativeManager.h> 15 16 // ---------------------------------------------------------------------------- 17 namespace android { 18 // ---------------------------------------------------------------------------- 19 20 HfNativeManager::HfNativeManager() : isDied(false) 21 { 22 23 } 24 25 HfNativeManager::~HfNativeManager() 26 { 27 } 28 29 void HfNativeManager::hfNativeServiceDied() 30 { 31 isDied = true; 32 mHfNativeServer.clear(); 33 } 34 35 status_t HfNativeManager::assertState() { 36 if (mHfNativeServer == NULL) { 37 // try for one second 38 const String16 name("hfnativeservice"); 39 for (int i=0 ; i<4 ; i++) { 40 status_t err = getService(name, &mHfNativeServer); 41 if (err == NAME_NOT_FOUND) { 42 usleep(250000); 43 continue; 44 } 45 if (err != NO_ERROR) { 46 return err; 47 } 48 break; 49 } 50 51 init_hfnative(); 52 ALOGI("test hfnativeservice [%d]", test_hfnative(20)); 53 54 55 class DeathObserver : public IBinder::DeathRecipient { 56 HfNativeManager& mHfNativeManager; 57 virtual void binderDied(const wp<IBinder>& who) { 58 ALOGW("hfnativeservice died [%p]", who.unsafe_get()); 59 mHfNativeManager.hfNativeServiceDied(); 60 } 61 public: 62 DeathObserver(HfNativeManager& mgr) : mHfNativeManager(mgr) { } 63 }; 64 65 mDeathObserver = new DeathObserver(*const_cast<HfNativeManager *>(this)); 66 mHfNativeServer->asBinder(mHfNativeServer)->linkToDeath(mDeathObserver); 67 } 68 69 return NO_ERROR; 70 } 71 72 bool HfNativeManager::checkService() const 73 { 74 return isDied? true:false; 75 } 76 77 void HfNativeManager::resetServiceStatus() 78 { 79 isDied = false; 80 } 81 82 83 int HfNativeManager::init_hfnative(void) 84 { 85 return mHfNativeServer->init_native(); 86 } 87 88 void HfNativeManager::deinit_hfnative(void) 89 { 90 mHfNativeServer->finalize_native(); 91 } 92 93 int HfNativeManager::read_queue(char *buff, int len) 94 { 95 return mHfNativeServer->read_native(buff,len); 96 } 97 98 int HfNativeManager::write_queue(char *buff, int len) 99 {100 return mHfNativeServer->write_native(buff,len);101 }102 103 int HfNativeManager::test_hfnative(int value)104 {105 return mHfNativeServer->test_native(value);106 }107 // ----------------------------------------------------------------------------108 }; // namespace android
frameworks/native/libs/hfnative/Android.mk
1 LOCAL_PATH:= $(call my-dir) 2 include $(CLEAR_VARS) 3 4 LOCAL_SRC_FILES:= \ 5 IHfNativeService.cpp \ 6 HfNativeManager.cpp 7 8 LOCAL_SHARED_LIBRARIES := \ 9 libbinder \10 libcutils \11 libutils 12 13 LOCAL_MODULE:= libhfnativemgriface14 15 #ifneq ($(filter generic%,$(TARGET_DEVICE)),)16 # Emulator build17 # LOCAL_CFLAGS += -DUSE_FENCE_SYNC18 #endif19 20 include $(BUILD_SHARED_LIBRARY)21 22 #ifeq (,$(ONE_SHOT_MAKEFILE))23 #include $(call first-makefiles-under,$(LOCAL_PATH))24 #endif
(C) 添加服务端
服务端说白了就是客户端的远程调用,如,客户端调用write_native()的时候,服务端的write_native()
也会被调用。为什么客户端不能直接调用服务端的write_native(),就是因为客户端和服务端分别处于不同的
进程中,进程间的通讯必须通过Binder、socket等机制进行传递。
frameworks/native/services/hfnativeservice/HfNativeService.h
1 #ifndef ANDROID_HACKFUN_NATIVE_SERVICE_H 2 #define ANDROID_HACKFUN_NATIVE_SERVICE_H 3 4 #include <stdint.h> 5 #include <sys/types.h> 6 7 #include <cutils/compiler.h> 8 9 #include <utils/Atomic.h>10 #include <utils/Errors.h>11 #include <utils/KeyedVector.h>12 #include <utils/RefBase.h>13 #include <utils/SortedVector.h>14 #include <utils/threads.h>15 16 #include <binder/BinderService.h>17 18 #include <hfnative/IHfNativeService.h>19 20 namespace android {21 22 // ---------------------------------------------------------------------------23 24 // ---------------------------------------------------------------------------25 class HfNativeService : public BinderService<HfNativeService>,26 public BnHfNativeService27 {28 public:29 static char const* getServiceName() {30 return "hfnativeservice";31 }32 33 HfNativeService();34 35 private:36 virtual int init_native(void);37 virtual void finalize_native(void);38 virtual int read_native(char *Buff, int Len);39 virtual int write_native(char *Buff, int Len);40 virtual int test_native(int value);41 };42 43 // ---------------------------------------------------------------------------44 }; // namespace android45 46 #endif // ANDROID_HACKFUN_NATIVE_SERVICE_H
frameworks/native/services/hfnativeservice/HfNativeService.cpp
1 #include <stdint.h> 2 #include <math.h> 3 #include <sys/types.h> 4 5 #include <utils/Errors.h> 6 #include <utils/RefBase.h> 7 #include <utils/Singleton.h> 8 #include <utils/String16.h> 9 10 #include <binder/BinderService.h> 11 #include <binder/IServiceManager.h> 12 13 #include <hfnative/IHfNativeService.h> 14 15 #include "HfNativeService.h" 16 17 #include <utils/misc.h> 18 #include <hardware/hardware.h> 19 #include <hardware/opersyshw.h> 20 21 #include <stdio.h> 22 23 namespace android { 24 // --------------------------------------------------------------------------- 25 26 27 opersyshw_device_t* opersyshw_dev; 28 29 30 HfNativeService::HfNativeService() 31 { 32 } 33 34 int HfNativeService::init_native(void) 35 { 36 int err; 37 hw_module_t* module; 38 opersyshw_device_t* dev = NULL; 39 40 ALOGI("init_native()"); 41 42 err = hw_get_module(OPERSYSHW_HARDWARE_MODULE_ID, (hw_module_t const**)&module); 43 if (err == 0) { 44 if (module->methods->open(module, "", ((hw_device_t**) &dev)) != 0) { 45 ALOGE("Can't open opersys module!!!"); 46 return 0; 47 } 48 } else { 49 ALOGE("Can't get opersys module!!!"); 50 return 0; 51 } 52 53 opersyshw_dev = dev; 54 55 return 0; 56 } 57 58 void HfNativeService::finalize_native(void) 59 { 60 opersyshw_device_t* dev = opersyshw_dev; 61 62 ALOGI("finalize_native()"); 63 64 if (dev == NULL) { 65 return; 66 } 67 68 dev->close(); 69 70 free(dev); 71 } 72 73 74 int HfNativeService::read_native(char *Buff, int Len) 75 { 76 opersyshw_device_t* dev = opersyshw_dev; 77 char* real_byte_array = Buff; 78 int length; 79 80 ALOGI("read_native()"); 81 82 if (dev == NULL) { 83 return 0; 84 } 85 86 length = dev->read((char*) real_byte_array, Len); 87 88 ALOGI("read data from hal: %s", (char *)real_byte_array); 89 90 return length; 91 } 92 93 int HfNativeService::write_native(char *Buff, int Len) 94 { 95 opersyshw_device_t* dev = opersyshw_dev; 96 char* real_byte_array = Buff; 97 int length; 98 99 ALOGI("write_native()");100 101 if (dev == NULL) {102 return 0;103 }104 105 length = dev->write((char*) real_byte_array, Len);106 107 ALOGI("write data to hal: %s", (char *)real_byte_array);108 109 return length;110 }111 112 int HfNativeService::test_native(int value)113 {114 opersyshw_device_t* dev = opersyshw_dev;115 116 if (dev == NULL) {117 return 0;118 }119 120 ALOGI("test_native()");121 122 return dev->test(value);123 }124 125 // ---------------------------------------------------------------------------126 }; // namespace android
frameworks/native/services/hfnativeservice/Android.mk
1 LOCAL_PATH:= $(call my-dir) 2 include $(CLEAR_VARS) 3 4 LOCAL_SRC_FILES:= \ 5 HfNativeService.cpp \ 6 7 LOCAL_CFLAGS:= -DLOG_TAG=\"HfNativeService\" 8 9 LOCAL_C_INCLUDES += \10 $(call include-path-for, libhardware)/hardware11 12 LOCAL_SHARED_LIBRARIES := \13 libcutils \14 libutils \15 libbinder \16 libhardware \17 libhfnativemgriface18 19 LOCAL_MODULE:= libhfnativeservice20 21 include $(BUILD_SHARED_LIBRARY)
(D) 注册服务端
这里启动添加的的服务,使其运行于一个独立的进程中,等待客户端的请求。
frameworks/native/cmds/hfnative/main_hfnativeservice.cpp
1 #include <binder/BinderService.h> 2 #include <HfNativeService.h> 3 #include <binder/IPCThreadState.h> 4 #include <binder/ProcessState.h> 5 #include <binder/IServiceManager.h> 6 7 #include <hfnative/IHfNativeService.h> 8 9 using namespace android;10 11 int main(int argc, char** argv) {12 #if 113 HfNativeService::publishAndJoinThreadPool(true);14 // Like the SurfaceFlinger, limit the number of binder threads to 4.15 ProcessState::self()->setThreadPoolMaxThreadCount(4);16 #else17 18 sp<ProcessState> proc(ProcessState::self());19 20 sp<IServiceManager> sm = defaultServiceManager();21 22 sm->addService(String16("hfnativeservice"), new HfNativeService());23 24 ProcessState::self()->startThreadPool();25 ProcessState::self()->giveThreadPoolName();26 IPCThreadState::self()->joinThreadPool();27 ProcessState::self()->setThreadPoolMaxThreadCount(4);28 #endif29 return 0;30 }
frameworks/native/cmds/hfnative/Android.mk
1 LOCAL_PATH:= $(call my-dir) 2 include $(CLEAR_VARS) 3 4 LOCAL_SRC_FILES:= \ 5 main_hfnativeservice.cpp 6 7 LOCAL_SHARED_LIBRARIES := \ 8 libhfnativeservice \ 9 libbinder \10 libutils11 12 LOCAL_C_INCLUDES := \13 $(LOCAL_PATH)/../../services/hfnativeservice14 15 LOCAL_MODULE:= hfnativeservice16 17 include $(BUILD_EXECUTABLE)
(E) 添加客户端
用户可以根据客户端提供的接口直接使用,无需关心复杂的客户端和服务端的通信细节。使用HfNativeManager
提供的接口,就能实现远程调用。这里创建了一个独立的线程用于等待接收服务端的死亡通知。
frameworks/base/tests/Hfnative/main_hfnativeclient.cpp
1 #define LOG_TAG "HfNativeClient" 2 3 #include <fcntl.h> 4 #include <sys/prctl.h> 5 #include <sys/wait.h> 6 #include <cutils/properties.h> 7 #include <utils/Log.h> 8 #include <unistd.h> 9 #include <binder/IPCThreadState.h>10 #include <binder/ProcessState.h>11 12 #include <hfnative/HfNativeManager.h>13 14 using namespace android;15 16 17 class HfThread: public Thread {18 public:19 HfNativeManager *hfmgr;20 21 HfThread(void *ptr) {22 this->hfmgr = (HfNativeManager *)ptr;23 }24 25 bool threadLoop();26 };27 28 bool HfThread::threadLoop()29 {30 if (hfmgr->checkService()) {31 ALOGW("hfnativeservice Died, please do some clear!"); 32 hfmgr->resetServiceStatus();33 }34 35 usleep(250000);36 37 return true;38 }39 40 int main(int argc, char **argv) 41 {42 const char *str = {"Hello, Android !\0"};43 char buff[strlen(str)];44 45 HfNativeManager *hfmgr = new HfNativeManager();46 47 if (hfmgr->assertState() == NO_ERROR) {48 hfmgr->write_queue(const_cast<char *>(str), strlen(str));49 usleep(100000);50 hfmgr->read_queue(buff, sizeof(buff));51 ALOGI("Service returned: %s", buff);52 }53 54 sp<HfThread> th = new HfThread((void *)hfmgr);55 th->run();56 57 ProcessState::self()->startThreadPool();58 IPCThreadState::self()->joinThreadPool();59 60 return 0;61 }
frameworks/base/tests/Hfnative/Android.mk
1 LOCAL_PATH:= $(call my-dir) 2 include $(CLEAR_VARS) 3 4 LOCAL_SRC_FILES:= \ 5 main_hfnativeclient.cpp 6 7 LOCAL_SHARED_LIBRARIES := \ 8 libhfnativemgriface \ 9 libbinder \10 libutils \11 libcutils12 13 LOCAL_C_INCLUDES := \14 $(ANDROID_SOURCE)/frameworks/native/include/15 16 LOCAL_MODULE:= hfnativeclient17 18 include $(BUILD_EXECUTABLE)
(F) 测试
编译后生成对应文件:
out/target/product/<device>/.../system/lib/libhfnativemgriface.soout/target/product/<device>/.../system/lib/libhfnativeservice.soout/target/product/<device>/.../system/bin/hfnativeserviceout/target/product/<device>/.../system/bin/hfnativeclient
然后push到机器的相应目录
在机器根目录下,执行以下命令,并观察对应的输出打印(注意要先启动服务端进程):
# cd system/bin# hfnativeservice &# service check hfnativeserviceService hfnativeservice: found# hfnativeclient &# kill -9 pid
对应的输出打印:
......01-01 13:53:55.148 2424 2424 I HfNativeService: init_native()01-01 13:53:55.149 2424 2424 D opersyshw_qemu: OPERSYS HW has been initialized01-01 13:53:55.150 2424 2427 I HfNativeService: test_native()01-01 13:53:55.151 2434 2434 I HfNative: test hfnativeservice [20]01-01 13:53:55.151 2424 2424 I HfNativeService: write_native()01-01 13:53:55.151 2424 2424 D opersyshw_qemu: OPERSYS HW - write()for 16 bytes called01-01 13:53:55.151 2424 2424 D opersyshw_qemu: write data to driver: Hello, Android !01-01 13:53:55.151 2424 2424 I HfNativeService: write data to hal: Hello, Android !01-01 13:53:55.252 2424 2427 I HfNativeService: read_native()01-01 13:53:55.252 2424 2427 D opersyshw_qemu: OPERSYS HW - read()for 16 bytes called01-01 13:53:55.252 2424 2427 D opersyshw_qemu: read data from driver: Hello, Android !01-01 13:53:55.252 2424 2427 I HfNativeService: read data from hal: Hello, Android !01-01 13:53:55.252 2434 2434 I HfNativeClient: Service returned: Hello, Android !......01-01 13:54:08.210 2434 2434 W HfNative: hfnativeservice died [0xb6cc90c0]01-01 13:54:08.210 211 211 I ServiceManager: service 'hfnativeservice' died01-01 13:54:08.269 2434 2437 W HfNativeClient: hfnativeservice Died, please do some clear!......
- Android 6.0一个完整的native service
- 一个Native Service的完整示例
- 一个Native Service的完整示例
- 【Android Native Code开发系列】六 一个Native Service的完整示例
- 【Android Native Code开发系列】六 一个Native Service的完整示例
- 【Android Native Code开发系列】一个Native Service的完整示例 1234567
- 【Android Native Code开发系列】六 一个Native Service的完整示例
- 一个完整的android Service
- Native Service的完整示例
- Android添加一个Native Service
- Android添加一个Native Service
- Android Service Framework (Native层的一个例子)
- 自己动手从零开始写一个完整的android Service
- 自己动手从零开始写一个完整的android Service
- 如何创建一个Android Native Binder Service
- 如何写一个native层的service
- 怎么写一个native层的service
- Android架构设计和软硬整合完整训练:HAL&Framework&Native Service&Android Service&Best Practice
- 王者荣耀T恤图案图形设计大赛—英雄台词字体设计
- 机器学习入门笔记(五)----过拟合问题
- 一起艳学SpringBoot
- CentOS 7下安装Python3.5
- linux env
- Android 6.0一个完整的native service
- mysql 密码修改过后忘记了重置的方法
- yii2 gii模块自动生成代码,让双手更自由
- input[file]标签的accept=”image/*”属性响应很慢的解决办法
- nodeJs -- 基于Express、superagent 和 cheerio
- Trailing Zeroes (III)
- golang 实现华容道
- oracle检查数据库是否有坏块的命令
- linux下crontab