Android, Android başlatma işleminin çok başında görüntü yakalama ve görüntüleme sağlayan ve sistem ömrü boyunca çalışmaya devam eden bir otomotiv HIDL Donanım Soyutlama Katmanı (HAL) içerir. HAL, dış görüntü sistemi (EVS) yığınını içerir ve genellikle Android tabanlı araç içi bilgi-eğlence (IVI) sistemlerine sahip araçlarda arka görüş kamerasını ve çevresel görüntüleme ekranlarını desteklemek için kullanılır. EVS, kullanıcı uygulamalarında gelişmiş özelliklerin uygulanmasını da sağlar.
Android, EVS'ye özel bir yakalama ve görüntüleme sürücü arayüzü de içerir (/hardware/interfaces/automotive/evs/1.0
içinde). Mevcut Android kamera ve görüntüleme hizmetlerinin üzerine bir arka görüş kamerası uygulaması oluşturmak mümkün olsa da bu tür bir uygulama, Android önyükleme sürecinde muhtemelen çok geç çalışır. Özel bir HAL kullanmak, basitleştirilmiş bir arayüz sağlar ve OEM'lerin EVS yığınını desteklemek için neleri uygulaması gerektiğini netleştirir.
Sistem bileşenleri
EVS aşağıdaki sistem bileşenlerini içerir:
Şekil 1. EVS sistem bileşenlerine genel bakış.
EVS uygulaması
Referans uygulama olarak örnek bir C++ EVS uygulaması (/packages/services/Car/evs/app
) kullanılır. Bu uygulama, EVS Yöneticisi'nden video kareleri istemekten ve tamamlanmış kareleri görüntüleme için EVS Yöneticisi'ne geri göndermekten sorumludur.
EVS ve Araba Hizmeti kullanılabilir olduğunda başlatılmaya başlanması bekleniyor. Hizmet verildikten sonra iki (2) saniye içinde hedeflenecek. OEM'ler EVS uygulamasını istedikleri gibi değiştirebilir veya değiştirebilir.
EVS Yöneticisi
EVS Yöneticisi (/packages/services/Car/evs/manager
), basit bir arka görüş kamerası ekranından 6 serbestlik dereceli çok kameralı oluşturmaya kadar her şeyi uygulamak için EVS uygulamasının ihtiyaç duyduğu yapı taşlarını sağlar. Arayüzü HIDL ile sunulur ve birden fazla eşzamanlı istemciyi kabul edecek şekilde tasarlanmıştır.
Diğer uygulamalar ve hizmetler (özellikle Araç Servisi), EVS sisteminin ne zaman etkin olduğunu öğrenmek için EVS Yöneticisi durumunu sorgulayabilir.
EVS HIDL arayüzü
Hem kamera hem de ekran öğeleri olan EVS sistemi, android.hardware.automotive.evs
paketinde tanımlanır. Arayüzü kullanan (sentetik test resimleri oluşturur ve resimlerin gidip geldiğini doğrular) örnek bir uygulama /hardware/interfaces/automotive/evs/1.0/default
'te sağlanmıştır.
/hardware/interfaces/automotive/evs
içindeki .hal dosyalarında ifade edilen API'nin uygulanmasından OEM sorumludur. Bu tür uygulamalar, fiziksel kameralardan veri yapılandırmaktan, toplamak ve Gralloc tarafından tanınabilen paylaşılan bellek arabellekleri aracılığıyla yayınlamaktan sorumludur. Uygulamanın ekran tarafı, uygulama tarafından doldurulabilecek paylaşılan bir bellek arabelleği sağlamaktan (genellikle EGL oluşturma yoluyla) ve tamamlanmış kareleri, fiziksel ekranda görünebilecek diğer her şeye tercih ederek sunmaktan sorumludur. EVS arayüzünün tedarikçi firma uygulamaları /vendor/… /device/…
veya hardware/…
altında (ör.
/hardware/[vendor]/[platform]/evs
) bilgileri gösterilir.
Çekirdek sürücüleri
EVS yığınını destekleyen bir cihaz için çekirdek sürücüleri gerekir. OEM'ler, yeni sürücüler oluşturmak yerine mevcut kamera ve/veya ekran donanım sürücüleri aracılığıyla EVS için gerekli özellikleri destekleme seçeneğine sahiptir. Sürücüleri yeniden kullanmak, özellikle de görüntü sunumunun diğer etkin iş parçacıklarıyla koordinasyon gerektirebileceği görüntü sürücüleri için avantajlı olabilir. Android 8.0, v4l2 desteği için çekirdeğe ve çıkış görüntüsünü sunmak için SurfaceFlinger'a dayanan v4l2 tabanlı bir örnek sürücü (packages/services/Car/evs/sampleDriver
içinde) içerir.
EVS donanım arayüzü açıklaması
Bu bölümde HAL açıklanmaktadır. Tedarikçi firmaların, bu API'nin donanımlarına göre uyarlanmış uygulamalarını sağlaması beklenir.
IEvsEnumerator
Bu nesne, sistemdeki kullanılabilir EVS donanımını (bir veya daha fazla kamera ve tek ekranlı cihaz) numaralandırmaktan sorumludur.
getCameraList() generates (vec<CameraDesc> cameras);
Sistemdeki tüm kameraların açıklamalarını içeren bir vektörü döndürür. Kamera grubunun sabit olduğu ve başlatma sırasında bilindiği varsayılmıştır. Kamera açıklamaları hakkında ayrıntılı bilgi için CameraDesc
başlıklı makaleyi inceleyin.
openCamera(string camera_id) generates (IEvsCamera camera);
Benzersiz camera_id dizesi ile tanımlanan belirli bir kamerayla etkileşim kurmak için kullanılan bir arayüz nesnesi alır. Başarısız olursa NULL döndürür.
Halihazırda açık olan bir kamerayı yeniden açma denemeleri başarısız olamaz. Uygulamanın başlatılması ve kapatılmasıyla ilişkili yarış koşullarını önlemek için kameranın yeniden açılması, yeni isteğinin yerine getirilebilmesi için önceki örneğin kapatılmasını sağlar. Bu şekilde öncelik verilen bir kamera örneği, nihai imha işlemini bekleyen ve kamera durumunu etkileme isteklerine OWNERSHIP_LOST
döndürme koduyla yanıt veren etkin olmayan bir duruma getirilmelidir.
closeCamera(IEvsCamera camera);
IEvsCamera arayüzünü serbest bırakır (openCamera()
çağrısının tam tersidir). closeCamera
çağrılmadan önce stopVideoStream()
çağrılarak kamera video akışı durdurulmalıdır.
openDisplay() generates (IEvsDisplay display);
Yalnızca sistemin EVS ekranıyla etkileşim kurmak için kullanılan bir arayüz nesnesi alır. Aynı anda yalnızca bir müşteri işlevsel IEvsDisplay örneğini barındırabilir. openCamera
bölümünde açıklanan agresif açma davranışına benzer şekilde, dilediğiniz zaman yeni bir IEvsDisplay nesnesi oluşturulabilir ve önceki örnekler devre dışı bırakılır. Geçersiz kılınan örnekler var olmaya devam eder ve sahiplerinden gelen işlev çağrılarına yanıt verir ancak ölü olduklarında hiçbir mutasyon işlemi gerçekleştirmemelidir. En sonunda, istemci uygulamasının OWNERSHIP_LOST
hata döndürme kodlarını fark edip etkin olmayan arayüzü kapatıp kullanıma sunması beklenir.
closeDisplay(IEvsDisplay display);
IEvsDisplay arayüzünü serbest bırakır (openDisplay()
çağrısının tam tersidir). getTargetBuffer()
çağrıları aracılığıyla alınan bekleyen arabellekler, ekran kapatılmadan önce ekrana döndürülmelidir.
getDisplayState() generates (DisplayState state);
Mevcut ekran durumunu alır. HAL uygulaması, mevcut gerçek durumu bildirmelidir. Bu durum, en son istenen durumdan farklı olabilir.
Ekran durumlarını değiştirmekten sorumlu mantık, cihaz katmanının üzerinde olmalıdır. Bu nedenle, HAL uygulamasının ekran durumlarını kendiliğinden değiştirmesi istenmez. Ekran şu anda herhangi bir istemci tarafından (openDisplay çağrısıyla) barındırılmıyorsa bu işlev NOT_OPEN
değerini döndürür. Aksi takdirde, EVS ekranının mevcut durumunu bildirir (IEvsDisplay API'ye bakın).
struct CameraDesc { string camera_id; int32 vendor_flags; // Opaque value }
camera_id
. Belirli bir kamerayı benzersiz şekilde tanımlayan dize. Cihazın çekirdek cihaz adı veya cihaz adı (ör. arka görünüm) olabilir. Bu dizenin değeri HAL uygulaması tarafından seçilir ve yukarıdaki yığın tarafından opak olarak kullanılır.vendor_flags
. Özel kamera bilgilerini sürücüden özel bir EVS uygulamasına şeffaf olmayan bir şekilde iletmek için kullanılan bir yöntem. Bu bilgi, sürücüden yorumlanmadan EVS uygulamasına iletilir. Bu uygulamayı görmezden gelebilirsiniz.
IEvsKamera
Bu nesne tek bir kamerayı temsil eder ve resim çekmek için birincil arayüzdür.
getCameraInfo() generates (CameraDesc info);
Bu kameradan CameraDesc
tanesini döndürür.
setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);
Kameranın desteklemesi gereken arabellek zincirinin derinliğini belirtir. IEvsCamera istemcisi bu kadar kareyi aynı anda tutabilir. Bu sayıda kare, doneWithFrame
tarafından iade edilmeden alıcıya teslim edilmişse akış, yeniden kullanılmak üzere bir arabellek döndürülene kadar kareleri atlar. Bu çağrının, akışlar zaten çalışırken bile herhangi bir zamanda gelmesi yasaldır. Bu durumda, uygun şekilde zincire arabellekler eklenmeli veya zincirden kaldırılmalıdır. Bu giriş noktasına çağrı yapılmazsa IEvsKamera varsayılan olarak en az bir kareyi destekler (daha kabul edilebilir bir çerçeve).
İstenen bufferCount karşılanamazsa işlev BUFFER_NOT_AVAILABLE
veya başka bir ilgili hata kodu döndürür. Bu durumda sistem, daha önce ayarlanmış değerle çalışmaya devam eder.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Bu kameradan EVS kamera karelerinin yayınlanmasını ister. IEvsCameraStream, stopVideoStream()
çağrılana kadar yeni resim kareleri içeren periyodik çağrılar almaya başlar. Çerçeveler, startVideoStream
çağrısından sonraki 500 ms içinde yayınlanmaya başlamalı ve başladıktan sonra en az 10 FPS'de oluşturulmalıdır. Video aktarımını başlatmak için gereken süre, arka görüş kamerasının başlatma süresi koşuluna dahil edilir. Akış başlatılmadıysa bir hata kodu döndürülmelidir. Aksi takdirde OK döndürülür.
oneway doneWithFrame(BufferDesc buffer);
IEvsCameraStream tarafından yayınlanan bir kareyi döndürür. IEvsKameraStream arayüzüne gönderilen bir kareyi tüketme işlemi tamamlandığında, çerçeve yeniden kullanılmak üzere IEvsKamera'ya döndürülmelidir. Az sayıda, sonlu sayıda arabellek kullanılabilir (muhtemelen bir tane kadar az). Kaynak tükenirse bir arabellek döndürülene kadar başka çerçeve gönderilmez. Bu da atlanan karelere neden olabilir (boş bir tutamağa sahip arabellek, bir aktarımın sonunu belirtir ve bu işlev aracılığıyla döndürülmesi gerekmez). Başarılı olduğunda OK değerini veya INVALID_ARG
ya da BUFFER_NOT_AVAILABLE
içerebilecek uygun hata kodunu döndürür.
stopVideoStream();
EVS kamera karelerinin yayınlanmasını durdurur. Yayınlama işlemi eşzamanlı olmadığından, bu çağrı döndükten sonra bir süre daha kareler gelmeye devam edebilir. Akış kapatılma sinyali IEvsCameraStream'e gönderilene kadar her kare döndürülmelidir. stopVideoStream
işlevinin, durdurulmuş veya hiç başlatılmamış bir akışta çağrılması yasaldır. Bu durumda işlev yoksayılır.
getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);
HAL uygulamasından sürücüye özel bilgileri ister. opaqueIdentifier
için izin verilen değerler sürücüye özeldir ancak iletilen hiçbir değer sürücüyü kilitleyemez. Sürücü, tanınmayan opaqueIdentifier
için 0 döndürmelidir.
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
HAL uygulamasına sürücüye özgü bir değer gönderir. Bu uzantı yalnızca araca özgü uzantıları kolaylaştırmak için sağlanmıştır ve hiçbir HAL uygulamasının bu çağrının varsayılan durumda çalışmasını gerektirmesi gerekmez. Sürücü değerleri tanır ve kabul ederse OK döndürülmelidir. Aksi takdirde INVALID_ARG
veya başka bir temsili hata kodu döndürülmelidir.
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 }
API üzerinden geçirilen bir görüntüyü açıklar. HAL sürücüsü, resim arabelleğini tanımlamak için bu yapıyı doldurmaktan sorumludur ve HAL istemcisi bu yapıyı salt okunur olarak ele almalıdır. Resmi eglCreateImageKHR()
uzantısı aracılığıyla EGL ile kullanmak gerekebileceğinden alanlar, istemcinin bir ANativeWindowBuffer
nesnesini yeniden oluşturmasına olanak tanıyacak kadar bilgi içerir.
width
. Sunulan resmin piksel cinsinden genişliği.height
. Sunulan resmin piksel cinsinden yüksekliği.stride
: Satırın hizalanması için yapılan dolguların hesaba katılması koşuluyla, her satırın bellekte kapladığı gerçek piksel sayısı. gralloc'un arabellek açıklamaları için benimsediği kurala uyması amacıyla piksel cinsinden ifade edilir.pixelSize
: Her bir pikselin kapladığı bayt sayısıdır. Bu sayede, resimdeki satırlar arasında geçiş yapmak için gereken bayt cinsinden boyutun hesaplanması sağlanır (bayt cinsindenstride
= piksel cinsindenstride
*pixelSize
).format
. Resim tarafından kullanılan piksel biçimi. Sağlanan biçim, platformun OpenGL uygulamasıyla uyumlu olmalıdır. Uyumluluk testini geçmek için kamera kullanımı içinHAL_PIXEL_FORMAT_YCRCB_420_SP
, ekran için iseRGBA
veyaBGRA
tercih edilmelidir.usage
. HAL uygulaması tarafından ayarlanan kullanım işaretleri. HAL istemcilerinin bu bilgileri değiştirmeden iletmesi beklenir (ayrıntılar içinGralloc.h
ile ilgili işaretlere bakın).bufferId
. HAL API'leri üzerinden gidip geldikten sonra bir arabelleğin tanınmasına izin vermek için HAL uygulaması tarafından belirtilen benzersiz bir değer. Bu alanda depolanan değer, HAL uygulaması tarafından keyfi olarak seçilebilir.memHandle
. Görüntü verilerini içeren temel bellek arabelleğinin tutma yeridir. HAL uygulaması burada bir Gralloc arabelleği tutamacını depolayabilir.
IEvsKamera Akışı
İstemci, video karelerini asynkron olarak almak için bu arayüzü uygular.
deliverFrame(BufferDesc buffer);
Bir video karesi incelemeye hazır olduğunda HAL'den çağrı alır.
Bu yöntem tarafından alınan arabellek herkese açık kullanıcı adları, IEvsCamera::doneWithFrame()
çağrılarıyla döndürülmelidir. Video akışı IEvsCamera::stopVideoStream()
çağrısıyla durdurulduğunda, ardışık düzen boşaltılırken bu geri çağırma devam edebilir. Her kare yine de döndürülmelidir. Akıştaki son kare yayınlandığında, akış sonunu ve başka kare yayınlanmayacağını belirten NULL bir bufferHandle yayınlanır. NULL bufferHandle değerinin doneWithFrame()
üzerinden geri gönderilmesi gerekmez ancak diğer tüm handle değerlerinin döndürülmesi gerekir.
Özel arabellek biçimleri teknik olarak mümkün olsa da uyumluluk testinde arabelleğin desteklenen dört biçimden birinde olması gerekir: NV21 (YCrCb 4:2:0 Yarı Düzlem), YV12 (YCrCb 4:2:0 Düzlem), YUYV (YCrCb 4:2:2 Aralıklı), RGBA (32 bit R:G:B:x), BGRA (32 bit B:G:R:x). Seçilen biçim, platformun GLES uygulamasında geçerli bir GL doku kaynağı olmalıdır.
Uygulama, BufferDesc
yapısındaki bufferId
alanı ile memHandle
arasında herhangi bir yazışma kullanmamalıdır. bufferId
değerleri temel olarak HAL sürücü uygulamasına özeldir ve sürücü bunları uygun gördüğü şekilde kullanabilir (ve yeniden kullanabilir).
IEvsEkran
Bu nesne, Evs ekranını temsil eder, ekranın durumunu kontrol eder ve resimlerin gerçek sunumunu yönetir.
getDisplayInfo() generates (DisplayDesc info);
Sistem tarafından sağlanan EVS ekranıyla ilgili temel bilgileri döndürür (DisplayDesc bölümüne bakın).
setDisplayState(DisplayState state) generates (EvsResult result);
Ekran durumunu ayarlar. İstemciler, görüntüleme durumunu istenen durumu ifade edecek şekilde ayarlayabilir. HAL uygulaması, başka bir durumdayken herhangi bir durumla ilgili isteği nazikçe kabul etmelidir. Yanıt, isteği yoksaymak olabilir.
Gösterim, başlatıldığında NOT_VISIBLE
durumunda başlamak üzere tanımlanır. Ardından istemcinin VISIBLE_ON_NEXT_FRAME
durumunu istemesi ve video sağlamaya başlaması beklenir. Ekran artık gerekli olmadığında istemcinin, son video karesini geçtikten sonra NOT_VISIBLE
durumunu istemesi beklenir.
Bu, herhangi bir eyalette herhangi bir zamanda istenebilecekler için geçerlidir. Ekran zaten görünür durumdaysa VISIBLE_ON_NEXT_FRAME
değerine ayarlanmışsa görünür kalması gerekir. İstenilen durum tanınmayan bir enum değeri olmadığı sürece her zaman OK değerini döndürür. Tanınmayan bir enum değeri ise INVALID_ARG
döndürülür.
getDisplayState() generates (DisplayState state);
Ekran durumunu alır. HAL uygulaması, mevcut gerçek durumu bildirmelidir. Bu durum, en son istenen durumdan farklı olabilir. Ekran durumlarının değiştirilmesinden sorumlu mantık, cihaz katmanının üzerinde bulunmalıdır. Bu, HAL uygulamasının ekran durumlarının istenmeyen bir şekilde değiştirilmesini istenmez.
getTargetBuffer() generates (handle bufferHandle);
Ekranla ilişkili bir çerçeve arabelleğinin tutamacını döndürür. Bu arabellek, yazılım ve/veya GL tarafından kilitlenebilir ve üzerine yazılabilir. Ekran artık görünmüyor olsa bile bu arabellek, returnTargetBufferForDisplay()
çağrısı aracılığıyla döndürülmelidir.
Özel arabellek biçimleri teknik olarak mümkün olsa da uyumluluk testinde arabelleğin desteklenen dört biçimden birinde olması gerekir: NV21 (YCrCb 4:2:0 Yarı Düzlem), YV12 (YCrCb 4:2:0 Düzlem), YUYV (YCrCb 4:2:2 Aralıklı), RGBA (32 bit R:G:B:x), BGRA (32 bit B:G:R:x). Seçilen biçim, platformun GLES uygulamasında geçerli bir GL oluşturma hedefi olmalıdır.
Yanlışlıkla, boş herkese açık kullanıcı adına sahip bir arabellek döndürülür ancak böyle bir arabelleğin, returnTargetBufferForDisplay
işlevine geri gönderilmesi gerekmez.
returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);
Ekranı, arabelleğin görüntülenmeye hazır olduğunu bildirir. Yalnızca getTargetBuffer()
çağrısı aracılığıyla alınan arabellekler bu çağrıda kullanılabilir. BufferDesc
içeriği istemci uygulaması tarafından değiştirilemez. Bu çağrıdan sonra arabellek istemci tarafından kullanılamaz. Başarılı olduğunda OK değerini veya INVALID_ARG
ya da BUFFER_NOT_AVAILABLE
içerebilecek uygun hata kodunu döndürür.
struct DisplayDesc { string display_id; int32 vendor_flags; // Opaque value }
EVS ekranının temel özelliklerini ve EVS uygulaması için gerekenleri açıklar. HAL, EVS ekranını tanımlamak için bu yapıyı doldurmaktan sorumludur. Fiziksel bir ekran veya başka bir sunum cihazıyla örtüşen ya da karıştırılan sanal bir ekran olabilir.
display_id
. Ekranı benzersiz şekilde tanımlayan bir dize. Bu, cihazın çekirdek cihaz adı veya cihazın adı (ör. arka görüş) olabilir. Bu dizenin değeri HAL uygulaması tarafından seçilir ve yukarıdaki yığın tarafından opak olarak kullanılır.vendor_flags
. Özel kamera bilgilerini sürücüden özel bir EVS uygulamasına opak bir şekilde aktarma yöntemi. Bu bilgiler, sürücüden EVS uygulamasına yorumlanmamış olarak aktarılır ve EVS uygulaması bu bilgileri yoksayabilir.
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 }
EVS ekranının durumunu açıklar. EVS ekranı devre dışı (sürücüye görünmez) veya etkin (sürücüye resim gösterir) olabilir.
Ekranın henüz görünmediği ancak returnTargetBufferForDisplay()
çağrısı aracılığıyla bir sonraki görüntü karesinin yayınlanmasıyla görünmeye hazır olduğu geçici bir durum içerir.
EVS Yöneticisi
EVS Yöneticisi, harici kamera görüntülerini toplamak ve sunmak için EVS sistemine herkese açık arayüzü sağlar. Donanım sürücüleri kaynak başına yalnızca bir etkin arayüze (kamera veya ekran) izin veriyorsa EVS Yöneticisi, kameralara ortak erişimi kolaylaştırır. Tek bir birincil EVS uygulaması, EVS Yöneticisi'nin ilk istemcisidir ve görüntülü reklam verilerini yazmasına izin verilen tek istemcidir (ek istemcilere kamera görüntülerine salt okuma erişimi verilebilir).
EVS Yöneticisi, temel HAL sürücüleriyle aynı API'yi uygular ve birden fazla eşzamanlı istemciyi destekleyerek genişletilmiş hizmet sunar (EVS Yöneticisi aracılığıyla birden fazla istemci bir kamerayı açıp video akışı alabilir).
Uygulamalar, EVS Donanım HAL uygulaması veya EVS Yöneticisi API'si üzerinden çalışırken herhangi bir fark görmez. Tek fark, EVS Yöneticisi API'sinin eşzamanlı kamera akışı erişimine izin vermesidir. EVS Yöneticisi, EVS Donanım HAL katmanının izin verilen istemcisidir ve EVS Donanım HAL için proxy görevi görür.
Aşağıdaki bölümlerde yalnızca EVS Yöneticisi uygulamasında farklı (genişletilmiş) davranışa sahip çağrılar açıklanmaktadır. Diğer çağrılar EVS HAL açıklamalarıyla aynıdır.
IEvsEnumerator
openCamera(string camera_id) generates (IEvsCamera camera);
Benzersiz camera_id dizesi ile tanımlanan belirli bir kamerayla etkileşim kurmak için kullanılan bir arayüz nesnesi alır. Başarısız olursa NULL döndürür.
EVS Yöneticisi katmanında, yeterli sistem kaynağı bulunduğu sürece, açık olan bir kamera başka bir işlem tarafından tekrar açılabilir. Bu sayede video akışının birden fazla tüketici uygulamasına yönlendirilmesi sağlanır. EVS Yöneticisi katmanındaki camera_id
dizeleri, EVS Donanım katmanına raporlananlarla aynıdır.
IEvsCamera
EVS Yöneticisi tarafından sağlanan IEvsCamera uygulaması dahili olarak sanallaştırılır. Böylece, bir istemcinin kamera üzerinde yaptığı işlemler diğer istemcileri etkilemez. Bu istemciler, kameralarına bağımsız olarak erişmeye devam eder.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Video akışları başlatır. İstemciler, aynı temel kamerada video akışlarını bağımsız olarak başlatabilir ve durdurabilir. Temel kamera, ilk istemci başladığında başlar.
doneWithFrame(uint32 frameId, handle bufferHandle) generates (EvsResult result);
Bir kare döndürür. Her müşteri, bittiğinde çerçevelerini iade etmelidir ancak çerçevelerini istedikleri kadar tutabilirler. İstemcinin tuttuğu kare sayısı, yapılandırılan sınıra ulaştığında bir kare döndürene kadar başka kare almaz. Bu kare atlama, diğer istemcileri etkilemez. Diğer istemciler tüm kareleri beklendiği gibi almaya devam eder.
stopVideoStream();
Video akışını durdurur. Her müşteri diğer müşterileri etkilemeden video akışını dilediği zaman durdurabilir. Belirli bir kameranın son istemcisi yayınını durdurduğunda donanım katmanındaki temel kamera yayını durdurulur.
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
Sürücüye özgü bir değer gönderir. Bu, bir müşterinin başka bir müşteriyi etkilemesine olanak tanıyabilir. EVS Yöneticisi, tedarikçi firma tarafından tanımlanan kontrol kelimelerinin sonuçlarını anlayamadığından bu kelimeler sanallaştırılmaz ve yan etkiler belirli bir kameranın tüm istemcileri için geçerli olur. Örneğin, bir tedarikçi firma kare hızlarını değiştirmek için bu çağrıyı kullanırsa etkilenen donanım katmanı kameranın tüm istemcileri yeni hızda kare alır.
IEvsDisplay
EVS yöneticisi düzeyinde bile ekranın yalnızca bir sahibi olabilir. Yönetici hiçbir işlev eklemez ve IEvsDisplay arayüzünü doğrudan temel HAL uygulamasına geçirir.
EVS uygulaması
Android, temel arka görüş kamerası işlevlerini sağlamak için EVS Yöneticisi ve Araç HAL ile iletişim kuran bir EVS uygulamasının yerel C++ referans uygulamasını içerir. Uygulamanın, sistem başlatma işleminin çok erken bir aşamasında başlaması ve kullanılabilir kameralara ve arabanın durumuna (dişli ve dönüş sinyali durumu) bağlı olarak uygun videonun gösterilmesi beklenir. OEM'ler EVS uygulamasını değiştirebilir veya kendi araçlarına özel mantık ve sunumla değiştirebilir.
Şekil 3. EVS uygulaması örnek mantığı, kamera listesini alma.
Şekil 4. EVS uygulaması örnek mantığı, çerçeve geri çağırması yapın.
Resim verileri uygulamaya standart bir grafik arabelleğinde sunulduğundan, resmi kaynak arabelleğinden çıkış arabelleğine taşıma sorumluluğu uygulamaya aittir. Bu durum, veri kopyasının maliyetini beraberinde getirse de uygulamanın, resmi ekran arabelleğinde istediği biçimde görüntülemesi için fırsat sunar.
Örneğin, uygulama satır içi ölçeklendirme veya döndürme işlemiyle piksel verilerinin kendisini taşımayı seçebilir. Uygulama, kaynak resmi OpenGL dokusu olarak kullanmayı da seçebilir ve simge, kılavuz ve animasyon gibi sanal öğeler içeren karmaşık bir sahneyi çıkış arabelleğine oluşturabilir. Daha gelişmiş bir uygulama, aynı anda birden fazla giriş kamerası seçip bunları tek bir çıkış çerçevesine birleştirebilir (ör. aracın çevresinin yukarıdan görünümü için).
EVS Ekran HAL'sinde EGL/SurfaceFlinger'ı kullanma
Bu bölümde, Android 10'da EVS Ekran HAL uygulaması oluşturmak için EGL'nin nasıl kullanılacağı açıklanmaktadır.
EVS HAL referans uygulaması, kamera önizlemesini ekranda oluşturmak için EGL'yi, hedef EGL oluşturma yüzeyini oluşturmak için ise libgui
'yi kullanır. Android 8 (ve sonraki sürümler)'de libgui
, VNDK-private olarak sınıflandırılır. Bu sınıflandırma, VNDK kitaplıklarının kullanabileceği ve tedarikçi firma işlemlerinin kullanamayacağı bir kitaplık grubunu ifade eder.
HAL uygulamalarının tedarikçi firma bölümünde bulunması gerektiğinden, tedarikçilerin HAL uygulamalarında yüzeyi kullanması engellenir.
Tedarikçi firma işlemleri için libgui oluşturma
libgui
, EVS Display HAL uygulamalarında EGL/SurfaceFlinger'ı kullanmanın tek yoludur. libgui
'ü uygulamanın en kolay yolu, doğrudan derleme komut dosyasında ek bir derleme hedefi kullanarak frameworks/native/libs/gui üzerindendir. Bu hedef, iki alanın eklenmesi dışında libgui
hedefiyle tamamen aynıdır:
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", ], …
Not: Tedarikçi firma hedefleri, paket verilerinden bir 32 bitlik kelimeyi kaldıran NO_INPUT
makrosu ile oluşturulur. SurfaceFlinger, kaldırılmış olan bu alanı beklediğinden paketi ayrıştıramaz. Bu durum fcntl
hatası olarak gözlemlenir:
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
Bu durumu çözmek için:
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);
Aşağıda örnek derleme talimatları verilmiştir. $(ANDROID_PRODUCT_OUT)/system/lib64/libgui_vendor.so
alırsınız.
$ 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
EVS HAL uygulamasında binder'ı kullanma
Android 8 (ve sonraki sürümler)'de /dev/binder
cihaz düğümü, çerçeve işlemlerine özel hale geldi ve bu nedenle tedarikçi firma süreçleri tarafından erişilemez hale geldi. Bunun yerine, tedarikçi firma işlemleri /dev/hwbinder
kullanmalıdır ve tüm AIDL arayüzlerini HIDL'ye dönüştürmelidir. Tedarikçi firma işlemleri arasında AIDL arayüzlerini kullanmaya devam etmek isteyenler /dev/vndbinder
bağlayıcı alanını kullanmalıdır.
IPC Alanı | Açıklama |
---|---|
/dev/binder |
AIDL arayüzleriyle çerçeve/uygulama işlemleri arasında IPC |
/dev/hwbinder |
HIDL arayüzleriyle çerçeve/tedarikçi firma işlemleri arasında IPC HIDL arayüzleriyle tedarikçi işlemleri arasında IPC |
/dev/vndbinder |
AIDL arayüzleriyle tedarikçi firma/tedarikçi firma işlemleri arasında IPC |
SurfaceFlinger, AIDL arayüzlerini tanımlarken tedarikçi firma işlemleri, çerçeve işlemleriyle iletişim kurmak için yalnızca HIDL arayüzlerini kullanabilir. Mevcut AIDL arayüzlerini HIDL'ye dönüştürmek için önemli miktarda çalışma gerekir. Neyse ki Android, kullanıcı alanı kitaplık işlemlerinin bağlı olduğu libbinder
için bağlayıcı sürücüsünü seçmenizi sağlayan bir yöntem sağlar.
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));
Not: Tedarikçi süreçleri, Process
veya IPCThreadState
'i ya da herhangi bir bağlayıcı çağrısı yapmadan önce bu işlevi çağırmalıdır.
SELinux politikaları
Cihaz uygulaması tam üçlü ise SELinux, tedarikçi firma işlemlerinin /dev/binder
kullanmasını engeller. Örneğin, bir EVS HAL örnek uygulaması hal_evs_driver
alanına atanmış ve binder_device
alanı için r/w izinleri gerektirir.
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
Ancak bu izinlerin eklenmesi, tam tiz cihaz için system/sepolicy/domain.te
içinde tanımlanan aşağıdaki neverallow kurallarını ihlal ettiğinden derleme hatasına neden olur.
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
hatayı yakalamak ve geliştirmeye rehberlik etmek için sağlanan bir özelliktir. Ayrıca yukarıda açıklanan Android 10 ihlalini
çözmek için de kullanılabilir.
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)
Tedarikçi firma süreci olarak bir EVS HAL referans uygulaması derleme
Referans olarak, packages/services/Car/evs/Android.mk
için aşağıdaki değişiklikleri uygulayabilirsiniz. Açıklanan tüm değişikliklerin uygulamanız için
çalıştığını doğruladığınızdan emin olun.
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;