AndroidQ(10.0) MTK 开机 Logo 动态替换

1,127 阅读11分钟

前言

之前写过一篇关于androidO版本的开机logo切换地表最强之Android开机Logo动态替换,

最近正好在研究 NVRAM 相关的东西,那就稍带手加一下这个功能。

开始以为照着之前 O 的修改来就行,没想到 Q 版本相关部分改动还挺大,前前后后折腾了快半个月才搞定。

开机Logo加载原理

1、u-boot logo显示原理

Little Kernel 会在 platform_early_init 阶段首先会获取 lcm params,其工作流程就是透过读id找到现在插入的LCM,

根据 LCM 的分辨率申请相应大小的 frame buffer并确定 frame buffer 起始地址,接着为 logo.bin 预留4M Ram

之后在 platform_init 阶段,直接将 logo.bin 载入到 4M Ram 中

完成载入后,在 platform_init 中 mt_disp_show_boot_logo() 会调用show_logo(0);完成第一张logo显示。

其中的index=0代表在 logo.bin 中压缩的第一张图片,logo.bin 中的图片压缩顺序可以察看文件

vendor\mediatek\proprietary\bootable\bootloader\lk\dev\logo\rules.mk

2、kernel logo 显示原理

Kernel logo 的工作方式与 U-boot logo 不同,是透过init.rc中注册的,boot_logo_updater service 完成读取raw data文件,

进行绘画的,所以在 kernel logo 只是经过了 bmp 向 raw 的转换,在目录 vendor\mediatek\proprietary\bootable\bootloader\lk\dev\logo\ 下

通过 bmp_to_raw 工具将 bmp 转换为 raw 文件,之后透过脚本文件将 boot_logo 文件搬移到

out\target\product\xxx\obj\BOOTLOADER_OBJ\build-xxx\dev\logo\wxga下,打包到 logo.bin,download 到手机中

3、logo.bin生成过程

Y5Y6DU.png

注:图片来自

blog.csdn.net/u011784994/…

4、替换原理

U-boot logo,将不同分辨率的图片压缩至 logo.bin 中,在读取时根据不同的 NVflag 显示相应的图片即可

platform.c 中 lk_display_show_logo(void) 读取 NVflag 传递给 mt_logo.c 调用 void mt_disp_show_boot_logo(int logo_index)

Kernel logo,需要将不同分辨率的 boot_logo raw data文件生成出来并 copy 到手机中,boot_logo_updater根据不同的分辨率进行识别,

读取相应的logo文件。在 boot_logo_updater 识别部分对 NVflag 进行判断,进而调用不同的boot_logo。

charging_animation.cpp 中 void show_kernel_logo() 读取 NVflag

开机Logo制作

根据 device/mediateksample/xxx/ProjectConfig.mk 中 BOOT_LOGO= wxga 对应字段,找到

vendor\mediatek\proprietary\bootable\bootloader\lk\dev\logo\wxga 文件夹中对应的图片分辨率

在 PS 中新建同等分辨率,置入素材,最终保存为 bmp 格式即可。

动态替换实现

0、坑位集锦

坑一、读取 Nvram 节点 SELinux权限问题

把之前的 NVram 读写 demo 直接安装后,读取 PRODUCT_INFO 节点,出现如下的权限日志

2020-11-20 15:32:49.132 4259-4259/com.android.qrdc I/om.android.qrdc: type=1400 audit(0.0:6575): avc: denied { call } for scontext=u:r:untrusted_app:s0:c79,c256,c512,c768 tcontext=u:r:nvram_agent_binder:s0 tclass=binder permissive=1 app=com.android.qrdc
2020-11-20 15:25:31.730 380-380/? E/SELinux: avc:  denied  { find } for interface=vendor.mediatek.hardware.nvram::INvram sid=u:r:untrusted_app:s0:c124,c256,c512,c768 pid=6200 scontext=u:r:untrusted_app:s0:c124,c256,c512,c768 tcontext=u:object_r:nvram_agent_binder_hwservice:s0 tclass=hwservice_manager permissive=0

根据 log 找到 untrusted_app.te 和 nvram_agent_binder.te

device/mediatek/sepolicy/basic/non_plat/nvram_agent_binder.te

 #for nvram hidl client support
 allow nvram_agent_binder sysfs:file { read open };
 
+#cpe add
+allow nvram_agent_binder proc_cmdline:file { read open getattr };
+allow nvram_agent_binder sysfs_dt_firmware_android:dir { search };
+allow nvram_agent_binder sysfs_dt_firmware_android:file { read };
+
 # Allow to use HWBinder IPC
 hwbinder_use(nvram_agent_binder);

