RenderScript

RenderScript là một framework để 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. Nó được thiết kế để sử dụng với tính toán song song dữ liệu, mặc dù khối lượng công việc nối tiếp cũng có thể được hưởng lợi. Thời gian chạy RenderScript song song hóa công việc trên các bộ xử lý có sẵn trên thiết bị, chẳng hạn như CPU ​​và GPU đa lõi, cho phép các nhà phát triển tập trung vào việc thể hiện các thuật toán thay vì lên lịch làm việc. RenderScript đặc biệt hữu ích cho các ứng dụng thực hiện xử lý hình ảnh, chụp ảnh tính 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:

Hình 1. Mã nhà cung cấp liên kết với lib nội bộ

Sự khác biệt so với RenderScript trong Android 7.x trở xuống bao gồm:

  • Hai phiên bản lib nội bộ của RenderScript trong một quy trình. Một bộ dành cho đường dẫn dự phòng CPU và được lấy trực tiếp tại /system/lib ; bộ còn lại dành cho đường dẫn GPU và từ /system/lib/vndk-sp .
  • Các lib nội bộ RS trong /system/lib được xây dựng như một phần của 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 xây dựng cho nhà cung cấp và không được cập nhật khi nâng cấp system.img (mặc dù chúng có thể được cập nhật để sửa lỗi bảo mật nhưng ABI của chúng vẫn giữ nguyên).
  • Mã 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 lib nội bộ của RenderScript có tại /system/lib/vndk-sp . Chúng không thể liên kết với các lib trong /system/lib vì các lib trong thư mục đó được xây dựng cho nền tảng và do đó có thể không tương thích với mã nhà cung cấp (tức là các ký hiệu có thể bị xóa). Làm như vậy sẽ khiến OTA chỉ có khung không thể thực hiện được.

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.

Thư viện RenderScript có sẵn cho nhà cung cấp

Phần này liệt kê các thư viện RenderScript (được gọi là NDK của nhà cung cấp cho HAL cùng quy trình hoặc VNĐK-SP) có sẵn cho mã nhà cung cấp và có thể được liên kết với. Nó cũng nêu 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ã 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 nó không thể thay đổi đối với một bản phát hành Android cụ thể; để biết 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 .

Thư viện RenderScript Thư viện 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 nhằm ngăn chặn các lib không có trong VNĐK-SP được mã nhà cung cấp sử dụng đượ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êm chi tiết, tham khảo phần trình bày của VNDK Design .)

