Android源碼-Android系統啓動源碼分析

Android系統啓動源碼分析

*本篇文章已授權微信公衆號 guolin_blog (郭霖)獨家發佈

解讀Android的源碼可以讓我們更好的學習系統的優秀源碼,以及google工程師對於一個程序的是如何實現的,從源碼的分析也可以強化我們的編程思想.

引導

Android系統啓動流程源碼分析,基於Android5.1(個人比較喜歡這個版本的源碼,因爲改動比較大)

Android系統是基於linux內核的,所以在Android啓動的時候會先去加載linux內核,內核啓動的時候會去加載各種驅動以及數據結構等,然而,Android的第一個進程是初始化進程(init).

進程是由C代碼實現的,即init.c;所以我們先從init.c開始閱讀.由於init.c文件在Android源碼中是有很多個的,我們需要閱讀的是內核core的init文件,注意包名不要錯誤.

1.init.c的main函數:

這裏寫圖片描述
在C語言中,main方法是函數的入口,我們先從main函數開始;由於是分析代碼,所以我會把不需要的部分的代碼刪除,僅留下部分作爲例子

int main(int argc, char **argv)
{

    //step1 創建必要的文件夾 , 權限分配 7代表可讀可寫可執行  5代表可讀可執行不可寫  掛載磁盤
    mkdir("/dev", 0755);
    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");

        //step2 初始化代碼 包括日誌初始化 配置文件初始化 以及硬件層初始化
    klog_init();
    property_init();


        //setp3 需要注意的一個初始化是init.rc配置文件的初始化   此處插入init.rc解讀 詳細請跳轉  2.init.rc解讀
    init_parse_config_file("/init.rc");

        //setp4 後續是很多的隊列等待,等待初始化的完成,以及一些初始化失敗的操作代碼
    action_for_each_trigger("early-init", action_add_queue_tail);
    queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");


    return 0;
}

2.init.rc解讀 init.rc是linux系統下的一個啓動配置文件,在android中的主要工作如下

這裏寫圖片描述
setp1 文件系統的初始化和寫入,變更權限等

    mkdir /sys/fs/cgroup/memory 0750 root system
    mount cgroup none /sys/fs/cgroup/memory memory
    write /sys/fs/cgroup/memory/memory.move_charge_at_immigrate 1
    chown system system /sys/kernel/ipv4/tcp_rmem_max

setp2 服務的啓動,如下實例是一個大家比較熟悉的服務,網絡模塊服務啓動,此項初始化了socket的網絡通信

 Daemon processes to be run by init.
    service netd /system/bin/netd
    class main
    socket netd stream 0660 root system
    socket dnsproxyd stream 0660 root inet
    socket mdns stream 0660 root system
    socket fwmarkd stream 0660 root inet

setp3 重點服務講解,孵化器服務

 service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    onrestart restart zygote  //重點注意代碼
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm

服務器服務zygote,進程的出現都是有孵化器完成的,也就是說孵化器進程是母進程

但是比較奇怪的是並沒有在這個文件中出現直接啓動的服務器進程的服務呢?這個就比較麻煩啦 哈哈

好好想一下,文件中既然有提到,onrestart restart zygote,從java的思想出發的話,這個文件裏面一定是導入了服務器進程的包的,那麼我們看一下文件的關聯文件有哪些吧

 import /init.environ.rc
 import /init.usb.rc
 import /init.${ro.hardware}.rc
 import /init.${ro.zygote}.rc
 import /init.trace.rc

在文件的頂頭會發現有一個import /init.${ro.zygote}.rc的文件關聯,那麼去找一下這個文件吧,搜索這個文件會發現有好幾個,因爲操作系統的位數分爲了四個,但是其中內容都是一樣的,細微差距就是app_process的路徑文件夾名字會不一樣,不過都指向同一個路徑
這裏寫圖片描述
如下:

    //service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd

**setp4 在這個服務中,可以看到路徑是在app_process,看一下這個路徑中的文件,只有一個文件**App_main.cpp,這個C++文件就是孵化器進程了
這次是一個C++文件,C++和C語言一樣,入口函數都是main函數

3.孵化器App_main.cpp解讀:

