HAL Kamera Kendaraan

Android berisi Lapisan Abstraksi Hardware (HAL) HIDL otomotif yang menyediakan pengambilan dan tampilan gambar di awal proses booting Android dan terus berfungsi selama masa pakai sistem. HAL menyertakan stack sistem tampilan luar (EVS) dan biasanya digunakan untuk mendukung kamera belakang dan tampilan tampilan sekeliling di kendaraan dengan sistem Infotainment dalam Kendaraan (IVI) berbasis Android. EVS juga memungkinkan fitur lanjutan diterapkan di aplikasi pengguna.

Android juga menyertakan antarmuka driver pengambilan dan tampilan khusus EVS (di /hardware/interfaces/automotive/evs/1.0). Meskipun Anda dapat mem-build aplikasi kamera belakang 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 hal yang perlu diterapkan OEM untuk mendukung stack EVS.

Komponen sistem

EVS mencakup komponen sistem berikut:

Diagram komponen
Sistem EVS

Gambar 1. Ringkasan komponen sistem EVS.

Aplikasi EVS

Contoh aplikasi EVS C++ (/packages/services/Car/evs/app) berfungsi sebagai implementasi referensi. Aplikasi ini bertanggung jawab untuk meminta frame video dari EVS Manager dan mengirim frame yang telah selesai untuk ditampilkan kembali ke EVS Manager. Layanan ini diharapkan dimulai oleh init segera setelah EVS dan Layanan Mobil tersedia, yang ditargetkan dalam waktu dua (2) detik setelah dinyalakan. OEM dapat mengubah atau mengganti aplikasi EVS sesuai keinginan.

Pengelola EVS

Pengelola EVS (/packages/services/Car/evs/manager) menyediakan elemen penyusun yang diperlukan oleh aplikasi EVS untuk menerapkan apa pun, mulai dari tampilan kamera belakang sederhana hingga rendering multi-kamera 6DOF. Antarmukanya dipresentasikan 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 EVS HIDL

Sistem EVS, baik kamera maupun elemen tampilan, ditentukan dalam paket android.hardware.automotive.evs. Contoh penerapan yang melatih antarmuka (menghasilkan gambar pengujian sintetis dan memvalidasi gambar untuk melakukan perjalanan bolak-balik) 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 layar implementasi bertanggung jawab untuk menyediakan buffering memori bersama yang dapat diisi oleh aplikasi (biasanya melalui rendering EGL) dan menampilkan frame yang sudah selesai sebagai preferensi daripada hal lain yang mungkin ingin muncul di layar fisik. Implementasi vendor antarmuka EVS dapat disimpan di bagian /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 bermanfaat, terutama untuk driver tampilan karena presentasi gambar 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 untuk menyediakan implementasi API ini yang disesuaikan untuk hardware mereka.

IEvsEnumerator

Objek ini bertanggung jawab untuk menghitung hardware EVS yang tersedia di sistem (satu atau beberapa kamera dan satu perangkat layar).

getCameraList() generates (vec<CameraDesc> cameras);

Menampilkan vektor yang berisi deskripsi untuk semua kamera dalam sistem. Diasumsikan bahwa kumpulan kamera bersifat tetap dan dapat diketahui saat 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. Mengembalikan NULL saat gagal. Upaya untuk membuka kembali kamera yang sudah terbuka tidak boleh gagal. Untuk menghindari kondisi race yang terkait dengan startup dan penonaktifan aplikasi, membuka kembali kamera akan menonaktifkan instance sebelumnya sehingga permintaan baru dapat dipenuhi. Instance kamera yang telah didahului dengan cara ini harus ditempatkan dalam status tidak aktif, menunggu pemusnahan akhir dan merespons permintaan apa pun untuk memengaruhi status kamera dengan kode return OWNERSHIP_LOST.

closeCamera(IEvsCamera camera);

