MTK平台修改Bootloader源代码,让Android设备一通电就自动开机

为什么要一通电就自动开机

总所周知,一台Android设备,默认情况下,插上USB供电,都是显示正在充电的电池图标,按住开机键才能开机。如果你手里只有一台手机,按住开机键去开机很容易,如果你手里有1000台手机呢?通常见于微信推广、微信站街、手游工作室、刷单工作室等,往往拥有数百台数千台手机,使用群控和脚本批量控制这些手机做一些interesting的事情。这些工作室往往使用定制的手机,手里握着全套Android源代码,这样可以方便的做很多root都做不到的事情。那么一个工作室如果有数百台手机,如果断电了,需要开机,或者需要重启,都是很痛苦的事情,如果能让这些Android手机一通电就自动开机,岂不是方便极了。那么在有全套Android源代码的情况下,如何分析代码并修改去实现这一功能呢?

思路

其实一通电就开机这个功能,和Android没什么关系,分析的时候,也不要再去看Android源代码了。首先了解一下Android设备的启动流程:

启动流程

实际上通电以后,屏幕上出现电池充电的图标,就一直停留在Bootloader这个步骤了,电池充电和屏幕显示充电的动画都是在这里面实现的,这个时候连Linux内核都还没加载,更不用说Android了。
所以要实现这个功能,首先锁定代码位置,那就是Android的Bootloader,通常是LK,代码位于bootable/bootloader/lk/。锁定了范围,只需要分析这里面的代码就行了。LK的代码量并不多,只有几千行,借助开发板使用串口打LOG调试,观察LOG输出内容,并以此为关键词在代码中搜索,定位LOG对应的代码,相信你很快就能找到方法。这里有网上找到的两篇文章,以MTK平台为例,分析了按下开机键后,由Preloader -> LK -> Kernel 的过程,结合文章中的时序图去阅读LK代码,会得到事半功倍的效果,相信你很快就能分析出来,充电的时候,代码执行到那里,按住开机键的时候,代码执行到了哪里。

深入MTK平台bootloader启动之【 Pre-loader -> Lk】分析笔记
深入MTK平台bootloader启动之【 lk -> kernel】分析笔记

MTK平台改法

有了思路以后,使用开发板串口打LOG,通电进入到充电界面后,观察串口输出的日志,用日志内容中的关键词去LK代码中搜索,进一步定位关键代码位置,通过阅读代码,bootable\bootloader\lk\platform\mt6582\boot_mode.c 中的 void boot_mode_select(void) 函数引起了我的注意,看函数名,很可能是通电以后,选择如何boot,是开机呢,还是充电呢,还是进入recovery。

