尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Android 16系统预置微信的SELinux策略实战
前阵子接到一个终端定制的需求一台基于 Android 16 的工程机上开机就要带一个能直接用的微信。说白了就是预置应用这事儿我一开始觉得很简单——把 APK 丢进系统镜像再打包刷机三十分钟搞定。结果真正做起来才发现预置本身确实不难难的是 Android 16 这套 SELinux 权限模型。开机之后微信的日志里一屏一屏的 avc denied应用连自己该读的厂商属性都被挡在外面光排查就花了两天。这篇文章就把这个项目从头到尾复盘一遍预置方案怎么选、Android.bp 怎么写、avc 日志怎么抓怎么解读、sepolicy 策略怎么补以及我在真机上踩过的那些坑。准备做系统定制、整机方案集成或者 ROM 开发的朋友可以直接照着这条链路走。1. 预置方案的整体设计与选型1.1 先想清楚微信该放进哪个分区Android 系统里“预置一个应用”不是简单地把 APK 拷进镜像。APK 放的位置直接决定它的身份和权限等级。常见的选择有这么几类/system/app/普通系统应用/system/priv-app/特权系统应用/product/app/或/product/priv-app/产品分区应用/vendor/app/厂商分区应用Google 对预置应用的权限划分很明确放进/system/app只是普通应用放进/system/priv-app才拥有特权权限比如可以直接调用某些系统 API、参与权限白名单。但微信这种第三方应用我强烈建议第一步别碰 priv-app原因有两个。第一个是签名冲突。priv-app 里如果放的是非平台签名应用Android 9 之后会触发 privapp-permissions 强制校验。应用在 AndroidManifest 里申请的敏感权限如果没写进白名单系统会直接忽略表现出来就是微信有些功能时好时坏非常诡异。微信是官方签名不是平台签名硬放进 priv-app 等于给自己埋雷。第二个是升级和卸载的逻辑问题。priv-app 里的包在 OTA 和系统重置后表现跟普通应用完全不一样。微信这种高频更新的应用预置版本一旦比用户后装的版本低会产生降级冲突轻则无法覆盖安装重则直接导致启动崩溃。所以这个项目里我最终选择的是/system/app/WeChat/也就是普通系统应用。它不参与特权白名单又能开机常驻即使被用户卸载恢复出厂设置后也会重新出现。这个折中方案是行业里预置第三方应用最常用的位置。1.2 Android 16 对第三方预置应用的隐藏限制Android 16 这条开发线上系统对“预置第三方应用”的态度又收紧了一档。最直观的变化是 SELinux 策略结构做了不少调整很多系统服务组件被挪进了 APEX 模块文件上下文类型也跟着变。这就导致一个现象以前同一套 allow 规则在 Android 14 上能跑换到 Android 16 上就会被 neverallow 拦下来编译直接报错。另外Android 16 上第三方应用进程的默认域仍然是untrusted_app跟用户自己从应用市场下载的应用用的是同一套基础策略。换句话说系统并不会因为你把微信预置进了 system 分区就额外给它开什么后门。它能访问什么、不能访问什么sepolicy 里写得很死。很多做定制的同学第一次遇到这种情况会懵觉得“我都把应用放 system 里了怎么还没权限”其实这跟分区位置没关系SELinux 看的是进程域不是安装路径。这带来一个非常现实的问题厂商在系统里自定义的硬件节点、系统属性、特殊路径默认策略里根本不会有针对第三方应用的 allow 规则。微信一旦需要访问这些东西就会产生 avc denied。这也是这篇文章要重点解决的核心矛盾。2. 把微信编进系统镜像2.1 准备 APK 和目录结构这一步看起来简单但细节不少。我先把微信官方渠道的 ARM64 正式版 APK 下载下来放到源码树的vendor/demo/apps/WeChat/目录下。注意几个容易踩的坑不要用从其他机器上导出的“备份版”微信那种 APK 很可能已经被某些工具重签过功能正常但后续升级会出问题。下载时确认 APK 包含 arm64-v8a 的原生库。现在很多终端是纯 64 位系统如果 APK 里只有 armeabi-v7a 的 so虽然能通过兼容层跑但性能和稳定性都堪忧。如果设备内存和存储都比较紧张可以考虑微信的轻量版或定制版不过那需要商务渠道普通项目一般拿不到。目录结构很简单vendor/demo/apps/WeChat/ ├── Android.bp ├── wechat.apk我当时把 APK 重命名成了wechat.apk避免文件名里有空格或版本号造成脚本解析问题。命名越简单越好后面所有配置都围绕这个名字来。2.2 编写 Android.bp 并决定签名策略在这个 demo 项目里我用的是android_app_import模块类型因为它就是专门用来导入已经签名好的 APK 的。Android.bp 内容如下android_app_import { name: WeChat, apk: wechat.apk, presigned: true, privileged: false, dex_preopt: { enabled: true, }, installable: true, sdk_version: current, }这里最关键的配置是presigned: true表示不重新签名直接用微信官方签名。为什么不改成certificate: platform让它变成平台签名应用我实测过一旦用 platform key 重签微信系统的包管理器确实会把它当作平台签名应用但微信自己的代码在运行过程中有签名校验逻辑检测到签名不是官方的话部分功能会认为“签名异常”然后拒绝运行。轻则登录态异常重则直接闪退。所以结论很简单预置微信这种由第三方开发者签名的应用保留原签名是最省事的。每个字段的意义也顺便说一下presigned: true跳过签名步骤。privileged: false明确按普通系统应用处理。dex_preopt: enabled: true让微信的 dex 在系统编译阶段就预编译成 oat显著加快首次启动速度。这个字段对微信这种大型应用尤其重要不开启的话开机后第一次点开微信要等好几秒的 dex 优化观感很差。sdk_version: current用当前系统的 SDK 版本编译。另外强调一点android_app_import默认情况下会在 out 目录生成一个可复制的 APK 产物安装包里是否要附带这个 APK取决于你产品是否允许用户卸载并恢复出厂版本。如果业务上希望微信不可卸载可以加preserve_in_ota: true这样系统升级时不会因为分区空间清理把预置应用删掉。2.3 注册到产品配置并编译Android.bp 只是定义了模块要让编译系统真正把它打进去还要在产品 mk 文件里注册。设备相关的配置一般在device/demo/device.mk里我加了一行PRODUCT_PACKAGES WeChatPRODUCT_PACKAGES是 Soong 和 make 之间传输模块列表的通道编译系统会把里面列出的模块组装进对应的系统镜像分区。这里有个执行顺序的坑如果你的产品 mk 里有多处PRODUCT_PACKAGES 有些在 include 某些公共 mk 之后有些在之前实际生效顺序可能不一致。我的建议是把预置应用相关的行集中放在设备主 mk 文件末尾并加注释避免后续维护的人重复注册。注册好之后就可以编译验证了source build/envsetup.sh lunch demo-device-userdebug make WeChat -j32单独编译 WeChat 模块是因为第一次不要直接全量 build先确认 APK 能正确打包。编译完成后去 out 目录检查find out/target/product/demo-device/system -name WeChat*如果能看到WeChat.apk或者对应的目录说明模块编译和组装都没有问题。这时候再执行全量编译和打包镜像后面排查问题时也能排除“根本没编进去”这个低级原因。3. avc 权限问题定位与抓取3.1 avc denied 是怎么来的先补个基础背景Android 的 SELinux 默认是 enforcing 强制模式每个进程都有安全上下文。比如微信这种第三方应用进程上下文一般是u:r:untrusted_app:s0:c512,c768后面那串c512,c768是 MCS category用来隔离不同应用的私有数据。当微信去访问一个文件、属性、socket 或者 binder 接口时SELinux 会拿三个关键信息去查策略库来源上下文scontext、目标上下文tcontext、目标类别tclass再加上请求的操作许可permission。策略库里如果找不到显式的 allow 规则内核直接打回请求并记录一条 avc denied 到内核日志。很多定制工程师第一次遇到 avc denied 会慌觉得是不是系统配置错了。其实这是 SELinux 的正常工作方式没有明确允许的权限一律默认拒绝。定制系统里出现 avc denied通常不是系统故意不给微信权限而是那些厂商自定义的节点、属性、外设路径原来的策略文件里根本没覆盖到。你需要做的不是诅咒 SELinux而是把这些缺口按规范补上。3.2 抓取 avc 日志的正确姿势抓日志的方法我推荐三种组合起来用# 方法一直接从内核日志抓 adb shell dmesg | grep avc # 方法二通过 logcat 的内核 buffer 抓 adb logcat -b kernel -d | grep avc # 方法三实时监控触发问题时边操作边看 adb shell dmesg -w | grep avc --line-buffered第三种方法是我最常用的。把微信打开然后逐个功能去点比如扫码、选图片、看视频每个动作触发的问题都会实时刷出来。这样后面定位“是哪步功能导致的 denied”就非常精准不用对着几百条日志瞎猜。一条典型的 denied 日志长这样type1400 audit(0.0:1251): avc: denied { read } for pid1234 commWeChat namedemo_status devtmpfs scontextu:r:untrusted_app:s0:c512,c768 tcontextu:object_r:vendor_demo_prop:s0 tclassfile怎么读我拆解一下denied { read }被拒绝的操作类型。pid1234 commWeChat哪个进程触发的。namedemo_status被访问对象的名字。scontextu:r:untrusted_app:s0:c512,c768来源域微信进程。tcontextu:object_r:vendor_demo_prop:s0目标类型厂商自定义的 demo_prop 属性。tclassfile目标类别是文件。后面写策略时就是根据这些字段反推出对应的 allow 规则。所以抓日志的时候别偷懒最好按功能把日志分段保存每条标注上“当前在操作什么”这样写策略时一目了然。3.3 微信在定制终端上最常见的几类 denied我们这个项目里微信集中遇到的拒绝有以下几类应该能代表大多数定制场景。第一类读厂商自定义属性。终端设备加了扫码枪、钱箱检测之类的硬件能力厂商在系统里定义了一个vendor.demo.hw.status属性SELinux 类型是vendor_demo_prop。微信的一个辅助模块会尝试读这个属性来判断设备形态于是被拒avc: denied { read } for namedemo_status devtmpfs scontextu:r:untrusted_app:s0:c512,c768 tcontextu:object_r:vendor_demo_prop:s0 tclassfile第二类访问外设节点。终端外接打印机、刷卡器时微信如果想要通过vendor_demo_device类型的节点探测硬件状态会触发对目录或设备文件的 deniedavc: denied { write } for nameprinter devtmpfs scontextu:r:untrusted_app:s0:c512,c768 tcontextu:object_r:vendor_demo_device:s0 tclassdir第三类尝试设置调试属性。微信某些版本为了排查问题会尝试写debug.xxx属性。这种属性在 userdebug 固件上通常能写在 user 版本上会被严格拒绝avc: denied { set } for propertydebug.wechat.log scontextu:r:untrusted_app:s0:c512,c768 tcontextu:object_r:debug_prop:s0 tclassproperty_service这里要提醒一句这些 denied 日志并不代表微信在“做坏事”很多就是厂商自定义节点缺少预置规则。你要做的是逐条判断是否合理而不是一股脑全 allow。4. 编写 SELinux 策略与编译4.1 先想清楚动全局还是给微信单独建域面对 avc denied最直接的想法是往system/sepolicy/private/untrusted_app.te里加 allow 规则。这样做有效但它是全局生效的意味着所有第三方应用包括用户之后自己安装的任何 App都会继承这个权限。如果只是读一个无关紧要的属性问题不大但如果是外设节点或者调试属性等于给所有第三方应用开了一扇门风险很高。我当时做了一个取舍项目时间紧目标设备是行业专用终端不开放第三方随意安装应用安装源可控所以先在untrusted_app域上把必要的读属性权限补上联调通过后再考虑把微信收进独立域。如果你的产品是公版设备、应用市场随意安装就一定不要图省事建议给微信单独分配一个 SELinux 域。给应用单独建域主要走这几步在system/sepolicy/private/seapp_contexts里给微信的包名和签名指纹分配一个自定义 domain。在system/sepolicy/private/mac_permissions.xml里把微信的签名指纹对应到 seinfo 标签。新建一个wechat_app.te声明type wechat_app, domain;然后通过typeattribute wechat_app app_api;让它继承所有普通 App 的基础权限再额外补厂商自定义节点的规则。seapp_contexts里的写法大致是这样的useruntrusted_app seinfowechat domainwechat_app namecom.tencent.mm typeapp_data_file levelFromall useruntrusted_app domainuntrusted_app注意最后一行必须保留兜底规则否则任何不在白名单里的第三方应用都会因为找不到匹配项而无法创建进程。wechat_app.te里则类似type wechat_app, domain; typeattribute wechat_app app_api; allow wechat_app vendor_demo_prop:file { read open getattr }; allow wechat_app vendor_demo_device:dir { open read search }; allow wechat_app vendor_demo_device:file { read write open getattr };这个方案的好处是权限边界非常清晰只给微信开的口子不影响其他应用。缺点是要维护 mac_permissions.xml 里的签名指纹如果 APK 升级换了签名还需要同步改配置维护成本略高。4.2 怎么从 avc 日志生成可用的规则如果 denied 条目很多手工一条条写会漏。这时可以直接用audit2allow工具。源码树里编译产物自带这个工具也可以把设备上的策略文件拉回来解析adb shell cat /sys/fs/selinux/policy policy audit2allow -p policy -i dmesg_avc.txt它会输出一组 allow 建议例如allow untrusted_app vendor_demo_prop:file { read open getattr };但记住一点audit2allow 给的只是“满足日志”的最小集合不是“安全”的最小集合。比如日志里出现{ read }它可能会顺带把open getattr ioctl都补上这些关联权限在多数场景下合理但你要自己判断是否过界。我在项目里会把生成结果跟设备需求逐条过一遍拿不准的规则宁可先不 allow用setenforce 0临时验证当前功能到底缺的是不是这条权限。4.3 编译、验证与回归写完策略后需要重新编译对应镜像。因为策略文件在system/sepolicy下正常情况下需要重新打包整个系统镜像make -j32刷机后先确认 SELinux 处于 enforcing 模式再看看微信相关的 denied 是否消失adb shell getenforce adb shell dmesg | grep avc: denied | grep WeChat如果微信相关 denied 已经清空再做一轮完整功能回归。我自己的回归清单包括微信冷启动、扫码/拍照/相册选择、收发消息、文件下载、语音/视频通话。每一项都要实际操作一遍因为有些权限是延迟申请的启动不触发一拍照才触发。另外要特别提醒setenforce 0只能在 userdebug 或 eng 版本上临时用user 版本不允许执行。它只用来做定位定位完马上setenforce 1恢复强制模式千万不要带着宽容模式去验收那样所有权限问题都会被掩盖。5. 常见问题与排查技巧实录5.1 问题速查表我把这个项目里遇到的高频问题和对应的处理思路整理成了表格方便后面直接查。现象可能原因处理办法开机后没有微信图标PRODUCT_PACKAGES 未生效或 APK 没编译进去检查 out 目录单独 make WeChat 后重新打包微信首次启动卡在加载界面dex 未预编译或 SELinux 阻止读取某些数据目录确认 dex_preopt 已开启抓 avc 日志定位微信点开就闪退签名被重签或 APK 架构不匹配重新使用官方 APK去掉 platform 签名配置无法扫码或相机黑屏相机权限未授予或相机 HAL 的 SELinux 规则缺失先检查运行时权限再抓 avc 日志收不到消息推送后台限制、doze 省电策略或厂商自定义电池管理拦截检查电量和后台白名单先别怀疑 SELinux相册选图空白分区存储权限问题或 FUSE 路径访问被拒检查本地存储权限抓 avc 日志确认OTA 升级后微信消失预置 APK 所在分区被覆盖或清理将预置目录写入持久化配置并开启 preserve_in_ota表格里的前两项是最常见的几乎每个做预置的项目都会遇到。如果你发现自己改了 PRODUCT_PACKAGES 但编译产物里没有优先检查是不是模块名写错了或者 Android.bp 里用了android_app_import但 APK 路径没配对Soong 在解析阶段就会报错。5.2 几个容易被忽略的低级坑第一个坑是 APK 更新后没有清掉 out 目录里的旧产物。我遇到过改完 APK 重新编译刷机后还是旧版本的情况排查半天发现是 out 目录缓存没刷新。做预置应用调试时每次替换 APK 后建议顺手删掉out/target/product/xxx/system/WeChat目录再重新 make避免走弯路。第二个坑是忽略老数据残留。如果这台工程机之前通过 adb install 装过同签名的微信预置新微信后系统会做包管理校验报INSTALL_FAILED_UPDATE_INCOMPATIBLE。最干净的办法是刷机前做一次 userdata 全清或者在验证脚本里加一步pm clear com.tencent.mm。否则你会以为是 SELinux 问题实际上纯粹是数据残留冲突。第三个坑是日志抓取时机太晚。avc denied 是内核实时打的如果问题已经发生完回头再看日志可能会被其他应用的海量 denied 刷屏。尽量用dmesg -w实时看配合复现操作一次抓一条精准定位。第四个坑是编译选错策略目录。Android 的 sepolicy 分散在system/sepolicy、vendor/sepolicy和device/.../sepolicy等多个目录不同分区有不同归属。如果你改的规则涉及 vendor 属性却写进了 system 目录有可能引用不到对应的类型。所以加规则前先确认tcontext里的对象类型归属哪个目录再决定策略文件放哪里。如果是 vendor 自定义节点的 deny很多情况下要写在vendor/sepolicy下。5.3 排查顺序建议最后给一个我自己习惯的排查顺序可以帮你少走很多冤枉路先用pm list packages | grep tencent确认微信已经安装。再用adb shell dmesg | grep avc抓一次日志确认有没有 avc denied。没有 denied 但功能异常就去查运行时权限和组件禁用状态。有 denied则按 3.2 的方式实时跟踪逐条分析确认该不该补规则。补完规则重新编译再回归回归通过才收工。把“先确认权限再调功能”这个顺序刻在脑子里。我见过不少同事一上来就改 sepolicy最后发现其实是应用自身的权限弹窗没点白忙活一场。最后再分享一点个人体会说实话这次预置微信处理 avc 权限整个过程最耗时的不是写 allow 规则而是判断每一条 denied 到底合不合理。SELinux 的设计思路本来就是“默认拒绝”它不会告诉你怎么做才安全只会告诉你“不行”。你需要自己去理解业务场景理解微信为什么访问这个节点才能做出准确的授权决策。另外独立域方案虽然前期麻烦一点但长期维护省心。下次如果再做类似项目我会第一时间就把微信单独拉一个 SELinux 域而不是先用全局授权跑通再回头改。很多问题当时觉得时间紧先凑合后面会花更多时间还债这个教训我算是深刻体会到了。希望这篇复盘能帮正在跟 avc 较劲的同学省下几个晚上。
RELATED

