Android çekirdeklerinin çekirdek içi ABI'sini dengelemek için Android 11 ve sonraki sürümlerde bulunan uygulama ikili arabirimi (ABI) izleme araçlarını kullanabilirsiniz. Araç, mevcut çekirdek ikililerinden (vmlinux
+ GKI modülleri) ABI temsillerini toplar ve karşılaştırır. Bu ABI gösterimleri, .stg
dosyaları ve sembol listeleridir. Temsilin bir görünüm sağladığı arayüze Kernel Module Interface (KMI) adı verilir. Araçları kullanarak KMI'deki değişiklikleri izleyebilir ve azaltabilirsiniz.
ABI izleme aracı AOSP'de geliştirilmiştir ve temsiller oluşturup karşılaştırmak için STG'yi (veya Android 13 ve önceki sürümlerde libabigail
) kullanır.
Bu sayfada, araçlar, ABI gösterimlerinin toplanması ve analiz edilmesi süreci ile çekirdek içi ABI'ye kararlılık sağlamak için bu tür gösterimlerin kullanımı açıklanmaktadır. Bu sayfada, Android çekirdeklerine değişiklik gönderme hakkında da bilgi verilmektedir.
İşle
Çekirdeğin ABI'sini analiz etmek için birden fazla adım gerekir. Bu adımların çoğu otomatikleştirilebilir:
- Çekirdeği ve ABI gösterimini oluşturun.
- Derleme ile referans arasındaki ABI farklılıklarını analiz edin.
- ABI gösterimini güncelleyin (gerekirse).
- Sembol listeleriyle çalışma.
Aşağıdaki talimatlar, desteklenen bir araç zinciri (ör. önceden oluşturulmuş Clang araç zinciri) kullanarak oluşturabileceğiniz tüm çekirdekler için geçerlidir. repo manifests
Tüm Android ortak çekirdek dallarında ve cihaza özel çeşitli çekirdeklerde kullanılabilir. Analiz için bir çekirdek dağıtımı oluşturduğunuzda doğru araç zincirinin kullanıldığını doğrular.
Sembol listeleri
KMI,çekirdekteki tüm sembolleri veya dışa aktarılan 30.000'den fazla sembolün tamamını içermez. Bunun yerine, satıcı modülleri tarafından kullanılabilecek semboller, çekirdek ağacında (Android 15 ve önceki sürümlerde gki/{ARCH}/symbols/*
veya android/abi_gki_{ARCH}_*
) herkese açık olarak tutulan bir dizi sembol listesi dosyasında açıkça listelenir. Tüm sembol listesi dosyalarındaki tüm sembollerin birleşimi, sabit olarak tutulan KMI sembolleri kümesini tanımlar. gki/aarch64/symbols/db845c
, DragonBoard 845c için gereken sembolleri bildiren örnek bir sembol listesi dosyasıdır.
Yalnızca bir sembol listesinde yer alan semboller ile ilgili yapılar ve tanımlar KMI'nin bir parçası olarak kabul edilir. İhtiyacınız olan semboller yoksa sembol listelerinizde değişiklik yayınlayabilirsiniz. Yeni arayüzler sembol listesine eklendikten ve KMI açıklamasının bir parçası olduktan sonra kararlı olarak korunur. Ayrıca, dal dondurulduktan sonra sembol listesinden kaldırılmamalı veya değiştirilmemelidir.
Her Android Common Kernel (ACK) KMI çekirdek dalının kendi sembol listeleri vardır. Farklı KMI çekirdek dalları arasında ABI kararlılığı sağlamak için herhangi bir girişimde bulunulmaz. Örneğin, android12-5.10
için KMI, android13-5.10
için KMI'den tamamen bağımsızdır.
ABI araçları, hangi arayüzlerin kararlılık açısından izlenmesi gerektiğini sınırlamak için KMI sembol listelerini kullanır. Satıcıların, kullandıkları arayüzlerin ABI uyumluluğunu koruduğunu doğrulamak için kendi sembol listelerini göndermeleri ve güncellemeleri beklenir. Örneğin, android16-6.12
çekirdeği için sembol listelerinin listesini görmek istiyorsanız https://android.googlesource.com/kernel/common/+/refs/heads/android16-6.12/gki/aarch64/symbols
bölümüne bakın.
Sembol listesi, belirli bir satıcı veya cihaz için gerekli olduğu bildirilen sembolleri içerir. Araçlar tarafından kullanılan tam liste, tüm KMI sembol listesi dosyalarının birleşimidir. ABI araçları, işlev imzası ve iç içe yerleştirilmiş veri yapıları da dahil olmak üzere her sembolün ayrıntılarını belirler.
KMI dondurulduğunda mevcut KMI arayüzlerinde değişiklik yapılmasına izin verilmez. Bu arayüzler sabittir. Ancak satıcılar, eklemeler mevcut ABI'nin kararlılığını etkilemediği sürece KMI'ye istedikleri zaman sembol ekleyebilirler. Yeni eklenen semboller, bir KMI sembol listesi tarafından alıntılanır alıntılanmaz kararlı hale gelir. Bir çekirdeğin sembolleri, hiçbir cihazın bu sembole bağımlı olarak gönderilmediği onaylanmadığı sürece listeden kaldırılmamalıdır.
Sembol listeleriyle çalışma başlıklı makaledeki talimatları uygulayarak bir cihaz için KMI sembol listesi oluşturabilirsiniz. Birçok iş ortağı, ACK başına bir sembol listesi gönderir ancak bu zorunlu değildir. Bakım açısından faydalı olacağını düşünüyorsanız birden fazla sembol listesi gönderebilirsiniz.
KMI'yi genişletme
KMI sembolleri ve ilgili yapılar kararlı olarak korunurken (yani, KMI'nin dondurulduğu bir çekirdekte kararlı arayüzleri bozan değişiklikler kabul edilemez) GKI çekirdeği, yılın ilerleyen dönemlerinde gönderilecek cihazların KMI dondurulmadan önce tüm bağımlılıklarını tanımlaması gerekmemesi için uzantılara açık kalır. KMI'yi genişletmek için KMI dondurulmuş olsa bile yeni veya mevcut dışa aktarılmış çekirdek işlevleri için KMI'ye yeni semboller ekleyebilirsiniz. KMI'yi bozmayan yeni çekirdek yamaları da kabul edilebilir.
KMI bozulmaları hakkında
Bir çekirdeğin kaynakları vardır ve ikili dosyalar bu kaynaklardan oluşturulur.
ABI izlemeli çekirdek dalları, mevcut GKI ABI'sinin ABI gösterimini (.stg
dosyası biçiminde) içerir. İkili dosyalar (vmlinux
, Image
ve GKI modülleri) oluşturulduktan sonra ikili dosyalardan bir ABI temsili çıkarılabilir. Bir çekirdek kaynak dosyasında yapılan herhangi bir değişiklik, ikili dosyaları ve dolayısıyla çıkarılan .stg
'yı da etkileyebilir. ABI Uygunluk Analizi, kaydedilen .stg
dosyasını derleme yapıtlarından çıkarılan dosyayla karşılaştırır ve anlamsal bir farklılık bulursa Gerrit'teki değişikliğe Lint-1 etiketi atar.
ABI bozulmalarını ele alma
Örneğin, aşağıdaki yama çok belirgin bir ABI kesintisi oluşturur:
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 42786e6364ef..e15f1d0f137b 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -657,6 +657,7 @@ struct mm_struct {
ANDROID_KABI_RESERVE(1);
} __randomize_layout;
+ int tickle_count;
/*
* The mm_cpumask needs to be at the end of mm_struct, because it
* is dynamically sized based on nr_cpu_ids.
Bu yama uygulandıktan sonra build ABI'yi çalıştırdığınızda araç, sıfır olmayan bir hata koduyla çıkar ve buna benzer bir ABI farkı bildirir:
function symbol 'struct block_device* I_BDEV(struct inode*)' changed
CRC changed from 0x8d400dbd to 0xabfc92ad
function symbol 'void* PDE_DATA(const struct inode*)' changed
CRC changed from 0xc3c38b5c to 0x7ad96c0d
function symbol 'void __ClearPageMovable(struct page*)' changed
CRC changed from 0xf489e5e8 to 0x92bd005e
... 4492 omitted; 4495 symbols have only CRC changes
type 'struct mm_struct' changed
byte size changed from 992 to 1000
member 'int tickle_count' was added
member 'unsigned long cpu_bitmap[0]' changed
offset changed by 64
Derleme sırasında ABI farklılıkları algılandı
Hataların en yaygın nedeni, bir sürücünün çekirdekteki sembol listelerinde bulunmayan yeni bir sembol kullanmasıdır.
Sembol, sembol listenizde yer almıyorsa önce EXPORT_SYMBOL_GPL(symbol_name)
ile dışa aktarıldığını doğrulamanız, ardından sembol listesini ve ABI gösterimini güncellemeniz gerekir. Örneğin, aşağıdaki değişiklikler android-12-5.10
dalına yeni Artımlı FS özelliğini ekler. Bu değişiklikler, sembol listesinin ve ABI gösteriminin güncellenmesini içerir.
- Özellik değişikliği örneği aosp/1345659 adresinde yer almaktadır.
- Sembol listesi örneği aosp/1346742 adresinde yer almaktadır.
- ABI gösterim değişikliği örneği aosp/1349377 adresinde yer almaktadır.
Sembol dışa aktarılmışsa (sizin tarafınızdan veya daha önce dışa aktarılmışsa) ancak başka bir sürücü tarafından kullanılmıyorsa aşağıdakine benzer bir derleme hatası alabilirsiniz.
Comparing the KMI and the symbol lists:
+ build/abi/compare_to_symbol_list out/$BRANCH/common/Module.symvers out/$BRANCH/common/abi_symbollist.raw
ERROR: Differences between ksymtab and symbol list detected!
Symbols missing from ksymtab:
Symbols missing from symbol list:
- simple_strtoull
Bu sorunu çözmek için hem çekirdeğinizde hem de ACK'de KMI sembol listesini güncelleyin (bkz. ABI gösterimini güncelleme). Sembol listesini ve ACK'deki ABI gösterimini güncelleme örneği için aosp/1367601 adresine bakın.
Çekirdek ABI bozulmalarını düzeltme
Kodu, ABI'yi değiştirmeyecek şekilde yeniden düzenleyerek veya ABI gösterimini güncelleyerek çekirdek ABI'deki bozulmaları giderebilirsiniz. Durumunuza en uygun yaklaşımı belirlemek için aşağıdaki grafiği kullanın.
1.şekil ABI bozulması çözümü
ABI değişikliklerinden kaçınmak için kodu yeniden düzenleme
Mevcut ABI'yi değiştirmemeye özen gösterin. Çoğu durumda, ABI'yi etkileyen değişiklikleri kaldırmak için kodunuzu yeniden düzenleyebilirsiniz.
Yapı alanı değişikliklerini yeniden düzenleme. Bir değişiklik, hata ayıklama özelliği için ABI'yi değiştirirse alanların (yapılarda ve kaynak referanslarında) etrafına
#ifdef
ekleyin ve#ifdef
için kullanılanCONFIG
öğesinin üretim defconfig'i vegki_defconfig
için devre dışı bırakıldığından emin olun. ABI'yi bozmadan bir yapıya nasıl hata ayıklama yapılandırması eklenebileceğine dair bir örnek için bu yama grubuna bakın.Çekirdek çekirdeği değiştirmeyen yeniden düzenleme özellikleri. İş ortağı modüllerini desteklemek için ACK'ye yeni özellikler eklenmesi gerekiyorsa çekirdek ABI'sini değiştirmemek için değişikliğin ABI bölümünü yeniden düzenlemeyi deneyin. Çekirdek ABI'sini değiştirmeden ek özellikler eklemek için mevcut çekirdek ABI'sini kullanma örneği için aosp/1312213 adresine bakın.
Android Gerrit'te bozuk bir ABI'yi düzeltme
Çekirdek ABI'sini kasıtlı olarak bozmadıysanız ABI izleme araçlarının sağladığı kılavuzdan yararlanarak durumu araştırmanız gerekir. En yaygın bozulma nedenleri, veri yapılarının ve ilişkili sembol CRC değişikliklerinin değiştirilmesi veya yukarıda belirtilenlerden herhangi birine yol açan yapılandırma seçeneği değişiklikleridir. Öncelikle araç tarafından bulunan sorunları ele alın.
ABI bulgularını yerel olarak yeniden üretebilirsiniz. Çekirdeği ve ABI gösterimini oluşturma başlıklı makaleyi inceleyin.
Lint-1 etiketleri hakkında
Dondurulmuş veya sonlandırılmış bir KMI içeren bir dala değişiklik yüklerseniz değişikliklerin ABI gösterimindeki değişikliklerin gerçek ABI'yi yansıtmasını ve herhangi bir uyumsuzluk (sembol kaldırma veya tür değişiklikleri) içermemesini sağlamak için ABI Uygunluk ve Uyumluluk analizlerinden geçmesi gerekir.
Bu ABI analizlerinin her biri, tüm sorunlar çözülene veya etiket geçersiz kılınana kadar Lint-1 etiketini ayarlayabilir ve değişiklik gönderimini engelleyebilir.
Çekirdek ABI'sini güncelleme
ABI'yi değiştirmenin kaçınılmaz olduğu durumlarda kod değişikliklerinizi, ABI gösterimini ve sembol listesini ACK'ye uygulamanız gerekir. Lint'in -1'i kaldırmasını ve GKI uyumluluğunu bozmasını önlemek için şu adımları uygulayın:
Yama grubu için Code-Review +2 almayı bekleyin.
Kod değişikliklerinizi ve ABI güncelleme değişikliğini birleştirin.
ABI kodu değişikliklerini ACK'ye yükleme
ACK ABI'nin güncellenmesi, yapılan değişikliğin türüne bağlıdır.
Bir ABI değişikliği, CTS veya VTS testlerini etkileyen bir özellikle ilgiliyse değişiklik genellikle olduğu gibi ACK olarak seçilebilir. Örneğin:
- Sesin çalışması için aosp/1289677 gerekir.
- USB'nin çalışması için aosp/1295945 gerekir.
Bir ABI değişikliği, ACK ile paylaşılabilecek bir özellik içinse bu değişiklik, ACK'ye olduğu gibi aktarılabilir. Örneğin, aşağıdaki değişiklikler CTS veya VTS testi için gerekli değildir ancak ACK ile paylaşılabilir:
- aosp/1250412 termal özellik değişikliğidir.
- aosp/1288857,
EXPORT_SYMBOL_GPL
değişikliğidir.
Bir ABI değişikliği, ACK'ye dahil edilmesi gerekmeyen yeni bir özellik sunuyorsa aşağıdaki bölümde açıklandığı gibi bir saplama kullanarak sembolleri ACK'ye ekleyebilirsiniz.
ACK için taslak kullanma
Stubs, yalnızca ACK'nin yararlanmadığı temel çekirdek değişiklikleri (ör. performans ve güç değişiklikleri) için gereklidir. Aşağıdaki listede, GKI için ACK'deki saplama ve kısmi cherry-pick örnekleri ayrıntılı olarak açıklanmaktadır.
Core-isolate özelliği için taslak (aosp/1284493). ACK'deki özellikler gerekli değildir ancak modüllerinizin bu sembolleri kullanabilmesi için ACK'de sembollerin bulunması gerekir.
Tedarikçi modülü için yer tutucu simge (aosp/1288860).
Süreç başına
mm
etkinlik izleme özelliğinin yalnızca ABI'ye yönelik olarak seçilerek eklenmesi (aosp/1288454). Orijinal yama, ACK için seçilip yalnızcatask_struct
vemm_event_count
için ABI farkını gidermek üzere gerekli değişiklikleri içerecek şekilde kırpıldı. Bu yama,mm_event_type
enum'unu son üyeleri içerecek şekilde de günceller.Yeni ABI alanlarını eklemenin ötesinde değişiklikler gerektiren termal yapı ABI değişikliklerinin kısmi olarak seçilip birleştirilmesi.
Yama aosp/1255544 iş ortağı çekirdeği ile ACK arasındaki ABI farklılıklarını giderdi.
Yama aosp/1291018 önceki yamanın GKI testi sırasında bulunan işlevsel sorunları düzeltmiştir. Düzeltme, birden fazla termal bölgeyi tek bir sensöre kaydetmek için sensör parametresi yapısının başlatılmasını içeriyordu.
CONFIG_NL80211_TESTMODE
ABI değişiklikleri (aosp/1344321). Bu yama, ABI için gerekli yapı değişikliklerini ekledi ve ek alanların işlevsel farklılıklara neden olmadığından emin oldu. Böylece iş ortakları, üretim çekirdeklerineCONFIG_NL80211_TESTMODE
'yı ekleyebildi ve GKI uyumluluğunu koruyabildi.
Çalışma zamanında KMI'yi zorunlu kılma
GKI çekirdekleri, dışa aktarılan sembolleri (ör. EXPORT_SYMBOL_GPL()
kullanılarak dışa aktarılan semboller) bir sembol listesinde listelenenlerle sınırlayan TRIM_UNUSED_KSYMS=y
ve UNUSED_KSYMS_WHITELIST=<union
of all symbol lists>
yapılandırma seçeneklerini kullanır. Diğer tüm semboller dışa aktarılmaz ve dışa aktarılmamış bir sembol gerektiren bir modülün yüklenmesi reddedilir. Bu kısıtlama derleme sırasında uygulanır ve eksik girişler işaretlenir.
Geliştirme amacıyla, sembol kırpma içermeyen bir GKI çekirdek derlemesi kullanabilirsiniz (yani genellikle dışa aktarılan tüm semboller kullanılabilir). Bu derlemeleri bulmak için ci.android.com adresinde kernel_debug_aarch64
derlemelerini arayın.
Modül sürüm oluşturmayı kullanarak KMI'yi zorunlu kılma
Genel Çekirdek Görüntüsü (GKI) çekirdekleri, çalışma zamanında KMI uyumluluğunu zorunlu kılmak için ek bir önlem olarak modül sürüm oluşturmayı (CONFIG_MODVERSIONS
) kullanır. Modül sürümü oluşturma, bir modülün beklenen KMI'si vmlinux
KMI ile eşleşmediğinde modül yükleme sırasında döngüsel yedeklilik denetimi (CRC) uyuşmazlığı hatalarına neden olabilir. Örneğin, aşağıdaki hata, module_layout()
sembolü için CRC uyuşmazlığı nedeniyle modül yükleme sırasında meydana gelen tipik bir hatadır:
init: Loading module /lib/modules/kernel/.../XXX.ko with args ""
XXX: disagrees about version of symbol module_layout
init: Failed to insmod '/lib/modules/kernel/.../XXX.ko' with args ''
Modül sürümü oluşturmanın kullanım alanları
Modül sürümü oluşturma aşağıdaki nedenlerden dolayı faydalıdır:
Modül sürümü oluşturma, veri yapısı görünürlüğündeki değişiklikleri yakalar. Modüller, KMI'nin parçası olmayan opak veri yapıları değiştirirse yapıdaki gelecekteki değişikliklerden sonra bozulur.
Örneğin,
struct device
içindekifwnode
alanını ele alalım. Bu alan, modüllerindevice->fw_node
alanlarında değişiklik yapamaması veya boyutuyla ilgili varsayımlarda bulunamaması için modüller tarafından opak OLMALIDIR.Ancak bir modül
<linux/fwnode.h>
(doğrudan veya dolaylı olarak) içeriyorsastruct device
içindekifwnode
alanı artık bu modül için opak değildir. Modül daha sonradevice->fwnode->dev
veyadevice->fwnode->ops
üzerinde değişiklik yapabilir. Bu senaryo çeşitli nedenlerden dolayı sorunludur:Temel çekirdek kodunun dahili veri yapıları hakkında yaptığı varsayımları bozabilir.
Gelecekteki bir çekirdek güncellemesi
struct fwnode_handle
'yı (fwnode
'nin veri türü) değiştirirse modül artık yeni çekirdekle çalışmaz. Ayrıca,stgdiff
, yalnızca ikili gösterimi inceleyerek yakalanamayacak şekilde dahili veri yapılarını doğrudan değiştirerek KMI'yi bozduğu için herhangi bir fark göstermez.
Mevcut bir modül, daha sonra uyumsuz yeni bir çekirdek tarafından yüklendiğinde KMI ile uyumsuz kabul edilir. Modül sürüm oluşturma, çekirdekle KMI uyumlu olmayan bir modülün yanlışlıkla yüklenmesini önlemek için çalışma zamanı kontrolü ekler. Bu kontrol, KMI'deki algılanmayan bir uyumsuzluktan kaynaklanabilecek, hata ayıklaması zor olan çalışma zamanı sorunlarını ve çekirdek çökmelerini önler.
Modül sürüm oluşturmayı etkinleştirmek tüm bu sorunları önler.
Cihazı başlatmadan CRC uyuşmazlıklarını kontrol etme
stgdiff
, diğer ABI farklılıklarının yanı sıra çekirdekler arasındaki CRC uyuşmazlıklarını karşılaştırır ve bildirir.
Ayrıca, CONFIG_MODVERSIONS
etkinleştirilmiş tam çekirdek derlemesi, normal derleme sürecinin bir parçası olarak Module.symvers
dosyası oluşturur. Bu dosyada, çekirdek (vmlinux
) ve modüller tarafından dışa aktarılan her sembol için bir satır bulunur. Her satırda CRC değeri, sembol adı, sembol ad alanı, sembolü dışa aktaran vmlinux
veya modül adı ve dışa aktarma türü (örneğin, EXPORT_SYMBOL
ve EXPORT_SYMBOL_GPL
) bulunur.
Module.symvers
tarafından dışa aktarılan sembollerdeki CRC farklılıklarını kontrol etmek için GKI derlemesi ile kendi derlemeniz arasındaki Module.symvers
dosyalarını karşılaştırabilirsiniz.vmlinux
vmlinux
tarafından dışa aktarılan herhangi bir sembolde CRC değeri farklılığı varsa ve bu sembol cihazınıza yüklediğiniz modüllerden biri tarafından kullanılıyorsa modül yüklenmez.
Tüm derleme yapılarınız yoksa ancak GKI çekirdeğinin ve çekirdeğinizin vmlinux
dosyaları varsa aşağıdaki komutu her iki çekirdekte de çalıştırıp çıktıyı karşılaştırarak belirli bir sembolün CRC değerlerini karşılaştırabilirsiniz:
nm <path to vmlinux>/vmlinux | grep __crc_<symbol name>
Örneğin, aşağıdaki komut module_layout
sembolünün CRC değerini kontrol eder:
nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout
CRC uyuşmazlıklarını çözme
Bir modül yüklenirken CRC uyuşmazlığını gidermek için aşağıdaki adımları uygulayın:
Aşağıdaki komutta gösterildiği gibi
--kbuild_symtypes
seçeneğini kullanarak GKI çekirdeğini ve cihazınızın çekirdeğini oluşturun:tools/bazel run --kbuild_symtypes //common:kernel_aarch64_dist
Bu komut, her
.o
dosyası için bir.symtypes
dosyası oluşturur. Ayrıntılar için Kleaf'teKBUILD_SYMTYPES
bölümüne bakın.Android 13 ve önceki sürümlerde, GKI çekirdeğini ve cihazınızın çekirdeğini oluşturmak için aşağıdaki komutta gösterildiği gibi çekirdeği oluşturmak üzere kullandığınız komutun başına
KBUILD_SYMTYPES=1
ekleyin:KBUILD_SYMTYPES=1 BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
build_abi.sh,
kullanılırkenKBUILD_SYMTYPES=1
işareti zaten örtülü olarak ayarlanır.Aşağıdaki komutu kullanarak, CRC uyuşmazlığı olan sembolün dışa aktarıldığı
.c
dosyasını bulun:git -C common grep EXPORT_SYMBOL.*module_layout kernel/module/version.c:EXPORT_SYMBOL(module_layout);
.c
dosyasının GKI'da ve cihazınızın çekirdek derleme yapılarında karşılık gelen bir.symtypes
dosyası vardır. Aşağıdaki komutları kullanarak.symtypes
dosyasını bulun:cd bazel-bin/common/kernel_aarch64/symtypes ls -1 kernel/module/version.symtypes
Android 13 ve önceki sürümlerde, eski derleme komut dosyaları kullanıldığında konumun
out/$BRANCH/common
veyaout_abi/$BRANCH/common
olması muhtemeldir.Her
.symtypes
dosyası, tür ve sembol açıklamalarından oluşan düz metin dosyasıdır:Her satır,
key description
biçimindedir. Açıklama, aynı dosyadaki diğer anahtarlara atıfta bulunabilir.[s|u|e|t]#foo
gibi anahtarlar[struct|union|enum|typedef] foo
değerine karşılık gelir. Örneğin:t#bool typedef _Bool bool
x#
ön eki olmayan anahtarlar yalnızca sembol adlarıdır. Örneğin:find_module s#module * find_module ( const char * )
İki dosyayı karşılaştırın ve tüm farklılıkları düzeltin.
symtypes
dosyasını, sorunlu değişiklikten hemen önce ve sorunlu değişiklik sırasında olmak üzere iki kez oluşturmanız en iyisidir. Tüm dosyaları kaydettiğinizde bu dosyalar toplu olarak karşılaştırılabilir.
Örneğin,
for f in $(find good bad -name '*.symtypes' | sed -r 's;^(good|bad)/;;' | LANG=C sort -u); do
diff -N -U0 --label good/"$f" --label bad/"$f" <(LANG=C sort good/"$f") <(LANG=C sort bad/"$f")
done
Aksi takdirde, yalnızca ilgilendiğiniz belirli dosyaları karşılaştırın.
1. örnek: Veri türü görünürlüğünden kaynaklanan farklılıklar
Yeni bir #include
, kaynak dosyaya yeni bir tür tanımı (örneğin struct foo
) çekebilir. Bu gibi durumlarda, ilgili .symtypes
dosyasındaki açıklaması boş structure_type foo { }
tanımından tam tanıma dönüşür.
Bu, açıklamaları doğrudan veya dolaylı olarak tür tanımına bağlı olan .symtypes
dosyasındaki tüm sembollerin tüm CRC'lerini etkiler.
Örneğin, çekirdeğinizdeki include/linux/device.h
dosyasına aşağıdaki satırı eklemek, biri module_layout()
için olmak üzere CRC uyuşmazlıklarına neden olur:
#include <linux/fwnode.h>
Bu sembolün module/version.symtypes
karşılaştırıldığında aşağıdaki farklılıklar ortaya çıkar:
$ diff -u <GKI>/kernel/module/version.symtypes <your kernel>/kernel/module/version.symtypes
--- <GKI>/kernel/module/version.symtypes
+++ <your kernel>/kernel/module/version.symtypes
@@ -334,12 +334,15 @@
...
-s#fwnode_handle structure_type fwnode_handle { }
+s#fwnode_reference_args structure_type fwnode_reference_args { s#fwnode_handle * fwnode ; unsigned int nargs ; t#u64 args [ 8 ] ; }
...
GKI çekirdeğinde tam tür tanımı varsa ancak çekirdeğinizde bu tanım eksikse (çok düşük bir ihtimal) en son GKI çekirdek tabanını kullanmak için en son Android Common Kernel'i çekirdeğinizle birleştirin.
Çoğu durumda GKI çekirdeğinde .symtypes
içinde tam tür tanımı eksiktir ancak çekirdeğinizde ek #include
yönergeleri nedeniyle bu tanım bulunur.
Android 16 ve sonraki sürümlerde çözünürlük
Etkilenen kaynak dosyanın Android KABI stabilizasyon üstbilgisini içerdiğinden emin olun:
#include <linux/android_kabi.h>
Etkilenen her tür için etkilenen kaynak dosyaya ANDROID_KABI_DECLONLY(name);
öğesini genel kapsamda ekleyin.
Örneğin, symtypes
farkı şu şekildeyse:
--- good/drivers/android/vendor_hooks.symtypes
+++ bad/drivers/android/vendor_hooks.symtypes
@@ -1051 +1051,2 @@
-s#ubuf_info structure_type ubuf_info { }
+s#ubuf_info structure_type ubuf_info { member pointer_type { const_type { s#ubuf_info_ops } } ops data_member_location(0) , member t#refcount_t refcnt data_member_location(8) , member t#u8 flags data_member_location(12) } byte_size(16)
+s#ubuf_info_ops structure_type ubuf_info_ops { member pointer_type { subroutine_type ( formal_parameter pointer_type { s#sk_buff } , formal_parameter pointer_type { s#ubuf_info } , formal_parameter t#bool ) -> base_type void } complete data_member_location(0) , member pointer_type { subroutine_type ( formal_parameter pointer_type { s#sk_buff } , formal_parameter pointer_type { s#ubuf_info } ) -> base_type int byte_size(4) encoding(5) } link_skb data_member_location(8) } byte_size(16)
Bu durumda sorun, struct ubuf_info
öğesinin artık symtypes
içinde tam bir tanımının olmasıdır. Çözüm, drivers/android/vendor_hooks.c
dosyasına bir satır eklemektir:
ANDROID_KABI_DECLONLY(ubuf_info);
Bu, gendwarfksyms
'ya adlandırılmış türü dosyada tanımlanmamış olarak değerlendirmesi talimatını verir.
Daha karmaşık bir olasılık ise yeni #include
öğesinin kendisinin bir başlık dosyasında olmasıdır. Bu durumda, bazıları zaten tür tanımlarının bir kısmına sahip olabileceğinden, farklı ANDROID_KABI_DECLONLY
makro çağırma kümelerini, ek tür tanımlarını dolaylı olarak çeken kaynak dosyalar arasında dağıtmanız gerekebilir.
Okunabilirliği artırmak için bu tür makro çağırmalarını kaynak dosyanın başına yakın bir yere yerleştirin.
Android 15 ve önceki sürümlerde çözünürlük
Çoğu zaman düzeltme, yeni #include
öğesini genksyms
öğesinden gizlemekten ibarettir.
#ifndef __GENKSYMS__
#include <linux/fwnode.h>
#endif
Aksi takdirde, farklılığa neden olan #include
öğesini belirlemek için aşağıdaki adımları uygulayın:
Bu farkı içeren sembolü veya veri türünü tanımlayan başlık dosyasını açın. Örneğin,
struct fwnode_handle
içininclude/linux/fwnode.h
sütununu düzenleyin.Üstbilgi dosyasının en üstüne aşağıdaki kodu ekleyin:
#ifdef CRC_CATCH #error "Included from here" #endif
CRC uyuşmazlığı olan modülün
.c
dosyasında,#include
satırlarından herhangi birinden önce ilk satıra aşağıdakileri ekleyin.#define CRC_CATCH 1
Modülünüzü derleyin. Derleme zamanı hatası, bu CRC uyuşmazlığına yol açan başlık dosyası
#include
zincirini gösterir. Örneğin:In file included from .../drivers/clk/XXX.c:16:` In file included from .../include/linux/of_device.h:5: In file included from .../include/linux/cpu.h:17: In file included from .../include/linux/node.h:18: .../include/linux/device.h:16:2: error: "Included from here" #error "Included from here"
Bu
#include
zincirindeki bağlantılardan biri, çekirdeğinizde yapılan ve GKI çekirdeğinde bulunmayan bir değişiklikten kaynaklanıyor.
2. durum: Veri türü değişikliklerinden kaynaklanan farklılıklar
Bir sembol veya veri türü için CRC uyuşmazlığı görünürlükteki bir farklılıktan kaynaklanmıyorsa veri türünün kendisinde yapılan gerçek değişikliklerden (eklemeler, kaldırmalar veya değişiklikler) kaynaklanıyordur.
Örneğin, çekirdeğinizde aşağıdaki değişikliği yapmak, birçok sembol bu tür bir değişiklikten dolaylı olarak etkilendiği için çeşitli CRC uyuşmazlıklarına neden olur:
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -259,7 +259,7 @@ struct iommu_ops {
void (*iotlb_sync)(struct iommu_domain *domain);
phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, dma_addr_t iova);
phys_addr_t (*iova_to_phys_hard)(struct iommu_domain *domain,
- dma_addr_t iova);
+ dma_addr_t iova, unsigned long trans_flag);
int (*add_device)(struct device *dev);
void (*remove_device)(struct device *dev);
struct iommu_group *(*device_group)(struct device *dev);
CRC uyuşmazlıklarından biri devm_of_platform_populate()
içindir.
Bu sembolün .symtypes
dosyalarını karşılaştırdığınızda şu şekilde görünebilir:
$ diff -u <GKI>/drivers/of/platform.symtypes <your kernel>/drivers/of/platform.symtypes
--- <GKI>/drivers/of/platform.symtypes
+++ <your kernel>/drivers/of/platform.symtypes
@@ -399,7 +399,7 @@
...
-s#iommu_ops structure_type iommu_ops { ... ; t#phy
s_addr_t ( * iova_to_phys_hard ) ( s#iommu_domain * , t#dma_addr_t ) ; int
( * add_device ) ( s#device * ) ; ...
+s#iommu_ops structure_type iommu_ops { ... ; t#phy
s_addr_t ( * iova_to_phys_hard ) ( s#iommu_domain * , t#dma_addr_t , unsigned long ) ; int ( * add_device ) ( s#device * ) ; ...
Değişen türü belirlemek için aşağıdaki adımları uygulayın:
Sembolün tanımını kaynak kodda (genellikle
.h
dosyalarında) bulun.- Çekirdeğiniz ile GKI çekirdeği arasındaki sembol farklılıkları için aşağıdaki komutu çalıştırarak commit'i bulun:
git blame
- Silinen semboller için (bir ağaçta silinen ve diğer ağaçta da silmek istediğiniz semboller) satırı silen değişikliği bulmanız gerekir. Satırın silindiği ağaçta aşağıdaki komutu kullanın:
git log -S "copy paste of deleted line/word" -- <file where it was deleted>
Değişikliği veya silme işlemini bulmak için döndürülen commit listesini inceleyin. Aradığınız muhtemelen ilk commit'tir. Değilse taahhüdü bulana kadar listede ilerleyin.
Onaylamayı belirledikten sonra çekirdeğinizde geri alın veya CRC değişikliğini bastırmak için güncelleyin ve ACK'ye yükleyip birleştirin. Her artık ABI kesintisinin güvenlik açısından incelenmesi ve gerekirse izin verilen bir kesintinin kaydedilmesi gerekir.
Mevcut dolguyu kullanmayı tercih etme
GKI'daki bazı yapılar, mevcut tedarikçi modüllerini bozmadan genişletilebilmeleri için doldurulur. Bir yukarı akış commit'i (örneğin) böyle bir yapıya üye eklerse bunun yerine dolgunun bir kısmını kullanacak şekilde değiştirilmesi mümkün olabilir. Bu değişiklik daha sonra CRC hesaplamasından gizlenir.
Standartlaştırılmış, kendi kendini belgeleyen makro ANDROID_KABI_RESERVE
, u64
değerinde (uyumlu) alan ayırır. Üye beyanı yerine kullanılır.
Örneğin:
struct data {
u64 handle;
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
};
Dolgu, ANDROID_KABI_USE
(veya ANDROID_KABI_USE2
ya da tanımlanabilecek diğer varyantlar) ile sembol CRC'lerini etkilemeden tüketilebilir.
Üye sekret
doğrudan bildirilmiş gibi kullanılabilir ancak makro aslında sekret
'yı ve gendwarfksyms
tarafından sembol türü kararlılığını korumak için kullanılan öğeleri içeren anonim bir birleşim üyesi olarak genişler.
struct data {
u64 handle;
ANDROID_KABI_USE(1, void *sekret);
ANDROID_KABI_RESERVE(2);
};
Android 16 ve sonraki sürümlerde çözünürlük
CRC'ler, DWARF hata ayıklama bilgilerini kullanan gendwarfksyms
tarafından hesaplanır. Bu nedenle hem C hem de Rust türlerini destekler. Çözüm, değişiklik türüne göre değişir. Aşağıda birkaç örnek verilmiştir.
Yeni veya değiştirilmiş numaralandırıcılar
Bazen yeni numaralandırıcılar eklenir ve zaman zaman MAX
veya benzeri bir numaralandırıcı değeri de etkilenir. Bu değişiklikler, GKI'dan "kaçmadıkları" veya tedarikçi modüllerinin değerlerini önemsemediğinden emin olunduğu durumlarda güvenlidir.
Örneğin:
enum outcome {
SUCCESS,
FAILURE,
RETRY,
+ TRY_HARDER,
OUTCOME_LIMIT
};
TRY_HARDER
eklenmesi ve OUTCOME_LIMIT
ile ilgili değişiklik, küresel kapsamda makro çağrılarıyla CRC hesaplamasından gizlenebilir:
ANDROID_KABI_ENUMERATOR_IGNORE(outcome, TRY_HARDER);
ANDROID_KABI_ENUMERATOR_VALUE(outcome, OUTCOME_LIMIT, 3);
Okunabilirlik için bunları enum
tanımının hemen sonrasına yerleştirin.
Mevcut bir boşluğu dolduran yeni bir yapı üyesi
Hizalama nedeniyle urgent
ile scratch
arasında kullanılmayan baytlar olacaktır.
void *data;
bool urgent;
+ bool retry;
void *scratch;
retry
eklenmesi, mevcut üye dengelemesini veya yapının boyutunu etkilemez. Ancak bu durum, sembol CRC'lerini veya ABI gösterimini ya da her ikisini de etkileyebilir.
Bu işlem, CRC hesaplamasında gizlenmesini sağlar:
void *data;
bool urgent;
+ ANDROID_KABI_IGNORE(1, bool retry);
void *scratch_space;
Üye retry
doğrudan bildirilmiş gibi kullanılabilir ancak makro aslında retry
'yı ve gendwarfksyms
tarafından sembol türü kararlılığını korumak için kullanılan öğeleri içeren anonim bir birleşim üyesi olarak genişler.
Yeni üyelerle yapının genişletilmesi
Üyeler bazen yapının sonuna eklenir. Bu durum, mevcut üyelerin telafilerini veya yapıyı yalnızca işaretçiyle erişen mevcut kullanıcıları etkilemez. Yapının boyutu CRC'sini etkiler ve bu yapıdaki değişiklikler, küresel kapsamda ek bir makro çağrısıyla aşağıdaki şekilde bastırılabilir:
struct data {
u64 handle;
u64 counter;
ANDROID_KABI_IGNORE(1, void *sekret);
};
ANDROID_KABI_BYTE_SIZE(data, 16);
Okunabilirlik için bunu struct
tanımının hemen sonrasına yerleştirin.
Bir türde veya bir sembolün türünde yapılan diğer tüm değişiklikler
Çok nadiren, önceki kategorilerden birine girmeyen değişiklikler olabilir. Bu durumda, önceki makrolar kullanılarak bastırılamayan CRC değişiklikleri oluşur.
Bu durumlarda, bir türün veya sembolün orijinal symtypes
açıklaması, global kapsamda ANDROID_KABI_TYPE_STRING
çağrısıyla birlikte sağlanabilir.
struct data {
/* extensive changes */
};
ANDROID_KABI_TYPE_STRING("s#data", "original s#data symtypes definition");
Okunabilirliği artırmak için bunu tür veya sembol tanımının hemen sonrasına yerleştirin.
Android 15 ve önceki sürümlerde çözünürlük
Tür ve sembol türü değişiklikleri genksyms
'dan gizlenmelidir. Bu işlem, __GENKSYMS__
ile ön işleme kontrol edilerek yapılabilir.
Rastgele kod dönüşümleri bu şekilde ifade edilebilir.
Örneğin, mevcut bir yapıda boşluğu dolduran yeni bir üyeyi gizlemek için:
struct parcel {
void *data;
bool urgent;
#ifndef __GENKSYMS__
bool retry;
#endif
void *scratch_space;
};