這裏寫圖片描述
int main(int argc, char* const argv[])
{
//step1 忽略一些參數初始化方法

        //step2 AppRuntime爲Android的運行時對象,下面代碼是初始化了一個Android運行時環境
        AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));


        //step3 初始化一些重要參數,後續對參數判斷,參數初始化的時候會跳過第一個參數及父級路徑
        bool zygote = false;
        bool startSystemServer = false;
        bool application = false;
        String8 niceName;
        String8 className;

        //step4 現在開始啓動android的代碼,com.android.internal.os.ZygoteInit
        //看到這樣的是不是很熟悉啦,此類爲android的孵化器進程
        if (zygote) {
            runtime.start("com.android.internal.os.ZygoteInit", args);
        } else if (className) {
            runtime.start("com.android.internal.os.RuntimeInit", args);
        } else {
            fprintf(stderr, "Error: no class name or --zygote supplied.\n");
            app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
        return 10;
        }
    }

4.java孵化器類ZygoteInit.java解讀:

這裏寫圖片描述
step1 package com.android.internal.os;此類所在包

step2 對於java代碼而言就沒有什麼main函數了,我們要從構造方法開始看

/**
 * Class not instantiable.
 * 比較尷尬 不給調用
 */
private ZygoteInit() {
}

孵化器的類是一個私有的構造方法,是不允許我們直接實例的類,那麼按照常規的java代碼套路的話,一般是有一個靜態方法去創建他或者直接獲得一個實例的,
但是找了一下,居然沒有,哈哈!但很是意外的發現有一個main方法:

step3 main方法解讀

    public static void main(String argv[]) {

            //在2.3的android\源碼中是有一個運行時設置堆內存大小的,不過貌似被取消了

        try {
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();

           /*
           *值得提醒一下的是,google的工程師在寫代碼的時候會有很多的邏輯判斷
           *系統級別的程序代碼就是嚴謹
           */

           //孵化器的socket註冊
            registerZygoteSocket(socketName);

           /**
           *static void preload()
           *從命名可以看出這個方法是用作預加載的
           *預加載中內容比較多,也比較重要,下面會詳細介紹
           *跳轉 5.預加載preload();
           */
            preload();

            // Do an initial gc to clean up after startup
            //需要強調的一點是,java的回收機制雖然不是你乎他他就會來的
            //但是可以看到系統在做大量的IO操作的前後都會主動地去呼叫gc,可以借鑑爲一個習慣
            gc();


                    //重點啓動服務
            if (startSystemServer) {
                //跳轉 6.啓動Android系統服務介紹
                startSystemServer(abiList, socketName);
            }

        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {

        }
    }

5.預加載preload();

step1 方法內容

    static void preload() {
            Log.d(TAG, "begin preload");
            preloadClasses();
            preloadResources();
            preloadOpenGL();
            preloadSharedLibraries();
            // Ask the WebViewFactory to do any initialization that must run in the zygote process,
            // for memory sharing purposes.
            WebViewFactory.prepareWebViewInZygote();
            Log.d(TAG, "end preload");
        }

step2 preloadClasses()預加載類說明
這裏寫圖片描述
/**
*從配置文件PRELOADED_CLASSES = “/system/etc/preloaded-classes”讀取需要加載的類
*標準的JAVA的IO讀取操作
*每次讀取一行,讀取到後進行反射加載類
*刪掉大部分代碼.留下核心部分
*在android5.1中這個配置文件是有3010行
*/
這裏寫圖片描述
private static void preloadClasses() {

        is = new FileInputStream(PRELOADED_CLASSES);

        try {
            BufferedReader br
                = new BufferedReader(new InputStreamReader(is), 256);
            while ((line = br.readLine()) != null) {

                try {

                    Class.forName(line);

                } catch (ClassNotFoundException e) {

                } catch (UnsatisfiedLinkError e) {

                } catch (Throwable t) {

                }
            }

        } catch (IOException e) {

        } finally {
                //加載
           runtime.preloadDexCaches();
        }
    }

step3 preloadResources()加載資源,這個方法比較簡單沒什麼好說的

 private static void preloadResources() {
    final VMRuntime runtime = VMRuntime.getRuntime();

    Debug.startAllocCounting();
    try {
        System.gc();
        runtime.runFinalizationSync();
        mResources = Resources.getSystem();
        mResources.startPreloading();
       //load資源數據
        mResources.finishPreloading();
    } catch (RuntimeException e) {
        Log.w(TAG, "Failure preloading resources", e);
    } finally {
        Debug.stopAllocCounting();
    }
}

step4 preloadOpenGL()方法,加載opengl相關,opengl是一個開源組織維護的,加載的話確實就是和java依賴庫一樣簡單,沒什麼好解釋的

private static void preloadOpenGL() {
    if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) {
        EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
    }
}

step5 preloadSharedLibraries()加載依賴庫

 private static void preloadSharedLibraries() {
    Log.i(TAG, "Preloading shared libraries...");
    System.loadLibrary("android");
    System.loadLibrary("compiler_rt");
    System.loadLibrary("jnigraphics");
}