Merilis 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 untuk berinteraksi secara eksklusif dengan layar EVS sistem. Hanya satu klien yang dapat menyimpan instance IEvsDisplay yang berfungsi pada satu waktu. Serupa dengan perilaku terbuka agresif yang dijelaskan di 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 mati. Pada akhirnya, aplikasi klien diharapkan akan melihat kode return error OWNERSHIP_LOST, lalu menutup dan merilis antarmuka yang tidak aktif.

closeDisplay(IEvsDisplay display);

Merilis antarmuka IEvsDisplay (dan merupakan kebalikan dari panggilan openDisplay()). Buffering luar biasa yang diterima melalui panggilan getTargetBuffer() harus ditampilkan ke layar sebelum menutup layar.

getDisplayState() generates (DisplayState state);

Mendapatkan status tampilan saat ini. Implementasi HAL harus melaporkan status sebenarnya saat ini, yang mungkin berbeda dari status terbaru yang diminta. Logika yang bertanggung jawab untuk mengubah status tampilan harus ada di atas lapisan perangkat, sehingga tidak diinginkan untuk implementasi HAL mengubah status tampilan secara spontan. Jika layar saat ini tidak dipegang oleh klien mana pun (dengan panggilan ke openDisplay), fungsi ini akan menampilkan NOT_OPEN. Jika tidak, metode ini akan melaporkan status Layar EVS saat ini (lihat IEvsDisplay API).

struct CameraDesc {
    string      camera_id;
    int32       vendor_flags;       // Opaque value
}
  • camera_id. String yang secara unik mengidentifikasi kamera tertentu. Dapat berupa nama perangkat kernel perangkat 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 buram dari driver ke aplikasi EVS kustom. Informasi ini diteruskan tanpa ditafsirkan dari driver hingga aplikasi EVS, yang bebas mengabaikannya.

IEvsCamera

Objek ini mewakili 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 buffering yang diminta untuk didukung kamera. Hingga sebanyak ini frame dapat disimpan secara serentak oleh klien IEvsCamera. Jika banyak frame ini telah dikirim ke penerima tanpa ditampilkan oleh doneWithFrame, streaming akan melewati frame hingga buffer ditampilkan untuk digunakan kembali. Panggilan ini dapat dilakukan kapan saja, bahkan saat streaming sudah berjalan, dalam hal ini buffer harus ditambahkan atau dihapus dari rantai sebagaimana diperlukan. Jika tidak ada panggilan yang dilakukan ke titik entri ini, IEvsCamera mendukung setidaknya satu frame secara default; dengan lebih dapat diterima.

Jika bufferCount yang diminta tidak dapat diakomodasi, 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 dikirim dalam waktu 500 md setelah panggilan startVideoStream dan setelah dimulai, harus dibuat minimal 10 FPS. Waktu yang diperlukan untuk memulai streaming video secara efektif mengurangi persyaratan waktu startup kamera belakang. Jika streaming tidak dimulai, kode error harus ditampilkan; jika tidak, OK akan ditampilkan.

oneway doneWithFrame(BufferDesc buffer);

Menampilkan frame yang dikirimkan oleh ke IEvsCameraStream. Setelah selesai menggunakan frame yang dikirim ke antarmuka IEvsCameraStream, frame tersebut harus dikembalikan ke IEvsCamera untuk digunakan kembali. Buffer dalam jumlah kecil dan terbatas tersedia (mungkin sekecil satu), dan jika persediaan habis, tidak ada frame lanjutan yang dikirim hingga buffer ditampilkan, yang berpotensi menyebabkan frame dilewati (buffer dengan handle null menunjukkan akhir streaming dan tidak perlu ditampilkan melalui fungsi ini). Menampilkan OK jika berhasil, atau kode error yang sesuai yang berpotensi menyertakan INVALID_ARG atau BUFFER_NOT_AVAILABLE.

stopVideoStream();

Menghentikan pengiriman frame kamera EVS. Karena pengiriman bersifat asinkron, frame dapat terus muncul selama beberapa waktu setelah panggilan ini ditampilkan. Setiap frame harus ditampilkan hingga penutupan streaming diberi sinyal ke IEvsCameraStream. Memanggil stopVideoStream pada streaming yang telah dihentikan atau tidak pernah dimulai adalah hal yang sah, dan dalam hal ini, panggilan akan diabaikan.

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

