Tiny4412 Android 启动流程

Posted CrazyDiode

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tiny4412 Android 启动流程相关的知识,希望对你有一定的参考价值。

android系统的启动主要包括三个阶段:

①BootLoader启动

②Linux Kernel启动

③Android系统启动

前面我们大致分析了前面两个步骤,即u-boot和内核的启动流程(内核启动流程待完善-_-!!),这次就来分析以下Linux内核启动之后是怎样挂载起Android这个“根文件系统”的。Android系统在Linux内核上运行了一系列的系统服务。

和Linux系统类似,Android系统中第一个被启动的进程也是init进程,它的PID为0。Android系统的init进程启动的过程中会解析init.rc文件,以此来构建出系统的初始运行形态。其他Android系统服务,比如装载Android的文件系统、创建系统目录、初始化属性系统、启动Android系统重要的守护进程,这些进程包括USB守护进程,adb守护进程,vold守护进程,rild守护进程、mediaserver和ServiceManager等,大多都是在这个脚本中被相继启动的。

init进程启动后会执行system/core/init/init.c 中的 main 函数,并且在main函数中调用init_parse_config_file函数来解析init.rc脚本。下面就分析以下这个main函数究竟做了那些事。

//  system/core/init/init.c
int main(int argc, char **argv)
{
    ....
    //对umask进行清零
    umask(0);
    //为rootfs建立必要的文件夹,并挂载适当的分区
    mkdir("/dev", 0755);
    mkdir("/proc", 0755);
    mkdir("/sys", 0755);
    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
    mkdir("/dev/pts", 0755);
    mkdir("/dev/socket", 0755);
    mount("devpts", "/dev/pts", "devpts", 0, NULL);
    mount("proc", "/proc", "proc", 0, NULL);
    mount("sysfs", "/sys", "sysfs", 0, NULL);
        /* indicate that booting is in progress to background fw loaders, etc */
    close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
    //调用dup函数把标准输入,输出,错误输出都重定位到/dev/__null__
    open_devnull_stdio();
    //初始化kernel log,创建/dev/kmsg设备节点
    klog_init();
    //属性初始化,读取default.prop
    property_init();
    //获取硬件信息/proc/cpuinfo
    get_hardware_name(hardware, &revision);
    //获取命linux内核传来命令行信息
    process_kernel_cmdline();
    union selinux_callback cb;
    cb.func_log = log_callback;
    selinux_set_callback(SELINUX_CB_LOG, cb);
    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
    selinux_initialize();
    /* These directories were necessarily created before initial policy load
     * and therefore need their security context restored to the proper value.
     * This must happen before /dev is populated by ueventd.
     */
    restorecon("/dev");
    restorecon("/dev/socket");
    restorecon("/dev/__properties__");
    restorecon_recursive("/sys");
    is_charger = !strcmp(bootmode, "charger");
    INFO("property init\\n");
    property_load_boot_defaults();
    INFO("reading config file\\n");
    ///解析init.rc脚本
    init_parse_config_file("/init.rc");
    //执行rc文件中触发器为 on early-init的语句
    action_for_each_trigger("early-init", action_add_queue_tail);
     /* 
        解析完init.rc配置文件后,会得到一系列的Action,action_for_each_trigger函数用来执行early-init阶段的Action。 
        init将动作执行的时间划分为4个阶段:early-init、init、early-boot、boot。由于有些动作必须要在其他动作完成后才能执行,
        所以就有了先后之分。哪些动作属于哪个阶段由配置文件决定。 
    */  
    queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
    queue_builtin_action(keychord_init_action, "keychord_init");
    queue_builtin_action(console_init_action, "console_init");
     // 执行init阶段的动作
    /* execute all the boot actions to get us started */
    action_for_each_trigger("init", action_add_queue_tail);
    /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
     * wasn\'t ready immediately after wait_for_coldboot_done
     */
    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
    queue_builtin_action(property_service_init_action, "property_service_init");
    queue_builtin_action(signal_init_action, "signal_init");
    /* Don\'t mount filesystems or start core system services if in charger mode. */
    if (is_charger) {
        action_for_each_trigger("charger", action_add_queue_tail);
    } else {
        action_for_each_trigger("late-init", action_add_queue_tail);
    }
    /* run all property triggers based on current state of the properties */
    queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
#if BOOTCHART
    queue_builtin_action(bootchart_init_action, "bootchart_init");
#endif
    // 无限循环,用来处理各种消息  
    for(;;) {
        int nr, i, timeout = -1;
        execute_one_command();
        // 重启那些已经死去的进程,启动所有init脚本中声明的service
        restart_processes();
        // 用来监听属性设置服务的事件
        if (!property_set_fd_init && get_property_set_fd() > 0) {
            ufds[fd_count].fd = get_property_set_fd();
            ufds[fd_count].events = POLLIN;
            ufds[fd_count].revents = 0;
            fd_count++;
            property_set_fd_init = 1;
        }
        if (!signal_fd_init && get_signal_fd() > 0) {
            ufds[fd_count].fd = get_signal_fd();
            ufds[fd_count].events = POLLIN;
            ufds[fd_count].revents = 0;
            fd_count++;
            signal_fd_init = 1;
        }
        if (!keychord_fd_init && get_keychord_fd() > 0) {
            ufds[fd_count].fd = get_keychord_fd();
            ufds[fd_count].events = POLLIN;
            ufds[fd_count].revents = 0;
            fd_count++;
            keychord_fd_init = 1;
        }
        if (process_needs_restart) {
            timeout = (process_needs_restart - gettime()) * 1000;
            if (timeout < 0)
                timeout = 0;
        }
        if (!action_queue_empty() || cur_action)
            timeout = 0;
#if BOOTCHART
        if (bootchart_count > 0) {
            if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
                timeout = BOOTCHART_POLLING_MS;
            if (bootchart_step() < 0 || --bootchart_count == 0) {
                bootchart_finish();
                bootchart_count = 0;
            }
        }
#endif
        nr = poll(ufds, fd_count, timeout);
        if (nr <= 0)
            continue;
        // 处理具体的消息
        for (i = 0; i < fd_count; i++) {
            if (ufds[i].revents & POLLIN) {
                if (ufds[i].fd == get_property_set_fd())
                    handle_property_set_fd();
                else if (ufds[i].fd == get_keychord_fd())
                    handle_keychord();
                else if (ufds[i].fd == get_signal_fd())
                    handle_signal();
            }
        }
    }
    return 0;
}

