文章目录

  • 硬件环境
  • 零、原理讲解
  • 一、内核修改
    • 1.1 头文件
    • 1.2 驱动
    • 1.3 赋予对应节点可读属性
  • 二、增加设置
    • 2.1 增加对应设置的入口
    • 2.2 增加对应选项列表
    • 2.3 增加功能代码
    • 2.4 增加对功能代码的调用
  • 三、增加对属性读取
  • 四、调试

硬件环境

soc:rk3568

android版本:11.0

零、原理讲解

1. 在rk的芯片中,有一块vendor_storage,其中内容掉电保存,用于厂商保存出厂设置,可以通过工厂烧写进去,也可以通过编程修改。

2. ro.sf.lcd_density这个属性可以修改屏幕密度,在每次安卓系统启动之前设置它,在启动的时候就会读取它,进行对属性的修改

3. 程序的逻辑流程如下

系统设置中修改density->保存到vendor_storage中对应节点->重启后读取对应节点内容->设置系统属性->启动->完成密度修改

一、内核修改

1.1 头文件

include/linux/soc/rockchip/rk_vendor_storage.h

增加一个ID DENSITY_ID对应density的属性保存

/** Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or (at* your option) any later version.*/#ifndef __PLAT_RK_VENDOR_STORAGE_H
#define __PLAT_RK_VENDOR_STORAGE_H#define RSV_ID                0
#define SN_ID               1
#define WIFI_MAC_ID         2
#define LAN_MAC_ID          3
#define BT_MAC_ID           4
#define HDCP_14_HDMI_ID         5
#define HDCP_14_DP_ID           6
#define HDCP_2X_ID          7
#define DRM_KEY_ID          8
#define PLAYREADY_CERT_ID       9
#define ATTENTION_KEY_ID        10
#define PLAYREADY_ROOT_KEY_0_ID     11
#define PLAYREADY_ROOT_KEY_1_ID     12
#define SENSOR_CALIBRATION_ID       13
#define IMEI_ID             15
#define LAN_RGMII_DL_ID         16
#define EINK_VCOM_ID            17/* 增加的ID */
#define ORIENTATION_ID 50
#define DENSITY_ID     51int rk_vendor_read(u32 id, void *pbuf, u32 size);
int rk_vendor_write(u32 id, void *pbuf, u32 size);
int rk_vendor_register(void *read, void *write);
bool is_rk_vendor_ready(void);#endif

1.2 驱动

driver/soc/rockchip/storage_vendor.c