Trên thiết bị chạy Android 8.0 trở lên, tất cả cá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 của 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 lỏng lẻo hơn một chút đối với các thư viện RenderScript. Vì việc triển khai RS cần tải mã bit đã biên dịch nên /data/*/*.so đượ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 lib hơn so với các không gian tên khác. libmediandk.solibft2.so được hiển thị trong không gian rslibRS_internal.so có phần phụ thuộc nội bộ vào 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

Đang tải trình điều khiển

Đường dẫn dự phòng CPU

Tùy thuộc vào sự tồn tại của bit RS_CONTEXT_LOW_LATENCY khi tạo bối 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 (triển khai chính của khung RS) sẽ được dlopen trực tiếp khỏi 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 lib lib.

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

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

Đường dẫn GPU

Đối với đường dẫn GPU, libRS_internal.so được tải khác nhau. Đầu 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 nhà cung cấp triển khai RS HAL) vào một không gian tên trình liên kết khác được gọi là sphal . RS HAL sau đó dlopen s libRS_internal.so trong một không gian tên trình liên kết khác có tên rs .

Các 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 RS HAL ( hardware/interfaces/renderscript/1.0/default/Context.cpp ). Tên trình điều khiển này sau đó dlopen sửa cho bối cảnh RS cho đường dẫn GPU.

Việc tạo đối tượng RsContext được ủy quyền cho việc triển khai RS HAL. 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 để sử dụng làm đối số. Sau đó, khung RS sẽ tải trình điều khiển được chỉ định khi RsContext được khởi tạo. Trong trường hợp này, thư viện trình điều khiển được tải vào không gian 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 5. Đường dẫn dự phòng GPU

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

Khi chuyển từ không gian tên sphal sang không gian rs , việc tải đượ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 thể tìm thấy/tải lib từ không gian tên sphal (điều này luôn xảy ra vì không gian tên sphal không tìm kiếm /system/lib/vndk-sp ở đâu libRS_internal.so cư trú). Với cấu hình này, một lệnh gọi dlopen() đơn giản tới libRS_internal.so là đủ để thực hiện chuyển đổi không gian tên.

Đang tải plugin 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 bị ràng buộc). Là SP-HAL, thư viện bcc-plugin :

  • Không thể liên kết với các thư viện chỉ có khung như libLLVM.so .
  • Chỉ có thể liên kết với các thư viện VNĐK-SP có sẵn của nhà cung cấp.

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 bằng hàm android_sphal_load_library() . Trong các phiên bản trước của Android, tên plugin đã được chỉ định bằng tùy chọn -load và lib được tải bằng cách sử dụng dlopen() đơn giản bởi libLLVM.so . Trong Android 8.0 trở lên, điều này được chỉ định trong tùy chọn -plugin và lib được chính bcc tải trực tiếp. Tùy chọn này cho phép đường dẫn không dành riêng cho Android tới dự án LLVM nguồn mở.

Hình 6. Đang tải plugin bcc, Android 7.x trở xuống


Hình 7. Đang tải plugin 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ố lib thời gian chạy RS được cung cấp làm đầ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 lib 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 lib thời gian chạy lại được liên kết động từ mã bit đã chuyển đổi.

Các lib 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 bitcode đã biên dịch vào quy trình ứng dụng, hãy cung cấp chính xác thư viện đã được ld.mc sử dụng. Nếu không, bitcode đã biên dịch có thể không tìm thấy ký hiệu 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 lib thời gian chạy khi thực thi ld.mc , tùy thuộc vào việc bản thân khung RS được tải từ /system/lib hay từ /system/lib/vndk-sp . Điều này có thể được xác định bằng cách đọc địa chỉ của một ký hiệu tùy ý của lib khung RS và sử dụng dladdr() để ánh xạ đường dẫn tệp tới địa chỉ.

Chính sách SELinux

Do những 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ả cá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 việc triển khai HAL chuyển tiếp.
  • 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 . Điều 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 các tệp khác ngoài exec_types trong phân vùng vendor .
  • Tất cả các phần phụ thuộc thư viện cho cùng một quy trình HAL được AOSP xác định phải được gắn nhãn là same_process_hal_file .

Để biết chi tiết về chính sách SELinux, hãy xem Linux được tăng cường bảo mật trong Android .

Khả năng tương thích ABI cho bitcode

Nếu không có API mới nào được thêm vào, nghĩa là không có phiên bản HAL nào, thì 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 những thay đổi HAL nhỏ (HAL 1.1) không ảnh hưởng đến bitcode, các khung sẽ chuyển sang CPU cho các API mới được 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 những thay đổi lớn về HAL (HAL 2.0) ảnh hưởng đến quá trình 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 và thay vào đó sử dụng đường dẫn CPU hoặc Vulkan để tăng tốc.

Việc sử dụng mã bit RenderScript xảy ra theo ba giai đoạn:

Sân khấu 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 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ụ: Trình thiết lập phân bổ ∓ getters, 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 trong số chúng nằm trong LibRSDriver hoặc tương đương với nhà cung cấp.
  • Các chức năng thời gian chạy mới hoặc phá vỡ các thay đổi siêu dữ liệu yêu cầu tăng cấp độ API bitcode. Vì trình điều khiển của nhà cung cấp sẽ không thể sử dụng nó 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 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 đó.
liên kết
  • Tệp .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 API thời gian chạy mới từ libRSDriver_foo thì trình điều khiển của nhà cung cấp phải được cập nhật để hỗ trợ API đó.
  • Một số nhà cung cấp nhất định có thể có trình liên kết của riêng họ, nhưng lập luận về ld.mc cũng áp dụng cho họ.
Trọng tải
  • libRSCpuRef tải đối tượng được chia sẻ. Nếu có những thay đổi đối với giao diện này thì cần có phiên bản HAL.
  • Các nhà cung cấp sẽ dựa vào libRSCpuRef để tải đối tượng được chia sẻ hoặc triển khai đối tượng của riêng họ.

Ngoài HAL, các API thời gian chạy và các ký hiệu được xuất cũng là các giao diện. Cả hai giao diện đều không thay đổi kể từ Android 7.0 (API 24) và hiện chưa có kế hoạch thay đổi giao diện đó trong Android 8.0 trở lên. Tuy nhiên, nếu giao diện thay đổi thì 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 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

  • Các 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} của chính nó hoặc khai báo cách triển khai mặc định android.hardware.renderscript@1.0-impl làm phần phụ thuộc của nó.
  • Việc triển khai CPU libRSDriver.so là một ví dụ điển hình về cách loại bỏ các phần phụ thuộc không phải VNĐK-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 pháp biên dịch GPU ưa thích). Tương tự như các mô-đun trình điều khiển khác, tệp nhị phân của trình biên dịch của nhà cung cấp không thể 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 các nhà cung cấp .
  2. Gọi bcc hệ thống: /system/bin/bcc bằng bcc plugin do nhà cung cấp cung cấp ; plugin này không thể phụ thuộc vào bất kỳ thư viện hệ thống nào không có trong danh sách lib RenderScript có sẵn cho nhà cung cấp .

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

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

Hình 8. Thay đổ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 được đồng bộ hóa.
  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ả trình điều khiển và trình thực thi của 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 thực thi trình biên dịch phải có khả năng được gọi bởi một quy trình ứng dụng, 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à thiết bị thỏa mãn các điều kiện sau:

  1. product_SHIPPING_API_LEVEL thấp hơn 26.
  2. product_FULL_TREBLE_OVERRIDE không được xác định.

Đối với các thiết bị cũ, các hạn chế 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 kiến ​​trúc liên quan đến OVERRIDE_RS_DRIVER , android.hardware.renderscript@1.0-impl phải được cài đặt vào phân vùng /vendor ; không làm như vậy buộc phải chuyển thời gian chạy RenderScript sang đườ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: Hướng tới tính toán GPU của Android . Thông tin tài nguyên cho việc ngừng sử dụng này bao gồm: