前言
当前功能主要适用于多lvds屏幕的android系统使用,当前我使用的是rk3288 android7.1.2系统,做这个功能主要是公司使用的lvds屏幕比较多,各个项目之间对系统的改动并不是很大,大部分都是换一个屏幕,为了不用制作多余系统,所以开发此功能
概述
当前lvds屏幕动态切换主要是通过U盘来实现,首先系统正常启动后,插入U盘,系统添加服务读取U盘中关于屏幕参数的标志,将标志数据写入misc分区指定位置,完成后拔出U盘,重启系统,系统重新启动后,在uboot中读取屏幕标志,获取标志后查找设备树关于lvds屏幕配置节点,修改指定节点完成新屏幕的适配工作,等待内核启动后,会从设备树中加载新的屏幕参数。
一、添加U盘读取服务
1、服务实现
system/core/lcdservice/lcdservice.c
/* monitor the /mnt/external_sd/rk_lcd_parameters. */
/* if the parameters has been changed, and then update the lcdparamers. */
/* the parameters will work after reboot. */
/* [email protected] */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LOG_TAG "LcdParamService"
typedef unsigned short uint16;
typedef unsigned long uint32;
typedef unsigned char uint8;
#define LCD_PARAMETE_FILE_PATH "busybox find /mnt/media_rw/ -name rk_lcd_screen"
#define MISC_PARTITIOM_NODE_PATH "/dev/block/platform/ff0f0000.dwmmc/by-name/misc"
/*#define MISC_PARTITIOM_NODE_PATH "data/oem"*/
/*#define RKNAND_GET_VENDOR_SECTOR0 _IOW('v', 16, unsigned int)*/
/*#define RKNAND_STORE_VENDOR_SECTOR0 _IOW('v', 17, unsigned int)*/
#define RKNAND_SYS_STORGAE_DATA_LEN 4096 //oem size
/*#define VENDOR_SECTOR_OP_TAG 0x444E4556 // "VEND"*/
#define POLY 0xEDB88320L //CRC stand
#define CONFIG_NUM 26
static char misc_lvds[100] = {0};
static char primary[100] = {0};
static char extend[100] = {0};
static char hwrotation[100] = {0};
char *strreplace(char *s, char old, char new)
{
for (; *s; ++s)
if (*s == old)
*s = new;
return s;
}
/*
*去除字符串左端空格
*/
char *strtriml(char *pstr)
{
int i = 0,j;
j = strlen(pstr) - 1;
while (isspace(pstr[i]) && (i <= j))
i++;
if (0= 0))
pstr[i--] = '\0';
return pstr;
}
/*
*去除字符串两端空格
*/
char *strtrim(char *pstr)
{
char *p;
p = strtrimr(pstr);
return strtriml(p);
}
char *strdelchr(char *pstr, int chr)
{
int i = 0;
int l = 0;
int ll = 0;
ll = l = strlen(pstr);
while(i < l)
{
if(pstr[i] == chr)
{
memmove((pstr + i), (pstr + i + 1), (ll - i -1));
pstr[ll - 1] = '\0';
ll--;
}
i++;
}
/* for(i = 0; i < l; i++) */
/* { */
/* if(pstr[i] == chr) */
/* { */
/* memmove((pstr + i), (pstr + i + 1), (l - i -1)); */
/* pstr[l - 1] = '\0'; */
/* break; */
/* } */
/* } */
return pstr;
}
void strrmspace(char * str)
{
char *p1, *p2;
char ch;
p1 = str; //first pointer
p2 = str; // second pointer to the remaining string
if (p1==NULL) return;
while (*p1)
{
if (*p1 != ' ')
{
ch = *p1;
*p2 = ch;
p1++;
p2++;
}
else
{
p1++;
}
}
*p2 = '\0';
}
char *get_misc_data(char *misc_buf, int length,int offset)
{
if (misc_buf == NULL || length <= 0)
{
return NULL;
}
int ret = -1;
int sys_fd = -1;
char *p = NULL;
if (0 != access(MISC_PARTITIOM_NODE_PATH, R_OK | W_OK)){
ALOGE("access fail!!!\n");
return -1;
}
sys_fd = open(MISC_PARTITIOM_NODE_PATH, O_RDONLY);
if (sys_fd < 0)
{
ALOGE("fopen err %s err=%d\n",MISC_PARTITIOM_NODE_PATH, sys_fd);
return -1;
}
ret = lseek(sys_fd,offset,SEEK_SET);
ret = read(sys_fd,misc_buf, length);
if (ret < 0)
{
ALOGE("read err %s err=%d\n",MISC_PARTITIOM_NODE_PATH, sys_fd);
return NULL;
}
p = strstr(misc_buf, "--wipe");
if(p == NULL)
return NULL;
*p = 0;
return misc_buf;
}
char * set_misc_data(char *lvds_buf, int length, int offset)
{
if (lvds_buf == NULL || length <= 0)
{
return NULL;
}
char misc_buf[100] = {0};
int ret = -1;
strcpy(misc_buf, lvds_buf);
strcat(misc_buf, "--wipe");
if (0 != access(MISC_PARTITIOM_NODE_PATH, R_OK | W_OK)){
ALOGE("access fail!!!\n");
return NULL;
}
int sys_fd = open(MISC_PARTITIOM_NODE_PATH, O_RDWR);
if (sys_fd < 0)
{
ALOGE("fopen err %s err=%d\n",MISC_PARTITIOM_NODE_PATH, sys_fd);
return NULL;
}
ret = lseek(sys_fd,offset,SEEK_SET);
ret = write(sys_fd, misc_buf, length);
if (ret < 0)
{
ALOGE("read err %s err=%d\n",MISC_PARTITIOM_NODE_PATH, sys_fd);
return NULL;
}
return lvds_buf;
}
char *get_file_path(char *path, int path_len)
{
char lcdparameter_buf[100] = {0};
FILE *stream = popen(LCD_PARAMETE_FILE_PATH, "r");
int ret = -1;
if (stream == NULL) {
return NULL;
}
ret = fread( lcdparameter_buf, sizeof(char), sizeof(lcdparameter_buf), stream);
if(ret < 0)
return NULL;
strreplace(lcdparameter_buf,'\n','\0');
pclose(stream);
memset(path, 0, path_len);
strcpy(path,lcdparameter_buf);
return path;
}
int update_misc_data(char *property, int offset)
{
char lcdparameter_buf[100] = {0};
char buf[100] = {0};
char file_property[100] = {0};
char *p = NULL;
int ret = -1;
FILE *fp = NULL;
char *path = NULL;
path = get_file_path(lcdparameter_buf, sizeof(lcdparameter_buf));
if(path == NULL) {
return -1;
}
fp = fopen(lcdparameter_buf, "r");
if(fp == NULL)
{
ALOGE("open file error : lcdparameter_buf %s \n",lcdparameter_buf);
return -1;
}
memset(file_property,0,sizeof(file_property));
while (fgets(buf,sizeof(buf),fp)) {
if((strlen(buf) !=0) && (strstr(buf,"#") == NULL)) {
if (strstr(buf,property)) {
strreplace(buf,'\r','\0');
strreplace(buf,'\n','\0');
memcpy(file_property,buf,sizeof(buf));
break;
}
}
}
ALOGD("file hwrotation = %s -- %d \n",file_property, __LINE__);
if(strcmp(property,"hwrotation") == 0) {
if (strcmp(hwrotation, file_property)!= 0) {
ret = set_misc_data(file_property, sizeof(file_property), offset);
if (ret == -1) {
ALOGE("update misc hwrotation failed\r\n");
return -1;
}
strcpy(hwrotation, file_property);
}
} else if (strcmp(property,"primary") == 0) {
if (strcmp(primary, file_property) != 0) {
ret = set_misc_data(file_property, sizeof(file_property), offset);
if (ret == -1) {
ALOGE("update misc hwrotation failed\r\n");
return -1;
}
strcpy(primary, file_property);
}
} else if (strcmp(property,"extend") == 0) {
if (strcmp(extend, file_property) != 0) {
ret = set_misc_data(file_property, sizeof(file_property), offset);
if (ret == -1) {
ALOGE("update misc hwrotation failed\r\n");
return -1;
}
strcpy(extend, file_property);
}
} else if (strcmp(property, "lvds_parameter") == 0) {
if (strcmp(misc_lvds, file_property) != 0) {
ret = set_misc_data(file_property, sizeof(file_property), offset);
if (ret == -1) {
ALOGE("update misc hwrotation failed\r\n");
return -1;
}
strcpy(misc_lvds, file_property);
sync();
reboot(RB_AUTOBOOT);
}
} else {
return -1;
}
return 0;
}
int update_system_property(char *property)
{
if(property == NULL) {
return -1;
}
char buf[100] = {0};
char sys_property[100] = {0};
char cmd[100] = {0};
char *p = NULL;
FILE *fp = NULL;
char get_property[100] = {0};
char set_property[100] = {0};
if ((strlen(hwrotation) ==0 ) || (strlen(primary) == 0) || (strlen(extend) == 0) || (strlen(misc_lvds) == 0)) {
if (strcmp(property,"hwrotation") == 0) {
get_misc_data(hwrotation, sizeof(hwrotation), 1536);
ALOGE("hwrotation = %s\n", hwrotation);
} else if (strcmp(property,"primary") == 0) {
get_misc_data(primary, sizeof(primary), 2048);
ALOGE("primary = %s\n", primary);
} else if (strcmp(property,"extend") == 0) {
get_misc_data(extend, sizeof(extend), 2560);
ALOGE("extend = %s\n", extend);
} else if (strcmp(property,"lvds_parameter") == 0) {
get_misc_data(misc_lvds, sizeof(misc_lvds), 1024);
ALOGE("misc_lvds = %s\n", misc_lvds);
}
}
if (strcmp(property,"primary") == 0) {
strcpy(get_property, "getprop persist.hwc.device.primary");
strcpy(buf,primary);
strcpy(set_property, "setprop persist.hwc.device.primary");
} else if (strcmp(property,"extend") == 0) {
strcpy(get_property, "getprop persist.hwc.device.extend");
strcpy(buf,extend);
strcpy(set_property, "setprop persist.hwc.device.extend");
} else if (strcmp(property,"hwrotation") == 0) {
strcpy(get_property, "getprop persist.sf.hwrotation");
strcpy(buf,hwrotation);
strcpy(set_property, "setprop persist.sf.hwrotation");
} else {
return -1;
}
p = strstr(buf, "=");
if (p == NULL)
return -1;
fp = popen(get_property,"r");
if (fp == NULL)
{
ALOGE("getprop file open error !\n");
return -1;
}
fread(sys_property, sizeof(char), sizeof(sys_property), fp);
strreplace(sys_property,'\r','\0');
strreplace(sys_property,'\n','\0');
pclose(fp);
if (strcmp(sys_property, p+1) != 0) {
sprintf(cmd,"%s %s", set_property, p+1);
ALOGD(" cmd = %s\n",cmd);
system(cmd);
} else {
return -1;
}
return 0;
}
int main(void)
{
ALOGE("V5 TEST\n");
get_misc_data(hwrotation, sizeof(hwrotation), 1536);
ALOGE("hwrotation = %s\n", hwrotation);
get_misc_data(primary, sizeof(primary), 2048);
ALOGE("primary = %s\n", primary);
get_misc_data(extend, sizeof(extend), 2560);
ALOGE("extend = %s\n", extend);
get_misc_data(misc_lvds, sizeof(misc_lvds), 1024);
ALOGE("misc_lvds = %s\n", misc_lvds);
while(1)
{
update_misc_data("hwrotation", 1536);
update_system_property("hwrotation");
update_misc_data("primary", 2048);
update_system_property("primary");
update_misc_data("extend", 2560);
update_system_property("extend");
update_misc_data("lvds_parameter", 1024);
usleep(1000000);
}
return 0;
}
该服务主要实现读取U盘中rk_lcd_screen文件,并将屏幕标志写入misc分区指定位置,同时还实现修改屏幕默认显示方向和主副显示屏幕设置。
2、添加服务编译
system/core/lcdservice/Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_SRC_FILES:= \
lcdservice.c
LOCAL_C_INCLUDES += bionic \
$(call include-path-for, libhardware_legacy)/hardware_legacy
LOCAL_MODULE:=lcdservice
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libfs_mgr libcutils libc liblog
LOCAL_SHARED_LIBRARIES := libhardware_legacy libnetutils liblog
include $(BUILD_EXECUTABLE)
device/rockchip/rk3288/device.mk
Lightning \
- SoundRecorder
+ SoundRecorder \
+ lcdparamservice
3、添加系统服务
device/rockchip/common/init.rk30board.rc
+service lcdservice /system/bin/lcdservice
+ class main
android服务添加需要对服务的SELinux权限做处理,具体操作可参考其他人写的android服务SELinux权限处理文档。