When we learn Android HAL development, we may encounter some compilation or runtime errors, which may affect the exploration script. In order to effectively locate and resolve these errors, you need to understand the architecture, tools, and methods of Android HAL. This article will introduce some of my own debugging skills and solutions to common errors when learning Android HAL. I hope it can help everyone.
Other articles on the Internet will never tell you the complete debugging process. At most, they will only tell you the results. You will know how many pitfalls there are when you try it yourself. This article only records less than half of the problems I encountered. Some of them are not very common and I am too lazy to record them.
Please correct me if there are any errors. HAL-related debugging and solutions will be updated here later. If you have any questions, please feel free to ask~
Series of articles:
Android HAL in-depth exploration (1): Architecture overview
Android HAL in-depth exploration (2): Traditional HAL and file encryption and decryption simulation
Android HAL in-depth exploration (3): HIDL Passthrough mode and serial port data callback simulation
Android HAL in-depth exploration (4 ): HIDL Binderized mode and CAN data callback simulation
Android HAL in-depth exploration (5): Debugging HAL error reports and solutions
问题1:declares types rather than the expected interface type ‘ICanBus’
When trying to compile a [email protected]
HAL called, you may encounter the following error:
declares types rather than the expected interface type 'ICanBus'
ERROR: Could not parse [email protected]::ICanBus. Aborting.
.hal
This error means that the interface is not defined correctly in our file, but some types (like or ) ICanBus
are declared instead . This violates the syntax rules of the HIDL language, since the file must start with an interface definition, and there can only be one interface definition.struct
enum
.hal
简单的说就是hal文件里面必须以interface 开头,不然就会报这个错误。
Reason: .hal
The structure of the file does not comply with HIDL syntax rules
HIDL language is a language used to define Android HAL interfaces. It has some specific syntax rules and conventions. One of them is that .hal
the file must start with an interface definition, and there can only be one interface definition. For example, if you want to define an [email protected]::ICanBus
interface named, .hal
the file should look like this:
package [email protected];
interface ICanBus {
// methods and types for the interface
}
struct
If some types (such as or ) are declared before or after the interface definition enum
, then the HIDL compiler ( hidl-gen
) will report an error because it cannot parse our interface definition. If our .hal
file looked like this:
package [email protected];
struct CanFrame {
// fields for the struct
}
interface ICanBus {
// methods and types for the interface
}
Then the HIDL compiler will report an error:
declares types rather than the expected interface type 'ICanBus'
ERROR: Could not parse [email protected]::ICanBus. Aborting.
Solution: Reorganize .hal
files or create new .hal
files
In order to solve this error, there are two solutions:
- Reorganize
.hal
the file: Move the interface definition to the top of the file, and then place the other type definitions. The above.hal
file can be modified to:
package [email protected];
interface ICanBus {
// methods and types for the interface
}
struct CanFrame {
// fields for the struct
}
- Create a new
.hal
file: If we want to separate the type definition and the interface definition, we can create a new.hal
file to store the type definition and.hal
import it in the original file. You can create aCanTypes.hal
file named:
package [email protected];
struct CanFrame {
// fields for the struct
}
.hal
Then import it in the original file:
package [email protected];
import [email protected];
interface ICanBus {
// methods and types for the interface
}
问题2:Expecting only package name and version
When trying to use hidl-gen
tools to generate implementation code for a HIDL interface, you may encounter the following error:
ERROR: Expecting only package name and version.
ERROR: output handler failed.
This error means that our command line parameters did not meet hidl-gen
the requirements because we provided redundant or wrong parameters.
Reason: The command line parameter format is incorrect.
hidl-gen
It is a tool for generating implementation code of HIDL interfaces. It has some specific command line parameter formats and options. One of the required parameters is the package name and version number of the HIDL interface, which should look like this:
package@version
For example, if we want to generate [email protected]::ICanBus
the implementation code of the interface, we should provide the following parameters:
[email protected]
If other content is added after this parameter, such as the interface name or file name, an hidl-gen
error will be reported because it only expects a package name and version number.
Solution: Correct the command line parameters
In order to solve this error, we need to modify our command line parameters to only provide the package name and version number. For example, if we used this command before:
hidl-gen -o hardware/interfaces/can_bus/1.0/default -Landroidbp-impl \
-randroid.hardware:hardware/interfaces \
-randroid.hidl:system/libhidl/transport \
[email protected]::ICanBus
It should be modified to:
hidl-gen -o hardware/interfaces/can_bus/1.0/default -Landroidbp-impl \
-randroid.hardware:hardware/interfaces \
-randroid.hidl:system/libhidl/transport \
[email protected]
hidl-gen -o hardware/interfaces/can_bus/1.0/default -Lc++-impl \
-randroid.hardware:hardware/interfaces \
-randroid.hidl:system/libhidl/transport \
[email protected]::ICanBus
这个命令会在输出目default录中生成C++或Android BP的接口代码
hidl-gen -o hardware/interfaces/can_bus/1.0/default -Landroidbp-impl \
-randroid.hardware:hardware/interfaces \
-randroid.hidl:system/libhidl/transport \
[email protected]
这个命令会在输出default目录中生成一个名为Android.bp的文件,包含了HIDL软件包的编译信息。
hardware/interfaces/can_bus$ tree
.
└── 1.0
├── Android.bp
├── default
│ ├── Android.bp
│ ├── CanBus.cpp
│ └── CanBus.h
└── ICanBus.hal
问题3:module “[email protected]” variant “android_arm64_armv8-a_cortex-a55”: depends on //system/libhwbinder:libhwbinder which is not visible to this module
When trying to compile a [email protected]
HAL service called, you may encounter the following error:
error: hardware/interfaces/can_bus/1.0/service/Android.bp:1:1: module "[email protected]" variant "android_arm64_armv8-a_cortex-a55": depends on //system/libhwbinder:libhwbinder which is not visible to this module
10:08:10 soong bootstrap failed with: exit status 1
This error means that our HAL service module depends on a library that is not visible to it, ie //system/libhwbinder:libhwbinder
. This violates the visibility rules of the Soong build system, as each module must declare other modules it can access.
Cause: Visibility attribute missing or wrong
The Soong build system, Android's tool for compiling source code, uses a language called Blueprint to describe modules and the relationships between them. The Blueprint language has some properties and keywords to control the visibility of modules, that is, which modules can access which modules.
One of the properties is visibility
that it is possible to specify in a module's definition which other modules can depend on it. If you want to make a testhal
module named visible only to other modules in the same package, you can write:
cc_library {
name: "testhal",
visibility: [":__subpackages__"],
}
If you want to make a testhal2
module named visible to all other modules, you can write:
cc_library {
name: "testhal2",
visibility: ["//visibility:public"],
}
In the above example, //
it represents the root directory, :
represents the separator within the package, and __subpackages__
represents all sub-packages in the same package.
If a module does not specify visibility
an attribute, then by default it is only visible to other modules in the same package. If a module specifies incorrect or mismatching visibility
attributes, it may cause compilation errors.
In my case, the HAL service module relied on a library located in the system partition, ie //system/libhwbinder:libhwbinder
. But visibility
the properties of this library are like this:
cc_library {
name: "libhwbinder",
visibility: [":__subpackages__"],
}
This library is only visible to other modules in the same package, that is, it is only visible to modules located under //hardware/interfaces/can_bus/1.0/...
(I guess it is impossible to express ). //system/libhwbinder/...
And my HAL service module is located //hardware/interfaces/can_bus/1.0/service/...
below, so it cannot access this library.
Solution: Modify or add visibility properties
To resolve this error, I tried two options:
- Modify the visibility properties of libraries: Modify libraries in the system partition and modify their visibility properties to make them visible to required modules. If you want to make it
//hardware/interfaces/can_bus/1.0/service/...
visible to all HAL service modules, you can modify it like this:
cc_library {
name: "libhwbinder",
export_include_dirs: ["include"],
visibility: [
":__subpackages__",
"//hardware/interfaces/...:service",
],
}
This way you //hardware/interfaces/can_bus/1.0/...
can service
depend on this library in any included module below.
or
+++ b/system/libhwbinder/Android.bp
@@ -66,7 +66,11 @@ cc_library {
export_include_dirs: ["include"],
- visibility: [":__subpackages__"],
+// visibility: [
+// ":__subpackages__",
+// ],
+visibility: ["//visibility:public"],
+
}
In this way, all modules and all paths can depend on this library.
Question 4: VNDK library list has been changed
When I try to compile a [email protected]
HAL called, I get the following error:
[ 10% 571/5241] build out/target/product/rk3568_r/obj/PACKAGING/vndk_intermediates/check-list-timestamp
FAILED: out/target/product/rk3568_r/obj/PACKAGING/vndk_intermediates/check-list-timestamp
/bin/bash -c "(( diff --old-line-format=\"Removed %L\" --new-line-format=\"Added %L\" --unchanged-line-format=\"\" build/make/target/product/gsi/30.txt out/soong/vndk/vndk.libraries.txt || ( echo -e \" error: VNDK library list has been changed.\\n\" \" Changing the VNDK library list is not allowed in API locked branches.\"; exit 1 )) ) && (mkdir -p out/target/product/rk3568_r/obj/PACKAGING/vndk_intermediates/ ) && (touch out/target/product/rk3568_r/obj/PACKAGING/vndk_intermediates/check-list-timestamp )"
Added VNDK-core: [email protected]
error: VNDK library list has been changed.
Changing the VNDK library list is not allowed in API locked branches.
10:21:14 ninja failed with: exit status 1
This error means that my HAL was added to the VNDK library list, but current.txt
was not listed in the file, causing a compilation error. current.txt
The file is a file that defines the list of VNDK libraries supported by the current Android version. It is located build/make/target/product/vndk/
in the directory. 30.txt
The file is a file that defines the list of VNDK libraries supported by Android 11. It is located build/make/target/product/gsi/
in the directory.
Reason: The VNDK library list is inconsistent or illegal
According to the information I checked:
The VNDK library list is a mechanism used to ensure the stability of the interface between vendors and systems. It specifies which framework shared libraries can be used by vendor modules and maintains compatibility between different Android versions. The VNDK library list has the following characteristics:
- The list of VNDK libraries is in alphabetical order.
- The VNDK library list only includes eligible VNDK libraries (Eligible-VNDK) and VNDK-core libraries.
- The VNDK library list does not include the LL-NDK library, VNDK-SP library, VNDK-SP-Ext library, VNDK-Ext library, FWK-ONLY library and SP-HAL library.
- VNDK library list is not allowed to change in API locked branches.
API locked branches refer to Android version branches that have been released or are about to be released, such as android-11 or android-s-beta-2. In these branches, the VNDK library list has been frozen, and no more libraries can be added or removed. This is to ensure compatibility between system and vendor partitions, as well as to support framework-specific updates (i.e. only update the system partition and not the vendor partition).
If we try to modify the VNDK library list in the API locked branch, or add libraries that do not comply with VNDK standards to the VNDK library list, the compilation system will report an error and stop the build.
Solution: Decide whether to add it to VNDK based on the nature and purpose of HAL
To resolve this error, I need to decide based on the nature and purpose of my HAL whether it should be added to the VNDK or not. If my HAL does need to be part of the VNDK, I can follow these steps:
-
Update
current.txt
: In the file, will be added to the appropriate locationcurrent.txt
depending on the nature of my HAL .[email protected]
If it is a core VNDK library, you can add it toVNDK-core
the section. You must pay attention to inserting them in alphabetical order, otherwise a compilation error will be reported. -
Update
30.txt
:30.txt
Here is the list of VNDK libraries for Android 11. If modified , the same modificationscurrent.txt
should be made in to ensure consistency between the two.30.txt
Care must be taken to insert them in alphabetical order.
But if our HAL is not supposed to be part of the VNDK, then any section marking it as VNDK should be removed from the build configuration and make sure it is not added to the VNDK library list. You can add an attribute to the Android.bp file of the HAL module (I haven’t figured out what the specific difference is yet, but I read this on the Internet):
vndk: {
enabled: false,
},
This way the system will not see the module as a VNDK library, but as a normal HAL module. This module will not be shared by the system partition and the supplier partition, but can only be used by the supplier partition.
This problem bothered me for a long time when I first worked on HIDL. Fortunately, I had added notes based on my review before. . .
In short, I will tell you a very simple method. After comparing these two files with a comparison tool, directly use the one in the out directory to the build directory and it will be OK out\soong\vndk\vndk.libraries.txt
.
build\target\product\gsi\30.txt
For more VNDK, please refer to the following link:
- Vendor Native Development Kit (VNDK) : Introduces the concepts, resources, classification and version control of VNDK.
- Android: Vendor Native Development Kit (VNDK) : Introduces the overview of VNDK, the distinction between libraries between frameworks and vendors, security policies, etc.
- What is VNDk?: Answers basic questions about VNDK.
- How to extend exported symbols using VNDk?: Describes how to use VNDK extensions to extend the AOSP library without breaking compatibility.
Question 5: hwservicemanager cannot find the HAL interface error
09-09 15:24:22.448 8915 8915 I [email protected]: CanBusService created
09-09 15:24:22.449 141 141 I hwservicemanager: getTransport: Cannot find entry [email protected]::ICanBus/default in either framework or device manifest.
09-09 15:24:22.450 8915 8915 E HidlServiceManagement: Service [email protected]::ICanBus/default must be in VINTF manifest in order to register/get.
This error means that my HAL service is trying to register to hwservicemanager
, but hwservicemanager
the corresponding entry cannot be found in the VINTF (Vendor Interface) manifest. VINTF manifests were introduced in Android 8.0 and higher to describe the interface between the HAL and the framework.
In order to resolve this error, we need to ensure that our HAL interface has been added to the VINTF manifest. Here are the steps on how to do this:
Step 1: Create or modify a VINTF manifest
In the source code directory, usually system
under the directory, find a manifest.xml
file called . This file is used to describe the HAL interface and version provided by our device, as well as other device-related information, such as SELinux policy version, etc.
Step 2: Add HAL interface to manifest
In manifest.xml
, add our HAL interface. The name, transmission method, version and instance of the interface need to be specified. For example, if we want to add an [email protected]::ICanBus
interface named and it uses hwbinder as the transport and has an instance named default, we can write:
<manifest version="1.0" type="device">
。。。
<hal format="hidl">
<name>android.hardware.can_bus</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>ICanBus</name>
<instance>default</instance>
</interface>
</hal>
<!-- 其他HAL接口 -->
。。。
</manifest>
<hal>
Multiple versions and instances can be added in a tag, as well as HAL interfaces in other formats, such as AIDL or native.
For more information about hwservicemanager and VINTF manifest, you can refer to the following link:
- HIDL : Introduces the HIDL language and architecture, and how to use hwservicemanager to manage HIDL services.
- Vendor Interface Object : Introduces the design and role of VINTF objects, and how to use lists and matrices to describe and match HAL interfaces.
Issue 6: Debugging and resolving errors where the extends attribute references a non-VNDK library
error: hardware/interfaces/can_bus/1.0/service/Android.bp:2:1: module "[email protected]" variant "android_vendor.30_arm64_armv8-a_cortex-a55": `extends` refers a non-vndk module "libhidltransport"
14:34:14 soong bootstrap failed with: exit status 1
This error prompts me that the system? A non-VNDK library is referenced in the partition, that is libhidltransport
. In Android 8.0 and above, to ensure device backward compatibility, Google introduced the VNDK concept. VNDK libraries are those libraries that are safe to use in vendor partitions.
To solve this problem, here is my attempt:
Method 1: Remove the extends attribute
If an inherited libhidltransport
property is not needed, you can simply vndk
remove extends
the property from the block. For example, in the Android.bp file of the HAL module, you can write:
cc_binary {
name: "[email protected]",
vendor: true,
vndk: {
enabled: true,
support_system_process: false,
},
srcs: ["CanBus.cpp"],
shared_libs: [
"[email protected]",
"libhidltransport",
"libhidlbase",
"libutils",
"libcutils",
"liblog",
],
}
This way the properties of non-VNDK libraries will not be referenced, but the default properties will be used.
Method 2: Use the VNDK version of the library
If libhidltransport
there is a VNDK version, for example libhidltransport_vndk
, we should shared_libs
use it in and extends
specify it in . In the Android.bp file of our HAL module, we can write:
cc_binary {
name: "[email protected]",
vendor: true,
vndk: {
enabled: true,
support_system_process: false,
extends: "libhidltransport_vndk",
},
srcs: ["CanBus.cpp"],
shared_libs: [
"[email protected]",
"libhidltransport_vndk",
"libhidlbase",
"libutils",
"libcutils",
"liblog",
],
}
You can inherit the properties of the VNDK library and will not reference non-VNDK libraries.
There is another way, which is similar to question 3. In fact, libhidltransport also has a visible attribute, which needs to be searched in the source code. Anyway, I was a little dizzy after working on Android.bp for a long time, so I just killed the libhidltransport dependent library. , it has no effect and I don’t understand the reason. Just treat this as a hole and fill it in later.
Question 7: How to debug and solve the error that the init process cannot start the service
09-09 15:50:30.479 0 0 E init : Control message: Could not ctl.start for 'vendor.hw_canbus' from pid: 2563 (start vendor.hw_canbus): File /system/bin/hw/[email protected](labeled "u:object_r:system_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
09-09 15:50:30.357 2563 2563 W libc : Unable to set property "ctl.start" to "vendor.hw_canbus": error code: 0x20
This error means that the HAL service cannot init
be started by the process because it does not have the correct SELinux context or domain translation. init
The process is the core process in the Android system responsible for starting and managing services. It has its own SELinux context (usually u:r:init:s0
) and needs to follow SELinux policies to perform the starting and stopping of services.
In order to resolve this error, you need to ensure the following:
Step 1: Confirm file context
File context is a mechanism used by SELinux to mark the security attributes of files, which includes user, role, type and optional level. File context can ls -Z
be viewed with commands, for example:
$ ls -Z /system/bin/hw/[email protected]
-rwxr-xr-x root root u:object_r:system_file:s0 /system/bin/hw/[email protected]
Here you can see that the file type system_file
is a general type and is not suitable for use in our HAL service. We need to define a specialized type for the HAL service, for example can_bus_exec
, and set the file context to that type at compile time.
Step 2: Service Definition
Service definition is .rc
a mechanism for specifying the start and stop methods, dependencies, priorities, resource limits and other information of the HAL service in a file. .rc
Files are usually located in our device-specific source code directory, eg system/etc/init/[email protected]
. In .rc
the file, we need to add a tag similar to the following for our HAL service:
service vendor.hw_canbus /system/bin/hw/[email protected]
class hal
user system
group system
seclabel u:object_r:hal_canbus_default_exec:s0
You can also add the following lines in the file_contexts file:
/(vendor|system)/bin/hw/android\.hardware\.canbus@1\.0-service u:object_r:hal_canbus_default_exec:s0
This paragraph indicates that a service named is defined vendor.hw_canbus
, which executes a /system/bin/hw/[email protected]
program named. It belongs to main
the category, runs as system user and system group, and has a seclabel u:object_r:hal_canbus_default_exec:s0
SELinux context named. It is a one-time service, that is, it only runs once and does not restart.
Step 3: Recompile and confirm
After completing the changes, run the following command on the device to check whether our HAL service has been started correctly
. If everything is OK, you can see output similar to the following:
09-11 09:07:46.421 9125 9125 I [email protected]: CanBusService created
09-11 09:07:46.424 9125 9125 I HidlServiceManagement: Registered [email protected]::ICanBus/default
09-11 09:07:46.424 9125 9125 I HidlServiceManagement: Removing namespace from process name [email protected] to [email protected].
09-11 09:07:46.424 9125 9125 I [email protected]: CanBusService is ready.
rk
#输出结果显示了一个名为[email protected]的进程,其进程ID为3435,它是由root用户启动的,并且当前处于睡眠状态(S)
3568_r:/ # ps -A | grep can
root 3435 567 10773968 2788 binder_thread_read 0 S [email protected]
#输出结果显示了一个名为[email protected]::ICanBus/default的HAL服务。这表示系统上有一个实现了[email protected]接口的HAL服务,并且它的实例名为default。
rk3568_r:/ # lshal | grep can
FM N [email protected]::ICanBus/default 0/1 3435 148
Label debugging process
rk3568_r:/system # find -name "*can*.rc"
./etc/init/[email protected]
rk3568_r:/system # cat ./etc/init/[email protected]
on boot
start vendor.hw_canbus
service vendor.hw_canbus /system/bin/hw/[email protected]
class hal
user system
group system
seclabel u:object_r:hal_canbus_default_exec:s0
rk3568_r:/system # start vendor.hw_canbus
Unable to start service 'vendor.hw_canbus'
See dmesg for error reason.
rk3568_r:/ # ls -llZ /system/bin/hw/[email protected]
-rwxr-xr-x 1 root shell u:object_r:system_file:s0 16616 2023-09-09 15:06:27.000000000 +0800 /system/bin/hw/[email protected]
rk3568_r:/ # restorecon /system/bin/hw/[email protected]
SELinux: Loaded file_contexts
rk3568_r:/ # ls -llZ /system/bin/hw/[email protected]
-rwxr-xr-x 1 root shell u:object_r:system_file:s0 16616 2023-09-09 15:06:27.000000000 +0800 /system/bin/hw/[email protected]
rk3568_r:/ # chcon u:object_r:hal_canbus_default_exec:s0 /system/bin/hw/[email protected]
r:hal_canbus_default_exec:s0 /system/bin/hw/[email protected]^C <
130|rk3568_r:/ # ls -llZ /system/bin/hw/[email protected]
-rwxr-xr-x 1 root shell u:object_r:hal_canbus_default_exec:s0 16616 2023-09-09 15:06:27.000000000 +0800 /system/bin/hw/[email protected]
This indicates that our HAL service has started successfully and has the correct SELinux context.
Question 8: Prompt android/hardware/can_bus/1.0/ICanBus.h
file cannot be found
When I added native frameworks/base/services/core/jni/com_android_server_SystemCanBusService.cpp
, I encountered an error when compiling, indicating that android/hardware/can_bus/1.0/ICanBus.h
the file could not be found.
frameworks/base/services/core/jni/com_android_server_SystemCanBusService.cpp:6:10: fatal error: 'android/hardware/can_bus/1.0/ICanBus.h' file not found
#include <android/hardware/can_bus/1.0/ICanBus.h>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Reason: Not generated correctly
android/hardware/can_bus/1.0/ICanBus.h
The header file was not generated correctly or its path was not correctly included in the compile-time header file search path.
Solution: Modify jni Android.bp so that the library is correctly included in the compilation dependencies
- Use
hidl-gen
the command to manually generate the required header files. This command willhardware/interfaces/can_bus/1.0/default
generate agen
subdirectory under the directory containingandroid/hardware/can_bus/1.0/ICanBus.h
the files.
hidl-gen -o hardware/interfaces/can_bus/1.0/default -Lc++-headers \
-randroid.hardware:hardware/interfaces \
-randroid.hidl:system/libhidl/transport \
[email protected]
hardware$ find -name "ICanBus.h"
./interfaces/can_bus/1.0/default/android/hardware/can_bus/1.0/ICanBus.h
-
Modify
frameworks/base/services/core/jni/Android.bp
the file to ensure that[email protected]
the library is correctly included in the build dependencies.@@ -155,6 +156,7 @@ cc_defaults { "[email protected]", "[email protected]", "[email protected]", + "[email protected]", "[email protected]", "[email protected]", "[email protected]",
The above steps can solve ICanBus.h
the problem of file not being found during compilation.