Meminta informasi khusus pengemudi dari implementasi HAL. Nilai yang diizinkan untuk opaqueIdentifier bersifat khusus driver, tetapi tidak ada nilai yang diteruskan yang dapat membuat driver error. Driver akan menampilkan 0 untuk opaqueIdentifier yang tidak dikenal.

setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);

Mengirimkan nilai khusus driver ke implementasi HAL. Ekstensi ini hanya disediakan untuk memfasilitasi ekstensi khusus kendaraan dan implementasi HAL tidak boleh memerlukan panggilan ini agar berfungsi dalam status default. Jika pengemudi mengenali dan menerima nilai, OK harus 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
}

Menjelaskan gambar yang diteruskan melalui API. Drive HAL bertanggung jawab untuk mengisi struktur ini guna mendeskripsikan buffering gambar dan klien HAL harus memperlakukan struktur ini sebagai hanya baca. Kolom ini berisi informasi yang cukup agar klien dapat merekonstruksi objek ANativeWindowBuffer, seperti yang mungkin diperlukan untuk menggunakan gambar dengan EGL melalui ekstensi eglCreateImageKHR().

  • width. Lebar dalam piksel dari gambar yang ditampilkan.
  • height. Tinggi gambar yang ditampilkan dalam piksel.
  • stride. Jumlah piksel yang sebenarnya digunakan setiap baris dalam memori, dengan memperhitungkan padding untuk perataan baris. Ditampilkan dalam piksel agar cocok dengan konvensi yang diadopsi oleh gralloc untuk deskripsi buffering-nya.
  • pixelSize. Jumlah byte yang ditempati oleh setiap piksel, mengaktifkan komputasi ukuran dalam byte yang diperlukan untuk berpindah-pindah baris dalam gambar (stride dalam byte = stride dalam piksel * pixelSize).
  • format. Format piksel yang digunakan oleh gambar. Format yang disediakan harus kompatibel dengan implementasi OpenGL platform. Agar lulus uji kompatibilitas, HAL_PIXEL_FORMAT_YCRCB_420_SP harus diutamakan untuk penggunaan kamera, dan RGBA atau BGRA harus diutamakan untuk tampilan.
  • usage. Flag penggunaan yang ditetapkan oleh implementasi HAL. Klien HAL diperkirakan akan meneruskan flag yang tidak dimodifikasi ini (untuk mengetahui detailnya, lihat flag terkait Gralloc.h).
  • bufferId. Nilai unik yang ditentukan oleh implementasi HAL untuk memungkinkan buffer dikenali setelah perjalanan bolak-balik melalui HAL API. Nilai yang disimpan di kolom ini dapat dipilih secara sewenang-wenang oleh implementasi HAL.
  • memHandle. Handle untuk buffer memori dasar yang berisi data gambar. Implementasi HAL mungkin 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. Handle buffering yang diterima oleh metode ini harus ditampilkan melalui panggilan ke IEvsCamera::doneWithFrame(). Saat streaming video dihentikan melalui panggilan ke IEvsCamera::stopVideoStream(), callback ini mungkin berlanjut saat pipeline habis. Setiap frame tetap harus ditampilkan; saat frame terakhir dalam streaming telah dikirimkan, bufferHandle NULL akan dikirimkan, yang menandakan akhir streaming dan tidak ada pengiriman frame lebih lanjut. bufferHandle NULL itu sendiri tidak perlu dikirim kembali melalui doneWithFrame(), tetapi semua handle lainnya harus ditampilkan

Meskipun format buffering eksklusif secara teknis memungkinkan, pengujian kompatibilitas mengharuskan buffering berada 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 menggunakannya (dan menggunakannya kembali) sesuai keinginan.

IEvsDisplay

Objek ini mewakili tampilan Evs, mengontrol status tampilan, dan menangani presentasi gambar yang sebenarnya.

