圖解 | 一圖摸清Android系統(tǒng)服務

一圖摸清Android系統(tǒng)服務的獲取和注冊流程~

大綱:

  • 獲取系統(tǒng)服務
  • 注冊系統(tǒng)服務
    • 獨立進程的服務
    • 非獨立進程的服務
  • 總結
  • 參考資料

本文約1.9k字,閱讀大約8分鐘俘种。

Android源碼基于8.0艺沼。

先預覽下整體流程~

image

開始分析奶栖!

獲取系統(tǒng)服務

在日常開發(fā)中盐捷,可以通過Context.getSystemService()在自己的應用程序里獲取到系統(tǒng)服務:

//ContextImpl.java
public Object getSystemService(String name) {
    //SystemServiceRegistry是系統(tǒng)服務的注冊表,用來集中管理系統(tǒng)服務
    return SystemServiceRegistry.getSystemService(this, name);
}

//SystemServiceRegistry.java
public static Object getSystemService(ContextImpl ctx, String name) {
    //根據(jù)服務名字從HashMap中取出ServiceFetcher
    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    //傳入上下文辜腺,借助ServiceFetcher來獲取系統(tǒng)服務
    return fetcher != null ? fetcher.getService(ctx) : null;
}

ServiceFetcher是一個抽象接口休建,抽象類CachedServiceFetcher實現(xiàn)了他乍恐,

//CachedServiceFetcher.java
public final T getService(ContextImpl ctx) {
    //每個上下文ctx都有一份系統(tǒng)服務緩存
    final Object[] cache = ctx.mServiceCache;
    synchronized (cache) {
        //從緩存里獲取系統(tǒng)服務
        Object service = cache[mCacheIndex];
        if (service == null) {
            //緩存里沒有,則創(chuàng)建
            service = createService(ctx);
            //存入緩存
            cache[mCacheIndex] = service;
        }
        return (T)service;
    }
}

//createService是個抽象方法
public abstract T createService(ContextImpl ctx);

在SystemServiceRegistry里有個靜態(tài)代碼塊static{}會“注冊服務”测砂,從中實現(xiàn)抽象方法createService()的邏輯茵烈,以電源服務PowerManager為例,

//SystemServiceRegistry.java
registerService(
    Context.POWER_SERVICE, PowerManager.class,
    new CachedServiceFetcher<PowerManager>() {
        @Override
        public PowerManager createService(ContextImpl ctx){
            //ServiceManager根據(jù)服務名字獲取系統(tǒng)服務的Binder對象
            IBinder b = ServiceManager.getServiceOrThrow(Context.POWER_SERVICE);
            //將服務端的Binder轉成客戶端所需的AIDL接口類型的對象IPowerManager
            IPowerManager service = IPowerManager.Stub.asInterface(b);
            //再用PowerManager類包一層砌些,方便外部使用
            return new PowerManager(ctx.getOuterContext(),
                                    service, 
                                    ctx.mMainThread.getHandler());
        }});

AIDL可以輔助生成用于binder通信的類呜投,IPowerManager就是定義在IPowerManager.aidl里的,binder內(nèi)部細節(jié)本文不做討論存璃。

ServiceManager的getServiceOrThrow()函數(shù)會調(diào)用getService()仑荐,

//ServiceManager.java
public static IBinder getService(String name) {
    //取緩存
    IBinder service = sCache.get(name);
    if (service != null) {
        return service;
    } else {
        //取不到就繼續(xù),這里創(chuàng)建完并沒有存入sCache纵东,即sCache只是預置了一些啟動階段存入的服務
        //getService()獲取系統(tǒng)服務的Binder對象粘招,用allowBlocking包了一下,允許阻塞
        return Binder.allowBlocking(getIServiceManager().getService(name));
    }
    return null;
}

private static IServiceManager getIServiceManager() {
    if (sServiceManager != null) {
        return sServiceManager;
    }
    //binder跨進程通信:
    //BinderInternal.getContextObject()得到系統(tǒng)級別上下文的IBinder偎球,可用來查找服務
    //asInterface將IBinder轉成IServiceManager(本質(zhì)是BpServiceManager)
    sServiceManager = ServiceManagerNative
        .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
    return sServiceManager;
}

可見洒扎,我們的應用程序進程會通過binder跨進程通信,拿到ServiceManager進程的IServiceManager對象(本質(zhì)是BpServiceManager)衰絮,然后就可以通過IServiceManager對象的getService來獲取系統(tǒng)服務了袍冷。

public interface IServiceManager extends IInterface{
    //從IServiceManager獲取系統(tǒng)服務,如果服務不存在岂傲,會阻塞最多5秒难裆,直到服務被發(fā)布注冊
    public IBinder getService(String name);
}

看下IServiceManager的具體實現(xiàn),在IServiceManager.cpp文件里镊掖,有個BpServiceManager類,

//class BpServiceManager : public BpInterface<IServiceManager>
//這里的BpInterface是binder內(nèi)部的細節(jié)了褂痰,不是很理解亩进,后面抽時間看看

virtual sp<IBinder> getService(const String16& name) const
{
    unsigned n;
    //如果獲取不到,則休眠1秒再取缩歪,最多阻塞5秒
    for (n = 0; n < 5; n++){
        if (n > 0) {
            //休眠1秒归薛,待會再取
            sleep(1);
        }
        sp<IBinder> svc = checkService(name);
        //獲取到系統(tǒng)服務,則返回
        if (svc != NULL) return svc;
    }
    return NULL;
}

//返回系統(tǒng)服務的binder匪蝙,暫不深究
virtual sp<IBinder> checkService( const String16& name) const
{
    //binder使用Parcelable來序列化數(shù)據(jù)
    Parcel data, reply;
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    data.writeString16(name);
    //remote()得到BpBinder主籍,transact發(fā)送請求
    remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
    return reply.readStrongBinder();//Binder
}

再梳理一下系統(tǒng)服務的獲取過程:

  1. 應用程序進程調(diào)用getSystemService
  2. 通過binder跨進程通信,拿到ServiceManager進程的BpServiceManager對象
  3. 通過BpServiceManager獲取到系統(tǒng)服務

注冊系統(tǒng)服務

系統(tǒng)服務可以分成兩大類:

一是有獨立進程的ServiceManager逛球、SurfaceFlinger等千元,他們在init進程啟動時就會被fork創(chuàng)建

二是非獨立進程的AMS颤绕、PMS幸海、WMS等祟身,他們在init進程fork出Zygote進程,Zygote進程fork出的SystemServer進程創(chuàng)建物独。

獨立進程的服務

獨立進程的系統(tǒng)服務在init進程解析init.rc時啟動袜硫,比如SurfaceFlinger,看下他的啟動配置文件surfaceflinger.rc挡篓,

注:frameworks/native/services下列出了一系列服務婉陷,不過ServiceManager服務放在了frameworks/native/cmds/servicemanager目錄下。

//frameworks/native/services/surfaceflinger/surfaceflinger.rc
service surfaceflinger /system/bin/surfaceflinger
    class core animation
    user system
    group graphics drmrpc readproc
    onrestart restart zygote

service以服務的形式來啟動進程官研,surfaceflinger是進程名字秽澳,/system/bin/surfaceflinger是可執(zhí)行程序的路徑,該程序的入口函數(shù)main在main_surfaceflinger.cpp阀参,

int main(int, char**) {
    //ProcessState會啟動binder機制(打開binder驅動肝集、映射內(nèi)存、分配緩沖區(qū))
    sp<ProcessState> ps(ProcessState::self());
    //啟動binder線程
    ps->startThreadPool();

    //初始化surfaceflinger
    sp<SurfaceFlinger> flinger = new SurfaceFlinger();
    flinger->init();

    //發(fā)布注冊surfaceflinger
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);

    //在當前線程運行surfaceflinger
    flinger->run();
    return 0;
}

看下defaultServiceManager()的實現(xiàn)蛛壳,在IServiceManager.cpp杏瞻,

sp<IServiceManager> defaultServiceManager()
{
    //有值,直接返回
    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;

    {
        AutoMutex _l(gDefaultServiceManagerLock);
        while (gDefaultServiceManager == NULL) {
            //查找ServiceManager衙荐,強轉為IServiceManager(本質(zhì)是BpServiceManager)
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));
            //如果IServiceManager還是null捞挥,則休眠1秒再取,直至取到才結束循環(huán)
            if (gDefaultServiceManager == NULL)
                sleep(1);
        }
    }

    return gDefaultServiceManager;
}

因為SurfaceFlinger進程和ServiceManager進程都是init進程啟動的忧吟,有可能SurfaceFlinger在獲取IServiceManager時砌函,ServiceManager還沒來得及注冊,所以這里會邊取邊休眠溜族,取到才結束循環(huán)讹俊。

得到IServiceManager后,執(zhí)行sm->addService煌抒,在IServiceManager.cpp文件里有個BpServiceManager類仍劈,

//class BpServiceManager : public BpInterface<IServiceManager>
//這里的BpInterface是binder內(nèi)部的細節(jié)了,不是很理解寡壮,后面抽時間看看

//注冊系統(tǒng)服務(的binder)贩疙,暫不深究
virtual status_t addService(const String16& name, const sp<IBinder>& service,
                            bool allowIsolated)
{
    //binder使用Parcelable來序列化數(shù)據(jù)
    Parcel data, reply;
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    data.writeString16(name);
    data.writeStrongBinder(service);//Binder
    data.writeInt32(allowIsolated ? 1 : 0);
    //remote()得到BpBinder,transact發(fā)送請求
    status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
    return err == NO_ERROR ? reply.readExceptionCode() : err;
}

梳理一下:

  1. init進程解析init.rc配置fork出新的進程况既,啟動多項獨立進程的系統(tǒng)服務这溅,如SurfaceFlinger
  2. 執(zhí)行SurfaceFlinger的可執(zhí)行程序,找到ServiceManager進程的BpServiceManager對象
  3. 通過BpServiceManager執(zhí)行addService注冊服務

非獨立進程的服務

非獨立進程的系統(tǒng)服務由SystemServer進程啟動棒仍,從圖解Android系統(tǒng)的啟動一文可知悲靴,SystemServer借助SystemServiceManager類(SSM)來啟動系統(tǒng)服務,比如AMS降狠,

//SystemServer.java
private void startBootstrapServices() {
    //AMS由SSM創(chuàng)建啟動
    mActivityManagerService = mSystemServiceManager
        //創(chuàng)建并啟動AMS服務
        .startService(ActivityManagerService.Lifecycle.class)
        //通過binder獲取AMS服務
        .getService();

    //注冊AMS
    mActivityManagerService.setSystemProcess();
}

看到ActivityManagerService对竣,

//ActivityManagerService.java
public void setSystemProcess() {
    //注冊AMS
    ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
}

調(diào)用了ServiceManager.addService()進行注冊庇楞,

//ServiceManager.java
public static void addService(String name, IBinder service, boolean allowIsolated) {
    //跟前邊一樣,通過binder跨進程通信否纬,拿到ServiceManager進程的BpServiceManager對象
    //調(diào)用BpServiceManager的addService
    getIServiceManager().addService(name, service, allowIsolated);
}

可見吕晌,無論是SystemServer進程啟動的服務,還是init進程啟動的運行在獨立進程里的服務临燃,最終都是走ServiceManager進程的BpServiceManager.addService進行集中注冊睛驳。

總結

綜上,不管是由init進程啟動的獨立進程的系統(tǒng)服務如SurfaceFlinger膜廊,還是由SystemServer進程啟動的非獨立進程的系統(tǒng)服務如AMS乏沸,都是在ServiceManager進程中完成注冊和獲取的,在跨進程通信上使用了Android的binder機制爪瓜。

不過哈迪在工作中沒怎么用過binder蹬跃,所以他的內(nèi)部細節(jié)就暫時不深入了,后面抽時間再看铆铆。

再回顧一下~

image

系列文章:

參考資料


更多性感文章蝶缀,關注原創(chuàng)技術公眾號:哈利迪ei

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市薄货,隨后出現(xiàn)的幾起案子翁都,更是在濱河造成了極大的恐慌,老刑警劉巖谅猾,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柄慰,死亡現(xiàn)場離奇詭異,居然都是意外死亡税娜,警方通過查閱死者的電腦和手機坐搔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來敬矩,“玉大人薯蝎,你說我怎么就攤上這事“” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵袒哥,是天一觀的道長缩筛。 經(jīng)常有香客問我,道長堡称,這世上最難降的妖魔是什么瞎抛? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮却紧,結果婚禮上桐臊,老公的妹妹穿的比我還像新娘胎撤。我一直安慰自己,他們只是感情好断凶,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布伤提。 她就那樣靜靜地躺著,像睡著了一般认烁。 火紅的嫁衣襯著肌膚如雪肿男。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天却嗡,我揣著相機與錄音舶沛,去河邊找鬼。 笑死窗价,一個胖子當著我的面吹牛如庭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播撼港,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼坪它,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了餐胀?” 一聲冷哼從身側響起哟楷,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎否灾,沒想到半個月后卖擅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡墨技,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年惩阶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扣汪。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡断楷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出崭别,到底是詐尸還是另有隱情冬筒,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布茅主,位于F島的核電站舞痰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏诀姚。R本人自食惡果不足惜响牛,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧呀打,春花似錦矢赁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瘫寝,卻和暖如春蜒蕾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背焕阿。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工咪啡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人暮屡。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓撤摸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親褒纲。 傳聞我的和親對象是個殘疾皇子准夷,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348