void boot_mode_select(void)
{

    int factory_forbidden = 0;
  //  int forbid_mode;
/*We put conditions here to filer some cases that can not do key detection*/
    extern int kedump_mini(void) __attribute__((weak));
    if (kedump_mini) 
    {
    if (kedump_mini()) 
    {
        mrdump_check();
        return;
    }
    }
    if (meta_detection())
    {
      return;
    }

    mrdump_check();

#if defined (HAVE_LK_TEXT_MENU)
/*Check RTC to know if system want to reboot to Fastboot*/
    if(Check_RTC_PDN1_bit13())
    {
      printf("[FASTBOOT] reboot to boot loader\n");
      g_boot_mode = FASTBOOT;
      Set_Clr_RTC_PDN1_bit13(false);
          return;
    }
    /*If forbidden mode is factory, cacel the factory key detection*/ 
    if(g_boot_arg->sec_limit.magic_num == 0x4C4C4C4C)
    {
        if(g_boot_arg->sec_limit.forbid_mode == F_FACTORY_MODE)
        {
            //Forbid to enter factory mode
            printf("%s Forbidden\n",MODULE_NAME);
            factory_forbidden=1;
        }
    }
  //  forbid_mode = g_boot_arg->boot_mode &= 0x000000FF;
    /*If boot reason is power key + volumn down, then
     disable factory mode dectection*/
    if(mtk_detect_pmic_just_rst())
    {
          factory_forbidden=1;
    }
    /*Check RTC to know if system want to reboot to Recovery*/
    if(Check_RTC_Recovery_Mode())
    {
          g_boot_mode = RECOVERY_BOOT;
          return;
    }
    /*If MISC Write has not completed  in recovery mode 
     before system reboot, go to recovery mode to
    finish remain tasks*/     
    if(unshield_recovery_detection())
    {
        return;
    }
    ulong begin = get_timer(0);

/*we put key dectection here to detect key which is pressed*/
    printf("eng build\n");
    printf("MT65XX_FACTORY_KEY 0x%x\n",MT65XX_FACTORY_KEY);
    printf("MT65XX_BOOT_MENU_KEY 0x%x\n",MT65XX_BOOT_MENU_KEY);
    printf("MT65XX_RECOVERY_KEY 0x%x\n",MT65XX_RECOVERY_KEY);
    while(get_timer(begin)<50)
    {


        if(!factory_forbidden){
                   if(mtk_detect_key(MT65XX_FACTORY_KEY))
                   {
                          printf("%s Detect key\n",MODULE_NAME);
                          printf("%s Enable factory mode\n",MODULE_NAME);
                          g_boot_mode = FACTORY_BOOT;
                          //video_printf("%s : detect factory mode !\n",MODULE_NAME);
                          return;
                   }
        }

        if(mtk_detect_key(MT65XX_BOOT_MENU_KEY))
         {
                           printf("\n%s Check  boot menu\n",MODULE_NAME);
                           printf("%s Wait 50ms for special keys\n",MODULE_NAME);
                           mtk_wdt_disable();
                           boot_mode_menu_select();
                           mtk_wdt_init();
                           return;  
         }
#ifdef MT65XX_RECOVERY_KEY
            if(mtk_detect_key(MT65XX_RECOVERY_KEY))
           {
                printf("%s Detect cal key\n",MODULE_NAME);
                printf("%s Enable recovery mode\n",MODULE_NAME);
                g_boot_mode = RECOVERY_BOOT;
                //video_printf("%s : detect recovery mode !\n",MODULE_NAME);
                return;
            }
#endif                   
    }
#else

/*We put conditions here to filer some cases that can not do key detection*/

/*Check RTC to know if system want to reboot to Fastboot*/
#ifdef MTK_FASTBOOT_SUPPORT
  if(Check_RTC_PDN1_bit13())
  {
    dprintf(INFO,"[FASTBOOT] reboot to boot loader\n");
    g_boot_mode = FASTBOOT;
    Set_Clr_RTC_PDN1_bit13(false);
         return ;
  }
#endif

   /*If forbidden mode is factory, cacel the factory key detection*/
    if(g_boot_arg->sec_limit.magic_num == 0x4C4C4C4C)
    {
        if(g_boot_arg->sec_limit.forbid_mode == F_FACTORY_MODE)
        {
            //Forbid to enter factory mode
            printf("%s Forbidden\n",MODULE_NAME);
            factory_forbidden=1;
        }
    }
//    forbid_mode = g_boot_arg->boot_mode &= 0x000000FF;
    /*If boot reason is power key + volumn down, then 
     disable factory mode dectection*/
    if(mtk_detect_pmic_just_rst())
    {
          factory_forbidden=1;
    }
    /*Check RTC to know if system want to reboot to Recovery*/
    if(Check_RTC_Recovery_Mode())
    {
          g_boot_mode = RECOVERY_BOOT;
          return ;
    }
    /*If MISC Write has not completed  in recovery mode 
     and interrupted by system reboot, go to recovery mode to 
    finish remain tasks*/
    if(unshield_recovery_detection())
    {
        return ;
    }
    ulong begin = get_timer(0);
/*we put key dectection here to detect key which is pressed*/
while(get_timer(begin)<50){
#ifdef MTK_FASTBOOT_SUPPORT
    if(mtk_detect_key(MT_CAMERA_KEY))
    {
          dprintf(INFO,"[FASTBOOT]Key Detect\n");
          g_boot_mode = FASTBOOT;
          return ;
    }
#endif
    if(!factory_forbidden){
                if(mtk_detect_key(MT65XX_FACTORY_KEY))
                {
                       printf("%s Detect key\n",MODULE_NAME);
                       printf("%s Enable factory mode\n",MODULE_NAME);
                       g_boot_mode = FACTORY_BOOT;
                       //video_printf("%s : detect factory mode !\n",MODULE_NAME);
                       return ;
                }
     }
#ifdef MT65XX_RECOVERY_KEY
        if(mtk_detect_key(MT65XX_RECOVERY_KEY))
        {
             printf("%s Detect cal key\n",MODULE_NAME);
             printf("%s Enable recovery mode\n",MODULE_NAME);
             g_boot_mode = RECOVERY_BOOT;
             //video_printf("%s : detect recovery mode !\n",MODULE_NAME);
             return ;
         }
#endif
}

#endif

#ifdef MTK_KERNEL_POWER_OFF_CHARGING
    if(kernel_power_off_charging_detection())
    {
        printf(" < Kernel Power Off Charging Detection Ok> \n");
        return;
    }
    else
    {
        printf("< Kernel Enter Normal Boot > \n");
    }
#endif
}

