5、VNDK(Vendor Native Development Kit)详解:VNDK版本管理、SP-HAL与VNDK的依赖关系

说到Android系统升级,VNDK绝对是个绕不开的话题。我记得刚接触Treble架构那会儿,光理解VNDK和SP-HAL的关系就花了我整整一周。说白了,VNDK就是Google为了解决碎片化问题,给厂商提供的一套稳定API集合。今天咱们就把它彻底讲透。

5.1 VNDK到底是什么?

VNDK的全称是Vendor Native Development Kit。你可以把它理解成一套「厂商原生开发工具包」。它的核心目标只有一个:让厂商的HAL模块和系统框架解耦

在Android 8.0之前,厂商的HAL代码直接链接到系统框架的共享库。每次系统升级,厂商都得重新编译HAL。这就像你装修房子,结果开发商告诉你「每次换墙纸,你得把整个墙拆了重砌」——是不是很崩溃?

VNDK的出现,就是为了解决这个问题。它把系统框架中那些稳定的、不会变动的原生库,单独抽出来给厂商用。厂商的HAL模块只依赖这些VNDK库,不依赖系统框架的其他部分。这样一来,系统升级时,只要VNDK接口不变,厂商的HAL就能直接跑。

核心要点:VNDK是系统框架和厂商HAL之间的「隔离层」。它保证了系统升级时,厂商的二进制模块不需要重新编译。

5.2 VNDK版本管理机制

VNDK是有版本号的。每个Android版本对应一个VNDK版本。比如Android 9对应VNDK 28,Android 10对应VNDK 29,以此类推。

版本管理的核心逻辑是这样的:

  • 系统框架:编译时指定VNDK版本,生成对应的VNDK库
  • 厂商HAL:编译时链接指定版本的VNDK库
  • 运行时:系统框架和厂商HAL必须使用同一VNDK版本

我遇到过一个问题:某厂商把Android 9的设备强行刷了Android 10的系统镜像,结果VNDK版本不匹配,所有HAL模块全部崩溃。嗯,这就是典型的版本管理没做好。

VNDK版本号定义在build/make/core/config.mk中:

# VNDK版本号定义
PLATFORM_VNDK_VERSION := 29
PLATFORM_VNDK_VERSION_MAJOR := 29
PLATFORM_VNDK_VERSION_MINOR := 0

厂商在编译HAL时,需要指定VNDK版本:

LOCAL_VNDK_VERSION := 29
LOCAL_VENDOR_MODULE := true

个人建议:厂商在开发新设备时,最好提前确认目标Android版本的VNDK版本号。我习惯在项目启动阶段就建立一个「VNDK版本对照表」,避免后期踩坑。

5.3 SP-HAL与VNDK的依赖关系

SP-HAL(Same Process HAL)是Android Treble架构中的一种HAL实现方式。它和VNDK的关系,可以用一句话概括:SP-HAL运行在系统框架进程中,但它依赖VNDK提供的稳定接口

具体来说,SP-HAL和VNDK的依赖关系是这样的:

  1. SP-HAL直接链接VNDK库:SP-HAL的代码中,会直接调用VNDK提供的API
  2. VNDK提供基础功能:比如内存管理、线程同步、日志输出等
  3. SP-HAL不能依赖非VNDK库:这是硬性规定,否则就失去了隔离的意义

举个例子,一个典型的SP-HAL实现:

// SP-HAL实现示例
#include <vendor/example/hardware/light/1.0/ILight.h>
#include <log/log.h>  // VNDK提供的日志接口

namespace vendor::example::hardware::light::implementation {

class Light : public ILight {
public:
    Return<Status> setLight(Type type, const LightState& state) override {
        ALOGI("Setting light type %d", static_cast<int>(type));
        // 实际硬件操作
        return Status::SUCCESS;
    }
};

}  // namespace vendor::example::hardware::light::implementation

你看,这个SP-HAL只依赖了VNDK提供的<log/log.h>,没有依赖任何系统框架的私有库。这就是VNDK的隔离效果。

注意:SP-HAL不能使用系统框架的私有API。我曾经见过一个厂商在SP-HAL里直接调用了android::sp的私有方法,结果系统升级后那个方法被删了,整个HAL直接崩溃。这种坑,踩一次就够了。

5.4 VNDK的依赖关系图

下面这张图,是我自己整理的VNDK依赖关系。它清晰地展示了系统框架、VNDK、SP-HAL和Vendor HAL之间的调用链路。

VNDK依赖关系图 系统框架(System Framework) VNDK(稳定API集合) SP-HAL(同进程HAL) Vendor HAL(独立进程HAL) 硬件设备(Hardware) 依赖 提供API 提供API 操作 操作 说明:SP-HAL和Vendor HAL都依赖VNDK提供的稳定API,但SP-HAL运行在系统框架进程中,Vendor HAL运行在独立进程中。

从这张图可以看出,VNDK处于系统框架和HAL模块之间的「中间层」。它既被系统框架使用,也被SP-HAL和Vendor HAL使用。这种设计,保证了系统升级时HAL模块的二进制兼容性。

5.5 版本兼容性实战

在实际项目中,VNDK版本兼容性是个大问题。我总结了几条经验:

  • 向前兼容:新版本的VNDK必须兼容旧版本的HAL模块。比如Android 10的VNDK 29,必须能跑Android 9的VNDK 28的HAL
  • 向后不兼容:旧版本的VNDK不能跑新版本的HAL模块。这个很好理解,新API旧系统不认识
  • 版本检查:系统启动时会检查VNDK版本,不匹配直接拒绝加载

版本检查的代码在system/libvndk/vndk.cpp中:

// VNDK版本检查
bool checkVndkVersion(const char* expected, const char* actual) {
    if (strcmp(expected, actual) != 0) {
        ALOGE("VNDK version mismatch: expected %s, actual %s", expected, actual);
        return false;
    }
    return true;
}

避坑指南:我曾经在项目里遇到一个坑——厂商的HAL模块编译时链接了VNDK 28,但设备上跑的是VNDK 29。结果所有HAL模块启动时都报版本不匹配错误。后来我养成了一个习惯:每次编译前先检查PLATFORM_VNDK_VERSION,确保和设备的VNDK版本一致。

5.6 总结

VNDK是Android Treble架构的核心组件。它通过版本管理和接口隔离,实现了系统框架和厂商HAL的解耦。SP-HAL作为同进程HAL,直接依赖VNDK提供的稳定API。理解VNDK的版本管理机制和依赖关系,是做好Android系统升级兼容性开发的基础。

记住一句话:VNDK版本不匹配,HAL模块全白费。这个教训,我是在项目里真金白银换来的。


公众号:蓝海资料掘金营,微信deep3321