在 restart_processes 函数中回去解析init.rc中的Service标号,启动Service

//system/core/init/init.c
static void restart_processes()        
{
    process_needs_restart = 0; 
   //调用service_for_each_flags
    service_for_each_flags(SVC_RESTARTING,
                           restart_service_if_needed);
}

在restart_processes调用了 service_for_each_flags

// system/core/init/init_parser.c
void service_for_each_flags(unsigned matchflags,        
                            void (*func)(struct service *svc))
{
    struct listnode *node;
    struct service *svc;
    //遍历service_list链表里的每一个节点
    list_for_each(node, &service_list) {
        svc = node_to_item(node, struct service, slist);
        if (svc->flags & matchflags) {
            //调用传进来的func函数处理svc
            func(svc);
        }
    }   
}

所以最终我们是调用了 restart_service_if_needed 来处理 SVC_RESTARTING链表里的每一个service节点。看一下这个restart_service_if_needed函数

static void restart_service_if_needed(struct service *svc)
{
    time_t next_start_time = svc->time_started + 5; 
    if (next_start_time <= gettime()) {                 
        svc->flags &= (~SVC_RESTARTING);
        //启动service
        service_start(svc, NULL);
        return;
    }    
    if ((next_start_time < process_needs_restart) ||
        (process_needs_restart == 0)) {
        process_needs_restart = next_start_time;
    }    
}

