Kamera Kendaraan HAL

Android berisi Lapisan Abstraksi Perangkat Keras (HAL) HIDL otomotif yang menyediakan pengambilan dan tampilan citra sejak awal proses booting Android dan terus berfungsi sepanjang masa pakai sistem. HAL mencakup tumpukan sistem tampilan eksterior (EVS) dan biasanya digunakan untuk mendukung kamera pandangan belakang dan tampilan tampilan sekeliling pada kendaraan dengan sistem In-Vehicle Infotainment (IVI) berbasis Android. EVS juga memungkinkan fitur-fitur canggih diimplementasikan di aplikasi pengguna.

Android juga menyertakan antarmuka driver tangkapan dan tampilan khusus EVS (di /hardware/interfaces/automotive/evs/1.0 ). Meskipun dimungkinkan untuk membuat aplikasi kamera pandangan belakang di atas layanan kamera dan tampilan Android yang ada, aplikasi semacam itu kemungkinan akan berjalan terlambat dalam proses booting Android. Penggunaan HAL khusus memungkinkan antarmuka yang disederhanakan dan memperjelas apa yang perlu diterapkan oleh OEM untuk mendukung tumpukan EVS.

Komponen sistem

EVS mencakup komponen sistem berikut:

Diagram komponen Sistem EVS

Gambar 1. Ikhtisar komponen sistem EVS.

aplikasi EVS

Contoh aplikasi C++ EVS ( /packages/services/Car/evs/app ) berfungsi sebagai implementasi referensi. Aplikasi ini bertanggung jawab untuk meminta bingkai video dari Manajer EVS dan mengirimkan bingkai yang sudah selesai untuk ditampilkan kembali ke Manajer EVS. Diharapkan dapat dimulai oleh init segera setelah EVS dan Servis Mobil tersedia, ditargetkan dalam waktu dua (2) detik setelah dihidupkan. OEM dapat memodifikasi atau mengganti aplikasi EVS sesuai keinginan.

Manajer EVS

EVS Manager ( /packages/services/Car/evs/manager ) menyediakan elemen penyusun yang diperlukan oleh aplikasi EVS untuk mengimplementasikan apa pun mulai dari tampilan kamera pandangan belakang sederhana hingga rendering multi-kamera 6DOF. Antarmukanya disajikan melalui HIDL dan dibuat untuk menerima beberapa klien secara bersamaan. Aplikasi dan layanan lain (khususnya Layanan Mobil) dapat menanyakan status Manajer 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 implementasi yang melatih antarmuka (menghasilkan gambar pengujian sintetik dan memvalidasi gambar selama perjalanan pulang pergi) disediakan di /hardware/interfaces/automotive/evs/1.0/default .

OEM bertanggung jawab untuk mengimplementasikan API yang dinyatakan oleh file .hal di /hardware/interfaces/automotive/evs . Implementasi tersebut bertanggung jawab untuk mengonfigurasi dan mengumpulkan data dari kamera fisik dan mengirimkannya melalui buffer memori bersama yang dapat dikenali oleh Gralloc. Sisi tampilan implementasi bertanggung jawab untuk menyediakan buffer memori bersama yang dapat diisi oleh aplikasi (biasanya melalui rendering EGL) dan menampilkan frame yang telah selesai dibandingkan dengan frame lain yang mungkin ingin ditampilkan di tampilan fisik. Implementasi vendor dari antarmuka EVS dapat disimpan di /vendor/… /device/… atau hardware/… (misalnya, /hardware/[vendor]/[platform]/evs ).

Driver kernel

Perangkat yang mendukung tumpukan EVS memerlukan driver kernel. Daripada membuat driver baru, OEM memiliki opsi untuk mendukung fitur yang diperlukan EVS melalui driver kamera dan/atau perangkat keras tampilan yang ada. Menggunakan kembali driver dapat bermanfaat, terutama untuk driver tampilan di mana presentasi gambar mungkin memerlukan koordinasi dengan thread aktif lainnya. Android 8.0 menyertakan driver sampel berbasis v4l2 (dalam packages/services/Car/evs/sampleDriver ) yang bergantung pada kernel untuk dukungan v4l2 dan pada SurfaceFlinger untuk menyajikan gambar keluaran.

Deskripsi antarmuka perangkat keras EVS

Bagian ini menjelaskan HAL. Vendor diharapkan menyediakan implementasi API ini yang disesuaikan untuk perangkat keras mereka.

