應用程序與驅動程序客服端方式交互
阿新 • • 發佈:2018-08-27
dex etime link next self 時間 ise elf defaults
實現方式是:
3 環通過IOServiceOpen打開連接驅動
0 環在 start 中設置一個與之交互的Client(方式有設置鍵值對或 new一個Client)
3 環:
// UserClientShared.h
實現方式是:
3 環通過IOServiceOpen打開連接驅動
0 環在 start 中設置一個與之交互的Client(方式有設置鍵值對或 new一個Client)
3 環:
// UserClientShared.h
// // UserClientShared.h // UserSpaceClient // #include <stdint.h> typedef struct TimerValue { uint64_t time; uint64_t timebase; } TimerValue; // 用於用戶客戶端方法的控制請求碼 enum TimerRequestCode { kTestUserClientStartTimer, kTestUserClientStopTimer, kTestUserClientGetElapsedTimerTime, kTestUserClientGetElapsedTimerValue, kTestUserClientDelayForMs, kTestUserClientDelayForTime, kTestUserClientInstallTimer, kTestUserClientMethodCount };
//main.cpp
// // main.c // UserSpaceClient // #include <CoreFoundation/CoreFoundation.h> #include <IOKit/IOKitLib.h> #include "UserClientShared.h" kern_return_t StartTimer (io_connect_t connection); kern_return_t StopTimer (io_connect_t connection); kern_return_t GetElapsedTimerTime (io_connect_t connection, uint32_t* timerTime); kern_return_t GetElapsedTimerValue (io_connect_t connection, TimerValue* timerValue); kern_return_t DelayForMs (io_connect_t connection, uint32_t milliseconds); kern_return_t DelayForTime (io_connect_t connection, const TimerValue* timerValue); //以下這些控制請求 都會調試驅動中IOUserClient的externalMethod方法(也就是必須實現) kern_return_t StartTimer (io_connect_t connection) { //IOConnectCallMethod用於控制請求 return IOConnectCallMethod( //連接(端口) connection, //控制碼(函數) kTestUserClientStartTimer, //參數 NULL, 0, NULL, 0, NULL, NULL, NULL, NULL); } kern_return_t StopTimer (io_connect_t connection) { return IOConnectCallMethod(connection, kTestUserClientStopTimer, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL); } kern_return_t GetElapsedTimerTime (io_connect_t connection, uint32_t* timerTime) { uint64_t scalarOut[1]; uint32_t scalarOutCount; kern_return_t result; scalarOutCount = 1; // 初始化為scalarOut數組的長度 result = IOConnectCallScalarMethod(connection, kTestUserClientGetElapsedTimerTime, NULL, 0, scalarOut, &scalarOutCount); if (result == kIOReturnSuccess) *timerTime = (uint32_t)scalarOut[0]; return result; } kern_return_t GetElapsedTimerValue (io_connect_t connection, TimerValue* timerValue) { size_t structOutSize; structOutSize = sizeof(TimerValue); return IOConnectCallStructMethod(connection, kTestUserClientGetElapsedTimerValue, NULL, 0, timerValue, &structOutSize); } kern_return_t DelayForMs (io_connect_t connection, uint32_t milliseconds) { uint64_t scalarIn[1]; scalarIn[0] = milliseconds; return IOConnectCallScalarMethod(connection, kTestUserClientDelayForMs, scalarIn, 1, NULL, NULL); } kern_return_t DelayForTime (io_connect_t connection, const TimerValue* timerValue) { return IOConnectCallStructMethod(connection, kTestUserClientDelayForTime, timerValue, sizeof(TimerValue), NULL, 0); } IONotificationPortRef gAsyncNotificationPort = NULL; IONotificationPortRef MyDriverGetAsyncCompletionPort () { // If the port has been allocated, return the existing instance if (gAsyncNotificationPort != NULL) return gAsyncNotificationPort; gAsyncNotificationPort = IONotificationPortCreate(kIOMasterPortDefault); return gAsyncNotificationPort; } kern_return_t InstallTimer (io_connect_t connection, uint32_t milliseconds, IOAsyncCallback0 timerCallback, void* context) { io_async_ref64_t asyncRef; uint64_t scalarIn[1]; //設置回調函數 asyncRef[kIOAsyncCalloutFuncIndex] = (uint64_t)timerCallback; asyncRef[kIOAsyncCalloutRefconIndex] = (uint64_t)context; //設置輸入參數 scalarIn[0] = milliseconds; return IOConnectCallAsyncScalarMethod(connection, kTestUserClientInstallTimer, IONotificationPortGetMachPort(gAsyncNotificationPort), asyncRef, kIOAsyncCalloutCount, scalarIn, 1, NULL, NULL); } void DelayCallback (void *refcon, IOReturn result) { printf("DelayCallback - refcon %08x and result %08x\n", (uint32_t)refcon, result); if (refcon == (void*)0xdeadbeef) CFRunLoopStop(CFRunLoopGetMain()); } int main (int argc, const char * argv[]) { CFDictionaryRef matchingDict = NULL; io_iterator_t iter = 0; io_service_t service = 0; kern_return_t kr; ////創建一個匹配字典,用於查找任意的 USB 設備 matchingDict = IOServiceMatching("com_osxkernel_driver_IOKitTest"); //為匹配字典的所有IO註冊表對象創建叠代器 kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter); if (kr != KERN_SUCCESS) return -1; ////叠代所有匹配的對象 while ((service = IOIteratorNext(iter)) != 0) { task_port_t owningTask = mach_task_self(); uint32_t type = 0; //就是一個端口 io_connect_t driverConnection; //建立驅動連接 //會觸發驅動程序 IOService類中的newUserClient方法實例化一個新的Client對象 驅動中可以不要實現 //只要設置一個值就好 // bool com_osxkernel_driver_IOKitTest::start (IOService *provider) // { // bool res = super::start(provider); // setProperty("IOUserClientClass", "com_osxkernel_driver_IOKitTestUserClient"); // registerService(); // return res; // } // virtual IOReturn newUserClient( //用戶傳遞的參數 //task_t owningTask, void * securityID, // UInt32 type, OSDictionary * properties, //handler返回給調用者 // IOUserClient ** handler ); // // virtual IOReturn newUserClient( task_t owningTask, void * securityID, // UInt32 type, IOUserClient ** handler ); kr = IOServiceOpen( //表示希望連接到的驅動程序 service, //表示運行的應用程序 owningTask, //無符號 32位××× type, //成功後的返回值 &driverConnection); if (kr == KERN_SUCCESS) { uint32_t timerTime; TimerValue timerValue; IONotificationPortRef notificationPort; //獲取一個通知端口 notificationPort = MyDriverGetAsyncCompletionPort(); if (notificationPort) { CFRunLoopSourceRef runLoopSource; runLoopSource = IONotificationPortGetRunLoopSource(notificationPort); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); } kr = StopTimer(driverConnection); printf("StopTimer - %08x\n", kr); kr = StartTimer(driverConnection); printf("StartTimer - %08x\n", kr); kr = GetElapsedTimerTime(driverConnection, &timerTime); printf("GetElapsedTimerTime - %08x, time %d\n", kr, timerTime); kr = DelayForMs(driverConnection, 100); printf("DelayForMs - %08x\n", kr); kr = GetElapsedTimerTime(driverConnection, &timerTime); printf("GetElapsedTimerTime - %08x, time %d\n", kr, timerTime); kr = GetElapsedTimerValue(driverConnection, &timerValue); printf("GetElapsedTimerValue - %08x, time %lld / %lld\n", kr, timerValue.time, timerValue.timebase); timerValue.timebase = 0; timerValue.time = 500; kr = DelayForTime(driverConnection, &timerValue); printf("DelayForTime - %08x\n", kr); timerValue.timebase = 1000; kr = DelayForTime(driverConnection, &timerValue); printf("DelayForTime - %08x\n", kr); kr = GetElapsedTimerTime(driverConnection, &timerTime); printf("GetElapsedTimerTime - %08x, time %d\n", kr, timerTime); kr = StopTimer(driverConnection); printf("StopTimer - %08x\n", kr); kr = InstallTimer(driverConnection, 10000, DelayCallback, (void*)0xdeadbeef); printf("InstallTimer - %08x\n", kr); kr = InstallTimer(driverConnection, 5000, DelayCallback, (void*)0xdead0005); printf("InstallTimer - %08x\n", kr); kr = InstallTimer(driverConnection, 2000, DelayCallback, (void*)0xdead0002); printf("InstallTimer - %08x\n", kr); kr = InstallTimer(driverConnection, 7000, DelayCallback, (void*)0xdead0007); printf("InstallTimer - %08x\n", kr); CFRunLoopRun(); IONotificationPortDestroy(gAsyncNotificationPort); gAsyncNotificationPort = NULL; //關閉驅動連接 IOServiceClose(driverConnection); } IOObjectRelease(service); } IOObjectRelease(iter); return 0; }
0 環:
//IOKitTestUserClient.h
// // IOKitTestUserClient.h // IOKitTest // #include <IOKit/IOUserClient.h> #include "IOKitTest.h" #include "UserClientShared.h" class com_osxkernel_driver_IOKitTestUserClient : public IOUserClient { OSDeclareDefaultStructors(com_osxkernel_driver_IOKitTestUserClient) private: task_t m_task; com_osxkernel_driver_IOKitTest* m_driver; bool m_timerRunning; uint64_t m_timerStartTime; static const IOExternalMethodDispatch sMethods[kTestUserClientMethodCount]; static IOReturn sStartTimer (OSObject* target, void* reference, IOExternalMethodArguments* arguments); static IOReturn sStopTimer (OSObject* target, void* reference, IOExternalMethodArguments* arguments); static IOReturn sGetElapsedTimerTime (OSObject* target, void* reference, IOExternalMethodArguments* arguments); static IOReturn sGetElapsedTimerValue (OSObject* target, void* reference, IOExternalMethodArguments* arguments); static IOReturn sDelayForMs (OSObject* target, void* reference, IOExternalMethodArguments* arguments); static IOReturn sDelayForTime (OSObject* target, void* reference, IOExternalMethodArguments* arguments); static IOReturn sInstallTimer (OSObject* target, void* reference, IOExternalMethodArguments* arguments); static void DelayThreadFunc (void *parameter, wait_result_t); IOReturn startTimer (); IOReturn stopTimer (); IOReturn getElapsedTimerTime (uint32_t* timerTime); IOReturn getElapsedTimerValue (TimerValue* timerValue); IOReturn delayForMs (uint32_t milliseconds); IOReturn delayForTime (const TimerValue* timerValue); public: virtual bool initWithTask (task_t owningTask, void* securityToken, UInt32 type, OSDictionary* properties); virtual IOReturn clientClose (void); virtual IOReturn clientDied (void); virtual bool start (IOService* provider); virtual void stop (IOService* provider); virtual void free (void); virtual IOReturn externalMethod ( //32位的請求控制碼 指定客戶端應用程序請求的是哪一個操作 uint32_t selector, //標題及結體體參數 IOExternalMethodArguments* arguments, //應該調用的類方法 IOExternalMethodDispatch* dispatch = 0, OSObject* target = 0, void* reference = 0); };
//UserClientShared.h
//
// UserClientShared.h
// UserSpaceClient
//
#include <stdint.h>
typedef struct TimerValue
{
uint64_t time;
uint64_t timebase;
} TimerValue;
// 用於用戶客戶端方法的控制請求碼
enum TimerRequestCode {
kTestUserClientStartTimer,
kTestUserClientStopTimer,
kTestUserClientGetElapsedTimerTime,
kTestUserClientGetElapsedTimerValue,
kTestUserClientDelayForMs,
kTestUserClientDelayForTime,
kTestUserClientInstallTimer,
kTestUserClientMethodCount
};
IOKitTestUserClient.cpp
//
// IOKitTestUserClient.cpp
// IOKitTest
//
#include <IOKit/IOLib.h>
#include "IOKitTestUserClient.h"
#define super IOUserClient
OSDefineMetaClassAndStructors(com_osxkernel_driver_IOKitTestUserClient, IOUserClient)
bool com_osxkernel_driver_IOKitTestUserClient::initWithTask (task_t owningTask, void* securityToken, UInt32 type, OSDictionary* properties)
{
if (!owningTask)
return false;
if (! super::initWithTask(owningTask, securityToken , type, properties))
return false;
m_task = owningTask;
//判斷進程的權限
IOReturn ret = clientHasPrivilege(securityToken, kIOClientPrivilegeAdministrator);
if ( ret == kIOReturnSuccess )
{
// m_taskIsAdmin = true;
}
return true;
}
bool com_osxkernel_driver_IOKitTestUserClient::start (IOService* provider)
{
if (! super::start(provider))
return false;
m_driver = OSDynamicCast(com_osxkernel_driver_IOKitTest, provider);
if (!m_driver)
return false;
return true;
}
void com_osxkernel_driver_IOKitTestUserClient::stop (IOService* provider)
{
IOLog("userClient::stop\n");
super::stop(provider);
}
void com_osxkernel_driver_IOKitTestUserClient::free (void)
{
IOLog("userClient::free\n");
super::free();
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::clientClose (void)
{
terminate();
return kIOReturnSuccess;
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::clientDied (void)
{
IOLog("userClient::clientDied\n");
return super::clientDied();
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::sStartTimer (OSObject* target, void* reference, IOExternalMethodArguments* arguments)
{
com_osxkernel_driver_IOKitTestUserClient* me = (com_osxkernel_driver_IOKitTestUserClient*)target;
return me->startTimer();
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::sStopTimer (OSObject* target, void* reference, IOExternalMethodArguments* arguments)
{
com_osxkernel_driver_IOKitTestUserClient* me = (com_osxkernel_driver_IOKitTestUserClient*)target;
return me->stopTimer();
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::sGetElapsedTimerTime (OSObject* target, void* reference, IOExternalMethodArguments* arguments)
{
com_osxkernel_driver_IOKitTestUserClient* me = (com_osxkernel_driver_IOKitTestUserClient*)target;
uint32_t timerTime;
IOReturn result;
//調用實現操作的方法
result = me->getElapsedTimerTime(&timerTime);
//將操作的標量結果返回給調用進程
arguments->scalarOutput[0] = timerTime;
return result;
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::sGetElapsedTimerValue (OSObject* target, void* reference, IOExternalMethodArguments* arguments)
{
com_osxkernel_driver_IOKitTestUserClient* me = (com_osxkernel_driver_IOKitTestUserClient*)target;
return me->getElapsedTimerValue((TimerValue*)arguments->structureOutput);
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::sDelayForMs (OSObject* target, void* reference, IOExternalMethodArguments* arguments)
{
com_osxkernel_driver_IOKitTestUserClient* me = (com_osxkernel_driver_IOKitTestUserClient*)target;
return me->delayForMs((uint32_t)arguments->scalarInput[0]);
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::sDelayForTime (OSObject* target, void* reference, IOExternalMethodArguments* arguments)
{
com_osxkernel_driver_IOKitTestUserClient* me = (com_osxkernel_driver_IOKitTestUserClient*)target;
return me->delayForTime((TimerValue*)arguments->structureInput);
}
//保存後臺操作所需參數的結構體
struct TimerParams
{
OSAsyncReference64 asyncRef;
uint32_t milliseconds;
OSObject* userClient;
};
IOReturn com_osxkernel_driver_IOKitTestUserClient::sInstallTimer (OSObject* target, void* reference, IOExternalMethodArguments* arguments)
{
TimerParams* timerParams;
thread_t newThread;
//分配一個結構體,存儲定時器需要的參數
timerParams = (TimerParams*)IOMalloc(sizeof(TimerParams));
//取得asyncReference緩沖區的一個副本
bcopy(arguments->asyncReference, timerParams->asyncRef, sizeof(OSAsyncReference64));
//取得用戶應用程序提供的milliseconds值的一個副本
timerParams->milliseconds = (uint32_t)arguments->scalarInput[0];
//取得userClient對象的一個引用
timerParams->userClient = target;
//異步操作執行時,保留該用戶客戶端
target->retain();
//啟動一個後臺線程,在返回給調用者之後繼續執行操作
kernel_thread_start(DelayThreadFunc, timerParams, &newThread);
thread_deallocate(newThread);
//立即返回給調用應用程序
return kIOReturnSuccess;
}
void com_osxkernel_driver_IOKitTestUserClient::DelayThreadFunc (void *parameter, wait_result_t)
{
TimerParams* timerParams = (TimerParams*)parameter;
//按請求的時間睡眠
IOSleep(timerParams->milliseconds);
//向用戶應用程序發送操作完成的通知
sendAsyncResult64(timerParams->asyncRef, kIOReturnSuccess, NULL, 0);
//後臺操作已經完成
timerParams->userClient->release();
IOFree(timerParams, sizeof(TimerParams));
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::startTimer ()
{
if (m_timerRunning == true)
return kIOReturnBusy;
m_timerRunning = true;
clock_get_uptime(&m_timerStartTime);
return kIOReturnSuccess;
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::stopTimer ()
{
if (m_timerRunning == false)
return kIOReturnNotOpen;
m_timerRunning = false;
return kIOReturnSuccess;
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::getElapsedTimerTime (uint32_t* timerTime)
{
uint64_t timeNow;
uint64_t elapsedTime;
if (m_timerRunning == false)
return kIOReturnNotOpen;
clock_get_uptime(&timeNow);
absolutetime_to_nanoseconds((timeNow - m_timerStartTime), &elapsedTime);
*timerTime = (uint32_t)(elapsedTime / 1000000);
return kIOReturnSuccess;
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::getElapsedTimerValue (TimerValue* timerValue)
{
uint64_t timeNow;
uint64_t elapsedTime;
if (m_timerRunning == false)
return kIOReturnNotOpen;
clock_get_uptime(&timeNow);
absolutetime_to_nanoseconds((timeNow - m_timerStartTime), &elapsedTime);
timerValue->timebase = 1000000;
timerValue->time = (elapsedTime * timerValue->timebase) / 1000000000;
return kIOReturnSuccess;
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::delayForMs (uint32_t milliseconds)
{
IOSleep(milliseconds);
return kIOReturnSuccess;
}
IOReturn com_osxkernel_driver_IOKitTestUserClient::delayForTime (const TimerValue* timerValue)
{
uint32_t milliseconds;
if (timerValue->timebase == 0)
return kIOReturnBadArgument;
milliseconds = (uint32_t)((timerValue->time * 1000) / timerValue->timebase);
IOSleep(milliseconds);
return kIOReturnSuccess;
}
//調試表
const IOExternalMethodDispatch com_osxkernel_driver_IOKitTestUserClient::sMethods[kTestUserClientMethodCount] =
{
// kTestUserClientStartTimer (void)
{ sStartTimer, 0, 0, 0, 0 },
// kTestUserClientStopTimer (void)
{ sStopTimer, 0, 0, 0, 0 },
// kTestUserClientGetElapsedTimerTime (uint32_t* timerValue)
{ sGetElapsedTimerTime, 0, 0, 1, 0 },
// kTestUserClientGetElapsedTimerValue (TimerValue* timerValue)
{ sGetElapsedTimerValue, 0, 0, 0, sizeof(TimerValue) },
// kTestUserClientDelayForMs (uint32_t milliseconds)
{ sDelayForMs, 1, 0, 0, 0 },
// kTestUserClientDelayForTime (const TimerValue* timerValue)
{ sDelayForTime, 0, sizeof(TimerValue), 0, 0 },
// kTestUserClientInstallTimer (uint32_t milliseconds)
{ sInstallTimer, 1, 0, 0, 0 }
};
//驅動程序的IOUserClient子類提供的實現
IOReturn com_osxkernel_driver_IOKitTestUserClient::externalMethod (uint32_t selector, IOExternalMethodArguments* arguments,
IOExternalMethodDispatch* dispatch, OSObject* target, void* reference)
{
//判斷控制碼 確保請求的控制碼選擇器在範圍內
if (selector >= kTestUserClientMethodCount)
return kIOReturnUnsupported;
//選擇相應的控制碼(也就是調試表)
dispatch = (IOExternalMethodDispatch*)&sMethods[selector];
target = this;
reference = NULL;
//返回父類的
return super::externalMethod(selector, arguments, dispatch, target, reference);
//超類的實現
// externalMethod(selector, arguments, dispatch, target, reference){
// Dispatch->function(target,reference,args);
// }
}
//IOKitTest.h
#include <IOKit/IOService.h>
class com_osxkernel_driver_IOKitTest : public IOService
{
OSDeclareDefaultStructors(com_osxkernel_driver_IOKitTest)
public:
virtual bool init (OSDictionary* dictionary = NULL);
virtual void free (void);
virtual bool start (IOService* provider);
virtual void stop (IOService* provider);
};
//IOKitTest.cpp
#include "IOKitTest.h"
#include <IOKit/IOLib.h>
#define super IOService
OSDefineMetaClassAndStructors(com_osxkernel_driver_IOKitTest, IOService)
bool com_osxkernel_driver_IOKitTest::init (OSDictionary* dict)
{
bool res = super::init(dict);
return res;
}
void com_osxkernel_driver_IOKitTest::free (void)
{
super::free();
}
//啟動時設置與之交互的IOUserClientClass
bool com_osxkernel_driver_IOKitTest::start (IOService *provider)
{
bool res = super::start(provider);
setProperty("IOUserClientClass", "com_osxkernel_driver_IOKitTestUserClient");
registerService();
return res;
}
void com_osxkernel_driver_IOKitTest::stop (IOService *provider)
{
super::stop(provider);
}
liuhailongdeMacBook-Air:~ liuhailong$ sudo chown -R root:wheel /Users/liuhailong/Library/Developer/Xcode/DerivedData/IOKitTest-dpmmsjcydkpiyxewowmltvnxxxgh/Build/Products/Debug/IOKitTest.kext
liuhailongdeMacBook-Air:~ liuhailong$ sudo kextload /Users/liuhailong/Library/Developer/Xcode/DerivedData/IOKitTest-dpmmsjcydkpiyxewowmltvnxxxgh/Build/Products/Debug/IOKitTest.kext
/Users/liuhailong/Library/Developer/Xcode/DerivedData/IOKitTest-dpmmsjcydkpiyxewowmltvnxxxgh/Build/Products/Debug/IOKitTest.kext failed to load - (libkern/kext) link error; check the system/kernel logs for errors or try kextutil(8).
liuhailongdeMacBook-Air:~ liuhailong$ sudo chown -R root:wheel /Users/liuhailong/Library/Developer/Xcode/DerivedData/IOKitTest-dpmmsjcydkpiyxewowmltvnxxxgh/Build/Products/Debug/IOKitTest.kext
liuhailongdeMacBook-Air:~ liuhailong$ sudo kextload /Users/liuhailong/Library/Developer/Xcode/DerivedData/IOKitTest-dpmmsjcydkpiyxewowmltvnxxxgh/Build/Products/Debug/IOKitTest.kext
liuhailongdeMacBook-Air:~ liuhailong$ /Users/liuhailong/Library/Developer/Xcode/DerivedData/UserSpaceClient-ffozqcnbwexasqelqqgpccijiicg/Build/Products/Debug/UserSpaceClient
StopTimer - e00002cd
StartTimer - 00000000
GetElapsedTimerTime - 00000000, time 0
DelayForMs - 00000000
GetElapsedTimerTime - 00000000, time 100
GetElapsedTimerValue - 00000000, time 100170 / 1000000
DelayForTime - e00002c2
DelayForTime - 00000000
GetElapsedTimerTime - 00000000, time 600
StopTimer - 00000000
InstallTimer - 00000000
InstallTimer - 00000000
InstallTimer - 00000000
InstallTimer - 00000000
DelayCallback - refcon dead0002 and result 00000000
DelayCallback - refcon dead0005 and result 00000000
DelayCallback - refcon dead0007 and result 00000000
DelayCallback - refcon deadbeef and result 00000000
liuhailongdeMacBook-Air:~ liuhailong$
應用程序與驅動程序客服端方式交互