RenderScript

RenderScript là một khung để chạy các tác vụ tính toán chuyên sâu với hiệu suất cao trên Android. RenderScript được thiết kế để sử dụng với tính năng tính toán song song dữ liệu (data-parallel computation), dùng vậy khối lượng công việc nối tiếp (serial workloads) cũng có thể hưởng lợi. Môi trường thời gian chạy RenderScript tải song song công việc trên các bộ xử lý hiện có trên thiết bị, chẳng hạn như GPU và CPU đa nhân, cho phép nhà phát triển tập trung vào việc thể hiện thuật toán thay vì lên lịch công việc. RenderScript đặc biệt hữu ích cho các ứng dụng xử lý hình ảnh, nhiếp ảnh điện toán hoặc thị giác máy tính.

Các thiết bị chạy Android 8.0 trở lên sử dụng khung RenderScript và HAL của nhà cung cấp sau đây:

Hình 1. Mã nhà cung cấp liên kết đến các thư viện nội bộ.

Sau đây là những điểm khác biệt so với RenderScript trong Android 7.x trở xuống:

  • Hai thực thể của lib nội bộ RenderScript trong một quy trình. Một tập hợp là dành cho đường dẫn dự phòng của CPU và bắt đầu từ /system/lib; tập hợp còn lại là dành cho đường dẫn GPU và bắt đầu từ /system/lib/vndk-sp.
  • Các thư viện nội bộ RS trong /system/lib được tạo trong nền tảng và được cập nhật khi system.img được nâng cấp. Tuy nhiên, lib trong /system/lib/vndk-sp được tạo cho nhà cung cấp và không được cập nhật khi system.img được nâng cấp (mặc dù có thể cập nhật để sửa lỗi bảo mật, nhưng ABI của các thư viện này vẫn giữ nguyên).
  • Mã của nhà cung cấp (RS HAL, trình điều khiển RS và bcc plugin) được liên kết với các thư viện nội bộ RenderScript nằm tại /system/lib/vndk-sp. Các thư viện này không thể liên kết với các thư viện trong /system/lib vì các thư viện trong thư mục đó được tạo cho nền tảng và do đó có thể không tương thích với mã của nhà cung cấp (tức là các biểu tượng có thể bị xoá). Nếu làm như vậy, bạn sẽ không thể thực hiện OTA chỉ dành cho khung.

Thiết kế

Các phần sau đây trình bày chi tiết về thiết kế RenderScript trong Android 8.0 trở lên.

Các thư viện RenderScript dành cho nhà cung cấp

Phần này liệt kê các thư viện RenderScript (còn gọi là NDK của nhà cung cấp cho HAL cùng quy trình hoặc VNDK-SP) có sẵn cho mã của nhà cung cấp và có thể được liên kết. Tài liệu này cũng trình bày chi tiết các thư viện bổ sung không liên quan đến RenderScript nhưng cũng được cung cấp cho mã của nhà cung cấp.

Mặc dù danh sách thư viện sau đây có thể khác nhau giữa các bản phát hành Android, nhưng không thể thay đổi cho một bản phát hành Android cụ thể. Để xem danh sách cập nhật các thư viện có sẵn, hãy tham khảo /system/etc/ld.config.txt.

Lib RenderScript Lib không phải RenderScript
  • android.hardware.graphics.renderscript@1.0.so
  • libRS_internal.so
  • libRSCpuRef.so
  • libblas.so
  • libbcinfo.so
  • libcompiler_rt.so
  • libRSDriver.so
  • libc.so
  • libm.so
  • libdl.so
  • libstdc++.so
  • liblog.so
  • libnativewindow.so
  • libsync.so
  • libvndksupport.so
  • libbase.so
  • libc++.so
  • libcutils.so
  • libutils.so
  • libhardware.so
  • libhidlbase.so
  • libhidltransport.so
  • libhwbinder.so
  • liblzma.so
  • libz.so
  • libEGL.so
  • libGLESv1_CM.so
  • libGLESv2.so

Cấu hình không gian tên của trình liên kết

