android 守护进程创建

如何创建一个守护进程

  • 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;
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值