Android Boot: After kernel stage

本文详细介绍了Android系统从内核启动后,如何通过init进程、Service Manager、app_process、ZygoteInit及SystemServer来一步步构建运行环境。首先init解析配置文件启动服务,接着Service Manager为启动app_process做准备,app_process运行ZygoteInit,通过Dalvik虚拟机启动Zygote。Zygote孵化SystemServer,加载libandroid_servers,注册JNI函数,并最终启动所有关键服务,完成Android系统的初始化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本来一直在分析WIFI service,后来一直往底层追溯,就跟踪到了Android的service manager等“大户”的启动,再往上追就到了init了。先大概记录一下启动的流程,以后有空了再补充某些步骤的细节。由于分析的是Kernel起来之后剩下的启动过程,所以从init进程开始:

一,init
Init是由kernel启动的用户级进程,它始终是第一个存在进程。init起来之后会解析init.rc和init.{hardware}.rc,然后根据其内容启动基本服务和做些其他的东西。init*rc里面可以有(Actions, Commands, Services, Options)四种类型的声明,另外再分析。下面先看看init.rc里面的两行:
service servicemanager /system/bin/servicemanager
    ...
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    ...

二,ServiceMangaer与app_process
其中servicemanager的代码为frameworks/base/cmds/servicemanager/service_manager.c,ServiceManager总管所有service(frameworks层次的service)的注册与查找(详情点击这里),先运行它主要是为后面的app_process启动zygote的过程提供前提条件。

app_prceoss的代码为frameworks/base/cmds/app_process/app_main.cpp,其主函数如下:
int main(int argc, const char* const argv[])
{
         ...
    AppRuntime runtime;
         ...    
    // Next arg is startup classname or "--zygote"
    if (i < argc) {
        arg = argv[i++];
        if (0 == strcmp("--zygote", arg)) {
            bool startSystemServer = (i < argc) ?
                    strcmp(argv[i], "--start-system-server") == 0 : false;
            setArgv0(argv0, "zygote");
            set_process_name("zygote");
            runtime.start("com.android.internal.os.ZygoteInit",
                startSystemServer);

        } else {
         ...
        }
    } else {
         ...
    }

}
其中以"com.android.internal.os.ZygoteInit"为类名调用AppRuntime : public AndroidRuntime的start()函数来启动zygote,其代码在frameworks/base/core/jni/AndroidRuntime.cpp中,start函数如下:
void AndroidRuntime::start(const char* className, const bool startSystemServer)
{
         ...
    if (startVm(&mJavaVM, &env) != 0)
        goto bail;
         ...
    if (startReg(env) < 0) {
        LOGE("Unable to register all android natives\n");
        goto bail;
    }
         ...
    startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            LOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
         ...
}
startVm启动dalvik虚拟机,startReg负责把注册一些jni函数,然后就是找到名字为ZygoteInit的类并运行其main()函数。

