构建和部署服务包

创建中间件并编写自定义代码后,您可以将服务软件包部署为 APEX 文件。

  1. 创建 SDV 配置文件:

    Rust

    1. 运行以下命令生成 SDV 配置文件:

      vsidlc -c /path/to/catalog -o /path/to/output --apex
      

      使用 --apex 标志运行 vsidlc 会自动生成所有必要的配置文件,包括:

      • APEX 清单 (apex_manifest.json)
      • SDV 元数据清单 (sdv_service_bundles_manifest.textproto)
      • 链接器配置 (linker.config.json)
      • SELinux 文件上下文 (file_contexts)
      • 公钥和私钥 (.avbpubkey.pem)
      • 权限声明和编排配置
      • 一个 Android.bp 文件,用于定义所有必要的 Soong 模块。

      您可以在以下位置找到生成的配置:

      /path/to/output/apex/
      

      /path/to/output/configs/
      

    C++

    1. 创建 SDV 元数据清单文件, service_bundle.manifest.textproto 使用以下基本执行元数据字段:

      • 根据命名惯例的服务名称
      • 服务软件包版本的整数和字符串表示形式
      • 之前创建的库的路径

      准备基本服务软件包元数据对于服务软件包打包和部署是强制性的。

      # proto-file: //system/software_defined_vehicle/core_services/service_bundles_registry/proto/sdv_service_bundles_manifest.proto
      # proto-message: SdvServiceBundleManifestEntry
      
      # SDV service bundle metadata definition with mandatory fields.
      sdv_service_bundle_metadata {
        # Service bundle name.
        name: "ServiceBundleName"
        # Service bundle integer version.
        version_number: 42
        # Service bundle version as a string.
        version_name: "42.alpha"
        # Service bundle library path.
        native_library_path: "lib64/libservice_bundle.so"
      }
      
    2. 创建新的 链接器配置 文件, linker.config.json

      { "visible": true }
      
    3. 使用以下字段创建新的 apex_manifest.json 文件:

      • 根据 SDV 命名惯例 的唯一 SDV 软件包名称
      • APEX 的版本
      • 对 SDV Comms 库的依赖项
      {
        "name": "com.sdv.oem.apex_and_module_name",
        "version": 1,
        "requireNativeLibs": [
            "libsdv_comms_ctx_ffi.so",
            "libsdv_comms_dt_ffi.so",
            "libsdv_comms_id_ffi.so",
            "libsdv_comms_sd_ffi.so"
        ]
      }
      
    4. 创建公钥 apex_name.apex_key.avbpubkey 和私钥 apex_name.apex_key.pem

    5. 创建新的 SELinux 文件上下文 apex_file_contexts

      (/.*)?    u:object_r:system_file:s0
      

      如需了解详情,请参阅安全上下文和类别

    6. 在新的或现有的 Android.bp 文件中创建预构建目标:

      // SDV manifest file prebuilt.
      prebuilt_etc {
          name: "com.sdv.oem.apex_and_module_name.service_bundles_manifest",
          // The source filename of the manifest file.
          src: "service_bundle.manifest.textproto",
          // The name of the installed file needs be `sdv_service_bundles_manifest.textproto`.
          filename: "sdv_service_bundles_manifest.textproto",
          // Disable direct installation of the prebuilt to one of the partitions.
          // The manifest is used only inside of an apex.
          installable: false,
      }
      // The linker config to allow libraries for the apex to be linkable.
      linker_config {
          name: "com.sdv.oem.apex_and_module_name. linker_config",
          src: "linker.config.json",
          // Disable direct installation of the prebuilt to one of the partitions.
          // The linker configuration is used only inside of an apex.
          installable: false,
      }
      // Key to be used for signing the apex.
      apex_key {
          name: "apex_name.apex_key",
          public_key: "apex_name.apex_key.avbpubkey",
          private_key: "apex_name.apex_key.pem",
      }
      
    7. 在新的或现有的 Android.bp 文件中创建新的 APEX 模块。使用 SDV 软件包名称作为 APEX 模块名称。

      apex {
          name: "com.sdv.oem.apex_and_module_name",
          // The service bundle(s) to be included in the apex.
          native_shared_libs: [
              "libservice_bundle",
          ],
          prebuilts: [
              // SDV service bundles manifest file.
              "com.sdv.oem.apex_and_module_name.service_bundles_manifest",
              // Linker configuration to enable loading library from apex.
              "com.sdv.oem.apex_and_module_name.linker_config",
          ],
          // Json manifest file describes metadata of the APEX package.
          // The 'name' field from the JSON is used as a mounting point.
          manifest: "apex_manifest.json",
          // Setting the security contexts to files in this APEX bundle.
          file_contexts: "apex_file_contexts",
          // Name of the apex_key module that provides the private key to sign the APEX bundle.
          key: "apex_name.apex_key",
          // Mark apex as non-updatable for now, this might be revisited going forward.
          updatable: false,
          // Service bundle package is installed into /product partition.
          product_specific: true,
      }
      
  2. 如需在 SDV 映像中添加新的 makefile,请将新的 APEX 模块添加到 PRODUCT_PACKAGES中的 产品 makefile。例如,请参阅 sdv_samples_core_services.mk

  3. 如果您使用的是 Cuttlefish,请运行以下命令来启动设备:

    sdv-cf create --instance_name=instance1
    
  4. 在系统启动时运行服务软件包:

    # Grant root access.
    adb root
    # Launch the new service bundle.
    adb shell sdv_service_bundle start \
      local-vm:com.sdv.oem.apex_and_module_name.ServiceBundleName/instance-1
    

服务软件包依赖项管理

在某些情况下,您可以使用服务软件包依赖项的静态链接来减小 APEX 大小和服务软件包内存占用空间,并缩短服务软件包的启动时间。这些情况包括具有以下特征的 APEX:

  • 单个服务软件包
  • 多个服务软件包,它们不共享许多常见依赖项

如需启用静态链接,请将以下属性添加到服务软件包库定义:

// Service bundle library.
rust_ffi_shared {
  // See rust_ffi_shared basic template.
  ...
  // uses static linking for the dependencies
  prefer_rlib: true,
  // needed to correctly resolve commstack deps
  ld_flags: ["-Wl,--no-as-needed"],
}

对于每种情况,我们建议您确认静态链接到依赖项是否会减少服务软件包的内存占用空间并缩短启动时间。

调试 (dumpsys)

生命周期管理器实现了 dumpsys 接口。此接口向用户显示处于 createdstarted 状态的服务软件包列表。该接口还会显示服务软件包进程的 FQIN 或 UID。

如需查看服务软件包的当前状态和标识符,请执行以下操作:

# Grant root access.
adb root

# Execute dumpsys to see service bundles state
adb shell dumpsys google.sdv.lifecycle.ILifecycleManager/default

后续步骤

如需自动执行 vsidlc 并使 IDE 插件能够使用 依赖项,请参阅 自动目录更新和 LSP 集成