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ı 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 oluşturma 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 öğesine bağlı olabileceğini gösterir:

libexample vendor_available:true and vndk.enabled:true

Şekil 1. desteği etkinleştirildi.

Hem çerçeve yürütülebilir dosyası /system/bin/foo hem de satıcı yürütülebilir dosyası /vendor/bin/bar, libexample öğesine bağlıdır ve shared_libs özelliklerinde libexample öğesini içerir.

libexample hem çerçeve modülleri hem de tedarikçi modülleri tarafından kullanılıyorsa libexample'nın iki varyantı oluşturulur. Çekirdek varyant (libexample'dan sonra adlandırılır) çerçeve modülleri tarafından, satıcı varyantı (libexample.vendor'dan sonra adlandırılır) ise satıcı modülleri tarafından kullanılır. İki varyant farklı dizinlere yüklenir:

  • Temel varyant, /system/lib[64]/libexample.so konumuna yüklenir.
  • vndk.enabled, true olduğu için satıcı varyantı VNDK APEX'e yüklenir.

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

Derleme desteğini yapılandırma

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

BOARD_VNDK_VERSION := current

Bu ayar genel bir etkiye sahiptir: BoardConfig.mk içinde tanımlandığında tüm modüller kontrol edilir. İhlal eden bir modülü kara listeye veya beyaz listeye alma mekanizması olmadığından BOARD_VNDK_VERSION öğesini eklemeden önce tüm gereksiz bağımlılıkları temizlemeniz gerekir. Ortam değişkenlerinizde BOARD_VNDK_VERSION değerini ayarlayarak 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 başlıklara bağlıysa header_libs, static_libs ve/veya shared_libs ile bağımlılıkları (açıkça) belirtmeniz gerekir.

VNDK APEX

Android 10 ve önceki sürümlerde, vndk.enabled simgesi olan modüller /system/lib[64]/vndk[-sp]-${VER} konumuna yükleniyordu. 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 standart yoldan /apex/com.android.vndk.v${VER} kullanılabilir.

VNDK APEX

Şekil 2. VNDK APEX.

Modül tanımı

Android'i BOARD_VNDK_VERSION ile oluşturmak 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ımları, VNDK ile ilgili çeşitli modül özellikleri ve derleme sisteminde uygulanan bağımlılık kontrolleri açıklanmaktadır.

Tedarikçi modülleri

Tedarikçi modülleri, tedarikçiye özel yürütülebilir dosyalar veya paylaşılan kitaplıklardır ve tedarikçi bölümüne yüklenmelidir. Android.bp dosyalarında, sağlayıcı modülleri sağlayıcı veya tescilli özelliği 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ımlanmışsa derleme sistemi, tedarikçi modülleri ile çerçeve modülleri arasındaki bağımlılıklara izin vermez ve şu 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 bir llndk_library modülüne bağlıdır.

Bağımlılık kontrolü, Android.bp içindeki header_libs, static_libs ve shared_libs ile Android.mk içindeki 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 satıcı modülleri aynı ve en son uygulamayı kullanır. Her bir LL-NDK paylaşılan kitaplığı için cc_library, sembol dosyası içeren bir llndk özelliği içerir:

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

Sembol dosyası, tedarikçi modüllerine görünür olan sembolleri açıklar. Örneğin:

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

Derleme sistemi, sembol dosyasına göre tedarikçi modülleri için bir saplama paylaşılan kitaplığı oluşturur. Bu kitaplıklar, BOARD_VNDK_VERSION etkinleştirildiğinde bu kitaplıklarla bağlantı oluşturur. Bir sembol, yalnızca aşağıdaki durumlarda kısa paylaşılan kitaplığa dahil edilir:

  • _PRIVATE veya _PLATFORM ile biten bölümde tanımlanmamış
  • #platform-only etiketi yoksa ve
  • #introduce* etiketleri 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 sağlayıcı) oluşturulabilir. Temel varyant, çerçeve modülü olarak; satıcı varyantı ise satıcı 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 özeldir ve satıcı modüllerine erişilemez.
  • Tedarikçi varyantına, çerçeve modülleri tarafından hiçbir zaman erişilemez.
  • header_libs, static_libs ve/veya shared_libs içinde belirtilen tedarikçi varyantının tüm bağımlılıkları llndk_library veya vendor_available ya da vndk.enabled içeren bir modül olmalıdır.
  • vendor_available true ise tedarikçi varyantına tüm tedarikçi modülleri erişebilir.
  • vendor_available false ise tedarikçi varyantına yalnızca diğer VNDK veya VNDK-SP modülleri erişebilir (ör. vendor:true içeren modüller vendor_available:false modüllerine bağlanamaz).

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

  • Temel varyant /system/lib[64] konumuna yüklenir.
  • Tedarikçi 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 sağlayıcı 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 özetlenmiştir:

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

false

false

false

Satıcı varyantı yok. Bu modül FWK-ONLY'dir.

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

VNDK uzantıları

VNDK uzantıları, ek API'ler içeren VNDK paylaşılan kitaplıklarıdır. Uzantılar, /vendor/lib[64]/vndk[-sp]'ya (sürüm soneki olmadan) yüklenir ve çalışma zamanında orijinal VNDK paylaşılan kitaplıklarının üzerine yazar.

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 özelliği olan 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 özelliği, 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şledikleri temel modül adlarına göre adlandırılır. Örneğin, libvndk_ext öğesinin çıkış ikilisi libvndk_ext.so yerine libvndk.so olur.
  • VNDK uzantıları /vendor/lib[64]/vndk içine yüklenir.
  • VNDK-SP uzantıları /vendor/lib[64]/vndk-sp içine yüklenir.
  • Temel paylaşılan kitaplıklar hem vndk.enabled:true hem de vendor_available:true içermelidir.

VNDK-SP uzantısı, VNDK-SP paylaşılan kitaplığından türetilmelidir (vndk.support_system_process eşit olmalıdır):

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 tarafından paylaşılan kitaplıklara 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

Bir satıcı 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",
    ],
}

