Hỗ trợ hệ thống xây dựng VNDK

Trong Android 8.1 trở lên, hệ thống bản dựng có hỗ trợ VNDK tích hợp. Khi bạn bật tính năng hỗ trợ VNDK, hệ thống xây dựng sẽ kiểm tra các phần phụ thuộc giữa các mô-đun, tạo một biến thể dành riêng cho nhà cung cấp cho các mô-đun của nhà cung cấp và tự động cài đặt các mô-đun đó vào các thư mục được chỉ định.

Ví dụ về hỗ trợ bản dựng VNDK

Trong ví dụ này, định nghĩa mô-đun Android.bp xác định một thư viện có tên là libexample. Thuộc tính vendor_available cho biết các mô-đun khung và mô-đun của nhà cung cấp có thể phụ thuộc vào libexample:

libexample vendor_available:true và vndk.enabled:true

Hình 1. đã bật chế độ hỗ trợ.

Cả tệp thực thi khung /system/bin/foo và tệp thực thi của nhà cung cấp /vendor/bin/bar đều phụ thuộc vào libexample và có libexample trong các thuộc tính shared_libs của chúng.

Nếu cả mô-đun khung và mô-đun nhà cung cấp đều dùng libexample, thì hai biến thể của libexample sẽ được tạo. Biến thể cốt lõi (được đặt tên theo libexample) được các mô-đun khung sử dụng và biến thể của nhà cung cấp (được đặt tên theo libexample.vendor) được các mô-đun của nhà cung cấp sử dụng. Hai biến thể này được cài đặt vào các thư mục khác nhau:

  • Biến thể cốt lõi được cài đặt vào /system/lib[64]/libexample.so.
  • Biến thể của nhà cung cấp được cài đặt vào VNDK APEX vì vndk.enabledtrue.

Để biết thêm thông tin chi tiết, hãy xem phần Định nghĩa mô-đun.

Định cấu hình hỗ trợ bản dựng

Để bật chế độ hỗ trợ đầy đủ cho hệ thống bản dựng cho một thiết bị sản phẩm, hãy thêm BOARD_VNDK_VERSION vào BoardConfig.mk:

BOARD_VNDK_VERSION := current

Chế độ cài đặt này có hiệu ứng toàn cầu: Khi được xác định trong BoardConfig.mk, tất cả các mô-đun đều được kiểm tra. Vì không có cơ chế đưa mô-đun vi phạm vào danh sách đen hoặc danh sách trắng, nên bạn phải xoá tất cả các phần phụ thuộc không cần thiết trước khi thêm BOARD_VNDK_VERSION. Bạn có thể kiểm thử và biên dịch một mô-đun bằng cách thiết lập BOARD_VNDK_VERSION trong các biến môi trường:

$ BOARD_VNDK_VERSION=current m module_name.vendor

Khi BOARD_VNDK_VERSION được bật, một số đường dẫn tìm kiếm tiêu đề chung mặc định sẽ bị xoá. bao gồm:

  • 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

Nếu một mô-đun phụ thuộc vào các tiêu đề trong những thư mục này, bạn phải chỉ định (một cách rõ ràng) các phần phụ thuộc bằng header_libs, static_libs và/hoặc shared_libs.

VNDK APEX

Trong Android 10 trở xuống, các mô-đun có vndk.enabled được cài đặt trong /system/lib[64]/vndk[-sp]-${VER}. Trong Android 11 trở lên, các thư viện VNDK được đóng gói ở định dạng APEX và tên của VNDK APEX là com.android.vndk.v${VER}. Tuỳ thuộc vào cấu hình thiết bị, VNDK APEX sẽ được làm phẳng hoặc không làm phẳng và có sẵn trong đường dẫn chuẩn /apex/com.android.vndk.v${VER}.

VNDK APEX

Hình 2. VNDK APEX.

Định nghĩa mô-đun

Để tạo Android bằng BOARD_VNDK_VERSION, bạn phải sửa đổi định nghĩa mô-đun trong Android.mk hoặc Android.bp. Phần này mô tả các loại định nghĩa mô-đun, một số thuộc tính mô-đun liên quan đến VNDK và các quy trình kiểm tra phần phụ thuộc được triển khai trong hệ thống xây dựng.

Mô-đun nhà cung cấp

Các mô-đun của nhà cung cấp là các tệp thực thi hoặc thư viện dùng chung dành riêng cho nhà cung cấp và phải được cài đặt vào một phân vùng của nhà cung cấp. Trong tệp Android.bp, các mô-đun của nhà cung cấp phải đặt thuộc tính của nhà cung cấp hoặc thuộc tính độc quyền thành true. Trong tệp Android.mk, các mô-đun của nhà cung cấp phải đặt LOCAL_VENDOR_MODULE hoặc LOCAL_PROPRIETARY_MODULE thành true.

Nếu BOARD_VNDK_VERSION được xác định, hệ thống xây dựng sẽ không cho phép các phần phụ thuộc giữa các mô-đun của nhà cung cấp và các mô-đun khung, đồng thời phát ra lỗi nếu:

  • một mô-đun không có vendor:true phụ thuộc vào một mô-đun có vendor:true, hoặc
  • một mô-đun có vendor:true phụ thuộc vào một mô-đun không phải llndk_library, không có vendor:true cũng như vendor_available:true.

Quy trình kiểm tra phần phụ thuộc áp dụng cho header_libs, static_libsshared_libs trong Android.bp, cũng như cho LOCAL_HEADER_LIBRARIES, LOCAL_STATIC_LIBRARIESLOCAL_SHARED_LIBRARIES trong Android.mk.

LL-NDK

Thư viện dùng chung LL-NDK là những thư viện dùng chung có ABI ổn định. Cả mô-đun khung và mô-đun nhà cung cấp đều dùng chung cùng một cách triển khai mới nhất. Đối với mỗi thư viện dùng chung LL-NDK, cc_library chứa một thuộc tính llndk có tệp biểu tượng:

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

Tệp biểu tượng mô tả các biểu tượng mà mô-đun nhà cung cấp có thể nhìn thấy. Ví dụ:

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

Dựa trên tệp biểu tượng, hệ thống xây dựng sẽ tạo một thư viện dùng chung gốc cho các mô-đun của nhà cung cấp. Các mô-đun này sẽ liên kết với các thư viện khi BOARD_VNDK_VERSION được bật. Một biểu tượng chỉ được đưa vào thư viện dùng chung stub nếu biểu tượng đó:

  • Không được xác định ở cuối phần bằng _PRIVATE hoặc _PLATFORM,
  • Không có thẻ #platform-only
  • Không có thẻ #introduce* hoặc thẻ này khớp với mục tiêu.

VNDK

Trong các tệp Android.bp, định nghĩa mô-đun cc_library, cc_library_static, cc_library_sharedcc_library_headers hỗ trợ 3 thuộc tính liên quan đến VNDK: vendor_available, vndk.enabledvndk.support_system_process.

Nếu vendor_available hoặc vndk.enabledtrue, thì có thể tạo 2 biến thể (corevendor). Biến thể cốt lõi phải được coi là một mô-đun khung và biến thể của nhà cung cấp phải được coi là một mô-đun của nhà cung cấp. Nếu một số mô-đun khung phụ thuộc vào mô-đun này, thì biến thể cốt lõi sẽ được tạo. Nếu một số mô-đun của nhà cung cấp phụ thuộc vào mô-đun này, thì biến thể của nhà cung cấp sẽ được tạo. Hệ thống bản dựng thực thi các bước kiểm tra phần phụ thuộc sau:

  • Biến thể cốt lõi luôn chỉ có khung và các mô-đun của nhà cung cấp không truy cập được.
  • Các mô-đun khung không bao giờ truy cập được vào biến thể của nhà cung cấp.
  • Tất cả các phần phụ thuộc của biến thể nhà cung cấp (được chỉ định trong header_libs, static_libs và/hoặc shared_libs) phải là llndk_library hoặc một mô-đun có vendor_available hoặc vndk.enabled.
  • Nếu vendor_availabletrue, thì tất cả các mô-đun của nhà cung cấp đều có thể truy cập vào biến thể của nhà cung cấp.
  • Nếu vendor_availablefalse, thì chỉ các mô-đun VNDK hoặc VNDK-SP khác mới có thể truy cập vào biến thể của nhà cung cấp (tức là các mô-đun có vendor:true không thể liên kết các mô-đun vendor_available:false).

Đường dẫn cài đặt mặc định cho cc_library hoặc cc_library_shared được xác định theo các quy tắc sau:

  • Biến thể cốt lõi được cài đặt vào /system/lib[64].
  • Đường dẫn cài đặt biến thể của nhà cung cấp có thể khác nhau:
    • Nếu vndk.enabledfalse, thì biến thể của nhà cung cấp sẽ được cài đặt vào /vendor/lib[64].
    • Nếu vndk.enabledtrue, thì biến thể của nhà cung cấp sẽ được cài đặt vào VNDK APEX(com.android.vndk.v${VER}).

Bảng dưới đây tóm tắt cách hệ thống xây dựng xử lý các biến thể của nhà cung cấp:

vendor_available vndk
enabled
vndk
support_system_process
Nội dung mô tả biến thể của nhà cung cấp
true false false Các biến thể của nhà cung cấp là CHỈ VND. Các thư viện dùng chung được cài đặt vào /vendor/lib[64].
true Không hợp lệ (Lỗi bản dựng)
true false Các biến thể của nhà cung cấp là VNDK. Các thư viện dùng chung được cài đặt vào VNDK APEX.
true Các biến thể của nhà cung cấp là VNDK-SP. Các thư viện dùng chung được cài đặt vào VNDK APEX.

false

false

false

Không có biến thể của nhà cung cấp. Mô-đun này là FWK-ONLY.

true Không hợp lệ (Lỗi bản dựng)
true false Các biến thể của nhà cung cấp là VNDK-Private. Các thư viện dùng chung được cài đặt vào VNDK APEX. Các mô-đun này không được các mô-đun của nhà cung cấp sử dụng trực tiếp.
true Các biến thể của nhà cung cấp là VNDK-SP-Private. Các thư viện dùng chung được cài đặt vào VNDK APEX. Các mô-đun này không được các mô-đun của nhà cung cấp sử dụng trực tiếp.

Tiện ích VNDK

Tiện ích VNDK là các thư viện dùng chung VNDK có thêm API. Các tiện ích được cài đặt vào /vendor/lib[64]/vndk[-sp] (không có hậu tố phiên bản) và ghi đè các thư viện dùng chung VNDK ban đầu trong thời gian chạy.

Xác định các tiện ích VNDK

Trong Android 9 trở lên, Android.bp hỗ trợ các tiện ích VNDK một cách tự nhiên. Để tạo một tiện ích VNDK, hãy xác định một mô-đun khác bằng vendor:true và thuộc tính extends:

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

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

Một mô-đun có các thuộc tính vendor:true, vndk.enabled:trueextends sẽ xác định tiện ích VNDK:

  • Thuộc tính extends phải chỉ định tên thư viện dùng chung VNDK cơ sở (hoặc tên thư viện dùng chung VNDK-SP).
  • Tiện ích VNDK (hoặc tiện ích VNDK-SP) được đặt tên theo tên mô-đun cơ sở mà chúng mở rộng. Ví dụ: tệp nhị phân đầu ra của libvndk_extlibvndk.so thay vì libvndk_ext.so.
  • Các tiện ích VNDK được cài đặt vào /vendor/lib[64]/vndk.
  • Các tiện ích VNDK-SP được cài đặt vào /vendor/lib[64]/vndk-sp.
  • Các thư viện dùng chung cơ sở phải có cả vndk.enabled:truevendor_available:true.

Tiện ích VNDK-SP phải mở rộng từ một thư viện dùng chung VNDK-SP (vndk.support_system_process phải bằng nhau):

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,
    },
}

Các tiện ích VNDK (hoặc tiện ích VNDK-SP) có thể phụ thuộc vào các thư viện dùng chung khác của nhà cung cấp:

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,
}

Sử dụng các tiện ích VNDK

Nếu một mô-đun nhà cung cấp phụ thuộc vào các API bổ sung do tiện ích VNDK xác định, thì mô-đun đó phải chỉ định tên của tiện ích VNDK trong thuộc tính shared_libs:

// 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",
    ],
}

Nếu một mô-đun nhà cung cấp phụ thuộc vào các tiện ích VNDK, thì những tiện ích VNDK đó sẽ tự động được cài đặt vào /vendor/lib[64]/vndk[-sp]. Nếu một mô-đun không còn phụ thuộc vào một tiện ích VNDK, hãy thêm một bước dọn dẹp vào CleanSpec.mk để xoá thư viện dùng chung. Ví dụ:

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

Biên dịch có điều kiện

Phần này mô tả cách xử lý sự khác biệt nhỏ (ví dụ: thêm hoặc xoá một tính năng khỏi một trong các biến thể) giữa 3 thư viện dùng chung VNDK sau đây:

  • Biến thể cốt lõi (ví dụ: /system/lib[64]/libexample.so)
  • Biến thể của nhà cung cấp (ví dụ: /apex/com.android.vndk.v${VER}/lib[64]/libexample.so)
  • Tiện ích VNDK (ví dụ: /vendor/lib[64]/vndk[-sp]/libexample.so)

Cờ trình biên dịch có điều kiện

Hệ thống xây dựng Android xác định __ANDROID_VNDK__ cho các biến thể của nhà cung cấp và các tiện ích VNDK theo mặc định. Bạn có thể bảo vệ mã bằng các lệnh bảo vệ của trình tiền xử lý C:

void all() { }

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

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

Ngoài __ANDROID_VNDK__, bạn có thể chỉ định cflags hoặc cppflags khác trong Android.bp. cflags hoặc cppflags được chỉ định trong target.vendor dành riêng cho biến thể của nhà cung cấp.

Ví dụ: Android.bp sau đây xác định libexamplelibexample_ext:

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",
    ],
}

Và đây là danh sách mã của src/example.c:

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

Theo hai tệp này, hệ thống xây dựng sẽ tạo ra các thư viện dùng chung có các biểu tượng được xuất sau đây:

Đường dẫn cài đặt Ký hiệu đã xuất
/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

Yêu cầu đối với các biểu tượng được xuất

Trình kiểm tra ABI VNDK so sánh ABI của các biến thể nhà cung cấp VNDKcác tiện ích VNDK với các kết xuất ABI tham chiếu trong prebuilts/abi-dumps/vndk.

  • Các biểu tượng do các biến thể nhà cung cấp VNDK xuất (ví dụ: /apex/com.android.vndk.v${VER}/lib[64]/libexample.so) phải giống hệt (không phải là siêu tập hợp của) các biểu tượng được xác định trong các kết xuất ABI.
  • Các biểu tượng do tiện ích VNDK xuất (ví dụ: /vendor/lib[64]/vndk/libexample.so) phải là tập hợp siêu của các biểu tượng được xác định trong các tệp kết xuất ABI.

Nếu các biến thể nhà cung cấp VNDK hoặc các tiện ích VNDK không tuân thủ các yêu cầu nêu trên, thì trình kiểm tra ABI VNDK sẽ phát ra lỗi bản dựng và dừng bản dựng.

Loại trừ các tệp nguồn hoặc thư viện dùng chung khỏi các biến thể của nhà cung cấp

Để loại trừ các tệp nguồn khỏi biến thể của nhà cung cấp, hãy thêm các tệp đó vào thuộc tính exclude_srcs. Tương tự, để đảm bảo các thư viện dùng chung không được liên kết với biến thể của nhà cung cấp, hãy thêm các thư viện đó vào thuộc tính exclude_shared_libs. Ví dụ:

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"],
        },
    },
}

Trong ví dụ này, biến thể cốt lõi của libexample_cond_exclude bao gồm mã từ fwk.cboth.c, đồng thời phụ thuộc vào các thư viện dùng chung libfwk_onlylibboth. Biến thể nhà cung cấp của libexample_cond_exclude chỉ bao gồm mã từ both.cfwk.c bị loại trừ theo thuộc tính exclude_srcs. Tương tự, nó chỉ phụ thuộc vào thư viện dùng chung libbothlibfwk_only bị loại trừ theo thuộc tính exclude_shared_libs.

Xuất tiêu đề từ các tiện ích VNDK

Một tiện ích VNDK có thể thêm các lớp mới hoặc hàm mới vào thư viện dùng chung VNDK. Bạn nên giữ những khai báo đó trong các tiêu đề độc lập và tránh thay đổi các tiêu đề hiện có.

Ví dụ: một tệp tiêu đề mới include-ext/example/ext/feature_name.h được tạo cho tiện ích VNDK libexample_ext:

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

Trong Android.bp sau đây, libexample chỉ xuất include, trong khi libexample_ext xuất cả includeinclude-ext. Điều này đảm bảo rằng feature_name.h sẽ không bị người dùng libexample đưa vào một cách không chính xác:

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",
    },
}

Nếu không thể tách các tiện ích thành các tệp tiêu đề độc lập, thì bạn có thể thêm các lệnh bảo vệ #ifdef. Tuy nhiên, hãy đảm bảo rằng tất cả người dùng tiện ích VNDK đều thêm cờ xác định. Bạn có thể xác định cc_defaults để thêm cờ xác định vào cflags và liên kết các thư viện dùng chung với shared_libs.

Ví dụ: để thêm một hàm thành viên mới Example2::get_b() vào tiện ích VNDK libexample2_ext, bạn phải sửa đổi tệp tiêu đề hiện có và thêm một lệnh bảo vệ #ifdef:

#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_

Một cc_defaults có tên là libexample2_ext_defaults được xác định cho người dùng libexample2_ext:

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",
    ],
}

Người dùng libexample2_ext chỉ cần thêm libexample2_ext_defaults vào thuộc tính defaults của họ:

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

Gói sản phẩm

Trong hệ thống xây dựng Android, biến PRODUCT_PACKAGES chỉ định các tệp thực thi, thư viện dùng chung hoặc gói cần được cài đặt vào thiết bị. Các phần phụ thuộc bắc cầu của những mô-đun được chỉ định cũng sẽ được cài đặt ngầm vào thiết bị.

Nếu BOARD_VNDK_VERSION được bật, các mô-đun có vendor_available hoặc vndk.enabled sẽ được xử lý đặc biệt. Nếu một mô-đun khung phụ thuộc vào một mô-đun có vendor_available hoặc vndk.enabled, thì biến thể cốt lõi sẽ được đưa vào bộ cài đặt bắc cầu. Nếu một mô-đun nhà cung cấp phụ thuộc vào một mô-đun có vendor_available, thì biến thể nhà cung cấp sẽ được đưa vào bộ cài đặt bắc cầu. Tuy nhiên, các biến thể của nhà cung cấp trong các mô-đun có vndk.enabled sẽ được cài đặt bất kể chúng có được các mô-đun của nhà cung cấp sử dụng hay không.

Khi các phần phụ thuộc không hiển thị cho hệ thống bản dựng (ví dụ: các thư viện dùng chung có thể được mở bằng dlopen() trong thời gian chạy), bạn nên chỉ định tên mô-đun trong PRODUCT_PACKAGES để cài đặt rõ ràng các mô-đun đó.

Nếu một mô-đun có vendor_available hoặc vndk.enabled, thì tên mô-đun sẽ là biến thể cốt lõi của mô-đun đó. Để chỉ định rõ ràng biến thể của nhà cung cấp trong PRODUCT_PACKAGES, hãy thêm hậu tố .vendor vào tên mô-đun. Ví dụ:

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

Trong ví dụ này, libexample/system/lib[64]/libexample.solibexample.vendor/vendor/lib[64]/libexample.so. Để cài đặt /vendor/lib[64]/libexample.so, hãy thêm libexample.vendor vào PRODUCT_PACKAGES:

PRODUCT_PACKAGES += libexample.vendor