IEvsEnumerator

Objek ini bertanggung jawab untuk menghitung perangkat keras EVS yang tersedia dalam sistem (satu atau lebih kamera dan perangkat tampilan tunggal).

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

Mengembalikan vektor yang berisi deskripsi untuk semua kamera di sistem. Diasumsikan kumpulan kamera sudah diperbaiki dan dapat diketahui pada saat boot. Untuk 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 jika gagal. Upaya untuk membuka kembali kamera yang sudah terbuka tidak akan gagal. Untuk menghindari kondisi balapan yang terkait dengan pengaktifan dan penonaktifan aplikasi, membuka kembali kamera harus mematikan instans sebelumnya sehingga permintaan baru dapat dipenuhi. Contoh kamera yang telah didahului dengan cara ini harus ditempatkan dalam keadaan tidak aktif, menunggu penghancuran akhir dan menanggapi setiap permintaan untuk mempengaruhi keadaan kamera dengan kode pengembalian 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 tampilan EVS sistem. Hanya satu klien yang dapat menyimpan instance fungsional IEvsDisplay pada satu waktu. Mirip dengan perilaku terbuka agresif yang dijelaskan dalam openCamera , objek IEvsDisplay baru dapat dibuat kapan saja dan akan menonaktifkan instance sebelumnya. Instance yang tidak divalidasi tetap ada dan merespons panggilan fungsi dari pemiliknya, namun tidak boleh melakukan operasi mutasi ketika mati. Pada akhirnya, aplikasi klien diharapkan memperhatikan kode pengembalian kesalahan OWNERSHIP_LOST dan menutup serta melepaskan antarmuka yang tidak aktif.

closeDisplay(IEvsDisplay display);

Merilis antarmuka IEvsDisplay (dan merupakan kebalikan dari panggilan openDisplay() ). Buffer luar biasa yang diterima melalui panggilan getTargetBuffer() harus dikembalikan ke tampilan sebelum menutup tampilan.

getDisplayState() generates (DisplayState state);

Mendapatkan status tampilan saat ini. Implementasi HAL harus melaporkan keadaan sebenarnya saat ini, yang mungkin berbeda dari keadaan terakhir yang 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. Jika tampilan saat ini tidak dipegang oleh klien mana pun (melalui panggilan ke openDisplay), maka fungsi ini akan mengembalikan NOT_OPEN . Jika tidak, ini akan melaporkan status Tampilan 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. Bisa berupa nama perangkat kernel atau nama perangkat, seperti spion . Nilai untuk string ini dipilih oleh implementasi HAL dan digunakan secara tidak jelas oleh tumpukan di atas.
  • vendor_flags . Sebuah metode untuk meneruskan informasi kamera khusus secara tidak jelas dari pengemudi ke aplikasi EVS khusus. Hal ini diteruskan tanpa ditafsirkan dari pengemudi hingga aplikasi EVS, yang bebas untuk mengabaikannya.

Kamera IEvs

Objek ini mewakili satu kamera dan merupakan antarmuka utama untuk mengambil gambar.

getCameraInfo() generates (CameraDesc info);

Mengembalikan CameraDesc dari kamera ini.

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

Menentukan kedalaman rantai buffer yang diminta untuk didukung oleh kamera. Hingga jumlah frame ini dapat disimpan secara bersamaan oleh klien IEvsCamera. Jika frame sebanyak ini telah dikirim ke penerima tanpa dikembalikan oleh doneWithFrame , aliran akan melewati frame hingga buffer dikembalikan untuk digunakan kembali. Panggilan ini sah untuk dilakukan kapan saja, bahkan ketika streaming sudah berjalan, dalam hal ini buffer harus ditambahkan atau dihapus dari rantai sebagaimana mestinya. Jika tidak ada panggilan yang dilakukan ke titik masuk ini, IEvsCamera mendukung setidaknya satu frame secara default; dengan lebih dapat diterima.

Jika bufferCount yang diminta tidak dapat diakomodasi, fungsi akan mengembalikan BUFFER_NOT_AVAILABLE atau kode kesalahan relevan lainnya. Dalam hal ini, sistem terus beroperasi dengan nilai yang telah ditetapkan sebelumnya.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Meminta pengiriman bingkai kamera EVS dari kamera ini. IEvsCameraStream mulai menerima panggilan berkala dengan bingkai gambar baru hingga stopVideoStream() dipanggil. Bingkai harus mulai dikirimkan dalam waktu 500 md sejak panggilan startVideoStream dan setelah dimulai, harus dihasilkan minimal 10 FPS. Waktu yang diperlukan untuk memulai streaming video secara efektif diperhitungkan terhadap persyaratan waktu pengaktifan kamera pandangan belakang. Jika streaming tidak dimulai, kode kesalahan harus dikembalikan; jika tidak, OK dikembalikan.

