Skip to content

Instantly share code, notes, and snippets.

@SebaUbuntu
Last active September 10, 2025 05:26
Show Gist options
  • Select an option

  • Save SebaUbuntu/ec053a00a9988eaea091fb1cc1f19324 to your computer and use it in GitHub Desktop.

Select an option

Save SebaUbuntu/ec053a00a9988eaea091fb1cc1f19324 to your computer and use it in GitHub Desktop.
Generate framework compatibility matrix from fqnames

Generate framework compatibility matrix from fqnames

  • Download these 2 files
  • Compile AOSP without fcm from stock and wait for check_vintf to error out
  • Delete Python prefix from all lines (e.g. checkvintf E 06-24 00:30:22 49120 49120 check_vintf.cpp:554])
  • Paste the result in fqnames.txt
  • Launch the script
# Add here a list of fqname
# You can get it if you try to build AOSP without a fcm
# check_vintf will print a list of needed entries
# This currently works with AIDL and HIDL
# Here an example from Xiaomi SM8150 common tree
[email protected]::IGnss/gnss_vendor
[email protected]::ISap/slot2
[email protected]::IImsCmService/qti.ims.connectionmanagerservice
[email protected]::IUceService/com.qualcomm.qti.uceservice
[email protected]::IDisplayColor/default
[email protected]::IDisplayConfig/default
[email protected]::IDisplayPostproc/default
[email protected]::IGoodixFingerprintDaemon/default
[email protected]::IGoodixFingerprintDaemonExt/default
[email protected]::IDisplayModes/default
[email protected]::IPictureAdjustment/default
vendor.lineage.power.IPower/default
[email protected]::IUsbRestrict/default
[email protected]::IFactory/default
[email protected]::IEsePowerManager/default
[email protected]::ILocHidlGnss/gnss_vendor
[email protected]::ILocHidlGnss/gnss_vendor
[email protected]::ILocHidlGnss/gnss_vendor
[email protected]::ILocHidlGnss/gnss_vendor
[email protected]::IAlarm/default
[email protected]::IAudioHalExt/default
[email protected]::IBluetoothAudioProvidersFactory/default
[email protected]::IBluetoothSar/default
[email protected]::IBTConfigStore/default
[email protected]::ICapabilityConfigStore/default
[email protected]::IDataConnection/slot1
[email protected]::IDataConnection/slot2
[email protected]::IQtiAllocator/default
[email protected]::IQtiAllocator/default
[email protected]::IQtiMapper/default
[email protected]::IQtiMapper/default
[email protected]::IDspService/dspservice
[email protected]::IFmHci/default
[email protected]::IIop/default
[email protected]::IPerf/default
[email protected]::IQccvndhal/qccvndhal
[email protected]::IQSEECom/default
[email protected]::IAppConnector/default
[email protected]::IGPAppConnector/default
[email protected]::IQcRilAudio/slot1
[email protected]::IQcRilAudio/slot2
[email protected]::IImsRadio/imsradio0
[email protected]::IImsRadio/imsradio1
[email protected]::IUimLpa/UimLpa0
[email protected]::IUimLpa/UimLpa1
[email protected]::IQtiOemHook/oemhook0
[email protected]::IQtiOemHook/oemhook1
[email protected]::IQtiRadio/slot1
[email protected]::IQtiRadio/slot2
[email protected]::IQtiRadio/slot1
[email protected]::IQtiRadio/slot2
[email protected]::IUim/Uim0
[email protected]::IUim/Uim1
[email protected]::IUimRemoteServiceClient/uimRemoteClient0
[email protected]::IUimRemoteServiceClient/uimRemoteClient1
[email protected]::IUimRemoteServiceServer/uimRemoteServer0
[email protected]::IUimRemoteServiceServer/uimRemoteServer1
[email protected]::ISensorsCalibrate/default
[email protected]::ISoter/default
[email protected]::ITuiComm/default
[email protected]::IHidlVppService/vppService
[email protected]::IWifiDisplaySessionImageTrack/wifidisplaysessionimagetrack
[email protected]::IRTPService/imsrtpservice
[email protected]::IXiaomiFingerprint/default
[email protected]::IMlipayService/default
# Author: Sebastiano Barezzi <[email protected]>
# Version: 1.3
from re import search
class Version:
def __init__(self, version: str):
self.major, self.minor = version.split(".")
def merge_version(self, version):
if version.minor > self.minor:
self.minor = version.minor
def format(self):
version_str = ' <version>'
if int(self.minor) > 0:
version_str += f"{self.major}.0-{self.minor}"
else:
version_str += f"{self.major}.{self.minor}"
version_str += '</version>\n'
return version_str
class Interface:
def __init__(self, name: str, instance: str):
self.name = name
self.instances = [instance]
def merge_interface(self, interface):
for instance in interface.instances:
if not instance in self.instances:
self.instances += [instance]
def format(self):
interface_str = ' <interface>\n'
interface_str += f' <name>{self.name}</name>\n'
for instance in self.instances:
interface_str += f' <instance>{instance}</instance>\n'
interface_str += ' </interface>\n'
return interface_str
class Entry:
def __init__(self, fqname: str):
self.type = "HIDL" if "@" in fqname else "AIDL"
if self.type == "HIDL":
self.name, version = fqname.split("::")[0].split("@")
interface_name, interface_instance = fqname.split("::")[1].split("/", 1)
else:
self.name, interface_str = fqname.rsplit(".", 1)
interface_name, interface_instance = interface_str.split("/")
if self.type == "HIDL":
version = Version(version)
self.versions = {version.major: version}
else:
self.versions = {}
interface = Interface(interface_name, interface_instance)
self.interfaces = {interface.name: interface}
def merge_entry(self, entry):
if entry.name != self.name:
raise AssertionError("Different entry name")
if entry.type != self.type:
raise AssertionError("Different HAL type")
for version_major, version in entry.versions.items():
if version_major in self.versions:
self.versions[version_major].merge_version(version)
else:
self.versions[version_major] = version
for interface_name, interface in entry.interfaces.items():
if interface_name in self.interfaces:
self.interfaces[interface_name].merge_interface(interface)
else:
self.interfaces[interface_name] = interface
pass
def format(self):
entry_str = f'<hal format="{self.type.lower()}" optional="true">\n'
entry_str += f' <name>{self.name}</name>\n'
for version in self.versions.values():
entry_str += version.format()
for interface in self.interfaces.values():
entry_str += interface.format()
entry_str += '</hal>\n'
return entry_str
def main():
entries = {}
for fqname in open("fqnames.txt").readlines():
fqname = fqname.strip()
if fqname == "" or fqname[0] == '#':
continue
versioned_aidl_match = search(" \(@[0-9]+\)$", fqname)
if versioned_aidl_match:
fqname = fqname.removesuffix(versioned_aidl_match.group(0))
entry = Entry(fqname)
if entry.name in entries:
entries[entry.name].merge_entry(entry)
else:
entries[entry.name] = entry
fcms = [entry.format() for entry in entries.values()]
print("".join(fcms))
return
main()
@dodyirawan85
Copy link

Hey, it doesn't work when there is aidl type entry example: android.hardware.power.IPower/default (@2)

I try to adapt the code to support versioning aidl here
Feel free to test and suggest better code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment