又过了一个星期了,终于抽出时间继续来更新我的博客,接上一篇文章,我们已经讨论了如何通过属性来让应用层与内核产生交互,但试想一下,针对一个功能更加复杂的驱动程序,仍然使用属性的值来定义一套交互的过程,会显得既笨拙又低效,今天就来继续学习一下如何用更好的方式来完成这个交互,我用了两篇文章来讨论应用层与内核之间的交互过程,一方面因为我能力有限短时间内还不能深入到具体的驱动程序的开发,但一方面我觉得既然驱动程序最终也是为应用层提供服务,所以两者之间的交互是一个必需的也非常重要的过程。
在上一篇文章中使用IOKit相关接口的时,或许你不经意间已经留意到了类似IOServiceOpen的方法,没错,这篇文章正是讨论怎样打开一个枚举到的驱动程序对象而建立连接,但IOKit框架并不会让会应用程序直接与驱动程序连接,而是需要引用一个IOUserClient作为媒介,其原因是因为应用程序与驱动程序并非一对一的关系,驱动程序可能需要同时为多个应用提供服务,而应用程序也可以同时与多个驱动对象交互,所以每一个连接就需要一个对象来进行维护,而这个工作就是由IOUserClient来完成的(大多情况下你会根据需求编写子类),这与面向对象编程的低耦合思想是相符的,为了加深理解这个机制,我们通过下面的关系图可以更加直观的理清它们之间的关系:
理论就介绍到这儿了,下面就直接开始编码了,我们本篇文章的Demo让驱动程序实现一个四则运算,然后用户程序通过与驱动建立连接,调用接口并得到计算结果。
IOUserClient虽然是应用程序与驱动程序的枢纽,但由于它也属于驱动程序的一个部分,所以应用程序也不能直接通过函数调用的方法使用到IOUserClient,而是通过IOKit框架提供的接口IOConnectCallStructMethod方法,应用程序需要调用什么什么方法,通过指定一个uint64的值传递到内核的IOUserClient,然后选择对应的方法,方法需要的参数和返回值都是通过结构体保存和传递,所以我们需要定义表示不同方法的uint64的值和不同的结构体,而这些定义在应用程序和驱动程序中都需要使用到,所以我们定义在一个公共的头文件Common.h中:
|
|
然后我们编写应用程序中的代码:
|
|
应用程序的代码就已经完成了,下面就需要修改驱动程序的代码了,修改之前编写的驱动程序代码,添加四个方法:
|
|
然后下面就要编写一个自定义的IOUserClient的子类com_osxkernel_driver_IOKitTestUserClient,实现应用程序与驱动程序之间的连接,为了让IOKit框架可以自动识别我们的用户连接类我们需要修改Info.plist文件,并在IOKitPersonalities下的IOKitTest字典中添加IOUserClientClass的值为com_osxkernel_driver_IOKitTestUserClient,另外将前面的公共头拖入到工程中,然后就开始编写代码,下面是com_osxkernel_driver_IOKitTestUserClient的头文件:
|
|
由代码可以看到用户连接类与驱动程序的类结构非常相似,其实IOUserClient也是IOService的一个子类,只不过初使化的方法和结束的方法不太一样,另外一个关键的方法就是externalMethod,具体的一些实现细节就直接看实现文件:
|
|
好了,代码到这儿就完全结束了,现在编译加载驱动,然后运行应用程序相信就能得到相应的结果了,本文章中的Demo源代码下载:IOKitTest+AppTest_2.zip