Android, Android başlatma sürecinin çok erken aşamalarında görüntü yakalama ve görüntüleme sağlayan ve sistemin ömrü boyunca çalışmaya devam eden bir otomotiv HIDL Donanım Soyutlama Katmanı (HAL) içerir. HAL, dış görünüm sistemi (EVS) yığınını içerir ve genellikle Android tabanlı araç içi bilgi-eğlence (IVI) sistemlerine sahip araçlarda dikiz aynası kamerasını ve kuş bakışı görünüm ekranlarını desteklemek için kullanılır. EVS, kullanıcı uygulamalarında gelişmiş özelliklerin uygulanmasına da olanak tanır.
Android'de ayrıca EVS'ye özel bir yakalama ve ekran sürücüsü arayüzü (/hardware/interfaces/automotive/evs/1.0
içinde) bulunur. Mevcut Android kamera ve ekran hizmetlerinin üzerine bir arka görüş kamerası uygulaması oluşturmak mümkün olsa da bu tür bir uygulama, Android başlatma sürecinde muhtemelen çok geç çalışır. Özel bir HAL kullanmak, arayüzü kolaylaştırır ve OEM'lerin EVS yığınını desteklemek için ne uygulaması gerektiğini netleştirir.
Sistem bileşenleri
EVS aşağıdaki sistem bileşenlerini içerir:

EVS uygulaması
Örnek bir C++ EVS uygulaması
(/packages/services/Car/evs/app
) referans uygulama olarak kullanılır. Bu uygulama, EVS Yöneticisi'nden video kareleri istemek ve görüntülenmek üzere tamamlanmış kareleri EVS Yöneticisi'ne geri göndermekten sorumludur.
EVS ve Car Service kullanıma sunulur sunulmaz init tarafından başlatılması beklenir. Bu işlemin, güç açıldıktan sonraki iki (2) saniye içinde tamamlanması hedeflenir. OEM'ler, EVS uygulamasını istedikleri gibi değiştirebilir veya güncelleyebilir.
EVS Manager
EVS Yöneticisi (/packages/services/Car/evs/manager
), EVS uygulamasının basit bir arka görüş kamerası ekranından 6DOF çok kameralı görüntülemeye kadar her şeyi uygulaması için gereken yapı taşlarını sağlar. Arayüzü HIDL aracılığıyla sunulur ve aynı anda birden fazla istemciyi kabul edecek şekilde oluşturulur.
Diğer uygulamalar ve hizmetler (özellikle Araç Hizmeti), 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 dahil olmak üzere EVS sistemi, android.hardware.automotive.evs
paketinde tanımlanır. Arayüzü kullanan (sentetik test resimleri oluşturan ve resimlerin gidiş dönüş yolculuğunu doğrulayan) örnek bir uygulama /hardware/interfaces/automotive/evs/1.0/default
içinde sağlanır.
OEM, /hardware/interfaces/automotive/evs
içindeki .hal dosyalarıyla ifade edilen API'yi uygulamaktan sorumludur. Bu tür uygulamalar, fiziksel kameralardan veri toplama ve yapılandırmadan, ayrıca bu verileri Gralloc tarafından tanınabilen paylaşılan bellek arabellekleri aracılığıyla iletmekten sorumludur. Uygulamanın görüntüleme tarafı, uygulama tarafından doldurulabilen (genellikle EGL oluşturma ile) paylaşılan bir bellek arabelleği sağlamaktan ve fiziksel ekranda görünmek isteyebilecek diğer her şey yerine bitmiş kareleri sunmaktan sorumludur. EVS arayüzünün satıcı uygulamaları /vendor/… /device/…
veya hardware/…
altında saklanabilir (ör.
/hardware/[vendor]/[platform]/evs
).
Ç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 EVS için gerekli özellikleri mevcut kamera veya ekran donanım sürücüleri aracılığıyla destekleyebilir. Sürücüleri yeniden kullanmak, özellikle görüntü sunumunun diğer etkin iş parçacıklarıyla koordinasyon gerektirebileceği ekran 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 bağlı olan 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çilerin, bu API'nin donanımlarına uyarlanmış uygulamalarını sağlamaları beklenir.
IEvsEnumerator
Bu nesne, sistemdeki mevcut EVS donanımını (bir veya daha fazla kamera ve tek ekran 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. Kameraların kümesinin sabit olduğu ve başlatma sırasında bilinebileceği varsayılır. Kamera açıklamalarıyla ilgili ayrıntılar için CameraDesc
başlıklı makaleyi inceleyin.
openCamera(string camera_id) generates (IEvsCamera camera);
Benzersiz camera_id dizesiyle tanımlanan belirli bir kamerayla etkileşim kurmak için kullanılan bir arayüz nesnesi alır. Başarısız olursa NULL değerini döndürür.
Zaten açık olan bir kamerayı yeniden açma denemeleri başarısız olamaz. Uygulama başlatma ve kapatma ile ilişkili yarış durumlarını önlemek için kameranın yeniden açılması, yeni isteğin karşılanabilmesi amacıyla önceki örneği kapatmalıdır. Bu şekilde önceliği alınmış bir kamera örneği, son imha işlemini bekleyerek etkin olmayan bir duruma getirilmelidir ve kamera durumunu etkileyecek tüm isteklere OWNERSHIP_LOST
dönüş koduyla yanıt vermelidir.
closeCamera(IEvsCamera camera);
IEvsCamera arayüzünü serbest bırakır (openCamera()
çağrısının tersidir). Kamera video akışı, closeCamera
çağrılmadan önce stopVideoStream()
çağrılarak durdurulmalıdır.
openDisplay() generates (IEvsDisplay display);
Sistemin EVS ekranıyla özel olarak etkileşim kurmak için kullanılan bir arayüz nesnesi alır. Aynı anda yalnızca bir istemci, IEvsDisplay'in işlevsel bir örneğini tutabilir. openCamera
bölümünde açıklanan agresif açma davranışına benzer şekilde, yeni bir IEvsDisplay nesnesi herhangi bir zamanda oluşturulabilir ve önceki tüm örnekleri devre dışı bırakır. Geçersiz kılınan örnekler var olmaya ve sahiplerinden gelen işlev çağrılarına yanıt vermeye devam eder ancak ölü olduklarında herhangi bir mutasyon işlemi gerçekleştirmemelidir. Sonunda, istemci uygulamasının OWNERSHIP_LOST
hata dönüş kodlarını fark etmesi, etkin olmayan arayüzü kapatması ve serbest bırakması beklenir.
closeDisplay(IEvsDisplay display);
IEvsDisplay arayüzünü serbest bırakır (openDisplay()
çağrısının tersidir). getTargetBuffer()
aramalarıyla alınan bekleyen arabellekler, ekran kapatılmadan önce ekrana geri gönderilmelidir.
getDisplayState() generates (DisplayState state);
Mevcut ekran durumunu alır. HAL uygulaması, en son istenen durumdan farklı olabilecek mevcut durumu bildirmelidir.
Görüntüleme durumlarını değiştirmekten sorumlu mantık, cihaz katmanının üzerinde olmalıdır. Bu nedenle, HAL uygulamasının görüntüleme durumlarını kendiliğinden değiştirmesi istenmez. Ekran şu anda herhangi bir istemci tarafından tutulmuyorsa (openDisplay çağrısıyla) bu işlev NOT_OPEN
değerini döndürür. Aksi takdirde, EVS Ekranı'nın mevcut durumunu bildirir (bkz. IEvsDisplay API).
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 için bir ad olabilir (ör. rearview). Bu dizenin değeri, HAL uygulaması tarafından seçilir ve yukarıdaki yığın tarafından opak bir şekilde kullanılır.vendor_flags
. Sürücüden özel bir EVS uygulamasına özel kamera bilgilerini opak bir şekilde iletme yöntemi. Bu bilgiler, sürücüden EVS uygulamasına yorumlanmadan iletilir. EVS uygulaması bu bilgileri yok sayabilir.
IEvsCamera
Bu nesne tek bir kamerayı temsil eder ve görüntü yakalamak için kullanılan birincil arayüzdür.
getCameraInfo() generates (CameraDesc info);
Bu kameranın CameraDesc
değerini döndürür.
setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);
Kameranın desteklemesi istenen arabellek zincirinin derinliğini belirtir. IEvsCamera istemcisi aynı anda bu kadar çok kare tutabilir. Bu kadar çok sayıda kare, doneWithFrame
tarafından döndürülmeden alıcıya teslim edildiyse akış, yeniden kullanılmak üzere bir arabellek döndürülene kadar kareleri atlar. Bu çağrının, yayınlar devam ederken bile herhangi bir zamanda yapılması yasaldır. Bu durumda, zincire uygun şekilde arabellekler eklenmeli veya zincirden arabellekler kaldırılmalıdır. Bu giriş noktasına herhangi bir çağrı yapılmazsa IEvsCamera, varsayılan olarak en az bir kareyi destekler. Daha fazla kare de kabul edilebilir.
İstenen bufferCount değeri karşılanamıyorsa işlev BUFFER_NOT_AVAILABLE
veya diğer ilgili hata kodunu döndürür. Bu durumda sistem, daha önce ayarlanan değerle çalışmaya devam eder.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Bu kameradan EVS kamera karelerinin teslim edilmesini ister. IEvsCameraStream
stopVideoStream()
çağrılana kadar yeni görüntü kareleriyle düzenli olarak çağrı almaya başlar. Kareler, startVideoStream
çağrısından sonraki 500 ms içinde teslim edilmeye başlanmalı ve başladıktan sonra en az 10 FPS hızında oluşturulmalıdır. Video akışının başlatılması için gereken süre, dikiz aynası kamerası başlatma süresi şartına dahil edilir. Akış başlatılmamışsa bir hata kodu döndürülmelidir. Aksi takdirde OK döndürülür.
oneway doneWithFrame(BufferDesc buffer);
IEvsCameraStream'e teslim edilen bir kareyi döndürür. IEvsCameraStream arayüzüne teslim edilen bir kare tüketimi tamamlandığında, kare yeniden kullanılmak üzere IEvsCamera'ya döndürülmelidir. Sınırlı sayıda küçük arabellek bulunur (bir tane kadar az olabilir) ve arabellekler tükendiğinde, bir arabellek döndürülene kadar başka kareler teslim edilmez. Bu durum, karelerin atlanmasına neden olabilir (null tutma yerine sahip bir arabellek, akışın sonunu gösterir ve bu işlev aracılığıyla döndürülmesi gerekmez). Başarı durumunda OK, aksi takdirde INVALID_ARG
veya BUFFER_NOT_AVAILABLE
dahil olmak üzere uygun hata kodunu döndürür.
stopVideoStream();
EVS kamera karelerinin yayınlanmasını durdurur. Teslimat eşzamansız olduğundan, bu çağrı döndükten sonra bir süre daha çerçeveler gelmeye devam edebilir. Akışın kapatılması IEvsCameraStream'e bildirilene kadar her kare döndürülmelidir. Durdurulmuş veya hiç başlatılmamış bir akışta stopVideoStream
çağrısı yapmak yasaldır. Bu durumlarda çağrı yoksayılır.
getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);
HAL uygulamasından sürücüye özel bilgiler ister. opaqueIdentifier
için izin verilen değerler sürücüye özeldir ancak iletilen değer sürücünün kilitlenmesine neden olabilir. Sürücü, tanınmayan tüm opaqueIdentifier
için 0 değerini döndürmelidir.
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
HAL uygulamasına sürücüye özel bir değer gönderir. Bu uzantı yalnızca araca özel uzantıları kolaylaştırmak için sağlanır ve varsayılan durumda çalışması için bu çağrının yapılması gerekmez. Sürücü değerleri tanıyıp 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 iletilen bir resmi açıklar. HAL sürücüsü, görüntü arabelleğini açıklamak için bu yapıyı doldurmaktan sorumludur ve HAL istemcisi bu yapıyı salt okunur olarak değerlendirmelidir. Alanlar, istemcinin ANativeWindowBuffer
nesnesini yeniden oluşturmasına olanak tanıyacak kadar bilgi içerir. Bu, eglCreateImageKHR()
uzantılı EGL ile görüntüyü kullanmak için gerekli olabilir.
width
. Sunulan resmin piksel cinsinden genişliği.height
. Sunulan resmin piksel cinsinden yüksekliği.stride
. Satırların hizalanması için dolgu da dahil olmak üzere, her satırın bellekte kapladığı gerçek piksel sayısı. gralloc'un arabellek açıklamaları için kullandığı kurala uygun olarak piksel cinsinden ifade edilir.pixelSize
. Her bir pikselin kapladığı bayt sayısıdır. Bu sayede, resimde satırlar arasında ilerlemek için gereken bayt cinsinden boyut hesaplanabilir (stride
bayt =stride
piksel *pixelSize
).format
. Görüntü 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ındaHAL_PIXEL_FORMAT_YCRCB_420_SP
, ekranda iseRGBA
veyaBGRA
tercih edilmelidir.usage
. HAL uygulaması tarafından ayarlanan kullanım işaretleri. HAL istemcilerinin bunları değiştirilmeden iletmesi beklenir (ayrıntılar içinGralloc.h
ile ilgili işaretlere bakın).bufferId
. HAL API'leri üzerinden gidiş dönüş yapıldıktan sonra arabelleğin tanınmasına olanak tanımak için HAL uygulaması tarafından belirtilen benzersiz bir değer. Bu alanda depolanan değer, HAL uygulaması tarafından rastgele seçilebilir.memHandle
. Resim verilerini içeren temel bellek arabelleğinin tutma yeri. HAL uygulaması, Gralloc arabellek tutacını burada depolamayı seçebilir.
IEvsCameraStream
İstemci, eşzamansız video çerçevesi teslimatlarını almak için bu arayüzü uygular.
deliverFrame(BufferDesc buffer);
Bir video karesi incelemeye hazır olduğunda HAL'den her seferinde çağrı alır.
Bu yöntemle alınan arabellekler, IEvsCamera::doneWithFrame()
çağrıları aracılığı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 teslim edildiğinde, akışın sonunu belirten ve başka kare teslimatı yapılmayacağını gösteren bir NULL bufferHandle
teslim edilir. NULL
bufferHandle
değerinin kendisinin
doneWithFrame()
ile birlikte geri gönderilmesi gerekmez ancak diğer tüm tutmaçlar döndürülmelidir.
Tescilli arabellek biçimleri teknik olarak mümkün olsa da uyumluluk testi için arabelleğin desteklenen dört biçimden birinde olması gerekir: NV21 (YCrCb 4:2:0 Yarı Düzlemsel), YV12 (YCrCb 4:2:0 Düzlemsel), YUYV (YCrCb 4:2:2 İç İçe), 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ındaki herhangi bir yazışmaya dayanmamalıdır. bufferId
değerleri, HAL sürücüsü uygulaması için temelde özeldir ve sürücü bunları uygun gördüğü şekilde kullanabilir (ve yeniden kullanabilir).
IEvsDisplay
Bu nesne, Evs ekranını temsil eder, ekranın durumunu kontrol eder ve görüntülerin gerçek sunumunu gerçekleştirir.
getDisplayInfo() generates (DisplayDesc info);
Sistem tarafından sağlanan EVS ekranı hakkında temel bilgileri döndürür (bkz. DisplayDesc).
setDisplayState(DisplayState state) generates (EvsResult result);
Ekran durumunu ayarlar. İstemciler, istenen durumu ifade etmek için ekran durumunu ayarlayabilir. HAL uygulaması, yanıt isteği yoksaymak olsa da diğer durumlarda herhangi bir durum isteğini sorunsuz bir şekilde kabul etmelidir.
Başlatma sırasında ekranın NOT_VISIBLE
durumunda başlaması tanımlanır. Ardından istemcinin VISIBLE_ON_NEXT_FRAME
durumunu istemesi ve video sağlamaya başlaması beklenir. Gösterim artık gerekli olmadığında, istemcinin son video karesini geçtikten sonra NOT_VISIBLE
durumunu istemesi beklenir.
Herhangi bir eyalette, herhangi bir zamanda talep edilebilir. Ekran zaten görünür durumdaysa VISIBLE_ON_NEXT_FRAME
olarak ayarlandığında görünür kalmalıdır. İstenen durum tanınmayan bir enum değeri olmadığı sürece her zaman OK değerini döndürür. Bu durumda INVALID_ARG
döndürülür.
getDisplayState() generates (DisplayState state);
Ekran durumunu alır. HAL uygulaması, en son istenen durumdan farklı olabilecek mevcut durumu bildirmelidir. Görüntüleme durumlarını değiştirmekten sorumlu mantık, cihaz katmanının üzerinde olmalıdır. Bu nedenle, HAL uygulamasının görüntüleme durumlarını kendiliğinden değiştirmesi istenmez.
getTargetBuffer() generates (handle bufferHandle);
Ekranla ilişkili bir çerçeve arabelleğinin tutma yerini döndürür. Bu arabellek, yazılım ve/veya GL tarafından kilitlenebilir ve üzerine yazılabilir. Bu arabellek, ekran artık görünür olmasa bile returnTargetBufferForDisplay()
çağrısıyla birlikte döndürülmelidir.
Tescilli arabellek biçimleri teknik olarak mümkün olsa da uyumluluk testi için arabelleğin dört desteklenen biçimden birinde olması gerekir: NV21 (YCrCb 4:2:0 Yarı Düzlemsel), YV12 (YCrCb 4:2:0 Düzlemsel), YUYV (YCrCb 4:2:2 İç İçe) ve 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.
Hata durumunda, boş tutamaçlı bir arabellek döndürülür ancak bu tür bir arabelleğin returnTargetBufferForDisplay
'ya geri iletilmesi gerekmez.
returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);
Ekrana, arabelleğin görüntülenmeye hazır olduğunu bildirir. Yalnızca getTargetBuffer()
çağrısıyla alınan arabellekler bu çağrıyla kullanılmak üzere geçerlidir ve BufferDesc
içeriği istemci uygulaması tarafından değiştirilemez. Bu çağrıdan sonra arabellek, istemci tarafından kullanılmak üzere geçerliliğini kaybeder. Başarılı olduğunda OK, başarısız olduğunda ise INVALID_ARG
veya BUFFER_NOT_AVAILABLE
dahil olmak üzere 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ı açıklamak için bu yapıyı doldurmaktan sorumludur. Fiziksel bir ekran veya başka bir sunum cihazıyla kaplanmış ya da karıştırılmış sanal bir ekran olabilir.
display_id
. Gösterimi benzersiz şekilde tanımlayan bir dize. Bu, cihazın çekirdek cihaz adı veya cihaz için bir ad olabilir (ör. rearview). Bu dizenin değeri HAL uygulaması tarafından seçilir ve yukarıdaki yığın tarafından opak olarak kullanılır.vendor_flags
. Sürücüden özel bir EVS uygulamasına özel kamera bilgilerini opak bir şekilde iletme yöntemi. Bu bilgiler, sürücüden EVS uygulamasına yorumlanmadan iletilir ve EVS uygulaması bu bilgileri yok sayabilir.
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. Bu durum devre dışı (sürücü tarafından görünmüyor) veya etkin (sürücüye görüntü gösteriliyor) olabilir.
Ekrana henüz yansıtılmamış ancak returnTargetBufferForDisplay()
çağrısıyla bir sonraki görüntü karesi geldiğinde yansıtılmaya hazır olan geçici bir durumu içerir.
EVS Manager
EVS Yöneticisi, harici kamera görünümlerini toplamak ve sunmak için EVS sistemine yönelik herkese açık arayüzü sağlar. Donanım sürücülerinin kaynak başına (kamera veya ekran) yalnızca bir etkin arayüze izin verdiği durumlarda EVS Yöneticisi, kameralara paylaşılan erişimi kolaylaştırır. Tek bir birincil EVS uygulaması, EVS Yöneticisi'nin ilk istemcisidir ve yalnızca görüntü verileri yazmasına izin verilen 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 kamera açabilir ve video akışı alabilir).

