这里是测试内容
文章目录
- 1.Linux kernel 驱动层
- 2.hardware层
- 3.frameworks services层:frameworks/base/services
- 4.systemserver进程调用
- 5.Android系统服务之新增自定义GPIO服务全系列链接
本文再次分析Android lights模块,此次分析处于以下目的原因:
1.Android8.1 新引入HIDL接口,HAL lights模块有变动
2.新增自定义服务,同时进一步深入理解Android系统服务板块
note:本文此次分析主要以HIDL接口分析为依托,旧方式可以移步msm8953 Android7.1.2 lights模块分析
1.Linux kernel 驱动层
关于Linux kernel驱动层这里就不多费口舌,直接上图和传送门:Android(Linux) led子系统分析
//TODO,此处缺图,后面补上
2.hardware层
2.1 hardware hal 硬件具体实现 (这里会根据硬件的不同而不同)
hardware/rockchip/liblights:此处以rockchip px30作为分析对象
因为这里的cpp实现是紧紧依赖硬件的,所以关于liblights/lights.cpp这里就不分析了,感兴趣的和可以结合我上面的传送门(以前的分析文章)自行阅读源码。
2.2 hardware/libhardware/include/hardware/lights.h
在hardware/libhardware/Android.bp中定义了cc_library_shared的生成规则,最终生成libhardware.so。
另外,lights.h内容如下,主要定义了针对lights的HAL的标准ID–LIGHTS_HARDWARE_MODULE_ID
,还有两个重要的结构体light_state_t
和light_device_t
。
2.3 hardware/interfaces/light
HIDL接口服务端实现处,这部分是Android8以后新增的一个架构,目的是将HAL里面在进行一次分层,促成依赖于binder的CS架构,即原来是直接通过jni的方式调用本地hal的硬件动态库变成依赖于binder的CS架构,什么意思呢?就是慢慢抛弃直接调用so的库的形式,jni调用binder的客户端,然后通过客户端与binder的服务端进行通信,实现对硬件的操作,这样做的好处是从原来的systemserver进程中将每个HAL模块独立在独立进程中,咱们先理解到这,后面结合分析深入理解。
目录结构如下:
light/
|-- 2.0
| |-- Android.bp
| |-- Android.mk
| |-- ILight.hal
| |-- default
| | |-- Android.mk
| | |-- Light.cpp
| | |-- Light.h
| | |-- android.hardware.light@2.0-service.rc
| | `-- service.cpp
| |-- types.hal
| `-- vts
| |-- Android.mk
| `-- functional
| |-- Android.bp
| `-- VtsHalLightV2_0TargetTest.cpp
`-- Android.bp
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
这里可以看到hardware/interface下的lights目录下即是HIDL的实现处,在旧版本这里是没有的,其中ILight.hal 即是HIDL接口的定义,(这里用白话解释下HIDL,熟悉AIDL接口的朋友可以以H换A来理解,AIDL是跨进程通信的,那HIDL也是可以这样理解,只不过它是处于HAL层的,好,就此打住!)
其他文件后续一一分析。
ILight.hal 内容如下:
package android.hardware.light@2.0;
interface ILight {
setLight(Type type, LightState state) generates (Status status);
getSupportedTypes() generates (vec<Type> types);
};
- 1
- 2
- 3
- 4
- 5
- 6
这个接口就提供了两个方法,它们用于对指定的light进行设置和获取支持的type;关于支持的type我们可以从前面提到的lights.h中得到,比如有BACKLIGHT,KEYBOARD等;
那这两个接口定义都是需要我们在hal服务层去实现的,最终调用到了hal硬件实现处,即light.cpp里。
**hal服务层实现在哪?**可以注意到在default目录下有Light.cpp,就是它了~
关于HIDL这部分都是可以自动生成,生成后我们进行具体化的实现,以及部分根据需要修改即可,这里重要的就是Light.cpp了,这里我们看看头文件Light.h的定义:
#ifndef ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
#define ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
#include <android/hardware/light/2.0/ILight.h>
#include <hardware/hardware.h>
#include <hardware/lights.h>
#include <hidl/Status.h>
#include <hidl/MQDescriptor.h>
#include <map>
namespace android {
namespace hardware {
namespace light {
namespace V2_0 {
namespace implementation {
using ::android::hardware::light::V2_0::ILight;
using ::android::hardware::light::V2_0::LightState;
using ::android::hardware::light::V2_0::Status;
using ::android::hardware::light::V2_0::Type;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::sp;
struct Light : public ILight {
Light(std::map<Type, light_device_t*> &&lights);
// Methods from ::android::hardware::light::V2_0::ILight follow.
Return<Status> setLight(Type type, const LightState& state) override;
Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override;
private:
std::map<Type, light_device_t*> mLights;
};
extern "C" ILight* HIDL_FETCH_ILight(const char* name);
} // namespace implementation
} // namespace V2_0
} // namespace light
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
上述代码可以看到:
实现了我们在ILight.hal
中看到的两个方法,setLight
和getSupportedTypes
;
note:这里注意一个点,关于HIDL_FETCH_ILight
方法,这个就是谷歌为了以前的就HAL方式的实现向前兼容的一个处理,可以看到现在很多厂商为了沿用之前的代码将这部分进行实现,也就可以直接沿用之前的一个hal直接调用so的实现了,而非现在的binder HIDL;
这里主要针对的是HIDL,看看实现,CPP文件内容比较长,这里就只留了部分重要的地方以供参考:
#define LOG_TAG "light"
#include <log/log.h>
#include "Light.h"
namespace android {
namespace hardware {
namespace light {
namespace V2_0 {
namespace implementation {
Light::Light(std::map<Type, light_device_t*> &&lights)
: mLights(std::move(lights)) {}
// Methods from ::android::hardware::light::V2_0::ILight follow.
Return<Status> Light::setLight(Type type, const LightState& state) {
auto it = mLights.find(type);
......
light_device_t* hwLight = it->second;
......
int ret = hwLight->set_light(hwLight, &legacyState);
......
}
Return<void> Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) {
......
}
const static std::map<Type, const char*> kLogicalLights = {
{Type::BACKLIGHT, LIGHT_ID_BACKLIGHT},
......
};
light_device_t* getLightDevice(const char* name) {
light_device_t* lightDevice;
const hw_module_t* hwModule = NULL;
int ret = hw_get_module (LIGHTS_HARDWARE_MODULE_ID, &hwModule);
if (ret == 0) {
ret = hwModule->methods->open(hwModule, name,
reinterpret_cast<hw_device_t**>(&lightDevice));
......
}
......
}
ILight* HIDL_FETCH_ILight(const char* /* name */) {
std::map<Type, light_device_t*> lights;
......
light_device_t* light = getLightDevice(name);
......
return new Light(std::move(lights));
}
} // namespace implementation
} // namespace V2_0
} // namespace light
} // namespace hardware
} // namespace android
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
这部分的实现也是挺简单的,这里简单分析下:
1.先把不相干但挺重要的说了吧,看到HIDL_FETCH_ILight
的实现,它是这么个流程,HIDL_FETCH_ILight->getLightDevice
,在getLightDevice
中有用到了以前很重要的一些东西–hw_get_module
和hwModule->methods->open
,这种方式就是HIDL方式出来之前的。那意思就是说只要实现了这部分,我们就可以不用binder C/S的方式,直接调用so到lights.cpp中。
2.再看getSupportedTypes
函数,这个就是HIDL的方式,这里的实现内容比较简单,就是将type进行归纳整理就不进行分析了,上述代码我也去掉了,感兴趣的可以自行查看源码。
3.setLight
函数,这个就是lights模块HIDL服务端的重头戏了,它就是对客户端的一个实际实现,但实现具体是在硬件实现层的lights.cpp。setlight通过hwLight
调用到了对应的set_light
,这个set_light
最终也到了lights.cpp中。hwLight
是一个light_device_t类型的指针,它指向了一个每一个type,因此只要传入的type不一样,那么最终实现的set_light
也就不一样。
这里还有一个比较的重要文件–service.cpp
,暂且理解成HIDL的HAL服务提供吧,理解成用来解决为啥HIDL客户端能够找到链接到这个服务端,这里由于笔者学艺不精,讲不太清,由大佬可以指教一二也就感激之至了!
#define LOG_TAG "android.hardware.light@2.0-service"
#include <android/hardware/light/2.0/ILight.h>
#include <hidl/LegacySupport.h>
using android::hardware::light::V2_0::ILight;
using android::hardware::defaultPassthroughServiceImplementation;
int main() {
return defaultPassthroughServiceImplementation<ILight>();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
可以看到service.cpp
的代码实现是很简单的,但里面涉及的知识量应该很大吧,所谓不知道就很神奇~
最后一个文件:android.hardware.light@2.0-service.rc
,它也可以是由工具生成,先看看内容,如下:
service light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service
class hal
user system
group system
- 1
- 2
- 3
- 4
有没有感觉很熟悉,没错就是由init.rc,init进程进行处理,因此这也就解释了为啥HIDL的模式会使得原来的HAL层代码脱离systemserver进程而可以独立有自己的进程空间。其实这里也可以想到,以独立服务运行了,一定会涉及到selinux的问题,这里关于新增的hal服务,新增的selinux机制咱们后面再谈。
最终运行效果如下图所示:
关于Android.bp,Android.mk文件,这里不做过多说明,感兴趣的不明白的可以移步:
关于type.hal
这个文件它是HIDL语法的文件,可以移步:
3.frameworks services层:frameworks/base/services
3.1 客户端jni调用
frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
namespace android {
class LightHal {
private:
static sp<ILight> sLight;
static bool sLightInit;
LightHal() {}
public:
static void disassociate() {
} // 断开ILight服务
static sp<ILight> associate() {
sLight = ILight::getService(); //取得ILight服务
return sLight;
}
};
sp<ILight> LightHal::sLight = nullptr;
bool LightHal::sLightInit = false;
//对参数进行检查
static bool validate(jint light, jint flash, jint brightness) {
return valid;
}
//构造LightState 类型参数
static LightState constructState(
jint colorARGB,
jint flashMode,
jint onMS,
jint offMS,
jint brightnessMode){
Flash flash = static_cast<Flash>(flashMode);
Brightness brightness = static_cast<Brightness>(brightnessMode);
LightState state{};
state.brightnessMode = brightness;
return state;
}
//处理返回结果
static void processReturn(
const Return<Status> &ret,
Type type,
const LightState &state) {
}
// jni本地方法 setLight
static void setLight_native(
JNIEnv* /* env */,
jobject /* clazz */,
jint light,
jint colorARGB,
jint flashMode,
jint onMS,
jint offMS,
jint brightnessMode) {
if (!validate(light, flashMode, brightnessMode)) {
return;
}
sp<ILight> hal = LightHal::associate(); //取得Light服务
LightState state = constructState(
colorARGB, flashMode, onMS, offMS, brightnessMode); //构造setLight需要的LightState类型参数
{
android::base::Timer t;
Return<Status> ret = hal->setLight(type, state); //调用hal的setLight函数实际是调用了HIDL里的setLight,最终调到lights里的对应setLight
processReturn(ret, type, state);//处理执行结果
}
}
//本地方法集合
static const JNINativeMethod method_table[] = {
{ "setLight_native", "(IIIIII)V", (void*)setLight_native },
};
//注册本地方法
int register_android_server_LightsService(JNIEnv *env) {
return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",
method_table, NELEM(method_table));
}
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
以上代码我去除了一些部分,并且对重要部分做了些注释,应该还算容易理解,完整的大家自行查阅源码;
3.2 客户端frameworks java服务:执行本地jni调用
frameworks/base/services/core/java/com/android/server/lights/LightsService.java
那么谁会调到setLight_native 呢,肯定就是jni的java文件了–LightsService.java
LightsService java块集中在frameworks/base/services/core/java/com/android/server/lights
,如下:
这里代码就不一一分析了,可以参考前面提到的传送门。
另外,这里提下之前没有讲到的关于Android系统服务之publishLocalService
和publishBinderService
,它们被定义在Systemservice里,前者所发布的服务非同进程的是不可以获取该服务的,也就是说它只能同进程内使用,这也就意味着,其他app无法使用该服务;那么后者所发布的服务(binder),这种显而易见就是跨进程通信的,因此它是能够被其他app所获取并使用的。
从另一方面来讲,我想之所以存在这两种类型的服务,大多是效率和需求所致,如果只有Local,那就不能实现跨进程通信,如果只有Binder,虽然同进程和非同进程的都能使用,但是对于同进程来说,就有点杀鸡用牛刀且效率不够高的那味了~。
LightsService 服务发布如下所示:
这也就意味着我们其他APP不能使用这个服务了,只能systemserver进程自己使用了,经过代码调用查找,也确实如此。关于light服务下的turnoff方法的使用,也只有很少的系统进程使用了,如下所示:
4.systemserver进程调用
现在看看如何对于使用publishLocalService
发布的服务,系统进程是如何使用的,就以电池服务作为例子吧。
frameworks/base/services/core/java/com/android/server/BatteryService.java
这里不明白的朋友可能会疑惑为啥这里有两种本地服务的调用方式,看下面方框的ActivityManagerInternal也是本地服务,它怎么是以LocalServices.getService的方式调用的,我们看看getLocalService的实现,如下:
可以知道getLocalService
的实现就是LocalServices.getService
,这样就清晰了。
结合上面将的lights模块,最终它是怎么调用到硬件lights的驱动呢?
看看led的构造,如下:
可以看到lights是一个LightsManager的对象,它通过getLight方法取得了电池的type id,这样通过前面的分析,jni java到cpp然后到HIDL接口再到服务端最终到达硬件实际实现地方lights.cpp。
至此,基于android8.1. 新特性HIDL的lights模块分析至此结束,后面讲讲如何新增自己的HAL层HIDL接口,以GPIO操控为例。