增加对id的过滤,对density节点的创建

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/soc/rockchip/rk_vendor_storage.h>
#include <linux/string.h>#define VENDOR_GET_MAX 32 /* 定义数据大小 */struct storage_data {char orientation[VENDOR_GET_MAX];char density[VENDOR_GET_MAX];struct kobject *s_kobj;
};static struct storage_data *gdata = NULL;struct storage_attribute {struct attribute    attr;ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,char *buf);ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n);
};static int read_storage(struct storage_data *sData, int id);
static int write_storage(struct storage_data *sData, int id, const char *buff);static ssize_t orientation_storage_show(struct kobject *kobj, struct kobj_attribute *attr,char *buf)
{if(gdata == NULL){return -1;}if(read_storage(gdata, ORIENTATION_ID) > 0){return sprintf(buf, "%s\n", gdata->orientation);} else {return sprintf(buf, "%s\n","null");}
}static ssize_t orientation_storage_write(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n)
{int ret = -1;if(gdata==NULL){return -1;}ret = write_storage(gdata, ORIENTATION_ID, buf);if(ret!=0){return ret;}return n;
}static ssize_t density_storage_show(struct kobject *kobj, struct kobj_attribute *attr,char *buf)
{if(gdata==NULL){return -1;}if(read_storage(gdata, DENSITY_ID) > 0){return sprintf(buf, "%s\n", gdata->density);} else {return sprintf(buf, "%s\n","null");}
}static ssize_t density_storage_write(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t n)
{int ret = -1;if(gdata==NULL){return -1;}ret = write_storage(gdata, DENSITY_ID, buf);if(ret!=0){return ret;}return n;
} static struct storage_attribute storage_data_attribute[] = {/*     node_name    permision       show_func   store_func */__ATTR(orientation,     S_IRUGO | S_IWUSR,     orientation_storage_show,    orientation_storage_write),__ATTR(density,          S_IRUGO | S_IWUSR,     density_storage_show,    density_storage_write),
};/* 读取vendorstorage分区数据 */
static int read_storage(struct storage_data *sData, int id)
{char str[VENDOR_GET_MAX] = {0};int ret = -1;memset(str, 0, VENDOR_GET_MAX);ret = rk_vendor_read(id, str, (VENDOR_GET_MAX-1));if (ret > 0) {switch (id){case ORIENTATION_ID:strcpy(sData->orientation, str);if(strlen(sData->orientation) <= 0 ){strcpy(sData->orientation, "null");}break;case DENSITY_ID:strcpy(sData->density, str);if(strlen(sData->density) <= 0 ){strcpy(sData->density, "null");}break;default:goto set_null;}}else {goto set_null;}return ret;set_null:switch (id){case ORIENTATION_ID:strcpy(sData->orientation, "null");break;case DENSITY_ID:strcpy(sData->density, "null");break;default:break;}return ret;
}/* 向vendorstorage分区写入数据 */
static int write_storage(struct storage_data *sData, int id, const char *buff)
{char str[VENDOR_GET_MAX];int ret = -1;memset(str, 0, VENDOR_GET_MAX);strcpy(str, buff);ret = rk_vendor_write(id, str, (VENDOR_GET_MAX-1));if (ret == 0) {printk("%s: Data storage succeeded: %s\n",__func__,str);} else {printk("%s: Data storage failure: %s\n",__func__,str);}return ret;
}static int storage_probe(struct platform_device *pdev)
{struct storage_data *sData;int ret = -1;sData = kzalloc(sizeof(struct storage_data), GFP_KERNEL);if (!sData)return -ENOMEM;/* /sys下创建storage目录读写接口 */sData->s_kobj = kobject_create_and_add("storage", NULL);if (!sData->s_kobj)return -1;/* storage目录下创建读写接口 */ret = sysfs_create_file(sData->s_kobj, &storage_data_attribute[0].attr);if (ret != 0) {printk("%s: create sysfs_create_file error\n",__func__);return ret;}ret = sysfs_create_file(sData->s_kobj, &storage_data_attribute[1].attr);if (ret != 0) {printk("%s: create sysfs_create_file error\n",__func__);return ret;}gdata = sData;platform_set_drvdata(pdev,sData);return 0;
}static int storage_remove(struct platform_device *pdev)
{struct storage_data *sData = platform_get_drvdata(pdev);kfree(sData);return 0;
}#ifdef CONFIG_OF
static struct of_device_id storage_of_match[] = {{ .compatible = "storage-vendor" },
};
MODULE_DEVICE_TABLE(of, storage_of_match);
#endifstatic struct platform_driver storage_driver = {.probe       = storage_probe,.remove        = storage_remove,.driver       = {.name   = "storage_vendor",.owner    = THIS_MODULE,
#ifdef CONFIG_OF.of_match_table = of_match_ptr(storage_of_match),
#endif},
};static int __init storage_vendor_init(void)
{return platform_driver_register(&storage_driver);
}static void __exit storage_vendor_exit(void)
{platform_driver_unregister(&storage_driver);
}late_initcall(storage_vendor_init);
module_exit(storage_vendor_exit);MODULE_DESCRIPTION("storage vendor driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:storage vendor");

1.3 赋予对应节点可读属性

device/rockchip/common/init.rk30board.rc

chmod 0666 /sys/storage/density

二、增加设置

2.1 增加对应设置的入口

package/app/Settings/res/values/strings.xml

<!-- Density box option --><string name="screen_density">Screen Density Options</string><string name="screen_density_summary">160</string>

package/app/Settings/res/values-zh-rcN/strings.xml

<!-- Density box option --><string name="screen_density">屏幕密度设置</string><string name="screen_density_summary">160</string>

2.2 增加对应选项列表

package/app/Settings/res/values/arrays.xml

<!-- Screen rotate options --><string-array name="screen_density_entries"><item>120</item><item>160</item><item>200</item><item>240</item></string-array><string-array name="screen_density_values" translatable="false"><item>120</item><item>160</item><item>200</item><item>240</item></string-array>

2.3 增加功能代码

package/app/Settings/src/com/android/settings/display/ScreenDensityPreferenceController.java