EVS Manager API'nin eşzamanlı kamera akışı erişimine izin vermesi dışında, uygulamalar EVS Hardware HAL uygulaması veya EVS Manager API üzerinden çalışırken herhangi bir fark görmez. EVS Yöneticisi, EVS Donanım HAL katmanının tek 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 olan ç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 dizesiyle tanımlanan belirli bir kamerayla etkileşim kurmak için kullanılan bir arayüz nesnesi alır. Başarısız olursa NULL değerini döndürür.
EVS Manager katmanında, yeterli sistem kaynağı olduğu sürece, zaten açık olan bir kamera başka bir işlem tarafından tekrar açılabilir. Bu sayede video akışı birden fazla tüketici uygulamasına yönlendirilebilir. EVS Yöneticisi katmanındaki camera_id
dizeleri, EVS Donanım katmanına bildirilenlerle aynıdır.
IEvsCamera
EVS Yöneticisi tarafından sağlanan IEvsCamera uygulaması dahili olarak sanallaştırıldığından bir istemci tarafından kamerada yapılan işlemler, kameralarına bağımsız erişimi koruyan diğer istemcileri etkilemez.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Video akışlarını başlatır. İstemciler, aynı temel kamerada video akışlarını bağımsız olarak başlatıp durdurabilir. Temel kamera, ilk istemci başlatıldığında çalışmaya başlar.
doneWithFrame(uint32 frameId, handle bufferHandle) generates (EvsResult result);
Bir çerçeve döndürür. Her müşteri, işi bittiğinde çerçevelerini iade etmelidir ancak çerçevelerini istediği kadar saklayabilir. Bir istemcinin tuttuğu kare sayısı, yapılandırılmış sınırına ulaştığında bir kare döndürene kadar daha fazla 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 istemci, diğer istemcileri etkilemeden video akışını istediği zaman durdurabilir. Belirli bir kameranın son istemcisi akışını durdurduğunda donanım katmanındaki temel kamera akışı durdurulur.
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
Sürücüye özel bir değer gönderir. Bu durum, bir istemcinin başka bir istemciyi etkilemesine neden olabilir. EVS Yöneticisi, satıcı tarafından tanımlanan kontrol kelimelerinin etkilerini anlayamadığı için bu kelimeler sanallaştırılmaz ve yan etkiler, belirli bir kameranın tüm istemcileri için geçerli olur. Örneğin, bir satıcı bu çağrıyı kare hızlarını değiştirmek için kullandıysa etkilenen donanım katmanı kamerasının tüm istemcileri kareleri yeni hızda alır.
IEvsDisplay
EVS Yöneticisi düzeyinde bile olsa yalnızca bir ekran sahibine izin verilir. Yönetici herhangi 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şlevleri sağlamak için EVS Yöneticisi ve Araç HAL'si ile iletişim kuran bir EVS uygulamasının yerel C++ referans uygulamasını içerir. Uygulamanın, sistem başlatma sürecinin çok erken aşamalarında başlaması ve mevcut kameralara ve arabanın durumuna (vites ve sinyal durumu) bağlı olarak uygun videonun gösterilmesi bekleniyor. OEM'ler, EVS uygulamasını kendi araca özel mantıkları ve sunumlarıyla değiştirebilir veya uygulamayı kendi mantıkları ve sunumlarıyla değiştirebilir.


