Skip to content
Code Inside Out

AAOS - Create AIDL Interface

Tags: automotiveandroidaidl

Android Interface Definition Language (AIDL) defines the programming interface that both the client and service agree upon, in order to communicate with each other using Inter-Process Communication (IPC).

Create AIDL Interface


Compiling the AIDL interface auto-generates 2 classes - a Proxy class and a Stub class:

  • The Proxy class acts as a client-side representation, managing communication with the remote service and marshalling the request to a kernel driver (Binder)
  • The Stub class serves as the server-side implementation, un-marshalling incoming requests from the proxy (via the Binder) and executing the actual service operations defined in the AIDL

AIDL Binding

Create folder structure in vendor/trongvq/interfaces/virtio_rtc as below:

  • Directoryvendor/trongvq/interfaces/virtio_rtc
    • Android.bp
    • Directoryvendor/trongvq/virtio_rtc
      • IVirtio_RTC.aidl

  1. Create an Android.bp file to define the build modules and build configuration:

    vendor/trongvq/interfaces/virtio_rtc/Android.bp
    aidl_interface {
    name: "vendor.trongvq.virtio_rtc",
    vendor: true, // installed in /vendor
    srcs: ["vendor/trongvq/virtio_rtc/*.aidl"],
    stability: "vintf", // Stable Vendor Interface
    owner: "TRONGVQ",
    backend: {
    cpp: {
    enabled: true,
    },
    java: {
    sdk_version: "module_current",
    },
    },
    }
  2. Create IVirtio_RTC.aidl file which define Interface’s methods:

    vendor/trongvq/interfaces/virtio_rtc/vendor/trongvq/virtio_rtc/IVirtio_RTC.aidl
    package vendor.trongvq.virtio_rtc;
    @VintfStability
    interface IVirtio_RTC {
    String getTime();
    boolean setTime(in String seconds);
    }
  3. Tag AIDL current version:

    Run make to build AIDL, but the first time, it will fail. Fix it with provided command:

    mm -j10
    API dump for the current version of AIDL interface vendor.trongvq.virtio_rtc does not exist.
    Run the command "m vendor.trongvq.virtio_rtc-update-api" or add "unstable: true" to the build rule for the interface if it does not need to be versioned

    Execute suggested command:

    m vendor.trongvq.virtio_rtc-update-api

    The command will create a tag current aidl api for the AIDL interface:

    • Directoryvendor/trongvq/interfaces/virtio_rtc
      • Android.bp
      • Directoryvendor/trongvq/virtio_rtc
        • IVirtio_RTC.aidl
        • Directoryaidl_api
          • Directoryvendor.trongvq.virtio_rtc
            • Directorycurrent
              • Directoryvendor/trongvq/virtio_rtc
                • IVirtio_RTC.aidl

    The current folder will be renamed to 1 if there is a new api created. That new version will be new current folder then after.

  4. Build AIDL Interface:

    vendor/trongvq/interfaces/virtio_rtc
    mm -j10
    find out/target/product/vsoc_x86_64_only/vendor/ -name *virtio_rtc*
    out/target/product/vsoc_x86_64_only/vendor/bin/vendor.trongvq.virtio_rtc-cpp-analyzer
    out/target/product/vsoc_x86_64_only/vendor/framework/vendor.trongvq.virtio_rtc-V1-java.jar
    out/target/product/vsoc_x86_64_only/vendor/lib64/libvendor_trongvq_virtio_rtc_V1.dylib.so
    out/target/product/vsoc_x86_64_only/vendor/lib64/vendor.trongvq.virtio_rtc-V1-ndk.so
    out/target/product/vsoc_x86_64_only/vendor/lib64/vendor.trongvq.virtio_rtc-V1-cpp.so

    Refer:


    AIDL has three different backends: Java, NDK, CPP:

    • Java vendor.trongvq.virtio_rtc-V1-java.jar: Stable Java Proxy and Java Stub classes, use find ./out/ -name *Virtio_RTC.java to locate the generated file.

    • NDK vendor.trongvq.virtio_rtc-V1-ndk.so: Stable Native Binder Proxy (BpVirio_RTC.h) class for client code and Binder Native Stub (BnVitio_RTC.h), linked to libbinder_ndk, use for vendor service and client, use find ./out/ -name *Virtio_RTC.h to locate the generated file.

    • CPP vendor.trongvq.virtio_rtc-V1-cpp.so: Unstable CPP Proxy (BpVirio_RTC.h) and Stube (BnVitio_RTC.h) classes, linked to libbinder, use find ./out/ -name *Virtio_RTC.h to locate the generated file.

  5. Add AIDL to vendor packages:

    Create a vendor make file:

    device/google/cuttlefish/shared/trongvq.mk
    PRODUCT_PACKAGES += vendor.trongvq.virtio_rtc

    Add vendor make file into Cuttlefish device make file:

    device/google/cuttlefish/shared/device.mk
    # Include vendor trongvq modules
    $(call inherit-product, device/google/cuttlefish/shared/trongvq.mk)
  6. Rebuild Android to include built AIDL library to target device