oneway doneWithFrame(BufferDesc buffer);

Mengembalikan bingkai yang dikirimkan ke IEvsCameraStream. Setelah selesai menggunakan bingkai yang dikirimkan ke antarmuka IEvsCameraStream, bingkai tersebut harus dikembalikan ke IEvsCamera untuk digunakan kembali. Tersedia buffer dalam jumlah kecil dan terbatas (mungkin sekecil satu), dan jika persediaan habis, tidak ada lagi frame yang dikirim sampai buffer dikembalikan, yang berpotensi mengakibatkan frame dilewati (buffer dengan pegangan nol menunjukkan akhir aliran dan tidak perlu dikembalikan melalui fungsi ini). Mengembalikan OK jika berhasil, atau kode kesalahan yang sesuai mungkin termasuk INVALID_ARG atau BUFFER_NOT_AVAILABLE .

stopVideoStream();

Menghentikan pengiriman bingkai kamera EVS. Karena pengiriman tidak sinkron, frame mungkin terus berdatangan selama beberapa waktu setelah panggilan ini kembali. Setiap frame harus dikembalikan hingga penutupan aliran diberi sinyal ke IEvsCameraStream. Memanggil stopVideoStream pada streaming yang sudah dihentikan atau belum pernah dimulai adalah hal yang sah, sehingga akan diabaikan.

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

Meminta informasi khusus pengemudi dari implementasi HAL. Nilai yang diperbolehkan untuk opaqueIdentifier bersifat khusus untuk driver, namun nilai yang tidak diteruskan dapat membuat driver crash. Pengemudi harus mengembalikan 0 untuk opaqueIdentifier yang tidak dikenali.

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

Mengirimkan nilai khusus driver ke implementasi HAL. Ekstensi ini disediakan hanya untuk memfasilitasi ekstensi khusus kendaraan dan implementasi HAL tidak memerlukan panggilan ini agar berfungsi dalam keadaan default. Jika pengemudi mengenali dan menerima nilainya, OK harus dikembalikan; jika tidak, INVALID_ARG atau kode kesalahan perwakilan lainnya harus dikembalikan.

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 melewati API. Drive HAL bertanggung jawab untuk mengisi struktur ini untuk mendeskripsikan buffer gambar dan klien HAL harus memperlakukan struktur ini sebagai hanya-baca. Bidang tersebut berisi informasi yang cukup untuk memungkinkan klien merekonstruksi objek ANativeWindowBuffer , yang mungkin diperlukan untuk menggunakan gambar dengan EGL melalui ekstensi eglCreateImageKHR() .

  • width . Lebar dalam piksel dari gambar yang disajikan.
  • height . Tinggi dalam piksel dari gambar yang disajikan.
  • stride . Jumlah piksel yang sebenarnya ditempati setiap baris dalam memori, memperhitungkan padding apa pun untuk penyelarasan baris. Dinyatakan dalam piksel agar sesuai dengan konvensi yang diadopsi oleh gralloc untuk deskripsi buffernya.
  • pixelSize . Jumlah byte yang ditempati oleh masing-masing piksel, memungkinkan penghitungan ukuran dalam byte yang diperlukan untuk berpindah antar baris dalam gambar ( stride in bytes = stride in pixel * pixelSize ).
  • format . Format piksel yang digunakan oleh gambar. Format yang disediakan harus kompatibel dengan implementasi OpenGL platform. Agar lulus pengujian kompatibilitas, HAL_PIXEL_FORMAT_YCRCB_420_SP sebaiknya diutamakan untuk penggunaan kamera, dan RGBA atau BGRA sebaiknya diutamakan untuk tampilan.
  • usage . Tanda penggunaan yang ditetapkan oleh implementasi HAL. Klien HAL diharapkan meneruskan ini tanpa modifikasi (untuk detailnya, lihat tanda 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 dalam bidang ini dapat dipilih secara sewenang-wenang oleh implementasi HAL.
  • memHandle . Pegangan untuk buffer memori dasar yang berisi data gambar. Implementasi HAL mungkin memilih untuk menyimpan pegangan buffer Gralloc di sini.

IEvsCameraStream

Klien mengimplementasikan antarmuka ini untuk menerima pengiriman bingkai video asinkron.

deliverFrame(BufferDesc buffer);

Menerima panggilan dari HAL setiap kali frame video siap untuk diperiksa. Pegangan buffer yang diterima oleh metode ini harus dikembalikan melalui panggilan ke IEvsCamera::doneWithFrame() . Saat streaming video dihentikan melalui panggilan ke IEvsCamera::stopVideoStream() , callback ini mungkin berlanjut saat alur terkuras. Setiap frame tetap harus dikembalikan; ketika frame terakhir dalam aliran telah dikirimkan, bufferHandle NULL akan dikirimkan, menandakan akhir aliran dan tidak ada pengiriman bingkai lebih lanjut yang terjadi. BufferHandle NULL itu sendiri tidak perlu dikirim kembali melalui doneWithFrame() , tetapi semua pegangan lainnya harus dikembalikan

Meskipun format buffer berpemilik secara teknis memungkinkan, pengujian kompatibilitas mengharuskan buffer 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 Disisipkan), RGBA (32 bit R:G:B:x), BGRA (32 bit B:G:R:x). Format yang dipilih harus merupakan sumber tekstur GL yang valid pada implementasi GLES platform.