相关推荐

小艺接入openclaw智能体:HarmonyOS 6语音入口实战全解析

小艺接入openclaw智能体:HarmonyOS 6语音入口实战全解析

小艺明明能听懂我的话,却总在关键问题上给我一句"我还没有学会这个功能",这种感觉大概每个折腾过智能家居的人都懂。我最近在HarmonyOS 6上做的一个项目,就是想彻底解决这个尴尬——把小艺的语音入口和openclaw智能体框架打通&…

📅 2026/10/20 15:03:06
NoFuserEx反混淆实战:拆解.NET程序集保护与还原链路

NoFuserEx反混淆实战:拆解.NET程序集保护与还原链路

简介:NoFuserEx 是一款面向逆向工程与恶意代码分析场景的 .NET 反混淆工具,主要用于还原被混淆器保护的程序集,帮助安全研究员、红队成员以及 .NET 开发者在缺乏源码的情况下恢复可读的代码逻辑。压缩包共 10 个文件,大小仅 1.76M…

📅 2026/10/20 15:03:06
STM32单片机FFT实战:从采样到频谱的避坑指南

STM32单片机FFT实战:从采样到频谱的避坑指南

简介:这份资源面向嵌入式开发初学者与数字信号处理方向的工程师,围绕STM32F1系列单片机(ARM Cortex-M3内核)讲解并实现快速傅里叶变换,帮助读者在资源受限的MCU上完成时域到频域的转换,适用于通信、音频与图…

