如何创建一个守护进程
- 1.新建一个模块,比如在system/core/下建一个目录brightnessenable
- 2.创建一个cpp文件 如service.cpp
- 3.添加Android.mk用来编译成可执行文件
- 4.创建xxx.rc文件,用于开机启动执行该进程
- 5.添加SElinux 权限
以上五步,我们一步步进行详细分析
第一步就不说了,比较简单,
先说下我这个需求的内容,开机创建一个守护进程,获取或监听Vhal发送的报文信息,根据报文信息
判断是否点亮背光。
1.创建service.cpp,
using namespace android;
namespace {
sp<VehicleListener> service;
}// namespace
int main()
{
//创建进程优先级
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
//创建一个进程
sp<ProcessState> proc(ProcessState::self());
//设置进程允许最大线程数为4
ProcessState::self()->setThreadPoolMaxThreadCount(4);
//开启一个线程池
ProcessState::self()->startThreadPool();
//用来监听或者获取Val的信息
service = new VehicleListener();
//把该进程加入线程池当中
IPCThreadState::self()->joinThreadPool();
return 0;
}
创建进程,设置进程的优先级,
开启一个线程池,设置最大线程数,
初始化Val业务逻辑
把该进程加入线程池当中
2.接下来看一下Val的业务逻辑处理
VehicleListener :: VehicleListener(){
//创建VehicleThread
mVehicleThread = new VehicleThread(this);
//启动VehicleThread
mVehicleThread->run("VehicleListener ::VehicleThread", PRIORITY_DISPLAY);
//获取 Vehicle服务
mVehicle = IVehicle::getService();
if(mVehicle != nullptr){
//获取PowerMode
int hasPowerMode = getPowerMode();
if (hasPowerMode == 0){
//注册Vehicle监听,用来监听Vehicle的PowerMode是否发生改变
registerVehicleCallback();
mRegiserVehichl = true;
}
}
}
1.主线程用于获取Vehicle服务,注册Vehicle服务监听,当Vehicle的PowerMode发生信息变化,
这边根据Vehicle信息,作出判断,通知VehicleThread去处理.
2.VehicleThread接受到Vehicle服务信息,做出处理,后面详细介绍怎么处理
###VehicleThread线程的创建
VehicleListener::VehicleThread::VehicleThread(sp<VehicleListener> vehicleListener)
{
//用来判断该线程是否运行运行状态,在threadloop中会设置为true
mRunning = false;
//获取mVehicleListener,
mVehicleListener = vehicleListener;
//获取VehicleService服务
mVehicleService = vehicleListener->mVehicle;
}
//线程运行
bool VehicleListener::VehicleThread::threadLoop()
{
{
Mutex::Autolock _l(mLock);
mRunning = true;
}
mCondition.wait(mLock);//等待主线程逻辑处理,阻塞在这里
//主线程处理完会通知该线程做以下逻辑处理
if (mVehicleListener->mForceUpdate) {
String8 reason = mVehicleListener->mReason;//更新的原因
bool lighton = mVehicleListener->mBackLightOn;//设置背光控制打开或者关闭
mVehicleListener->setForceUpdateVaule(false);
ALOGD("VehicleListener force update brightness enable to %d, reason %s", lighton, reason.string());
property_set("brightness.enable.op", lighton?"on":"off");//背光打开,写入背光节点brightness.enable.op为on,否则写入off
}
if(mVehicleListener->mRegiserVehichl){
mVehicleService->unsubscribe(mVehicleListener, toInt(VehicleProperty::BCM_POWER_MODE));
}
mVehicleService.clear();
return false;
}
1.这块主要处理获取Val信息之后,是否要更新背光判断节点的值,
2.on代表打开屏幕背光,off代表关闭屏幕背光
下面看下主线程的逻辑
//获取PowerMode
int hasPowerMode = getPowerMode();
if (hasPowerMode == 0){
//注册Vehicle监听,用来监听Vehicle的PowerMode是否发生改变
registerVehicleCallback();
mRegiserVehichl = true;
}
1.主线程分两步,先获取PowerMode,如果从获取到PowerMode,则不用再去注册Vehicle监听
根据Vehicle状态属性信息,直接去更新mReason,mBackLightOn
2.通过getPowerMode方法,如果获取不到PowerMode相关值,则需要注册监听,当BCMPowerMode发生变化
或返回Vehicle状态属性信息,直接去更新mReason,mBackLightOn
以上两步,我们详细分析看下
###getPowerMode() 获取Vehicle状态属性信息
int VehicleListener::getPowerMode(){
//Vehicle的属性值
VehiclePropValue propValue{};
初始化属性值
propValue.prop = toInt(VehicleProperty::BCM_POWER_MODE);
propValue.areaId = 0;
StatusCode status = StatusCode::TRY_AGAIN;
bool called = false;
获取Vehicle信息
Return<void> ret = mVehicle->get(propValue,[&propValue, &status, &called](StatusCode s,
const VehiclePropValue& value) {
status = s;
//更新属性值
propValue = value;
called = true;
});
if (ret.isOk()) {
//根据propValue属性值进行判断,后续会做详细讲解
updateBacklight(propValue);
return 1;
} else {
ALOGE("get power mode failed error %d", status);
}
return 0;
}
1.getPowerMode逻辑很简单,通过mVehicle的get方法更新属性值,
2.如果有属性值,则调用updateBacklight去处理属性值
接下来看下注册监听的处理
registerVehicleCallback() 注册监听Vehicle
void VehicleListener::registerVehicleCallback(){
SubscribeOptions optionsData[1] = {
{
.propId = toInt(VehicleProperty::BCM_POWER_MODE),
.flags = SubscribeFlags::ON_CHANGE
},
};
hidl_vec<SubscribeOptions> options;
options.setToExternal(optionsData, arraysize(optionsData));
mVehicle->subscribe(this, options);
}
//当监听到VehiclePropValue属性值发生变化,会回调该方法
Return<void> VehicleListener::onPropertyEvent(const hidl_vec <VehiclePropValue> &values) {
for(VehiclePropValue propValue: values){
if(propValue.prop == toInt(VehicleProperty::BCM_POWER_MODE)){
//根据propValue属性值进行判断,后续会做详细讲解
updateBacklight(propValue);
}
}
return Return<void>();
注册监听Vehicle,监听到VehiclePropValue属性值发生变化,回调onPropertyEvent,根据prop
去调用updateBacklight方法更新背光的逻辑逻辑处理。
updateBacklight()核心方法
void VehicleListener::updateBacklight(VehiclePropValue propValue) {
if(propValue.value.int32Values.size() == 0){
return;
}
//整车电源模式有3三种,分别ACC、ON、OFF三种对应整车不同电源状态
int32_t mode = propValue.value.int32Values[0];
//整车电源模式标志位 local remote的两种
int32_t flag = propValue.value.int32Values[2];
bool lighton = false;
String8 reason;
if (flag == 0) {
switch(mode) {
//local off 此时正在整车模式将要进入休眠,开机不会点亮屏幕
case 0:
reason = "local_off";
break;
case 1:
//local acc 状态,整车进入正常模式,开机时获取这种状态提前点亮屏幕
lighton = true;
reason = "local_acc";
break;
case 2:
//local on 状态,整车进入正常模式,开机时获取这种状态提前点亮屏幕
lighton = true;
reason = "local_on";
break;
case 3:
reason = "local_invalid";
break;
default:
reason = "local_unknow";
break;
}
if (mode == 1 || mode == 2) {
lighton = true;
}
} else if (flag == 1) {
//POWER_MODE_REMOTE, force brightness op to off.
//remote 状态(车内无人) ,此时正在整车模式将要进入部分运行工作或者休眠,开机不会点亮屏幕
reason = "remote_off";
}
if (lighton != mBackLightOn) {
更新BackLight状态值
//是否强制更新
mForceUpdate = true;
//更新的原因
mReason = reason;
//更新的判断。根据此变量判断是否打开背光
mBackLightOn = lighton;
while(true){
usleep(250000);
if(mVehicleThread->isRunning()){
//唤醒VehicleThread
mVehicleThread-> mCondition.signal();
break;
}
}
}
}
这段逻辑主要处理整车模式后,获取整车电源模式状态,根据电源模式状态,判断是否要要打开
背光
VehicleThread::threadLoop()解析
bool VehicleListener::VehicleThread::threadLoop()
{
{
Mutex::Autolock _l(mLock);
mRunning = true;
}
//等待主线程处理逻辑
mCondition.wait(mLock);
//主线程处理完以后,取消阻塞,判断是否强制更新
if (mVehicleListener->mForceUpdate) {
//跟新点亮背光的原因(主要为了方便以后log调查)
String8 reason = mVehicleListener->mReason;
//判断是否要写背光为on, true 为on
bool lighton = mVehicleListener->mBackLightOn;
mVehicleListener->setForceUpdateVaule(false);
ALOGD("VehicleListener force update brightness enable to %d, reason %s", lighton, reason.string());
//lighton 为true,设置brightness.enable.op系统属性为on
property_set("brightness.enable.op", lighton?"on":"off");
}
//取消注册VehicleListener
if(mVehicleListener->mRegiserVehichl){
mVehicleService->unsubscribe(mVehicleListener, toInt(VehicleProperty::BCM_POWER_MODE));
}
mVehicleService.clear();
return false;
}
- 主线程处理完整车电源模式以后,会唤醒子线程 VehicleThread , VehicleThread根据整车模式的处理判断
,主要处理是否要强制更新支持背光的属性, lighton为true,强制设置brightness.enable.op为on,这样背光
就会打开,开机动画就能完全显示。
下面介绍进程启动的一些配置
- 1.配置brightnessenable.rc(自己命名)脚本文件,用于系统启动init初始化brightnessenable(自己命名)服务,
service brightnessenable(进程服务名(自己命名)) /system/bin/brightnessenable(可执行程序路径)
class main //main函数启动入口
user root //root权限
group root //所属用户组root
- 2.Android.mk 的创建以及配置
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
//编译生成可执行模块的名字
LOCAL_MODULE := brightnessenable
//程序所在文件
LOCAL_SRC_FILES:= \
service.cpp \
VehicleListener.cpp
//程序中所要引入的库
LOCAL_SHARED_LIBRARIES := \
libhidlbase \
libhidltransport \
libcutils \
liblog \
libutils \
libhardware \
libbase \
libbinder \
android.hardware.automotive.vehicle@2.0
//序中所要引入的静态库?
LOCAL_STATIC_LIBRARIES += \
android.hardware.automotive.vehicle@2.0-manager-lib
//编译生成可执行文件的脚本
LOCAL_INIT_RC := brightnessenable.rc
include $(BUILD_EXECUTABLE)
主要用来编译程序生成文件,以及编译程序要引入相关的库
- 3.编译生成的脚本文件,存放的位置配置
brightnessenable 编译生成会放到设备的 /system/bin 下
brightnessenable.rc 编译生成会放到设置的 /system/etc/init 下
具体配置如下,在M01_AE.mk(产品名)中配置
部分代码如下
#add for brightnessenable
PRODUCT_PACKAGES += \
brightnessenable \
brightnessenable.rc
SElinux 的配置
可以根据kernel log 提示的错误,一步步百度解决
- 1.file_contexts配置system/sepolicy/private/
/system/bin/brightnessenable u:object_r:brightnessenable_exec:s0 - 2.domin 进程配置
device/xxx/sepolicy/private/brightnessenable.te
init_daemon_domain(brightnessenable)
- 3.type 配置,其他权限配置
device/xxx/sepolicy/public/brightnessenable.te
type brightnessenable , domain,coredomain;
type brightnessenable_exec, exec_type, file_type,vendor_file_type;
//权限配置
allow hwservicemanager brightnessenable:dir search;
allow hwservicemanager brightnessenable:file {read open};
allow hwservicemanager brightnessenable:process {getattr};
allow brightnessenable hwservicemanager:binder {call transfer};
allow hwservicemanager brightnessenable:binder {transfer};
allow brightnessenable hwservicemanager_prop:file {getattr open read};
set_prop(brightnessenable, system_prop)
权限配置说明:允许主体 brightnessenable
对客体 hwservicemanager
的file 行使
{read open}
权限
- 4.vendor 下自定义配置
vendor/xxx/sepolicy/brightnessenable.te
binder_call(hal_automotive_vehicle_ts, brightnessenable);
allow brightnessenable hal_automotive_vehicle_ts:binder { transfer call };
allow brightnessenable hal_automotive_vehicle_hwservice:hwservice_manager find;