device/mediatek/sepolicy/basic/non_plat/untrusted_app.te

+#cpe add
+allow untrusted_app drivertest_device:chr_file { open read write ioctl  };
+allow untrusted_app nvram_agent_binder:binder { call  };
+allow untrusted_app nvram_agent_binder_hwservice:hwservice_manager { find  };
\ No newline at end of file

修改.te文件后,编译时报错,根据提示去除 app_neverallows.te 中的 neverallow 规则

system/sepolicy/private/app_neverallows.te

system/sepolicy/prebuilts/api/29.0/private/app_neverallows.te

 # Restrict *Binder access from apps to HAL domains. We can only do this on full
 # Treble devices where *Binder communications between apps and HALs are tightly
 # restricted.
-full_treble_only(`
-  neverallow all_untrusted_apps {
-    halserverdomain
-    -coredomain
-    -hal_cas_server
-    -hal_codec2_server
-    -hal_configstore_server
-    -hal_graphics_allocator_server
-    -hal_neuralnetworks_server
-    -hal_omx_server
-    -binder_in_vendor_violators # TODO(b/35870313): Remove once all violations are gone
-    -untrusted_app_visible_halserver_violators
-  }:binder { call transfer };
-')
+
 
# neverallow all_untrusted_apps {
#   hwservice_manager_type
#   -same_process_hwservice
#   -coredomain_hwservice
#   -hal_codec2_hwservice
#   -hal_configstore_ISurfaceFlingerConfigs
#   -hal_graphics_allocator_hwservice
#   -hal_omx_hwservice
#   -hal_cas_hwservice
#   -hal_neuralnetworks_hwservice
#   -untrusted_app_visible_hwservice_violators
# }:hwservice_manager find;

坑二、nvram lid 无法成功写入

呃,这下能正常读取数据了,写入又不行,在这卡了好几天,后来在FAQ上找到了相关的解释和修改方法。

new nvram partition

./external/libnvram_ext/libnvram.cpp: NVRAM_LOG("New NVRAM partition name is %s.\n", cMtdDevName); $ find -name "*.cpp" | xargs grep "write file error" ./external/libnvram/nvram_hidl/1.0/Nvram.cpp: NVRAM_LOG("write file error!\n"); ./external/libnvram/nvram_hidl/1.1/Nvram.cpp: NVRAM_LOG("write file error!\n"); ./external/libnvram/nvram_hidl/1.1/Nvram.cpp: NVRAM_LOG("write file error!\n"); ./external/libnvram/nvram_agent_binder/nvram_agent.cpp: NVRAM_LOG("write file error!\n"); ./external/libnvram/nvram_agent_binder/nvram_agent.cpp: NVRAM_LOG("write file error!\n"); ./external/libnvram/nvram_agent_binder/nvram_agent.cpp:

在上一篇android10.0(Q) Nvram 新增节点 中最后给出了解决方案

Dear Customer,

您好,

O版本 "/vendor/nvdata/APCFG/APRDEB/PRODUCT_INFO",没有写权限

==>请问贵司是否在normal boot下写product info? 如果是的话,product info会被EMMC写保护挡下。

另外powner on write protection的设置位置在这里:

/vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6763/write_protect.c if (!bypass_wp) { ret = set_write_protect(); //可以注释掉关闭写保护这行做测试试试, 直接注释掉这行只给测试版本验证用

将其注释后重新编译烧写这次能成功写入 nvram 了。

坑三、Kernel logo 模块引入 Nvram 编译报错

kernel logo 显示在 vendor/mediatek/proprietary/external/libshowlogo/ 中绘制,

在 Android.mk 中加入 libnvram 相关库后,编译报错如下

vendor/mediatek/proprietary/external/libshowlogo/Android.mk: error: libshowlogo (native:platform) should not link to libnvram (native:vendor)

vendor/mediatek/proprietary/external/libshowlogo/Android.mk: error: libshowlogo (native:platform) should not link to libcustom_nvram (native:vendor)

这是由于 VNDK 的编译限制,为了降低 vendor 和 platform 的耦合度,从 P 版本开始将 vendor 和 system 目录下的 lib 分开了,互相不能直接访问

具体可查看

(native:platform) should not link to libxxx (native:vendor)

Android P vendor三方模块dlopen failed: library "libstdc++.so" not found, 失败问题分析

按照文章里说的方法尝试后发现没有用,依旧报错,后来在源码下搜索最终修改如下文件可行

build/make/core/binary.mk

my_allowed_types := native:recovery native:platform native:platform_vndk $(my_al
 else
 my_link_type := native:platform
 my_warn_types := $(my_warn_ndk_types)
-my_allowed_types := $(my_allowed_ndk_types) native:platform native:platform_vndk
+my_allowed_types := native:vendor $(my_allowed_ndk_types) native:platform native:platform_vndk
 endif

坑四、LK 阶段读取新增 Nvram LID 不成功

之前 O 版本都是直接在 AP_CFG_REEB_PRODUCT_INFO_LID 中读写,这次本想着新增一个 LID 专门用于存储 logo 的 index 值

开始在 java 中读写保存都 ok, 在 libshowlogo 中读取也是 ok 的,也能读取到正确的值,但在 lk 阶段一直没找到合适的方法

去读取新增的 AP_CFG_CUSTOM_FILE_LOGO_INDEX_LID。最终兜兜转转还是读写 AP_CFG_REEB_PRODUCT_INFO_LID 算了,具体原因

没去深究,lk 部分的代码改起来太麻烦,log 必须要接串口才能看。

1、java 层读写 NVram

java 层主要通过 INvram 接口来读写,对应的需要导入静态库,

LOCAL_STATIC_JAVA_LIBRARIES += vendor.mediatek.hardware.nvram-V1.0-java

显然在AS 中是编译不过的,所以只能放到源码环境通过配置 Android.mk 的方式编译。

测试用 Android.mk 文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#引入静态库读写nvram
LOCAL_STATIC_JAVA_LIBRARIES += vendor.mediatek.hardware.nvram-V1.0-java
LOCAL_MODULE_TAGS :=  optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := NvramDemo
LOCAL_PRIVATE_PLATFORM_APIS := true
include $(BUILD_PACKAGE)

测试用 NVActivity 代码如下

package com.android.qrdc;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.text.TextUtils;

import java.util.ArrayList;
import java.util.Arrays;

import vendor.mediatek.hardware.nvram.V1_0.INvram;
import com.android.internal.util.HexDump;

public class NVActivity extends Activity {

    private static final String SU = "/data/local/tmp/su";
    private static final String TAG = "NVActivity";
    private TextView tv_result;
    private EditText cmdEt,regEt,idPath;

    private static int ADDRESS_OFFSET = 0;

    private static void log(String msg) {
        Log.e("NVActivity", msg);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.nv_layout);

        tv_result = findViewById(R.id.tv_result);
        cmdEt = findViewById(R.id.cmdEt);
        regEt = findViewById(R.id.regEt);
        idPath = findViewById(R.id.idPath);
    }

    public void readNv(View v) {
        log("readNv click");
        ADDRESS_OFFSET = Integer.parseInt(regEt.getText().toString());
        String newIdPath =  idPath.getText().toString();
        if (!TextUtils.isEmpty(newIdPath)) {
            PRODUCT_INFO_FILENAME = newIdPath;
        }
        tv_result.setText("read result"+ readData());
    }

    public void writeNv(View v) {
        String cmd = cmdEt.getText().toString();
        ADDRESS_OFFSET = Integer.parseInt(regEt.getText().toString());
        log("writeNv click -----" + cmd);
        String newIdPath =  idPath.getText().toString();
        if (!TextUtils.isEmpty(newIdPath)) {
            PRODUCT_INFO_FILENAME = newIdPath;
        }
        writeData(Integer.parseInt(cmd));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }


   //mediatek/proprietary/packages/apps/CdsInfo/src/com/mediatek/connectivity/CdsWifiInfoActivity.java:   
  // private static final String PRODUCT_INFO_FILENAME = "/mnt/vendor/nvdata/APCFG/APRDEB/WIFI";
   public static  String PRODUCT_INFO_FILENAME = "/mnt/vendor/nvdata/APCFG/APRDCL/LOGO_INDEX";
    private static  void writeData(int n) {
        byte[] write_buff = new byte[]{0, 0, 0, 0};
        byte[] by = getBytes(n);
        for (int i = 0; i < 4; i++) {
            write_buff[i] = by[i];
        }
        try {
            INvram agent = INvram.getService();
            if (agent != null) {
                ArrayList<Byte> dataArray = new ArrayList<>(4);
                for (byte b : write_buff) {
                    dataArray.add(new Byte(b));
                }
                int ret_1 = agent.writeFileByNamevec(PRODUCT_INFO_FILENAME, ADDRESS_OFFSET, dataArray);
                if (ret_1>0){
                    log("write success"+ ret_1);
                }else {
                    log("write failed"+ ret_1);
                }
            } else {
                Log.e(TAG, "writeData: agent null");
            }
        } catch (Exception e) {
            Log.e(TAG, "writeData exception:" + e.getLocalizedMessage());
            e.printStackTrace();
        }
    }

    private static  byte[] getBytes(int data) {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) (data & 0xff);
        bytes[1] = (byte) ((data & 0xff00) >> 8);
        bytes[2] = (byte) ((data & 0xff0000) >> 16);
        bytes[3] = (byte) ((data & 0xff000000) >> 24);
        return bytes;
    }

    public static  int readData() {
        int targets = 0;
        try {
            String buff = null;
            INvram agent = INvram.getService();
            Log.i(TAG, "readData from PRODUCT_INFO_FILENAME");
            if (agent != null) {
                buff = agent.readFileByName(PRODUCT_INFO_FILENAME, ADDRESS_OFFSET);//10
            }
            byte[] buffArr = HexDump.hexStringToByteArray(buff.substring(0, buff.length() - 1));
            targets = (buffArr[0] & 0xff) | ((buffArr[1] << 8) & 0xff00) | ((buffArr[2] << 24) >>> 8) | (buffArr[3] << 24);
            Log.i(TAG, "readData: buffArr=" + Arrays.toString(buffArr) + ", targets == " + targets);
        } catch (Exception e) {
            Log.e(TAG, "readData exception:" + e.getLocalizedMessage());
            e.printStackTrace();
        }
        return targets;
    }
}

布局文件 nv_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="20dp"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="top|center_horizontal"
        android:textSize="22sp"
        android:text="pwd  " />

    <EditText
        android:id="@+id/regEt"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:text="100" />

    <EditText
        android:id="@+id/idPath"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="/mnt/vendor/nvdata/APCFG/APRDCL/LOGO_INDEX" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/cmdEt"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="10" />

        <Button
            android:id="@+id/write"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:onClick="writeNv"
            android:text="writeNv" />

        <Button
            android:id="@+id/read"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:onClick="readNv"
            android:text="readNv" />
    </LinearLayout>

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="this is test text"/>
</LinearLayout>

修改代码清单

vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/rules.mk  
vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/update  
vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6765/load_image.c  
vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6765/mt_logo.c  
vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6765/platform.c  
vendor/mediatek/proprietary/external/libshowlogo/Android.mk  
vendor/mediatek/proprietary/external/libshowlogo/charging_animation.cpp  
vendor/mediatek/proprietary/external/libshowlogo/charging_animation.h  

2、native 层读取 NVram

kernel logo 绘制方法位于 charging_animation.cpp 中 void show_kernel_logo()

先在 Android.mk 中导入所需 nvram 库

vendor\mediatek\proprietary\external\libshowlogo\Android.mk

LOCAL_CFLAGS += -DMTK_LCM_PHYSICAL_ROTATION=\"$(MTK_LCM_PHYSICAL_ROTATION)\"
 
-LOCAL_SHARED_LIBRARIES := libcutils libutils libc libstdc++ libz libdl liblog libgui libui libbase
+# LOCAL_SHARED_LIBRARIES := libcutils libutils libc libstdc++ libz libdl liblog libgui libui libbase
+LOCAL_SHARED_LIBRARIES := libcutils libutils libc libstdc++ libz libdl liblog libgui libui libbase libnvram libcustom_nvram
 
 LOCAL_STATIC_LIBRARIES += libfs_mgr
 
@@ -61,6 +62,9 @@ LOCAL_C_INCLUDES += $(TOP)/frameworks/native/libs/nativewindow/include
 LOCAL_C_INCLUDES += system/core/fs_mgr/include
 LOCAL_C_INCLUDES += $(TOP)/vendor/mediatek/proprietary/external/libsysenv
 
+LOCAL_C_INCLUDES += \
+    $(MTK_PATH_SOURCE)/external/nvram/libnvram 
+
 LOCAL_MODULE := libshowlogo
 #LOCAL_PROPRIETARY_MODULE := true
 #LOCAL_MODULE_OWNER := mtk

在头文件 charging_animation.h 中增加读取 index 方法

vendor/mediatek/proprietary/external/libshowlogo/charging_animation.h

 // show logo function
 void anim_show_logo(int index);
+//cpe add
+int  nvram_read_index(void);
 
 #ifdef __cplusplu

charging_animation.c 中实现 nvram_read_index 方法并传值给 show_kernel_logo()

vendor/mediatek/proprietary/external/libshowlogo/charging_animation.cpp


 #include <fs_mgr.h>
 
+//cpe add
+#include "libnvram.h"
+#include "../../custom/common/cgen/inc/CFG_file_lid.h"
+ 
+#include "CFG_PRODUCT_INFO_File.h"
+#include "Custom_NvRam_LID.h"
+
 #include "charging_animation.h"
 //#include <sysenv_utils.h>

int anim_fb_init(void)
     }
 
     int rotation = getValue(MTK_LCM_PHYSICAL_ROTATION_PROP, "0");
	 //此处的角度关系到横竖屏显示是否花显示,根据自己情况修改 rotation
+    SLOGE("[libshowlogo: %s %d]rotation = %d\n",__FUNCTION__,__LINE__, rotation);
     if (MTK_LOG_ENABLE == 1) {
         SLOGD("[libshowlogo: %s %d]rotation = %d\n",__FUNCTION__,__LINE__, rotation);
     }
@@ -733,8 +741,8 @@ int anim_fb_init(void)
     } else if((2 == rotation) && (phical_screen.need180Adjust == 1)){//180
         phical_screen.rotation = 180;
     } else {
        phical_screen.rotation = 0;

     }

//cpe add
#define MAX_RETRY_COUNT 100
int nvram_read_index(void){
    int logo_index = kernel_logo_position;
    int read_nvram_ready_retry = 0;
    F_ID fid;
    int rec_size = 0;
    int rec_num = 0;
    int nvinfo_lid = AP_CFG_REEB_PRODUCT_INFO_LID;
    // int nvinfo_lid = AP_CFG_CUSTOM_FILE_LOGO_INDEX_LID;
    char *nvdata_result;
    bool isread = false;
    char nvram_init_val[128] = {0};
    SLOGE("Entry get_logo_from_nvram11111");
    //checkNvramReady
    while (read_nvram_ready_retry < MAX_RETRY_COUNT) {
        read_nvram_ready_retry++;
        property_get("vendor.service.nvram_init", nvram_init_val, NULL);
        if (strcmp(nvram_init_val, "Ready") == 0 ||
            strcmp(nvram_init_val, "Pre_Ready") == 0) {
            break;
        } else {
            SLOGE("%s(), property_get(\"vendor.service.nvram_init\") = %s, read_nvram_ready_retry = %d",
                      __FUNCTION__, nvram_init_val, read_nvram_ready_retry);
            usleep(500 * 1000);
        }
    }

    if (read_nvram_ready_retry >= MAX_RETRY_COUNT) {
        SLOGE("Get nvram restore ready failed!");
        return logo_index;
    }
    SLOGE("Entry nvram go!");
   
    fid = NVM_GetFileDesc(nvinfo_lid, &rec_size, &rec_num, true);
    if (fid.iFileDesc < 0) {
        SLOGE("fid.iFileDesc < 0");
        return logo_index;
    }
    SLOGE("rec_num is :%d\n",rec_num);
    int size = rec_size*rec_num;
    nvdata_result = (char *) malloc(size);//12800 1024
    if (nvdata_result == NULL) {
        SLOGE("nvdata_result < 0");
        return logo_index;
    }

    int result = read(fid.iFileDesc, nvdata_result, size);
    SLOGE("Entry nvram result=%d", result);
    // if (result != sizeof(nvdata_result)) {
   
    free(nvdata_result);
    if (!NVM_CloseFileDesc(fid)) {
        return logo_index;
    }

    int targets = (nvdata_result[0] & 0xff) | ((nvdata_result[1] << 8) & 0xff00) 
    | ((nvdata_result[2] << 24) >> 8) | (nvdata_result[3] << 24);
    SLOGE("nvramstr targets =%d  line=%d \n",targets,__LINE__);  

    SLOGE("nvramstr hex buff[0]=%x, buff[1]=%x, buff[2]=%x, buff[3]=%x \n",
    nvdata_result[0],nvdata_result[1],nvdata_result[2],nvdata_result[3]);

    SLOGE("The size of nvdata_result:%d\n", sizeof(nvdata_result));

    SLOGE("nvramstr dex buff[0]=%d, buff[1]=%d, buff[2]=%d, buff[3]=%d \n",
    nvdata_result[0],nvdata_result[1],nvdata_result[2],nvdata_result[3]);
    //SLOGE("nvramstr dex buff[9]==%d, buff[10]==%d \n", nvdata_result[9],nvdata_result[10]);

    logo_index = targets;
    return logo_index;
}


void show_kernel_logo()
         SLOGD("[libshowlogo: %s %d]show kernel logo, index = 38 \n",__FUNCTION__,__LINE__);
     }
        if (error_flag == 0) {
+        //cpe add read index from nvram data
+        int kernel_logo_position = nvram_read_index();
                anim_show_logo(kernel_logo_position);
+        SLOGE("[show_kernel_logo: %d %d]show kernel logo, \n",__LINE__, kernel_logo_position);
     }
 }

调试小技巧

这部分可直接编译,编译后得到 system\lib\libshowlogo.so ,将其 push 到 system\lib\ 目录下,adb shell

直接执行 /system/bin/boot_logo_updater 即可查看 kernel logo 显示,同时配合 adb shell dmesg > logo.txt

抓取这部分运行的 log 查看读取是否正确。

logo 中的关键信息入下

[ 1183.906255] .(5)[3490:boot_logo_updat]libshowlogo: [show_animation_common: init_charging_animation_ui_dimension 197] lcm_width and lcm_height= 1280 , 800 
[ 1183.908249] .(5)[3490:boot_logo_updat]libshowlogo: [show_animation_common: init_charging_animation_ui_dimension 558]Inside 1280*800 
[ 1183.950082] .(4)[3490:boot_logo_updat]libshowlogo: [libshowlogo: anim_fb_init 732]rotation = 0
[ 1183.951328] .(4)[3490:boot_logo_updat]libshowlogo: Entry get_logo_from_nvram11111
[ 1183.952179] .(4)[3490:boot_logo_updat]libshowlogo: Entry nvram go!
[ 1183.954799] .(4)[3490:boot_logo_updat]libshowlogo: rec_num is :1
[ 1183.956211] .(5)[3490:boot_logo_updat]libshowlogo: Entry nvram result=1024
[ 1183.957080] .(5)[3490:boot_logo_updat]libshowlogo: nvramstr targets =39  line=1041 
[ 1183.958117] .(5)[3490:boot_logo_updat]libshowlogo: nvramstr hex buff[0]=25, buff[1]=0, buff[2]=0, buff[3]=0 
[ 1183.959554] .(5)[3490:boot_logo_updat]libshowlogo: The size of nvdata_result:4

执行 boot_logo_updater 时会出现如下 4 个 so 找不到,因为它们编译到了 vendor 分区下,暂时先 push 到设备中执行,

后面在处理。

CANNOT LINK EXECUTABLE "boot_logo_updater": library "libnvram.so" not found

:/system/bin # boot_logo_updater

CANNOT LINK EXECUTABLE "boot_logo_updater": library "libcustom_nvram.so" not found

:/system/bin # boot_logo_updater

CANNOT LINK EXECUTABLE "boot_logo_updater": library "libnvram_platform.so" not found

:/system/bin # boot_logo_updater

CANNOT LINK EXECUTABLE "boot_logo_updater": library "libnvram_sec.so" not found

:/system/bin # boot_logo_updater

解决 system/lib 下找不到相关 so 库的办法

那就是编译的时候将生成的 so 拷贝一份到 system 下,开始想的是去找到每个编译生成 so 的 mk中去拷贝

后来觉得太麻烦且估计会有问题,索性就直接将 out 下的4个 so 先复制一份,直接用脚本拷贝就行。

新建 vendor\mediatek\FileCopy\lib 和 vendor\mediatek\FileCopy\lib64 文件夹,将对应 so 扔进去就行。

新建 vendor\mediatek\FileCopy\Android.mk

LOCAL_PATH := $(call my-dir)
DEPT_PATH := system/media

COPY_FILES += $(shell ${LOCAL_PATH}/copy.sh ${DEPT_PATH})

$(info ${COPY_FILES})

新建脚本 vendor\mediatek\FileCopy\copy.sh

#!/bin/bash

bootanimation_path=$(pwd)/vendor/mediatek/BootAnimation

files=($(find ${bootanimation_path}/ -type f -name "*.zip"))
for f in ${files[@]} ;do
	if [ ! -e ${OUT}/${1} ] ;then
	  mkdir -p ${OUT}/${1}
    fi
	cp -r ${f} ${OUT}/${1}
done

audiofiles=($(find ${bootanimation_path}/ -type f -name "*.mp3"))
for f in ${audiofiles[@]} ;do
	if [ ! -e ${OUT}/${1} ] ;then
	  mkdir -p ${OUT}/${1}
    fi
	cp -r ${f} ${OUT}/${1}
done


lib_path=$(pwd)/vendor/mediatek/BootAnimation/lib
lib64_path=$(pwd)/vendor/mediatek/BootAnimation/lib64
libfiles=($(find ${lib_path}/ -type f -name "*.so"))
lib64files=($(find ${lib64_path}/ -type f -name "*.so"))
depPath="system/lib"
depPath2="system/lib64"

for f in ${libfiles[@]} ;do
	if [ ! -e ${OUT}/${depPath} ] ;then
	  mkdir -p ${OUT}/${depPath}
    fi
	cp -r ${f} ${OUT}/${depPath}
done

for f in ${lib64files[@]} ;do
	if [ ! -e ${OUT}/${depPath2} ] ;then
	  mkdir -p ${OUT}/${depPath2}
    fi
	cp -r ${f} ${OUT}/${depPath2}
done

3、uboot 区域读取 NVram

这块真的是巨麻烦,要抓取串口 log 才能看到执行流程,读取区域开始和结束都是瞎蒙的。搞了老长时间也没进展,

后来就先放了放,某天突然看到 mt_boot.c 中的 SN 读写方法 read_product_info(),突然灵机一动仿照这个

试了试,没想到最终还真成了。这块设计到的分区读写知识看来后续需要补补课了,不然看起来灰常麻烦。

vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6765/load_image.c


int mboot_common_load_logo(uint32_t logo_addr, char *filename)
{
	....
}

//cpe add
int mt_load_logo_index(char *part_name, uint32_t *addr, uint32_t size)
{
	long len;
	uint32_t begin;

	if (partition_exists(part_name) == PART_NOT_EXIST)
		return -ENOENT;

	begin = get_timer(0);

	len = partition_read(part_name, 0, (uchar *)addr, (size_t)size);
	if (len < 0) {
		len = -EIO;
		goto exit;
	}

	pal_log_err("[%s] Load '%s' partition to 0x%08x (%d bytes in %ld ms)\n",
		MODULE_NAME, part_name, (uint32_t)addr, size, get_timer(begin));

exit:
	return len;
}

vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6765/platform.c


 //cpe add
+unsigned char logoindex = 0;
+extern int mt_load_logo_index(char *part_name, uint32_t *addr, uint32_t size);

 extern void platform_early_init_timer();

 void platform_init(void)
 {
        bool bearly_backlight_on = false;
        int logo_size;


		...

		//cpe add
+       unsigned char *addr;
+       int length = 1024;
+      addr = (unsigned char *) malloc(length * sizeof(unsigned char));
+       mt_load_logo_index("proinfo", addr , 5);
+
+       pal_log_err("nvramstr dex buff[0]=%d, buff[1]=%d, buff[2]=%d, buff[3]=%d \n",
+    addr[0],addr[1],addr[2],addr[3]);//26
+    pal_log_err("nvramstr hex buff[0]=%x, buff[1]=%x, buff[2]=%x, buff[3]=%x \n",
+    addr[0],addr[1],addr[2],addr[3]);//26
+    

+       /*video_printf(" => part_dev->read addr=%s\n", addr);//&
+       video_printf("The size of nvdata_result:%d\n", sizeof(addr));//4
+       video_printf("nvramstr dex buff[0]=%d, buff[1]=%d, buff[2]=%d, buff[3]=%d \n",
+       addr[0],addr[1],addr[2],addr[3]);//26*/
+       int result = addr[0];//boot logo flag
+       //video_printf(" => result=%d\n", result);
+       logoindex = result;
		

vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6765/mt_logo.c

 #include <show_animation_common.h>
 
//cpe add
+extern unsigned char logoindex;
 
 LCM_SCREEN_T phical_screen;
 void  *logo_addr = NULL;
@@ -132,13 +133,18 @@ void mt_disp_show_boot_logo(void)
 {
        dprintf(INFO, "[lk logo: %s %d]\n",__FUNCTION__,__LINE__);
        mt_logo_get_custom_if();
+       dprintf(INFO, "[lk logoindex: %s %d]\n",__FUNCTION__, logoindex);
 
        if (logo_cust_if->show_boot_logo) {
                logo_cust_if->show_boot_logo();
        } else {
                ///show_logo(0);
                init_fb_screen();
-               fill_animation_logo(BOOT_LOGO_INDEX, mt_get_fb_addr(), (void *)mt_get_tempfb_addr(), logo_addr, phical_screen);
+               if (logoindex > 0){
+                       fill_animation_logo(logoindex, mt_get_fb_addr(), (void *)mt_get_tempfb_addr(), logo_addr, phical_screen);
+               }else{
+                       fill_animation_logo(BOOT_LOGO_INDEX, mt_get_fb_addr(), (void *)mt_get_tempfb_addr(), logo_addr, phical_screen);
+               }
                mt_disp_update(0, 0, CFG_DISPLAY_WIDTH, CFG_DISPLAY_HEIGHT);
        }

4、预置logo资源打包到rom中

经过上面修改,读写 nvram 都已正常,最后预置 logo bmp 图片打包即可,还需修改如下两个地方

在 (BOOT_LOGO)_kernel.raw 后面增加要打包进的资源图片名称,可配置 N 个,index值在 kernel 后依次累加。

vendor\mediatek\proprietary\bootable\bootloader\lk\dev\logo\rules.mk

@@ -118,6 +118,10 @@ else
 RESOURCE_OBJ_LIST +=   \
             $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_kernel.raw
 endif
+
+RESOURCE_OBJ_LIST +=   \
+            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_uboot_kernel.raw
+
 RESOURCE_OBJ_LIST +=   \
             $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_low_battery01.raw \
             $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_low_battery02.raw \

增加对应的 bmp 转化 raw 规则

vendor\mediatek\proprietary\bootable\bootloader\lk\dev\logo\update

 ./tool/bmp_to_raw ./temp37.raw ./$p/"${p}_bat_100".bmp
 ./tool/bmp_to_raw ./boot_logo ./$p/"${p}_kernel".bmp
+./tool/bmp_to_raw ./boot_logo ./$p/"${p}_uboot_kernel".bmp
 ./tool/zpipe -l 9 ./"${p}.raw" temp0.raw temp1.raw temp2.raw temp3.raw temp4.raw temp5.raw temp6.raw temp7.raw temp8.raw temp9.raw temp10.raw temp11.raw temp12.raw temp13.raw temp14.raw temp15.raw temp16.raw temp17.raw temp18.raw temp19.raw temp20.raw temp21.raw temp22.raw temp23.raw temp24.raw temp25.raw temp26.raw temp27.raw temp28.raw temp29.raw temp30.raw temp31.raw temp32.raw temp33.raw temp34.raw temp35.raw temp36.raw temp37.raw

在对应文件下放置 ?_uboot_kernel.bmp 图片

调试过程中对应串口log如下

[1198] [DISP]func|disp_lcm_is_video_mode
[1199] [PROFILE] mmc read 1 blks in 0 ms: 8KB/s
[1200] [LK_BOOT] Load 'proinfo' partition to 0x4817d3ac (5 bytes in 1 ms)
[1201] nvramstr dex buff[0]=39, buff[1]=0, buff[2]=0, buff[3]=0 
[1202] nvramstr hex buff[0]=27, buff[1]=0, buff[2]=0, buff[3]=0 
[1205] fb dump: 0x00000000, 0x00000000, 0x00000000, 0x00000000
[1206] [DISP]func|primary_display_trigger
[1207] [LK_DDP/ddp_manager]path check busy on scenario primary_disp
[1208] [DISP]func|ddp_dsi_is_busy
[1208] [LK_DDP/ddp_manager]dsi0 is busy
[1209] [DISP]func|disp_lcm_is_video_mode

[1645] [LK_ENV]get_env MTK_DEVICE_ID from area 0 [1645] Set serial # to default value. [1646] [PROFILE] mmc read 1 blks in 0 ms: 8KB/s [1647] [LK_BOOT] Load 'proinfo' partition to 0x480c3790 (19 bytes in 1 ms) [1648] read_product_info. len: 0 [1648] Serial #: "0123456789ABCDEF"

[1694] [LK_ENV]get_env MTK_DEVICE_ID from area 0 [1695] Set serial # to default value. [1695] [PROFILE] mmc read 1 blks in 0 ms: 8KB/s [1696] [LK_BOOT] Load 'proinfo' partition to 0x480c3790 (19 bytes in 1 ms) [1697] read_product_info. len: 12 [1697] Serial #: "123456644566"

NVM_GetLIDByName /mnt/vendor/nvdata/APCFG/APRDEB/PRODUCT_INFO buff[0]31, buff[1]32, buff[2]33, buff[3]34, buff[4]35, buff[5]36, buff[6]36, buff[7]34, buff[8]34 buffArr=[49, 50, 51, 52, 53, 54, 54, 52, 52, 53, 54, 54, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], targets == 875770417

buff[0]27, buff[1]0, buff[2]0, buff[3]0, buff[4]71, buff[5]bb, buff[6]bb, buff[7]bb, buff[8]bb buffArr=[39, 0, 0, 0, 113, -69, -69, -69, -69, -69, -69, -69, -69, -69, 0, 0, 0, -46, -125, -105, 113, 0, 0, 0, -91, 1, 0, 0, 0, 0, 0, 0, -91, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 112, -125, -124, -105, 113, 0, 0, 0, -104, -125, -124, -105, 113, 0, 0, 0, -104, -125, -124, -105, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -51, -36, -57, 28, 0, -8, -123, -105, 113, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0], targets == 39

/LOGO_INDEX nvramstr 2700000077BBBBBBBBBBBBBBBB000000CDDCC71C00F8459E770000000400000000000000040000000000000000000000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFEFEFEFBBBBBBBBBBBBBBBB000000000000000000000000000000000000000000000000

/PRODUCT_INFO nvramstr 2700000071BBBBBBBBBBBBBBBBBB000000D2839771000000A501000000000000A50100000000000001000000000000007083849771000000988384977100000098838497710000000000000000000000CDDCC71C00F88597710000000400000000000000

开机logo切换逻辑深入研究

MTK 平台 NVRAM 分区修改及应用解析--双logo切换