Bir satıcı modülü VNDK uzantılarına bağlıysa bu VNDK uzantıları otomatik olarak /vendor/lib[64]/vndk[-sp]'ya yüklenir. Bir modül artık VNDK uzantısına bağlı değilse paylaşılan kitaplığı kaldırmak için CleanSpec.mk'ya temiz bir adım ekleyin. Örneğin:

$(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 küçük farklılıkların (ör. varyantlardan birine özellik ekleme veya varyantlardan birinden özellik kaldırma) nasıl ele alınacağı açıklanmaktadır:

  • Temel varyant (ör. /system/lib[64]/libexample.so)
  • Tedarikçi 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, varsayılan olarak tedarikçi varyantları ve VNDK uzantıları için __ANDROID_VNDK__ tanımlar. Kodu C ön işlemci korumalarıyla koruyabilirsiniz:

void all() { }

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

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

__ANDROID_VNDK__'ya ek olarak, Android.bp içinde farklı cflags veya cppflags belirtilebilir. target.vendor içinde belirtilen cflags veya cppflags, satıcı varyantına özgüdür.

Örneğin, aşağıdaki Android.bp, libexample ve libexample_ext öğelerini 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",
    ],
}

Aşağıda src/example.c kod listesi yer almaktadır:

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 sembollerle 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 sembollerle ilgili koşullar

VNDK ABI denetleyicisi, 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ı tarafından dışa aktarılan semboller (ör. /apex/com.android.vndk.v${VER}/lib[64]/libexample.so), ABI dökümlerinde tanımlanan sembollerle aynı olmalıdır (üst kümeleri olmamalıdır).
  • VNDK uzantıları tarafından dışa aktarılan semboller (ör. /vendor/lib[64]/vndk/libexample.so), ABI dökümlerinde tanımlanan sembollerin üst kümeleri olmalıdır.

VNDK satıcı 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ı satıcı varyantlarının dışında tutma

Kaynak dosyaları tedarikçi varyantının dışında tutmak için bu dosyaları exclude_srcs özelliğine ekleyin. Benzer şekilde, paylaşılan kitaplıkların satıcı varyantıyla bağlantılı olmadığından emin olmak için bu kitaplıkları exclude_shared_libs özelliğine ekleyin. Örneğin:

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 çekirdek varyantı, fwk.c ve both.c kodunu içerir ve libfwk_only ile libboth paylaşılan kitaplıklarına bağlıdır. libexample_cond_exclude öğesinin sağlayıcı varyantı, fwk.c öğesi exclude_srcs özelliği tarafından hariç tutulduğu için yalnızca both.c öğesindeki kodu içerir. Benzer şekilde, libfwk_only, exclude_shared_libs özelliği tarafından hariç tutulduğu için yalnızca paylaşılan kitaplığa libboth bağlıdır.

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

VNDK uzantısı, VNDK paylaşılan kitaplığına yeni sınıflar veya yeni işlevler ekleyebilir. Bu bildirimlerin bağımsız başlıklarda tutulması ve mevcut başlıkların değiştirilmemesi ö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, libexample dışa aktarma işlemlerinde yalnızca include dışa aktarılırken libexample_ext dışa aktarma işlemlerinde hem include hem de include-ext dışa aktarılır. Bu sayede, feature_name.h öğesinin libexample kullanıcıları tarafından yanlışlıkla eklenmesi önlenir:

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ı bağımsız başlık dosyalarına ayırmak mümkün değilse alternatif olarak #ifdef korumaları eklenebilir. Ancak tüm VNDK uzantısı kullanıcılarının tanımlama işaretlerini eklediğinden emin olun. cc_defaults tanımlayarak cflags'ye tanımlama işaretleri ekleyebilir ve paylaşılan kitaplıkları shared_libs ile bağlayabilirsiniz.

Örneğin, VNDK uzantısına libexample2_ext yeni bir üye işlevi Example2::get_b() eklemek için mevcut başlık dosyasını değiştirmeniz ve bir #ifdef koruması 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ımlanmıştı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ı, defaults özelliklerine libexample2_ext_defaults 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 örtülü olarak yüklenir.

BOARD_VNDK_VERSION etkinse vendor_available veya vndk.enabled içeren modüller özel işlem görür. Bir çerçeve modülü, vendor_available veya vndk.enabled içeren bir modüle bağlıysa temel varyant, geçişli yükleme kümesine dahil edilir. Bir tedarikçi modülü vendor_available içeren bir modüle bağlıysa tedarikçi varyantı geçişli yükleme grubuna dahil edilir. Ancak, vndk.enabled içeren modüllerin tedarikçi varyantları, tedarikçi modülleri tarafından kullanılıp kullanılmadıklarına bakılmaksızın yüklenir.

Bağımlılıklar derleme sistemi için görünür olmadığında (ö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ı ifade eder. PRODUCT_PACKAGES içinde satıcı varyantını açıkça belirtmek için modül adına .vendor sonekini ekleyin. Örneğin:

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

Bu örnekte libexample, /system/lib[64]/libexample.so, libexample.vendor ise /vendor/lib[64]/libexample.so anlamına gelir. /vendor/lib[64]/libexample.so uygulamasını yüklemek için libexample.vendorPRODUCT_PACKAGES'a ekleyin:

PRODUCT_PACKAGES += libexample.vendor