在自启动的.rc文件中添加服务

1:根据rc语法格式添加新增service:

service btwlansn /vendor/bin/btwlansn
    class main
    user root
    group root
    disabled
    oneshot

启动btwlansn服务

并加上点kernel日志

on property:sys.boot_completed=1
    start qcom-post-boot
    start qti-testscripts
    write /dev/kmsg "btwlansn starting"
    start btwlansn
    write /dev/kmsg "btwlansn started"

说明下如上:
class main 中 class 包括core main late_start等,可以不设置。默认default
user root 中 用户属性,默认root,一般给root即可,权限最大
group root 中 所属组,默认root
disabled 即通过class不能启动,只能start screencap 这种name的方式启动
oneshot只运行一次

服务启动

on property:sys.boot_completed=1
start btwlansn

2.添加对应的te文件,获取执行权限

#wifilearner daemon
/(vendor|system/vendor)/bin/btwlansn       u:object_r:vendor_shell_exec:s0

添加了服务的权限,使用的是现成的te文件,没有进行新建,vendor_shell.te在这个路径下:
/system/sepolicy/public/vendor_shell.te
我们查看下这个te文件给的权限:

type vendor_shell, domain;
type vendor_shell_exec, exec_type, vendor_file_type, file_type;

allow vendor_shell vendor_shell_exec:file rx_file_perms;
allow vendor_shell vendor_toolbox_exec:file rx_file_perms;

#Use fd from shell when vendor_shell is started from shell
allow vendor_shell shell:fd use;

#adbd: allow `adb shell /vendor/bin/sh` and `adb shell` then `/vendor/bin/sh`
allow vendor_shell adbd:fd use;
allow vendor_shell adbd:process sigchld;
allow vendor_shell adbd:unix_stream_socket {
    
     getattr ioctl read write };

allow vendor_shell devpts:chr_file rw_file_perms;
allow vendor_shell tty_device:chr_file rw_file_perms;
allow vendor_shell console_device:chr_file rw_file_perms;
allow vendor_shell input_device:dir r_dir_perms;
allow vendor_shell input_device:chr_file rw_file_perms;

vendor_shell这个te文件我是在哪里找到的呢?在这个路径下:
vendor/qcom/proprietary/FactoryAPP/FactoryInterface/sepolicy/ato_version/qcom/non_plat/file_contexts
cat一下,只保留了有用的信息:

/(vendor|system/vendor)/bin/ftmdaemon           u:object_r:vendor_shell_exec:s0

所以我直接用了这个,参照ftmdaemon来的,当然其他路径下的te也是可以的,只要权限满足你的要求。
测试时先关闭SELinux

adb root
adb shell setenforce 0

我们进入dev/kmsg查看一下日志,如果发现类似的日志,就表明有异常:

type=1400 audit(1511821362.996:9): avc: denied { search } for pid=540 comm=“init” name=“nfc” dev=“sda45” ino=1310721 scontext=u:r:vendor_init:s0 tcontext=u:object_r:nfc_data_file:s0 tclass=dir permissive=0

解释一下添加规则:

  1. scontext=u:r:vendor_init 表示目标te文件是 vendor_init.te
  2. tcontext=u:object_r:nfc_data_file 表示是哪个进程需要。这样说明是 nfc_data_file 需要
  3. tclass=dir 表示操作种类。这里表示 dir
  4. avc: denied { search } 表示缺失的权限 search

所以可以根据日志来添加权限

3.将新添加的服务加入到我们编译的img里

添加方法:
在vendor/qcom/proprietary / common/config/device-vendor.mk中添加如下语句:

PRODUCT_PACKAGES += $(MAC)
#MAC
MAC := btwlansn

同样的,还在vendor/qcom/proprietary / common/config/device-vendor-qssi.mk里加入相同的添加:

PRODUCT_PACKAGES += $(MAC)
#MAC
MAC := btwlansn

说了这么多,我们的服务在哪里呢?

4.编写服务,是一个cpp文件:

vendor/qcom/proprietary / btwlansn/btwlansn.cpp

#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include<android/log.h>

#define LOG_TAG "debug"
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)

#define CMD_LENGTH 		(128)
#define STR_LENGTH 		(16)
#define BT_MAC_LENGTH	 	(12)
#define WIFI_MAC_LENGTH         (12)
#define PCBA_SN_START 	0X00
#define WHOLE_SN_START 	0X20
#define BT_MAC_START 	0Xa0
#define WIFI_MAC_START 	0Xc0

