第二章:硬件访问服务(1)-框架介绍

通过上一章节,知道怎么通过JNI注册本地函数,注册之后,APP软件可以间接调用C函数,进而访问硬件。但是(之前也有提及过),我们直接编写APP程序,然后访问硬件是不安全的,比如:手机是有很多APP的,如果每个APP需要播放声音,那么如果同一时刻到底播放谁的呢?针对类似问题,adriod系统中,有一套较好的解决方法- 访 \color{red}{硬件访问服务} 。顾名思义,这个框架是一个专门为应用层访问底层而存在的服务。下面,我们就开始解析吧。

框图解说

这里引用韦老师的一副框图(题外话:韦老师的确是一个很好的老师,只能说是相识恨晚,如果在大学就能知道韦老师,或许现在也不会是这幅潦倒的模样,扯远了,继续我们的框架解析)。如下:
在这里插入图片描述
初步看起来,该框图似乎不好理解,别急我们慢慢分析,下面我将以酒店作为类比,来逐步解说(该小节只谈框架理解,暂不涉及程序)。

Andriod app(java)

这里表示的是一个应用程序,可以当做一个client(客户,即我们硬件访问服务器服务的对象),我们所做的一切,都是为了给client提供合适的java接口去控制硬件。当然,即使客户是上帝,也的遵循一定的规则。那么客户,需要遵循什么样的规则,才能达到他访问硬件的目的呢?
1.需要申请具体服务(getService),就好像你去酒店吃饭一样,你需要点菜,指定具体的菜名。只有菜单里存在的菜式才可以点
2.指令发送,你获得服务以后,就可以发送对硬件的操作指令了,可以申请打开或者关闭LED。类似于,上菜之后,客户可以用勺子挖着吃,也可以用筷子夹着吃。

service_manager.c

前面提到,客服get服务时,需要先查询服务,那么这些支持的服务都被罗列在哪里呢?andriod中应用了一个进程专门负责管理这些服务。可以理解为饭店的菜单,这个菜单上面有很多的菜式,service_manager(服务管理)管理着很多服务,如ledService,vibratorService,sendService等等。

SystemServer.java

饭店的菜单上的菜式有哪些呢?或者说这些菜式该怎么写呢?当然得看厨师会做什么菜,只有能做出来的菜,我们才能添加到菜单之中。我们的service_manager(服务管理)也是一样,他需要管理服务,但是他管理哪些服务,他又是怎么知道的,在andriod系统中,是通过SystemServer.java进行添加的,他会向service_manager注册服务,只有注册成功的service才能供顾客选择。这里的SystemServer.java可以理解为一个厨师总管,总管上报能做的菜式,图中的register_android_server——xxx类比如真正的厨师,可以真实提供对应的服务。

其余杂项

其中的黄色圈中的代表的是方法,后续章节会提及,

onload.cpp理解为厨师总管罗列的菜单,这个菜单主要让菜式和厨师一一对应(那个菜式具体由那个厨师制作:服务与硬件操作一一对应),并且方便管理。

hw_get_module在后续章节进行具体讲解,可以理解为每个厨师都拥有的公共技能,提高菜式的档次(让代码看起来层次分明)。

源码追踪

通过前面讲解,大家对硬件访问服务的框架应该有了大致的了解,下面我们对SDK/frameworks中的源码进行追踪。我们以 v i b r a t o r \color{red}{vibrator(震动器)} 进行讲解

该文件处于SDK/frameworksbase/services/java/com/android/server/SystemServer.java
该文件我们可以看到

    public static void main(String[] args) {
        new SystemServer().run();
    }

说明其会调用run()函数,在该函数中,可以找到如下代码

   System.loadLibrary("android_servers");

这里实质加载的是框图中的onload.cpp(为什么是他,后续进行讲解),那么onload.cpp做了什么我们继续查看源码:

	......
    register_android_server_ActivityManagerService(env);
    register_android_server_PowerManagerService(env);
    register_android_server_SerialService(env);
    register_android_server_InputApplicationHandle(env);
    register_android_server_VibratorService(env);
	.......

为使博文看起来不过于臃肿,只粘贴少部分代码,可以看到该文件只要调用了一堆的服务注册函数,那么我们来看看
r e g i s t e r a n d r o i d s e r v e r V i b r a t o r S e r v i c e ( e n v ) ; \color{red}{ register_android_server_VibratorService(env);}

int register_android_server_VibratorService(JNIEnv *env)
{
    return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
            method_table, NELEM(method_table));
}

可谓是返璞归真啊,看到jniRegisterNativeMethods是不是很熟悉(可查看之前博文,有相关介绍),就这样我们似乎知道系统是怎么通过服务调用C函数,然后对硬件进行操作了,具体细节,后面再进行讲解,我们返回到run函数中,可以看到如下代码:

	if(!isBox){
	  	  traceBeginAndSlog("StartVibratorService");
		  vibrator = new VibratorService(context);
		  ServiceManager.addService("vibrator", vibrator);
		  Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
	}

首先nwe了一个VibratorService对象,然后通过ServiceManager.addService把该对象添加到ServiceManager中,让系统进程进行维护,我们右击VibratorService查看其定义,可以找到VibratorService.java文件,我们可以看到如下代码

    native static boolean vibratorExists();
    native static void vibratorInit();
    native static void vibratorOn(long milliseconds);
    native static void vibratorOff();

这些之前通过JNI注册的本地方法,就与软件层就联系到一起了

小节回顾

该小节用比喻的方法进行讲解,不知道是不是更加容易理解,我们充当的是厨师部分,菜谱不需要我们制作,客户我们也不用管,只需要把菜做出来就可以了,当然。在这之前我们先要在菜单上填写我们的菜式。
在访问硬件的时候,客户需要通过申请服务才能访问,什么时候让该客户进行访问,都由服务器决定分配,他的内部机制(具体细节可查询其他资料)会保证多个应用访问用一硬件时,而不会错乱。
下小节我们将进入手写代码章节敬请期待!

猜你喜欢

转载自blog.csdn.net/weixin_43013761/article/details/86744129