package com.android.settings.display;import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.text.TextUtils;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;import androidx.annotation.VisibleForTesting;
import androidx.preference.ListPreference;
import androidx.preference.Preference;import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import android.content.Intent;import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import android.util.Log;
import java.io.File;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;public class ScreenDensityPreferenceController extends AbstractPreferenceController implementsPreferenceControllerMixin, Preference.OnPreferenceChangeListener {private static final String TAG = "ScreenDensity";private static final String KEY_SCREEN_DENSITY = "screen_density";private static final String STORAGE_PATH = "/sys/storage/density"; private static final String DENSITY_120  = "120";private static final String DENSITY_160  = "160";private static final String DENSITY_200  = "200";private static final String DENSITY_240  = "240";Context mContext;public ScreenDensityPreferenceController(Context context) {super(context);mContext = context;}@Overridepublic String getPreferenceKey() {return KEY_SCREEN_DENSITY;}@Overridepublic boolean isAvailable() {return true;}/* 获取分区保存的屏幕密度参数,并显示出来 */@Overridepublic void updateState(Preference preference) {ListPreference pref = (ListPreference) preference;/* 读取保存在分区的屏幕密度参数 */String density = ReadFile(STORAGE_PATH);switch(density){case "D120" :    density = DENSITY_120; break;case "D160" :   density = DENSITY_160;  break;case "D200" :  density = DENSITY_200; break;case "D240" :   density = DENSITY_240; break;default       :   density = DENSITY_160;     break;}/* 更新界面显示当前屏幕密度的参数 */pref.setSummary(density);pref.setValue(density);}/* 获取人工设置的屏幕密度参数,并保存到分区中*/@Overridepublic boolean onPreferenceChange(Preference preference, Object newValue) {ListPreference pref = (ListPreference) preference;int value = Integer.parseInt((String) newValue);String density = "0";/* value是界面选择的旋转参数,并转换为带R标志参数 */switch(value){case 120 :  density = "D120"; break;case 160 :   density = "D160";  break;case 200 :  density = "D200";  break;case 240 :  density = "D240";  break;default  :  density = "D160";     break;}/* 将设置的屏幕密度的参数写入分区中保存 */int ret = WriteFile(STORAGE_PATH, density);if(ret == 0){pref.setSummary((String) newValue);Log.d(TAG,"density = " + density);/* 弹出重启选项按键 */new AlertDialog.Builder(mContext).setTitle("设置重启后生效").setMessage("是否立刻重启").setCancelable(true).setPositiveButton("立刻重启", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {/* 数据写入成功后,自动重启系统使其生效 */Intent intent = new Intent(Intent.ACTION_REBOOT);intent.putExtra("nowait", 1);intent.putExtra("interval", 1);intent.putExtra("window", 0);mContext.sendBroadcast(intent);   }}).setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.cancel();}}).show();}return true;}/* 读取底层接口数据函数 */public String ReadFile(String filePath) { File file = new File(filePath);if((file != null) && file.exists()) {try {FileInputStream fs= new FileInputStream(file);BufferedReader reader= new BufferedReader(new InputStreamReader(fs));String density = reader.readLine();fs.close();Log.d(TAG, "===== read density:" + density + "======");return density;} catch(IOException e) {e.printStackTrace();}}return null;}/* 把数据写入底层接口函数 */public int WriteFile(String filePath, String density) {Log.d(TAG,"WriteFile, write density = " + density);File file = new File(filePath);if((file == null) || !file.exists()) {Log.e(TAG, "write error: " + filePath);return -1;}try {FileOutputStream fos = new FileOutputStream(file);PrintWriter pWriter = new PrintWriter(fos);pWriter.println(density);pWriter.flush();pWriter.close();fos.close();return 0;} catch(IOException ret) {Log.d(TAG,"write error:" + ret);return -1;}}
}

2.4 增加对功能代码的调用

package/app/Settings/src/com/android/settings/DisplaySettings.java

import com.android.settings.display.ScreenDensityPreferenceController;
....
controllers.add(new ScreenDensityPreferenceController(context));

三、增加对属性读取

system/core/init/init.cpp

在SecondStageMain()中增加以下内容

注意:如果在别的mk(比如device.mk、rk3568_r.mk等)文件中有对ro.sf.lcd_density属性的修改,请去除,否则会覆盖以下代码设置的属性

 std::string density;if (ReadFileToString("/sys/storage/density", &density)) { if(strstr(density.c_str(), "D120")){SetProperty("ro.sf.lcd_density", "120");} else if(strstr(density.c_str(), "D160")){SetProperty("ro.sf.lcd_density", "160");} else if(strstr(density.c_str(), "D200")){SetProperty("ro.sf.lcd_density", "200");} else if(strstr(density.c_str(), "D240")){SetProperty("ro.sf.lcd_density", "240");} else {SetProperty("ro.sf.lcd_density", "160");}LOG(ERROR) << "Density: open /sys/storage/density " << density;} else {LOG(ERROR) << "Prientation: Unable to open /sys/storage/density";SetProperty("ro.sf.lcd_density", "160");}

四、调试

教程不教人怎么调试就是害人

1.检查vendor_storage节点

cat /sys/storage/density

ls -l /sys/storage/density

2.检查系统属性

getprop |grep ro.sf.lcd_density

3.查看log

logcat -b all | grep density

