Araç Kamerası HAL

Android, Android önyükleme işleminin çok erken aşamalarında görüntülerin yakalanmasını ve görüntülenmesini sağlayan ve sistemin ömrü boyunca çalışmaya devam eden bir otomotiv HIDL Donanım Soyutlama Katmanı (HAL) içerir. HAL, dış görüş sistemi (EVS) yığınını içerir ve genellikle Android tabanlı Araç İçi Bilgi-Eğlence (IVI) sistemlerine sahip araçlarda arka görüş kamerasını ve surround görüş ekranlarını desteklemek için kullanılır. EVS ayrıca gelişmiş özelliklerin kullanıcı uygulamalarında uygulanmasına da olanak tanır.

Android ayrıca EVS'ye özel bir yakalama ve görüntüleme sürücüsü arayüzü 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, böyle bir uygulama muhtemelen Android önyükleme sürecinde çok geç çalışacaktır. Özel bir HAL kullanmak, kolaylaştırılmış bir arayüz sağlar ve bir OEM'in 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:

AGH Sistemi bileşenleri şeması

Şekil 1. AGH sistem bileşenlerine genel bakış.

AGH uygulaması

Örnek bir C++ EVS uygulaması ( /packages/services/Car/evs/app ) referans uygulaması görevi görür. Bu uygulama, AGH Yöneticisinden video kareleri istemekten ve tamamlanmış kareleri görüntülenmek üzere AGH Yöneticisine geri göndermekten sorumludur. EVS ve Araç Hizmeti kullanılabilir hale gelir gelmez init tarafından başlatılması bekleniyor ve bu, güç açıldıktan sonraki iki (2) saniye içinde hedefleniyor. OEM'ler EVS uygulamasını istedikleri gibi değiştirebilir veya değiştirebilir.

AGH Müdürü

EVS Yöneticisi ( /packages/services/Car/evs/manager ), basit bir arka görüş kamerası ekranından 6DOF çoklu kamera görüntülemeye kadar her şeyi uygulamak için bir EVS uygulamasının ihtiyaç duyduğu yapı taşlarını sağlar. Arayüzü HIDL aracılığıyla sunulur ve birden fazla eşzamanlı istemciyi kabul edecek şekilde tasarlanmıştır. Diğer uygulamalar ve hizmetler (özellikle Araç Hizmeti), AGH sisteminin ne zaman aktif olduğunu öğrenmek için AGH Yöneticisi durumunu sorgulayabilir.

EVS HIDL arayüzü

EVS sistemi, hem kamera hem de ekran elemanları, android.hardware.automotive.evs paketinde tanımlanmıştır. Arayüzü çalıştıran (sentetik test görüntüleri oluşturur ve görüntülerin gidiş dönüşünü doğrulayan) örnek bir uygulama /hardware/interfaces/automotive/evs/1.0/default adresinde verilmiştir.

OEM /hardware/interfaces/automotive/evs içindeki .hal dosyaları tarafından ifade edilen API'nin uygulanmasından sorumludur. Bu tür uygulamalar, fiziksel kameralardan verilerin yapılandırılması, toplanması ve Gralloc tarafından tanınabilen paylaşılan bellek arabellekleri aracılığıyla iletilmesinden sorumludur. Uygulamanın görüntüleme tarafı, uygulama tarafından doldurulabilecek (genellikle EGL oluşturma yoluyla) paylaşılan bir bellek arabelleği sağlamaktan ve fiziksel ekranda görünmesi isteyebilecek diğer herhangi bir şeye tercihli olarak bitmiş kareleri sunmaktan sorumludur. EVS arayüzünün satıcı uygulamaları /vendor/… /device/… veya hardware/… (örneğin, /hardware/[vendor]/[platform]/evs ) altında saklanabilir.

Çekirdek sürücüleri

EVS yığınını destekleyen bir aygıt, çekirdek sürücüleri gerektirir. OEM'ler, yeni sürücüler oluşturmak yerine EVS'nin gerektirdiği özellikleri mevcut kamera ve/veya ekran donanım sürücüleri aracılığıyla destekleme seçeneğine sahiptir. Sürücülerin yeniden kullanılması, ö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 çıktı görüntüsünün sunulması 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. Satıcıların bu API'nin kendi donanımlarına uyarlanmış uygulamalarını sağlamaları bekleniyor.