Resim verileri uygulamaya standart bir grafik arabelleğinde sunulduğundan, resmi kaynak arabelleğinden çıkış arabelleğine taşımak uygulamanın sorumluluğundadır. Bu işlem, veri kopyalama maliyetini artırsa da uygulamanın resmi istediği şekilde görüntü arabelleğine işlemesine olanak tanır.
Örneğin, uygulama, satır içi ölçeklendirme veya döndürme işlemiyle birlikte piksel verilerini taşımayı seçebilir. Uygulama, kaynak resmi OpenGL dokusu olarak kullanmayı ve simgeler, kılavuz çizgileri ve animasyonlar gibi sanal öğeler de dahil olmak üzere karmaşık bir sahneyi çıkış arabelleğine işlemeyi de seçebilir. Daha gelişmiş bir uygulama, aynı anda birden fazla giriş kamerası da seçebilir ve bunları tek bir çıkış karesinde birleştirebilir (ör. aracın çevresinin yukarıdan aşağıya sanal görünümünde kullanılmak üzere).
EVS Display HAL'de EGL/SurfaceFlinger'ı kullanma
Bu bölümde, Android 10'da EVS Display HAL uygulamasını 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
kullanır. Android 8 ve sonraki sürümlerde libgui
VNDK-private olarak sınıflandırılır.
Bu, satıcı işlemlerinin kullanamadığı VNDK kitaplıkları için kullanılabilen bir kitaplık grubunu ifade eder.
HAL uygulamaları tedarikçi bölümünde yer alması gerektiğinden tedarikçilerin HAL uygulamalarında Surface kullanması engellenir.
Tedarikçi işlemleri için libgui'yi oluşturma
libgui
kullanımı, EVS Display HAL uygulamalarında EGL/SurfaceFlinger'ı kullanmanın tek seçeneğidir. libgui
'yı uygulamanın en basit yolu, derleme komut dosyasında ek bir derleme hedefi kullanarak doğrudan frameworks/native/libs/gui üzerinden yapmaktır. 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: Satıcı hedefleri, paket verilerinden 32 bitlik bir kelimeyi kaldıran NO_INPUT
makrosuyla oluşturulur. SurfaceFlinger, kaldırılan bu alanı beklediği için 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 düzeltmek 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);
Örnek derleme talimatları aşağıda verilmiştir. $(ANDROID_PRODUCT_OUT)/system/lib64/libgui_vendor.so
almayı bekleyin.
$ 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 bağlayıcı kullanma
Android 8 (ve sonraki sürümlerde) /dev/binder
cihaz düğümü, yalnızca çerçeve işlemlerine özel hale geldi ve bu nedenle satıcı işlemleri tarafından erişilemez oldu. Bunun yerine, satıcı işlemleri /dev/hwbinder
kullanmalı ve tüm AIDL arayüzlerini HIDL'ye dönüştürmelidir. Tedarikçi süreçleri arasında AIDL arayüzlerini kullanmaya devam etmek isteyenler için bağlayıcı alanı /dev/vndbinder
kullanılır.
IPC Alanı | Açıklama |
---|---|
/dev/binder |
AIDL arayüzleriyle çerçeve/uygulama süreçleri arasında IPC |
/dev/hwbinder |
HIDL arayüzleriyle çerçeve/tedarikçi süreçleri arasında IPC HIDL arayüzleriyle tedarikçi süreçleri arasında IPC |
/dev/vndbinder |
AIDL arayüzleriyle tedarikçi/tedarikçi süreçleri arasında IPC |
SurfaceFlinger, AIDL arayüzlerini tanımlarken tedarikçi 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ığı işlemlerinin bağlandığı libbinder
için bağlayıcı sürücüyü seçme yöntemi sunar.
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
'ye çağrı yapmadan önce ya da herhangi bir bağlayıcı çağrısı yapmadan önce bu yöntemi çağırmalıdır.
SELinux politikaları
Cihazda tam Treble uygulanıyorsa SELinux, satıcı işlemlerinin /dev/binder
kullanmasını engeller. Örneğin, bir EVS HAL örnek uygulaması hal_evs_driver
alanına atanır ve binder_device
alanında okuma/yazma 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, 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
bir 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)
EVS HAL referans uygulamasını satıcı süreci olarak oluşturma
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ızda çalıştığını onayladığı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;