Araç Kamerası HAL'si

Android, Android önyükleme işleminin çok erken aşamalarında görüntü yakalama ve görüntüleme olanağı sağlayan ve sistemin kullanım ömrü boyunca çalışmaya devam eden bir otomotiv HIDL Donanım Soyutlamalı Katmanı (HAL) içerir. HAL, dıştan görünüm sistemi (EVS) yığınını içerir ve genellikle Android tabanlı Araç İçi Bilgi-eğlence (IVI) sistemlerine sahip araçlarda dikiz kamerası ve surround görünüm 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 kullanılması, arayüzlerin sadeleşmesini sağlar ve bir OEM'in EVS yığınını desteklemek için neleri uygulaması gerektiğini açıkça gösterir.

Sistem bileşenleri

EVS aşağıdaki sistem bileşenlerini içerir:

EVS sistemi bileşenleri şeması
Şekil 1. EVS sistem bileşenlerine genel bakış.

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 istemekten ve tamamlanmış kareleri görüntüleme için EVS Yöneticisi'ne geri göndermekten sorumludur. EVS ve Car Service kullanılabilir hale gelir gelmez init tarafından başlatılması beklenir. Hedef, güç açıldıktan sonraki iki (2) saniye içinde başlatılmasıdır. 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 Araba Hizmeti), EVS sisteminin ne zaman aktif 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ü çalıştıran (sentetik test görüntüleri oluşturan ve gidiş dönüşü oluşturan görüntüleri doğrulayan) örnek bir uygulama /hardware/interfaces/automotive/evs/1.0/default içinde 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ırıp toplamaktan ve Gralloc tarafından tanınabilen paylaşılan bellek arabellekleriyle yayınlamaktan sorumludur. Uygulamanın görüntü tarafı, uygulama tarafından doldurulabilen (genellikle EGL oluşturma ile) paylaşılan bir bellek arabelleği sağlamaktan ve bitmiş kareleri fiziksel ekranda görünmek isteyecek 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 veya ekran donanım sürücüleri aracılığıyla EVS'nin gerektirdiği ö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 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çi firmaların, bu API'nin donanımlarına uyarlanmış uygulamalarını sağlaması beklenir.

IEvsEnumerator

Bu nesne, sistemdeki kullanılabilir EVS donanımlarını (bir veya daha fazla kamera ve tek ekran cihazı) saymaktan 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 önyükleme sırasında bilindiği varsayılı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. Hata durumunda NULL değeri 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);

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

Yalnızca sistemin EVS ekranıyla etkileşim kurmak için kullanılan bir arayüz nesnesi alır. Aynı anda yalnızca bir istemci IEvsDisplay'ın işlevsel bir örneğini tutabilir. openCamera bölümünde açıklanan agresif açık davranışa benzer şekilde, her zaman yeni bir IEvsDisplay nesnesi oluşturulabilir ve önceki tüm örnekleri 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() aramaları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ın değiştirilmesinden sorumlu mantık, cihaz katmanının üzerinde bulunmalıdır. Bu nedenle, HAL uygulamasının ekran durumlarının kendiliğinden değişmesi istenmeyen bir durumdur. Ekran şu anda herhangi bir müşteri tarafından tutulmuyorsa (openDisplay çağrısı ile) 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 bir 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 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.

IEvsCamera

Bu nesne tek bir kamerayı temsil eder ve resim çekmek için 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 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 IEvsCamera varsayılan olarak en az bir kareyi destekler. Daha fazla kare kabul edilir.

İstenen bufferCount kullanılamazsa işlev BUFFER_NOT_AVAILABLE veya ilgili başka bir hata kodunu döndürür. Bu durumda sistem, daha önce ayarlanmış değerle çalışmaya devam eder.

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

EVS kamera çerçevelerinin bu kameradan teslim edilmesini istiyor. 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 sonra 500 ms. içinde teslim edilmeye başlamalı ve başlatıldı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ılmamışsa 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. IEvsCameraStream arayüzüne iletilen bir çerçeveyi kullandıktan sonra, çerçeve yeniden kullanılmak üzere IEvsCamera'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 eşzamansız olduğundan, çerçeveler bu çağrı geri döndükten bir süre sonra 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 özgü bilgiler 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ülür. Aksi takdirde INVALID_ARG veya başka bir temsili hata kodu döndürülür.

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 iletilen bir resmi tanımlar. 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. Alanlar, istemcinin bir ANativeWindowBuffer nesnesini yeniden oluşturmasına olanak tanıyacak kadar bilgi içerir. Bunun nedeni, resmin eglCreateImageKHR() uzantısıyla EGL ile kullanılması gerekebilir.

  • 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 uygun şekilde 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 cinsinden stride = piksel cinsinden stride * 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çin HAL_PIXEL_FORMAT_YCRCB_420_SP, ekran için ise RGBA veya BGRA 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çin Gralloc.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. Resim verilerini içeren temel bellek arabelleğinin tutamaç. HAL uygulaması burada bir Gralloc arabelleği tutamacını depolayabilir.

IEvsCameraStream