IEvsEnumerator

Bu nesne, sistemdeki mevcut EVS donanımının (bir veya daha fazla kamera ve tek görüntüleme cihazı) numaralandırılmasından sorumludur.

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

Sistemdeki tüm kameralar için açıklamaları içeren bir vektör döndürür. Kamera setinin sabit olduğu ve önyükleme sırasında bilinebilir olduğu varsayılmaktadır. Kamera açıklamalarına ilişkin ayrıntılar için bkz. CameraDesc .

openCamera(string camera_id) generates (IEvsCamera camera);

Benzersiz kamera_id dizesi tarafından tanımlanan belirli bir kamerayla etkileşimde bulunmak için kullanılan bir arayüz nesnesi elde eder. Başarısızlık durumunda NULL döndürür. Zaten açık olan bir kamerayı yeniden açma girişimleri başarısız olamaz. Uygulamanın başlatılması ve kapatılmasıyla ilişkili yarış koşullarından kaçınmak için, bir kameranın yeniden açılması, yeni isteğin yerine getirilebilmesi için önceki örneği kapatmalıdır. Bu şekilde önlenen bir kamera örneğinin, nihai imhayı bekleyen ve kamera durumunu etkilemeye yönelik herhangi bir isteğe OWNERSHIP_LOST dönüş koduyla yanıt veren etkin olmayan bir duruma getirilmesi gerekir.

closeCamera(IEvsCamera camera);

IEvsCamera arayüzünü serbest bırakır (ve openCamera() çağrısının tersidir). closeCamera çağrılmadan önce stopVideoStream() çağrılarak kamera video akışı durdurulmalıdır.

openDisplay() generates (IEvsDisplay display);

Sistemin EVS ekranıyla özel olarak etkileşimde bulunmak için kullanılan bir arayüz nesnesi elde eder. Aynı anda yalnızca bir istemci IEvsDisplay'in işlevsel bir örneğini tutabilir. openCamera açıklanan agresif açma davranışına benzer şekilde, yeni bir IEvsDisplay nesnesi herhangi bir zamanda oluşturulabilir ve önceki örnekleri devre dışı bırakacaktır. Geçersiz kılınmış örnekler var olmaya devam eder ve sahiplerinden gelen işlev çağrılarına yanıt verir, ancak öldüklerinde hiçbir mutasyon işlemi gerçekleştirmemelidir. Sonunda istemci uygulamasının OWNERSHIP_LOST hata dönüş kodlarını fark etmesi ve etkin olmayan arayüzü kapatıp serbest bırakması beklenir.

closeDisplay(IEvsDisplay display);

IEvsDisplay arayüzünü serbest bırakır (ve openDisplay() çağrısının tersidir). getTargetBuffer() çağrıları aracılığıyla alınan bekleyen arabelleklerin, ekranı kapatmadan önce ekrana döndürülmesi gerekir.

getDisplayState() generates (DisplayState state);

Geçerli görüntü durumunu alır. HAL uygulaması, en son talep edilen durumdan farklı olabilecek gerçek mevcut durumu rapor etmelidir. Görüntüleme durumlarını değiştirmekten sorumlu olan mantık, cihaz katmanının üzerinde mevcut olmalıdır; bu da HAL uygulamasının görüntü durumlarını kendiliğinden değiştirmesini istenmeyen bir hale getirir. Görüntü şu anda herhangi bir istemci tarafından tutulmuyorsa (openDisplay çağrısıyla), bu işlev NOT_OPEN 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 bir dize. Aygıtın çekirdek aygıt adı veya dikiz gibi aygıt adı olabilir. 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 . Özel kamera bilgilerini sürücüden özel bir EVS uygulamasına opak bir şekilde aktarmaya yönelik bir yöntem. Sürücüden EVS uygulamasına yorumlanmadan aktarılır ve bu uygulama bunu göz ardı etmekte özgürdür.

IEvsKamera

Bu nesne tek bir kamerayı temsil eder ve görüntü yakalamak için birincil arayüzdür.

getCameraInfo() generates (CameraDesc info);

Bu kameranın CameraDesc döndürür.

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

Kameranın desteklemesi istenen tampon zincirinin derinliğini belirtir. Bu kadar çok kare IEvsCamera istemcisi tarafından aynı anda tutulabilir. Bu kadar çok kare alıcıya, doneWithFrame tarafından döndürülmeden teslim edildiyse, akış, yeniden kullanım için bir arabellek döndürülene kadar kareleri atlar. Bu çağrının herhangi bir zamanda, akışlar zaten çalışıyorken bile gelmesi yasaldır; bu durumda, uygun şekilde arabelleklerin zincire eklenmesi veya zincirden çıkarılması gerekir. Bu giriş noktasına herhangi bir çağrı yapılmazsa IEvsCamera varsayılan olarak en az bir kareyi destekler; daha kabul edilebilir.

İstenen bufferCount karşılanamıyorsa işlev BUFFER_NOT_AVAILABLE veya diğer ilgili hata kodunu döndürür. Bu durumda sistem önceden ayarlanan değerle çalışmaya devam eder.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Bu kameradan EVS kamera karelerinin teslimini talep ediyor. IEvsCameraStream, stopVideoStream() çağrılıncaya kadar yeni görüntü çerçeveleriyle periyodik çağrılar almaya başlar. Çerçeveler, startVideoStream çağrısından sonraki 500 ms içinde teslim edilmeye başlamalı ve başlatıldıktan sonra minimum 10 FPS'de oluşturulmalıdır. Video akışını etkili bir şekilde başlatmak için gereken süre, herhangi bir arka görüş kamerası başlatma süresi gereksinimine dahil edilir. Akış başlatılmazsa bir hata kodu döndürülmelidir; aksi takdirde Tamam döndürülür.

oneway doneWithFrame(BufferDesc buffer);

IEvsCameraStream tarafından teslim edilen bir kareyi döndürür. IEvsCameraStream arayüzüne gönderilen bir çerçevenin tüketilmesi tamamlandığında, çerçevenin yeniden kullanılmak üzere IEvsCamera'ya iade edilmesi gerekir. Küçük, sınırlı sayıda arabellek mevcuttur (muhtemelen bir kadar küçük) ve eğer kaynak tükenirse, bir arabellek döndürülene kadar başka çerçeve gönderilmez, bu da potansiyel olarak çerçevelerin atlanmasına neden olur (boş tanıtıcılı bir arabellek, bitişi belirtir) bir akışın parçasıdır ve bu işlev aracılığıyla döndürülmesine gerek yoktur). Başarı durumunda Tamam'ı veya INVALID_ARG veya BUFFER_NOT_AVAILABLE dahil olmak üzere potansiyel olarak uygun hata kodunu döndürür.

stopVideoStream();

EVS kamera karelerinin dağıtımını durdurur. Teslimat eşzamansız olduğundan, bu çağrı geri döndükten sonra çerçeveler bir süre daha gelmeye devam edebilir. Akışın kapanması IEvsCameraStream'e bildirilinceye kadar her karenin döndürülmesi gerekir. Zaten durdurulmuş veya hiç başlatılmamış bir akışta stopVideoStream çağrısını yapmak yasaldır; bu durumda bu çağrı dikkate alınmaz.

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 aktarılan hiçbir değer sürücüyü çökertemez. Tanınmayan herhangi bir opaqueIdentifier için sürücünün 0 döndürmesi gerekir.

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ğlanmıştır ve hiçbir HAL uygulaması, bu çağrının varsayılan durumda çalışmasını gerektirmemelidir. Sürücü değerleri tanıyıp kabul ederse OK döndürülmelidir; aksi takdirde INVALID_ARG veya diğer 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'den geçirilen bir görüntüyü açıklar. HAL sürücüsü, görüntü arabelleğini tanımlamak için bu yapının doldurulmasından sorumludur ve HAL istemcisi bu yapıyı salt okunur olarak ele almalıdır. Alanlar, görüntünün eglCreateImageKHR() uzantısı aracılığıyla EGL ile kullanılması gerekebileceği gibi, istemcinin bir ANativeWindowBuffer nesnesini yeniden yapılandırmasına imkan verecek yeterli bilgiyi içerir.

  • width . Sunulan görüntünün piksel cinsinden genişliği.
  • height . Sunulan görüntünün piksel cinsinden yüksekliği.
  • stride . Her satırın aslında bellekte kapladığı piksel sayısı, satırların hizalanması için yapılan dolguları hesaba katar. Gralloc'un arabellek açıklamaları için benimsediği kurala uyacak şekilde piksel cinsinden ifade edilir.
  • pixelSize . Her bir pikselin kapladığı bayt sayısı; görüntüdeki satırlar arasında adım atmak için gereken boyutun bayt cinsinden hesaplanmasına olanak tanır (bayt cinsinden stride = piksel cinsinden stride * pixelSize ).
  • format . Görüntünün kullandığı piksel biçimi. Sağlanan format, platformun OpenGL uygulamasıyla uyumlu olmalıdır. Uyumluluk testini geçebilmek için kamera kullanımında HAL_PIXEL_FORMAT_YCRCB_420_SP , görüntüleme için ise RGBA veya BGRA tercih edilmelidir.
  • usage . HAL uygulaması tarafından belirlenen kullanım bayrakları. HAL istemcilerinin bunları değiştirilmeden geçmesi beklenir (ayrıntılar için Gralloc.h ile ilgili işaretlere bakın).
  • bufferId . HAL API'leri arasında gidiş-dönüş sonrasında bir arabelleğin tanınmasına izin vermek için HAL uygulaması tarafından belirtilen benzersiz bir değer. Bu alanda saklanan değer HAL uygulaması tarafından keyfi olarak seçilebilir.
  • memHandle . Görüntü verilerini içeren temel bellek arabelleğinin tanıtıcısı. HAL uygulaması burada bir Gralloc arabellek tanıtıcısını saklamayı seçebilir.

