Android源碼學(xué)習(xí)--SystemServer進程

SystemServer進程在Android中的角色
SystemServer進程是Android系統(tǒng)的核心之一蚂且,大部分Android提供的服務(wù)都運行在這個進程里隘梨,如AMS舌菜,PMS,等六十多種服務(wù)场梆。我們都知道Android的應(yīng)用進程沒有權(quán)限直接訪問設(shè)備的底層資源,只能通過SystemServer中的服務(wù)代理訪問纯路,這樣做的目的是為了防止應(yīng)用進程對系統(tǒng)造成破壞或油。

SystemServer進程的創(chuàng)建過程

一、 創(chuàng)建SystemServer進程
ZygoteInit類的main()方法里調(diào)用startSystemServer()方法來啟動SystemServer驰唬。

//位于ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
        ...
        // 準備啟動參數(shù)
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;
        ...
        int pid;
        try {
            ...
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
        // 進入子進程system_server
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            // 完成system_server進程剩余的工作
            handleSystemServerProcess(parsedArgs);
        }
        return true;
    }

在startSystemServer()方法中顶岸,主要做了3件事:
1.為SystemServer準備啟動參數(shù)。
SystemServer進程的uid和gid都被指定為1000叫编。SystemServer進程的名字是system_server辖佣,其執(zhí)行類是com.android.server.SystemServer。
2.調(diào)用Zygote類的forkSystemServer()來fork出SystemServer子進程搓逾。
forkSystemServer()方法最終會調(diào)用native層的nativeForkSystemServer()函數(shù)卷谈,最終調(diào)用ForkAndSpecializeCommon函數(shù)來執(zhí)行實際的fork操作。
在native層調(diào)用完forkAndSpecializeCommon()函數(shù)后霞篡,如果啟動的是SystemServer世蔗,Zygote會檢查SystemServer是否啟動成功,如果失敗朗兵,Zygote進程會讓進程自己退出污淋,重啟zygote進程。

//位于com_android_internal_os_Zygote.cpp
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
        jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
        jlong effectiveCapabilities) {
  // fork子進程
  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                      debug_flags, rlimits,
                                      permittedCapabilities, effectiveCapabilities,
                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                      NULL, NULL);
  if (pid > 0) {
      // zygote進程檢測子進程是否創(chuàng)建
      gSystemServerPid = pid;
      int status;
      if (waitpid(pid, &status, WNOHANG) == pid) {
          // system_server進程死亡后余掖,重啟zygote進程
          RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
      }
  }
  return pid;
}

在ForkAndSpecializeCommon()函數(shù)中將調(diào)用fork()函數(shù)來創(chuàng)建子進程之前還調(diào)用了SetSigChldHandler函數(shù)設(shè)置處理SIGCHLD信號的函數(shù)SigChldHandler()寸爆。

static void SigChldHandler(int /*signal_number*/) {
  pid_t pid;
  ...
  while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
    ...
    if (pid == gSystemServerPid) {
      ALOGE("Exit zygote because system server (%d) has terminated", pid);
      kill(getpid(), SIGKILL); // 如果死亡的是SystemServer進程,zygote將退出
    }
  }
  ...
}

SigChldHandler函數(shù)接收到子進程死亡的信號后盐欺,除了調(diào)用waitpid()來防止子進程變“僵尸”外而昨,還會判斷死亡的子進程是否是SystemServer進程,如果是找田,Zygote進程會“自殺”歌憨,這樣將導(dǎo)致Init進程殺死所有用戶進程并重啟Zygote。整個手機相當于重啟了一扁墩衙,從而達到系統(tǒng)“軟重啟”的目的务嫡。

3.在fork出SystemServer進程后,在fork出的進程中調(diào)用handleSystemServerProcess()來初始化SystemServer進程漆改。

private static void handleSystemServerProcess(
            ZygoteConnection.Arguments parsedArgs)
            throws ZygoteInit.MethodAndArgsCaller {
        // 關(guān)閉父進程zygote復(fù)制而來的Socket
        closeServerSocket(); 
        // 接SystemServer進程的umask設(shè)為0077(S_IRWXG|S_IRWXO)心铃,
        // 這樣SystemServer創(chuàng)建的文件的屬性就是0077,只有SystemServer進程可以訪問挫剑。
        Os.umask(S_IRWXG | S_IRWXO);

        if (parsedArgs.niceName != null) {
            // 設(shè)置當前進程名為 "system_server"
            Process.setArgV0(parsedArgs.niceName);
        }

        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
        if (systemServerClasspath != null) {
            // 執(zhí)行dex優(yōu)化操作
            performSystemServerDexOpt(systemServerClasspath);
        }

        if (parsedArgs.invokeWith != null) {// invokeWith通常為null
            String[] args = parsedArgs.remainingArgs;
            if (systemServerClasspath != null) {
                String[] amendedArgs = new String[args.length + 2];
                amendedArgs[0] = "-cp";
                amendedArgs[1] = systemServerClasspath;
                System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);
            }
            // 啟動應(yīng)用進程
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(), null, args);
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
                //創(chuàng)建類加載器去扣,并賦予當前線程
                cl = createSystemServerClassLoader(systemServerClasspath,
                                                   parsedArgs.targetSdkVersion);
                Thread.currentThread().setContextClassLoader(cl);
            }
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
        }
    }