📅 2026/10/20 15:03:06
MORE NEWS

更多资讯

📰

React核心知识点实战复盘:组件设计、状态管理与渲染优化

做前端这些年,React 是我用得最多、也踩坑最多的一套框架。老实说,网上的教程和文档写得很全,但零零散散读完总有种"我知道了,可一到项目里还是慌"的感觉。这篇笔记就是把我自己工作里反复用到的 React 核心知识点——从…

📰

Afkayas.2 CrackMe 逆向实战:从脱壳到注册机

说句实在话,CrackMe 这玩意儿在很多人眼里就是个“破解练习”,但在逆向圈子里,一套精心设计的 CrackMe 往往比好几本教程都管用。Afkayas 系列作为经典的入门序列,里面的手法覆盖了字符串定位、API 断点、关键跳转分析、算法还原这…

📰

diagram-design:如何设计可维护的架构图与流程图

1. 从一张草图到一套系统:diagram-design 到底在解决什么问题 第一次看到 “diagram-design” 这个标题,很多人会以为它只是教你怎么画流程图、架构图或者线框图。但真正做过项目的人都知道,图不是画给自己看的,而是画给未来的自己…

📰

PHP批量删除MySQL相同前缀数据表:高效安全的运维实践

简介:这是一份针对MySQL数据库批量清理场景的PHP源码工具,可根据指定前缀一次性删除匹配的数据表,主要面向开发、测试及运维人员,解决手动逐表删除效率低、易出错的问题,尤其适合清理临时表或重置项目数据。压缩包仅含…

📰

ArcGIS符号库本质与正确加载方法

简介:本资源是面向GIS从业者、测绘制图人员及高校地理信息专业学习者的ArcGIS专业符号库集合,解决地图制图中符号缺失、风格不统一、标准化程度低等实际问题。压缩包共142个文件,含74个.style样式文件(定义点线面符号规则&#xf…

📰

PPT制作效率革命:用工程化思维管理演示文档生产流程

1. 项目缘起与核心定位第一次看到“ppt-master”这个标题,我脑子里蹦出来的第一个念头是:又是一个想教人做PPT的?市面上讲PPT技巧的内容已经多到泛滥,从排版四原则到配色方案,从字体搭配到动画节奏,几乎每个…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