VNDK derleme sistemi desteği

Android 8.1 ve sonraki sürümlerde, derleme sisteminde yerleşik VNDK desteği bulunur. VNDK desteği etkinleştirildiğinde derleme sistemi, modüller arasındaki bağımlılıklarını kontrol eder, satıcı modülleri için satıcıya özel bir varyant oluşturur ve bu modülleri belirlenen dizinlere otomatik olarak yükler.

VNDK derleme desteği örneği

Bu örnekte, Android.bp modülü tanımı libexample adlı bir kitaplığı tanımlar. vendor_available özelliği, çerçeve modüllerinin ve tedarikçi modüllerinin libexample'a bağlı olabileceğini gösterir:

libexample vendor_available:true ve vndk.enabled:true

Şekil 1.

Hem çerçeve yürütülebilir dosyası /system/bin/foo hem de tedarikçi yürütülebilir dosyası /vendor/bin/bar, libexample'ye bağlıdır ve shared_libs özelliklerinde libexample vardır.

libexample hem çerçeve modülleri hem de tedarikçi modülleri tarafından kullanılıyorsa libexample'nin iki varyantı oluşturulur. Temel varyant (libexample adında), çerçeve modülleri tarafından, tedarikçi varyantı (libexample.vendor adında) ise tedarikçi modülleri tarafından kullanılır. İki varyant farklı dizinlere yüklenir:

  • Temel varyant /system/lib[64]/libexample.so'e yüklenir.
  • vndk.enabled değeri true olduğundan tedarikçi firma varyantı, VNDK APEX'e yüklendi.

Ayrıntılı bilgi için Modül tanımı başlıklı makaleyi inceleyin.

Derleme desteğini yapılandırma

Bir ürün cihazı için tam derleme sistemi desteğini etkinleştirmek üzere BOARD_VNDK_VERSION dosyasını BoardConfig.mk dosyasına ekleyin:

BOARD_VNDK_VERSION := current

Bu ayarın genel bir etkisi vardır: BoardConfig.mk içinde tanımlandığında tüm modüller kontrol edilir. Rahatsız edici bir modülü kara listeye veya beyaz listeye ekleme mekanizması olmadığından, BOARD_VNDK_VERSION eklemeden önce tüm gereksiz bağımlılıkları temizlemeniz gerekir. Ortam değişkenlerinizde BOARD_VNDK_VERSION ayarını yaparak bir modülü test edip derleyebilirsiniz:

$ BOARD_VNDK_VERSION=current m module_name.vendor

BOARD_VNDK_VERSION etkinleştirildiğinde, birkaç varsayılan genel üstbilgi arama yolu kaldırılır. Bunlardan bazıları:

  • frameworks/av/include
  • frameworks/native/include
  • frameworks/native/opengl/include
  • hardware/libhardware/include
  • hardware/libhardware_legacy/include
  • hardware/ril/include
  • libnativehelper/include
  • libnativehelper/include_deprecated
  • system/core/include
  • system/media/audio/include

Bir modül bu dizinlerdeki üstbilgilerden yararlanıyorsa header_libs, static_libs ve/veya shared_libs ile bağımlılıklarını (açıkça) belirtmeniz gerekir.

VNDK APEX

Android 10 ve önceki sürümlerde, vndk.enabled içeren modüller /system/lib[64]/vndk[-sp]-${VER}'e yüklendi. Android 11 ve sonraki sürümlerde VNDK kitaplıkları APEX biçiminde paketlenir ve VNDK APEX'in adı com.android.vndk.v${VER} olur. Cihaz yapılandırmasına bağlı olarak VNDK APEX düzleştirilir veya düzleştirilmez ve /apex/com.android.vndk.v${VER} kanonik yolundan kullanılabilir.

VNDK APEX

Şekil 2. VNDK APEX.

Modül tanımı

