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.
Ö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.
ç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.
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.
Ç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:
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.
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!