Create Service


Refer: https://source.android.com/docs/core/architecture/aidl/aidl-backends

Create a vendor service in vendor/trongvq/services/virtio_rtc:

  • Directoryvendor/trongvq/
    • device_framework_matrix.xml # compatibility
    • Directoryinterfaces/virio_rtc
      • Android.bp
      • Directoryvendor/trongvq/virtio_rtc
        • IVirtio_RTC.aidl
    • Directoryservices/virtio_rtc
      • Android.bp
      • inc
      • Directorysrc
        • Virtio_RTC_Service.cpp
      • vendor.trongvq.virtio_rtc-service.rc # start service at startup
      • vendor.trongvq.virtio_rtc-service.xml # declare and configure interface

  1. Create Android.bp to declare a Service binary:

    vendor/trongvq/services/virtio_rtc/Android.bp
    cc_binary {
    name: "vendor.trongvq.virtio_rtc-service",
    vendor: true,
    relative_install_path: "hw", // relative to /vendor/bin
    init_rc: ["vendor.trongvq.virtio_rtc-service.rc"],
    vintf_fragments: ["vendor.trongvq.virtio_rtc-service.xml"],
    local_include_dirs: [
    "inc",
    ],
    srcs: [
    "src/*.cpp",
    ],
    cflags: [
    "-Wall",
    "-Werror",
    ],
    shared_libs: [
    "liblog",
    "libutils",
    "libbinder_ndk", // stable version
    "vendor.trongvq.virtio_rtc-V1-ndk", // stable version
    ],
    }
  2. Create Service RC file:

    vendor/trongvq/services/virtio_rtc/vendor.trongvq.virtio_rtc-service.rc
    service vendor.trongvq.virtio_rtc-service /vendor/hw/vendor.trongvq.virtio_rtc-service
    interface aidl vendor.trongvq.virtio_rtc.IVirtio_RTC/default
    class hal
    user system
    group system
  3. Create Service XML file:

    vendor/trongvq/services/virtio_rtc/vendor.trongvq.virtio_rtc-service.xml
    <manifest version="1.0" type="device">
    <hal format="aidl">
    <name>vendor.trongvq.virtio_rtc</name>
    <version>1</version>
    <fqname>IVirtio_RTC/default</fqname>
    </hal>
    </manifest>
  4. Add Service to target device:

    device/google/cuttlefish/shared/trongvq.mk
    PRODUCT_PACKAGES += vendor.trongvq.virtio_rtc
    PRODUCT_PACKAGES += vendor.trongvq.virtio_rtc-service

    However, when rebuild system, it fails:

    ERROR: files are incompatible: The following instances are in the device manifest but not specified in framework compatibility matrix:
    vendor.trongvq.virtio_rtc.IVirtio_RTC/default (@1)
    Suggested fix:
    1. Update deprecated HALs to the latest version.
    2. Check for any typos in device manifest or framework compatibility matrices with FCM version >= 202404.
    3. For new platform HALs, add them to any framework compatibility matrix with FCM version >= 202404 where applicable.
    4. For device-specific HALs, add to DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE or DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE

    To fix this, move to the next step.

  5. Add Service to Device Framework Compatibility Matrix (FCM):

    The framework compatibility matrix consists of the system compatibility matrix, the product compatibility matrix, and the system_ext compatibility matrix.

    The requirements of the FCM must be satisfied by the device manifest (requirements enforced at build time, runtime, and in VTS):

    • correct name
    • compatible versions
    • compatible interface instances
    vendor/trongvq/device_framework_matrix.xml
    <compatibility-matrix version="1.0" type="framework">
    <hal format="aidl" optional="true">
    <name>vendor.trongvq.virtio_rtc</name>
    <version>1</version>
    <interface>
    <name>IVirtio_RTC</name>
    <instance>default</instance>
    </interface>
    </hal>
    </compatibility-matrix>

    Add to vendor packages:

    device/google/cuttlefish/shared/trongvq.mk
    DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE := vendor/trongvq/device_framework_matrix.xml
    PRODUCT_PACKAGES += vendor.trongvq.virtio_rtc
    PRODUCT_PACKAGES += vendor.trongvq.virtio_rtc-service
  6. Rebuild again

    The service binary is built and copied into output folder at vendor/bin/hw (noted that Android.bp uses relative path hw):

    ./out/target/product/vsoc_x86_64_only/vendor/bin/hw/vendor.trongvq.virtio_rtc-service