Aplikasi tidak boleh bergantung pada korespondensi apa pun antara bidang bufferId dan memHandle dalam struktur BufferDesc . Nilai bufferId pada dasarnya bersifat pribadi untuk implementasi driver HAL, dan nilai tersebut dapat digunakan (dan digunakan kembali) sesuai keinginan.

Tampilan IEvs

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

getDisplayInfo() generates (DisplayDesc info);

Mengembalikan informasi dasar tentang tampilan EVS yang disediakan oleh sistem (lihat DisplayDesc ).

setDisplayState(DisplayState state) generates (EvsResult result);

Mengatur status tampilan. Klien dapat mengatur status tampilan untuk menyatakan status yang diinginkan, dan implementasi HAL harus dengan baik hati menerima permintaan untuk status apa pun saat berada di status lain, meskipun responsnya mungkin mengabaikan permintaan tersebut.

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

Ini berlaku untuk negara bagian mana pun untuk diminta kapan saja. Jika tampilan sudah terlihat, tampilan akan tetap terlihat jika disetel ke VISIBLE_ON_NEXT_FRAME . Selalu mengembalikan OK kecuali status yang diminta adalah nilai enum yang tidak dikenal, dalam hal ini INVALID_ARG dikembalikan.

getDisplayState() generates (DisplayState state);

Mendapatkan status tampilan. Implementasi HAL harus melaporkan keadaan sebenarnya saat ini, yang mungkin berbeda dari keadaan terakhir yang 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);

Mengembalikan pegangan ke buffer bingkai yang terkait dengan tampilan. Buffer ini mungkin dikunci dan ditulis oleh perangkat lunak dan/atau GL. Buffer ini harus dikembalikan melalui panggilan ke returnTargetBufferForDisplay() meskipun tampilan tidak lagi terlihat.

Meskipun format buffer berpemilik secara teknis memungkinkan, pengujian kompatibilitas mengharuskan buffer 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 Disisipkan), RGBA (32 bit R:G:B:x), BGRA (32 bit B:G:R:x). Format yang dipilih harus merupakan target render GL yang valid pada implementasi GLES platform.

Jika terjadi kesalahan, buffer dengan pegangan null dikembalikan, tetapi buffer tersebut tidak perlu diteruskan kembali ke returnTargetBufferForDisplay .

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

Memberitahukan tampilan 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. Mengembalikan OK jika berhasil, atau kode kesalahan yang sesuai mungkin termasuk INVALID_ARG atau BUFFER_NOT_AVAILABLE .

struct DisplayDesc {
     string  display_id;
     int32   vendor_flags;  // Opaque value
}