boot_mode_select函数中的g_boot_mode变量尤为重要,不同的赋值决定着它boot什么。在boot_mode_select函数中可以看到所有的分支,对boot_mode_select的赋值,要么是NORMAL_BOOT要么是FASTBOOT要么是RECOVERY_BOOT,似乎都和充电界面没什么关系啊。但是注意函数的尾部:

#ifdef MTK_KERNEL_POWER_OFF_CHARGING
    if(kernel_power_off_charging_detection())
    {
        printf(" < Kernel Power Off Charging Detection Ok> \n");
        return;
    }
    else
    {
        printf("< Kernel Enter Normal Boot > \n");
    }
#endif

看到了power_off_charging,似乎和关机状态下的充电有关系,再看两个分支的printf,一个分支和充电相关,一个分支是Kernel Enter Normal Boot正常开机启动。马上搜索kernel_power_off_charging_detection的定义:
find -name “*.c” | xargs grep “kernel_power_off_charging_detection”
在bootable\bootloader\lk\platform\mt6582\mt_kernel_power_off_charging.c中找到了这个函数,看文件名,显然是和关机充电相关的代码:

BOOL kernel_power_off_charging_detection(void)
{
    int off_mode_status = 1;
    /* */
    if(is_force_boot()) {
        upmu_set_rg_chrind_on(0);
        printf("[%s] Turn off HW Led\n", __func__);
        return FALSE;
    }

    off_mode_status = get_off_mode_charge_status();
    printf("[%s] off_mode_status %d\n", __func__, off_mode_status);
    if(upmu_is_chr_det() == KAL_TRUE) {
        if (off_mode_status) {
            g_boot_mode = KERNEL_POWER_OFF_CHARGING_BOOT;
        } else {
            g_boot_mode = NORMAL_BOOT;
            upmu_set_rg_chrind_on(0);
            return FALSE;
        }
        return TRUE;
    }
    else {
        /* power off */
        #ifndef NO_POWER_OFF
        printf("[kernel_power_off_charging_detection] power off\n");
        mt6575_power_off();        
        #endif
        return FALSE;   
    }
    /* */
}

可以看到这里对g_boot_mode有两种赋值,一种是关机状态下充电,一种是正常开机。那么一个改动思路就是将:
g_boot_mode = KERNEL_POWER_OFF_CHARGING_BOOT;
改成
g_boot_mode = NORMAL_BOOT;
这样原本要进行关机充电的,改成了正常开机启动。

还有一种找关键代码的思路是,找到了g_boot_mode这个变量后,在LK代码目录中搜索,看看哪里对它进行了赋值:
find -name “*.c” | xargs grep “g_boot_mode = ”
可以看到,只有bootable\bootloader\lk\platform\mt6582\mt_kernel_power_off_charging.c 文件中对g_boot_mode赋值为KERNEL_POWER_OFF_CHARGING_BOOT,其它地方都是赋值为NORMAL_BOOT、FASTBOOT、RECOVERY_BOOT、ALARM_BOOT等,明显和充电无关。这样也能快速定位到关键代码,究竟是哪里,让它进入了关机充电那个界面。

此时还没有结束,我又注意到了这个宏MTK_KERNEL_POWER_OFF_CHARGING:

#ifdef MTK_KERNEL_POWER_OFF_CHARGING
    if(kernel_power_off_charging_detection())
    {
        printf(" < Kernel Power Off Charging Detection Ok> \n");
        return;
    }
    else
    {
        printf("< Kernel Enter Normal Boot > \n");
    }
#endif

在bootable\bootloader\lk\platform\mt6582\boot_mode.c的 boot_mode_select 函数中,如果代码运行到这里,又没定义MTK_KERNEL_POWER_OFF_CHARGING这个宏,宏内这段代码不会执行,那么此时g_boot_mode的赋值是什么?当然是初始值NORMAL_BOOT,当然这只是猜想,万一哪个函数里改变了它的值呢,接下来在这个位置插入打LOG的代码把g_boot_mode的值输出来看看,果然是NORMAL_BOOT。那么尝试取消定义MTK_KERNEL_POWER_OFF_CHARGING这个宏,是不是就能实现直接开机的效果呢?经过测试,果然如此。

这个宏的意思是是否允许在关机状态下充电,可以理解为,如果不允许,那么插电后,设备会开机再充电。
当然,宏的改法是MTK平台特有的,其它平台可以参考代码的改法,虽然不同平台的LK代码有差异,但总体流程还是不变的。

那么,如何取消这个宏的定义呢:
通常这个宏位于ProjectConfig.mk中,具体路径各不相同,如果找不到的话可以find -name “ProjectConfig.mk”搜索,另外有的同学改了以后还是无效,那可能不止这一处的mk文件定义了MTK_KERNEL_POWER_OFF_CHARGING哦,最简单的办法是直接全局搜索:
find -name “*.mk” | xargs grep “MTK_KERNEL_POWER_OFF_CHARGING = yes”
然后全部改为MTK_KERNEL_POWER_OFF_CHARGING = no

改完以后重新编译LK
mmm bootable/bootloader/lk:clean-lk
mmm bootable/bootloader/lk:lk
然后make snod 并 Download
USB插入,通电

Perfect!

总结

① 对于MTK平台,关键在于MTK_KERNEL_POWER_OFF_CHARGING这个宏,搜索源代码目录下的所有mk文件:
find -name “*.mk” | xargs grep “MTK_KERNEL_POWER_OFF_CHARGING = yes”
将其替换为为MTK_KERNEL_POWER_OFF_CHARGING = no即可

② 如果是MTK平台,但是没有MTK_KERNEL_POWER_OFF_CHARGING这个宏,尝试找到bootable\bootloader\lk\platform\mt6582\mt_kernel_power_off_charging.c文件
你的源码不一定是这个路径,尝试搜索mt_kernel_power_off_charging.c
find -name “mt_kernel_power_off_charging.c”
里面有个kernel_power_off_charging_detection(void)函数,函数内对g_boot_mode的赋值,通通改为g_boot_mode = NORMAL_BOOT;

③ 对于高通等其它平台,如果没有方法②中的函数,需要花点功夫了,首先定位bootloader的lk部分代码,然后搜索这些和启动模式相关的关键词:
g_boot_mode NORMAL_BOOT FASTBOOT RECOVERY_BOOT
搜索哪些地方对g_boot_mode赋值了:
find -name “*.c” | xargs grep “g_boot_mode = ”
着重去分析这些地方,配合打LOG调试,相信你很快就能搞定



本文由CharlesSimonyi发表于优快云博客:https://blog.youkuaiyun.com/CharlesSimonyi/article/details/82236494 转载请注明出处