三,ZygoteInit类
下面看看这个类的main函数,代码在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java,主函数如下:
  public static void main(String argv[]) {
        try {
                  ...
            if (argv[1].equals("true")) {
                startSystemServer();
            } else if (!argv[1].equals("false")) {
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }
                 ...
            if (ZYGOTE_FORK_MODE) {
                runForkMode();
            } else {
                runSelectLoopMode();
            }

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }
因为在AndroidRuntime::start中,"true"参数由strArray带进来,所以会调用到 startSystemServer()函数:
private static boolean startSystemServer()
            throws MethodAndArgsCaller, RuntimeException {
        /* Hardcoded command line to start the system server */
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
            "--capabilities=130104352,130104352",
            "--runtime-init",
            "--nice-name=system_server",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
                   ...
            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(    // 具体实现查看dalvik/vm/InternalNative.c
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids, debugFlags, null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }
设置一堆启动参数之后,调用forkSystemServer启动子进程来跑handleSystemServerProcess(),父进程返回继续忙其他的事情(就是runForkMode或者runSelectLoopMode),然后这个函数又绕到了RuntimeInit.zygoteInit(parsedArgs.remainingArgs):
public static final void zygoteInit(String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
            ...
        commonInit();   // 做些初始化的工作
        zygoteInitNative();

            ...
        String startClass = argv[curArg++];
        String[] startArgs = new String[argv.length - curArg];

        System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);
        invokeStaticMain(startClass, startArgs);
    }
invokeStaticMain这个函数在根据startArgs找到类名为"com.android.server.SystemServer"的main函数(还检查了public和static属性),然后通过throw new ZygoteInit.MethodAndArgsCaller(m, argv)返回。注意观察中间这些函数都带throws ZygoteInit.MethodAndArgsCaller的,所以这个 ZygoteInit.MethodAndArgsCaller最后会被ZygoteInit的main函数catch到然后通过 caller.run();启动SystemServer的main函数。


四,SystemServer类
类的代码在frameworks/base/services/java/com/android/server/SystemServer.java中,主函数:
public static void main(String[] args) {
              ...
        System.loadLibrary("android_servers");
        init1(args);
    }
先显式加载libandroid_servers,这个库由frameworks/base/services/jni中的代码生成,加载时会把onload.cpp里的JNI_OnLoad()跑一遍把jni函数注册上去:
    register_android_server_PowerManagerService(env);
    register_android_server_InputManager(env);
    register_android_server_LightsService(env);
    register_android_server_AlarmManagerService(env);
    register_android_server_BatteryService(env);
    register_android_server_UsbService(env);
    register_android_server_VibratorService(env);
    register_android_server_SystemServer(env);
    register_android_server_location_GpsLocationProvider(env);
库加载完后,SystemServer的main函数再调用init1(args)进行下一步的工作,这个函数在SystemServer.java中是这样定义的native public static void init1(String[] args);所以是通过jni的方式进行调用,init1的实现在libandroid_servers库的代码中:
static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
{
    system_init();
}
system_init()的实现在frameworks/base/cmds/system_server/library/system_init.cpp中(生成的是libsystem_server):
extern "C" status_t system_init()
{
        ... // 先启动SurfaceFinger和SensorService等关键服务
    property_get("system_init.startsurfaceflinger", propBuf, "1");
    if (strcmp(propBuf, "1") == 0) {
        // Start the SurfaceFlinger
        SurfaceFlinger::instantiate();
    }

    // Start the sensor service
    SensorService::instantiate();

    // 如果是emulator的话直接在这里把下面的service也拉起来
    if (!proc->supportsProcesses()) {

        // Start the AudioFlinger
        AudioFlinger::instantiate();

        // Start the media playback service
        MediaPlayerService::instantiate();

        // Start the camera service
        CameraService::instantiate();

        // Start the audio policy service
        AudioPolicyService::instantiate();
    }
        ...
    LOGI("System server: starting Android services.\n");
    runtime->callStatic("com/android/server/SystemServer", "init2");
        ...
    return NO_ERROR;
}
通过callStatic调用,又绕回了java层去,SystemServer.java中得init2如下:
public static final void init2() {
        Slog.i(TAG, "Entered the Android system server!");
        Thread thr = new ServerThread();
        thr.setName("android.server.ServerThread");
        thr.start();
}
ServerThread的start()调用run()来启动所有的JAVA Service:

    @Override
    public void run() {
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,
            SystemClock.uptimeMillis());

        Looper.prepare();

        android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);

        BinderInternal.disableBackgroundScheduling(true);
        android.os.Process.setCanSelfBackground(false);

        // Check whether we failed to shut down last time we tried.
        {
            final String shutdownAction = SystemProperties.get(
                    ShutdownThread.SHUTDOWN_ACTION_PROPERTY, "");
            if (shutdownAction != null && shutdownAction.length() > 0) {
                boolean reboot = (shutdownAction.charAt(0) == '1');

                final String reason;
                if (shutdownAction.length() > 1) {
                    reason = shutdownAction.substring(1, shutdownAction.length());
                } else {
                    reason = null;
                }

                ShutdownThread.rebootOrShutdown(reboot, reason);
            }
        }

        String factoryTestStr = SystemProperties.get("ro.factorytest");
        int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
                : Integer.parseInt(factoryTestStr);

        LightsService lights = null;
        PowerManagerService power = null;
        BatteryService battery = null;
        ConnectivityService connectivity = null;
        IPackageManager pm = null;
        Context context = null;
        WindowManagerService wm = null;
        BluetoothService bluetooth = null;
        BluetoothA2dpService bluetoothA2dp = null;
        HeadsetObserver headset = null;
        DockObserver dock = null;
        UsbService usb = null;
        UiModeManagerService uiMode = null;
        RecognitionManagerService recognition = null;
        ThrottleService throttle = null;

        // Critical services...
        try {
                     ...
            // 类似下面这段代码,先创建JAVA Service类(new或者getInstance)
            // 再调用ServiceManager的addService API将系统的各种JAVA Service加进来
            try {
                Slog.i(TAG, "Connectivity Service");
                connectivity = ConnectivityService.getInstance(context);
                ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);   
               // WIFI相关的service由connectivity service管理
               // getInstance()会调用ConnectivityService()构造函数,其中会通过
               // WifiStateTracker wst = new WifiStateTracker(context, mHandler);
               // WifiService wifiService = new WifiService(context, wst);
               // ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
               // wifiService.startWifi(); 来启动wifi service
               // wifi相关的另文分析
            } catch (Throwable e) {
                Slog.e(TAG, "Failure starting Connectivity Service", e);
            }
                    ...

        // It is now time to start up the app processes...
        // Service加完后,可以通过systemReady()回调来通知各个Service现在可以开始自己的服务了
        if (devicePolicy != null) {
            devicePolicy.systemReady();
        }

        if (notification != null) {
            notification.systemReady();
        }

        if (statusBar != null) {
            statusBar.systemReady();
        }
        wm.systemReady();
        power.systemReady();
        try {
            pm.systemReady();
        } catch (RemoteException e) {
        }

        // These are needed to propagate to the runnable below.
        final StatusBarManagerService statusBarF = statusBar;
        final BatteryService batteryF = battery;
        final ConnectivityService connectivityF = connectivity;
        final DockObserver dockF = dock;
        final UsbService usbF = usb;
        final ThrottleService throttleF = throttle;
        final UiModeManagerService uiModeF = uiMode;
        final AppWidgetService appWidgetF = appWidget;
        final WallpaperManagerService wallpaperF = wallpaper;
        final InputMethodManagerService immF = imm;
        final RecognitionManagerService recognitionF = recognition;
        final LocationManagerService locationF = location;

        // We now tell the activity manager it is okay to run third party
        // code.  It will call back into us once it has gotten to the state
        // where third party code can really run (but before it has actually
        // started launching the initial applications), for us to complete our
        // initialization.
        ((ActivityManagerService)ActivityManagerNative.getDefault())
                .systemReady(new Runnable() {  // 这个回调将会通过发送intent.CATEGORY_HOME启动第一个activity,具体代码待分析
            public void run() {
                Slog.i(TAG, "Making services ready");

                if (statusBarF != null) statusBarF.systemReady2();
                if (batteryF != null) batteryF.systemReady();
                if (connectivityF != null) connectivityF.systemReady();
                if (dockF != null) dockF.systemReady();
                if (usbF != null) usbF.systemReady();
                if (uiModeF != null) uiModeF.systemReady();
                if (recognitionF != null) recognitionF.systemReady();
                Watchdog.getInstance().start();

                // It is now okay to let the various system services start their
                // third party code...

                if (appWidgetF != null) appWidgetF.systemReady(safeMode);
                if (wallpaperF != null) wallpaperF.systemReady();
                if (immF != null) immF.systemReady();
                if (locationF != null) locationF.systemReady();
                if (throttleF != null) throttleF.systemReady();
            }
        });

        // For debug builds, log event loop stalls to dropbox for analysis.
        if (StrictMode.conditionallyEnableDebugLogging()) {
            Slog.i(TAG, "Enabled StrictMode for system server main thread.");
        }

        Looper.loop();
        Slog.d(TAG, "System ServerThread is exiting!");
        }
    }

五,后续
至此,提供给app运行的环境已经搭建起来,但是某些步骤还是不太完善需要以后补充。其中关system_init()这个函数也可以通过/system/bin/system_server来显式调用。找到一段说明如下:
There is another way to start system server, which is through a program named system_server whose source is frameworks/base/cmds/system_server/system_main.cpp. It also calls system_init to start system services. So there is a question: why does Android have two methods to start system services? My guess is that directly start system_server may have synchronous problem with zygote because system_server will call JNI to start SystemServer::init2, while at that time zygote may not start JAVA VM yet. So Android uses another method. After zynote is initialized, fork a new process to start system services.

大致意思是,可以通过system_server这个命令调用system_init来启动system services,但是为什么Android要使用上述的方式来启动呢。据猜测是如果直接用命令来启动的话会跟zygote有同步的问题存在,因为system_init会通过JNI来调用SystemServer::init2,如果这时候zygote尚未启动JAVA VM就会出问题了。 
### TDA4VM U-Boot Configuration and Usage Tutorial For the Texas Instruments (TI) TDA4VM platform, configuring and using U-Boot involves several key steps to ensure proper initialization of the system before loading an operating system or application. The process starts with setting up the hardware correctly. Configuring SW8 and SW9 dip switches into SD card boot mode is essential as part of initial setup procedures[^1]. Once these settings are confirmed, inserting a properly prepared SD card that contains the necessary bootloader files including U-Boot will allow the board to start from this medium when powered on. After powering up the device successfully through the described method, accessing the command line interface typically requires logging in as `root` without needing additional credentials during development phases[^2]. To delve deeper specifically into U-Boot: #### Setting Up Environment Variables Environment variables within U-Boot play a critical role in defining how the bootloader operates. These can be set via commands directly at the U-Boot prompt after gaining access post-boot sequence completion. Commonly adjusted parameters include those specifying memory addresses where kernel images should reside once loaded along with other important configurations like IP address assignment methods for network operations if applicable. ```bash setenv ipaddr 192.168.0.10 setenv serverip 192.168.0.1 saveenv ``` These examples demonstrate basic networking environment variable assignments which might prove useful depending upon intended use cases involving remote file transfers over Ethernet connections between host machines and target boards running U-Boot. #### Loading Kernel Image Using TFTP Protocol Transferring binary payloads such as Linux kernels onto RAM buffers inside embedded systems often leverages protocols supported by U-Boot. One common approach employs Trivial File Transfer Protocol (TFTP), facilitating straightforward downloads initiated either manually or scripted automatically based on predefined paths stored among previously mentioned environmental properties. ```bash tftpboot ${loadaddr} /path/to/kernel.img go ${loadaddr} ``` This pair of instructions first fetches then executes code located remotely relative to what has been specified under `${loadaddr}` placeholder symbolizing destination location within volatile storage space allocated temporarily while executing tasks outside persistent filesystem contexts. #### Customizing Boot Arguments Passed To OS Kernels Tailoring arguments passed down ultimately influences behavior exhibited throughout subsequent stages following successful invocation past early-stage firmware layers managed hereunder control structures implemented natively alongside core functionalities provided out-of-the-box but extendable according to project requirements. ```bash setenv bootargs "console=ttyS2,115200n8 root=/dev/mmcblk0p2 rw" bootm ${loadaddr} ``` Above snippet illustrates appending console output redirection together with designating active partition serving as root filesystem mount point besides read-write permissions flagging – all crucial aspects affecting overall performance characteristics observable later downstream processes contingent upon accurate parameterization applied upstream accordingly prior launch sequences commence execution flow transition points bridging low-level abstractions towards higher-order constructs embodied fully formed runtime environments ready hosting applications atop solid foundations laid meticulously beforehand ensuring stability reliability efficiency across diverse scenarios encountered field deployments real-world conditions varying widely case-by-case basis. --related questions-- 1. How does one customize U-Boot's default environment variables? 2. What tools are available for debugging issues related to U-Boot on TI platforms? 3. Can you provide guidance on integrating custom scripts into U-Boot for automated testing purposes? 4. Are there any specific considerations when updating U-Boot versions on TDA4VM devices?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值