getDisplayInfo() generates (DisplayDesc info);

Menampilkan informasi dasar tentang layar EVS yang disediakan oleh sistem (lihat DisplayDesc).

setDisplayState(DisplayState state) generates (EvsResult result);

Menetapkan status tampilan. Klien dapat menetapkan status tampilan untuk mengekspresikan status yang diinginkan, dan implementasi HAL harus menerima permintaan status apa pun dengan baik saat dalam status lain, meskipun responsnya mungkin mengabaikan permintaan.

Setelah inisialisasi, tampilan ditentukan untuk dimulai dalam status NOT_VISIBLE, setelah itu klien diharapkan untuk meminta status VISIBLE_ON_NEXT_FRAME dan mulai menyediakan video. Jika tampilan tidak lagi diperlukan, klien diharapkan untuk meminta status NOT_VISIBLE setelah meneruskan frame video terakhir.

Status apa pun dapat diminta kapan saja. Jika sudah terlihat, layar akan tetap terlihat jika disetel ke VISIBLE_ON_NEXT_FRAME. Selalu menampilkan OK kecuali jika status yang diminta adalah nilai enum yang tidak dikenal, dalam hal ini INVALID_ARG akan ditampilkan.

getDisplayState() generates (DisplayState state);

Mendapatkan status tampilan. Implementasi HAL harus melaporkan status saat ini yang sebenarnya, yang mungkin berbeda dengan status yang terakhir diminta. Logika yang bertanggung jawab untuk mengubah status tampilan harus ada di atas lapisan perangkat, sehingga implementasi HAL tidak diinginkan untuk mengubah status tampilan 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 buffering eksklusif secara teknis memungkinkan, pengujian kompatibilitas memerlukan buffering 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 buffering 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, buffering 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 menjelaskan tampilan EVS. Dapat berupa layar fisik atau layar virtual yang ditumpangkan atau dicampur dengan perangkat presentasi lain.

  • display_id. String yang secara unik mengidentifikasi tampilan. Nama ini bisa berupa nama perangkat kernel perangkat, atau nama perangkat, seperti spion. 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 buram dari driver ke aplikasi EVS kustom. Informasi ini diteruskan tanpa ditafsirkan dari driver hingga 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 dinonaktifkan (tidak terlihat oleh pengemudi) atau diaktifkan (menampilkan gambar kepada pengemudi). Menyertakan status sementara saat layar belum terlihat, tetapi siap untuk terlihat dengan pengiriman frame gambar berikutnya melalui panggilan returnTargetBufferForDisplay().

Pengelola EVS

Pengelola EVS 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), Pengelola EVS akan 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).

Pengelola EVS menerapkan API yang sama dengan driver HAL yang mendasarinya dan memberikan layanan yang diperluas dengan mendukung beberapa klien serentak (lebih dari satu klien dapat membuka kamera melalui Pengelola EVS dan menerima streaming video).

Diagram EVS Manager dan
EVS Hardware API.

Gambar 2. EVS Manager mencerminkan EVS Hardware API yang mendasarinya.

Aplikasi tidak melihat perbedaan saat beroperasi melalui implementasi HAL Hardware EVS atau EVS Manager API, kecuali bahwa EVS Manager API memungkinkan akses streaming kamera serentak. Pengelola EVS itu sendiri adalah satu 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 Pengelola EVS; panggilan lainnya identik dengan deskripsi HAL EVS.

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

Mendapatkan objek antarmuka yang digunakan untuk berinteraksi dengan kamera tertentu yang diidentifikasi oleh string camera_id yang unik. Mengembalikan NULL saat gagal. Di lapisan Pengelola EVS, selama resource sistem yang memadai tersedia, kamera yang sudah terbuka dapat dibuka lagi oleh proses lain, sehingga memungkinkan pemisahan streaming video ke beberapa aplikasi konsumen. String camera_id di lapisan Pengelola EVS sama dengan yang dilaporkan ke lapisan Hardware EVS.

IEvsCamera