Menjelaskan properti dasar tampilan EVS dan diperlukan oleh implementasi EVS. HAL bertanggung jawab untuk mengisi struktur ini untuk menggambarkan tampilan EVS. Dapat berupa tampilan fisik atau tampilan virtual yang di-overlay atau dicampur dengan perangkat presentasi lainnya.

  • display_id . Sebuah string yang secara unik mengidentifikasi tampilan. Ini bisa berupa nama perangkat kernel dari perangkat tersebut, atau nama perangkat tersebut, seperti spion . Nilai untuk string ini dipilih oleh implementasi HAL dan digunakan secara tidak jelas oleh tumpukan di atas.
  • vendor_flags . Sebuah metode untuk meneruskan informasi kamera khusus secara tidak jelas dari pengemudi ke aplikasi EVS khusus. Hal ini diteruskan tanpa ditafsirkan dari pengemudi hingga aplikasi EVS, yang bebas untuk 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 keadaan tampilan EVS, yang dapat dinonaktifkan (tidak terlihat oleh pengemudi) atau diaktifkan (menampilkan gambar kepada pengemudi). Menyertakan keadaan sementara saat tampilan belum terlihat namun dipersiapkan untuk terlihat dengan pengiriman bingkai citra berikutnya melalui panggilan returnTargetBufferForDisplay() .

Manajer EVS

EVS Manager menyediakan antarmuka publik ke sistem EVS untuk mengumpulkan dan menyajikan tampilan kamera eksternal. Jika driver perangkat keras hanya mengizinkan satu antarmuka aktif per sumber daya (kamera atau layar), Manajer EVS memfasilitasi akses bersama ke kamera. Satu aplikasi EVS utama adalah klien pertama dari Manajer EVS, dan merupakan satu-satunya klien yang diizinkan untuk menulis data tampilan (klien tambahan dapat diberikan akses hanya baca ke gambar kamera).

EVS Manager mengimplementasikan API yang sama dengan driver HAL yang mendasarinya dan menyediakan layanan yang diperluas dengan mendukung beberapa klien secara bersamaan (lebih dari satu klien dapat membuka kamera melalui EVS Manager dan menerima aliran video).

Diagram EVS Manager dan API Perangkat Keras EVS.

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

Aplikasi tidak melihat perbedaan saat beroperasi melalui implementasi EVS Hardware HAL atau EVS Manager API kecuali bahwa EVS Manager API mengizinkan akses aliran kamera secara bersamaan. EVS Manager sendiri merupakan klien yang diizinkan dari lapisan HAL Perangkat Keras EVS, dan bertindak sebagai proksi untuk HAL Perangkat Keras EVS.

Bagian berikut hanya menjelaskan panggilan-panggilan yang memiliki perilaku berbeda (diperluas) dalam implementasi 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. Mengembalikan NULL jika gagal. Pada lapisan EVS Manager, selama sumber daya sistem mencukupi tersedia, kamera yang sudah terbuka dapat dibuka kembali oleh proses lain, sehingga memungkinkan streaming video ke beberapa aplikasi konsumen. String camera_id pada lapisan EVS Manager sama dengan yang dilaporkan pada lapisan EVS Hardware.

Kamera IEvs

Implementasi IEvsCamera yang disediakan oleh Manajer EVS divirtualisasikan secara internal sehingga pengoperasian 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 secara mandiri memulai dan menghentikan streaming video pada kamera dasar yang sama. Kamera yang mendasarinya dimulai saat klien pertama dimulai.

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

Mengembalikan bingkai. Setiap klien harus mengembalikan bingkainya setelah selesai, namun diizinkan untuk menyimpan bingkainya selama yang mereka inginkan. Ketika jumlah frame yang ditahan oleh klien mencapai batas yang dikonfigurasi, klien tidak akan menerima frame lagi sampai klien mengembalikan satu frame. Lompatan frame ini tidak mempengaruhi klien lain, yang terus menerima semua frame seperti yang diharapkan.

stopVideoStream();

Menghentikan aliran video. Setiap klien dapat menghentikan streaming videonya kapan saja tanpa mempengaruhi klien lainnya. Aliran kamera yang mendasari pada lapisan perangkat keras dihentikan ketika klien terakhir dari kamera tertentu menghentikan alirannya.

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

Mengirimkan nilai khusus driver, yang berpotensi memungkinkan satu klien memengaruhi klien lain. Karena Manajer EVS tidak dapat memahami implikasi dari kata-kata kontrol yang ditentukan vendor, kata-kata tersebut tidak divirtualisasikan dan efek samping apa pun berlaku untuk semua klien kamera tertentu. Misalnya, jika vendor menggunakan panggilan ini untuk mengubah kecepatan bingkai, semua klien dari kamera lapisan perangkat keras yang terpengaruh akan menerima bingkai dengan kecepatan baru.

Tampilan IEvs