step6 WebViewFactory.prepareWebViewInZygote()瀏覽器作爲APP中一個比較特殊的應用.這裏就不詳解

 public static void prepareWebViewInZygote() {
    try {
            //加載瀏覽器內核
        System.loadLibrary("webviewchromium_loader");
        long addressSpaceToReserve =
                SystemProperties.getLong(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
                CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
        sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);
    } catch (Throwable t) {

    }
}

6.啓動Android系統服務介紹

step1 方法聲明

 private static boolean startSystemServer(String abiList, String socketName)
                    throws MethodAndArgsCaller, RuntimeException {
               //初始化參數的代碼(太多,不貼代碼了)
               /**
               * "com.android.server.SystemServer"
               *參數初始化的時候有一個比較搶眼的參數SystemServer
               */
                try {
                /**
                *args參數中封裝了"com.android.server.SystemServer"這個參數
                */
                    parsedArgs = new ZygoteConnection.Arguments(args);
                    /* Request to fork the system server process */

                    //這個方法中可以看到fork\出了一個系統進程
                    pid = Zygote.forkSystemServer(
                            parsedArgs.uid, parsedArgs.gid,
                            parsedArgs.gids,
                            parsedArgs.debugFlags,
                            null,
                            parsedArgs.permittedCapabilities,
                            parsedArgs.effectiveCapabilities);
                } catch (IllegalArgumentException ex) {
                    throw new RuntimeException(ex);
                }

                /* For child process */
                if (pid == 0) {
                    if (hasSecondZygote(abiList)) {
                        waitForSecondaryZygote(socketName);
                    }
                    //在系統進程完成之後處理剩下的一些子進程
                    handleSystemServerProcess(parsedArgs);
        }

        return true;
    }

7.SystemServer分析

step1 類聲明和構造說明
這裏寫圖片描述

public final class SystemServer//此類被聲明瞭爲一個最終類,不可改變,公開訪問

public SystemServer() {
    // Check for factory test mode.//只是做了模式檢測
    mFactoryTestMode = FactoryTest.getMode();
}

在Android2.3的源碼中,SystemServer類還包含了兩個內部類,但是在5.1的版本中已經把兩個內部類合併了(SensorService.cpp中),有興趣的可以追溯一下2.3的源碼

step2 main方法分析

public static void main(String[] args) {
    new SystemServer().run();
    //在main方法中只是調用了構造方法和run方法
}

step3 run方法分析

private void run() {
    //時間初始化
    if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
        Slog.w(TAG, "System clock is before 1970; setting to 1970.");
        SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
    }
    //looper的初始化,handler處理的時候不需要自己初始化一個looper就是因爲系統已經爲主線程準備了looper
    Looper.prepareMainLooper();

    // Initialize native services
    /**
    *加載了一個so庫文件,然後調用了init的jni方法
    *libandroid_servers.so
    *可以在目錄中找到這個文件的so庫閱讀init方法
    */
    System.loadLibrary("android_servers");
    nativeInit();

    // Start services.重點放到  第九點說明
    try {
        startBootstrapServices();
        startCoreServices();
        startOtherServices();
    } catch (Throwable ex) {
        Slog.e("System", "******************************************");
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    }

    // Loop forever.
    //到此處說明已經開始輪訓去做消息處理了 完成
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

8.android_servers庫源碼

step1 源代碼查找
路徑:F:\Android5\android5.1\frameworks\base\services\core\jni
這裏寫圖片描述

step2 nativeInit方法

static void android_server_SystemServer_nativeInit(JNIEnv* env, jobject clazz) {
    char propBuf[PROPERTY_VALUE_MAX];
    property_get("system_init.startsensorservice", propBuf, "1");
    if (strcmp(propBuf, "1") == 0) {
        // Start the sensor service
        SensorService::instantiate();
    }
}

該方法主要調用了SensorService::instantiate(),實例了SensorService對象

step3 SensorService閱讀
這裏寫圖片描述
路徑如下:F:\Android5\android5.1\frameworks\native\services\sensorservice
因爲SensorService啓動後執行的就是onFirstRef方法,所以我們直接看這個方法

void SensorService::onFirstRef()
{
//硬件的初始化
SensorDevice& dev(SensorDevice::getInstance());

        //looper的初始化
        mLooper = new Looper(false);
        //運行SensorService
        run("SensorService", PRIORITY_URGENT_DISPLAY);

}

9 後續啓動

step1 硬件完成後

startBootstrapServices();
startCoreServices();
startOtherServices();

step2 startBootstrapServices()

 private void startBootstrapServices() {

    Installer installer = mSystemServiceManager.startService(Installer.class);

    // Activity manager runs the show.Activity相關啓動
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);

    //電源相關啓動
    mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
    mActivityManagerService.initPowerManagement();

   //顯示相關啓動
    mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);

  //應用管理器
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
            mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
    mFirstBoot = mPackageManagerService.isFirstBoot();
    mPackageManager = mSystemContext.getPackageManager();

    //服務管理器
    ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());

    // Initialize attribute cache used to cache resources from packages.
    AttributeCache.init(mSystemContext);

    // Set up the Application instance for the system process and get started.
    mActivityManagerService.setSystemProcess();
}

step3 startCoreServices();
這一段google工程師註釋很詳細了就不多解釋了
private void startCoreServices() {
// Manages LEDs and display backlight.
mSystemServiceManager.startService(LightsService.class);

    // Tracks the battery level.  Requires LightService.
    mSystemServiceManager.startService(BatteryService.class);

    // Tracks application usage stats.
    mSystemServiceManager.startService(UsageStatsService.class);
    mActivityManagerService.setUsageStatsManager(
            LocalServices.getService(UsageStatsManagerInternal.class));
    // Update after UsageStatsService is available, needed before performBootDexOpt.
    mPackageManagerService.getUsageStatsIfNoPackageUsageInfo();

    // Tracks whether the updatable WebView is in a ready state and watches for update installs.
    mSystemServiceManager.startService(WebViewUpdateService.class);
}

step4 startOtherServices();
此處代碼量非常大,認真慢慢來

private void startOtherServices() {
   //前面變量初始化就刪掉啦,下面代碼也一樣,留下重要部分
    try {
            //功能性服務初始化
         //電話功能 此try內大部分爲相似,值得注意的是,在這部分在會掉過藍牙服務
        telephonyRegistry = new TelephonyRegistry(context);
        ServiceManager.addService("telephony.registry", telephonyRegistry);
    } catch (RuntimeException e) {

    }

     //此處基本上爲手機對於我們可見部分的服務啓動,比如UI

    try {
        wm.displayReady();
    } catch (Throwable e) {
        reportWtf("making display ready", e);
    }


      //系統設置服務初始化,比如wifi什麼的,通知什麼的
            mSystemServiceManager.startService("com.android.server.wifi.RttService");

        //launcher服務
        mSystemServiceManager.startService(LauncherAppsService.class);
    }

      //必要的系統配置
    Configuration config = wm.computeNewConfiguration();


   //可授權第三方的APP啓動了,值得注意的是ActivityManagerService的systemReady()方法
    mActivityManagerService.systemReady(new Runnable() {
        @Override
        public void run() {
            Slog.i(TAG, "Making services ready");
            mSystemServiceManager.startBootPhase(
                    SystemService.PHASE_ACTIVITY_MANAGER_READY);

            try {
                mActivityManagerService.startObservingNativeCrashes();
            } catch (Throwable e) {
                reportWtf("observing native crashes", e);
            }

            Slog.i(TAG, "WebViewFactory preparation");
            WebViewFactory.prepareWebViewInSystemServer();

             //此處忽略各種判斷捕獲
        }
    });
}

10.ActivityManagerService.java

這裏寫圖片描述
路徑依然還是frameworks下
step1 systemReady()方法

public void systemReady(final Runnable goingCallback) {
    //在這個方法中會發現很多代碼都有synchronized在修飾
    synchronized(this) {
        if (mSystemReady) {
            // If we're done calling all the receivers, run the next "boot phase" passed in
            // by the SystemServer
            if (goingCallback != null) {
                goingCallback.run();
            }
            return;
        }

       //安全檢查,就是鎖屏輸密碼
        updateCurrentProfileIdsLocked();

        if (!mDidUpdate) {
            if (mWaitingUpdate) {
                return;
            }
            final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
            mWaitingUpdate = deliverPreBootCompleted(new Runnable() {
                public void run() {
                   //記載各種組件
                    systemReady(goingCallback);
                }
            }, doneReceivers, UserHandle.USER_OWNER);

        }

        mAppOpsService.systemReady();
        mSystemReady = true;
    }



    //到這裏的時候 系統已經萬全準備好了
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
        SystemClock.uptimeMillis());

         //鎖定棧頂的activity,至此,已經是到了手機解鎖的界面了
        mStackSupervisor.resumeTopActivitiesLocked();
        sendUserSwitchBroadcastsLocked(-1, mCurrentUserId);
    }
}

總結

對於Android的啓動源碼呢,涉及到了很多的東西,方方面面,我可能講的不是很到位,還是各位慢慢吸收理解.多多支持.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章