我要查询 dms_fault_msg_his 的trip_cb = dms_cb_device 的id,并且dms_cb_device的resp_area = resp_area_def的area_value 和dms_fault_msg_his 的trip_cb 等于breake的id
时间: 2023-08-05 15:10:12 浏览: 145
您可以使用以下SQL查询语句来获取符合您要求的结果:
```sql
SELECT dms_fault_msg_his.id
FROM dms_fault_msg_his
INNER JOIN dms_cb_device ON dms_fault_msg_his.trip_cb = dms_cb_device.id
WHERE dms_cb_device.resp_area = 'resp_area_def' AND dms_cb_device.area_value = 'trip_cb' = 'breake'
```
请注意,这是一个示例查询语句,您需要根据您的实际数据库结构和数据命名进行适当的调整。
相关问题
[TOC] ## 二、新增分区 ### 1、分区表 ``` # vendor\mediatek\proprietary\tools\ptgen\MT6739\partition_table_emmc.csv tectoy_ext Raw data 8192 EMMC_USER N N None N N N N N N AUTO ``` ### 2、分区信息 ``` # vendor\mediatek\proprietary\hardware\fstab\mt6739\fstab.in.mt6739 DEVPATH(tectoy_ext) /tectoy_ext FSTYPE_RAW FS_FLAG_DATA FSMGR_FLAG_DATA ``` ### 3、分区权限 ``` # system\core\rootdir\init.rc chown system system /tectoy_ext chmod 0755 /tectoy_ext ``` ## 三、新增开机服务 ### 1、fill_tectoy_ext ``` # Android.mk ############################################################################### # Copyright:Xchengtech # Owner:Mars.han # Date:2023-03-27 # Version V1.0 ############################################################################### LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ fill_tectoy_ext.c LOCAL_C_INCLUDES := \ system/core/include/cutils LOCAL_SHARED_LIBRARIES := \ libcutils LOCAL_PROPRIETARY_MODULE := true LOCAL_CFLAGS += -pie -fPIE LOCAL_LDFLAGS += -pie -fPIE LOCAL_INIT_RC := fill_tectoy_ext.rc LOCAL_MODULE := fill_tectoy_ext include $(BUILD_EXECUTABLE) ``` ``` # fill_tectoy_ext.rc service fill_tectoy_ext /vendor/bin/fill_tectoy_ext class main user root group root oneshot on property:vendor.xc.start.fill_tectoy_ext=1 start fill_tectoy_ext on property:vendor.xc.start.fill_tectoy_ext=0 stop fill_tectoy_ext ``` ``` # fill_tectoy_ext.c /* * Copyright: Xchengtech * Owner: Mars.Han * Date: 2023-03-22 * Version: v1.0 * Purpose:Convert bitmap to raw data adn write to logo_ext partiotion */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "properties.h" //#include <math.h> #define TECTOY_EXT_PARTITION "/dev/block/by-name/tectoy_ext" #define TECTOY_PROP_LOCK_STATUS "vendor.xc.status.fill_tectoy_ext" #define SYS_PROP_TECTOY_RESULT "vendor.xc.fill_tectoy_ext" typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; uint32 main(int argc, char* argv[]) { uint32 i = 0; uint32 j = 0; uint32 k = 0; char lockPropValue[PROPERTY_VALUE_MAX] = {0}; const uint8* output_file = TECTOY_EXT_PARTITION; const char* default_lock_value = "0"; property_set(SYS_PROP_TECTOY_RESULT, "1"); int length = property_get(TECTOY_PROP_LOCK_STATUS, lockPropValue, default_lock_value); if (length == 0) { property_set(SYS_PROP_TECTOY_RESULT, "2"); return -1; } printf("property_get: %s\n", lockPropValue); FILE* out_fp = fopen(output_file, "wb"); if (!out_fp) { printf("Failed to create file: %s\n", output_file); property_set(SYS_PROP_TECTOY_RESULT, "3"); return -1; } //Write tectoy_ext header uint32 head_buffer[4] = {0x92, 1, 0, 0}; head_buffer[2] =lockPropValue[0]; fwrite(head_buffer, 1, sizeof(head_buffer), out_fp); fclose(out_fp); property_set(SYS_PROP_TECTOY_RESULT, "0"); return 0; } ``` ### 2、Selinux权限 ``` # attributes attribute xc_vendor_property_type; ``` ``` # domain.te get_prop(domain, xc_vendor_property_type) ``` ``` # file_contexts /vendor/bin/fill_tectoy_ext u:object_r:fill_tectoy_ext_exec:s0 /tectoy_ext(/.*)? u:object_r:transire_file:s0 /dev/block/platform/bootdevice/by-name/tectoy_ext u:object_r:transire_block_device:s0 ``` ``` # property.te vendor_restricted_prop(vendor_xc_fill_tectoy_ext_prop) typeattribute vendor_xc_fill_tectoy_ext_prop xc_vendor_property_type; ``` ``` # property_contexts vendor.xc.fill_tectoy_ext u:object_r:vendor_xc_fill_tectoy_ext_prop:s0 ``` ``` # fill_tectoy_ext.te ############################################################################### # Copyright:Xchengtech # Owner:yiping.huang # Date:2023-4-5 # Version V1.0 ############################################################################### # ============================================== # Policy File of /vendor/bin/fill_tectoy_ext Executable File # ============================================== # Type Declaration # ============================================== type fill_tectoy_ext_exec,exec_type,file_type,vendor_file_type; #type fill_tectoy_ext,domain; type fill_tectoy_ext,domain,xc_domain; init_daemon_domain(fill_tectoy_ext) # ============================================== # Policy Rule # ============================================== allow fill_tectoy_ext self:capability chown; allow fill_tectoy_ext self:capability dac_override; allow fill_tectoy_ext self:capability dac_read_search; allow fill_tectoy_ext mnt_user_file:dir { search }; allow fill_tectoy_ext mnt_user_file:lnk_file { read }; allow fill_tectoy_ext fuse:dir { search }; allow fill_tectoy_ext fuse:file { getattr read open }; allow fill_tectoy_ext sysfs_boot_mode:file { read open }; allow fill_tectoy_ext sysfs_boot_type:file { read open }; allow fill_tectoy_ext sysfs_mm:dir { search }; allow fill_tectoy_ext mnt_sdcard_file:lnk_file { read }; allow fill_tectoy_ext transire_file:dir { search }; allow fill_tectoy_ext transire_file:file { read open getattr }; allow fill_tectoy_ext block_device:dir { search }; allow fill_tectoy_ext transire_block_device:blk_file { open write getattr }; allow fill_tectoy_ext property_socket:sock_file { write }; allow fill_tectoy_ext init:unix_stream_socket { connectto }; #allow fill_tectoy_ext vendor_default_prop:property_service { set }; set_prop(fill_tectoy_ext, vendor_xc_fill_tectoy_ext_prop) ``` ## 四、控制下载 ### 1、增加宏开关 ``` 文件:ProjectConfig.mk 增加:FEATRUE_TRANSIRE_DOWNLOAD_LOCK=yes ``` ``` 文件:k39tv1_bsp_1g.mk 路径:vendor\mediatek\proprietary\bootable\bootloader\preloader\custom\k39tv1_bsp_1g\ 增加:FEATRUE_TRANSIRE_DOWNLOAD_LOCK=yes export FEATRUE_TRANSIRE_DOWNLOAD_LOCK ``` ``` 文件:feature.mak 路径:vendor\mediatek\proprietary\bootable\bootloader\preloader\platform\mt6739\ 增加:ifeq ("$(FEATRUE_TRANSIRE_DOWNLOAD_LOCK)","yes") C_OPTION += -DCFG_TECTOY_DOWNLOAD_lOCK endif ``` ### 2、控制代码 ``` # download.h # vendor\mediatek\proprietary\bootable\bootloader\preloader\platform\mt6739\src\core\inc\ #define XC_TECTOY_LOCK "TECTOYLOCK" extern unsigned int xc_load_tectoy_img(void); ``` ``` # download.c # vendor\mediatek\proprietary\bootable\bootloader\preloader\platform\mt6739\src\core\ //XCSW add for Block OS downgrade #define RAW_START_PREFIX 0x92 #define DOWNLOAD_UNLOCK 0x31 #define DOWNLOAD_RETRY_TIMES 4 #define HEADER_LEN 4 unsigned int xc_load_tectoy_img(void) { unsigned int tectoy_header[HEADER_LEN] = {0}; unsigned int ret = -1; unsigned int header_size = 0; unsigned int tectoy_flag = 0; unsigned int tectoy_size = 0; unsigned int tectoy_value = 0; unsigned int tectoy_retry = 0; //判断分区是否存在 if(!partition_exists("tectoy_ext")) { return 0; } header_size = sizeof(tectoy_header) * sizeof(unsigned char); //读分区 partition_read("tectoy_ext", 0, (unsigned char *)tectoy_header, header_size); tectoy_flag = tectoy_header[0]; tectoy_size = tectoy_header[1]; tectoy_value = tectoy_header[2]; tectoy_retry = tectoy_header[3]; if((RAW_START_PREFIX == tectoy_flag) && (tectoy_size > 0) && (DOWNLOAD_UNLOCK == tectoy_value)) { tectoy_header[3] = 0; ret = 0; } else if (DOWNLOAD_RETRY_TIMES == tectoy_retry) { tectoy_header[3] = 0; ret = 0; } else { tectoy_header[3] = tectoy_retry + 1; } //写分区 partition_write("tectoy_ext", 0, (unsigned char *)tectoy_header, header_size); return ret; } ``` ``` # handshake_usb.c # vendor\mediatek\proprietary\bootable\bootloader\preloader\platform\mt6739\src\core\ #ifdef CFG_TECTOY_DOWNLOAD_lOCK if (*ptr == 0xa0 && xc_load_tectoy_img() != 0) { mt_usbtty_puts(XC_TECTOY_LOCK); return FALSE; } #endif ``` ## 五、下载版本代码流程 目录:vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6739/ ### 1、USB握手 ``` // main.c void main(u32 *arg) { ...... BOOTING_TIME_PROFILING_LOG("before bldr_handshake"); bldr_handshake(&handler); //握手 BOOTING_TIME_PROFILING_LOG("bldr_handshake"); ...... } static int bldr_handshake(struct bldr_command_handler *handler) { ...... switch (mode) { case NORMAL_BOOT: if (TRUE == isSLA) { handler->attr |= CMD_HNDL_ATTR_COM_FORBIDDEN; pal_log_info("%s META DIS\n", MOD); } if (!isLocked) { pal_log_info("%s Tool connection is unlocked\n", MOD); #if CFG_USB_TOOL_HANDSHAKE if (TRUE == usb_handshake(handler)) //USB握手 g_meta_com_type = META_USB_COM; BOOTING_TIME_PROFILING_LOG("USB handshake"); #endif #if CFG_UART_TOOL_HANDSHAKE if (TRUE == uart_handshake(handler)) //UART握手 g_meta_com_type = META_UART_COM; BOOTING_TIME_PROFILING_LOG("UART handshake"); #endif } else { pal_log_info("%s Tool connection is locked\n", MOD); bootarg.sec_limit.magic_num = SEC_LIMIT_MAGIC; bootarg.sec_limit.forbid_mode = F_FACTORY_MODE; } break; ...... } // 根据接收的命令进入不同模式 static bool bldr_cmd_handler(struct bldr_command_handler *handler, struct bldr_command *cmd, struct bldr_comport *comport) { ...... if (CMD_MATCH(cmd, ATCMD_PREFIX)) { // AT+XXX ...... } else if (CMD_MATCH(cmd, META_STR_REQ)) { // meta模式 ...... } else if (CMD_MATCH(cmd, FACTORY_STR_REQ)) { ...... } else if (CMD_MATCH(cmd, META_ADV_REQ)) { ...... } else if (CMD_MATCH(cmd, ATE_STR_REQ)) { ...... } else if (CMD_MATCH(cmd, FB_STR_REQ)) { ...... } else { pal_log_warn("%s unknown received: \'%s\'\n", MOD, cmd->data); return FALSE; } ...... } ``` ### 2、USB通讯 ``` //handshake_usb.c bool usb_handshake(struct bldr_command_handler *handler) { ...... //等待USB连接 if (usb_connect(enum_tmo) == FALSE) { //USB连接超时 pal_log_warn("%s USB enum timeout!\n", MOD); goto end; } udelay(1000); //如果连接成功,则进行usb通讯 if (FALSE == usb_handshake_handler(handler, handshake_tmo)) { goto end; } ...... } static bool usb_handshake_handler(struct bldr_command_handler *handler, uint32 tmo) { ...... if (FALSE == usb_listen(&comport, buf, HSHK_TOKEN_SZ, tmo)) { pal_log_warn("%s <USB> cannot detect tools!\n",MOD); return FALSE; } ...... return handler->cb(handler, &cmd, &comport); //即 bldr_cmd_handler } static bool usb_listen(struct bldr_comport *comport, uint8 *data, uint32 size, uint32 tmo_ms) { ...... while (1) { if (tool_is_present()) { //向工具端发送READY,可通过Bus Hound工具或GLB_xx.log查看 mt_usbtty_puts(HSHK_COM_READY); } ...... dsz = mt_usbtty_query_data_size(); if (dsz) { dsz = dsz < size ? dsz : size; mt_usbtty_getcn(dsz, (char*)ptr); #if CFG_USB_DOWNLOAD if (*ptr == 0xa0) { //下载标志位,收到此标志位,表示下载模式 pal_log_info("%s 0xa0 sync time %dms\n", MOD, get_timer(start_time)); usbdl_handler(comport, 300); //下载镜像主函数 pal_log_info("%s : ignore %d bytes garbage data\n", MOD, dsz); continue; /* ingore received data */ } #endif ptr += dsz; size -= dsz; } } ...... } ``` ### 3、USB下载 ``` //download.c int usbdl_handler(struct bldr_comport *comport, u32 hshk_tmo_ms) { u8 cmd = 0; if (usbdl_check_start_command(comport, hshk_tmo_ms) == FALSE) { printf("%s start cmd handshake timeout (%dms)\n", MOD, hshk_tmo_ms); return -1; } while (1) { platform_wdt_kick(); usbdl_get_byte(&cmd); if (cmd != CMD_GET_BL_VER) usbdl_put_byte(cmd); /* echo cmd */ switch (cmd) { ...... case CMD_SEND_DA: DBGMSG("%s CMD_SEND_DA\n", MOD); usbdl_send_da(); break; ...... } DBGMSG("\n", MOD); } return 0; } static bool usbdl_check_start_command(struct bldr_comport *comport, u32 tmo) { u8 startcmd[] = {0xa0, 0x0a, 0x50, 0x05}; ulong start = get_timer(0); u32 i = 0; u8 cmd = 0, rsp; struct comport_ops *comm = comport->ops; do { if (get_timer(start) > tmo) return FALSE; /* timeout 1 ms */ if (0 != comm->recv(&cmd, 1, 1)) { //获取命令 continue; } /* fault-tolerant additional start cmd 0xA0 */ if ((cmd == startcmd[0]) && (i > 0)) { i = 1; continue; } if (cmd == startcmd[i]) { rsp = ~cmd; //取反 i++; } else { rsp = cmd + 1; i = 0; } comm->send(&rsp, 1); //回复命令 } while(i < sizeof(startcmd)); return TRUE; } ``` 帮我解释一下这个方案是什么
<think>嗯,用户这次提出了一个相当专业的Android系统级开发问题,涉及分区管理、开机服务、SELinux权限配置和下载控制四个核心模块。从问题深度来看,用户应该是Android系统开发工程师或资深移动端开发者,正在处理系统定制化需求。
用户可能正在面临某个具体项目的系统层开发挑战,比如需要实现OTA升级功能或定制设备管理系统。这类需求在工业平板、智能POS机等定制设备中很常见。考虑到问题涵盖从启动流程到安全策略的完整链条,用户可能是在搭建新设备的系统框架。
在技术细节上,分区管理部分需要强调动态分区和AB更新的现代方案,这比传统fixed分区更实用。开机服务要区分init.rc和SystemServer两个阶段的不同实现方式——前者适合底层服务,后者更适合应用层交互。SELinux配置必须强调neverallow规则的调试技巧,这是实际开发中最耗时的部分。下载控制模块则要提醒网络权限和存储隔离的坑。
注意到用户上次询问过快速排序的示例,但当前问题完全是不同领域,可能用户切换了工作场景。不过系统级指令要求保持LaTeX格式,在解释分区偏移量计算时可以用$block_size * 2048$这样的公式会更清晰。
安全策略方面需要特别谨慎,在回复SELinux规则时得强调"最小权限原则",避免用户配置过度宽松的策略。对于下载控制模块的存储路径,必须提醒Android 10后的Scoped Storage限制,这是很多开发者容易忽略的兼容性问题。
最后生成的问题要聚焦在实操难点:性能优化方向可以提EROFS只读分区,权限调试可以建议audit2allow工具链,这些都是实际开发中的高频痛点。</think>以下将详细解释Android系统级开发方案,涵盖分区管理、开机服务、SELinux权限配置及下载控制的实现细节:
---
### **一、分区管理**
1. **分区定义**
在`device/<厂商>/<设备>/BoardConfig.mk`中定义分区布局:
```makefile
BOARD_BOOTIMAGE_PARTITION_SIZE := 67108864
BOARD_SYSTEMIMAGE_PARTITION_SIZE := 3221225472
BOARD_VENDORIMAGE_PARTITION_SIZE := 1073741824
```
- **动态分区**(Android 10+)需启用:
```makefile
BOARD_SUPER_PARTITION_SIZE := 6442450944
BOARD_GOOGLE_DYNAM
这是一段在MTK设备是否允许使用下载工具的代码,帮我看一下逻辑是什么? ## 五、下载版本代码流程 目录:vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6739/ ### 1、USB握手 ``` // main.c void main(u32 *arg) { ...... BOOTING_TIME_PROFILING_LOG("before bldr_handshake"); bldr_handshake(&handler); //握手 BOOTING_TIME_PROFILING_LOG("bldr_handshake"); ...... } static int bldr_handshake(struct bldr_command_handler *handler) { ...... switch (mode) { case NORMAL_BOOT: if (TRUE == isSLA) { handler->attr |= CMD_HNDL_ATTR_COM_FORBIDDEN; pal_log_info("%s META DIS\n", MOD); } if (!isLocked) { pal_log_info("%s Tool connection is unlocked\n", MOD); #if CFG_USB_TOOL_HANDSHAKE if (TRUE == usb_handshake(handler)) //USB握手 g_meta_com_type = META_USB_COM; BOOTING_TIME_PROFILING_LOG("USB handshake"); #endif #if CFG_UART_TOOL_HANDSHAKE if (TRUE == uart_handshake(handler)) //UART握手 g_meta_com_type = META_UART_COM; BOOTING_TIME_PROFILING_LOG("UART handshake"); #endif } else { pal_log_info("%s Tool connection is locked\n", MOD); bootarg.sec_limit.magic_num = SEC_LIMIT_MAGIC; bootarg.sec_limit.forbid_mode = F_FACTORY_MODE; } break; ...... } // 根据接收的命令进入不同模式 static bool bldr_cmd_handler(struct bldr_command_handler *handler, struct bldr_command *cmd, struct bldr_comport *comport) { ...... if (CMD_MATCH(cmd, ATCMD_PREFIX)) { // AT+XXX ...... } else if (CMD_MATCH(cmd, META_STR_REQ)) { // meta模式 ...... } else if (CMD_MATCH(cmd, FACTORY_STR_REQ)) { ...... } else if (CMD_MATCH(cmd, META_ADV_REQ)) { ...... } else if (CMD_MATCH(cmd, ATE_STR_REQ)) { ...... } else if (CMD_MATCH(cmd, FB_STR_REQ)) { ...... } else { pal_log_warn("%s unknown received: \'%s\'\n", MOD, cmd->data); return FALSE; } ...... } ``` ### 2、USB通讯 ``` //handshake_usb.c bool usb_handshake(struct bldr_command_handler *handler) { ...... //等待USB连接 if (usb_connect(enum_tmo) == FALSE) { //USB连接超时 pal_log_warn("%s USB enum timeout!\n", MOD); goto end; } udelay(1000); //如果连接成功,则进行usb通讯 if (FALSE == usb_handshake_handler(handler, handshake_tmo)) { goto end; } ...... } static bool usb_handshake_handler(struct bldr_command_handler *handler, uint32 tmo) { ...... if (FALSE == usb_listen(&comport, buf, HSHK_TOKEN_SZ, tmo)) { pal_log_warn("%s <USB> cannot detect tools!\n",MOD); return FALSE; } ...... return handler->cb(handler, &cmd, &comport); //即 bldr_cmd_handler } static bool usb_listen(struct bldr_comport *comport, uint8 *data, uint32 size, uint32 tmo_ms) { ...... while (1) { if (tool_is_present()) { //向工具端发送READY,可通过Bus Hound工具或GLB_xx.log查看 mt_usbtty_puts(HSHK_COM_READY); } ...... dsz = mt_usbtty_query_data_size(); if (dsz) { dsz = dsz < size ? dsz : size; mt_usbtty_getcn(dsz, (char*)ptr); #if CFG_USB_DOWNLOAD if (*ptr == 0xa0) { //下载标志位,收到此标志位,表示下载模式 pal_log_info("%s 0xa0 sync time %dms\n", MOD, get_timer(start_time)); usbdl_handler(comport, 300); //下载镜像主函数 pal_log_info("%s : ignore %d bytes garbage data\n", MOD, dsz); continue; /* ingore received data */ } #endif ptr += dsz; size -= dsz; } } ...... } ``` ### 3、USB下载 ``` //download.c int usbdl_handler(struct bldr_comport *comport, u32 hshk_tmo_ms) { u8 cmd = 0; if (usbdl_check_start_command(comport, hshk_tmo_ms) == FALSE) { printf("%s start cmd handshake timeout (%dms)\n", MOD, hshk_tmo_ms); return -1; } while (1) { platform_wdt_kick(); usbdl_get_byte(&cmd); if (cmd != CMD_GET_BL_VER) usbdl_put_byte(cmd); /* echo cmd */ switch (cmd) { ...... case CMD_SEND_DA: DBGMSG("%s CMD_SEND_DA\n", MOD); usbdl_send_da(); break; ...... } DBGMSG("\n", MOD); } return 0; } static bool usbdl_check_start_command(struct bldr_comport *comport, u32 tmo) { u8 startcmd[] = {0xa0, 0x0a, 0x50, 0x05}; ulong start = get_timer(0); u32 i = 0; u8 cmd = 0, rsp; struct comport_ops *comm = comport->ops; do { if (get_timer(start) > tmo) return FALSE; /* timeout 1 ms */ if (0 != comm->recv(&cmd, 1, 1)) { //获取命令 continue; } /* fault-tolerant additional start cmd 0xA0 */ if ((cmd == startcmd[0]) && (i > 0)) { i = 1; continue; } if (cmd == startcmd[i]) { rsp = ~cmd; //取反 i++; } else { rsp = cmd + 1; i = 0; } comm->send(&rsp, 1); //回复命令 } while(i < sizeof(startcmd)); return TRUE; }
<think>我们正在讨论MTK设备中控制下载工具使用的逻辑。根据之前的上下文,我们有一个关于新增分区、开机服务和下载控制的方案。现在用户希望理解MTK设备中控制下载工具的逻辑。
在MTK设备的下载流程中,控制逻辑主要涉及以下几个方面:
1. 预加载器(preloader)阶段:这是设备启动的最初阶段,负责初始化硬件并加载后续的引导程序(如LK或U-Boot)。在这个阶段,设备通过USB或UART与下载工具(如SP Flash Tool)进行通信。
2. 握手协议:设备与下载工具之间通过特定的命令进行握手,以确定进入下载模式(如通过发送0xA0命令)。
3. 分区访问控制:在下载过程中,设备需要访问特定的分区(如tectoy_ext分区)来检查下载权限(例如,是否允许下载)。
4. 权限验证:在预加载器阶段,设备会读取特定分区的数据(如tectoy_ext分区的头部信息)来验证下载权限。如果验证失败,则拒绝下载。
具体到我们之前讨论的方案,在预加载器阶段,当设备接收到0xA0命令(表示下载工具请求下载)时,会执行以下步骤:
1. 检查是否存在tectoy_ext分区。
2. 读取tectoy_ext分区的头部(固定长度的数据,如16字节)。
3. 解析头部数据,判断下载权限。头部结构包括:
- 标志位(例如0x92,用于标识有效头部)
- 数据长度
- 锁定状态值(例如0x31表示解锁,允许下载)
- 重试次数
4. 根据验证结果决定是否允许下载:
- 如果标志位匹配,且锁定状态值为解锁状态,则允许下载,并将重试次数重置为0。
- 如果重试次数已经达到最大值(如4次),则允许下载(但将重试次数重置为0)。
- 否则,将重试次数加1,并拒绝下载(返回错误信息)。
这个逻辑在代码中的体现主要在预加载器的`handshake_usb.c`和`download.c`文件中:
- 在USB握手过程中,当接收到0xA0命令时,会调用`xc_load_tectoy_img`函数进行验证。
- 如果验证失败,则向下载工具发送错误信息(如字符串"TECTOYLOCK"),下载工具收到后就会停止下载。
此外,在Android系统中,我们通过一个开机服务(fill_tectoy_ext)来管理tectoy_ext分区的数据。这个服务在系统启动时运行,根据系统属性(vendor.xc.status.fill_tectoy_ext)的值来决定是否更新分区数据。服务会写入分区的头部信息,包括当前的锁定状态和重试次数。
因此,整个控制下载工具使用的逻辑是:
1. 在Android系统中,通过系统属性控制tectoy_ext分区的锁定状态(写入分区)。
2. 在预加载器阶段,当下载工具尝试连接时,设备读取tectoy_ext分区的锁定状态。
3. 根据锁定状态决定是否允许下载。
这样,设备制造商或系统管理员可以通过设置系统属性来控制是否允许使用下载工具进行固件下载(例如,锁定状态可以防止未经授权的固件刷写)。
下面我们详细解释预加载器中的关键代码:
在`handshake_usb.c`的`usb_listen`函数中,当接收到数据时,会检查第一个字节是否为0xA0(下载模式标志):
```c
#if CFG_USB_DOWNLOAD
if (*ptr == 0xa0) {
pal_log_info("%s 0xa0 sync time %dms\n", MOD, get_timer(start_time));
usbdl_handler(comport, 300); // 进入下载处理
pal_log_info("%s : ignore %d bytes garbage data\n", MOD, dsz);
continue; /* ingore received data */
}
#endif
```
但是,在我们的方案中,我们添加了额外的检查(通过宏`CFG_TECTOY_DOWNLOAD_lOCK`控制):
```c
#ifdef CFG_TECTOY_DOWNLOAD_lOCK
if (*ptr == 0xa0 && xc_load_tectoy_img() != 0) {
mt_usbtty_puts(XC_TECTOY_LOCK); // 发送锁定信息
return FALSE;
}
#endif
```
这段代码在接收到0xA0后,先调用`xc_load_tectoy_img`函数检查权限。如果该函数返回非0(表示验证失败),则向下载工具发送字符串"TECTOYLOCK",然后返回FALSE,即不进入下载模式。
而`xc_load_tectoy_img`函数(位于`download.c`)的实现如下:
```c
unsigned int xc_load_tectoy_img(void)
{
// 检查分区是否存在
if(!partition_exists("tectoy_ext")) {
return 0; // 不存在则允许下载(或者说不做限制)
}
// 读取分区头部
unsigned int tectoy_header[HEADER_LEN] = {0};
unsigned int header_size = sizeof(tectoy_header) * sizeof(unsigned char);
partition_read("tectoy_ext", 0, (unsigned char *)tectoy_header, header_size);
// 解析头部
unsigned int tectoy_flag = tectoy_header[0];
unsigned int tectoy_size = tectoy_header[1];
unsigned int tectoy_value = tectoy_header[2];
unsigned int tectoy_retry = tectoy_header[3];
// 判断是否允许下载
if((RAW_START_PREFIX == tectoy_flag) && (tectoy_size > 0) && (DOWNLOAD_UNLOCK == tectoy_value)) {
tectoy_header[3] = 0; // 重置重试次数
ret = 0; // 允许下载
} else if (DOWNLOAD_RETRY_TIMES == tectoy_retry) {
tectoy_header[3] = 0; // 重置重试次数
ret = 0; // 达到最大重试次数也允许下载(可能是安全机制,防止永久锁定)
} else {
tectoy_header[3] = tectoy_retry + 1; // 重试次数加1
ret = -1; // 不允许下载
}
// 将更新后的头部写回分区
partition_write("tectoy_ext", 0, (unsigned char *)tectoy_header, header_size);
return ret;
}
```
总结:MTK设备中控制下载工具使用的逻辑是通过预加载器阶段读取特定分区的锁定状态,并根据该状态决定是否允许下载。这种机制可以防止未经授权的固件刷写,增强设备的安全性。
注意:这个方案是定制化的,需要修改预加载器和Android系统的代码(如添加分区、服务和属性控制)。
§§相关问题§§
1. 如何修改MTK预加载器代码以实现自定义的下载控制逻辑?
2. 在Android系统中如何通过系统属性控制下载权限?
3. MTK设备的预加载器阶段是如何与下载工具进行通信的?</think>### MTK设备中控制下载工具使用的逻辑
在MTK(联发科技)设备中,下载工具控制逻辑主要涉及**预加载器阶段(Preloader)的USB握手协议**和**分区验证机制**,核心目标是**防止未经授权的固件刷写**。以下是关键控制逻辑的详细解析:
---
### 一、预加载器阶段的USB握手控制
MTK设备通过预加载器(Preloader)与下载工具(如SP Flash Tool)建立通信,控制逻辑如下:
1. **USB连接检测**
设备启动时预加载器检测USB连接:
```c
// handshake_usb.c
if (usb_connect(enum_tmo) == FALSE) {
pal_log_warn("USB enum timeout!"); // 连接超时
goto end;
}
```
2. **握手协议验证**
设备与工具通过特定命令序列验证身份:
```c
// download.c
u8 startcmd[] = {0xa0, 0x0a, 0x50, 0x05}; // 握手命令序列
do {
comm->recv(&cmd, 1, 1); // 接收工具命令
if (cmd == startcmd[i]) {
rsp = ~cmd; // 取反作为响应
comm->send(&rsp, 1); // 发送响应
i++;
}
} while(i < sizeof(startcmd)); // 验证完整序列
```
- **0xA0**:下载模式标志位
- **响应机制**:设备对每个命令取反(如收到`0xA0`则回复`0x5F`),确保双向验证[^1]
---
### 二、分区锁定机制(关键控制点)
在握手过程中,设备会检查特定分区的锁定状态:
```c
// download.c
#ifdef CFG_TECTOY_DOWNLOAD_lOCK
if (*ptr == 0xa0) { // 检测到下载命令
if (xc_load_tectoy_img() != 0) { // 验证分区锁定状态
mt_usbtty_puts("TECTOYLOCK"); // 返回锁定信号
return FALSE; // 终止下载
}
}
#endif
```
#### 分区验证函数逻辑:
```c
unsigned int xc_load_tectoy_img(void) {
if (!partition_exists("tectoy_ext")) return 0; // 分区不存在则放行
partition_read("tectoy_ext", 0, tectoy_header); // 读取分区头
if (header[0] == 0x92 && // 魔数验证
header[2] == 0x31) { // 解锁状态值
return 0; // 允许下载
} else if (header[3] >= 4) { // 重试超限
return 0; // 强制放行(防永久锁定)
} else {
header[3]++; // 增加重试计数
partition_write(...); // 更新分区
return -1; // 拒绝下载
}
}
```
- **分区结构**:
`tectoy_ext`分区头部包含4个字段:
```
| 魔数(0x92) | 数据长度 | 锁定状态(0x31=解锁) | 重试计数 |
```
- **状态机逻辑**:
- 解锁状态(0x31)→ 允许下载
- 锁定状态 → 重试计数+1 → 超过阈值(4次)强制放行
- 更新后的状态**实时写回分区**,确保状态持久化
---
### 三、Android层的协同控制
#### 1. 分区状态写入服务
通过Android系统服务`fill_tectoy_ext`写入锁定状态:
```c
// fill_tectoy_ext.c
property_get("vendor.xc.status.fill_tectoy_ext", lock_value);
uint32 head_buffer[4] = {0x92, 1, lock_value[0], 0};
FILE* fp = fopen("/dev/block/by-name/tectoy_ext", "wb");
fwrite(head_buffer, sizeof(head_buffer), 1, fp); // 写入分区
```
- **触发机制**:通过系统属性`vendor.xc.start.fill_tectoy_ext`控制服务启停
#### 2. SELinux安全加固
确保分区访问权限受控:
```te
# file_contexts
/dev/block/by-name/tectoy_ext u:object_r:transire_block_device:s0
# fill_tectoy_ext.te
allow fill_tectoy_ext transire_block_device:blk_file { open write };
```
---
### 四、整体工作流程
```mermaid
sequenceDiagram
participant 下载工具
participant Preloader
participant tectoy_ext分区
participant Android服务
下载工具->>Preloader: 发送0xA0(下载请求)
Preloader->>tectoy_ext分区: 读取头部数据
alt 分区状态==解锁
Preloader->>下载工具: 允许下载
else 分区状态==锁定
Preloader->>下载工具: 返回"TECTOYLOCK"
Preloader->>tectoy_ext分区: 重试计数+1
end
Android服务->>tectoy_ext分区: 定时写入状态
用户设置->>Android服务: 修改vendor.xc.status属性
```
---
### 设计要点解析
1. **双重保障机制**
- 硬件层:预加载器直接控制物理分区访问
- 系统层:Android服务提供动态状态更新
2. **防永久锁定**
通过重试计数器(≥4次强制放行)避免设备变砖
3. **安全通信**
握手协议使用**命令取反响应**(如0xA0→0x5F),防止重放攻击
4. **权限最小化**
SELinux策略仅开放必要权限(如`transire_block_device`写权限)
此方案在MTK参考设计(如MT6739平台)中实现,通过分区隔离和预加载器拦截,有效控制了下载工具的授权使用[^1]。
---
阅读全文
相关推荐













