Sao Nian! Android görüşmecilerini tamamen fethetmek için Binder ilkesini kullanın

Önsöz

ServiceManager'da Binder mekanizmasını öğrenme sürecinde, alan problemlerinden dolayı kapsanmayan bir problem var ve MediaPlayerService bu şekilde kaydediliyor. MediaPlayerService'in nasıl kaydedildiğini anlayarak, sistem hizmetlerinin kayıt sürecini öğrenebilirsiniz.

1. MediaPlayerService'in çağrı zinciri açısından nasıl kaydedildiğini açıklayın

Önce MediaServer'ın giriş fonksiyonuna bakalım, kod aşağıda gösterilmiştir. çerçeveler / av / media / mediaserver / main_mediaserver.cpp

int main (int argc __unused, char ** argv __unused) { sinyal (SIGPIPE, SIG_IGN); // ProcessState örneğini alın sp < ProcessState > proc (ProcessState :: self ()); sp < IServiceManager > sm (defaultServiceManager ()); ALOGI ("ServiceManager:% p", sm.get ()); InitializeIcuOrDie (); // MediaPlayerService'i kaydettirin MediaPlayerService :: instantiate (); // 1 ResourceManagerService :: instantiate (); registerExtensions (); // Binder iş parçacığı havuzunu başlat ProcessState :: self () - > startThreadPool (); // Mevcut iş parçacığı iş parçacığı havuzuna eklenir IPCThreadState :: self () - > joinThreadPool (); }

Bu koddaki içeriğin çoğu önceki makalede tanıtılmıştı ve ardından kodu yorum 1'de analiz edin.

çerçeveler / av / media / libmediaplayerservice / MediaPlayerService.cpp

void MediaPlayerService :: instantiate () { defaultServiceManager () - > addService ( String16 ("media.player"), yeni MediaPlayerService, ()); }

Hangi defaultServiceManager dönüşü BpServiceManager'dır.Binder'in bu kadar zayıf olduğu ve Tencent ile röportaj yapmaya geldiği açık değil mi? ServiceManager'daki Bağlayıcı mekanizmasıyla ilgili bu makale. Parametre, kaydı tamamlamak için Anahtar / Değer'e benzeyen bir dize ve MediaPlayerService'dir ve ardından addService işlevine bakar.

çerçeveler / native / libs / binder / IServiceManager.cpp

sanal durum_t addService (const String16 adı, const sp < IBinder > hizmet, bool allowIsolated, int dumpsysPriority) { Parsel verileri, yanıt; // veri paketi data.writeInterfaceToken (IServiceManager :: getInterfaceDescriptor ()); data.writeString16 (name); // isim değeri "media.player" data.writeStrongBinder (servis); // servis değeri MediaPlayerService data.writeInt32 (allowIsolated? 1: 0); data.writeInt32 (dumpsysPriority); status_t err = uzak () - > transact (ADD_SERVICE_TRANSACTION, veri, cevap); // 1 dönüş hatası == HATA HAYIR? answer.readExceptionCode (): hata; }

Veriler, verileri daha sonra verilere yazmaya devam edecek olan bir veri paketidir Not 1'deki remote (), BpBinder olan mRemote'a atıfta bulunur. AddService işlevinin işlevi, istenen verileri verilere paketlemek ve daha sonra BpBinder'ın işlem işlevine iletmektir. Kod aşağıda gösterilmiştir.

çerçeveler / native / libs / binder / BpBinder.cpp

status_t BpBinder :: transact ( uint32_t kodu, const Parcel verileri, Parsel * yanıtı, uint32_t işaretleri) { if (mAlive) { status_t status = IPCThreadState :: self () - > işlem ( mHandle, kod, veri, yanıt, bayraklar); eğer (durum == DEAD_OBJECT) mAlive = 0; iade durumu; } DEAD_OBJECT döndür; }

BpBinder mantık işlemeyi IPCThreadState'e verir. İlk önce IPCThreadState :: self () ne yaptı? çerçeveler / native / libs / binder / IPCThreadState.cpp

IPCThreadState * IPCThreadState :: self () { // gHaveTLS'nin ilk kez gelen değeri yanlıştır eğer (gHaveTLS) { tekrar başlat: const pthread_key_t k = gTLS; // 1 IPCThreadState * st = (IPCThreadState *) pthread_getspecific (k); // 2 eğer (st) st döndürür; yeni IPCThreadState; // 3 döndür } ... pthread_mutex_unlock (gTLSMutex); yeniden başlatmaya git; }

Not 1 TLS'nin tam adı, iş parçacığı yerel depolama alanını ifade eden İş Parçacığı yerel depolamadır.Her iş parçacığında TLS vardır ve iş parçacıkları arasında paylaşılmaz. Not 2, içeriği TLS'de elde etmek ve IPCThreadState * işaretçisine atamak için kullanılır. Not 3, yeni bir IPCThreadState oluşturacaktır, burada IPCThreadState :: self () 'in aslında IPCThreadState oluşturacağını biliyorsunuz, yapıcısı aşağıdaki gibidir.

çerçeveler / native / libs / binder / IPCThreadState.cpp

IPCThreadState :: IPCThreadState () : mProcess (ProcessState :: self ()), mStrictModePolicy (0), mLastTransactionBinderFlags (0) { pthread_setspecific (gTLS, bu); // 1 clearCaller (); mIn.setDataCapacity (256); mOut.setDataCapacity (256); }

Not 1'deki pthread_setspecific işlevi TLS'yi ayarlamak ve IPCThreadState :: self () ve kendisi tarafından elde edilen TLS'yi geçirmek için kullanılır.

IPCThreadState ayrıca mIn ve bir mOut içerir; burada mIn, Binder sürücüsünden veri almak için kullanılır ve mOut, Ciltleyici sürücüsüne gönderilen verileri depolamak için kullanılır ve varsayılan boyutu 256 bayttır.

IPCThreadState yapıcısını öğrenin, IPCThreadState'in işlem işlevini görmek için geri gelin.

çerçeveler / native / libs / binder / IPCThreadState.cpp

status_t IPCThreadState :: transact (int32_t tutamaç, uint32_t kodu, const Parcel verileri, Parsel * yanıtı, uint32_t işaretleri) { status_t err; bayraklar | = TF_ACCEPT_FDS; ... err = writeTransactionData (BC_TRANSACTION, bayraklar, tutamaç, kod, veri, NULL); // 1 eğer (err! = NO_ERROR) { eğer (cevap) cevapla- > setError (err); dönüş (mLastError = hata); } if ((bayraklar ve TF_ONE_WAY) == 0) { ... eğer (cevap) { err = waitForResponse (cevap); // 2 } Başka { Parsel fakeReply; err = waitForResponse (fakeReply); } ... } Başka { // Cevap dalını beklemeye gerek yok err = waitForResponse (NULL, NULL); } dönüş hatası; }

BpBinder'ın işlem işlevini çağırmak aslında IPCThreadState'in işlem işlevini çağırmaktır. Not 1'deki writeTransactionData işlevi verileri aktarmak için kullanılır.İlk parametre BC_TRANSACTION, Binder sürücüsüne gönderilen komut protokolünü temsil eder.Binder cihazına gönderilen komut protokolü BC_ ile başlar ve Binder sürücüsü tarafından döndürülen komut protokolü BR_ ile başlar. Bu komuta anlaşmasını hatırlayalım ve ona daha sonra tekrar değineceğiz.

Şimdi not 1'in writeTransactionData işlevini ve not 2'nin waitForResponse işlevini analiz edelim.

1.1 writeTransactionData işlevinin analizi

çerçeveler / native / libs / binder / IPCThreadState.cpp

status_t IPCThreadState :: writeTransactionData (int32_t cmd, uint32_t binderFlags, int32_t tutamaç, uint32_t kodu, const Parcel verileri, status_t * statusBuffer) { binder_transaction_data tr; // 1 tr.target.ptr = 0; tr.target.handle = tutamaç; // 2 tr.code = code; // code = ADD_SERVICE_TRANSACTION tr.flags = binderFlags; tr.cookie = 0; tr.sender_pid = 0; tr.sender_euid = 0; const status_t err = data.errorCheck (); // 3 eğer (err == NO_ERROR) { tr.data_size = data.ipcDataSize (); tr.data.ptr.buffer = data.ipcData (); tr.offsets_size = data.ipcObjectsCount () * sizeof (binder_size_t); tr.data.ptr.offsets = data.ipcObjects (); } else if (statusBuffer) { tr.flags | = TF_STATUS_CODE; * statusBuffer = hata; tr.data_size = sizeof (durum_t); tr.data.ptr.buffer = reinterpret_cast < uintptr_t > (statusBuffer); tr.offsets_size = 0; tr.data.ptr.offsets = 0; } Başka { dönüş (mLastError = hata); } mOut.writeInt32 (cmd); // cmd = BC_TRANSACTION mOut.write (tr, sizeof (tr)); NO_ERROR döndür; }

Not 1'deki binder_transaction_data yapısı (tr yapısı), Binder ile iletişimi yönlendiren bir veri yapısıdır Not 2'de, tutamaç, hedefi tanımlamak için hedefin tutamacına geçirilir Buradaki tutamacın değeri, ServiceManager'ı temsil eden 0'dır. Not 3, veriler hatalara karşı kontrol edilir, herhangi bir hata yoksa, veri ilgili tr yapısına atanır. Son olarak, BC_TRANSACTION ve tr yapısı mOut'a yazılacaktır.

Yukarıdaki kod çağrı zincirinin sıra diyagramı aşağıda gösterilmektedir.

1.2 waitForResponse fonksiyon analizi

Sonra, waitForResponse işlevinin ne yaptığını görmek için geriye dönüp bakın .. waitForResponse işlevinde birçok durum ifadesi vardır, bu nedenle kodun bir kısmı burada verilmiştir. çerçeveler / native / libs / binder / IPCThreadState.cpp

status_t IPCThreadState :: waitForResponse (Parcel * yanıt, status_t * acquireResult) { uint32_t cmd; int32_t err; while (1) { eğer ((err = talkWithDriver ()) < NO_ERROR) break; // 1 err = mIn.errorCheck (); eğer (err < NO_ERROR) mola; (mIn.dataAvail () == 0) devam ederse; cmd = (uint32_t) mIn.readInt32 (); IF_LOG_COMMANDS () { bir kayıt < < "WaitForResponse Komutu işleniyor:" < < getReturnString (cmd) < < endl; } anahtarı (cmd) { durum BR_TRANSACTION_COMPLETE: eğer (! answer! acquireResult) bitirmek; kırmak; durum BR_DEAD_REPLY: err = DEAD_OBJECT; git bitirmek; ... varsayılan: // Çeşitli komut protokollerini işleyin err = executeCommand (cmd); eğer (err! = NO_ERROR) bitirmeye git; kırmak; } } bitiş: ... dönüş hatası; }

Not 1 talkWithDriver işlevi Binder sürücüsü ile ioctl aracılığıyla iletişim kurar.Kod aşağıda gösterilmiştir. çerçeveler / native / libs / binder / IPCThreadState.cpp

status_t IPCThreadState :: talkWithDriver (bool doReceive) { eğer (mProcess- > mDriverFD < = 0) { dönüş -EBADF; } // Binder sürücüsüyle iletişim yapısı binder_write_read bwr; // 1 // mIn'de okunabilir veri var mı? Alınan veriler mIn'de saklanır const bool needRead = mIn.dataPosition () > = mIn.dataSize (); const size_t outAvail = (! doReceive || needRead)? mOut.dataSize (): 0; bwr.write_size = outAvail; bwr.write_buffer = (uintptr_t) mOut.data (); // 2 // doReceive'in değeri şu anda doğrudur if (doReceive needRead) { bwr.read_size = mIn.dataCapacity (); bwr.read_buffer = (uintptr_t) mIn.data (); // 3 } Başka { bwr.read_size = 0; bwr.read_buffer = 0; } ... eğer ((bwr.write_size == 0) (bwr.read_size == 0)) NO_ERROR döndür; bwr.write_consumed = 0; bwr.read_consumed = 0; status_t err; yapmak { IF_LOG_COMMANDS () { bir kayıt < < "Okumak / yazmak üzere, size = yazma" < < mOut.dataSize () < < endl; } # tanımlıysa (__ ANDROID__) eğer (ioctl (mProcess- > mDriverFD, BINDER_WRITE_READ, bwr) > = 0) // 4 err = NO_ERROR; Başka err = -errno; #Başka err = INVALID_OPERATION; #endif ... } while (err == -EINTR); ... dönüş hatası; }

Not 1'deki binder_write_read, Binder sürücüsüyle iletişim kuran bir yapıdır. Not 2 ve 3'te, mOut ve mIn'i ilgili binder_write_read alanlarına atayın ve son olarak not 4'teki ioctl işlevi aracılığıyla Binder sürücüsü ile iletişim kurun. Binder içeriği ayrıntılı olarak tanıtılmayacaktır.

1.3 Bölüm

Çağrı zinciri açısından, MediaPlayerService'in nasıl kaydedildiği karmaşık görünmüyor, çünkü burada bir çağrı zinciri şubesine kısa bir giriş, aşağıdaki adımlar olarak kısaca özetlenebilir:

  • AddService işlevi verileri paketler ve işlenmesi için BpBinder'e gönderir.
  • BpBinder yeni bir IPCThreadState nesnesi oluşturur ve iletişim görevini IPCThreadState'e devreder.
  • IPCThreadState'in writeTransactionData işlevi, komut protokolünü ve verileri mOut'a yazmak için kullanılır.
  • IPCThreadState'in waitForResponse işlevi temelde iki şey yapar: Bir şey, ioctl işlevi aracılığıyla mOut ve mIn'i çalıştırarak Binder sürücüsüyle etkileşim kurmak, diğeri ise çeşitli komut protokollerini işlemektir.
  • 2. MediaPlayerService'in süreç açısından nasıl kaydedildiğini açıklayın

    Aslında, MediaPlayerService kaydı, aşağıdaki şekilde gösterildiği gibi süreci de içerir.

    C / S mimarisine dayandığı ve addService'in Client tarafı olan MediaPlayerService'de yapıldığı ve sistem servislerinin eklenmesini talep etmek için kullanıldığı şekilden görülebilmektedir. Sunucu tarafı, sistem hizmetlerinin eklenmesini tamamlamak için kullanılan ServiceManager'ı ifade eder.

    İstemci tarafı ve Sunucu tarafı sırasıyla iki işlemde çalışır ve Bağlayıcı aracılığıyla iletişim kurar. Daha ayrıntılı bir açıklama, her iki ucun da Binder sürücüsüne bir komut protokolü göndererek sistem hizmetlerinin eklenmesini tamamlamasıdır. Birçok komut protokolü vardır ve süreç daha karmaşıktır.Komut protokolü burada basitleştirilmiştir ve sadece dört komut protokolü söz konusudur.Bunlardan BC_TRANSACTION ve BR_TRANSACTION işlemi tam bir işlemdir ve BC_REPLY ve BR_REPLY tam bir işlemdir.

    İstemci ve Sunucu tarafından Bağlayıcı sürücüsüne gönderilen komut protokolü BC ile başlar ve Bağlayıcı sürücüsü tarafından İstemciye ve Sunucuya döndürülen komut protokolü BR_ ile başlar.

    Adımlar aşağıdaki gibidir:

    1. İstemci BC_TRANSACTION komutunu Binder sürücüsüne gönderir. 2. Bağlayıcı sürücüsü, talebi aldıktan sonra BR_TRANSACTION komutunu üretir ve Sunucuyu uyandırdıktan sonra BR_TRANSACTION komutunu ServiceManager'a gönderir. 3. Sunucu tarafında hizmet kaydı tamamlandıktan sonra, BC_REPLY komutu üretilir ve Ciltleyici sürücüsüne gönderilir. 4. Ciltleyici sürücüsü BR_REPLY komutunu üretir ve istemciyi uyandırdıktan sonra istemciye BR_REPLY komutunu gönderir.

    Bu protokol komutları, sistem hizmetlerinin kaydını sürmek ve tamamlamak için kullanılır.

    3. Özet

    Bu makale, MediaPlayerService hizmetinin çağrı zinciri perspektifinden ve süreç perspektifinden nasıl kaydedildiğini açıklar ve dolaylı olarak hizmetin nasıl kaydedildiğini türetir. Bu perspektiflerin her ikisi de daha karmaşıktır, bu yüzden burada sırasıyla bu iki perspektifin basitleştirmeleri var.Uygulama geliştirme olarak çok fazla işleme ve detaya dikkat etmemize gerek yok, sadece genel adımları anlamamız gerekiyor.

    Son olarak, sadece anlamanız gereken değil, aynı zamanda onları iyi ifade edebilmeniz için bazı şeyler var, böylece görüşmeyi yapan kişi görüşmede mutlaka sorulması gereken bir soru olan İşleyici mekanizması gibi anlayışınızı tanıyabilir. Bazı belirsiz noktalar var, belki sadece röportajda yaşıyor, gerçek işte hiç kullanmayacaksın ama ne olduğunu bilmelisin.

    Altın, gümüş ve gümüş röportajları için en yoğun sezon olmak üzere. Herkes favori bir iş bulmak için bu fırsatı değerlendirmeyi umuyor. Ama ne olursa olsun, görüşmenin boyutu ne olursa olsun, görüşmeci tarafından istismar edilmekten kaçınmak istiyorsanız, görüşme sorularını en üst düzeye çıkarmalı ve kapsamlı bir hazırlık yapmalısınız.Elbette buna ek olarak barış zamanında da sağlam bir temel atmalısınız. Yani görüşmeyi yapan kişi kendi bilgisine nasıl girerse girsin, bununla başa çıkabilirsiniz ~

    Röportaj: Tam bir röportaj için hazırlanmazsanız, bu zaman kaybı olur ve kendinize karşı sorumsuz olursunuz!

    Altın Üç Gümüş Dört röportaj sezonu, acele edin ve röportajınız için hazırlanın!

    Son olarak, buradaki editör, yukarıdaki teknik sistem şemalarıyla ilgili düzinelerce set koleksiyonunu paylaşıyor. Tencent, Toutiao, Ali, Meituan ve diğer şirketlerden 19 yıl içinde mülakat soruları , Teknik noktaları video ve PDF olarak düzenledi (aslında beklenenden çok daha fazla enerji harcadı), Bilgi bağlamı + birçok ayrıntı , Sınırlı alan nedeniyle, işte resim şeklinde bir parçası.

    ve ayrıca Gelişmiş mimari teknolojisi gelişmiş zihin haritası, Android geliştirme röportajı özel materyalleri , Herkesin ileri seviyeyi geliştirmeyi öğrenmesine yardımcı olmak için gelişmiş gelişmiş çerçeve materyalleri ve ayrıca internette öğrenmek için materyal aramak için herkesin zamanından tasarruf sağlar ve ayrıca birlikte öğrenmek için arkadaşlarla paylaşılabilir.

    [Android geliştirmeyle ilgili temel bilgilerle ilgili notlar]

    [Android zihin haritası (beceri ağacı)]

    [Android temel ileri teknoloji PDF belgesi, BAT görüşmesindeki gerçek soruların analizi]

    [Android Advanced Architecture Video Öğrenme Kaynakları]

    Android Tanıtım Videosu alıp öğrendikten sonra, daha da güçlü hale geliyor! BATJ fabrikasına girin ve benzeri (hazırlık)! Günümüzde İnternetin soğuk olduğu söyleniyor. Aslında, yanlış arabaya bindiğinizden ve daha az (beceri) giydiğinizden başka bir şey değil. Doğru arabaya binerseniz ve kendi teknik yeteneğiniz yeterince güçlüyse, şirketin değişim maliyeti yüksek olacaktır. Sadece son iş Curd'u ortadan kaldırmak için! Günümüzde piyasada genç programcılar akınına uğramaktadır. Bu eğitim seti 1-6 yaş arası Android geliştirme mühendislerine yöneliktir. Darboğaz dönemindedirler. Gelecek yıl maaş artışlarını aşmak isteyenler, ileri düzey Android orta ve kıdemli, mimarlar daha da önemlidir Sudaki bir balık gibi, çabuk alın!

    [Android gelişmiş öğrenme videosu], [Android mülakat hilelerinin tam seti PDF], [Android geliştirme temel bilgi notları] özel mesajla [Android] ücretsiz olarak elde edilebilir!

    30 yaşında bir mühendis istifa etmek zorunda kalabilir mi? Statüko nasıl kırılır?
    önceki
    Altın üç gümüş dört: 2019'daki gerçek röportajın özeti, bu Android mülakat sorularına ihtiyacınız var
    Sonraki
    Mobil: Salgın gökyüzünün yarısına vuruyor ve programcılar istikrar istiyorlarsa güç için savaşmalılar
    Android programcısı: "Bytedance röportajcısı olarak bir şey söylemem gerekiyor!"
    İş değiştirmeyi düşündün mü? İşte Android mimarlarının görüşmeler için bazı önerileri ve hazırlıkları var
    Altın üç gümüş dörtlü için hazır mısınız: işte Android 20'nin sorulması gereken mülakat soruları ve ayrıntılı analiz
    Öne çıkan! Android büyük OPPO mülakat soruları ve deneyim özeti
    Android LayoutManager üst düzey oyuncular, süslü formların farkına varın
    Android programcı sorunu: farklı geliştirme aşamalarında nasıl ilerlenir?
    Android geliştiricilerinin 2020'de tanrı olmasına giden yol! Bu temel becerileri öğrenin
    Mobil programcıların iş değiştirmeleri ve mülakat başarı oranını% 80 artırmaları için mülakat sorularına nasıl hazırlanılır?
    2020'de ne öğrenmeli? Android beceri haritası yükselişte
    Android mülakat deneyimi için gerekli beceri rezervinin detaylı açıklaması, teklifi aldı
    Teknik yön konusunda kafanız mı karıştı? Kıdemli mobil geliştiriciler, Android geliştirmenin gelecekteki yönü hakkında konuşuyor
    To Top