İ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öntemle alınan arabellek herkese açık kimlikleri, 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şaldıkça bu geri çağırma devam edebilir. Her kare yine de döndürülmelidir. Akıştaki son kare yayınlandığında, akış sona erdiğini ve başka kare yayını yapılmadığını belirten NULL bufferHandle yayınlanır. bufferHandle NULL değerinin doneWithFrame() ile birlikte geri gönderilmesi gerekmez ancak diğer tüm herkese açık kullanıcı adları 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 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).

IEvsDisplay

Bu nesne Evs ekranını temsil eder, ekranın durumunu kontrol eder ve resimlerin gerçek sunumunu işler.

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. Görüntü artık gerekli olmadığında, istemcinin son video karesini geçtikten sonra NOT_VISIBLE durumunu istemesi beklenir.

İstediğiniz zaman herhangi bir eyalet için istek gönderebilirsiniz. Ekran zaten görünüyorsa VISIBLE_ON_NEXT_FRAME olarak ayarlanırsa görünür durumda kalır. İ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ı 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.

getTargetBuffer() generates (handle bufferHandle);

Ekranla ilişkili bir çerçeve arabelleğine herkese açık kullanıcı adı 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ı ile 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.

Hata oluştuğunda, null tutamaç içeren bir arabellek döndürülür ancak bu tür bir arabelleğin returnTargetBufferForDisplay'e geri aktarılması 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. EVS ekranını tanımlamak için bu yapının doldurulmasından HAL sorumludur. Fiziksel bir ekran veya başka bir sunum cihazıyla yer paylaşımlı ya da birlikte kullanılan sanal bir ekran olabilir.

  • display_id. Ekranı benzersiz şekilde tanımlayan bir dize. Bu, cihazın çekirdek cihaz adı veya cihaz için bir 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 yöntem, sürücüden yorum yapılmadan EVS uygulamasına iletilir. Bu uygulamayı görmezden gelebilirsiniz.
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ıyla sonraki görüntü çerçevesinin 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ü 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 (birden fazla istemci, EVS Yöneticisi aracılığıyla bir kamera açabilir ve video akışı alabilir).

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

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.

IEvsNumaralandırıcı

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önetici katmanında, yeterli sistem kaynağı mevcut olduğu sürece, halihazırda açık olan bir kamera başka bir işlem tarafından tekrar açılabilir. Böylece, video akışı birden fazla tüketici uygulamasına gösterilir. 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, kameralarına bağımsız erişim sağlayan 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ş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. Bir istemci tarafından tutulan kare sayısı yapılandırılmış sınırına ulaştığında, bir kare döndürülene 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 istemci, diğer istemcileri etkilemeden video aktarımını istediği zaman durdurabilir. Belirli bir kameranın son istemcisi akışı durdurduğunda, donanım katmanındaki alttaki 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 etkilemesini sağlayabilir. EVS Yöneticisi tedarikçi tarafından tanımlanan kontrol kelimelerinin etkilerini anlayamadığı için bu kelimeler sanallaştırılmaz ve belirli bir kameranın tüm müşterileri için yan etkiler 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.

IEvsEkran

EVS yöneticisi düzeyinde bile ekranın yalnızca bir sahibi olabilir. Yönetici herhangi bir işlev eklemez ve IEvsDisplay arayüzünü doğrudan temel HAL uygulamasına iletir.

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 önyükleme işleminin çok erken bir aşamasında başlaması ve mevcut kameralara ve aracın durumuna (vites 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 al.


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

Resim verileri uygulamaya standart bir grafik arabelleğinde sunulduğundan, resmi kaynak arabelleğinden çıkış arabelleğine taşıma sorumluluğu uygulamaya aittir. Bu, veri kopyalama maliyetini beraberinde getirse de uygulamanın resmi ekran arabelleğine istediği şekilde oluşturma fırsatı da sunar.

Örneğin, uygulama, satır içi ölçek veya döndürme işlemiyle birlikte pikselin kendisini taşımayı seçebilir. Uygulama ayrıca kaynak görüntüyü bir OpenGL dokusu olarak kullanmayı ve çıkış arabelleğine simgeler, yönergeler ve animasyonlar gibi sanal öğeler de dahil olmak üzere karmaşık bir sahne oluşturmayı da seçebilir. Daha gelişmiş bir uygulama da aynı anda birden fazla giriş kamerasını seçip bunları tek bir çıkış çerçevesine ekleyebilir (örneğin, araç çevresinin yukarıdan aşağıya, sanal görünümünde kullanım için).

EVS Görüntü HAL'inde 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'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 bölümünde bulunması gerektiğinden, tedarikçilerin HAL uygulamalarında Surface'i 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 öğesini uygulamanın en basit yolu, derleme komut dosyasında doğrudan frameworks/native/libs/gui kullanarak ek bir derleme hedefi 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: 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 bir 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 bağlayıcı 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üzlerine sahip çerçeve/tedarikçi süreçleri arasındaki IPC
HIDL arayüzlerine sahip tedarikçi süreçleri arasındaki 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 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, 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 süreci olarak 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 geçerli olduğundan 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;