Set SE Policy


  • Directorydevice/google/cuttlefish/shared/sepolicy/vendor
    • file_contexts
    • hal_virtio_rtc_default.te
  • Directoryvendor/trongvq/
    • device_framework_matrix.xml # compatibility
    • Directoryinterfaces/virio_rtc
      • Android.bp
      • Directoryvendor/trongvq/virtio_rtc
        • IVirtio_RTC.aidl
    • Directoryservices/virtio_rtc
      • Android.bp
      • inc
      • Directorysrc
        • Virtio_RTC_Service.cpp
      • vendor.trongvq.virtio_rtc-service.rc # start service at startup
      • vendor.trongvq.virtio_rtc-service.xml # declare and configure interface

Launch Cuttlefish device and check in logcat or dmesg to see that the service could not start:

dmesg | grep virtio_rtc
Could not start service 'vendor.trongvq.virtio_rtc-service' as part of class 'hal': File /vendor/bin/hw/vendor.trongvq.virtio_rtc-service(labeled "u:object_r:vendor_file:s0") has incorrect label or no domain transition from u:r:init:s0 to another SELinux domain defined. Have you configured your service correctly? https://source.android.com/security/selinux/device-policy#label_new_services_and_address_denials. Note: this error shows up even in permissive mode in order to make auditing denials possible.

File vendor.trongvq.virtio_rtc-service is labeled as u:object_r:vendor_file:s0 which is incorrect. On target shell, use ls -lZ to see the label.

That default label is defined in file system/sepolicy/private/file_contexts:

system/sepolicy/private/file_contexts
# Vendor files
/(vendor|system/vendor)(/.*)? u:object_r:vendor_file:s0

  1. Add SE Policy for vendor service:

    The vendor service should have the label hal_virtio_rtc_default_exec defined in Device SE Policy:

    device/google/cuttlefish/shared/sepolicy/vendor/file_contexts
    /vendor/bin/hw/vendor\.trongvq\.virtio_rtc-service u:object_r:hal_virtio_rtc_default_exec:s0

    When rebuild, it fails due to type hal_virtio_rtc_default_exec is not defined.

  2. Create vendor SE Policy file:

    Add a new file hal_virtio_rtc_default.te:

    device/google/cuttlefish/shared/sepolicy/vendor/hal_virtio_rtc_default.te
    type hal_virtio_rtc_default, domain;
    type hal_virtio_rtc_default_exec, exec_type, vendor_file_type, file_type;
    init_daemon_domain(hal_virtio_rtc_default);
    • domain means it can be assigned to processes and that it is allowed to execute code.
    • exec_type means it can be executed, applied for vendor_file_type and general file_type.
    • init_daemon_domain is an SELinux macro that’s defined in the Android public policies, details in system/sepolicy/public/te_macros. It’s used to transition the domain context from init to hal_virtio_rtc_default.
  3. Rebuild the target and it should be compiled.

    Go to the device shell, verify the label of the service binary:

    ls -lZ vendor/bin/hw/vendor.trongvq.virtio_rtc-service
    -rwxr-xr-x 1 root shell u:object_r:hal_virtio_rtc_default_exec:s0 vendor/bin/hw/vendor.trongvq.virtio_rtc-service

    and check the logcat or dmesg:

    dmesg | grep virtio_rtc
    init: starting service 'vendor.trongvq.virtio_rtc-service'...
    init: ... started service 'vendor.trongvq.virtio_rtc-service' has pid 508

Implement Service


  • Directorydevice/google/cuttlefish/shared/sepolicy/vendor
    • service.te
    • service_contexts
    • file_contexts
    • hal_virtio_rtc_default.te
  • Directoryvendor/trongvq/
    • device_framework_matrix.xml # compatibility
    • Directoryinterfaces/virio_rtc
      • Android.bp
      • Directoryvendor/trongvq/virtio_rtc
        • IVirtio_RTC.aidl
    • Directoryservices/virtio_rtc
      • Android.bp
      • Directoryinc
        • Virtio_RTC.h
      • Directorysrc
        • Virtio_RTC.cpp
        • Virtio_RTC_Service.cpp
      • vendor.trongvq.virtio_rtc-service.rc # start service at startup
      • vendor.trongvq.virtio_rtc-service.xml # declare and configure interface