接着分析一下这个service_start函数

//   system/core/init/init.c
void service_start(struct service *svc, const char *dynamic_args)
{
    ....
     NOTICE("starting \'%s\'\\n", svc->name);
    //创建一个子线程,启动service
     pid = fork();
     ....
}

init.rc语法

以行尾单位,以空格间隔的语法,以#开始代表注释行。rc文件主要包含Action、Service、Command、Options,其中对于Action和Service的名称都是唯一的,对于重复的命名视为无效。在android 5.0.2源码system/core/init/readme.txt中有init.rc语法的帮助文档。

①Action(动作)

Action: 通过trigger,即以 on开头的语句,决定何时执行相应的service。

on early-init; 在初始化早期阶段触发;

on init; 在初始化阶段触发;

on late-init; 在初始化晚期阶段触发;

on boot/charger: 当系统启动/充电时触发,还包含其他情况,此处不一一列举;

on property:<key>=<value>: 当属性值满足条件时触发;

 

②Commands(命令)

下面列举常用的命令

class_start <service_class_name>: 启动属于同一个class的所有服务;

start <service_name>: 启动指定的服务,若已启动则跳过;

stop <service_name>: 停止正在运行的服务;

setprop <name> <value>:设置属性值;

mkdir <path>:创建指定目录;

symlink <target> <sym_link>: 创建连接到<target>的<sym_link>符号链接;

write <path> <string>: 向文件path中写入字符串;

exec: fork并执行,会阻塞init进程直到程序完毕;

exprot <name> <name>:设定环境变量;

loglevel <level>:设置log级别;

 

③Service(服务)

服务Service,以 service开头,由init进程启动,一般运行于另外一个init的子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service,在启动时会通过fork方式生成子进程。

例如: service servicemanager /system/bin/servicemanager代表的是服务名为servicemanager,服务的路径,也就是服务执行操作时运行/system/bin/servicemanager。

 

④Options(选项)

Options是Services的可选项,与service配合使用

disabled: 不随class自动启动,只有根据service名才启动;

oneshot: service退出后不再重启;

user/group: 设置执行服务的用户/用户组,默认都是root;

class:设置所属的类名,当所属类启动/退出时,服务也启动/停止,默认为default;

onrestart:当服务重启时执行相应命令;

socket: 创建名为/dev/socket/<name>的socket

critical: 在规定时间内该service不断重启,则系统会重启并进入恢复模式

default: 意味着disabled=false,oneshot=false,critical=false。

所有的Service里面只有servicemanager ,zygote ,surfaceflinger这3个service有onrestart关键字来触发其他service启动过程。

系统启动流程

本地系统服务:在init.rc初始化一个server入口,然后通过这个server去启动其他service,比如mediaserver

Java系统服务启动:

 1):init启动service manager,这个进程主要负责系统服务的注册管理,包括“java系统服务”“本地系统服务”

 2):init启动Media server,这个进程负责启动C/C++的“本地系统服务”。

 3):init启动Zygote,这个进程启动System server进程,这个进程启动"Java系统服务"---[包括power manager    service,sensor service]

 4):另外init启动system/bin下面的各种守护进程

首先看一下init.rc里面是如何启动这些系统服务的

## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0
service logd /system/bin/logd
    class core
    socket logd stream 0666 logd logd
    socket logdr seqpacket 0666 logd logd
    socket logdw dgram 0222 logd logd
    seclabel u:r:logd:s0
service healthd /sbin/healthd
    class core
    critical
    seclabel u:r:healthd:s0
service console /system/bin/sh
    class core
    console
    disabled
    user shell
    group shell log
    seclabel u:r:shell:s0
on property:ro.debuggable=1
    start console
# adbd is controlled via property triggers in init.<platform>.usb.rc
service adbd /sbin/adbd --root_seclabel=u:r:su:s0
    class core
    socket adbd stream 660 system system
    disabled
    seclabel u:r:adbd:s0