Hạn chế liên kết ngăn mã nhà cung cấp sử dụng các thư viện không có trong VNDK-SP được thực thi trong thời gian chạy bằng cách sử dụng không gian tên trình liên kết. (Để biết thông tin chi tiết, hãy tham khảo bản trình bày Thiết kế VNDK.)

Trên thiết bị chạy Android 8.0 trở lên, tất cả HAL cùng quy trình (SP-HAL) ngoại trừ RenderScript đều được tải bên trong không gian tên trình liên kết sphal. RenderScript được tải vào không gian tên dành riêng cho RenderScript rs, một vị trí cho phép thực thi hơi lỏng lẻo hơn cho các thư viện RenderScript. Vì quá trình triển khai RS cần tải mã bit đã biên dịch, nên /data/*/*.so sẽ được thêm vào đường dẫn của không gian tên rs (các SP-HAL khác không được phép tải lib từ phân vùng dữ liệu).

Ngoài ra, không gian tên rs cho phép nhiều thư viện hơn so với các không gian tên khác. libmediandk.solibft2.so hiển thị với không gian tên rslibRS_internal.so có phần phụ thuộc nội bộ với các thư viện này.

Hình 2. Cấu hình không gian tên cho trình liên kết.

Tải trình điều khiển

Đường dẫn dự phòng của CPU

Tuỳ thuộc vào sự tồn tại của bit RS_CONTEXT_LOW_LATENCY khi tạo ngữ cảnh RS, đường dẫn CPU hoặc GPU sẽ được chọn. Khi đường dẫn CPU được chọn, libRS_internal.so (phương thức triển khai chính của khung RS) sẽ được dlopen trực tiếp từ không gian tên trình liên kết mặc định, nơi cung cấp phiên bản nền tảng của thư viện RS.

Việc triển khai RS HAL của nhà cung cấp hoàn toàn không được sử dụng khi CPU sử dụng đường dẫn dự phòng và đối tượng RsContext được tạo bằng mVendorDriverName rỗng. libRSDriver.so được dlopen (theo mặc định) và thư viện trình điều khiển được tải từ không gian tên default vì phương thức gọi (libRS_internal.so) cũng được tải trong không gian tên default.

Hình 3. Đường dẫn dự phòng của CPU.

Đường dẫn GPU

Đối với đường dẫn GPU, libRS_internal.so được tải theo cách khác. Trước tiên, libRS.so sử dụng android.hardware.renderscript@1.0.so (và libhidltransport.so cơ bản của nó) để tải android.hardware.renderscript@1.0-impl.so (một cách triển khai RS HAL của nhà cung cấp) vào một không gian tên trình liên kết khác có tên là sphal. Sau đó, HAL RS sẽ dlopen libRS_internal.so trong một không gian tên trình liên kết khác có tên là rs.

Nhà cung cấp có thể cung cấp trình điều khiển RS của riêng họ bằng cách đặt cờ thời gian xây dựng OVERRIDE_RS_DRIVER, được nhúng vào quá trình triển khai HAL RS (hardware/interfaces/renderscript/1.0/default/Context.cpp). Sau đó, tên trình điều khiển này được dlopen cho ngữ cảnh RS cho đường dẫn GPU.

Việc tạo đối tượng RsContext được uỷ quyền cho quá trình triển khai HAL RS. HAL gọi lại khung RS bằng cách sử dụng hàm rsContextCreateVendor() với tên của trình điều khiển để dùng làm đối số. Sau đó, khung RS sẽ tải trình điều khiển đã chỉ định khi khởi tạo RsContext. Trong trường hợp này, thư viện trình điều khiển sẽ được tải vào không gian tên rs, vì đối tượng RsContext được tạo bên trong không gian tên rs/vendor/lib nằm trong đường dẫn tìm kiếm của không gian tên.

Hình 4. Đường dẫn dự phòng GPU.

Khi chuyển đổi từ không gian tên default sang không gian tên sphal, libhidltransport.so sử dụng hàm android_load_sphal_library() để yêu cầu rõ ràng trình liên kết động tải thư viện -impl.so từ không gian tên sphal.

Khi chuyển đổi từ không gian tên sphal sang không gian tên rs, quá trình tải sẽ được thực hiện gián tiếp bằng dòng sau trong /system/etc/ld.config.txt:

namespace.sphal.link.rs.shared_libs = libRS_internal.so

Dòng này chỉ định trình liên kết động sẽ tải libRS_internal.so từ không gian tên rs khi không tìm thấy/tải thư viện từ không gian tên sphal (luôn là trường hợp này vì không gian tên sphal không tìm kiếm /system/lib/vndk-sp nơi libRS_internal.so nằm). Với cấu hình này, một lệnh gọi dlopen() đơn giản đến libRS_internal.so là đủ để thực hiện quá trình chuyển đổi không gian tên.

Tải trình bổ trợ bcc

bcc plugin là thư viện do nhà cung cấp cung cấp được tải vào trình biên dịch bcc. Vì bcc là một quy trình hệ thống trong thư mục /system/bin, nên thư viện bcc plugin có thể được coi là SP-HAL (tức là HAL của nhà cung cấp có thể được tải trực tiếp vào quy trình hệ thống mà không cần liên kết). Là một SP-HAL, thư viện bcc-plugin:

  • Không thể liên kết với các thư viện chỉ dành cho khung như libLLVM.so.
  • Chỉ có thể liên kết với các thư viện VNDK-SP mà nhà cung cấp có.

Quy định hạn chế này được thực thi bằng cách tải bcc plugin vào không gian tên sphal thông qua hàm android_sphal_load_library(). Trong các phiên bản Android trước, tên trình bổ trợ được chỉ định bằng tuỳ chọn -load và thư viện được tải bằng dlopen() đơn giản của libLLVM.so. Trong Android 8.0 trở lên, điều này được chỉ định trong tuỳ chọn -plugin và lib được tải trực tiếp bởi chính bcc. Tuỳ chọn này cho phép một đường dẫn không dành riêng cho Android đến dự án LLVM nguồn mở.

Hình 5. Đang tải trình bổ trợ bcc, Android 7.x trở xuống.



Hình 6. Tải trình bổ trợ bcc, Android 8.0 trở lên.

Đường dẫn tìm kiếm cho ld.mc

Khi thực thi ld.mc, một số thư viện thời gian chạy RS được cung cấp dưới dạng dữ liệu đầu vào cho trình liên kết. Mã bit RS từ ứng dụng được liên kết với các thư viện thời gian chạy và khi mã bit đã chuyển đổi được tải vào một quy trình ứng dụng, các thư viện thời gian chạy lại được liên kết động từ mã bit đã chuyển đổi.

Các thư viện thời gian chạy bao gồm:

  • libcompiler_rt.so
  • libm.so
  • libc.so
  • Trình điều khiển RS (libRSDriver.so hoặc OVERRIDE_RS_DRIVER)

Khi tải mã bit đã biên dịch vào quy trình ứng dụng, hãy cung cấp chính xác thư viện mà ld.mc đã sử dụng. Nếu không, mã bit đã biên dịch có thể không tìm thấy một biểu tượng có sẵn khi được liên kết.

Để làm như vậy, khung RS sử dụng các đường dẫn tìm kiếm khác nhau cho các thư viện thời gian chạy khi thực thi ld.mc, tuỳ thuộc vào việc khung RS có được tải từ /system/lib hay từ /system/lib/vndk-sp. Bạn có thể xác định điều này bằng cách đọc địa chỉ của một ký hiệu tuỳ ý của thư viện khung RS và sử dụng dladdr() để liên kết đường dẫn tệp với địa chỉ đó.

Chính sách SELinux

Do các thay đổi về chính sách SELinux trong Android 8.0 trở lên, bạn phải tuân theo các quy tắc cụ thể (được thực thi thông qua neverallows) khi gắn nhãn các tệp bổ sung trong phân vùng vendor:

  • vendor_file phải là nhãn mặc định cho tất cả tệp trong phân vùng vendor. Chính sách nền tảng yêu cầu điều này để truy cập vào các phương thức triển khai HAL truyền qua.
  • Tất cả exec_types mới được thêm vào phân vùng vendor thông qua SEPolicy của nhà cung cấp phải có thuộc tính vendor_file_type. Việc này được thực thi thông qua neverallows.
  • Để tránh xung đột với các bản cập nhật nền tảng/khung trong tương lai, hãy tránh gắn nhãn cho các tệp không phải là exec_types trong phân vùng vendor.
  • Tất cả phần phụ thuộc thư viện cho các HAL cùng quy trình do AOSP xác định phải được gắn nhãn là same_process_hal_file.

Để biết thông tin chi tiết về chính sách SELinux, hãy xem bài viết Security-Enhanced Linux trong Android.

Khả năng tương thích ABI cho mã bit

Nếu bạn không thêm API mới nào, tức là không tăng phiên bản HAL, khung RS sẽ tiếp tục sử dụng trình điều khiển GPU (HAL 1.0) hiện có.

Đối với các thay đổi nhỏ về HAL (HAL 1.1) không ảnh hưởng đến mã bit, các khung này nên sử dụng lại CPU cho các API mới thêm này và tiếp tục sử dụng trình điều khiển GPU (HAL 1.0) ở nơi khác.

Đối với các thay đổi lớn về HAL (HAL 2.0) ảnh hưởng đến việc biên dịch/liên kết mã bit, khung RS nên chọn không tải trình điều khiển GPU do nhà cung cấp cung cấp mà thay vào đó sử dụng CPU hoặc đường dẫn Vulkan để tăng tốc.

Quá trình sử dụng mã bit RenderScript diễn ra theo 3 giai đoạn:

Giai đoạn Thông tin chi tiết
Biên dịch
  • Mã bit đầu vào (.bc) cho bcc phải ở định dạng mã bit LLVM 3.2bcc phải có khả năng tương thích ngược với các ứng dụng (cũ) hiện có.
  • Tuy nhiên, siêu dữ liệu trong .bc có thể thay đổi (có thể có các hàm thời gian chạy mới, ví dụ: Hàm setter và getter phân bổ, hàm toán học, v.v.). Một phần của các hàm thời gian chạy nằm trong libclcore.bc, một phần nằm trong LibRSDriver hoặc tương đương với nhà cung cấp.
  • Các hàm thời gian chạy mới hoặc thay đổi siêu dữ liệu vi phạm yêu cầu tăng cấp độ API mã bit. Vì trình điều khiển của nhà cung cấp sẽ không thể sử dụng phiên bản này, nên phiên bản HAL cũng phải được tăng lên.
  • Nhà cung cấp có thể có trình biên dịch riêng, nhưng các kết luận/yêu cầu đối với bcc cũng áp dụng cho các trình biên dịch đó.
Đường liên kết
  • Miền .o đã biên dịch sẽ được liên kết với trình điều khiển của nhà cung cấp, ví dụ: libRSDriver_foo.solibcompiler_rt.so. Đường dẫn CPU sẽ liên kết với libRSDriver.so.
  • Nếu .o yêu cầu một API thời gian chạy mới từ libRSDriver_foo, bạn phải cập nhật trình điều khiển của nhà cung cấp để hỗ trợ API đó.
  • Một số nhà cung cấp có thể có trình liên kết riêng, nhưng đối số cho ld.mc cũng áp dụng cho các nhà cung cấp đó.
Tải
  • libRSCpuRef tải đối tượng dùng chung. Nếu giao diện này có thay đổi, bạn cần phải nâng cấp phiên bản HAL.
  • Nhà cung cấp sẽ dựa vào libRSCpuRef để tải đối tượng chia sẻ hoặc triển khai đối tượng của riêng họ.

Ngoài HAL, API thời gian chạy và những biểu tượng được xuất cũng là giao diện. Không có giao diện nào thay đổi kể từ Android 7.0 (API 24) và hiện vẫn chưa có kế hoạch thay đổi giao diện này trong Android 8.0 trở lên. Tuy nhiên, nếu giao diện thay đổi, phiên bản HAL cũng sẽ tăng lên.

Triển khai của nhà cung cấp

Android 8.0 trở lên yêu cầu một số thay đổi về trình điều khiển GPU để trình điều khiển GPU hoạt động chính xác.

Mô-đun trình điều khiển

  • Mô-đun trình điều khiển không được phụ thuộc vào bất kỳ thư viện hệ thống nào không có trong danh sách.
  • Trình điều khiển phải cung cấp android.hardware.renderscript@1.0-impl_{NAME} riêng hoặc khai báo phương thức triển khai mặc định android.hardware.renderscript@1.0-impl làm phần phụ thuộc.
  • Việc triển khai CPU libRSDriver.so là một ví dụ hay về cách xoá các phần phụ thuộc không phải VNDK-SP.

Trình biên dịch mã bit

Bạn có thể biên dịch mã bit RenderScript cho trình điều khiển của nhà cung cấp theo hai cách:

  1. Gọi trình biên dịch RenderScript dành riêng cho nhà cung cấp trong /vendor/bin/ (phương thức biên dịch GPU được ưu tiên). Tương tự như các mô-đun trình điều khiển khác, tệp nhị phân trình biên dịch của nhà cung cấp không được phụ thuộc vào bất kỳ thư viện hệ thống nào không có trong danh sách các thư viện RenderScript mà nhà cung cấp có thể sử dụng.
  2. Gọi hệ thống bcc: /system/bin/bcc bằng bcc plugin do nhà cung cấp cung cấp; trình bổ trợ này không được phụ thuộc vào bất kỳ thư viện hệ thống nào không có trong danh sách các thư viện RenderScript có sẵn cho nhà cung cấp.

Nếu nhà cung cấp bcc plugin cần can thiệp vào quá trình biên dịch CPU và phần phụ thuộc của nó trên libLLVM.so không thể dễ dàng xoá được, thì nhà cung cấp phải sao chép bcc (và tất cả các phần phụ thuộc không phải LL-NDK, bao gồm cả libLLVM.so, libbcc.so) vào phân vùng /vendor.

Ngoài ra, nhà cung cấp cần thực hiện những thay đổi sau:

Hình 7. Thay đổi đối với trình điều khiển của nhà cung cấp.

  1. Sao chép libclcore.bc vào phân vùng /vendor. Điều này đảm bảo libclcore.bc, libLLVM.solibbcc.so đồng bộ hoá.
  2. Thay đổi đường dẫn đến tệp thực thi bcc bằng cách đặt RsdCpuScriptImpl::BCC_EXE_PATH từ quá trình triển khai RS HAL.

Chính sách SELinux

Chính sách SELinux ảnh hưởng đến cả các tệp thực thi của trình điều khiển và trình biên dịch. Tất cả các mô-đun trình điều khiển phải được gắn nhãn same_process_hal_file trong file_contexts của thiết bị. Ví dụ:

/vendor/lib(64)?/libRSDriver_EXAMPLE\.so     u:object_r:same_process_hal_file:s0

Trình biên dịch có thể thực thi phải có thể được một quy trình ứng dụng gọi, cũng như bản sao bcc của nhà cung cấp (/vendor/bin/bcc). Ví dụ:

device/vendor_foo/device_bar/sepolicy/file_contexts:
/vendor/bin/bcc                    u:object_r:same_process_hal_file:s0

Thiết bị cũ

Thiết bị cũ là những thiết bị đáp ứng các điều kiện sau:

  1. PRODUCT_shippingPING_API_LEVEL thấp hơn 26.
  2. PRODUCT_FULL_TREBLE_OVERRIDE chưa được xác định.

Đối với các thiết bị cũ, các quy định hạn chế này sẽ không được thực thi khi nâng cấp lên Android 8.0 trở lên, nghĩa là trình điều khiển có thể tiếp tục liên kết với các thư viện trong /system/lib[64]. Tuy nhiên, do thay đổi về cấu trúc liên quan đến OVERRIDE_RS_DRIVER, bạn phải cài đặt android.hardware.renderscript@1.0-impl vào phân vùng /vendor; nếu không, thời gian chạy RenderScript sẽ buộc phải quay lại đường dẫn CPU.

Để biết thông tin về lý do ngừng sử dụng Renderscript, hãy xem Blog dành cho nhà phát triển Android: Tính năng điện toán GPU của Android trong tương lai. Thông tin tài nguyên về việc ngừng sử dụng này bao gồm: