国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android中Binder詳細(xì)學(xué)習(xí)心得

2019-10-22 18:17:27
字體:
供稿:網(wǎng)友

該文章是一個系列文章,是本人在Android開發(fā)的漫漫長途上的一點感想和記錄,我會盡量按照先易后難的順序進(jìn)行編寫該系列。該系列引用了《Android開發(fā)藝術(shù)探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相關(guān)知識,另外也借鑒了其他的優(yōu)質(zhì)博客,在此向各位大神表示感謝,膜拜!!!另外,本系列文章知識可能需要有一定Android開發(fā)基礎(chǔ)和項目經(jīng)驗的同學(xué)才能更好理解,也就是說該系列文章面向的是Android中高級開發(fā)工程師。

前言

上一次還不如不說去面試了呢,估計是掛了,數(shù)據(jù)結(jié)構(gòu)與算法方面雖然面試前突擊了一波,但是時間太短,當(dāng)時學(xué)的也不好。另外Android的一些知識也不是很了解。不過這也加大了我寫博客的動力。許多知識總覺得自己掌握的還挺好,不過一問到比較細(xì)節(jié)的方面就不太清楚了。所以寫這整個博客的目的也是加深自己的知識,培養(yǎng)自己的溝通能力,和大家一起學(xué)習(xí)吧。
好了,閑話少說,我們這一篇先解決上一篇中遺留的問題,之后有時間的話,我把這次的面試經(jīng)歷單寫一篇博客,和大家共勉。
本篇我們來看一下ServiceManager。上一篇中沒怎么說它,ServiceManager作為Android系統(tǒng)服務(wù)的大管家。我們還是有必要來看一下它的。

ServiceManager概述

ServiceManager是Android世界中所有重要系統(tǒng)服務(wù)的大管家。像前文提到的AMS(ActivityManagerService),還有許多以后可能分析到的PackageManagerService等等服務(wù)都需要像ServiceManager中注冊。那么為何需要一個ServiceManager呢,其重要作用何在呢?私認(rèn)為有以下幾點:

ServiceManager能集中管理系統(tǒng)內(nèi)的所有服務(wù),它能施加權(quán)限控制,并不是任何進(jìn)程都能注冊服務(wù)的。 ServiceManager支持通過字符串名稱來查找對應(yīng)的Service。這個功能很像DNS。由于各種原因的影響,Server進(jìn)程可能生死無常。 如果讓每個Client都去檢測,壓力實在太大了。 現(xiàn)在有了統(tǒng)一的管理機構(gòu),Client只需要查詢ServiceManager,就能把握動向,得到最新信息。

ServiceManager

[SystemServer.java]

public void setSystemProcess() {  try {    //注冊服務(wù),第二個參數(shù)為this,這里假設(shè)SystemServer通過“socket”與SM交互    ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);    ..........  } catch (PackageManager.NameNotFoundException e) {    ........  }}

 

我們SystemServer進(jìn)程中的AMS通過SM的代理與SM進(jìn)程交互(讀者也可以把這個過程想象為你所能理解的進(jìn)程間通信方式,例如管道、Socket等),并把自己注冊在SM中。這個情況下,我們使用ServiceManager的代理與SM進(jìn)程交互,既然有代理,那么也得有對應(yīng)的服務(wù)端。那么根據(jù)我們之前博客的思路分析的話,就是如下的流程:

ServiceManager是如何啟動的?

按照我們之前博客的思路,我們在SystemServer端有了個ServiceManager的代理,那么Android系統(tǒng)中應(yīng)該提供類似AMS這樣的繼承或間接繼承自java層Binder然后重寫onTransact方法以處理請求。但是并沒有,ServiceManager并沒有使用如AMS這樣復(fù)雜的Binder類結(jié)構(gòu)。而是直接與Binder驅(qū)動設(shè)備打交道。所以我們上一篇說了ServiceManager不一樣。我們來看具體看一下。

ServiceManager在init.rc配置文件中配置啟動,是一個以c/c++語言編寫的程序。init進(jìn)程、SM進(jìn)程等關(guān)系如下圖

Android,Binder,學(xué)習(xí)心得

我們來看它的main方法。

int main(int argc, char **argv){  struct binder_state *bs;  //①應(yīng)該是打開binder設(shè)備吧?  bs = binder_open(128*1024);  if (!bs) {    ALOGE("failed to open binder driver/n");    return -1;  }  //②成為manager  if (binder_become_context_manager(bs)) {    ALOGE("cannot become context manager (%s)/n", strerror(errno));    return -1;  }  ......  //③處理客戶端發(fā)過來的請求  binder_loop(bs, svcmgr_handler);  return 0;}

①打開Binder設(shè)備

[binder.c]

struct binder_state*binder_open(unsigned mapsize){  struct binder_state*bs;  bs=malloc(sizeof(*bs));  ......  //打開Binder設(shè)備  bs->fd=open("/dev/binder",O_RDWR);  ......  bs->mapsize=mapsize;  //進(jìn)行內(nèi)存映射  bs->mapped=mmap(NULL,mapsize,PROT_READ,MAP_PRIVATE,bs->  fd,0);}

 

這一步的目的是把內(nèi)核層的binder驅(qū)動映射到用戶空間。我們知道進(jìn)程之間是獨立的,進(jìn)程呢運行在用戶空間內(nèi),內(nèi)核層的Binder驅(qū)動可以看成是一個文件(實際上它也是,Linux上都是文件)。這一步呢,可以看成把一個文件映射到用戶空間,我們的進(jìn)程呢通過這個文件進(jìn)行交互。

Android,Binder,學(xué)習(xí)心得

②成為manager

[Binder.c]

int binder_become_context_manager(struct binder_state*bs){  //實現(xiàn)太簡單了!這個有個0,什么鬼?  return ioctl(bs->fd,BINDER_SET_CONTEXT_MGR,0);}

 

③處理客戶端發(fā)過來的請求

[Binder.c]

void binder_loop(struct binder_state *bs, binder_handler func){  int res;  struct binder_write_read bwr;  uint32_t readbuf[32];  bwr.write_size = 0;  bwr.write_consumed = 0;  bwr.write_buffer = 0;  readbuf[0] = BC_ENTER_LOOPER;  binder_write(bs, readbuf, sizeof(uint32_t));  for (;;) {//果然是循環(huán)    bwr.read_size = sizeof(readbuf);    bwr.read_consumed = 0;    bwr.read_buffer = (uintptr_t) readbuf;    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);    if (res < 0) {      ALOGE("binder_loop: ioctl failed (%s)/n", strerror(errno));      break;    }    //接收到請求交給binder_parse,最終會調(diào)用func來處理這些請求    res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);    if (res == 0) {      ALOGE("binder_loop: unexpected reply?!/n");      break;    }    if (res < 0) {      ALOGE("binder_loop: io error %d %s/n", res, strerror(errno));      break;    }  }}

上面?zhèn)魅雈unc的是svcmgr_ handler函數(shù)指針,所以會在svcmgr_handler中進(jìn)行集中處理客戶端的請求。

[service_manager.c]

ServiceManager的代理是如何獲得的?

我們來回到最初的調(diào)用

[SystemServer.java]

public void setSystemProcess() {  try {    //注冊服務(wù),第二個參數(shù)為this,這里假設(shè)SystemServer通過“socket”與SM交互    ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);    ..........  } catch (PackageManager.NameNotFoundException e) {    ........  }}

上面的請求最終是通過SM服務(wù)代理發(fā)送的,那這個代理是怎么來的呢?我們來看

[ServiceManager.java]

public static void addService(String name, IBinder service) {  try {    getIServiceManager().addService(name, service, false);  } catch (RemoteException e) {    Log.e(TAG, "error in addService", e);  }}private static IServiceManager getIServiceManager() {  if (sServiceManager != null) {    return sServiceManager;  }  // 是這里,沒錯了  sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());  return sServiceManager;}

我們先來看BinderInternal.getContextObject()

[BinderInternal.java]

//好吧,它還是個native函數(shù)public static final native IBinder getContextObject();

 

跟進(jìn)[android_ util_Binder.cpp]

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz){  sp<IBinder> b = ProcessState::self()->getContextObject(NULL);  return javaObjectForIBinder(env, b);}

跟進(jìn)[ProcessState.cpp]

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/){  return getStrongProxyForHandle(0);}/*這個函數(shù)是不是我們之前見過*/sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle){  sp<IBinder> result;  AutoMutex _l(mLock);  handle_entry* e = lookupHandleLocked(handle);  if (e != NULL) {    IBinder* b = e->binder;    if (b == NULL || !e->refs->attemptIncWeak(this)) {      if (handle == 0) {//這里我們的handle為0        Parcel data;      //在handle對應(yīng)的BpBinder第一次創(chuàng)建時      //會執(zhí)行一次虛擬的事務(wù)請求,以確保ServiceManager已經(jīng)注冊        status_t status = IPCThreadState::self()->transact(            0, IBinder::PING_TRANSACTION, data, NULL, 0);        if (status == DEAD_OBJECT)          return NULL;//如果ServiceManager沒有注冊,直接返回      }      //這里還是以handle參數(shù)創(chuàng)建了BpBinder      b = new BpBinder(handle);       e->binder = b;      if (b) e->refs = b->getWeakRefs();      result = b;    } else {            result.force_set(b);      e->refs->decWeak(this);    }  }  return result;}

我們再一步步返回

[android_ util_Binder.cpp]

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz){  sp<IBinder> b = ProcessState::self()->getContextObject(NULL);  //這里的b = new BpBinder(0);  return javaObjectForIBinder(env, b);}/*這個函數(shù)我們上一篇是不是也見過*/jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) {  if (val == NULL) return NULL;  //如果val是Binder對象,進(jìn)入下面分支,此時val是BpBinder  if (val->checkSubclass(&gBinderOffsets)) {    // One of our own!    jobject object = static_cast<JavaBBinder*>(val.get())->object();    LOGDEATH("objectForBinder %p: it's our own %p!/n", val.get(), object);    return object;  }  .........  //調(diào)用BpBinder的findObject函數(shù)  //在Native層的BpBinder中有一個ObjectManager,它用來管理在Native BpBinder上創(chuàng)建的Java BinderProxy對象  //findObject用于判斷gBinderProxyOffsets中,是否存儲了已經(jīng)被ObjectManager管理的Java BinderProxy對象  jobject object = (jobject)val->findObject(&gBinderProxyOffsets);  if (object != NULL) {    jobject res = jniGetReferent(env, object);    ............    //如果該Java BinderProxy已經(jīng)被管理,則刪除這個舊的BinderProxy    android_atomic_dec(&gNumProxyRefs);    val->detachObject(&gBinderProxyOffsets);    env->DeleteGlobalRef(object);  }  //創(chuàng)建一個新的BinderProxy對象  object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);  if (object != NULL) {    env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());    val->incStrong((void*)javaObjectForIBinder);    jobject refObject = env->NewGlobalRef(        env->GetObjectField(object, gBinderProxyOffsets.mSelf));    //新創(chuàng)建的BinderProxy對象注冊到BpBinder的ObjectManager中,同時注冊一個回收函數(shù)proxy_cleanup    //當(dāng)BinderProxy對象detach時,proxy_cleanup函數(shù)將被調(diào)用,以釋放一些資源    val->attachObject(&gBinderProxyOffsets, refObject,        jnienv_to_javavm(env), proxy_cleanup);    // Also remember the death recipients registered on this proxy    sp<DeathRecipientList> drl = new DeathRecipientList;    drl->incStrong((void*)javaObjectForIBinder);    //將死亡通知list和BinderProxy聯(lián)系起來    env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));    // Note that a new object reference has been created.    android_atomic_inc(&gNumProxyRefs);    //垃圾回收相關(guān);利用gNumRefsCreated記錄創(chuàng)建出的BinderProxy數(shù)量    //當(dāng)創(chuàng)建出的BinderProxy數(shù)量大于200時,該函數(shù)將利用BinderInternal的ForceGc函數(shù)進(jìn)行一個垃圾回收    incRefsCreated(env);    return object;  }}

接著返回到[ServiceManager.java]

private static IServiceManager getIServiceManager() {  if (sServiceManager != null) {    return sServiceManager;  }  // 是這里,沒錯了BinderInternal.getContextObject()是BinderProxy對象  sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());  return sServiceManager;}

跟進(jìn)[[ServiceManagerNative.java]]

static public IServiceManager asInterface(IBinder obj){  if (obj == null) {    return null;  }  我們知道這里的obj指向的是BinderProxy對象  IServiceManager in =    (IServiceManager)obj.queryLocalInterface(descriptor);  if (in != null) {    return in;  }  return new ServiceManagerProxy(obj);}

跟進(jìn)[Binder.java]

final class BinderProxy implements IBinder {  public IInterface queryLocalInterface(String descriptor) {    return null;  }}

跟進(jìn)[ServiceManagerNative.java]

class ServiceManagerProxy implements IServiceManager {  public ServiceManagerProxy(IBinder remote) {    //這里的mRemote指向了BinderProxy,與我們上一篇博客中講述的遙相呼應(yīng)    mRemote = remote;  }}

本節(jié)小結(jié)

我們詳盡講述了SM進(jìn)程的啟動以及它作為服務(wù)大管家的意義。結(jié)合上一篇的內(nèi)容我們總算是把Binder講述的比較清楚了。

Binder補充說明 AIDL

經(jīng)過上面的介紹,你應(yīng)該明白Java層Binder的架構(gòu)中,Bp端可以通過BinderProxy的transact()方法與Bn端發(fā)送請求,而Bn端通過集成Binder重寫onTransact()接收并處理來自Bp端的請求。這個結(jié)構(gòu)非常清晰簡單,在Android6.0,我們可以處處看到這樣的設(shè)計,比如我們的ActivityManagerNavtive這個類,涉及到Binder通信的基本上都是這種設(shè)計。不過如果我們想要自己來定義一些遠(yuǎn)程服務(wù)。那這樣的寫法就比較繁瑣,還好Android提供了AIDL,并且在Android8.0之后,我們可以看到與ActivityManagerNavtive相似的許多類已經(jīng)被標(biāo)注過時,因為Android系統(tǒng)也使用AIDL了。

AIDL的簡單例子

AIDL的語法與定義一個java接口非常類似。下面我就定以一個非常簡單的aidl

IMyAidlInterface.aidl

interface IMyAidlInterface {  int getTest();}

然后基本上就行了,我們重新build之后會得到一個
IMyAidlInterface.java文件,這個文件由aidl工具生成,我們現(xiàn)在使用的基本是AndroidStudio,即使你使用的是Eclipse也沒關(guān)系,這個文件會自動生成,不需要你操心。但是我們還是得來看看我們生成的這個文件

public interface IMyAidlInterface extends android.os.IInterface {  //抽象的Stub類,繼承自Binder并實現(xiàn)我們定義的IMyAidlInterface接口  //繼承自Binder,重寫onTransact方法,是不是感覺跟我們的XXXNative很像  public static abstract class Stub extends android.os.Binder implements com.mafeibiao.testapplication.IMyAidlInterface {    private static final java.lang.String DESCRIPTOR = "com.mafeibiao.testapplication.IMyAidlInterface";    /**     * Construct the stub at attach it to the interface.     */    public Stub() {      this.attachInterface(this, DESCRIPTOR);    }    /**     * Cast an IBinder object into an com.mafeibiao.testapplication.IMyAidlInterface interface,     * generating a proxy if needed.     */    public static com.mafeibiao.testapplication.IMyAidlInterface asInterface(android.os.IBinder obj) {      if ((obj == null)) {        return null;      }      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);      if (((iin != null) && (iin instanceof com.mafeibiao.testapplication.IMyAidlInterface))) {        return ((com.mafeibiao.testapplication.IMyAidlInterface) iin);      }      return new com.mafeibiao.testapplication.IMyAidlInterface.Stub.Proxy(obj);    }    @Override    public android.os.IBinder asBinder() {      return this;    }    @Override    public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {      switch (code) {        case INTERFACE_TRANSACTION: {          reply.writeString(DESCRIPTOR);          return true;        }        case TRANSACTION_getTest: {          data.enforceInterface(DESCRIPTOR);          int _result = this.getTest();          reply.writeNoException();          reply.writeInt(_result);          return true;        }      }      return super.onTransact(code, data, reply, flags);    }    /*這個Proxy不用說肯定是代理了,其內(nèi)部還有個mRemote對象*/    private static class Proxy implements com.mafeibiao.testapplication.IMyAidlInterface {      private android.os.IBinder mRemote;      Proxy(android.os.IBinder remote) {        mRemote = remote;      }      @Override      public android.os.IBinder asBinder() {        return mRemote;      }      public java.lang.String getInterfaceDescriptor() {        return DESCRIPTOR;      }      @Override      public int getTest() throws android.os.RemoteException {        android.os.Parcel _data = android.os.Parcel.obtain();        android.os.Parcel _reply = android.os.Parcel.obtain();        int _result;        try {          _data.writeInterfaceToken(DESCRIPTOR);          mRemote.transact(Stub.TRANSACTION_getTest, _data, _reply, 0);          _reply.readException();          _result = _reply.readInt();        } finally {          _reply.recycle();          _data.recycle();        }        return _result;      }    }    static final int TRANSACTION_getTest = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);  }  public int getTest() throws android.os.RemoteException;}

可見,AIDL的本質(zhì)與XXXNative之類的類并沒有什么本質(zhì)的不同,不過他的出現(xiàn)使得構(gòu)建一個Binder服務(wù)的工作大大簡化了。

AIDL的使用詳解

上面用一個非常簡單的小例子來解密AIDL的本質(zhì),但是在實際使用AIDL的時候還有許多地方需要注意。

AIDL支持的數(shù)據(jù)類型 基本數(shù)據(jù)類型(int,long,charmboolean,double等) String和CharSequence List:只支持ArrrayList,并且里面每個元素的類型必須是AIDL支持的 Map:只支持HashMap,t,并且里面每個元素的類型必須是AIDL支持的 Parcelable:所有實現(xiàn)Parcelable接口的對象 AIDL:所有的AIDL接口本身也可以在AIDL文件中使用

以上6種數(shù)據(jù)類型就是AIDL所支持的所有類型,其中自定義的Parcel對象和AIDL對象必須要顯示import進(jìn)來,不管他們是否和當(dāng)前的AIDL文件位于同一個包內(nèi)。

另外一個需要注意的地方是如果我們在AIDL中使用了自定義的Parcelable接口的對象,那么我們必須新建一個和它同名的AIDL文件,并在其中聲明它為Parcelable類型。

如下例

[IBookManager.aidl]

package com.ryg.chapter_2.aidl;/*這里顯示import*/import com.ryg.chapter_2.aidl.Book;interface IBookManager {   //這里我們使用了自定義的Parcelable對象   List<Book> getBookList();   void addBook(in Book book);}

這里我們新建一個與Book同名的AIDL文件并聲明

[Book.aidl]

package com.ryg.chapter_2.aidl;parcelable Book;

定向tag

定向tag:這是一個極易被忽略的點——這里的“被忽略”指的不是大家都不知道,而是很少人會正確的使用它。
AIDL中的定向 tag 表示了在跨進(jìn)程通信中數(shù)據(jù)的流向,其中 in 表示數(shù)據(jù)只能由客戶端流向服務(wù)端, out 表示數(shù)據(jù)只能由服務(wù)端流向客戶端,而 inout 則表示數(shù)據(jù)可在服務(wù)端與客戶端之間雙向流通。其中,數(shù)據(jù)流向是針對在客戶端中的那個傳入方法的對象而言的。in 為定向 tag 的話表現(xiàn)為服務(wù)端將會接收到一個那個對象的完整數(shù)據(jù),但是客戶端的那個對象不會因為服務(wù)端對傳參的修改而發(fā)生變動;out 的話表現(xiàn)為服務(wù)端將會接收到那個對象的的空對象,但是在服務(wù)端對接收到的空對象有任何修改之后客戶端將會同步變動;inout 為定向 tag 的情況下,服務(wù)端將會接收到客戶端傳來對象的完整信息,并且客戶端將會同步服務(wù)端對該對象的任何變動。

另外,Java 中的基本類型和 String ,CharSequence 的定向 tag 默認(rèn)且只能是 in 。還有,請注意,請不要濫用定向 tag ,而是要根據(jù)需要選取合適的——要是不管三七二十一,全都一上來就用 inout ,等工程大了系統(tǒng)的開銷就會大很多——因為排列整理參數(shù)的開銷是很昂貴的。

所有的非基本參數(shù)都需要一個定向tag來指出數(shù)據(jù)的流向,不管是 in , out , 還是 inout 。基本參數(shù)的定向tag默認(rèn)是并且只能是 in 。

本篇總結(jié)

我們本篇詳細(xì)分析了ServiceManager,ServiceManager并沒有使用復(fù)雜的類結(jié)構(gòu),他直接與Binder驅(qū)動設(shè)備交互達(dá)到IPC通信的目的。感謝你對VEVB武林網(wǎng)的支持。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 平武县| 弥渡县| 房山区| 望江县| 巴南区| 斗六市| 盐池县| 广宁县| 秭归县| 科技| 桦南县| 海林市| 儋州市| 太仓市| 红原县| 马山县| 格尔木市| 汾西县| 噶尔县| 册亨县| 彩票| 房山区| 自治县| 荆州市| 常熟市| 凌源市| 莱芜市| 五家渠市| 祁连县| 嘉荫县| 沂南县| 易门县| 洞头县| 宜川县| 五大连池市| 介休市| 滨海县| 晋城| 安新县| 永德县| 绵竹市|