简介面向MTK平台Android 9.0及以上系统定制开发者这份zip包提供了在MT6761上新增FDRAM分区并挂载到根目录的完整实操参考覆盖分区表修改、文件系统格式化、fstab挂载配置及安全注意事项并针对Android 9.0 A/B更新与Vold框架给出适配思路。包内共21个文件以mk、te、csv、py等类型为主包含构建配置、SELinux策略、分区定义和辅助脚本另有makefile、rc、c等文件整体仅133KB便于快速下载查阅。当前已有682人学习。资源中附有partition.map与partition.bin调整方法、mkfs.f2fs/ext4格式化命令、挂载权限设置示例及多系统分区适配细节适合有一定内核与文件系统基础的MTK工程师直接参考可显著缩短分区扩展的开发验证周期。1. 给 Android 加一个新分区一次格式化变砖后的复盘在定制 Android 系统时“加一个分区再挂到根目录”听起来是最不起眼的需求实际上它同时踩了 bootloader 分区表、内核设备树、fstab、init 和 SELinux 五道门槛任何一道漏掉轻则挂载后目录为空重则开机直接卡在 logo。这套资源包就是从一次真实变砖中反推出来的完整清单把新分区 FDRAM 从“在 gpt 里画一块区域”到“开机自动出现在根目录下指定位置”的每一步都打成了可复用的补丁与脚本。适合正在做系统定制、整机 ROM、行业终端 BSP 的工程师也适合第一次被“分区挂载”需求砸中的入门开发者照着复现。2. 挂载链路四道关卡为什么改 fstab 远远不够2.1 第一关bootloader 分区表先在“地基”里画一块地很多人以为新增分区只改 fstab 就行这是第一个翻车点。Android 设备的存储布局由 bootloader 阶段的分区表定义它不只是一张“名字到起始扇区”的映射表还承担了开机时给内核传递分区参数、配合恢复出厂、OTA 差分升级等职责。改 fstab 等于告诉系统“我要用一块地”但没人在地上画线这块地根本不存在。这套资源包里改的第一个文件就是 bootloader 分区描述文件。常见做法是维护一个静态分区数组每个分区有名称、起始偏移、大小、标志位/* partition_config.c */ static const struct pt_entry partitions[] { /* 原有分区... */ { .name system, .start 0x00200000, .size 0x06000000, .flags PT_SYSTEM, }, /* 新增 FDRAM 分区紧跟 system 之后 */ { .name FDRAM, .start 0x08000000, .size 0x02000000, /* 512MB按实际需求调整 */ .flags PT_USER, /* 用户数据区不参与系统校验 */ }, /* 原有分区... */ };逻辑上并没有多复杂新分区只是数组里多了一行但请注意.start是硬编码偏移意味着它前面的所有分区大小只要动过这里就得同步算。资源包的做法是不手算而是在编译时用脚本从前一个分区的start size自动推导杜绝“算错偏移导致分区重叠”的隐患。参数层面.flags决定分区能不能被普通文件系统挂载、是否纳入 dm-verity 校验、是否允许恢复出厂时格式化。给 FDRAM 标PT_USER意味着它属于用户数据性质和/data同策略如果你希望它像system一样只读校验那就标PT_SYSTEM但那样的话“往里写数据”的需求就要重新考虑了。我一般建议数据扩展区都按PT_USER处理省事且符合直觉。2.2 第二关内核设备树给分区一张“身份证”bootloader 画完地内核还需要在设备树里见到这个分区否则 Linux 的块设备层根本不会为它创建/dev/block/...节点。这一步漏掉的典型症状是fstab 里写了挂载点开机 log 里报device not found目录存在但完全没挂载。设备树里描述的是一块“存储区域”不是“文件系统”。看资源里给的 dts 片段/* 在 boot 设备节点的 partitions 子节点中追加 */ partition8000000 { label FDRAM; reg 0x08000000 0x02000000; /* 起始地址 128MB大小 512MB */ };注意reg的两个值必须和 bootloader 分区表完全一致起始地址和大小都是十六进制字节数。这里最容易犯的错是拿 MB 当字节直接写进去——0x2000000是 32MB不是 512MB差了 16 倍。资源包附带了一个check_partition.py脚本专门读取 bootloader 表和 dts 的reg做交叉比对数值不一致直接报错退出编译从流程上掐掉这种低级但致命的错。设备树节点的名字partition后缀理论上只要求唯一但内核的 mmc 驱动会按这个reg注册块设备号所以它的排序决定了/dev/block/mmcblk0pN的 N。如果新分区插在其他分区中间后面所有分区的 N 都会后移fstab 里没有用by-name而是用裸节点名的写法就会全部失效。这套资源包强制建议 fstab 一律用by-name/FDRAM这种符号链接原因就在这。2.3 第三关fstab 与 init 配合挂载时机比挂载命令更重要fstab 文件是第二阶段 init 解析的关键输入它决定了分区在用户空间启动的哪个阶段、以什么方式挂载到哪个目录。但“挂载到根目录”这个需求需要先拆解不是往/上挂那是根文件系统本身的位置而是在根文件系统下的某个专门目录挂载新分区比如/frdata。目录可以是空的不影响根文件系统但你要保证它在挂载动作发生前已经存在。资源包里提供的 fstab 写法# vendor/etc/fstab # 设备节点 挂载点 文件系统类型 挂载标志 其他选项 /dev/block/by-name/FDRAM /frdata ext4 rw,noatime wait,check,fileencryptionsoftwarewait表示 init 会等待这个设备节点出现再继续避免 boot 设备 probe 慢导致挂载失败check表示开机时会用 fsck 检查文件系统完整性fileencryptionsoftware是为 FDRAM 单独开启软件级加密这是/data之后第二个加密分区时很容易忽略的选项——不加这行SDC 或 vold 的加密策略会对陌生分区直接跳过数据裸奔不说某些 OEM 的恢复出厂流程还会拒绝格式化它。init.rc 侧的配合则是在挂载时机上。卷管理vold的挂载路径是异步的不适合开机关键路径FDRAM 如果承载的是日志、缓存、预加载资源这类开机就需要访问的内容建议走 init 的mount_allon fs mount_all /vendor/etc/fstab # 挂载完成后设置属主 chown system system /frdata chmod 0771 /frdataon fs阶段比on post-fs-data早意味着 FDRAM 在 zygote 启动前就已就位App 一开机就能读写。代价是这一阶段挂载失败会直接触发 panic翻车现场所以资源包里放了一个开关宏——调试期把该行挪到on post-fs-data降级为“挂不上也继续开机”等稳定再挪回关键路径。2.4 第四关SELinux 策略让新分区不再“有权限却没权限”分区挂上了目录存在df也看得到但一写入就Permission denied——这是 SELinux 在挡路也是新手最觉得“玄学”的一关。Android 的用户空间大量进程跑在受限域里vold、init、system_server对非标准分区的访问默认都是拒绝的。资源包里加入了三个层面的 SELinux 补丁# fdr.am.te type fdr_data_file, file_type, data_file_type; typeattribute fdr_data_file core_data_file_type;第一个.te声明了新的文件类型标签。然后是file_contexts把实际目录映射到标签/frdata(/.*)? u:object_r:fdr_data_file:s0缺少这条目录还是default_t类型带core_data_file_type属性的进程照样写不进去。最后是授权规则资源包按“最小权限”给了init和vold的标签声明不直接给system_server开全权限避免扩大攻击面allow init fdr_data_file:dir { create read write open search setattr }; allow init fdr_data_file:file { create read write open setattr }; allow vold fdr_data_file:dir { read write search create mounton };四条规则之外别忘了seapp_contexts可能需要为新分区上运行的应用进程单独指派 domain。如果是系统级分区不做这步也能跑如果某个第三方 App 要直接读写 FDRAM那它所在的 domain 必须显式allow否则应用层表现为“文件管理器能看到目录但拷贝文件永远失败”。3. 动手落地把 FDRAM 变更合入现有工程3.1 先跑检查脚本确认分区表中没有旧定义拿到资源包的第一件事不是改代码而是确认你的基线工程里不存在同名分区。某些厂商 BSP 里 FDRAM 或类似名字已被占用于隐藏区域硬加数组项会导致 bootloader 解析直接报partition duplicated卡死在 preloader 阶段。python3 tool/check_dup_partition.py --config bootloader/pt_config.c脚本会扫描分区名并输出冲突项。如果返回零进入下一步如果有同名分区先在原位置把名字改为FDRAM_BACKUP这类临时名不要直接删——有些分区是 OTA 增量升级的依赖项删了会破坏后续升级链。3.2 统一修改三处描述文件保持字节级一致最稳的顺序是先改 bootloader 分区表再改 dts最后改 fstab。三处的“起始地址/大小”必须完全一致资源包里用一个part_info.json作为唯一数据源{ name: FDRAM, start_mb: 2048, size_mb: 512, filesystem: ext4, mount_point: /frdata }之后执行python3 gen_partitions.py它会同时生成 C 结构体片段、dts 片段和 fstab 片段不给你任何手改漂移的机会。这个脚本的逻辑看起来简单但它把“一致性”从人的纪律变成了流程约束强烈建议沿用。3.3 生成文件系统镜像并固化到用户数据区FDRAM 的初始内容有两种来源空分区第一次刷机后由 init 格式化和预置镜像出厂时烧录好特定数据。如果是后者需要先用make_ext4fs生成镜像mkfs.ext4 -O ^metadata_csum -b 4096 -L FDRAM -d ./frdata_contents frdam.img 512M simg2img frdam.img FDRAM.raw.img注意-O ^metadata_csum关掉了较新的 metadata 校验特性部分旧内核的 ext4 驱动不认识它挂载时会报unsupported filesystem features。这类问题刷机后极难排查因为内核日志往往被 Android 的 log 系统吃掉了一部分建议在生成阶段就按目标内核版本核对mkfs.ext4的版本与参数支持范围。3.4 把变更写进编译产物并验证 SELinux 标签生效修改完源码后编译阶段要特别注意bootloader 分区表和 dts 的变更会影响boot.img和 bootloader 产物但 fstab 变更会进入vendor.img或system.img——如果你的工程是动态分区fstab 所在的分区在编译目录树里甚至不是一个独立目录而是会被打包进vendor。资源包附带了一个构建后自检脚本python3 tool/post_build_check.py --out out/target/product/xxx/vendor脚本读vendor/etc/fstab检查by-name/FDRAM是否存在再解析file_contexts确认/frdata有唯一标签。这两项都通过后我再接着刷机不然很容易出现“改动全做了但烧进去的镜像少了某个文件”的尴尬局面。4. 编译刷机与验证从亮屏到写入三步确认改动生效4.1 分阶段编译别一次编全量包新增分区相关的代码分散在 bootloader、内核和 vendor 三处我不建议上来就跑make全量编译时间太长出错时也不好定位。资源包的 README 里推荐的顺序是分产物编译source build/envsetup.sh lunch 你的产品-userdebug # 先编 bootloader 产物确认分区表无误 make bootloader -j$(nproc) # 再编内核和 boot 镜像 make bootimage -j$(nproc) # 最后编 vendor 以刷新 fstab 和 SELinux make vendorimage -j$(nproc)三个产物独立编译的好处是bootloader 编译不过问题大概率在分区表数组的语法或宏定义bootimage不过问题在 dts 节点vendorimage不过问题在 fstab 行或file_contexts。分开编让错误定位范围缩小 75% 以上。编译逻辑上bootloader 产物不依赖内核因此最先编能最快验证分区表层bootimage 依赖 dts 编译进内核二进制所以第二轮核验设备树vendorimage 里的 fstab 是纯文本配置理论上不会编不过但如果 SELinux 的.te文件语法错误vendorimage的编译会在 sepolicy 生成阶段中断——不要怀疑这是最常见的“编不过第三阶段”的原因。4.2 刷机后的第一轮检查按 log 顺序排查刷完机、开机到桌面后别急着跑业务功能先用 adb 做三连检查# 看分区是否存在及大小是否正确 adb shell ls -l /dev/block/by-name/FDRAM adb shell cat /proc/partitions | grep FDRAM # 看挂载状态 adb shell mount | grep frdata adb shell df -h /frdata # 试写一个文件验证权限 adb shell echo test /frdata/probe.txt cat /frdata/probe.txt第一行的输出如果找不到by-name/FDRAM说明 bootloader 分区表或 dts 至少有一层没生效第二行mount没输出说明 fstab 的wait没等到节点、或 fsck 失败把挂载动作跳过了第三行echo test被拒绝则是 SELinux 的写入权限没有放到位。按这个顺序逐条排查基本二十分钟内能定位到具体关卡。这里有一个血泪经验每次刷完机后第一件事先看adb shell getenforce。如果返回Enforcing先执行setenforce 0再测试 FDRAM 写入如果权限问题消失说明是 SELinux 规则缺失如果关了 SELinux 照样写不进去大概率是文件系统只读或挂载标志少了rw——两者的差异帮你筛掉一半的排查方向。4.3 恢复出厂与 OTA 场景下的补充验证常规挂载测试只是第一步FDRAM 这种新增分区最容易在恢复出厂和 OTA 升级时“现原形”。这个场景下vold会读取分区表来执行“格式化用户数据分区”的流程如果它不认识 FDRAM恢复出厂后新分区的内容不会被清掉但这既是好事也是坏事——你需要验证的是它会怎么处理未知分区# 在恢复模式下手动触发格式化观察输出 adb reboot recovery adb shell recovery --wipe_data --wipe_cache命令执行后从 recovery 日志里找 FDRAM 相关行。如果没有任何日志说明vold的分区类型映射表需要补FDRAM的条目如果它被当作userdata一并格式化了那也没问题但你要确认 FDRAM 里预置的数据不被误删。OTA 升级同理差分升级脚本通常会把system、vendor等分区列进升级范围FDRAM 如果不在升级列表里那新旧版本对它的格式约定必须保持兼容否则 OTA 后可能挂载失败。由于这个环节最容易在真机上翻车我把验证顺序固定成刷机亮屏 → 三连检查 →setenforce 0对比写入问题 → 恢复出厂测试 → OTA 灰度包冒烟。这套顺序变成了资源包里的verify_fdram.sh一次跑完并输出对照表不用人肉盯屏。5. 避坑指南FDRAM 挂载最常见的五个“翻车现场”5.1 现象开机卡在 bootloaderlog 提示 partition duplicate原因基线工程里已经存在同名分区或 bootloader 分区数组前一项的size被改过导致数组里的start与 dtsreg不一致bootloader 自检阶段拒绝进入内核。解决跑一次check_dup_partition.py如有重复先给旧分区改名再跑gen_partitions.py重新生成三处描述文件确保start由脚本计算而不是手填。我在某款设备上遇到卡 preloader事后发现是前一个分区的size字段被业务同事手动加了 0x80000导致 FDRAM 与它重叠了 4MB——这类问题靠肉眼看数组几乎发现不了必须交给脚本比对。5.2 现象挂载成功但/frdata下所有文件消失df显示0% used原因文件系统类型在 fstab 里写的是auto内核探测到的却是f2fs或ext4而分区本身从未被真实格式化过。auto不会帮你执行mkfs只会帮你猜类型。解决fstab 里写死ext4首次开机的check模式会在文件系统头不合法时自动触发一次格式化。注意这种情况下mount路径会从persist变成erofs相关报错但不要慌自检日志里会明确提示filesystem not recognized。资源包的init-fdram.sh脚本里加了首次格式化逻辑这也是防呆措施避免每一台设备在产线上人工敲mkfs.ext4。5.3 现象mount命令手动执行成功但 init 阶段自动挂载失败原因fstab 里wait和check的顺序写反了。wait必须在check之前否则 fsck 会在设备节点还不存在时直接失败并跳过挂载。个别厂商的 fstab 解析器对wait,check,fileencryptionsoftware连写没有做重排序老老实实按依赖顺序排列。解决把 fstab 相关参数改成wait,check不要写成check,wait。另外确认设备节点用by-name而不用mmcblk0pN因为 N 可能在内核版本升级后变化by-name是稳定的符号链接。这个坑我碰到过一次里面明明写了wait但排在了noatime后面解析器先处理了noatime再处理wait行为就变了。5.4 现象App 读写/frdata时反复Permission denied但 shell 下 root 用户一切正常原因SELinux 没有为相关 app 域放行。fdr_data_file类型虽然声明了但untrusted_app域对它的dir/search和file/read权限缺失root shell 不受 SELinux 限制当然什么都正常。解决按应用的实际需求在untrusted_app.te或业务专属 domain 里追加最小权限。生产环境别直接给untrusted_app开放全局写权限建议让 App 通过某个系统服务去访问 FDRAM——听起来是架构决策实际也是安全策略的一部分。如果不方便加系统服务至少用neverallow反向限制write权限给到特定子集不要把整个域都放开。5.5 现象恢复出厂后FDRAM 分区仍在但整个/frdata被 vold 格式化成了 f2fs原因vold在 wipe 数据时按分区类型执行格式化它把 FDRAM 识别成了userdata一类并套用了默认文件系统策略。这是分区标志位的锅不是 fstab 能解决的。解决回到 bootloader 分区表的.flags确认它只含PT_USER而不含继承自PT_DATA的默认格式化类型如果平台要求在fstab的fs_mgr_flags里显式check或者formattable按厂商提供的分区类型表核对。这个问题没有统一修法因为不同 BSP 对flags的语义定义不同但排查思路一致从 vold 识别到的分区 MTD 名称出发反查 bootloader 分区表。6. 进阶技巧把 FDRAM 用成“日志与缓存自愈区”FDRAM 分区的天然优势是独立于/data这意味着系统 OTA、恢复出厂、甚至/data被恶意填满时它都能保持可用。我的习惯是把它定位成“可重建的临时资源区”——存放系统日志缓冲、OTA 增量包的解压临时目录、以及大尺寸的媒体缓存。具体的进阶方案是定制一个开机后自检脚本放在init.frames.rc的on post-fs-data阶段service selfcheck_fdram /system/bin/sh /system/bin/fdram_health.sh class late_start user root disabled oneshot on property:vold.decrypttrigger_restart_framework start selfcheck_fdram脚本的核心逻辑是检查/frdata是否可写若不可写则尝试umount后重新mkfs.ext4再挂载回/frdata。这样一来绝大多数文件系统损坏场景都被自动化兜住——代价是分区内容会丢但因为定位是“可重建的临时资源”这个代价是设计上能接受的。这和把重要数据放同一个分区是两种截然不同的设计哲学FDRAM 要的是“耐操”而不是“可靠”。另一个技巧是给它设置配额逻辑FDRAM 毕竟不是无限大缓存类写入必须在脚本层做水位线控制。我通常会在fdram_health.sh里加一个df读取使用超过 90% 时按目录 mtime 顺序删除最老的缓存文件而不是等极低剩余空间导致 pstore 或 logcat 崩溃。这套“自愈配额”组合明显减少了售后设备上报“系统卡死但 /data 还有 5GB”之类的相关问题。从那以后我每接一个定制项目只要涉及新分区都会强制走一遍分区表 → dts → fstab → SELinux → 恢复出厂/OTA 验证的完整流程再补上自愈脚本而不是改完 fstab 就交付。这个顺序帮我绕开了绝大多数生产环境才暴露的深坑希望帮到你。本文还有配套的精品资源点击获取