IEvsKamera Akışı

İstemci, eşzamansız video karesi teslimatlarını almak için bu arayüzü uygular.

deliverFrame(BufferDesc buffer);

Bir video karesi incelemeye her hazır olduğunda HAL'den çağrıları alır. Bu yöntemle alınan arabellek tanıtıcıları IEvsCamera::doneWithFrame() çağrıları yoluyla döndürülmelidir. Video akışı IEvsCamera::stopVideoStream() çağrısı yoluyla durdurulduğunda, bu geri çağırma işlem hattı boşaldıkça devam edebilir. Her karenin yine de iade edilmesi gerekir; akıştaki son çerçeve teslim edildiğinde, akışın sonunu belirten bir NULL bufferHandle teslim edilir ve başka çerçeve teslimatı gerçekleşmez. NULL bufferHandle'ın kendisinin doneWithFrame() yoluyla geri gönderilmesine gerek yoktur, ancak diğer tüm tanıtıcıların döndürülmesi gerekir

Tescilli arabellek formatları teknik olarak mümkün olsa da uyumluluk testleri, arabelleğin desteklenen dört formattan birinde olmasını gerektirir: NV21 (YCrCb 4:2:0 Yarı Düzlemsel), YV12 (YCrCb 4:2:0 Düzlemsel), YUYV (YCrCb 4: 2:2 Aralıklı), RGBA (32 bit R:G:B:x), BGRA (32 bit B:G:R:x). Seçilen format, 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 aslında HAL sürücüsü uygulamasına özeldir ve bunları uygun gördüğü şekilde kullanabilir (ve yeniden kullanabilir).

IEvsEkran

Bu nesne Evs ekranını temsil eder, ekranın durumunu kontrol eder ve görüntülerin gerçek sunumunu yönetir.

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);

Görüntüleme durumunu ayarlar. İstemciler, görüntü durumunu istenen durumu ifade edecek şekilde ayarlayabilir ve HAL uygulaması, herhangi bir durumdayken herhangi bir durum için bir isteği incelikli bir şekilde kabul etmelidir; ancak yanıt, isteğin göz ardı edilmesi olabilir.

Başlatma sonrasında, ekran NOT_VISIBLE durumunda başlayacak şekilde tanımlanır; bundan sonra istemcinin VISIBLE_ON_NEXT_FRAME durumunu talep etmesi ve video sağlamaya başlaması beklenir. Görüntüye artık ihtiyaç duyulmadığında, istemcinin son video karesini geçtikten sonra NOT_VISIBLE durumunu talep etmesi beklenir.

Herhangi bir zamanda talep edilmesi her durum için geçerlidir. Ekran zaten görünürse, VISIBLE_ON_NEXT_FRAME olarak ayarlandığında görünür kalmalıdır. İstenen durum tanınmayan bir numaralandırma değeri olmadığı sürece her zaman Tamam değerini döndürür; bu durumda INVALID_ARG döndürülür.