Android'i BOARD_VNDK_VERSION ile derlemek için Android.mk veya Android.bp içinde modül tanımını düzeltmeniz gerekir. Bu bölümde, farklı modül tanımı türleri, VNDK ile ilgili çeşitli modül özellikleri ve derleme sisteminde uygulanan bağımlılık kontrolleri açıklanmaktadır.

Satıcı modülleri

Tedarikçi modülleri, tedarikçiye özgü yürütülebilir dosyalar veya tedarikçi bölümüne yüklenmesi gereken paylaşılan kitaplıklardır. Android.bp dosyalarında tedarikçi modülleri, tedarikçi veya özel mülkü true olarak ayarlamalıdır. Android.mk dosyalarında tedarikçi modülleri, LOCAL_VENDOR_MODULE veya LOCAL_PROPRIETARY_MODULE değerini true olarak ayarlamalıdır.

BOARD_VNDK_VERSION tanımlanırsa yapı sistemi, tedarikçi modülleri ile çerçeve modülleri arasındaki bağımlılıklara izin vermez ve aşağıdaki durumlarda hata verir:

  • vendor:true içermeyen bir modül, vendor:true içeren bir modüle bağlıysa veya
  • vendor:true içeren bir modül, vendor:true veya vendor_available:true içermeyen llndk_library olmayan bir modüle bağlıdır.

Bağımlılık kontrolü, Android.bp ürününde header_libs, static_libs ve shared_libs, Android.mk bölgesinde ise LOCAL_HEADER_LIBRARIES, LOCAL_STATIC_LIBRARIES ve LOCAL_SHARED_LIBRARIES için geçerlidir.

LL-NDK

LL-NDK paylaşılan kitaplıkları, kararlı ABI'lere sahip paylaşılan kitaplıklardır. Hem çerçeve hem de tedarikçi modülleri aynı ve en son uygulamayı paylaşır. cc_library, her LL-NDK paylaşılan kitaplığı için simge dosyasına sahip bir llndk özelliği içerir:

cc_library {
    name: "libvndksupport",
    llndk: {
        symbol_file: "libvndksupport.map.txt",
    },
}

Simge dosyası, tedarikçi modülleri tarafından görülebilen simgeleri tanımlar. Örnek:

LIBVNDKSUPPORT {
  global:
    android_load_sphal_library; # llndk
    android_unload_sphal_library; # llndk
  local:
    *;
};

Derleme sistemi, simge dosyasını temel alarak tedarikçi modülleri için bir stub paylaşılan kitaplık oluşturur. Bu kitaplık, BOARD_VNDK_VERSION etkinleştirildiğinde bu kitaplıklarla bağlantı kurar. Bir simge, yalnızca aşağıdaki durumlarda stub paylaşılan kitaplığına dahil edilir:

  • _PRIVATE veya _PLATFORM ile biten bölümde tanımlanmamışsa,
  • #platform-only etiketi yok ve
  • #introduce* etiketi yok veya etiket hedefle eşleşiyor.

VNDK

Android.bp dosyalarında cc_library, cc_library_static, cc_library_shared ve cc_library_headers modül tanımları, VNDK ile ilgili üç özelliği destekler: vendor_available, vndk.enabled ve vndk.support_system_process.

vendor_available veya vndk.enabled true ise iki varyant (çekirdek ve tedarikçi) oluşturulabilir. Temel varyant, çerçeve modülü olarak, tedarikçi varyantı ise tedarikçi modülü olarak değerlendirilmelidir. Bazı çerçeve modülleri bu modüle bağlıysa temel varyant oluşturulur. Bazı tedarikçi modülleri bu modüle bağlıysa tedarikçi varyantı oluşturulur. Derleme sistemi aşağıdaki bağımlılık kontrollerini zorunlu kılar:

  • Temel varyant her zaman yalnızca çerçeveye özgüdür ve tedarikçi modülleri tarafından erişilemez.
  • Çerçeve modülleri, tedarikçi varyantına her zaman erişemez.
  • Tedarikçi firma varyantının header_libs, static_libs ve/veya shared_libs içinde belirtilen tüm bağımlılıkları llndk_library ya da vendor_available veya vndk.enabled içeren bir modül olmalıdır.
  • vendor_available true ise tedarikçi firma varyantına tüm tedarikçi firma modülleri erişebilir.
  • vendor_available false ise tedarikçi varyantına yalnızca diğer VNDK veya VNDK-SP modülleri erişebilir (yani vendor:true içeren modüller vendor_available:false modüllerini bağlayamaz).