The AIDL interface is generated as NDK stable source code:

tree out/soong/.intermediates/vendor/trongvq/interfaces/virtio_rtc/vendor.trongvq.virtio_rtc-V1-ndk-source/gen/
├── include
│   ├── aidl
│   │   └── vendor
│   │   └── trongvq
│   │   └── virtio_rtc
│   │   ├── BnVirtio_RTC.h
│   │   ├── BpVirtio_RTC.h
│   │   └── IVirtio_RTC.h
└── vendor
└── trongvq
└── virtio_rtc
├── IVirtio_RTC.cpp
└── IVirtio_RTC.cpp.d
  • The AIDL interace is defined in class IVirtio_RTC (inheriates ::ndk::ICInterface).

  • The Binder Proxy is defined in class BpVirtio_RTC (inheriates ::ndk::BpCInterface<IVirtio_RTC>), and implemented in IVirtio_RTC.cpp. The methods of interface are fully implemented for Binder Proxy. Any process having a Binder Proxy object can call its methods to communicate with the Binder Native Stub.

  • The Binder Native is defined in class BnVirtio_RTC (inheriates ::ndk::BnCInterface<IVirtio_RTC>), but partially impplemented in IVirtio_RTC.cpp. It is required to implement virtual methods declared in the AIDL interfaces. These methods are called through the Binder IPC, and they are user-defined functionanities.

  1. Create Service Header in Virtio_RTC.h:

    vendor/trongvq/services/virtio_rtc/inc/Virtio_RTC.h
    #pragma once
    #include <aidl/vendor/trongvq/virtio_rtc/BnVirtio_RTC.h>
    namespace aidl::vendor::trongvq::virtio_rtc {
    class Virtio_RTC : public BnVirtio_RTC {
    public:
    ::ndk::ScopedAStatus getTime(std::string *_aidl_return) override;
    ::ndk::ScopedAStatus setTime(const std::string &in_seconds, bool *_aidl_return) override;
    };
    } // namespace aidl::vendor::trongvq::virtio_rtc
  2. Implement Service Methods in Virtio_RTC.cpp:

    vendor/trongvq/services/virtio_rtc/src/Virtio_RTC.cpp
    #include "Virtio_RTC.h"
    #include <fcntl.h>
    #include <utils/Log.h>
    namespace aidl::vendor::trongvq::virtio_rtc {
    static const char VIRTIO_RTC_PATH[] = "/dev/virtio_rtc";
    ::ndk::ScopedAStatus Virtio_RTC::getTime(std::string *_aidl_return) {
    int fd = open(VIRTIO_RTC_PATH, O_RDONLY);
    if (fd < 0) {
    ALOGE("Failed to open %s", VIRTIO_RTC_PATH);
    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC));
    }
    char buf[64];
    int len = read(fd, buf, sizeof(buf));
    if (len < 0) {
    close(fd);
    ALOGE("Failed to read %s", VIRTIO_RTC_PATH);
    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC));
    }
    close(fd);
    buf[len] = '\0';
    ALOGI("Current time: %s", buf);
    *_aidl_return = buf;
    return ndk::ScopedAStatus::ok();
    }
    ::ndk::ScopedAStatus Virtio_RTC::setTime(const std::string &in_seconds, bool *_aidl_return) {
    int fd = open(VIRTIO_RTC_PATH, O_WRONLY);
    if (fd < 0) {
    ALOGE("Failed to open %s", VIRTIO_RTC_PATH);
    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC));
    }
    int len = write(fd, in_seconds.c_str(), in_seconds.size());
    if (len < 0) {
    close(fd);
    ALOGE("Failed to write %s", VIRTIO_RTC_PATH);
    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC));
    }
    close(fd);
    ALOGI("Setting time to %s", in_seconds.c_str());
    *_aidl_return = true;
    return ndk::ScopedAStatus::ok();
    }
    } // namespace aidl::vendor::trongvq::virtio_rtc
  3. Update SE Policy:

    Rebuild target and check service in the logcat or dmesg, expect it fails with avc: denied error:

    W binder:3962_2: type=1400 audit(0.0:147): avc: denied { call } for scontext=u:r:hal_virtio_rtc_default:s0 tcontext=u:r:servicemanager:s0 tclass=binder permissive=0

    When service calls AServiceManager_addService(), the process calls the Service Manager via the Binder to register its service. This step needs a permission!


    1. Use tool audit2allow to convert SELinux audit messages into SELinux allow rules:

      sudo apt install policycoreutils-python-utils
    2. Now pull the policy file, and read logcat to check audit message:

      mkdir ~/temp
      cd ~/temp
      adb pull /sys/fs/selinux/policy
      adb logcat -b all -d | grep virtio_rtc | audit2allow -p policy
      #============= hal_virtio_rtc_default ==============
      allow hal_virtio_rtc_default servicemanager:binder call;
    3. Add suggested statement to vendor policy:

      device/google/cuttlefish/shared/sepolicy/vendor/hal_virtio_rtc_default.te
      allow hal_virtio_rtc_default servicemanager:binder call;

      Rebuild again, and check service in the logcat or dmesg, expect it fails with another avc: denied error:

      W binder:3914_2: type=1400 audit(0.0:124): avc: denied { transfer } for scontext=u:r:hal_virtio_rtc_default:s0 tcontext=u:r:servicemanager:s0 tclass=binder permissive=0
    4. Run the tool and add suguested statement to vendor policy:

      device/google/cuttlefish/shared/sepolicy/vendor/hal_virtio_rtc_default.te
      allow hal_virtio_rtc_default servicemanager:binder call;
      allow hal_virtio_rtc_default servicemanager:binder { call transfer };
    5. Rebuild again, and check service in the logcat or dmesg, expect it fails with another avc: denied error:

      I auditd : avc: denied { add } for pid=3947 uid=1000 name=vendor.trongvq.virtio_rtc.IVirtio_RTC/default scontext=u:r:hal_virtio_rtc_default:s0 tcontext=u:object_r:default_android_service:s0 tclass=service_manager permissive=0
    6. Run the tool and add suguested statement to vendor policy:

      device/google/cuttlefish/shared/sepolicy/vendor/hal_virtio_rtc_default.te
      allow hal_virtio_rtc_default default_android_service:service_manager add;
    7. Building again and expect the following SELinux neverallow build error due to service_manager add permission:

      neverallow check failed at out/soong/.intermediates/system/sepolicy/plat_pub_versioned.cil/android_common/vsoc_x86_64_only/plat_pub_versioned.cil:6162
      (neverallow base_typeattr_224_202404 default_android_service_202404 (service_manager (add find list)))
      <root>
      allow at out/soong/.intermediates/system/sepolicy/vendor_sepolicy.cil/android_common/vsoc_x86_64_only/vendor_sepolicy.cil:1697
      (allow hal_virtio_rtc_default default_android_service_202404 (service_manager (add)))

      Open system/sepolicy/public/domain.te, it has a specific neverallow rule that does not allow service_manager to add a default_android_service:

      system/sepolicy/public/domain.te
      # Do not allow service_manager add for default service labels.
      # Instead domains should use a more specific type such as
      # system_app_service rather than the generic type.
      # New service_types are defined in {,hw,vnd}service.te and new mappings
      # from service name to service_type are defined in {,hw,vnd}service_contexts.
      neverallow * default_android_service:service_manager *;
      neverallow * default_android_vndservice:service_manager *;
      neverallow * default_android_hwservice:hwservice_manager *;

      To fix this, need to define a specific service type:

      device/google/cuttlefish/shared/sepolicy/vendor/service.te
      # Virtio_RTC Service
      type hal_virtio_rtc_service, service_manager_type, hal_service_type;

      then assign it a new label:

      device/google/cuttlefish/shared/sepolicy/vendor/service_contexts
      # Virtio_RTC Service
      vendor.trongvq.virtio_rtc.IVirtio_RTC/default u:object_r:hal_virtio_rtc_service:s0

      then change default_android_service to hal_virtio_rtc_service in service_manager add:

      device/google/cuttlefish/shared/sepolicy/vendor/hal_virtio_rtc_default.te
      allow hal_virtio_rtc_default default_android_service:service_manager add;
      allow hal_virtio_rtc_default hal_virtio_rtc_service:service_manager add;
  4. Rebuild and verify service is working well

    service list | grep virtio_rtc
    292 vendor.trongvq.virtio_rtc.IVirtio_RTC/default: [vendor.trongvq.virtio_rtc.IVirtio_RTC]

Interface Native Test App


  • Directorydevice/google/cuttlefish/shared/sepolicy/vendor
    • service.te
    • service_contexts
    • file.te
    • file_contexts
    • hal_virtio_rtc_default.te
  • Directoryvendor/trongvq/
    • device_framework_matrix.xml # compatibility
    • Directoryinterfaces/virio_rtc
      • Android.bp
      • Directoryvendor/trongvq/virtio_rtc
        • IVirtio_RTC.aidl
        • Directorytest
          • Android.bp
          • Virtio_RTC_Test.cpp
    • Directoryservices/virtio_rtc
      • Android.bp
      • Directoryinc
        • Virtio_RTC.h
      • Directorysrc
        • Virtio_RTC.cpp
        • Virtio_RTC_Service.cpp
      • vendor.trongvq.virtio_rtc-service.rc # start service at startup
      • vendor.trongvq.virtio_rtc-service.xml # declare and configure interface

  1. Create Android.bp to declare a test binary:

    vendor/trongvq/interfaces/virtio_rtc/test/Android.bp
    cc_binary {
    name: "Virtio_RTC_Test",
    vendor: true,
    relative_install_path: "hw",
    srcs: ["Virtio_RTC_Test.cpp"],
    shared_libs: [
    "libbinder_ndk",
    "vendor.trongvq.virtio_rtc-V1-ndk",
    ],
    }
  2. Create Virtio_RTC_Test.cpp to implement the test binary:

    vendor/trongvq/interfaces/virtio_rtc/test/Virtio_RTC_Test.cpp
    #include <aidl/vendor/trongvq/virtio_rtc/IVirtio_RTC.h>
    #include <android/binder_manager.h>
    #include <chrono>
    #include <iostream>
    #include <thread>
    using aidl::vendor::trongvq::virtio_rtc::IVirtio_RTC;
    int main(int argc, char **argv) {
    std::string instance = std::string(IVirtio_RTC::descriptor) + "/default";
    std::shared_ptr<IVirtio_RTC> rtc = IVirtio_RTC::fromBinder(
    ndk::SpAIBinder(AServiceManager_getService(instance.c_str())));
    std::string time;
    rtc->getTime(&time);
    std::cout << "Current time: " << time; // returned string has newline
    std::this_thread::sleep_for(std::chrono::seconds(1));
    rtc->getTime(&time);
    std::cout << "Current time: " << time;
    bool success = false;
    rtc->setTime("1234", &success);
    rtc->getTime(&time);
    std::cout << "Current time: " << time;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    rtc->getTime(&time);
    std::cout << "Current time: " << time;
    return 0;
    }
  3. Change owner of /dev/virtio_rtc:

    When build and run vendor/bin/hw/Virtio_RTC_Test, it prints out:

    E vendor.trongvq.virtio_rtc-service: Failed to open /dev/virtio_rtc

    Device is created for root user:

    ls -al /dev/virtio_rtc
    crw------- 1 root root 488, 0 2024-10-27 13:12 /dev/virtio_rtc

    Service is running under system user:

    ps -AZ | grep virtio_rtc
    u:r:hal_virtio_rtc_default:s0 system binder_ioctl_write_read 0 S vendor.trongvq.virtio_rtc-service

    Need to add an action at start up:

    vendor/trongvq/services/virtio_rtc/vendor.trongvq.virtio_rtc-service.rc
    on boot
    chown system root /dev/virtio_rtc
  4. Add SE Policy for /dev/virtio_rtc:

    When build and run again, vendor/bin/hw/Virtio_RTC_Test prints out audit error:

    W binder:506_1: type=1400 audit(0.0:113): avc: denied { read } for name="virtio_rtc" dev="tmpfs" ino=1297 scontext=u:r:hal_virtio_rtc_default:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=0
    W binder:506_1: type=1400 audit(0.0:113): avc: denied { write } for name="virtio_rtc" dev="tmpfs" ino=1297 scontext=u:r:hal_virtio_rtc_default:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=0

    Run audit2allow to get:

    #============= hal_virtio_rtc_default ==============
    allow hal_virtio_rtc_default device:chr_file { read write };

    However, it conflics with a neverallow rule for general device:

    system/sepolicy/public/domain.te
    # Don't allow raw read/write/open access to generic devices.
    # Rather force a relabel to a more specific type.
    neverallow domain device:chr_file { open read write };

    Therefore, define a new label virtio_rtc_device:

    device/google/cuttlefish/shared/sepolicy/vendor/file.te
    # Virtio_RTC Device
    type virtio_rtc_device, dev_type;

    Then assign new label to the dev /dev/virtio_rtc:

    device/google/cuttlefish/shared/sepolicy/vendor/file_contexts
    # Virtio_RTC Device
    /dev/virtio_rtc u:object_r:virtio_rtc_device:s0

    Finally, allow service to access the device with defined label:

    device/google/cuttlefish/shared/sepolicy/vendor/hal_virtio_rtc_default.te
    allow hal_virtio_rtc_default virtio_rtc_device:chr_file { open read write };
  5. Rebuild and run, verify that the test binary can get and set Virtio_RTC seconds:

    vendor/bin/hw/Virtio_RTC_Test
    output
    Current time: 86
    Current time: 87
    Current time: 1234
    Current time: 1235
    logcat
    I vendor.trongvq.virtio_rtc-service: Current time: 86
    I vendor.trongvq.virtio_rtc-service: Current time: 87
    I vendor.trongvq.virtio_rtc-service: Setting time to 1234
    I vendor.trongvq.virtio_rtc-service: Current time: 1234
    I vendor.trongvq.virtio_rtc-service: Current time: 1235

