Android berisi Lapisan Abstraksi Hardware (HAL) HIDL otomotif yang menyediakan pengambilan dan tampilan gambar sangat awal dalam proses booting Android dan terus berfungsi selama masa aktif sistem. HAL mencakup stack sistem tampilan eksterior (EVS) dan biasanya digunakan untuk mendukung kamera belakang dan tampilan surround view di kendaraan dengan sistem In-Vehicle Infotainment (IVI) berbasis Android. EVS juga memungkinkan fitur lanjutan diimplementasikan di aplikasi pengguna.
Android juga menyertakan antarmuka driver pengambilan dan tampilan khusus EVS (di /hardware/interfaces/automotive/evs/1.0
). Meskipun aplikasi kamera tampilan belakang dapat dibuat di atas layanan kamera dan tampilan Android yang ada, aplikasi tersebut kemungkinan akan berjalan terlalu lambat dalam proses booting Android. Penggunaan HAL khusus memungkinkan antarmuka yang disederhanakan
dan memperjelas apa yang perlu diterapkan OEM untuk mendukung stack EVS.
Komponen sistem
EVS mencakup komponen sistem berikut:

Gambar 1. Ringkasan komponen sistem EVS.
Aplikasi EVS
Aplikasi EVS C++ contoh
(/packages/services/Car/evs/app
) berfungsi sebagai implementasi
referensi. Aplikasi ini bertanggung jawab untuk meminta frame video dari EVS Manager dan mengirimkan frame yang telah selesai untuk ditampilkan kembali ke EVS Manager.
Layanan ini diharapkan dimulai oleh init segera setelah EVS dan Layanan Mobil tersedia,
ditargetkan dalam waktu dua (2) detik setelah dinyalakan. OEM dapat mengubah atau mengganti aplikasi EVS sesuai keinginan.
EVS Manager
EVS Manager (/packages/services/Car/evs/manager
) menyediakan
blok penyusun yang diperlukan oleh aplikasi EVS untuk menerapkan apa pun mulai dari
tampilan kamera belakang sederhana hingga rendering multi-kamera 6DOF. Antarmukanya
disajikan melalui HIDL dan dibuat untuk menerima beberapa klien serentak.
Aplikasi dan layanan lain (khususnya Layanan Mobil) dapat mengkueri status Pengelola EVS untuk mengetahui kapan sistem EVS aktif.
Antarmuka HIDL EVS
Sistem EVS, baik kamera maupun elemen tampilan, ditentukan dalam paket android.hardware.automotive.evs
. Contoh penerapan
yang menggunakan antarmuka (membuat gambar pengujian sintetis dan memvalidasi
gambar yang melakukan perjalanan pulang pergi) disediakan di
/hardware/interfaces/automotive/evs/1.0/default
.
OEM bertanggung jawab untuk menerapkan API yang dinyatakan oleh file .hal
di /hardware/interfaces/automotive/evs
. Implementasi tersebut bertanggung jawab untuk mengonfigurasi dan mengumpulkan data dari kamera fisik serta mengirimkannya melalui buffer memori bersama yang dapat dikenali oleh Gralloc. Sisi
tampilan penerapan bertanggung jawab untuk menyediakan buffer memori bersama
yang dapat diisi oleh aplikasi (biasanya melalui rendering EGL) dan menampilkan
frame yang telah selesai daripada hal lain yang mungkin ingin muncul di
tampilan fisik. Implementasi vendor untuk antarmuka EVS dapat disimpan
di /vendor/… /device/…
atau hardware/…
(misalnya,
/hardware/[vendor]/[platform]/evs
).
Driver kernel
Perangkat yang mendukung stack EVS memerlukan driver kernel. Daripada membuat driver baru, OEM memiliki opsi untuk mendukung fitur yang diperlukan EVS melalui driver hardware kamera dan/atau layar yang ada. Menggunakan kembali driver dapat
menguntungkan, terutama untuk driver layar yang presentasi gambarnya mungkin
memerlukan koordinasi dengan thread aktif lainnya. Android 8.0 menyertakan driver contoh berbasis v4l2 (di packages/services/Car/evs/sampleDriver
) yang bergantung pada kernel untuk dukungan v4l2 dan pada SurfaceFlinger untuk menampilkan gambar output.
Deskripsi antarmuka hardware EVS
Bagian ini menjelaskan HAL. Vendor diharapkan menyediakan penerapan API ini yang disesuaikan untuk hardware mereka.
IEvsEnumerator
Objek ini bertanggung jawab untuk menghitung hardware EVS yang tersedia dalam sistem (satu atau beberapa kamera dan satu perangkat tampilan).
getCameraList() generates (vec<CameraDesc> cameras);
Menampilkan vektor yang berisi deskripsi untuk semua kamera dalam sistem. Diasumsikan set kamera sudah ditetapkan dan dapat diketahui saat waktu booting. Untuk mengetahui detail tentang deskripsi kamera, lihat CameraDesc
.
openCamera(string camera_id) generates (IEvsCamera camera);
Mendapatkan objek antarmuka yang digunakan untuk berinteraksi dengan kamera tertentu yang diidentifikasi oleh string camera_id unik. Menampilkan NULL jika gagal.
Upaya untuk membuka kembali kamera yang sudah terbuka tidak boleh gagal. Untuk menghindari kondisi persaingan (race condition) yang terkait dengan startup dan shutdown aplikasi, membuka kembali kamera harus mematikan instance sebelumnya sehingga permintaan baru dapat dipenuhi. Instance
kamera yang telah dihentikan dengan cara ini harus dalam keadaan tidak aktif, menunggu penghancuran akhir dan merespons permintaan apa pun untuk memengaruhi status kamera dengan kode yang ditampilkan OWNERSHIP_LOST
.
closeCamera(IEvsCamera camera);
Melepaskan antarmuka IEvsCamera (dan merupakan kebalikan dari
panggilan openCamera()
). Streaming video kamera harus dihentikan dengan memanggil stopVideoStream()
sebelum memanggil closeCamera
.
openDisplay() generates (IEvsDisplay display);
Mendapatkan objek antarmuka yang digunakan secara eksklusif untuk berinteraksi dengan tampilan EVS sistem. Hanya satu klien yang dapat menyimpan instance fungsional IEvsDisplay pada satu waktu. Mirip dengan perilaku pembukaan agresif yang dijelaskan dalam openCamera
,
objek IEvsDisplay baru dapat dibuat kapan saja dan akan menonaktifkan instance
sebelumnya. Instance yang dibatalkan validasinya akan terus ada dan merespons panggilan fungsi
dari pemiliknya, tetapi tidak boleh melakukan operasi mutasi saat tidak aktif. Pada akhirnya,
aplikasi klien diharapkan untuk memperhatikan kode error OWNERSHIP_LOST
dan menutup serta melepaskan antarmuka yang tidak aktif.
closeDisplay(IEvsDisplay display);
Melepaskan antarmuka IEvsDisplay (dan merupakan kebalikan dari
panggilan openDisplay()
). Buffer yang belum selesai diterima melalui panggilan
getTargetBuffer()
harus dikembalikan ke layar sebelum
menutup layar.
getDisplayState() generates (DisplayState state);
Mendapatkan status tampilan saat ini. Penerapan HAL harus melaporkan status saat ini yang sebenarnya, yang mungkin berbeda dari status yang terakhir diminta.
Logika yang bertanggung jawab untuk mengubah status tampilan harus ada di atas lapisan perangkat, sehingga tidak diinginkan jika implementasi HAL mengubah status tampilan secara spontan. Jika saat ini tampilan tidak dipegang oleh klien mana pun (dengan panggilan ke
openDisplay), fungsi ini akan menampilkan NOT_OPEN
. Jika tidak, API ini akan melaporkan status EVS Display saat ini (lihat
IEvsDisplay API).
struct CameraDesc { string camera_id; int32 vendor_flags; // Opaque value }
camera_id
. String yang mengidentifikasi kamera tertentu secara unik. Dapat berupa nama perangkat kernel atau nama untuk perangkat, seperti rearview. Nilai untuk string ini dipilih oleh implementasi HAL dan digunakan secara buram oleh stack di atas.vendor_flags
. Metode untuk meneruskan informasi kamera khusus secara transparan dari driver ke aplikasi EVS kustom. Informasi ini diteruskan tanpa ditafsirkan dari driver ke aplikasi EVS, yang bebas mengabaikannya.
IEvsCamera
Objek ini merepresentasikan satu kamera dan merupakan antarmuka utama untuk mengambil gambar.
getCameraInfo() generates (CameraDesc info);
Menampilkan CameraDesc
kamera ini.
setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);
Menentukan kedalaman rantai buffer yang diminta untuk didukung oleh kamera. Hingga
sejumlah frame ini dapat ditahan secara bersamaan oleh klien IEvsCamera. Jika
sebanyak ini frame telah dikirim ke penerima tanpa dikembalikan oleh
doneWithFrame
, streaming akan melewati frame hingga buffer dikembalikan
untuk digunakan kembali. Panggilan ini dapat dilakukan kapan saja secara sah, bahkan saat streaming sudah berjalan. Dalam hal ini, buffer harus ditambahkan atau dihapus dari rantai sebagaimana mestinya. Jika tidak ada panggilan yang dilakukan ke titik entri ini, IEvsCamera mendukung
setidaknya satu frame secara default; dengan lebih banyak frame yang dapat diterima.
Jika bufferCount yang diminta tidak dapat ditampung, fungsi akan menampilkan
BUFFER_NOT_AVAILABLE
atau kode error relevan lainnya. Dalam hal ini,
sistem akan terus beroperasi dengan nilai yang ditetapkan sebelumnya.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Meminta pengiriman frame kamera EVS dari kamera ini. IEvsCameraStream mulai menerima panggilan berkala dengan frame gambar baru hingga stopVideoStream()
dipanggil. Frame harus mulai dikirimkan dalam waktu 500 md setelah panggilan startVideoStream
dan setelah dimulai, harus dibuat dengan kecepatan minimal 10 FPS. Waktu yang diperlukan untuk memulai streaming video
secara efektif dihitung terhadap persyaratan waktu mulai kamera tampilan belakang. Jika
streaming tidak dimulai, kode error harus ditampilkan; jika tidak, OK akan ditampilkan.
oneway doneWithFrame(BufferDesc buffer);
Menampilkan frame yang dikirimkan oleh IEvsCameraStream. Setelah selesai
menggunakan frame yang dikirimkan ke antarmuka IEvsCameraStream, frame harus
dikembalikan ke IEvsCamera untuk digunakan kembali. Sejumlah kecil buffer terbatas tersedia (mungkin hanya satu), dan jika persediaan habis, tidak ada frame lebih lanjut yang dikirimkan hingga buffer dikembalikan, yang berpotensi mengakibatkan frame dilewati (buffer dengan handle null menandakan akhir streaming dan tidak perlu dikembalikan melalui fungsi ini). Menampilkan OK jika berhasil, atau
kode error yang sesuai, yang berpotensi mencakup INVALID_ARG
atau
BUFFER_NOT_AVAILABLE
.
stopVideoStream();
Menghentikan pengiriman frame kamera EVS. Karena pengiriman bersifat asinkron,
frame dapat terus tiba selama beberapa waktu setelah panggilan ini ditampilkan. Setiap frame
harus ditampilkan hingga penutupan streaming disinyalkan ke
IEvsCameraStream. Memanggil stopVideoStream
pada stream yang telah dihentikan atau tidak pernah dimulai adalah tindakan yang sah, dan dalam kasus ini, panggilan akan diabaikan.
getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);
Meminta informasi khusus driver dari implementasi HAL. Nilai
yang diizinkan untuk opaqueIdentifier
khusus untuk driver, tetapi tidak ada nilai
yang diteruskan dapat menyebabkan driver mengalami error. Driver harus menampilkan 0 untuk
opaqueIdentifier
yang tidak dikenal.
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
Mengirim nilai khusus driver ke implementasi HAL. Ekstensi ini hanya disediakan untuk memfasilitasi ekstensi khusus kendaraan dan tidak ada implementasi HAL yang memerlukan panggilan ini agar berfungsi dalam status default. Jika driver mengenali dan menerima nilai, OK akan ditampilkan; jika tidak, INVALID_ARG
atau kode error representatif lainnya akan ditampilkan.
struct BufferDesc { uint32 width; // Units of pixels uint32 height; // Units of pixels uint32 stride; // Units of pixels uint32 pixelSize; // Size of single pixel in bytes uint32 format; // May contain values from android_pixel_format_t uint32 usage; // May contain values from Gralloc.h uint32 bufferId; // Opaque value handle memHandle; // gralloc memory buffer handle }
Mendeskripsikan gambar yang diteruskan melalui API. Drive HAL bertanggung jawab untuk
mengisi struktur ini untuk menjelaskan buffer gambar dan klien HAL
harus memperlakukan struktur ini sebagai hanya baca. Kolom berisi informasi yang cukup
untuk memungkinkan klien merekonstruksi objek ANativeWindowBuffer
,
sebagaimana mungkin diperlukan untuk menggunakan gambar dengan EGL melalui
ekstensi eglCreateImageKHR()
.
width
. Lebar gambar yang ditampilkan dalam piksel.height
. Tinggi gambar yang ditampilkan dalam piksel.stride
. Jumlah piksel yang sebenarnya ditempati setiap baris dalam memori, dengan memperhitungkan padding untuk perataan baris. Dinyatakan dalam piksel agar sesuai dengan konvensi yang diterapkan oleh gralloc untuk deskripsi buffer-nya.pixelSize
. Jumlah byte yang ditempati oleh setiap piksel, memungkinkan penghitungan ukuran dalam byte yang diperlukan untuk berpindah antar-baris dalam gambar (stride
dalam byte =stride
dalam piksel *pixelSize
).format
. Format piksel yang digunakan oleh gambar. Format yang diberikan harus kompatibel dengan implementasi OpenGL platform. Untuk lulus pengujian kompatibilitas,HAL_PIXEL_FORMAT_YCRCB_420_SP
harus lebih disukai untuk penggunaan kamera, danRGBA
atauBGRA
harus lebih disukai untuk tampilan.usage
. Flag penggunaan yang ditetapkan oleh implementasi HAL. Klien HAL diharapkan meneruskan flag ini tanpa diubah (untuk mengetahui detailnya, lihat flag terkaitGralloc.h
).bufferId
. Nilai unik yang ditentukan oleh implementasi HAL untuk memungkinkan buffer dikenali setelah round trip melalui API HAL. Nilai yang disimpan di kolom ini dapat dipilih secara arbitrer oleh implementasi HAL.memHandle
. Handle untuk buffer memori pokok yang berisi data gambar. Implementasi HAL dapat memilih untuk menyimpan handle buffer Gralloc di sini.
IEvsCameraStream
Klien menerapkan antarmuka ini untuk menerima pengiriman frame video asinkron.
deliverFrame(BufferDesc buffer);
Menerima panggilan dari HAL setiap kali frame video siap untuk diperiksa.
Buffer yang ditangani yang diterima oleh metode ini harus ditampilkan melalui panggilan ke
IEvsCamera::doneWithFrame()
. Saat streaming video dihentikan melalui
panggilan ke IEvsCamera::stopVideoStream()
, callback ini dapat berlanjut
saat pipeline dikosongkan. Setiap frame harus tetap ditampilkan; saat frame terakhir dalam streaming telah dikirimkan, bufferHandle NULL akan dikirimkan, menandakan akhir streaming dan tidak ada lagi pengiriman frame. bufferHandle NULL itu sendiri tidak perlu dikirim kembali melalui
doneWithFrame()
, tetapi semua handle lainnya harus ditampilkan
Meskipun format buffer eksklusif secara teknis dimungkinkan, pengujian kompatibilitas mengharuskan buffer dalam salah satu dari empat format yang didukung: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 Interleaved), RGBA (32 bit R:G:B:x), BGRA (32 bit B:G:R:x). Format yang dipilih harus berupa sumber tekstur GL yang valid pada penerapan GLES platform.
Aplikasi tidak boleh mengandalkan korespondensi apa pun
antara kolom bufferId
dan memHandle
dalam
struktur BufferDesc
. Nilai bufferId
pada dasarnya bersifat pribadi untuk implementasi driver HAL, dan dapat menggunakan (dan menggunakan kembali) nilai tersebut sesuai keinginannya.
IEvsDisplay
Objek ini merepresentasikan tampilan EVS, mengontrol status tampilan, dan menangani presentasi gambar yang sebenarnya.
getDisplayInfo() generates (DisplayDesc info);
Menampilkan informasi dasar tentang tampilan EVS yang disediakan oleh sistem (lihat DisplayDesc).
setDisplayState(DisplayState state) generates (EvsResult result);
Menetapkan status tampilan. Klien dapat menyetel status tampilan untuk menyatakan status yang diinginkan, dan implementasi HAL harus menerima permintaan untuk status apa pun dengan baik saat dalam status lain, meskipun responsnya mungkin mengabaikan permintaan.
Setelah inisialisasi, layar ditentukan untuk dimulai dalam status
NOT_VISIBLE
, setelah itu klien diharapkan meminta
status VISIBLE_ON_NEXT_FRAME
dan mulai menyediakan video. Jika tampilan tidak lagi diperlukan, klien diharapkan meminta status NOT_VISIBLE
setelah meneruskan frame video terakhir.
Valid untuk negara bagian mana pun yang diminta kapan saja. Jika tampilan sudah terlihat, tampilan akan tetap terlihat jika disetel ke VISIBLE_ON_NEXT_FRAME
. Selalu menampilkan OK kecuali jika status yang diminta adalah nilai enum yang tidak dikenal, yang dalam hal ini INVALID_ARG
akan ditampilkan.
getDisplayState() generates (DisplayState state);
Mendapatkan status tampilan. Penerapan HAL harus melaporkan status saat ini yang sebenarnya, yang mungkin berbeda dari status yang terakhir diminta. Logika yang bertanggung jawab untuk mengubah status layar harus ada di atas lapisan perangkat, sehingga tidak diinginkan jika implementasi HAL mengubah status layar secara spontan.
getTargetBuffer() generates (handle bufferHandle);
Menampilkan handle ke buffer frame yang terkait dengan layar. Buffer ini dapat dikunci dan ditulis oleh software dan/atau GL. Buffer ini harus ditampilkan
melalui panggilan ke returnTargetBufferForDisplay()
meskipun layar
tidak lagi terlihat.
Meskipun format buffer eksklusif secara teknis dimungkinkan, pengujian kompatibilitas memerlukan buffer dalam salah satu dari empat format yang didukung: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 Interleaved), RGBA (32 bit R:G:B:x), BGRA (32 bit B:G:R:x). Format yang dipilih harus berupa target render GL yang valid pada implementasi GLES platform.
Jika terjadi error, buffer dengan handle null akan ditampilkan, tetapi buffer tersebut tidak
perlu diteruskan kembali ke returnTargetBufferForDisplay
.
returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);
Memberi tahu layar bahwa buffer siap untuk ditampilkan. Hanya buffer yang diambil
melalui panggilan ke getTargetBuffer()
yang valid untuk digunakan dengan
panggilan ini, dan konten BufferDesc
tidak boleh diubah oleh
aplikasi klien. Setelah panggilan ini, buffer tidak lagi valid untuk digunakan oleh
klien. Menampilkan OK jika berhasil, atau kode error yang sesuai, yang berpotensi mencakup INVALID_ARG
atau BUFFER_NOT_AVAILABLE
.
struct DisplayDesc { string display_id; int32 vendor_flags; // Opaque value }
Menjelaskan properti dasar tampilan EVS dan diperlukan oleh penerapan EVS. HAL bertanggung jawab untuk mengisi struktur ini guna mendeskripsikan tampilan EVS. Dapat berupa layar fisik atau layar virtual yang ditumpuk atau dicampur dengan perangkat presentasi lain.
display_id
. String yang mengidentifikasi layar secara unik. Nama ini bisa berupa nama perangkat kernel, atau nama untuk perangkat, seperti rearview. Nilai untuk string ini dipilih oleh penerapan HAL dan digunakan secara buram oleh stack di atas.vendor_flags
. Metode untuk meneruskan informasi kamera khusus secara transparan dari driver ke aplikasi EVS kustom. Informasi ini diteruskan tanpa ditafsirkan dari driver ke aplikasi EVS, yang bebas mengabaikannya.
enum DisplayState : uint32 { NOT_OPEN, // Display has not been “opened” yet NOT_VISIBLE, // Display is inhibited VISIBLE_ON_NEXT_FRAME, // Will become visible with next frame VISIBLE, // Display is currently active DEAD, // Display is not available. Interface should be closed }
Menjelaskan status tampilan EVS, yang dapat berupa dinonaktifkan (tidak
terlihat oleh pengemudi) atau diaktifkan (menampilkan gambar kepada pengemudi).
Mencakup status sementara saat tampilan belum terlihat, tetapi sudah siap
untuk terlihat dengan pengiriman frame gambar berikutnya melalui panggilan
returnTargetBufferForDisplay()
.
EVS Manager
EVS Manager menyediakan antarmuka publik ke sistem EVS untuk mengumpulkan dan menampilkan tampilan kamera eksternal. Jika driver hardware hanya mengizinkan satu antarmuka aktif per resource (kamera atau layar), EVS Manager memfasilitasi akses bersama ke kamera. Satu aplikasi EVS utama adalah klien pertama EVS Manager, dan merupakan satu-satunya klien yang diizinkan untuk menulis data tampilan (klien tambahan dapat diberi akses hanya baca ke gambar kamera).
EVS Manager menerapkan API yang sama dengan driver HAL yang mendasarinya dan menyediakan layanan yang diperluas dengan mendukung beberapa klien serentak (lebih dari satu klien dapat membuka kamera melalui EVS Manager dan menerima streaming video).

Gambar 2. EVS Manager mencerminkan EVS Hardware API yang mendasarinya.
Aplikasi tidak melihat perbedaan saat beroperasi melalui penerapan HAL Hardware EVS atau EVS Manager API, kecuali bahwa EVS Manager API memungkinkan akses streaming kamera serentak. EVS Manager sendiri adalah satu-satunya klien yang diizinkan dari lapisan HAL Hardware EVS, dan bertindak sebagai proxy untuk HAL Hardware EVS.
Bagian berikut hanya menjelaskan panggilan yang memiliki perilaku (diperluas) yang berbeda dalam penerapan EVS Manager; panggilan yang tersisa identik dengan deskripsi EVS HAL.
IEvsEnumerator
openCamera(string camera_id) generates (IEvsCamera camera);
Mendapatkan objek antarmuka yang digunakan untuk berinteraksi dengan kamera tertentu yang diidentifikasi oleh string camera_id unik. Menampilkan NULL jika gagal.
Di lapisan EVS Manager, selama resource sistem yang memadai tersedia,
kamera yang sudah terbuka dapat dibuka lagi oleh proses lain, sehingga memungkinkan
pengiriman aliran video ke beberapa aplikasi konsumen. String
camera_id
di lapisan EVS Manager sama dengan yang
dilaporkan ke lapisan Hardware EVS.
IEvsCamera
Implementasi IEvsCamera yang disediakan EVS Manager divirtualisasi secara internal sehingga operasi pada kamera oleh satu klien tidak memengaruhi klien lain, yang mempertahankan akses independen ke kamera mereka.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Memulai streaming video. Klien dapat memulai dan menghentikan streaming video secara independen di kamera yang sama. Kamera yang mendasarinya akan dimulai saat klien pertama dimulai.
doneWithFrame(uint32 frameId, handle bufferHandle) generates (EvsResult result);
Menampilkan frame. Setiap klien harus mengembalikan frame-nya setelah selesai, tetapi diizinkan untuk menyimpan frame-nya selama yang diinginkan. Saat jumlah frame yang ditahan oleh klien mencapai batas yang dikonfigurasi, klien tidak akan menerima frame lagi hingga mengembalikan satu frame. Pelewatan frame ini tidak memengaruhi klien lain, yang terus menerima semua frame seperti yang diharapkan.
stopVideoStream();
Menghentikan streaming video. Setiap klien dapat menghentikan streaming videonya kapan saja tanpa memengaruhi klien lain. Streaming kamera yang mendasarinya di lapisan hardware akan dihentikan saat klien terakhir dari kamera tertentu menghentikan streaming-nya.
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
Mengirim nilai khusus driver, yang berpotensi memungkinkan satu klien memengaruhi klien lain. Karena EVS Manager tidak dapat memahami implikasi kata kontrol yang ditentukan vendor, kata kontrol tersebut tidak divirtualisasi dan efek samping apa pun berlaku untuk semua klien kamera tertentu. Misalnya, jika vendor menggunakan panggilan ini untuk mengubah kecepatan frame, semua klien kamera lapisan hardware yang terpengaruh akan menerima frame dengan kecepatan baru.
IEvsDisplay
Hanya satu pemilik layar yang diizinkan, bahkan di tingkat Pengelola EVS. Manager tidak menambahkan fungsi apa pun dan hanya meneruskan antarmuka IEvsDisplay langsung ke implementasi HAL yang mendasarinya.
Aplikasi EVS
Android menyertakan implementasi referensi C++ native aplikasi EVS yang berkomunikasi dengan EVS Manager dan Vehicle HAL untuk menyediakan fungsi kamera belakang dasar. Aplikasi diharapkan dimulai sangat awal dalam proses booting sistem, dengan video yang sesuai ditampilkan bergantung pada kamera yang tersedia dan status mobil (status gigi dan sinyal belok). OEM dapat mengubah atau mengganti aplikasi EVS dengan logika dan presentasi khusus kendaraan mereka sendiri.

Gambar 3. Contoh logika aplikasi EVS, dapatkan daftar kamera.

Gambar 4. Contoh logika aplikasi EVS, callback frame receive.
Karena data gambar disajikan ke aplikasi dalam buffer grafis standar, aplikasi bertanggung jawab untuk memindahkan gambar dari buffer sumber ke buffer output. Meskipun menimbulkan biaya salinan data, hal ini juga memberikan peluang bagi aplikasi untuk merender gambar ke dalam buffer tampilan dengan cara apa pun yang diinginkannya.
Misalnya, aplikasi dapat memilih untuk memindahkan data piksel itu sendiri, kemungkinan dengan operasi penskalaan atau rotasi inline. Aplikasi juga dapat memilih untuk menggunakan gambar sumber sebagai tekstur OpenGL dan merender adegan yang kompleks ke buffer output, termasuk elemen virtual seperti ikon, panduan, dan animasi. Aplikasi yang lebih canggih juga dapat memilih beberapa kamera input serentak dan menggabungkannya ke dalam satu frame output (seperti untuk digunakan dalam tampilan virtual dari atas ke bawah di sekitar kendaraan).
Menggunakan EGL/SurfaceFlinger di EVS Display HAL
Bagian ini menjelaskan cara menggunakan EGL untuk merender implementasi HAL Tampilan EVS di Android 10.
Implementasi referensi HAL EVS menggunakan EGL untuk merender pratinjau kamera di layar dan menggunakan libgui
untuk membuat target platform render EGL. Di Android 8 (dan yang lebih tinggi), libgui
diklasifikasikan sebagai VNDK-private,
yang mengacu pada sekelompok library yang tersedia untuk library VNDK yang tidak dapat digunakan oleh proses vendor.
Karena implementasi HAL harus berada di partisi vendor, vendor dicegah menggunakan
Surface dalam implementasi HAL.
Membangun libgui untuk proses vendor
Penggunaan libgui
berfungsi sebagai satu-satunya opsi untuk menggunakan EGL/SurfaceFlinger
dalam implementasi HAL Tampilan EVS. Cara paling mudah untuk menerapkan libgui
adalah
melalui
frameworks/native/libs/gui
secara langsung dengan menggunakan target build tambahan dalam skrip build. Target ini sama persis dengan target libgui
, kecuali penambahan dua kolom:
name
vendor_available
cc_library_shared { name: "libgui_vendor", vendor_available: true, vndk: { enabled: false, }, double_loadable: true,
defaults: ["libgui_bufferqueue-defaults"],
srcs: [ … // bufferhub is not used when building libgui for vendors target: { vendor: { cflags: [ "-DNO_BUFFERHUB", "-DNO_INPUT", ], …
Catatan: Target vendor dibuat dengan makro NO_INPUT
, yang menghapus satu kata 32-bit dari data bidang tanah. Karena SurfaceFlinger mengharapkan kolom yang telah dihapus ini, SurfaceFlinger gagal mengurai paket. Hal ini diamati sebagai kegagalan fcntl
:
W Parcel : Attempt to read object from Parcel 0x78d9cffad8 at offset 428 that is not in the object list E Parcel : fcntl(F_DUPFD_CLOEXEC) failed in Parcel::read, i is 0, fds[i] is 0, fd_count is 20, error: Unknown error 2147483647 W Parcel : Attempt to read object from Parcel 0x78d9cffad8 at offset 544 that is not in the object list
Untuk mengatasi kondisi ini:
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 6066421fa..25cf5f0ce 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -54,6 +54,9 @@ status_t layer_state_t::write(Parcel& output) const output.writeFloat(color.b); #ifndef NO_INPUT inputInfo.write(output); +#else + // Write a dummy 32-bit word. + output.writeInt32(0); #endif output.write(transparentRegion); output.writeUint32(transform);
Contoh petunjuk
build disediakan di bawah. Anda akan menerima
$(ANDROID_PRODUCT_OUT)/system/lib64/libgui_vendor.so
.
$ cd <your_android_source_tree_top> $ . ./build/envsetup. $ lunch <product_name>-<build_variant> ============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=10 TARGET_PRODUCT=<product_name> TARGET_BUILD_VARIANT=<build_variant> TARGET_BUILD_TYPE=release TARGET_ARCH=arm64 TARGET_ARCH_VARIANT=armv8-a TARGET_CPU_VARIANT=generic TARGET_2ND_ARCH=arm TARGET_2ND_ARCH_VARIANT=armv7-a-neon TARGET_2ND_CPU_VARIANT=cortex-a9 HOST_ARCH=x86_64 HOST_2ND_ARCH=x86 HOST_OS=linux HOST_OS_EXTRA=<host_linux_version> HOST_CROSS_OS=windows HOST_CROSS_ARCH=x86 HOST_CROSS_2ND_ARCH=x86_64 HOST_BUILD_TYPE=release BUILD_ID=QT OUT_DIR=out ============================================
$ m -j libgui_vendor … $ find $ANDROID_PRODUCT_OUT/system -name "libgui_vendor*" .../out/target/product/hawk/system/lib64/libgui_vendor.so .../out/target/product/hawk/system/lib/libgui_vendor.so
Menggunakan binder dalam implementasi HAL EVS
Di Android 8 (dan yang lebih tinggi), node perangkat /dev/binder
menjadi eksklusif untuk
proses framework dan, oleh karena itu, tidak dapat diakses oleh proses vendor. Sebagai gantinya,
proses vendor harus menggunakan /dev/hwbinder
dan harus mengonversi semua antarmuka AIDL
ke HIDL. Bagi yang ingin terus menggunakan antarmuka AIDL di antara proses vendor,
gunakan domain binder, /dev/vndbinder
.
Domain IPC | Deskripsi |
---|---|
/dev/binder |
IPC antara proses framework/aplikasi dengan antarmuka AIDL |
/dev/hwbinder |
IPC antara proses framework/vendor dengan antarmuka HIDL IPC antara proses vendor dengan antarmuka HIDL |
/dev/vndbinder |
IPC antara proses vendor/vendor dengan Antarmuka AIDL |
Meskipun SurfaceFlinger menentukan antarmuka AIDL, proses vendor hanya dapat menggunakan antarmuka HIDL untuk
berkomunikasi dengan proses framework. Sejumlah besar pekerjaan diperlukan untuk mengonversi antarmuka AIDL yang ada menjadi HIDL. Untungnya, Android menyediakan metode untuk memilih driver binder untuk libbinder
, yang ditautkan ke proses library ruang pengguna.
diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp index d8fb3166..5fd02935 100644 --- a/evs/sampleDriver/service.cpp +++ b/evs/sampleDriver/service.cpp @@ -21,6 +21,7 @@ #include <utils/Errors.h> #include <utils/StrongPointer.h> #include <utils/Log.h> +#include <binder/ProcessState.h> #include "ServiceNames.h" #include "EvsEnumerator.h" @@ -43,6 +44,9 @@ using namespace android; int main() { ALOGI("EVS Hardware Enumerator service is starting"); + // Use /dev/binder for SurfaceFlinger + ProcessState::initWithDriver("/dev/binder"); + // Start a thread to listen to video device addition events. std::atomic<bool> running { true }; std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running));
Catatan: Proses vendor harus memanggilnya sebelum memanggil
Process
atau IPCThreadState
, atau sebelum melakukan panggilan binder.
Kebijakan SELinux
Jika implementasi perangkat adalah treble penuh, SELinux mencegah proses vendor menggunakan /dev/binder
. Misalnya, penerapan contoh HAL EVS ditetapkan ke domain hal_evs_driver
dan memerlukan izin baca/tulis ke domain binder_device
.
W ProcessState: Opening '/dev/binder' failed: Permission denied F ProcessState: Binder driver could not be opened. Terminating. F libc : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 9145 (android.hardwar), pid 9145 (android.hardwar) W android.hardwar: type=1400 audit(0.0:974): avc: denied { read write } for name="binder" dev="tmpfs" ino=2208 scontext=u:r:hal_evs_driver:s0 tcontext=u:object_r:binder_device:s0 tclass=chr_file permissive=0
Namun, penambahan izin ini menyebabkan kegagalan build karena melanggar aturan
neverallow berikut yang ditentukan dalam system/sepolicy/domain.te
untuk perangkat treble penuh.
libsepol.report_failure: neverallow on line 631 of system/sepolicy/public/domain.te (or line 12436 of policy.conf) violated by allow hal_evs_driver binder_device:chr_file { read write }; libsepol.check_assertions: 1 neverallow failures occurred
full_treble_only(` neverallow { domain -coredomain -appdomain -binder_in_vendor_violators } binder_device:chr_file rw_file_perms; ')
binder_in_vendor_violators
adalah atribut yang disediakan untuk menemukan bug dan memandu pengembangan. Alat ini juga dapat digunakan untuk menyelesaikan pelanggaran Android 10 yang dijelaskan di atas.
diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te index f1f31e9fc..6ee67d88e 100644 --- a/evs/sepolicy/evs_driver.te +++ b/evs/sepolicy/evs_driver.te @@ -3,6 +3,9 @@ type hal_evs_driver, domain, coredomain; hal_server_domain(hal_evs_driver, hal_evs) hal_client_domain(hal_evs_driver, hal_evs) +# Allow to use /dev/binder +typeattribute hal_evs_driver binder_in_vendor_violators; + # allow init to launch processes in this context type hal_evs_driver_exec, exec_type, file_type, system_file_type; init_daemon_domain(hal_evs_driver)
Membangun implementasi referensi HAL EVS sebagai proses vendor
Sebagai referensi, Anda dapat menerapkan perubahan berikut pada
packages/services/Car/evs/Android.mk
. Pastikan untuk mengonfirmasi bahwa semua perubahan yang dijelaskan berfungsi untuk penerapan Anda.
diff --git a/evs/sampleDriver/Android.mk b/evs/sampleDriver/Android.mk index 734feea7d..0d257214d 100644 --- a/evs/sampleDriver/Android.mk +++ b/evs/sampleDriver/Android.mk @@ -16,7 +16,7 @@ LOCAL_SRC_FILES := \ LOCAL_SHARED_LIBRARIES := \ android.hardware.automotive.evs@1.0 \ libui \ - libgui \ + libgui_vendor \ libEGL \ libGLESv2 \ libbase \ @@ -33,6 +33,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_INIT_RC := android.hardware.automotive.evs@1.0-sample.rc LOCAL_MODULE := android.hardware.automotive.evs@1.0-sample +LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE_TAGS := optional LOCAL_STRIP_MODULE := keep_symbols @@ -40,6 +41,7 @@ LOCAL_STRIP_MODULE := keep_symbols LOCAL_CFLAGS += -DLOG_TAG=\"EvsSampleDriver\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code +LOCAL_CFLAGS += -Iframeworks/native/include # NOTE: It can be helpful, while debugging, to disable optimizations #LOCAL_CFLAGS += -O0 -g diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp index d8fb31669..5fd029358 100644 --- a/evs/sampleDriver/service.cpp +++ b/evs/sampleDriver/service.cpp @@ -21,6 +21,7 @@ #include <utils/Errors.h> #include <utils/StrongPointer.h> #include <utils/Log.h> +#include <binder/ProcessState.h> #include "ServiceNames.h" #include "EvsEnumerator.h" @@ -43,6 +44,9 @@ using namespace android; int main() { ALOGI("EVS Hardware Enumerator service is starting"); + // Use /dev/binder for SurfaceFlinger + ProcessState::initWithDriver("/dev/binder"); + // Start a thread to listen video device addition events. std::atomic<bool> running { true }; std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running)); diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te index f1f31e9fc..632fc7337 100644 --- a/evs/sepolicy/evs_driver.te +++ b/evs/sepolicy/evs_driver.te @@ -3,6 +3,9 @@ type hal_evs_driver, domain, coredomain; hal_server_domain(hal_evs_driver, hal_evs) hal_client_domain(hal_evs_driver, hal_evs) +# allow to use /dev/binder +typeattribute hal_evs_driver binder_in_vendor_violators; + # allow init to launch processes in this context type hal_evs_driver_exec, exec_type, file_type, system_file_type; init_daemon_domain(hal_evs_driver) @@ -22,3 +25,7 @@ allow hal_evs_driver ion_device:chr_file r_file_perms; # Allow the driver to access kobject uevents allow hal_evs_driver self:netlink_kobject_uevent_socket create_socket_perms_no_ioctl; + +# Allow the driver to use the binder device +allow hal_evs_driver binder_device:chr_file rw_file_perms;