cc_library veya cc_library_shared için varsayılan kurulum yolu aşağıdaki kurallara göre belirlenir:

  • Temel varyant /system/lib[64]'e yüklenir.
  • Tedarikçi firma varyantı yükleme yolu değişiklik gösterebilir:
    • vndk.enabled false ise tedarikçi varyantı /vendor/lib[64]'ye yüklenir.
    • vndk.enabled true ise tedarikçi varyantı VNDK APEX'e(com.android.vndk.v${VER}) yüklenir.

Aşağıdaki tabloda, derleme sisteminin tedarikçi varyantlarını nasıl işlediği özetlenmektedir:

vendor_available vndk
enabled
vndk
support_same_process
Tedarikçi varyant açıklamaları
true false false Tedarikçi firma varyantları VND-ONLY şeklindedir. Paylaşılan kitaplıklar /vendor/lib[64]'e yüklenir.
true Geçersiz (Derleme hatası)
true false Tedarikçi firma varyantları VNDK'dır. Paylaşılan kitaplıklar VNDK APEX'e yüklenir.
true Tedarikçi firma varyantları VNDK-SP'dir. Paylaşılan kitaplıklar VNDK APEX'e yüklenir.

false

false

false

Satıcı varyantları yok. Bu modül YALNIZCA ÇERÇEVE'dir.

true Geçersiz (Derleme hatası)
true false Tedarikçi varyantları VNDK-Private'dir. Paylaşılan kitaplıklar, VNDK APEX'e yüklenir. Bunlar doğrudan tedarikçi modülleri tarafından kullanılmamalıdır.
true Tedarikçi firma varyantları VNDK-SP-Private'dır. Paylaşılan kitaplıklar VNDK APEX'e yüklenir. Bunlar doğrudan tedarikçi modülleri tarafından kullanılmamalıdır.

VNDK uzantıları

VNDK uzantıları, ek API'lere sahip VNDK paylaşılan kitaplıklarıdır. Uzantıların /vendor/lib[64]/vndk[-sp] (sürüm son eki olmadan) içine yüklenmesi ve çalışma zamanında orijinal VNDK paylaşılan kitaplıklarını geçersiz kılması

VNDK uzantılarını tanımlama

Android 9 ve sonraki sürümlerde Android.bp, VNDK uzantılarını yerel olarak destekler. VNDK uzantısı oluşturmak için vendor:true ve extends mülkü içeren başka bir modül tanımlayın:

cc_library {
    name: "libvndk",
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libvndk_ext",
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libvndk",
    },
}

vendor:true, vndk.enabled:true ve extends özelliklerine sahip bir modül, VNDK uzantısını tanımlar:

  • extends mülkü, temel bir VNDK paylaşılan kitaplık adını (veya VNDK-SP paylaşılan kitaplık adını) belirtmelidir.
  • VNDK uzantıları (veya VNDK-SP uzantıları), genişletildiği temel modül adlarından sonra adlandırılır. Örneğin, libvndk_ext değerinin çıkış ikilisi libvndk_ext.so yerine libvndk.so olur.
  • VNDK uzantıları /vendor/lib[64]/vndk'e yüklenir.
  • VNDK-SP uzantıları /vendor/lib[64]/vndk-sp'e yüklenir.
  • Temel paylaşılan kitaplıklarda hem vndk.enabled:true hem de vendor_available:true olmalıdır.

VNDK-SP uzantısı, VNDK-SP paylaşılan kitaplığından uzanmalıdır (vndk.support_system_process eşittir):

cc_library {
    name: "libvndk_sp",
    vendor_available: true,
    vndk: {
        enabled: true,
        support_system_process: true,
    },
}

cc_library {
    name: "libvndk_sp_ext",
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libvndk_sp",
        support_system_process: true,
    },
}

VNDK uzantıları (veya VNDK-SP uzantıları) diğer tedarikçi firmaların paylaşılan kitaplıklarına bağlı olabilir:

cc_library {
    name: "libvndk",
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libvndk_ext",
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libvndk",
    },
    shared_libs: [
        "libvendor",
    ],
}

cc_library {
    name: "libvendor",
    vendor: true,
}

VNDK uzantılarını kullanma

Tedarikçi firma modülü, VNDK uzantıları tarafından tanımlanan ek API'lere bağlıysa modül, shared_libs özelliğinde VNDK uzantısının adını belirtmelidir:

// A vendor shared library example
cc_library {
    name: "libvendor",
    vendor: true,
    shared_libs: [
        "libvndk_ext",
    ],
}

// A vendor executable example
cc_binary {
    name: "vendor-example",
    vendor: true,
    shared_libs: [
        "libvndk_ext",
    ],
}

Tedarikçi firma modülü VNDK uzantılarına bağlıysa bu VNDK uzantıları otomatik olarak /vendor/lib[64]/vndk[-sp] ürününe yüklenir. Bir modül artık VNDK uzantısına bağlı değilse paylaşılan kitaplığı kaldırmak için CleanSpec.mk bölümüne temiz bir adım ekleyin. Örnek:

$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)

Koşullu derleme

Bu bölümde, aşağıdaki üç VNDK paylaşılan kitaplığı arasındaki ince farklılıklar (ör. varyantlardan birine özellik ekleme veya kaldırma) nasıl ele alınacağı açıklanmaktadır:

  • Temel varyant (ör. /system/lib[64]/libexample.so)
  • Satıcı varyantı (ör. /apex/com.android.vndk.v${VER}/lib[64]/libexample.so)
  • VNDK uzantısı (ör. /vendor/lib[64]/vndk[-sp]/libexample.so)

Koşullu derleyici işaretleri

Android derleme sistemi, tedarikçi firma varyantları ve VNDK uzantıları için varsayılan olarak __ANDROID_VNDK__ değerini tanımlar. C ön işlemci korumalarıyla kodu koruyabilirsiniz:

void all() { }

#if !defined(__ANDROID_VNDK__)
void framework_only() { }
#endif

#if defined(__ANDROID_VNDK__)
void vndk_only() { }
#endif

__ANDROID_VNDK__ öğesine ek olarak, Android.bp içinde farklı cflags veya cppflags belirtilebilir. target.vendor öğesinde belirtilen cflags veya cppflags, tedarikçi firma varyantına özeldir.

Örneğin, aşağıdaki Android.bp libexample ve libexample_ext'yi tanımlar:

cc_library {
    name: "libexample",
    srcs: ["src/example.c"],
    vendor_available: true,
    vndk: {
        enabled: true,
    },
    target: {
        vendor: {
            cflags: ["-DLIBEXAMPLE_ENABLE_VNDK=1"],
        },
    },
}

cc_library {
    name: "libexample_ext",
    srcs: ["src/example.c"],
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libexample",
    },
    cflags: [
        "-DLIBEXAMPLE_ENABLE_VNDK=1",
        "-DLIBEXAMPLE_ENABLE_VNDK_EXT=1",
    ],
}

src/example.c için de kod listesi şöyle:

void all() { }

#if !defined(LIBEXAMPLE_ENABLE_VNDK)
void framework_only() { }
#endif

#if defined(LIBEXAMPLE_ENABLE_VNDK)
void vndk() { }
#endif

#if defined(LIBEXAMPLE_ENABLE_VNDK_EXT)
void vndk_ext() { }
#endif

Bu iki dosyaya göre derleme sistemi, aşağıdaki dışa aktarılan simgelerle paylaşılan kitaplıklar oluşturur:

Yükleme yolu Dışa aktarılan simgeler
/system/lib[64]/libexample.so all, framework_only
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so all, vndk
/vendor/lib[64]/vndk/libexample.so all, vndk, vndk_ext

Dışa aktarılan simgelerle ilgili koşullar

VNDK ABI kontrol aracı, VNDK tedarikçi varyantlarının ve VNDK uzantılarının ABI'sini prebuilts/abi-dumps/vndk altındaki referans ABI dökümleriyle karşılaştırır.

  • VNDK tedarikçi varyantları (ör. /apex/com.android.vndk.v${VER}/lib[64]/libexample.so) tarafından dışa aktarılan simgeler, ABI dökümlerinde tanımlanan simgelerle aynı olmalıdır (üst kümeleri değil).
  • VNDK uzantıları (ör. /vendor/lib[64]/vndk/libexample.so) tarafından dışa aktarılan simgeler, ABI dökümlerinde tanımlanan simgelerin üst kümesi olmalıdır.

VNDK tedarikçi varyantları veya VNDK uzantıları yukarıdaki şartlara uymazsa VNDK ABI denetleyicisi derleme hataları verir ve derlemeyi durdurur.

Kaynak dosyaları veya paylaşılan kitaplıkları tedarikçi varyantlarından hariç tutma

Kaynak dosyaları tedarikçi firma varyantından hariç tutmak için exclude_srcs mülküne ekleyin. Benzer şekilde, paylaşılan kitaplıkların tedarikçi firma varyantıyla bağlanmadığından emin olmak için bu kitaplıkları exclude_shared_libs özelliğine ekleyin. Örnek:

cc_library {
    name: "libexample_cond_exclude",
    srcs: ["fwk.c", "both.c"],
    shared_libs: ["libfwk_only", "libboth"],
    vendor_available: true,
    target: {
        vendor: {
            exclude_srcs: ["fwk.c"],
            exclude_shared_libs: ["libfwk_only"],
        },
    },
}

Bu örnekte, libexample_cond_exclude'ün temel varyantı fwk.c ve both.c'deki kodu içerir ve libfwk_only ile libboth adlı paylaşılan kitaplıklara bağlıdır. fwk.c, exclude_srcs özelliği tarafından hariç tutulduğundan, libexample_cond_exclude ürününün tedarikçi firma varyantı yalnızca both.c kaynaklı kodu içerir. Benzer şekilde, libfwk_only, exclude_shared_libs mülkü tarafından hariç tutulduğu için yalnızca paylaşılan kitaplık libboth'e bağlıdır.

VNDK uzantılarından başlıkları dışa aktarma

VNDK uzantıları, VNDK paylaşılan kitaplığına yeni sınıflar veya yeni işlevler ekleyebilir. Bu beyanları bağımsız başlıklarda tutmanız ve mevcut başlıkları değiştirmemeniz önerilir.

Örneğin, VNDK uzantısı libexample_ext için yeni bir başlık dosyası include-ext/example/ext/feature_name.h oluşturulur:

  • Android.bp
  • include-ext/example/ext/feature_name.h
  • include/example/example.h
  • src/example.c
  • src/ext/feature_name.c

Aşağıdaki Android.bp örneğinde libexample yalnızca include'yi, libexample_ext ise hem include hem de include-ext'i dışa aktarır. Bu sayede, feature_name.h, libexample kullanıcıları tarafından yanlışlıkla dahil edilmez:

cc_library {
    name: "libexample",
    srcs: ["src/example.c"],
    export_include_dirs: ["include"],
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libexample_ext",
    srcs: [
        "src/example.c",
        "src/ext/feature_name.c",
    ],
    export_include_dirs: [
        "include",
        "include-ext",
    ],
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libexample",
    },
}

Uzantıların bağımsız başlık dosyalarına ayrılması mümkün değilse #ifdef koruma eklemek de bir alternatiftir. Ancak tüm VNDK uzantısı kullanıcılarının tanımlama işaretlerini eklediğinden emin olun. cflags öğesine işaretler eklemek ve paylaşılan kitaplıkları shared_libs ile bağlamak için cc_defaults öğesini tanımlayabilirsiniz.

Örneğin, VNDK uzantısı libexample2_ext'ye yeni bir üye işlevi Example2::get_b() eklemek için mevcut başlık dosyasını değiştirmeniz ve bir #ifdef koruyucu eklemeniz gerekir:

#ifndef LIBEXAMPLE2_EXAMPLE_H_
#define LIBEXAMPLE2_EXAMPLE_H_

class Example2 {
 public:
  Example2();

  void get_a();

#ifdef LIBEXAMPLE2_ENABLE_VNDK_EXT
  void get_b();
#endif

 private:
  void *impl_;
};

#endif  // LIBEXAMPLE2_EXAMPLE_H_

libexample2_ext kullanıcıları için libexample2_ext_defaults adlı bir cc_defaults tanımlanır:

cc_library {
    name: "libexample2",
    srcs: ["src/example2.cpp"],
    export_include_dirs: ["include"],
    vendor_available: true,
    vndk: {
        enabled: true,
    },
}

cc_library {
    name: "libexample2_ext",
    srcs: ["src/example2.cpp"],
    export_include_dirs: ["include"],
    vendor: true,
    vndk: {
        enabled: true,
        extends: "libexample2",
    },
    cflags: [
        "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1",
    ],
}

cc_defaults {
    name: "libexample2_ext_defaults",
    shared_libs: [
        "libexample2_ext",
    ],
    cflags: [
        "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1",
    ],
}

libexample2_ext kullanıcıları, libexample2_ext_defaults özelliğini defaults mülklerine ekleyebilir:

cc_binary {
    name: "example2_user_executable",
    defaults: ["libexample2_ext_defaults"],
    vendor: true,
}

Ürün paketleri

Android derleme sisteminde PRODUCT_PACKAGES değişkeni, cihaza yüklenmesi gereken yürütülebilir dosyaları, paylaşılan kitaplıkları veya paketleri belirtir. Belirtilen modüllerin geçişli bağımlılıkları da cihaza dolaylı olarak yüklenir.

BOARD_VNDK_VERSION etkinse vendor_available veya vndk.enabled içeren modüller özel işleme tabi tutulur. Bir çerçeve modülü vendor_available veya vndk.enabled içeren bir modüle bağlıysa temel varyant, aktarmalı yükleme grubuna dahil edilir. Tedarikçi firma modülü vendor_available içeren bir modüle bağlıysa tedarikçi firma varyantı geçişli yükleme grubuna dahil edilir. Bununla birlikte, vndk.enabled özelliğine sahip modüllerin tedarikçi varyantları, tedarikçi modülleri tarafından kullanılmalarına bakılmaksızın yüklenir.

Bağımlılıklar derleme sistemi tarafından görünmez olduğunda (ör. çalışma zamanında dlopen() ile açılabilen paylaşılan kitaplıklar), bu modülleri açıkça yüklemek için PRODUCT_PACKAGES içinde modül adlarını belirtmeniz gerekir.

Bir modülde vendor_available veya vndk.enabled varsa modül adı, temel varyantını temsil eder. PRODUCT_PACKAGES içinde tedarikçi varyantını açıkça belirtmek için modül adına .vendor son eki ekleyin. Örnek:

cc_library {
    name: "libexample",
    srcs: ["example.c"],
    vendor_available: true,
}

Bu örnekte libexample, /system/lib[64]/libexample.so yerine, libexample.vendor ise /vendor/lib[64]/libexample.so yerine kullanılmıştır. /vendor/lib[64]/libexample.so'ü yüklemek için libexample.vendor'u PRODUCT_PACKAGES'ye ekleyin:

PRODUCT_PACKAGES += libexample.vendor