当使用OHOS-SDK编译的应用或者移植的三方库,都需要签名后方可在鸿蒙PC真机上运行。在鸿蒙PC系统的开发中,签名就像是给应用贴上一个可信的标签,是确保应用能在设备上安全运行的关键步骤。然而,传统的手动签名方式在复杂项目中极其繁琐,这就使得自动签名技术变得尤为重要。

今天,给大家推荐一个鸿蒙 ohos-sdk 的自动二进制或库签名的技巧,免去手动一个一个签名的麻烦。

当前网上的博客里面做法基本上都是用 ohos-sdk 编完东西之后再用 ohos-sdk 里面的签名工具手动做一次签名。这样的手工操作较为繁琐,尤其是涉及到大量二进制或 so 的时候就会更繁琐。

这里提供一个技巧,可以让编译工具链在编东西的时候直接自动对产物打上代码签名,省去人工操作的繁琐。

实现原理

鸿蒙 SDK 代码签名机制

鸿蒙系统有个严格的要求,所有可执行文件和共享库都必须经过签名才能在设备上运行。这就好比你要进入一个安全的场所,必须要有有效的通行证才行。传统的签名方式就是使用 binary-sign-tool (在toolchains/lib目录下有该签名工具)对编译后的产物进行处理,

例如:

../../ohos-sdk/linux/toolchains/lib/binary-sign-tool sign -inFile "a.out" -outFile "a.out.signed" -selfSign "1"

但在复杂项目里,手动给每个依赖库签名,就像要给一群人逐个发放通行证,工作量巨大,所以自动化签名就成了刚需。

这个技巧是建立在这个 PR 的基础之上的:

https://gitcode.com/openharmony/third_party_llvm-project/pull/882

这是 OpenHarmony 社区的人往 ohos-sdk 里面的 LLVM 添加的一个特性:如果链接器收到了 --code-sign 参数,它就会自动对生成出来的 ELF 文件做自签名。

这相比于手工签名已经便利很多了,但每次编东西要额外加一个链接器参数还是会有点影响体验。

为了把这最后一步的体验问题也优化掉,我们选择对调用链接器的流程做一点改造,让 clang 驱动器在调用链接器的时候一定携带这个参数,那就能实现自动签名的效果了。

链接器封装技术

这项技术的核心就是把原生的 ld.lld 软链接替换成一个封装脚本。这个脚本就像是一个智能小助手,在链接过程中会自动注入签名参数。具体来说,就是通过脚本向 lld 链接器传递 --code-sign 参数,实现编译时自动签名。而且,对于开发者而言,这个签名过程就像隐身了一样,完全不需要额外操作。

ELF 文件格式与代码签名段

签名信息会存储在 ELF 文件的特定段 .codesign 中。我们可以使用 llvm-readelf -S 命令来查看这个段。这个段有一些特殊的属性,它属于 PROGBITS 类型,并且有特定的内存对齐要求,是 4096 字节。

代码解析

自动化签名实施步骤

1. SDK 下载与解压
sdk_download_url="https://cidownload.openharmony.cn/version/Daily_Version/OpenHarmony_6.1.0.27/20260111_020523/version-Daily_Version-OpenHarmony_6.1.0.27-20260111_020523-ohos-sdk-public.tar.gz"
curl -o ohos-sdk-public.tar.gz $sdk_download_url
mkdir ohos-sdk
tar -zxf ohos-sdk-public.tar.gz -C ohos-sdk

这段代码的作用是从指定的 URL 下载 SDK 压缩包,然后创建一个名为 ohos-sdk 的目录,并将压缩包解压到该目录下。

注意:为了使用这个最新的链接器签名特性,我们需要把 ohos-sdk 换成最新的日构建版本。ohos-sdk 6.0 正式版是不行的,比较旧的日构建版本也不行。这里下载一份(1 月 11 日)的日构建版本。

2. 链接器封装配置
cd ohos-sdk/linux/native/llvm/bin
rm ld.lld  # 移除原始软链接
lld_absolute_path=$(realpath lld)
# 创建封装脚本
printf '#!/bin/bash\nexec -a "$0" %s --code-sign "$@"\n' "$lld_absolute_path" > ld.lld
chmod 0755 ld.lld  # 添加执行权限

首先进入指定的目录,移除原始的 ld.lld 软链接,然后获取 lld 的绝对路径。接着创建一个封装脚本,这个脚本会在调用 ld.lld 时自动传递 --code-sign 参数。最后给脚本添加执行权限。

编译验证流程

0. 环境变量配置
export PATH=$PATH:$(realpath ohos-sdk/linux/native/llvm/bin)

这行代码将修改后的链接器目录添加到环境变量 PATH 中,这样系统就能找到我们定制的链接器了。(此步骤根据你的需要,非必须。如果你是使用export的方式导出的则不需要配置到环境变量里。这里只是方面下面测试直接使用clang命令)

1. 简单程序编译测试
echo -e '#include <stdio.h>\nint main(void) {\n    printf("Hello, world!\\n");\n    return 0;\n}' > helloworld.c
clang --target=aarch64-linux-ohos helloworld.c -o helloworld

这里创建了一个简单的 C 语言程序 helloworld.c,然后使用 clang 编译器将其编译成可执行文件 helloworld

2. 签名验证
llvm-readelf -S helloworld | grep codesign
# 应输出包含 .codesign 段的信息

通过 llvm-readelf -S 命令查看 helloworld 文件的段信息,并使用 grep 命令过滤出 .codesign 段的信息。如果输出中有相关信息,说明签名成功。

  [34] .symtab           SYMTAB          0000000000000000 001de0 000990 18     36  91  8
  [35] .shstrtab         STRTAB          0000000000000000 002770 000178 00      0   0  1
  [36] .strtab           STRTAB          0000000000000000 0028e8 0002f9 00      0   0  1
  [37] .codesign         PROGBITS        0000000000000000 003000 001000 00      0   0 4096

常见问题与解决方案

SDK下载链接失效

日构建版本的产物过期策略并不透明,有时候一年都不会过期,有时候一个月就过期了。
如果你刚好碰到文中的下载链接过期了,这里有两个处理办法:

  1. 去网页上下载最新的;
  2. 用脚本下载最新的。

网页就是这个网页:https://dcp.openharmony.cn,对着我的截图去找这个产物就行。
在这里插入图片描述

脚本方式下载SDK如下:

query_component() {
  component=$1
  curl -fsSL 'https://dcp.openharmony.cn/api/daily_build/build/list/component' \
    -H 'Accept: application/json, text/plain, */*' \
    -H 'Content-Type: application/json' \
    --data-raw '{"projectName":"openharmony","branch":"master","pageNum":1,"pageSize":10,"deviceLevel":"","component":"'${component}'","type":1,"startTime":"2025080100000000","endTime":"20990101235959","sortType":"","sortField":"","hardwareBoard":"","buildStatus":"success","buildFailReason":"","withDomain":1}'
}

sdk_download_url=$(query_component "ohos-sdk-public" | jq -r ".data.list.dataList[0].obsPath")
curl -o ohos-sdk-public.tar.gz $sdk_download_url

签名失败问题

  • 问题现象:编译成功了,但文件里却没有 .codesign 段。
  • 解决方案
    1. 检查封装脚本权限:chmod 0755 ld.lld
    2. 验证脚本内容是否正确指向 lld 路径
    3. 确认 --code-sign 参数格式正确

总结

使用上述技巧,可以使得鸿蒙 ohos-sdk 自动对库或二进制文件签名,为开发者带来了极大的便利,它显著提高了开发效率,尤其是在处理复杂项目依赖时,避免了繁琐的手动签名过程。同时,它也确保了代码的安全性和合规性,让代码在鸿蒙系统上能够安全、稳定地运行。

展望

随着鸿蒙系统的不断发展和完善,自动代码签名技术也可能会有更多的优化和改进。未来,可能会有更简洁、高效的签名方式出现,进一步降低开发者的工作量。同时,在安全性方面也可能会有新的增强措施,为鸿蒙生态的发展提供更坚实的保障。

希望通过这篇文章,大家对鸿蒙 ohos-sdk 自动代码签名技术有了更深入的了解,能够在开发中更好地运用这项技术。

最后,欢迎加入开源鸿蒙PC社区https://harmonypc.csdn.net/,共同交流进步!

参考链接

让ohos-sdk实现自动代码签名的小技巧

蓝香蕉代码 |【鸿蒙电脑开发命令行-签名篇与本机hdc shell】

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