#define CONFIG_FIILE_PATH 	"/mnt/vendor/persist/factory/customNv/CUSTOM_PRODUCT_INFO"
#define BT_MAC_PATH 		"/mnt/vendor/persist/bt_mac/bt_macaddress"
#define WIFI_MAC_PATH 		"/mnt/vendor/persist/qca6390/wlan_mac.bin"
int main()
{
    
    
	FILE* 	fp = NULL;
	char 	buf[STR_LENGTH + 1] = {
    
    0};
	char 	cmd_str[CMD_LENGTH] = {
    
    0};
	
	LOGI("====btwlansn entered===");

	fp = fopen(CONFIG_FIILE_PATH,"r");
	if(fp == NULL)
	{
    
    
		LOGI("file not exist error\n");
		return -1;
	}
	/* write WIFI MAC to the config file */
	system("mkdir /mnt/vendor/persist/qca6390/");
	fseek(fp,WIFI_MAC_START,SEEK_SET);
	memset(buf,0,STR_LENGTH + 1);
	fread(buf,1,WIFI_MAC_LENGTH,fp);
	printf("WiFi mac:%s\r\n",buf);
	memset(cmd_str,0,CMD_LENGTH);
	sprintf(cmd_str,"echo  'Intf0MacAddress=%s\nEND' > %s",buf,WIFI_MAC_PATH);
	system(cmd_str);
	system("rmmod wlan");
	system("insmod /vendor/lib/modules/qca_cld3_qca6390.ko");
//	system("svc wifi disable");
// system("svc wifi enable");

	/* write BT MAC to the config file and setprop to the system */
	fseek(fp,BT_MAC_START,SEEK_SET);
	memset(buf,0,STR_LENGTH + 1);
	fread(buf,1,BT_MAC_LENGTH,fp);
	system("mkdir /mnt/vendor/persist/bt_mac");
	memset(cmd_str,0,CMD_LENGTH);
	sprintf(cmd_str,"echo %c%c:%c%c:%c%c:%c%c:%c%c:%c%c > %s",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10],buf[11],BT_MAC_PATH);
	printf("Bt mac:%s\r\n",cmd_str);
	system(cmd_str);
	system("chmod 777 /mnt/vendor/persist/bt_macaddress");
	memset(cmd_str,0,CMD_LENGTH);
	sprintf(cmd_str,"setprop ro.vendor.bt.bdaddr_path %s",BT_MAC_PATH);
	system(cmd_str);
	system("svc bluetooth disable");
	system("svc bluetooth enable");

	return 0;
}

如上是将指定CUSTOM_PRODUCT_INFO文件中的信息读取到另外一个规定的或者自己创建的文件中。
解释一下两个函数:

  1. int fseek(FILE *stream, long int offset, int whence) 设置流 stream
    的文件位置为给定的偏移 offset,参数 offset 意味着从给定的 whence 位置查找的字节数。

    • stream – 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
    • offset – 这是相对 whence 的偏移量,以字节为单位。
    • whence – 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一

    SEEK_SET文件的开头 SEEK_CUR 文件指针的当前位置 SEEK_END 文件的末尾

  2. size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
    从给定流 stream 读取数据到 ptr 所指向的数组中。

ptr – 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
size – 这是要读取的每个元素的大小,以字节为单位。
nmemb – 这是元素的个数,每个元素的大小为 size 字节。
stream – 这是指向 FILE 对象的指针,该 FILE对象指定了一个输入流。

说明几个define的由来:

  • #define CONFIG_FIILE_PATH “/mnt/vendor/persist/factory/customNv/CUSTOM_PRODUCT_INFO”
    这个是固定的信息及地址,在安卓系统起来后,会将几个信息读取到这个文本里,这些信息里包括wifi mac和bt mac等。
  • #define WIFI_MAC_PATH “/mnt/vendor/persist/qca6390/wlan_mac.bin” 在vendor/qcom/opensource/wlan/qcacld-3.0/Android.mk这个路径下有将out目录下的bin文件拷到指定目录下:
$(shell mkdir -p $(TARGET_FW_PATH); ln -sf $(TARGET_MAC_BIN_PATH)/wlan_mac.bin $(TARGET_FW_PATH)/wlan_mac.bin)

TARGET_MAC_BIN_PATH := /mnt/vendor/persist
TARGET_FW_PATH:/out/target/product/kona/vendor/firmware/wlan/qca_cld/qca6390$
注意:虽然上面代码存在bt的,但是写bt mac代码就不进行解释了

5.在同路径下编写Andriod.mk文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := btwlansn
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := btwlansn.cpp
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_EXECUTABLES)
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
include $(BUILD_EXECUTABLE)

解释一下:也是引用网上的介绍

LOCAL_PATH := $(call my-dir)

一个 Android.mk文件的开头必须从定义这个变量开始,这个变量用于在开发过程中定位 Android.mk文件在项目中的路径;my-dir是一个宏函数,由系统提供,调用这个函数会返回当前文件所在目录的路径

include $(CLEAR_VARS)

这个 CLEAR_VARS变量是系统提供的,它指向一个特殊的 GNU Makefile文件,它会清除很多 LOCAL_XXX的变量(如:LOCAL_MODULE、LOCAL_SRC_FILES、LOCAL_STATIC_LIBRARIES等);为什么要清除?因为很多的控制文件都是在单个 GUN make中生成的,这些变量都是GUN make中的全局变量,如果不清除,上一次构建的数据信息会影响下一次的构建

LOCAL_MODULE := btwlansn

该命令用于为每一个模块定义其名称,这个名称必须是唯一且不包含空格;在构建过程中,系统会自动为模块加上前缀,如:btwlansn 生成的模块为 libbtwlansn.so
PS:如果模块名为libbtwlansn,那么生成的模块还是 libbtwlansn.so

LOCAL_SRC_FILES := btwlansn.cpp

该命令用于列举编译模块需要的 C/C++源文件,同时不要列举头文件和包含文件,因为系统在构建的过程中自动计算这些文件的依赖,我们只需要列举出正确的C/C++源文件就行

include $(BUILD_EXECUTABLE)

BUILD_EXECUTABLE是系统的提供的一个变量,它指向 GUN Makefile的一个脚本,这个脚本会收集你定义的所有 LOCAL_XXX形式的变量,然后根据这些变量构建 .so动态库。其他的变量还有:BUILD_EXECUTABLE(构建静态库)

猜你喜欢

转载自blog.csdn.net/weixin_42271802/article/details/113889564