Implementasi IEvsCamera yang disediakan Pengelola EVS 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 pada kamera dasar yang sama. Kamera yang mendasarinya dimulai saat klien pertama dimulai.

doneWithFrame(uint32 frameId, handle bufferHandle) generates (EvsResult result);

Menampilkan frame. Setiap klien harus menampilkan frame-nya setelah selesai, tetapi diizinkan untuk menyimpan frame-nya selama yang diinginkan. Jika jumlah frame yang disimpan oleh klien mencapai batas yang dikonfigurasi, klien tidak akan menerima frame lagi hingga menampilkannya. Pelemparan 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 dihentikan saat klien terakhir dari kamera tertentu menghentikan streamingnya.

setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);

Mengirim nilai khusus driver, yang berpotensi memungkinkan satu klien memengaruhi klien lain. Karena Pengelola EVS 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. Pengelola tidak menambahkan fungsi apa pun dan hanya meneruskan antarmuka IEvsDisplay langsung ke implementasi HAL yang mendasarinya.

Aplikasi EVS

Android menyertakan implementasi referensi C++ native dari aplikasi EVS yang berkomunikasi dengan Pengelola EVS dan HAL Kendaraan 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 memodifikasi atau mengganti aplikasi EVS dengan logika dan presentasi khusus kendaraan mereka sendiri.

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



Gambar 4. Logika contoh aplikasi EVS, menerima callback frame.

Karena data gambar ditampilkan ke aplikasi dalam buffer grafis standar, aplikasi bertanggung jawab untuk memindahkan gambar dari buffer sumber ke buffer output. Meskipun memperkenalkan biaya penyalinan data, cara ini juga menawarkan kesempatan bagi aplikasi untuk merender gambar ke buffer tampilan dengan cara apa pun yang diinginkan.

Misalnya, aplikasi dapat memilih untuk memindahkan data piksel itu sendiri, yang mungkin dengan operasi rotasi atau penskalaan inline. Aplikasi juga dapat memilih untuk menggunakan gambar sumber sebagai tekstur OpenGL dan merender tampilan yang kompleks ke buffering 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).

Gunakan EGL/SurfaceFlinger di EVS Display HAL

Bagian ini menjelaskan cara menggunakan EGL untuk merender implementasi HAL Layar EVS di Android 10.

Implementasi referensi HAL EVS menggunakan EGL untuk merender pratinjau kamera di layar dan menggunakan libgui untuk membuat platform render EGL target. Di Android 8 (dan yang lebih tinggi), libgui diklasifikasikan sebagai VNDK-pribadi, 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 untuk menggunakan Surface dalam implementasi HAL.

Membangun libgui untuk proses vendor

Penggunaan libgui berfungsi sebagai satu-satunya opsi untuk menggunakan EGL/SurfaceFlinger dalam implementasi HAL Layar 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 untuk 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 paket. Karena SurfaceFlinger mengharapkan kolom ini yang telah dihapus, 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 diberikan di bawah ini. Nantikan untuk 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 sehingga tidak dapat diakses oleh proses vendor. Sebagai gantinya, proses vendor harus menggunakan /dev/hwbinder dan harus mengonversi 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. Diperlukan banyak pekerjaan 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 memanggil ini sebelum memanggil Process atau IPCThreadState, atau sebelum melakukan panggilan binder.

Kebijakan SELinux

Jika implementasi perangkat adalah treble penuh, SELinux akan mencegah proses vendor menggunakan /dev/binder. Misalnya, implementasi contoh EVS HAL ditetapkan ke domain hal_evs_driver dan memerlukan izin r/w 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

Akan tetapi, menambahkan izin ini akan menyebabkan kegagalan build karena melanggar aturan "neverallow" berikut yang ditentukan dalam system/sepolicy/domain.te untuk perangkat dengan 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 mendeteksi bug dan memandu pengembangan. Hal 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)

Mem-build implementasi referensi HAL EVS sebagai proses vendor

Sebagai referensi, Anda dapat menerapkan perubahan berikut ke 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;