news 2026/10/21 10:18:37

RK3588 Android 12设备权限修改:从chmod到SELinux

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RK3588 Android 12设备权限修改:从chmod到SELinux

1. 场景先行:你遇到的"设备权限问题"到底属于哪一类

经常有做 RK3588 项目的朋友问我类似的问题:"我在 Android 12 上访问 /dev/ttyS4 报 permission denied,设备权限怎么改?" 说实话,这个问题没法用一句"chmod 777"打发。RK3588 是当下很多 AIOT 设备和开发板在用的平台,Android 12 的权限管理又比老版本严格不少,如果你一上来就闷头改文件权限,很容易陷入"改了没用、重启失效、才改完又被审计拦下来"的连环坑。

我自己就在一块 RK3588 板子上栽过跟头。当时要调试一个串口外设,应用层通过 JNI 去open("/dev/ttyS4", O_RDWR),结果返回失败。第一反应是看节点权限:adb shell ls -l /dev/ttyS4,输出是crw-rw---- root root。应用跑在普通 app 的 uid 下,确实没有读写资格。于是我想当然地执行了chmod 666 /dev/ttyS4,功能立刻通了,但重启后权限全部还原。接着我又试图把这条命令固化到 init.rc 里,编译烧录后发现还是不行——因为 Android 12 默认开着 SELinux 的 enforcing 模式,文件权限放开了,安全策略照样把你拦在门外。那次之后,我把整个权限链路从头到尾捋了一遍。

先说清楚一个概念:在 RK3588 Android 12 系统里,"设备权限"从来不是单一的一件事,而是由三层共同决定。

  • 设备节点的 mode 和属主:比如/dev/ttyS4是 0660 还是 0666,属主是root:root还是system:shell。这是最直观的一层,ls -l就能看到。
  • 设备节点的创建逻辑:节点不是天生存在的,是 init/ueventd 收到内核事件后创建出来的,创建时的权限由配置文件决定。临时手动chmod一旦碰到节点重建就会被覆盖。
  • SELinux 安全策略:即便 chmod 给了读写权限,SELinux 在 enforcing 模式下仍会通过类型规则决定某个进程能不能访问该节点。这是最隐蔽、也最容易被忽略的一层。

这三层分别对应不同的改法。先分清你卡在哪一层,再决定动哪个文件。

1.1 一段典型的 RK3588 串口调试经历

我接手那个项目的时候,设备是一个基于 RK3588 的工控盒子,系统版本是 Android 12,底板上引出了几路串口和 I2C。需求很简单:系统里安装一个控制类 App,通过串口跟外设通信。App 的 native 层代码很直白:

int fd = open("/dev/ttyS4", O_RDWR | O_NOCTTY); if (fd < 0) { // 报错 }

编译、安装、运行,结果就是打不开。第一层我确认过,节点存在,权限是crw-rw----,属主 root。App 不属于 root,不属于 system 组,自然没权限。当时我的第一个动作是临时验证,用了最快但最粗暴的方式:

adb root adb shell chmod 666 /dev/ttyS4

App 再跑,通了。可这只能证明"改设备节点权限确实能解决问题",离真正交付还差得远。重启后节点权限大概率被 ueventd 按配置重置,同时系统审计日志里也留下了一堆 SELinux 的 denied 记录。这一步其实很有价值:它帮我确认了问题确实出在权限层,而不是驱动、管脚复用或者串口配置。后面要做的,是把这种"手工生效"变成"系统启动就是正确的状态"。

1.2 三类最常见的权限诉求

在实际 RK3588 项目里,我见过的大多数"修改设备权限"需求可以分成三类:

第一类是应用层访问外设节点。比如 App 要操作串口、GPIO、I2C 或者 SPI 设备,典型表现就是open()返回Permission denied。这类问题的解决路径最完整,需要同时处理节点权限和 SELinux 策略。

第二类是系统服务或开机脚本需要访问某些节点。比如某个 vendor 进程要在 boot 阶段读写一个传感器节点,或者 init.rc 里想 cp 一个文件到 /data 目录但权限不足。这类问题通常涉及 init.rc / ueventd.rc 里的chmod、chown配置,以及对应 service 的 SELinux 域。

第三类是纯开发调试期的临门一脚。只是为了在开发阶段快速验证硬件通路,想在 userdebug 版本上临时放权,不考虑交付。对这种需求,有时候一条setenforce 0加chmod 666就够用了,但千万不要把这种做法直接搬进量产固件。

分清这些,后面的操作才有针对性。

2. 权限体系解剖:RK3588 上 Android 12 的三道门

我在接触 RK3588 的 Android 12 之前,对"权限"的理解基本停留在chmod和chown。但在实际项目中你会发现,这两条命令只是表象,真正决定你有没有权限访问一个设备节点的,是下面这三道叠加在一起的门。

2.1 第一道门:/dev 节点 mode 与属主

所有设备节点在 Linux 里本质都是特殊文件,有自己的一套属主、属组和权限位。RK3588 板子上常见的/dev/ttyS0、/dev/gpiochip0、/dev/i2c-1、/dev/spidev2.0都是这样。

这个 mode 是谁决定的?内核里的 devtmpfs 会在设备注册时自动生成节点,但具体权限通常由 Android 的 ueventd 根据配置文件在创建节点时指定。举个例子,一条典型的 ueventd.rc 配置是:

/dev/ttyS4 0660 root system

意思是这个节点属主是 root,属组是 system,权限是crw-rw----。如果 App 进程既不是 root,也不属于 system 组,那就没有读写权限。

这里有个绝大多数人都会忽略的细节:你手动执行chmod改掉的权限,只对"当前存在"的那个节点有效。一旦设备节点被内核事件重新触发创建,比如串口重新 probe、USB 设备重新插拔、系统重启,权限又会回到配置文件里定义的样子。所以手工chmod从来不是交付方案,只是排查手段。

2.2 第二道门:init/ueventd 的权限管理逻辑

Android 启动过程中,init 进程会启动一个 ueventd 的子进程。ueventd 的作用是监听内核的 uevent,收到事件后负责在 /dev 下创建对应的节点、设置软链接,并按照配置文件给节点赋权限。

ueventd 读的配置主要是各个分区里的ueventd.rc文件。RK3588 的 SDK 里,设备的 ueventd.rc 通常放在设备目录下,比如类似device/.../rk3588/ueventd.rc这样的地方,同目录下还可能存在按模块拆分的子文件。不同平台的习惯不太一样,但逻辑是统一的:找对 ueventd.rc,在里面加一行节点权限规则,系统每次创建设备节点时都会按这个规则来。

不过 ueventd.rc 也有管不到的地方。它主要在设备节点创建时生效,而 sysfs 里许多属性文件、debugfs 下的调试接口、还有一些用 misc driver 注册的逻辑节点,并不一定走标准的 devtmpfs 流程。这时候更多会借助 init.rc 里的启动阶段命令。

init.rc 是 init 进程的主脚本,支持在on boot、on property:xxx等触发点执行chmod、chown、mkdir等命令。比如:

on boot chmod 0666 /sys/class/.../attr chown system system /sys/class/.../attr

这种方式灵活,但有执行时机的问题:如果触发时节点还没创建,命令就会静默失败。所以工程上我一般优先用 ueventd.rc 管 /dev 节点,用 init.rc 补 sysfs 和特殊路径。

2.3 第三道门:SELinux 的 avc 拦截机制

这是 RK3588 Android 12 里最容易出问题、也最让新手困惑的一层。SELinux 会给每个进程打一个安全上下文标签,比如u:r:untrusted_app:s0,给每个文件/设备节点也打一个标签,比如u:object_r:tty_device:s0。进程访问节点时,系统不仅在文件权限层校验 uid/gid,还要在安全策略层判断"这个进程域有没有权访问那个对象的类型"。

判断的依据是 policy,由一堆 .te 文件在编译时生成。一旦策略里没有对应的 allow 规则,访问就会被拒,内核在 dmesg 里打印一条类似这样的日志:

avc: denied { open } for pid=1234 comm="xxx" path="/dev/ttyS4" dev=tmpfs scontext=u:r:untrusted_app:s0 tcontext=u:object_r:tty_device:s0 tclass=chr_file

注意,即使你把 /dev/ttyS4 的 mode 改成了 0666,App 的 uid/gid 已经放行,只要 SELinux 还在 enforcing 模式,这条 avc 拒绝依然会把 open 拦下来。我见过太多人在这层上面两眼一抹黑:文件权限明明都对了,App 还是打不开设备,最后查下来是 SELinux 的策略没放行。

2.4 Android 12 对 SELinux 的强化点

Android 12 相比 Android 9/10,最大的感觉是"不再给你那么多偷懒空间"。一是 neverallow 规则更多,以前经常用的某些宽泛放行写法在编译阶段就直接被拒绝;二是 vendor 和 system 的分离更彻底,修改 system 镜像还牵涉启动校验的问题;三是 treble 化之后,权限策略被拆成 system 和 vendor 多段,单独改一边不一定有用。

在 RK3588 的 userdebug 版本上,你可以通过adb root后setenforce 0临时关掉 SELinux 来做硬件调试,但量产固件基本都在 enforcing 模式下运行。开发阶段能用 permissive 快速验证功能,交付阶段如果还是 permissive,上线后大概率会在安全审计上出问题,而且平台的 neverallow 链路也可能禁止你整体修改为 permissive。正确做法是:临时关掉只是确认问题,最终一定要把精确的 allow 规则写进 policy。

3. 权限修改实操:从临时验证到固化烧录

现在说具体怎么做。我通常会按"先临时验证,再固化配置,最后补 SELinux 策略"的顺序推进,每一步都有它存在的理由。

3.1 第一步:adb shell 临时验证功能链路

拿到一个报权限问题的 RK3588 设备,我推荐先不要急着改代码。先确认整条硬件链路是不是通的。具体操作:

adb root adb wait-for-device adb shell chmod 666 /dev/ttyS4 adb shell chown system:system /dev/ttyS4

然后跑你的 App 再试一次。如果通了,说明设备节点权限确实是最主要的瓶颈。如果还不行,那问题可能就不在权限上,而是在驱动注册、设备树配置、管脚复用或者 open 方式上,比如你 open 的是错误节点,或者设备根本没 probe。

这一步的价值是快速把"权限问题"和"非权限问题"切分开。我习惯把这一步的结果记录在案,后面所有固化操作都以这个基线为准。还有个细节:adb root只存在于 userdebug/eng 版本,release 版本没有这个入口。如果你手里的机器是 release 固件,开发期最好先让编译版本切到 userdebug,否则后面的大多数排查手段都用不上。

3.2 固化方式一:ueventd.rc 指定节点属性

临时验证通过后,第一件要做的事就是把权限写进 ueventd.rc,让系统每次创建设备节点时都按你的规则来。

以 RK3588 平台的 SDK 为例,设备相关的 ueventd.rc 一般位于设备板级目录下,比如类似device/.../rk3588/ueventd.rc的路径,也可能有按产品型号拆分的ueventd.<产品>.rc。找到内容后,在文件里增加一行:

/dev/ttyS4 0666 system system

这行的格式是:节点路径、mode、属主、属组。注意,这里的路径要跟设备实际上报的 devname 一致,不能用软链接路径,因为 ueventd 先创建设备文件,之后才处理 symlink。如果你不确定该改哪个文件,可以先用下面命令看 ueventd 实际加载了哪些配置:

adb shell ls -l /dev/block/by-name/ # 不重要 # 更直接的是: adb shell ps -A | grep ueventd

实际上更实用的方法是直接查看当前节点的权限来源。对已经存在的节点,比较难反查它来自哪个配置文件,最稳妥的做法是全源码搜索你要修改的节点路径,看它在哪个 ueventd.rc 或 init.rc 中出现过。如果整个 SDK 里都搜不到,说明节点走的是内核默认的 devtmpfs 权限(通常 0600 root root),这时新增一行 ueventd.rc 规则就是正确解法。

3.3 固化方式二:init.rc 里补 chmod/chown

ueventd.rc 适合管 /dev 下标准设备节点,但有些文件它管不了,典型包括 sysfs 导出的属性文件,比如背光亮度、GPIO 的 direction/value,以及部分 debugfs 节点。这些文件往往在系统启动过程中由内核动态创建,权限默认是0444或者更严格。需要放开的时候,我会在 init.rc 里加启动命令。

常见的写法是这样:

on boot chmod 0666 /sys/class/gpio/gpiochip0/device/direction chown system system /sys/class/gpio/gpiochip0/device/direction

或者针对需要等待设备真正 ready 的场景,用属性触发:

on property:sys.boot_completed=1 chmod 0666 /sys/class/.../attr

这里要注意两条:第一,init.rc 里的脚本命令在目标文件不存在时会直接返回失败,不会报错也不会重试,所以如果你发现节点确实存在但命令没生效,优先怀疑执行时机太早;第二,chmod/chown 的对象路径如果带有通配符,语法和匹配规则跟 shell 里不完全一样,尽量写全路径,减少意外。

3.4 固化方式三:为 App/服务补充 SELinux 规则

这一步才是真正解决"为什么 chmod 后 App 还是访问不了"的关键。SELinux 的规则写在 .te 文件里,编译时被打进 sepolicy。RK3588 Android 12 的 SDK 里,sepolicy 相关代码分布在 system/sepolicy、vendor 相关目录以及设备板级目录下。常见需要改的地方有几类:

第一类,给 App 访问设备开绿灯。理论上 Android 不允许普通 App 直接访问任意设备节点,很多产品会把访问逻辑封装在一个特权服务里,App 通过服务间接操作。如果你的产品确实需要让某个 App 直接访问串口,一种相对可控的做法是把这个 App 指定为 system_app 或 privileged_app,然后在对应的 te 文件里追加 allow 规则。

例如在untrusted_app.te里:

allow untrusted_app tty_device:chr_file rw_file_perms;

但这么做有风险。Android 12 的 neverallow 规则经常禁止 untrusted_app 直接访问这类节点,编译时就会报错。更常见的做法是给特定场景单独定义一个类型,或者使用vendor_file域的服务去处理。不要为了省事对所有域通配放行,平台的 neverallow 会教你做人。

第二类,给系统服务或 vendor 进程放行。操作对象通常是你在 init.rc 里启动的某个自定义服务,你需要确认它的 domain 以及它访问节点的类型。比如你的服务域是myservice,节点上下文是tty_device,那么:

allow myservice tty_device:chr_file rw_file_perms;

第三类,修改节点的 SELinux 标签。这一步经常被忽略。即使你写了 allow 规则,如果节点的安全上下文不是你预想的类型,规则就不匹配。RK3588 上有file_contexts文件负责给 /dev 下的节点打标签。你可以给特定节点指定一个单独类型,比如:

/dev/ttyS4 u:object_r:tty_device:s0

如果节点没匹配到 file_contexts 里的规则,它会被打上默认标签,可能是device,也可能是tmpfs,这样你的 allow 规则可能就完全落空了。

4. 编译烧录与验证的完整闭环

权限改完不是说"存个文件就完事"。RK3588 Android 12 的分区结构决定了你改了不同位置,要编译烧录的镜像完全不同。这一节我重点说说怎么把这些改动变成设备上真正生效的状态。

4.1 哪些改动对应哪些分区与镜像

我习惯先列一张表,每次改完照着查:

修改的位置大致对应的镜像/分区说明
device 板级目录下的 ueventd.rcvendor 相关分区 / vendor_boot节点权限配置属于 vendor 侧
init.rc / init.xxx.rcboot / vendor_boot取决于具体平台的分区策略
system/sepolicy 下公共策略boot 中的 sepolicy / system 分区改动 system 侧 policy 通常影响 boot 镜像
设备板级目录下的 sepolicy 策略vendor 相关分区 / bootvendor 域的规则一般进 vendor_boot 或 boot
file_contextsboot / vendor标签文件影响节点安全上下文

这个表格在不同 SDK 版本上会有细节差异,但原则一致:vendor 相关文件尽量打包进 vendor/vendor_boot,system 相关文件打包进 system/boot。RK3588 平台因为 GKI 内核的引入,boot 镜像里通常会带一版 sepolicy,vendor_boot 里也带一段 vendor sepolicy,两边编译时合并。你改了 vendor 侧的 .te 文件却没烧 vendor_boot,现象就是"我明明改了,重启后还是 denied"。

具体到编译动作,一般是先执行 SDK 提供的打包命令生成对应镜像。举例来说,如果只改了设备目录下 ueventd.rc 和 vendor sepolicy,我通常会编译并烧写 vendor_boot 和 vendor 镜像。改完没必要整包刷机,烧对应分区能省很多时间,但前提是你清楚自己改的内容落在哪个分区,否则烧了等于没烧。

4.2 权限生效后的自查命令与检查项

烧录完成、系统重新起来之后,我有一套固定的检查命令,基本能覆盖上面说的三层门:

# 1. 看节点权限和属主 adb shell ls -l /dev/ttyS4 # 2. 看节点 SELinux 标签 adb shell ls -Z /dev/ttyS4 # 3. 看当前 SELinux 模式 adb shell getenforce # 4. 实时抓 avc 拒绝日志 adb shell dmesg | grep avc adb logcat -d | grep avc

一个健康的最终状态应该是:ls -l显示你预期的 mode 和属主;ls -Z显示你在 file_contexts 里定义的标签;getenforce是 Enforcing;dmesg里没有新的 avc denied。如果节点权限对了、标签也对了,App 依然报错,再看一下 App 进程的 uid 和 domain:

adb shell ps -A -Z | grep 你的包名

对应 App 的 domain 需要和你在 allow 规则里的 scontext 一致。如果 App 的 domain 是untrusted_app,而你给priv_app写了规则,那自然还是不行。

4.3 一个完整的验证清单

我把这些整理成一个清单,方便项目里传阅:

  1. 确认/dev/ttyS4节点存在,ls -l权限符合预期。
  2. 确认ls -Z标签符合预期。
  3. 确认getenforce为 Enforcing。
  4. App 重新打开设备,看是否成功。
  5. dmesg和logcat中不再出现新的 avc denied。
  6. 拔插相关设备或重启系统,确认权限仍然正确。
  7. 如果用 init.rc 命令改的 sysfs 属性,确认触发时机准确,节点出现后属性确实被改掉。

这个清单最大的价值是防止"开发机上是好的、量产机上就失效"。比如你只在 userdebug 上验证过,重启后没问题,但量产固件是 user 版本、没有 adb root、SELinux 又是 enforcing,情况就会完全不同。

5. 排错实录:我在这块板子上踩过的几个权限坑

做 RK3588 几年下来,权限问题的坑我基本都踩了一遍。下面这几个例子不是理论推演,都是实际调试中反复遇到过的场景,写出来供大家排错时对照。

5.1 坑一:改了 ueventd.rc 权限却不生效

有一回我在一台 RK3588 设备上要放开/dev/ttyS1的权限,在 ueventd.rc 里加了一行0666 root root,编译烧录后一看,节点权限还是老的crw-rw----。当时我一度怀疑是不是编译缓存问题,后来发现是配置文件根本没被加载。原因很典型:平台有多个 ueventd.rc,系统实际加载的是根据硬件型号拼出来的ueventd.<产品名>.rc,而不是我一直改的那个公共ueventd.rc。

排查办法也很简单:先看当前加载的配置文件路径。在 init 执行早期,日志里会打印加载了哪些 ueventd 配置文件,或者去源码里 grep 一下产品型号相关的 rc 文件。确定文件改对后,再检查编译产物是否真的包含这个修改,很多时候问题出在镜像没烧对分区,而不是配置本身写错。

5.2 坑二:avc denied 反复出现,明明 allow 规则写了

这类问题最容易让人怀疑人生。你明明在某个 .te 文件里加了 allow 规则,重新编译烧录后 dmesg 里却还在刷同样的 avc denied。我遇到过两个可能。

第一个是 file_contexts 没配对。例如我允许某个进程访问tty_device类型,但实际节点的 SELinux 标签是device,因为文件上下文里那条/dev/ttyS4的规则没有生效,节点落到了默认标签上。allow 规则写的是tty_device,实际访问的是device,两边对不上,自然继续被拒。

第二个是修改的 policy 没有打进对应的镜像分区。treble 化之后 vendor policy 和 system policy 分离,你改了 system 侧的公共规则,却只烧了 vendor 分区;或者改了 vendor 侧规则,只烧了 system 分区。它不会报错,但行为就是"规则不存在"。遇到反复 avc denied,先别急着加新规则,而是把你改的文件落到了哪个分区这件事查清楚。

5.3 坑三:App 通过 JNI 访问串口还是失败

有次一个合作方找到我,说 RK3588 Android 12 上,App 在 debug 状态怎么都正常,一旦切到 user 版本就彻底打不开串口。我们远程查了两天,最后发现是 App 的 SELinux domain 不同。debug 版的 App 是用包管理器安装的,domain 是untrusted_app,而合作方为了获取特权,把 App 放进了系统的 priv-app 目录,并且声明了 privileged 权限,于是它的 domain 可能变成了priv_app。我们一开始只给untrusted_app写了 allow,所以 privileged 模式下反而被拦。

这类问题提醒我:排查 avc 日志时,一定要确认 scontext 和 tcontext 两侧分别是什么,然后把规则写到对的那个 domain 上。用日志里的实际字符串写规则,而不是靠猜。看到avc: denied { open }就以为加一条allow xxx tty_device:chr_file open就结束,往往只是开始的一半。

5.4 通用排查链路

最后我把排查权限问题的链路整理成一个固定套路,基本能覆盖 80% 以上的场景:

第一步,确认硬件链路。节点是否存在,驱动有没有 probe,dmesg | grep ttyS4有没有异常。硬件没起来就改权限,纯属缘木求鱼。

第二步,确认文件权限层。ls -l看 mode 和属主。不确定的话,在 userdebug 上 adb root 后手动chmod 666测试。通了说明问题在文件权限;不通则往驱动、设备树方向排查。

第三步,确认 SELinux 层。getenforce看当前模式;如果 enforcing,抓dmesg | grep avc,看有没有和你的进程/节点相关的拒绝记录。有 denied 就按 scontext、tcontext、tclass 精确补规则。

第四步,固化修改。把临时命令转成 ueventd.rc / init.rc / .te 文件,确认落在哪个分区,重新编译烧录。

第五步,重启复验。重点检查两层:权限是否还在,avc 是否继续刷。如果重启后恢复到旧权限,说明 ueventd.rc 没有被正确加载或没被打进镜像。

这套链路我从 RK3588 一直用到其他平台,总体思路都是通用的,差别只在具体文件路径和分区名。

6. 最后再分享两个小技巧

写到这儿,该讲的链路基本都覆盖了,最后分享两个我在实际项目里觉得很重要的小习惯。

第一个习惯是:所有权限修改尽量收敛在 vendor 分区侧。RK3588 Android 12 的项目里,vendor 侧改动比 system 侧改动好维护得多,而且不依赖全局镜像重刷。比如设备和产品相关的 ueventd.rc、vendor 域的 sepolicy,都优先放到设备板级目录下,不要动 system/sepolicy 公共部分。这样不同产品型号之间的权限配置隔离得更干净,升级系统版本时也少一些冲突。

第二个习惯是:把每一个权限改动都记录清楚"为什么要放"和"放给谁"。权限问题最怕的就是"顺手开个权限",最后根本不知道哪个域因为哪条需求被放开。项目里我习惯在 commit message 里写明白:节点路径、目标 domain、触发场景、对应的应用需求单号。等哪天出安全审计或者 after 版本升级,这份记录能帮你省下好几个通宵。

RK3588 + Android 12 的设备权限修改,说难其实不难,本质就是厘清设备节点权限、初始化配置、SELinux 策略这条链路,按顺序一步步来。真正做到位的标志不是"我现在能访问了",而是"重启之后、换一台机器之后、从 userdebug 换成 user 之后,依然能访问"。祝各位调试顺利,少遇几个坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 10:18:14

AOSP定制:设置界面输入法列表按包名过滤的完整方案

前两天有同行在群里问了个挺实际的问题&#xff1a;做一个AOSP定制系统&#xff0c;客户要求设置里的“语言与输入法”列表&#xff0c;只能看到Gboard和AOSP键盘&#xff0c;其他输入法藏起来。这个需求听起来简单&#xff0c;真动手改原生设置时&#xff0c;很容易踩到“改了…

作者头像 李华
网站建设 2026/10/21 10:18:14

Nginx证书过期排查与自动续期实战:从诊断到预防的完整指南

刚接手维护一台老服务器时&#xff0c;最怕的不是服务宕机&#xff0c;而是半夜收到监控告警说“证书过期”。尤其是 Nginx 这类承载着对外流量的入口&#xff0c;证书一过期&#xff0c;用户访问直接报红&#xff0c;轻则影响业务形象&#xff0c;重则导致接口调用失败、支付回…

作者头像 李华
网站建设 2026/10/21 10:17:34

diagram-design实战指南:如何设计一张让人一眼看懂的技术图

1. 从"diagram-design"这个标题说起&#xff1a;它到底在解决什么问题第一次看到"diagram-design"这个标题&#xff0c;我脑子里冒出来的第一个念头是&#xff1a;这大概率不是一个单纯的"画图工具推荐"&#xff0c;而是一套关于"如何把复杂…

作者头像 李华
网站建设 2026/10/21 10:17:21

open-code-review:让代码评审从“挑毛病”走向“共建设计”

1. 评审从"挑毛病"变成"共同确认设计"&#xff1a;我见到的评审变形记 1.1 流于形式的 review 到底卡在哪 我刚带团队那会儿&#xff0c;内部也有一套"代码评审"制度&#xff1a;拉分支、提 PR、找两个人点 Approve、合入。看起来很标准&#x…

作者头像 李华
网站建设 2026/10/21 10:16:44

自回归离散化预训练:统一具身VLM推理与机器人动作生成

第一次调试机器人抓取任务时&#xff0c;最让我崩溃的瞬间不是机械臂突然乱动&#xff0c;而是模型明明认出了红色杯子&#xff0c;也完全听懂了“把红色杯子放到托盘上”这句指令&#xff0c;最后输出的轨迹却直接穿过杯子底部。问题不出在视觉模型&#xff0c;也不出在语言模…

作者头像 李华
网站建设 2026/10/21 10:16:44

agent-skills:打造可复用技能库,破解Agent开发效率难题

做Agent开发做了差不多一年&#xff0c;我发现自己反复在做同一件很蠢的事情&#xff1a;换一个项目&#xff0c;就把上一个项目里写过的工具函数、调用流程和提示词重新敲一遍。直到我把这些散落的东西整理成一个叫“agent-skills”的可复用技能库之后&#xff0c;开发效率和效…

作者头像 李华