# adbd on at boot in emulator
on property:ro.kernel.qemu=1
    start adbd
service lmkd /system/bin/lmkd
    class core
    critical
    socket lmkd seqpacket 0660 system system
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
service vold /system/bin/vold
    class core
    socket vold stream 0660 root mount
    ioprio be 2
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
service debuggerd /system/bin/debuggerd
    class main
# for ZTE 3G
service ril-daemon /system/bin/rild -l /system/lib/libzte-ril.so -- -d /dev/ttyUSB1 -u /dev/ttyUSB3
    class main
    socket rild stream 660 root radio
    socket rild-debug stream 660 radio system
    user root
    group radio cache inet misc audio sdcard_r sdcard_rw log net_admin net_raw
on property:ril.reset.rild=1
    stop ril-daemon
    start ril-daemon
    setprop ril.reset.rild 0
service pppd_gprs /system/etc/ppp/init.gprs-pppd
    user root
    group radio cache inet misc log net_admin net_raw
    disabled
    oneshot
service surfaceflinger /system/bin/surfaceflinger
    class core
    user system
    group graphics drmrpc
    #重启时会触发zygote重启
    onrestart restart zygote
service drm /system/bin/drmserver
    class main
    user drm
    group drm system inet drmrpc
service media /system/bin/mediaserver
    class main
    user media
    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
    ioprio rt 4
# One shot invocation to deal with encrypted volume.
service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted
    disabled
    oneshot
    # vold will set vold.decrypt to trigger_restart_framework (default
    # encryption) or trigger_restart_min_framework (other encryption)
# One shot invocation to encrypt unencrypted volumes
service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
    disabled
    oneshot
    # vold will set vold.decrypt to trigger_restart_framework (default
    # encryption)
service bootanim /system/bin/bootanimation
    class core
    user graphics
    group graphics audio
    disabled
    oneshot
service installd /system/bin/installd
    class main
    socket installd stream 600 system system
service flash_recovery /system/bin/install-recovery.sh
    class main
    seclabel u:r:install_recovery:s0
    oneshot
service racoon /system/bin/racoon
    class main
    socket racoon stream 600 system system
    # IKE uses UDP port 500. Racoon will setuid to vpn after binding the port.
    group vpn net_admin inet
    disabled
    oneshot
service mtpd /system/bin/mtpd
    class main
    socket mtpd stream 600 system system
    user vpn
    group vpn net_admin inet net_raw
    disabled
    oneshot
service keystore /system/bin/keystore /data/misc/keystore
    class main
    user keystore
    group keystore drmrpc
service dumpstate /system/bin/dumpstate -s
    class main
    socket dumpstate stream 0660 shell log
    disabled
    oneshot
service mdnsd /system/bin/mdnsd
    class main
    user mdnsr
    group inet net_raw
    socket mdnsd stream 0660 mdnsr inet
    disabled
    oneshot
service pre-recovery /system/bin/uncrypt
    class main
    disabled
    oneshot

init进程通过init.rc脚本启动servicemanager

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

个servicemanager是Android系统Binder进程间通信的重要的守护进程

这个先放一下,之后学习Binder系统的时候再深入分析。

init进程又启动了zygote进程

init.rc脚本在开是引入了zygote的启动脚本

import /init.${ro.zygote}.rc
#system/core/rootdir/init.zygote32.rc
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

zygote进程是java环境的入口

// frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
    ....
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }
    if (zygote) {
        //启动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;
    }
}

看一下系统是怎样进入java环境的