Vendor Test Suite


Refer: https://source.android.com/docs/core/tests/vts.

The Android Vendor Test Suite (VTS) provides extensive testing on the following:

  • Kernel
  • Hardware abstraction layer (HAL)

VTS runs on a desktop machine and executes test cases directly on attached devices or on the emulators. The test cases can be GTest-style tests, kernel tests, or JUnit-style tests written in Java.

  • Directorydevice/google/cuttlefish/shared/sepolicy/vendor
    • service.te
    • service_contexts
    • file.te
    • file_contexts
    • hal_virtio_rtc_default.te
  • Directoryvendor/trongvq/
    • device_framework_matrix.xml # compatibility
    • Directoryinterfaces/virio_rtc
      • Android.bp
      • Directoryvendor/trongvq/virtio_rtc
        • IVirtio_RTC.aidl
        • Directorytest
          • Android.bp
          • Virtio_RTC_Test.cpp
    • Directoryservices/virtio_rtc
      • Android.bp
      • Directoryinc
        • Virtio_RTC.h
      • Directorysrc
        • Virtio_RTC.cpp
        • Virtio_RTC_Service.cpp
      • vendor.trongvq.virtio_rtc-service.rc # start service at startup
      • vendor.trongvq.virtio_rtc-service.xml # declare and configure interface
    • Directoryvts
      • Android.bp
      • Vts_Virtio_RTC_Test.cpp

  1. Create Android.bp to declare VTS Test Suite:

    vendor/trongvq/vts/Android.bp
    cc_test {
    name: "VtsVirtioRTCTest",
    defaults: [
    "VtsHalTargetTestDefaults",
    "use_libaidlvintf_gtest_helper_static",
    ],
    srcs: [
    "Vts_Virtio_RTC_Test.cpp",
    ],
    cflags: [
    "-Wall",
    "-Werror",
    ],
    shared_libs: [
    "liblog",
    "libutils",
    "libbinder_ndk",
    "vendor.trongvq.virtio_rtc-V1-ndk",
    ],
    static_libs : [
    ],
    test_suites: [
    "general-tests", // atest
    "vts", // vts run
    ],
    compile_multilib: "64"
    }
  2. Create Vts_Virtio_RTC_Test.cpp to impelement test cases:

    vendor/trongvq/vts/Vts_Virtio_RTC_Test.cpp
    #include <android/binder_manager.h>
    #include <android/binder_process.h>
    #include <gtest/gtest.h>
    #include <thread>
    #include <aidl/vendor/trongvq/virtio_rtc/IVirtio_RTC.h>
    using aidl::vendor::trongvq::virtio_rtc::IVirtio_RTC;
    class VirtioRTCServiceTest : public testing::Test {
    public:
    void SetUp() override {
    std::string instance = std::string(IVirtio_RTC::descriptor) + "/default";
    mService = IVirtio_RTC::fromBinder(
    ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())));
    ASSERT_NE(mService, nullptr);
    }
    std::shared_ptr<IVirtio_RTC> mService;
    };
    TEST_F(VirtioRTCServiceTest, GetTime) {
    std::string time1;
    ASSERT_TRUE(mService->getTime(&time1).isOk());
    ASSERT_FALSE(time1.empty());
    std::this_thread::sleep_for(std::chrono::milliseconds(1100));
    std::string time2;
    ASSERT_TRUE(mService->getTime(&time2).isOk());
    ASSERT_FALSE(time2.empty());
    ASSERT_NE(time1, time2);
    }
    TEST_F(VirtioRTCServiceTest, SetTime) {
    std::string time("1234\n");
    bool success = false;
    std::string time1;
    ASSERT_TRUE(mService->getTime(&time1).isOk());
    ASSERT_FALSE(time1.empty());
    ASSERT_NE(time1, time);
    ASSERT_TRUE(mService->setTime(time, &success).isOk());
    ASSERT_TRUE(success);
    std::string time2;
    ASSERT_TRUE(mService->getTime(&time2).isOk());
    ASSERT_FALSE(time2.empty());
    ASSERT_EQ(time2, time);
    }
    int main(int argc, char **argv) {
    ABinderProcess_setThreadPoolMaxThreadCount(1);
    ABinderProcess_startThreadPool();
    std::thread([] { ABinderProcess_joinThreadPool(); }).detach();
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
    }
  3. Export AIDL for vendor access:

    When buid, there is an error that AIDL NDK variant is missing:

    error: vendor/trongvq/vts/Android.bp:1:1: dependency "vendor.trongvq.virtio_rtc-V1-ndk" of "VtsVirtioRTCTest" missing variant:
    os:android,image:,arch:x86_64_silvermont,sdk:,link:shared

    Export the ADIL using keyword vendor_available:

    vendor/trongvq/interfaces/virtio_rtc/Android.bp
    vendor: true, // installed in /vendor
    vendor_available: true, // export for vendors

    Then rebuild the system.

  4. Run atest:

    atest VtsVirtioRTCTest
    x86_64 VtsVirtioRTCTest
    -----------------------
    VtsVirtioRTCTest (2 Tests)
    [1/2] VirtioRTCServiceTest#GetTime: PASSED (1.101s)
    [2/2] VirtioRTCServiceTest#SetTime: PASSED (0ms)
    Summary (Test executed with 1 devices.)
    -------
    x86_64 VtsVirtioRTCTest: Passed: 2, Failed: 0, Ignored: 0, Assumption Failed: 0
    All tests passed!
  5. Run VTS:

    Firstly, build VTS Trade Federation test framework:

    m vts -j10

    Then enter the VTS Trade Federation Console:

    vts-tradefed

    Then execute a VTS Test Suite:

    run vts -m VtsVirtioRTCTest
    ================= Results ==================
    =============== Consumed Time ==============
    x86_64 VtsVirtioRTCTest: 7s
    Total aggregated tests run time: 7s
    ============== TOP 1 Slow Modules ==============
    x86_64 VtsVirtioRTCTest: 0.27 tests/sec [2 tests / 7282 msec]
    ============== Modules Preparation Times ==============
    x86_64 VtsVirtioRTCTest => prep = 2887 ms || clean = 5982 ms
    Total preparation time: 2s || Total tear down time: 5s
    =======================================================
    =============== Summary ===============
    Total Run time: 1m 2s
    1/1 modules completed
    Total Tests : 2
    PASSED : 2
    FAILED : 0
    ============== End of Results ==============

    Note: VTS Trade Federation test framework will not execute the tests immmediately, it will take upto a minute to probe, set up the Device. Test is scheduled, and re-run after a device is found.

  6. Customize the test configuration:

    Run make command to build the config, then search for a generated config file.

    m VtsVirtioRTCTest
    find out/ -name VtsVirtioRTCTest.config
    out/target/product/vsoc_x86_64_only/testcases/VtsVirtioRTCTest/VtsVirtioRTCTest.config
    <configuration description="Runs VtsVirtioRTCTest.">
    <option name="test-suite-tag" value="apct" />
    <option name="test-suite-tag" value="apct-native" />
    <!-- Use Root -->
    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
    </target_preparer>
    <!-- Target location -->
    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
    <option name="cleanup" value="true" />
    <option name="push" value="VtsVirtioRTCTest->/data/local/tmp/VtsVirtioRTCTest" />
    </target_preparer>
    <!-- Test Type -->
    <test class="com.android.tradefed.testtype.GTest" >
    <option name="native-test-device-path" value="/data/local/tmp" />
    <option name="module-name" value="VtsVirtioRTCTest" />
    </test>
    </configuration>

    Custom config file can be set in Android.bp:

    Android.bp
    test_config: "Vts_Virtio_RTC_Test.xml",