<think>我们正在讨论Android手机相关的日志关键词。根据用户提供的引用和之前的问题,我们需要关注充状态、池状态变化、关机充模式等相关的日志关键词。参考引用: [^1]提到了池相关的统计时间,如battery realtime,battery uptime等,这些可能与池充时的计时有关。[^2]展示了一个广播接收器,用于监听量低的广播(ACTION_BATTERY_LOW)。这提示我们池状态变化会通过广播发送,并在日志中可能有相应输出。 [^3]讨论了MTK平台Bootloader修改,让设备一通自动开机,以及如何通过搜索g_boot_mode变量来定位关机充的代码。这提示我们关机充模式在日志中可能有特定的关键词。[^4]是一个Python脚本,用于处理构建输出的镜像,与充日志关系不大。结合以上,我们可以整理出Android手机时日志中可能出现的关键词:1.**池状态变化**:如充状态(charging,discharging)、量水平(level)、温度(temperature)等。这些状态的变化通常由系统服务BatteryService管理,并在日志中输出。2. **充模式**:如正常充、快速充、无线充等,以及关机充模式(在引用[^3]中提到)。3. **广播事件**:如ACTION_BATTERY_CHANGED,ACTION_BATTERY_LOW,ACTION_POWER_CONNECTED等,这些广播的发送和接收可能会在日志中留下痕迹。4.**充流和压**:在调试日志中,可能会输出实时的充流(current_now)和压(voltage_now)。5. **充芯片状态**:不同平台(如MTK、高通)的驱动可能会输出充芯片的状态和调试信息。因此,我们可以列出以下关键词:-充状态相关:-"charging" /"discharging"-"accharger" /"usb charger" /"wireless charger"-"battery level"-"battery temp" -广播相关:- "ACTION_POWER_CONNECTED" /"Intent.ACTION_POWER_CONNECTED"- "ACTION_POWER_DISCONNECTED"- "ACTION_BATTERY_CHANGED"- "ACTION_BATTERY_LOW"-充模式相关(特别是关机充):-"offmode_charging"(关机充)-"g_boot_mode"(引用[^3]中提到的变量,可能出现在日志中)- "KERNEL_POWER_OFF_CHARGING_BOOT"(引用[^3]中提到的模式) -充压:- "current_now"- "voltage_now"-"batterycurrent" -系统服务/内核日志:-"BatteryService"-"HealthHal"(池健康HAL)-"qpnp_charger"(高通平台驱动)-"mtk_charger"(MTK平台驱动)此外,在日志中搜索这些关键词时,可以使用adblogcat命令,并配合grep过滤,例如: ```bashadblogcat| grep-iE "charging|battery|power"```下面我们详细解释一些常见的日志输出示例:1. **连接源时的日志**:```I/BatteryService: [充状态]源已连接,充类型:AC```或者:```I/BatteryService:ACTION_POWER_CONNECTED```2.**池状态更新**:```I/BatteryService:量:45%,状态:充中,健康:良好,温度:27.5℃```3. **关机充模式**(当手机关机后入充器进入充界面):在引用[^3]中提到,MTK平台通过设置g_boot_mode为KERNEL_POWER_OFF_CHARGING_BOOT来进入关机充模式。在日志中(通常是内核日志)可能会看到:```[0.000000] g_boot_mode =2(KERNEL_POWER_OFF_CHARGING_BOOT)```4.**充压**:```D/qpnp_charger:流:1500mA,压:4300mV```5.**低量广播**:```I/ActivityManager:广播:Intent.ACTION_BATTERY_LOW```注意:不同手机制造商可能定制了不同的日志输出,因此关键词可能略有不同。但以上关键词是Android系统通用的。相关问题:1.如何通过adb命令实时监控充状态的变化?2.在关机充模式下,如何查看日志?3.如何判断手机是否支持快速充?在日志中如何体现?4.充过程中温度过高,日志中会有哪些警告?希望这些信息能帮助您定位充相关的日志。</think>### Android日志关键词分析 在 Android 系统中,充状态相关的日志通常包含以下关键词,这些关键词可帮助诊断充问题或监控充状态: #### 核心充状态关键词 1. **`BATTERY_CHANGED`** - 系统广播,当池状态变化时触发(如拔充器) - 日志示例:`Broadcast: Intent.ACTION_BATTERY_CHANGED level=85 scale=100 status=2` - 关键参数说明: - `level`:当前量百分比(如 85%) - `status=2`:充状态(2=充中,5=充满)[^2] 2. **`POWER_CONNECTED/DISCONNECTED`** - 充器连接/断开事件 - 日志示例:`ACTION_POWER_CONNECTED` 或 `USB charger connected` 3. **`healthd` 守护进程日志** - 池健康守护进程输出的底层信息: ```log healthd: battery l=85 v=4.3 t=30.5 h=2 st=2 c=1500 fc=1000000 chg=u ``` - `l`:量百分比 - `v`:压(伏特) - `t`:池温度(℃) - `c`:充流(mA) - `st=2`:充状态(同 BATTERY_CHANGED)[^1] #### 高级充诊断关键词 4. **`ChargingState`** - 充状态机切换日志: `ChargingState: State transition: DISCHARGING -> CHARGING` 5. **`QC_FACTOR`** - 快充协议相关(如 Qualcomm Quick Charge): `QC_FACTOR: 9V/2A mode activated` 6. **`thermal`** - 充温控相关: `thermal: Charging throttled at 42°C, current reduced to 500mA` #### 关机充模式关键词 7. **`offmode_charging`** - 关机充模式(参考引用[^3]): `g_boot_mode = KERNEL_POWER_OFF_CHARGING_BOOT` `offmode_charging: show battery animation` 8. **`battery screen off`** - 息屏充统计(参考引用[^1]): `battery screen off realtime: 3600s` #### 充协议关键词 9. **`PD`/`PPS`** - USB Power Delivery 协议: `PD: Contract 20V/3A established` 10. **`WIRELESS`** - 无线充相关: `WIRELESS: Alignment check passed, 15W charging` --- ### 日志捕获方法 使用 ADB 获取充日志: ```bash # 实时监控充日志 adb logcat | grep -Ei "battery|charging|power|healthd" # 获取完整的池服务日志 adb logcat -b all | grep BatteryService ``` --- ### 相关问题 1. **如何区分快充和普通充的日志特征?** (分析 `QC_FACTOR`/`PD` 等协议的日志差异) 2. **充过程中出现 `healthd: over-voltage protection` 警告应如何处理?** (诊断充器兼容性问题) 3. **关机充动画卡在 0% 如何通过日志诊断?** (分析 `offmode_charging` 和池检测逻辑) 4. **为什么息屏充速度比亮屏快?日志中哪些参数能证明?** (对比 `battery screen off realtime` 的流数据) 5. **如何通过日志判断无线充线圈是否对齐?** (解析 `WIRELESS` 相关日志的定位信号)
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值