getDisplayState() generates (DisplayState state);

Görüntüleme durumunu alır. HAL uygulaması, en son talep edilen durumdan farklı olabilecek gerçek mevcut durumu rapor etmelidir. Görüntüleme durumlarını değiştirmekten sorumlu olan mantık, cihaz katmanının üzerinde mevcut olmalıdır; bu da HAL uygulamasının görüntü durumlarını kendiliğinden değiştirmesini istenmeyen bir hale getirir.

getTargetBuffer() generates (handle bufferHandle);

Ekranla ilişkili çerçeve arabelleğine bir tanıtıcı döndürür. Bu arabellek yazılım ve/veya GL tarafından kilitlenebilir ve yazılabilir. Bu arabellek, ekran artık görünür olmasa bile, returnTargetBufferForDisplay() çağrısı yoluyla döndürülmelidir.

Tescilli arabellek formatları teknik olarak mümkün olsa da uyumluluk testleri, arabelleğin desteklenen dört formattan birinde olmasını gerektirir: NV21 (YCrCb 4:2:0 Yarı Düzlemsel), YV12 (YCrCb 4:2:0 Düzlemsel), YUYV (YCrCb 4: 2:2 Aralıklı), RGBA (32 bit R:G:B:x), BGRA (32 bit B:G:R:x). Seçilen format, platformun GLES uygulamasında geçerli bir GL oluşturma hedefi olmalıdır.

Hata durumunda, boş tanıtıcıya sahip bir arabellek döndürülür, ancak böyle bir arabelleğin returnTargetBufferForDisplay öğesine geri iletilmesi gerekmez.

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

Ekrana arabelleğin görüntülenmeye hazır olduğunu söyler. Yalnızca getTargetBuffer() çağrısı yoluyla alınan arabellekler bu çağrıyla kullanım için geçerlidir ve BufferDesc içeriği istemci uygulaması tarafından değiştirilemez. Bu çağrıdan sonra arabellek artık istemci tarafından kullanım için geçerli değildir. Başarı durumunda Tamam'ı veya INVALID_ARG veya BUFFER_NOT_AVAILABLE dahil olmak üzere potansiyel olarak uygun hata kodunu döndürür.

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

Bir EVS ekranının temel özelliklerini ve bir EVS uygulamasının gerektirdiği temel özellikleri açıklar. HAL, EVS ekranını tanımlamak için bu yapının doldurulmasından sorumludur. Fiziksel bir ekran veya başka bir sunum cihazıyla kaplanmış veya karıştırılmış sanal bir ekran olabilir.

  • display_id . Ekranı benzersiz şekilde tanımlayan bir dize. Bu, aygıtın çekirdek aygıt adı veya aygıtın dikiz gibi bir adı olabilir. 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 . Özel kamera bilgilerini sürücüden özel bir EVS uygulamasına opak bir şekilde aktarmaya yönelik bir yöntem. Sürücüden EVS uygulamasına yorumlanmadan aktarılır ve bu uygulama bunu göz ardı etmekte özgürdür.
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
}

Devre dışı bırakılabilen (sürücü tarafından görülemeyen) veya etkinleştirilebilen (sürücüye bir görüntü gösteren) EVS ekranının durumunu açıklar. Ekranın henüz görünür olmadığı ancak bir sonraki görüntü karesinin returnTargetBufferForDisplay() çağrısı aracılığıyla sunulmasıyla görünür olmaya hazırlandığı geçici bir durumu içerir.

AGH Müdürü

EVS Yöneticisi, harici kamera görüntülerini toplamak ve sunmak için EVS sistemine genel arayüz sağlar. Donanım sürücülerinin kaynak (kamera veya ekran) başına yalnızca bir aktif arayüze izin verdiği durumlarda EVS Yöneticisi, kameralara paylaşımlı erişimi kolaylaştırır. Tek bir birincil EVS uygulaması, EVS Manager'ın ilk istemcisidir ve ekran verilerini yazmasına izin verilen tek istemcidir (ek istemcilere kamera görüntülerine salt okunur erişim verilebilir).

EVS Yöneticisi, temel HAL sürücüleri ile aynı API'yi uygular ve birden fazla eşzamanlı istemciyi destekleyerek genişletilmiş hizmet sağlar (birden fazla istemci, EVS Yöneticisi aracılığıyla bir kamera açabilir ve bir video akışı alabilir).