Android11增加对dpi屏幕密度的设置相关推荐

  1. 屏幕显示密度dpi_华为mate7——修改 DPI 屏幕密度 !可使屏幕在视觉上变得更大...

    本帖最后由 丶浩南丶 于 2015-6-5 18:36 编辑 7eed1eeb1ec25a2f7c2eba32caac659a8147.jpg (99.56 KB, 下载次数: 106) 2015-6 ...

  2. 屏幕适配,彻底理解dp,dpi,屏幕密度,分辨率之间的爱恨纠葛

    android初学者都会对密度,分辨率,dp,dpi等等混淆,今天来好好捋一捋这剪不断理还乱的江湖关系! 废话不多说,直入主题. in:英寸inch,物理尺寸,1in =2.54厘米(cm).4.2寸 ...

  3. 图像相关——DPI、PPI、像素、屏幕密度等关系与解释

    今天查了一下有关图像分辨率,设备显示分辨率,以及其他的一些相关概念.之前一直没弄懂,在手机.电脑设备上的分辨率与摄影机上面的分辨率有什么不同,还有DPI.PPI又是什么.今天查了之后大概有了一些了解, ...

  4. 屏幕显示密度dpi_屏幕密度和DPI的对应关系

    基本概念铺垫 像素 像素(pixel)为图像的基本单位,是一个抽象的采样,在很多情况下,它们采用点或者方块显示.每个像素可有各自的颜色值,可以采用RGB表示.单位面积内的像素越多代表分辨率越高,所显示 ...

  5. 【Android 屏幕适配】屏幕适配基础概念 ③ ( 屏幕像素密度 DPI 与素材大小关联 | 屏幕像素密度 DPI 与 屏幕密度限定符关联 )

    文章目录 一.屏幕像素密度 DPI 与素材大小关联 二.屏幕像素密度 DPI 与 屏幕密度限定符 xhdpi 关联 参考文档 : 设备兼容性概览 屏幕兼容性概览 支持不同的像素密度 声明受限屏幕支持 ...

  6. Android屏幕密度的深刻理解

    context.getResources().getDisplayMetrics() Android中有一个类:DisplayMetrics,官方文档在此:https://developer.andr ...

  7. android笔记 看过stormzhang大大的博客(关于像素,屏幕密度)

    px像素 dpi单位内的像素数 dpi是Dots Per Inch的缩写, 每英寸点数,即每英寸包含像素个数.比如320X480分辨率的手机,宽2英寸,高3英寸,  每英寸包含的像素点的数量为320/ ...

  8. android 密度像素,Android屏幕密度适配问题之px,dp,sp等详细介绍

    一  ,android屏幕相关知识 屏幕大小:指屏幕对角线的长度,使用"寸"度量,如4.7寸手机 分 辨  率:分辨率指手机屏幕的像素点个数,如720*1280 指屏幕宽有720个 ...

  9. android 屏幕密度350 是xh xxh,Android-绘图机制总结

    这里你将了解到以下内容:Android屏幕相关知识 Android绘图技巧 Android图像处理技巧 SurfaceView的使用 1.屏幕尺寸信息 1.屏幕参数 一块屏幕通常具备以下的几个参数 屏 ...

最新文章

  1. Java生成固定长度的随机字符串(以大小写字母和数字)
  2. 【Linux网络编程】TCP三次握手和四次挥手
  3. 用iTunes管理iPhone
  4. 记录学习antd design pro dva的过程,主要记错, 多图预警,如有理解偏差,忘指出,多谢!...
  5. Linux 安装SNMPWALK工具
  6. 分享按钮-新浪微博开放平台
  7. Codeforces Round #322 A Vasya the Hipster
  8. 怎么画出好的架构图,架构师必备!
  9. android 辅助功能(无障碍)
  10. 微信小程序:setData 数据传输长度为 1678 KB,存在有性能问题!
  11. 2. web前端开发分享-css,js进阶篇
  12. html表格嵌套最外层属性无效,表格可以嵌套吗
  13. electron打包生成exe程序
  14. mysql外链删除_清理mysql外链的意思 和命令
  15. 亿信华辰讲述如何做好客商主数据管理
  16. 【转载】警情通报为啥一定是蓝底白字?
  17. 【Go】Goland下载与安装教程(详细)
  18. 【统计学】基本Stata使用手册(4):工具变量法
  19. 用千千静听修改mp3的属性
  20. 太极发送卡片软件_qn卡片版app下载-QN模块卡片版软件 v35_5577安卓网

热门文章

  1. CP2K+Gaussian+LAMMPS+ReaxFF计算材料化学系列四大专题。
  2. 博图V17弹窗源程序 釆用SCL自定义功能块,自定义数据类型
  3. 网站文章的类型有哪些?
  4. Java Web----EL(表达式语言)详解
  5. Mysql执行计划和Mysql优化
  6. 【微信】公众号自定义菜单类型
  7. Android 分区存储常见问题解答
  8. Oracle底子底细根基常识
  9. Aicon 3D Studio v3.6.00 1CD(专业的三维测量系统
  10. MySQL运行退出命令