Hanya satu pemilik layar yang diperbolehkan, bahkan pada level Manajer EVS. Manajer tidak menambahkan fungsionalitas dan hanya meneruskan antarmuka IEvsDisplay langsung ke implementasi HAL yang mendasarinya.

aplikasi EVS

Android menyertakan implementasi referensi C++ asli dari aplikasi EVS yang berkomunikasi dengan EVS Manager dan Vehicle HAL untuk menyediakan fungsi dasar kamera pandangan belakang. Aplikasi ini diharapkan dimulai sangat awal dalam proses booting sistem, dengan video yang sesuai ditampilkan tergantung pada kamera yang tersedia dan kondisi mobil (keadaan gigi dan lampu sein). OEM dapat memodifikasi 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, menerima panggilan balik bingkai.

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

Misalnya, aplikasi dapat memilih untuk memindahkan data piksel itu sendiri, kemungkinan dengan operasi skala inline atau rotasi. Aplikasi juga dapat memilih untuk menggunakan gambar sumber sebagai tekstur OpenGL dan merender adegan kompleks ke buffer keluaran, termasuk elemen virtual seperti ikon, pedoman, dan animasi. Aplikasi yang lebih canggih juga dapat memilih beberapa kamera masukan secara bersamaan dan menggabungkannya ke dalam bingkai keluaran tunggal (seperti untuk digunakan dalam tampilan virtual atas-bawah di sekitar kendaraan).

Gunakan EGL/SurfaceFlinger di EVS Display HAL

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

Implementasi referensi EVS HAL menggunakan EGL untuk merender pratinjau kamera di layar dan menggunakan libgui untuk membuat permukaan render EGL target. Di Android 8 (dan lebih tinggi), libgui diklasifikasikan sebagai VNDK-private , yang mengacu pada sekelompok perpustakaan yang tersedia untuk perpustakaan VNDK yang tidak dapat digunakan oleh proses vendor. Karena implementasi HAL harus berada di partisi vendor, vendor dilarang menggunakan Surface dalam implementasi HAL.

Membangun libgui untuk proses vendor

Penggunaan libgui berfungsi sebagai satu-satunya pilihan untuk menggunakan EGL/SurfaceFlinger dalam implementasi EVS Display HAL. Cara paling mudah untuk mengimplementasikan libgui adalah melalui frameworks/native/libs/gui secara langsung dengan menggunakan target build tambahan di skrip build. Target ini sama persis dengan target libgui kecuali ada 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 bidang ini telah dihapus, SurfaceFlinger gagal menguraikan paket tersebut. 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 instruksi pembuatan disediakan di bawah ini. Berharap 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

Gunakan pengikat dalam implementasi EVS HAL

Di Android 8 (dan lebih tinggi), node perangkat /dev/binder menjadi eksklusif untuk proses framework dan, oleh karena itu, tidak dapat diakses oleh proses vendor. Sebaliknya, proses vendor harus menggunakan /dev/hwbinder dan harus mengubah antarmuka AIDL apa pun menjadi HIDL. Bagi mereka yang ingin terus menggunakan antarmuka AIDL antar proses vendor, gunakan domain pengikat, /dev/vndbinder .

Domain IPC Keterangan
/dev/binder IPC antara proses kerangka/aplikasi dengan antarmuka AIDL
/dev/hwbinder IPC antara proses framework/vendor dengan antarmuka HIDL
IPC antar proses vendor dengan antarmuka HIDL
/dev/vndbinder IPC antara proses vendor/vendor dengan Antarmuka AIDL

Meskipun SurfaceFlinger mendefinisikan antarmuka AIDL, proses vendor hanya dapat menggunakan antarmuka HIDL untuk berkomunikasi dengan proses kerangka kerja. Dibutuhkan banyak pekerjaan untuk mengubah antarmuka AIDL yang ada menjadi HIDL. Untungnya, Android menyediakan metode untuk memilih driver binder untuk libbinder , yang mana proses perpustakaan userspace ditautkan.

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 pengikat apa pun.

kebijakan SELinux

Jika implementasi perangkat adalah treble penuh, SELinux mencegah penggunaan proses vendor /dev/binder . Misalnya, implementasi sampel EVS HAL ditugaskan 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

Namun, menambahkan izin ini akan 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 menangkap bug dan memandu pengembangan. Ini juga dapat digunakan untuk mengatasi 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)

Bangun implementasi referensi EVS HAL 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;