因為參數(shù)invokeWith通常為null,所以會調(diào)用RuntimeInit.zygoteInit()方法樊破。在zygoteInit()方法中愉棱,它最終會以拋出MethodAndArgsCaller異常的方式返回唆铐,實現(xiàn)真正調(diào)用SystemServer類的main()方法。

二奔滑、SystemServer的初始化
SystemServer是一個java類艾岂,其main()方法中調(diào)用了對象的run()方法。

    public static void main(String[] args) {
        //先初始化SystemServer對象朋其,再調(diào)用對象的run()方法
        new SystemServer().run();
    }

    private void run() {
        try {
            //當系統(tǒng)時間比1970年更早王浴,就設(shè)置當前系統(tǒng)時間為1970年 
            if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
                SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
            }

            if (!SystemProperties.get("persist.sys.language").isEmpty()) {
                final String languageTag = Locale.getDefault().toLanguageTag();
                SystemProperties.set("persist.sys.locale", languageTag);
                SystemProperties.set("persist.sys.language", "");
                SystemProperties.set("persist.sys.country", "");
                SystemProperties.set("persist.sys.localevar", "");
            }

            //變更虛擬機的庫文件,對于Android 6.0默認采用的是libart.so
            SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

            if (SamplingProfilerIntegration.isEnabled()) {
                SamplingProfilerIntegration.start();
                mProfilerSnapshotTimer = new Timer();
                //system_server每隔1小時采用一次梅猿,并保存結(jié)果到system_server文件
                mProfilerSnapshotTimer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            SamplingProfilerIntegration.writeSnapshot("system_server", null);
                        }
                    }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
            }

            VMRuntime.getRuntime().clearGrowthLimit();
            VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
            Build.ensureFingerprintProperty();
            Environment.setUserRequired(true);
            BaseBundle.setShouldDefuse(true);
            BinderInternal.disableBackgroundScheduling(true);
            BinderInternal.setMaxThreads(sMaxBinderThreads);
            android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
            // 主線程looper就在當前線程運行
            Looper.prepareMainLooper();
            //加載android_servers.so庫氓辣,該庫包含的源碼在frameworks/base/services/目錄下
            System.loadLibrary("android_servers");
            // 檢查上次關(guān)機過程是否失敗,該方法可能不會返回
            performPendingShutdown();
            // 初始化系統(tǒng)上下文
            createSystemContext();
            //創(chuàng)建系統(tǒng)服務(wù)管理
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            //將mSystemServiceManager添加到本地服務(wù)的成員sLocalServiceObjects
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }

        // 創(chuàng)建并運行所有的Java服務(wù)
        try {
            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
            startBootstrapServices();   //啟動引導(dǎo)服務(wù)
            startCoreServices();        //啟動核心服務(wù)
            startOtherServices();       //啟動其它服務(wù)
        } catch (Throwable ex) {
            throw ex;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
        // 進入處理消息的循環(huán)
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

main()方法的主要是有:
1.調(diào)用時間袱蚓,如果當前系統(tǒng)時間比1970年更早钞啸,就設(shè)置當前系統(tǒng)時間為1970年 。
2.設(shè)置屬性persist.sys.dalvik.vm.lib.2的值為當前虛擬機的運行庫的路徑癞松。
3.調(diào)整虛擬機堆的內(nèi)存爽撒。設(shè)定虛擬機利用率為0.8入蛆。
4.加載android_servers.so庫响蓉。
5.調(diào)用createSystemContext()來獲取Context。
6.創(chuàng)建SystemServiceManager的對象mSystemServiceManager哨毁,這個對象負責系統(tǒng)Service的啟動枫甲。
7.啟動服務(wù)。startBootstrapServices()扼褪,startBootstrapServices()想幻,startBootstrapServices()三大方法。
8.調(diào)用Loop.loop()话浇,進入處理消息的循環(huán)脏毯。

    private void createSystemContext() {
        //創(chuàng)建ActivityThread對象
        ActivityThread activityThread = ActivityThread.systemMain();
        //創(chuàng)建ContextImpl、LoadedApk對象
        mSystemContext = activityThread.getSystemContext();
        //設(shè)置主題
        mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
    }

在createSystemContext()方法里幔崖,通過ActivityThread的靜態(tài)方法systemMain()創(chuàng)建了一個activityThread食店。然后調(diào)用它的getSystemContext()方法來獲取系統(tǒng)的Context,最后設(shè)置主題赏寇。

接下來看看systemMain()方法吉嫩。

    public static ActivityThread systemMain() {
        //對于低內(nèi)存的設(shè)備,禁用硬件加速
        if (!ActivityManager.isHighEndGfx()) {
            ThreadedRenderer.disable(true);
        } else {
            ThreadedRenderer.enableForegroundTrimming();
        }
        // 創(chuàng)建ActivityThread
        ActivityThread thread = new ActivityThread();
        // 創(chuàng)建Application以及調(diào)用其onCreate()方法
        thread.attach(true);//代表是系統(tǒng)的應(yīng)用進程
        return thread;
    }

上面的代碼主要是new了一個ActivityThread對象嗅定。
同樣的我們知道自娩,ActivityThread是應(yīng)用程序的主線程類,該類同時也存在一個main()主方法渠退,zygote進程在啟動過程的最后會在拋出的MethodAndArgsCaller異常中忙迁,通過反射來執(zhí)行ActivityThread類的main()方法脐彩。那么這里為什么要用new來創(chuàng)建ActivityThread對象呢?
實際上SystemServer不僅是一個單純的后臺進程动漾,它也是一個運行著組件Service的進程丁屎,很多系統(tǒng)的對話框就是從SystemServer中顯示出來的,因此旱眯,SystemServer本身也需要一個和APK應(yīng)用類似的上下文環(huán)境晨川,創(chuàng)建ActivityThread是獲取這個環(huán)境的第一步,后面還需要創(chuàng)建SystemContext對象删豺。ActivityThread的attach(boolean)方法中共虑,傳入?yún)?shù)true時,表示是在SystemServer中調(diào)用呀页。如下代碼:

    private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {//進入應(yīng)用進程的處理流程
            ...
        } else { //進入系統(tǒng)進程妈拌。該情況只在SystemServer中處理,設(shè)置DDMS時看到的systemserver進程名為system_process
            android.ddm.DdmHandleAppName.setAppName("system_process",
                    UserHandle.myUserId());
            try {
                mInstrumentation = new Instrumentation();
                // 創(chuàng)建應(yīng)用上下文SystemContext
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                // 創(chuàng)建Application
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                // 調(diào)用Application的onCreate()方法
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }
        ...
    }

system為true時蓬蝶,創(chuàng)建了ContextImpl和Application對象尘分,最后還調(diào)用了Application的onCreate()方法,完全模擬創(chuàng)建一個應(yīng)用的過程丸氛。但是培愁,創(chuàng)建應(yīng)用上下文環(huán)境需要對應(yīng)的一個apk文件,這個的apk文件是哪個呢缓窜?上面的參數(shù)中g(shù)etSystemContext().mPackageInfo正是定续。
通過跟蹤getSystemContext()的代碼,最終可以找到在ContextImpl類的createSystemContext(ActivityThread)方法中創(chuàng)建了一個LoadedApk對象禾锤。

    LoadedApk(ActivityThread activityThread) {
        mActivityThread = activityThread;
        mApplicationInfo = new ApplicationInfo();
        mApplicationInfo.packageName = "android";
        mPackageName = "android";
        ...
    }

LoadedApk對象保存了一個apk文件的信息私股,它指明了將使用的包名為“android”,而framework-res.apk的包名正是“android”恩掷。因此倡鲸,getSystemContext()方法返回的對象所對象的apk文件就是framework-res.apk。
因此黄娘,ActivityThread的SystemMain()方法相當于創(chuàng)建了一個framework-res.apk的上下文環(huán)境峭状。

總結(jié):
SystemServer進程是一個應(yīng)用進程訪問底層資源的中間層代理,通過它來啟動和管理AMS寸宏,PMS等眾多服務(wù)宁炫。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市氮凝,隨后出現(xiàn)的幾起案子羔巢,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竿秆,死亡現(xiàn)場離奇詭異启摄,居然都是意外死亡,警方通過查閱死者的電腦和手機幽钢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門歉备,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人匪燕,你說我怎么就攤上這事蕾羊∶毖保” “怎么了利凑?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵割按,是天一觀的道長丙躏。 經(jīng)常有香客問我栅盲,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好涉波,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布辜纲。 她就那樣靜靜地躺著见剩,像睡著了一般扫俺。 火紅的嫁衣襯著肌膚如雪苍苞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天狼纬,我揣著相機與錄音羹呵,去河邊找鬼。 笑死疗琉,一個胖子當著我的面吹牛冈欢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盈简,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼凑耻,長吁一口氣:“原來是場噩夢啊……” “哼犯戏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拳话,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤先匪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后弃衍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呀非,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年镜盯,在試婚紗的時候發(fā)現(xiàn)自己被綠了岸裙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡速缆,死狀恐怖降允,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情艺糜,我是刑警寧澤剧董,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站破停,受9級特大地震影響翅楼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜真慢,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一毅臊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧黑界,春花似錦管嬉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至童社,卻和暖如春求厕,著一層夾襖步出監(jiān)牢的瞬間著隆,已是汗流浹背扰楼。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留美浦,地道東北人弦赖。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像浦辨,于是被迫代替她去往敵國和親蹬竖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容