// frameworks/base/core/jni/AndroidRuntime.cpp 
void AndroidRuntime::start(const char* className, const Vector<String8>& options)
{
    ALOGD("\\n>>>>>> AndroidRuntime START %s <<<<<<\\n",
    ....
    //启动systemserver
    static const String8 startSystemServer("start-system-server");
    ....
    //启动java进程
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class \'%s\'\\n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in \'%s\'\\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
        ....
}

接着就是启动systemserver了,它是由zygote启动的

// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 
public static void main(String argv[]) {
    ....
    registerZygoteSocket(socketName);//注册socket
    ....
    if (startSystemServer) {
                //启动SystemServer
                startSystemServer(abiList, socketName);
            }
    ....
}

systemserver启动了一票的Java层服务

//frameworks/base/services/java/com/android/server/SystemServer.java 
public static void main(String[] args) {
        //new一个SystemServer对象并调用其run函数
        new SystemServer().run();
    }
private void run() {
    ....
    // Here we go!
    Slog.i(TAG, "Entered the Android system server!");
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
    ....
    // Initialize native services.
    //加载本地库并初始化
    System.loadLibrary("android_servers");
    nativeInit();
    ....
    // Start services.
    //启动一票的Java层系统服务
        try {
            startBootstrapServices();
            startCoreServices();
            startOtherServices(); 
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        }

下面看一下这些系统服务的启动过程,注释很详细

 private void startBootstrapServices() {
        // Wait for installd to finish starting up so that it has a chance to
        // create critical directories such as /data/user with the appropriate
        // permissions.  We need this to complete before we initialize other services.
        mInstaller = mSystemServiceManager.startService(Installer.class);
        // Activity manager runs the show.
        mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        // Power manager needs to be started early because other services need it.
        // Native daemons may be watching for it to be registered so it must be ready
        // to handle incoming binder calls immediately (including being able to verify
        // the permissions for those calls).
        mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
        // Now that the power manager has been started, let the activity manager
        // initialize power management features.
        mActivityManagerService.initPowerManagement();
        // Display manager is needed to provide display metrics before package manager
        // starts up.
        mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
        // We need the default display before we can initialize the package manager.
        mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
        // Only run "core" apps if we\'re encrypting the device.
        String cryptState = SystemProperties.get("vold.decrypt");
        if (ENCRYPTING_STATE.equals(cryptState)) {
            Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
            mOnlyCore = true;
        } else if (ENCRYPTED_STATE.equals(cryptState)) {
            Slog.w(TAG, "Device encrypted - only parsing core apps");
            mOnlyCore = true;
        }
        // Start the package manager.
        Slog.i(TAG, "Package Manager");
        mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();
        Slog.i(TAG, "User Service");
        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();
    }
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));
        // Tracks whether the updatable WebView is in a ready state and watches for update installs.
        mSystemServiceManager.startService(WebViewUpdateService.class);
    }
private void startOtherServices() {
    ....
    Slog.i(TAG, "Reading configuration...");
    SystemConfig.getInstance();
    Slog.i(TAG, "Scheduling Policy");
    ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
    Slog.i(TAG, "Telephony Registry");
    telephonyRegistry = new TelephonyRegistry(context);
    ServiceManager.addService("telephony.registry", telephonyRegistry);
    Slog.i(TAG, "Entropy Mixer");
    ServiceManager.addService("entropy", new EntropyMixer(context));
    Slog.i(TAG, "Account Manager");
    accountManager = new AccountManagerService(context);
    ServiceManager.addService(Context.ACCOUNT_SERVICE, accountManager);
    //下面还有很多,具体用到哪些东西的时候再回过头来分析
    ....

再往下就是开机进入锁屏界面了,这部分内容还不熟悉,之后再分析。。。。。-_-!!!

 

 

多谢下面两位前辈的无私分享

参考文章:

http://gityuan.com/

http://blog.csdn.net/hovan/article/details/9896751

 

以上是关于Tiny4412 Android 启动流程的主要内容,如果未能解决你的问题,请参考以下文章

Tiny4412 u-boot分析u-boot启动流程

Tiny4412 u-boot分析u-boot 引导内核流程

Tiny4412学习杂记

Tiny4412 Linux 内核配置流程

Tiny4412 u-boot分析u-boot配置流程分析

使用NFS启动Tiny4412开发板根文件系统