EVS Yöneticisi ve EVS Donanım API diyagramı.

Şekil 2. EVS Yöneticisi, temel EVS Donanım API'sini yansıtır.

Uygulamalar, EVS Donanım HAL uygulaması veya EVS Manager API'si aracılığıyla çalışırken, EVS Manager API'sinin eşzamanlı kamera akışı erişimine izin vermesi dışında hiçbir fark görmez. EVS Yöneticisi, EVS Donanım HAL katmanının izin verilen tek istemcisidir ve EVS Donanım HAL'i için bir proxy görevi görür.

Aşağıdaki bölümlerde yalnızca AGH Yöneticisi uygulamasında farklı (genişletilmiş) davranışa sahip olan çağrılar açıklanmaktadır; kalan aramalar EVS HAL açıklamalarıyla aynıdır.

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

Benzersiz kamera_id dizesi tarafından tanımlanan belirli bir kamerayla etkileşimde bulunmak için kullanılan bir arayüz nesnesi elde eder. Başarısızlık durumunda NULL döndürür. EVS Yöneticisi katmanında, yeterli sistem kaynakları mevcut olduğu sürece, zaten açık olan bir kamera başka bir işlemle tekrar açılarak video akışının birden fazla tüketici uygulamasına bağlanmasına olanak tanır. EVS Yöneticisi katmanındaki camera_id dizeleri, EVS Donanım katmanına bildirilenlerle aynıdır.

IEvsKamera

EVS Yöneticisi tarafından sağlanan IEvsCamera uygulaması dahili olarak sanallaştırılmıştır, böylece bir istemcinin bir kamera üzerinde yaptığı işlemler diğer istemcileri etkilemez ve bu istemciler kendi kameralarına bağımsız erişime sahiptir.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

Video akışlarını başlatır. İstemciler aynı temel kamera üzerinde video akışlarını bağımsız olarak başlatabilir ve durdurabilir. Temel kamera, ilk istemci başlatıldığında başlar.

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

Bir çerçeve döndürür. Her müşterinin işi bittiğinde çerçevelerini iade etmesi gerekir, ancak çerçevelerini istedikleri kadar tutmalarına izin verilir. İstemcinin 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, tüm kareleri beklendiği gibi almaya devam eden diğer istemcileri etkilemez.

stopVideoStream();

Bir 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öndererek bir istemcinin başka bir istemciyi etkileme potansiyeline sahip olmasını sağlar. EVS Yöneticisi, satıcı tarafından tanımlanan kontrol kelimelerinin sonuçlarını anlayamadığından, bunlar sanallaştırılmaz ve herhangi bir yan etki, belirli bir kameranın tüm istemcilerine uygulanır. Örneğin, bir satıcı bu çağrıyı kare hızlarını değiştirmek için kullanırsa, etkilenen donanım katmanı kamerasının tüm istemcileri kareleri yeni hızda alacaktır.

IEvsEkran

AGH Yöneticisi düzeyinde bile ekranın yalnızca bir sahibine izin verilir. Yönetici hiçbir işlevsellik eklemez ve IEvsDisplay arayüzünü doğrudan temeldeki HAL uygulamasına aktarır.

AGH 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, mevcut kameralara ve aracın durumuna (vites ve dönüş sinyali durumu) bağlı olarak uygun videonun gösterilmesiyle, sistem önyükleme sürecinin çok erken bir aşamasında başlaması bekleniyor. OEM'ler EVS uygulamasını kendi araca özel mantık ve sunumlarıyla değiştirebilir veya değiştirebilir.

Şekil 3. EVS uygulaması örnek mantığı, kamera listesini alın.



Şekil 4. EVS uygulaması örnek mantığı, çerçeve geri çağırma alma.

Görüntü verileri uygulamaya standart bir grafik arabelleğinde sunulduğundan, uygulamanın kaynak arabellekten çıktı arabelleğine taşınmasından uygulama sorumludur. Bu, bir veri kopyasının maliyetini ortaya çıkarırken, aynı zamanda uygulamanın görüntüyü ekran arabelleğine istediği şekilde oluşturma fırsatını da sunar.

Örneğin uygulama, potansiyel olarak satır içi ölçekleme veya döndürme işlemiyle piksel verilerini kendisi taşımayı seçebilir. Uygulama ayrıca kaynak görüntüyü bir OpenGL dokusu olarak kullanmayı ve simgeler, kılavuzlar ve animasyonlar gibi sanal öğeler dahil olmak üzere karmaşık bir sahneyi çıktı arabelleğine işlemeyi de seçebilir. Daha karmaşık bir uygulama aynı zamanda birden fazla eşzamanlı giriş kamerasını seçip bunları tek bir çıkış çerçevesinde birleştirebilir (örneğin, araç çevresinin yukarıdan aşağıya, sanal görünümünde kullanım için).

EVS Ekran HAL'inde EGL/SurfaceFlinger'ı kullanın

Bu bölümde, Android 10'da bir EVS Display HAL uygulaması oluşturmak için EGL'nin nasıl kullanılacağı açıklanmaktadır.

Bir EVS HAL referans uygulaması, ekranda kamera önizlemesini oluşturmak için EGL'yi kullanır ve hedef EGL oluşturma yüzeyini oluşturmak için libgui kullanır. Android 8'de (ve üzeri), libgui , VNDK-private olarak sınıflandırılır; bu, VNDK kitaplıklarının kullanabileceği ve satıcı işlemlerinin kullanamayacağı bir kitaplık grubunu ifade eder. HAL uygulamalarının satıcı bölümünde bulunması gerektiğinden satıcıların HAL uygulamalarında Surface kullanması engellenir.

Satıcı süreçleri için libgui oluşturma

libgui kullanımı, EVS Display HAL uygulamalarında EGL/SurfaceFlinger'ı kullanmanın tek seçeneği olarak hizmet vermektedir. libgui uygulamanın en basit yolu, derleme betiğinde ek bir derleme hedefi kullanarak doğrudan çerçeveler/native/libs/gui'yi kullanmaktı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 makrosu ile oluşturulmuştur. SurfaceFlinger bu alanın kaldırılmasını beklediğinden SurfaceFlinger paketi ayrıştıramaz. Bu bir fcntl hatası olarak gözlenir:

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);

Örnek oluşturma 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ı kullanın

Android 8'de (ve üzeri), /dev/binder aygıt düğümü çerçeve işlemlerine özel hale geldi ve bu nedenle satıcı işlemlerine erişilemez hale geldi. Bunun yerine satıcı işlemleri /dev/hwbinder kullanmalı ve tüm AIDL arayüzlerini HIDL'ye dönüştürmelidir. Satıcı işlemleri arasında AIDL arayüzlerini kullanmaya devam etmek isteyenler için bağlayıcı etki alanını /dev/vndbinder kullanın.

IPC Alanı Tanım
/dev/binder AIDL arayüzleriyle çerçeve/uygulama işlemleri arasındaki IPC
/dev/hwbinder HIDL arayüzleriyle çerçeve/satıcı işlemleri arasındaki IPC
HIDL arayüzleriyle satıcı işlemleri arasında IPC
/dev/vndbinder AIDL Arayüzleriyle satıcı/satıcı işlemleri arasındaki IPC

SurfaceFlinger, AIDL arayüzlerini tanımlarken satıcı 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 önemsiz miktarda çalışma gereklidir. Neyse ki Android, kullanıcı alanı kitaplığı işlemlerinin bağlı olduğu libbinder için ciltleyici sürücüsünün seçileceği 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: Satıcı işlemleri, Process veya IPCThreadState öğesini çağırmadan veya herhangi bir ciltleyici çağrısı yapmadan önce bunu çağırmalıdır.

SELinux politikaları

Cihaz uygulaması tam tiz ise, SELinux satıcı işlemlerinin /dev/binder kullanmasını engeller. Örneğin, bir EVS HAL örnek uygulaması hal_evs_driver etki alanına atanır ve binder_device etki alanına 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 tizli bir cihaz için system/sepolicy/domain.te dosyasında tanımlanan aşağıdaki asla izin vermeme 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. 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)

Satıcı süreci olarak bir EVS HAL referans uygulaması oluşturun

Referans olarak aşağıdaki değişiklikleri packages/services/Car/evs/Android.mk dosyasına uygulayabilirsiniz. Açıklanan tüm değişikliklerin uygulamanız için işe yaradığı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;