linux系统启动流程分析

来源:互联网 发布:手机pdf修改软件 编辑:程序博客网 时间:2024/04/30 04:38

 

桌面操作系统启动流程(redhat,federa,ubuntu)
ubuntu从6.10开始逐步用upstart代替原来的sysinit,进行服务进程的管理。为了对原有的init实现向后兼容,
目前ubuntu中与init相关的几个目录和应用程序,可以方便后面的论述。这些目录和程序包括:
init
telinit  //字面理解 tell init
runlevel
/etc/event.d/
/etc/init.d/
/etc/rcX.d/
首先是/etc/event.d/目录,这是upstart的核心,upstart不同于原有的init的地方就在于它引入了event机制。Event 机制通俗的讲就是将所有进程的触发、停止等等都看作event(事件)。/etc/event.d/中就存放了目前upstart需要识别的event。这其中主要有三种
rc-default, rcX(x=0,1,...6,S)以及ttyX。这rc-default就类似于 inittab文件,它就是设置默认运行级别的 ,需要运行程序的脚本,而ttyX则是设置伪终端数目的,也就是你Ctrl+Alt+F(1~6)调出的那个Console。我们以rc2为例,cat rc2:
rc-default
start on stopped rcS
telinit 2
所以会依次执行 /etc/event.d/rcS /etc/event.d/rc2
它们又会分别执行:
exec /etc/init.d/rc S
exec /etc/init.d/rc 2
这样,我们就可以自然地过渡到下一个重要的目录,/etc/init.d/了。
/etc/init.d/中存放的是服务(services)或者任务(tasks)的执行脚本。可以这么说,只要你安装了一个程序(特别是服务程序daemon),它可以在系统启动的时候运行,那么它必定会在/etc/init.d/中有一个脚本文件。
执行了一个exec /etc/init.d/rc 2的命令。也就是说,给/etc/init.d/rc脚本传递了一个参数"2",让它执行。
rc脚本(很长,耐心点),能看到这样的一段:
# Now run the START scripts for this runlevel.
# Run all scripts with the same level in parallel
.......
for s in /etc/rc$runlevel.d/S*
.......
将会开始执行/etc/rc2.d/下S开头的脚本。这就过渡到下一个目录/etc/rc2.d/了。
/etc/rc2.d 都是一些到/etc/init.d/中脚本的符号链接。不同的是在开头加上了S和一个数字,S表示在启动时运行,数字则表示执行的先后顺序。
/etc/rcS.d/S35mountall.sh
K08vmware
S19vmware
S20nfs-common
S20nfs-kernel-server
S20samba
S20xinetd
S30gdm
S98usplash
S99rc.local
总结:
    这样一来,upstart管理的ubuntu启动过程应该就清楚了。梳理一下:
    1,内核启动init
    2,init找到/etc/event.d/rc-default文件,确定默认的运行级别(X)
    3,触发相应的runlevel事件,开始运行/etc/event.d/rcX
    4,rcX运行/etc/init.d/rc,传入参数X
    5,/etc/init.d/rc脚本进行一系列设置,最后运行相应的/etc/rcX.d/中的脚本
    6,/etc/rcX.d/中的脚本按事先设定的优先级依次启动,直至最后给出登录画面(启动X服务器和GDM)
    理解了这些,手动配置开机服务的启动与否就很简单了。Ubutnu默认的启动级别是2,不想启动的程序,只要把相应的符号链接从/etc/rc2.d/中删去即可
注意:
想redat ,federa 这些系统,他们用的是sysvinit ,有 /etc/inittab 文件,里面定义了 :
id:5:initdefault:
si::sysinit:/etc/init.d/rcS
init 直接解析  id:5:initdefault 字段,然后执行 /etc/rc5.d/ 下面的脚本
================
参考文档:
linux教程:upstart 和ubuntu启动过程原理介绍
http://www.zhiweinet.com/jiaocheng/2009-06/12500.htm

小型嵌入式系统启动流程
小型嵌入式的 init 通常使用busybox中自带的,
android 系统启动流程
init 是内核进入文件系统后第一个运行的程序,我们可以在linux的命令行中进行指定,如果没指定,内核将会到/sbin/, /bin/ 等目录下查找默认的init,如果没有找到那么就报告出错。
init 源代码分析
init的mian函数在文件:./system/core/init/init.c 中,init会一步步完成下面的任务:
1.初始化log系统
2.解析/init.rc和/init.%hardware%.rc文件  
3. 执行 early-init action in the two files parsed in step 2.  
4. 设备初始化,例如:在 /dev 下面创建所有设备节点,下载 firmwares.  
5. 初始化属性服务器,Actually the property system is working as a share memory. Logically it looks like a registry under Windows system.  
6. 执行 init action in the two files parsed in step 2.  
7. 开启 属性服务。
8. 执行 early-boot and boot actions in the two files parsed in step 2.  
9. 执行 Execute property action in the two files parsed in step 2.  
10. 进入一个无限循环 to wait for device/property set/child process exit events.例如,如果SD卡被插入,init会收到一个设备插入事件,它会为这个设备创建节点。系统中比较重要的进程都是由init来fork的,所以如果他们他谁崩溃了,那么init 将会收到一个 SIGCHLD 信号,把这个信号转化为子进程退出事件, 所以在loop中,init 会操作进程退出事件并且执行 *.rc 文件中定义的命令。
例如,在init.rc中,因为有:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    socket zygote stream 666
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
所以,如果zygote因为启动某些服务导致异常退出后,init将会重新去启动它。
int main(int argc, char **argv){
    ...
    //需要在后面的程序中看打印信息的话,需要屏蔽open_devnull_stdio()函数
    open_devnull_stdio();
    ...
    //初始化log系统
    log_init();
    //解析/init.rc和/init.%hardware%.rc文件
    parse_config_file("/init.rc");
    ...
    snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
    parse_config_file(tmp);
    ...
    //执行 early-init action in the two files parsed in step 2.
    action_for_each_trigger("early-init", action_add_queue_tail);
    drain_action_queue();
    ...
    /* execute all the boot actions to get us started */
    /* 执行 init action in the two files parsed in step 2 */
    action_for_each_trigger("init", action_add_queue_tail);
    drain_action_queue();
    ...
    /* 执行 early-boot and boot actions in the two files parsed in step 2 */
    action_for_each_trigger("early-boot", action_add_queue_tail);
    action_for_each_trigger("boot", action_add_queue_tail);
    drain_action_queue();
    /* run all property triggers based on current state of the properties */
    queue_all_property_triggers();
    drain_action_queue();
    /* enable property triggers */  
    property_triggers_enabled = 1;   
    ...
    for(;;) {
        int nr, timeout = -1;
    ...
        drain_action_queue();
        restart_processes();
        if (process_needs_restart) {
            timeout = (process_needs_restart - gettime()) * 1000;
            if (timeout 
  
重要的数据结构
两个列表,一个队列。
static list_declare(service_list);
static list_declare(action_list);
static list_declare(action_queue);
*.rc 脚本中所有 service关键字定义的服务将会添加到 service_list 列表中。
*.rc 脚本中所有 on     关键开头的项将会被会添加到 action_list 列表中。
每个action列表项都有一个列表,此列表用来保存该段落下的 Commands
脚本解析过程
parse_config_file("/init.rc")
int parse_config_file(const char *fn){
    char *data;
    data = read_file(fn, 0);
    if (!data) return -1;
    parse_config(fn, data);
    DUMP();
    return 0;
}
static void parse_config(const char *fn, char *s){
    ...
    case T_NEWLINE:
        if (nargs) {
            int kw = lookup_keyword(args[0]);
            if (kw_is(kw, SECTION)) {
                state.parse_line(&state, 0, 0);
                parse_new_section(&state, kw, nargs, args);
            } else {
                state.parse_line(&state, nargs, args);
            }
            nargs = 0;
        }
   ...

parse_config会逐行对脚本进行解析,如果关键字类型为  SECTION ,那么将会执行 parse_new_section()
类型为 SECTION 的关键字有: on 和 sevice
关键字类型定义在 Parser.c (system\core\init) 文件中
Parser.c (system\core\init)
#define SECTION 0x01
#define COMMAND 0x02
#define OPTION  0x04
关键字        属性      
capability,  OPTION,  0, 0)
class,       OPTION,  0, 0)
class_start, COMMAND, 1, do_class_start)
class_stop,  COMMAND, 1, do_class_stop)
console,     OPTION,  0, 0)
critical,    OPTION,  0, 0)
disabled,    OPTION,  0, 0)
domainname,  COMMAND, 1, do_domainname)
exec,        COMMAND, 1, do_exec)
export,      COMMAND, 2, do_export)
group,       OPTION,  0, 0)
hostname,    COMMAND, 1, do_hostname)
ifup,        COMMAND, 1, do_ifup)
insmod,      COMMAND, 1, do_insmod)
import,      COMMAND, 1, do_import)
keycodes,    OPTION,  0, 0)
mkdir,       COMMAND, 1, do_mkdir)
mount,       COMMAND, 3, do_mount)
on,          SECTION, 0, 0)
oneshot,     OPTION,  0, 0)
onrestart,   OPTION,  0, 0)
restart,     COMMAND, 1, do_restart)
service,     SECTION, 0, 0)
setenv,      OPTION,  2, 0)
setkey,      COMMAND, 0, do_setkey)
setprop,     COMMAND, 2, do_setprop)
setrlimit,   COMMAND, 3, do_setrlimit)
socket,      OPTION,  0, 0)
start,       COMMAND, 1, do_start)
stop,        COMMAND, 1, do_stop)
trigger,     COMMAND, 1, do_trigger)
symlink,     COMMAND, 1, do_symlink)
sysclktz,    COMMAND, 1, do_sysclktz)
user,        OPTION,  0, 0)
write,       COMMAND, 2, do_write)
chown,       COMMAND, 2, do_chown)
chmod,       COMMAND, 2, do_chmod)
loglevel,    COMMAND, 1, do_loglevel)
device,      COMMAND, 4, do_device)
parse_new_section()中再分别对 service 或者 on 关键字开头的内容进行解析。
    ...
    case K_service:
        state->context = parse_service(state, nargs, args);
        if (state->context) {
            state->parse_line = parse_line_service;
            return;
        }
        break;
    case K_on:
        state->context = parse_action(state, nargs, args);
        if (state->context) {
            state->parse_line = parse_line_action;
            return;
        }
        break;
    }
    ...
对 on 关键字开头的内容进行解析
static void *parse_action(struct parse_state *state, int nargs, char **args)
{
    ...
    act = calloc(1, sizeof(*act));
    act->name = args[1];
    list_init(&act->commands);
    list_add_tail(&action_list, &act->alist);
    ...
}
对 service 关键字开头的内容进行解析
static void *parse_service(struct parse_state *state, int nargs, char **args)
{
    struct service *svc;
    if (nargs name = args[1];
    svc->classname = "default";
    memcpy(svc->args, args + 2, sizeof(char*) * nargs);
    svc->args[nargs] = 0;
    svc->nargs = nargs;
    svc->onrestart.name = "onrestart";
    list_init(&svc->onrestart.commands);
    //添加该服务到 service_list 列表
    list_add_tail(&service_list, &svc->slist);
    return svc;
}
服务的表现形式:
service   [  ]*
...
申请一个service结构体,然后挂接到service_list链表上,name 为服务的名称 pathname 为执行的命令 argument
为命令的参数。之后的 option 用来控制这个service结构体的属性,parse_line_service 会对 service关键字后的
内容进行解析并填充到 service 结构中 ,当遇到下一个service或者on关键字的时候此service选项解析结束。
例如:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    socket zygote stream 666
    onrestart write /sys/android_power/request_state wake
服务名称为:                           zygote
启动该服务执行的命令:                 /system/bin/app_process
命令的参数:                           -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666: 创建一个名为:/dev/socket/zygote 的 socket ,类型为:stream
当*.rc 文件解析完成以后:
action_list 列表项目如下:
on init
on boot
on property:ro.kernel.qemu=1
on property:persist.service.adb.enable=1
on property:persist.service.adb.enable=0
init.marvell.rc 文件
on early-init
on init
on early-boot
on boot
service_list 列表中的项有:
service console
service adbd
service servicemanager
service mountd
service debuggerd
service ril-daemon
service zygote
service media
service bootsound
service dbus
service hcid
service hfag
service hsag
service installd
service flash_recovery
设备初始化
early-init 初始化
初始化属性服务器
在init.c 的main函数中启动状态服务器。
property_set_fd = start_property_service();
状态读取函数:
Property_service.c (system\core\init)
const char* property_get(const char *name)
Properties.c (system\core\libcutils)
int property_get(const char *key, char *value, const char *default_value)
状态设置函数:
Property_service.c (system\core\init)
int property_set(const char *name, const char *value)
Properties.c (system\core\libcutils)
int property_set(const char *key, const char *value)
在终端模式下我们可以通过执行命令 setprop  
setprop 工具源代码所在文件: Setprop.c (system\core\toolbox)
Getprop.c (system\core\toolbox):        property_get(argv[1], value, default_value);
Property_service.c (system\core\init)
中定义的状态读取和设置函数仅供init进程调用,
handle_property_set_fd(property_set_fd);
  property_set()   //Property_service.c (system\core\init)
    property_changed(name, value) //Init.c (system\core\init)
      queue_property_triggers(name, value)
      drain_action_queue()
只要属性一改变就会被触发,然后执行相应的命令:  
例如:
在init.rc 文件中有
on property:persist.service.adb.enable=1
  start adbd
on property:persist.service.adb.enable=0
  stop adbd
所以如果在终端下输入:
setprop property:persist.service.adb.enable 1或者0
那么将会开启或者关闭adbd 程序。
执行action_list 中的命令:
从action_list 中取出 act->name 为 early-init 的列表项,再调用 action_add_queue_tail(act)将其插入到
队列 action_queue 尾部。drain_action_queue() 从action_list队列中取出队列项 ,然后执行act->commands
列表中的所有命令。
所以从  ./system/core/init/init.c mian()函数的程序片段:
action_for_each_trigger("early-init", action_add_queue_tail);
drain_action_queue();
action_for_each_trigger("init", action_add_queue_tail);
drain_action_queue();
action_for_each_trigger("early-boot", action_add_queue_tail);
action_for_each_trigger("boot", action_add_queue_tail);
drain_action_queue();
/* run all property triggers based on current state of the properties */
queue_all_property_triggers();
drain_action_queue();
可以看出,在解析完init.rc init.marvell.rc 文件后,action 命令执行顺序为:
执行act->name 为 early-init,act->commands列表中的所有命令
执行act->name 为 init,            act->commands列表中的所有命令
执行act->name 为 early-boot,act->commands列表中的所有命令
执行act->name 为 boot,            act->commands列表中的所有命令
关键的几个命令:
class_start default   启动所有service 关键字定义的服务。
class_start 在act->name为boot的 act->commands列表中,所以当 class_start 被触发后,实际
上调用的是函数 do_class_start()
int do_class_start(int nargs, char **args)
{
        /* Starting a class does not start services
         * which are explicitly disabled.  They must
         * be started individually.
         */
    service_for_each_class(args[1], service_start_if_not_disabled);
    return 0;
}
void service_for_each_class(const char *classname,
                            void (*func)(struct service *svc)){
    struct listnode *node;
    struct service *svc;
    list_for_each(node, &service_list) {
        svc = node_to_item(node, struct service, slist);
        if (!strcmp(svc->classname, classname)) {
            func(svc);
        }
    }
}
因为在调用 parse_service() 添加服务列表的时候,所有服务 svc->classname 默认取值:"default",
所以 service_list 中的所有服务将会被执行。
参考文档:
http://blog.chinaunix.net/u1/38994/showart_1775465.html
http://blog.chinaunix.net/u1/38994/showart_1168440.html

浅析kernel启动的第1个用户进程init如何解读init.rc脚本
http://blog.chinaunix.net/u1/38994/showart_1168440.html

Zygote 服务概论:
Zygote 是android 系统中最重要的一个服务,它将一步一步完成下面的任务:
start Android Java Runtime and start system server. It’s the most important service. The source is in device/servers/app.
1. 创建JAVA 虚拟机
2. 为JAVA 虚拟机注册android 本地函数
3. 调用 com.android.internal.os.ZygoteInit 类中的main函数,android/com/android/internal/os/ZygoteInit.java.
a) 装载ZygoteInit类
b) 注册zygote socket
c) 装载preload classes(the default file is device/java/android/preloaded-classes)
d) 装载Load preload 资源
e) 调用 Zygote::forkSystemServer (定义在./dalvik/vm/InternalNative.c)来fork一个新的进程,在新进程中调用
com.android.server.SystemServer 的main函数。
a) 装载 libandroid_servers.so库
bb) 调用JNI native init1 函数 (device/libs/android_servers/com_android_server_SystemServers)
Load libandroid_servers.so
Call JNI native init1 function implemented in device/libs/android_servers/com_android_server_SystemServers.
It only calls system_init implemented in device/servers/system/library/system_init.cpp.
If running on simulator, instantiate AudioFlinger, MediaPlayerService and CameraService here.
Call init2 function in JAVA class named com.android.server.SystemServer, whose source is in
device/java/services/com/android/server. This function is very critical for Android because it start all of
Android JAVA services.
If not running on simulator, call IPCThreadState::self()->joinThreadPool() to enter into service dispatcher.
SystemServer::init2 将会启动一个新的线程来启动下面的所有JAVA服务:
Core 服务:
1.  Starting Power Manager(电源管理)
2.  Creating Activity Manager(活动服务)
3.  Starting Telephony Registry(电话注册服务)
4.  Starting Package Manager(包管理器)
5.  Set Activity Manager Service as System Process
6.  Starting Context Manager
7.  Starting System Context Providers
8.  Starting Battery Service(电池服务)
9.  Starting Alarm Manager(闹钟服务)
10. Starting Sensor Service
11. Starting Window Manager(启动窗口管理器)
12. Starting Bluetooth Service(蓝牙服务)
13. Starting Mount Service
其他services:
1.  Starting Status Bar Service(状态服务)
2.  Starting Hardware Service(硬件服务)
3.  Starting NetStat Service(网络状态服务)
4.  Starting Connectivity Service
5.  Starting Notification Manager
6.  Starting DeviceStorageMonitor Service
7.  Starting Location Manager
8.  Starting Search Service(查询服务)
9.  Starting Clipboard Service
10. Starting Checkin Service
11. Starting Wallpaper Service
12. Starting Audio Service
13. Starting HeadsetObserver
14. Starting AdbSettingsObserver
最后SystemServer::init2 将会调用 ActivityManagerService.systemReady 通过发送Intent.CATEGORY_HOME intent来启动第一个 activity.还有另外一种启动system server的方法是:通过名为 system_server的程序(源代码:device/servers/system/system_main.cpp)它也是通过调用 system_init 来启动 system services,这时候就有个问题:为什么android 有两种方式启动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.
Zygote服务启动的详细过程:
通过启动服务列表的 app_process 进程,实际上进入的是
App_main.cpp (frameworks\base\cmds\app_process)
main()
根据 init.rc 中的 --zygote --start-system-server
分别调用的是
runtime.start("com.android.internal.os.ZygoteInit",startSystemServer);
或者
runtime.start();
start()函数在 AndroidRuntime.cpp (frameworks\base\core\jni)文件中
从打印信息:
D/AndroidRuntime(   56): >>>>>>>>>>>>>> AndroidRuntime START GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
  从上面的调用可以看出一类引用的过程都是从 main方法
所以接着调用了 ZygoteInit 类的main方法
main方法主要完成:
1.Register zygote socket, Registers a server socket for zygote command connections
2.Load preload classes(the default file is device/java/android/preloaded-classes).
3.Load preload resources, Load in commonly used resources, so they can be shared across processes.
4.Start SystemServer, Prepare the arguments and fork for the system server process.
具体执行过程如下:
ZygoteInit.java (frameworks\base\core\java\com\android\internal\os)中的mian
main()
  registerZygoteSocket()
  preloadClasses()
    loadLibrary()
      Log.i(TAG, "Preloading classes...");
    Runtime.loadLibrary
      Dalvik_java_lang_Runtime_nativeLoad()
        dvmLoadNativeCode()
          LOGD("Trying to load lib %s %p\n", pathName, classLoader);
          System.loadLibrary("media_jni");
  preloadResources();
  startSystemServer()
    Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids, debugFlags, null);
    //Zygote.java (dalvik\libcore\dalvik\src\main\java\dalvik\system)
      forkSystemServer()
        forkAndSpecialize()   //Zygote.java (dalvik\libcore\dalvik\src\main\java\dalvik\system)
          Dalvik_dalvik_system_Zygote_forkAndSpecialize() //dalvik_system_Zygote.c (dalvik\vm\native)
            Dalvik_dalvik_system_Zygote_forkAndSpecialize()
              setSignalHandler()
              fork()
      handleSystemServerProcess() //handleChildProc(parsedArgs, descriptors, newStderr);
        closeServerSocket();
      RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
        zygoteInit()         //RuntimeInit.java (frameworks\base\core\java\com\android\internal\os)
          zygoteInitNative()
            invokeStaticMain()
              System.loadLibrary("android_servers");
              //com.android.server.SystemServer startSystemServer() 函数中
              m = cl.getMethod("main", new Class[] { String[].class });
                //执行的是SystemServer 类的main函数 SystemServer.java (frameworks\base\services\java\com\android\server)
                init1() //SystemServer.java (frameworks\base\services\java\com\android\server)            
                  //init1()实际上是调用android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
                  //com_android_server_SystemServer.cpp (frameworks\base\services\jni)
                android_server_SystemServer_init1()//JNI 调用
                  system_init() //System_init.cpp (frameworks\base\cmds\system_server\library)
                    // Start the SurfaceFlinger
                    SurfaceFlinger::instantiate();
                    //Start the AudioFlinger media playback  camera service
                      AudioFlinger::instantiate();
                      MediaPlayerService::instantiate();
                      CameraService::instantiate();
                      //调用 SystemServer 类的init2
                      runtime->callStatic("com/android/server/SystemServer", "init2");
                      init2()//SystemServer.java (frameworks\base\services\java\com\android\server)
                      ServerThread()
                        run()//在run中启动电源管理,蓝牙,等核心服务以及状态,查找等其他服务
                         ((ActivityManagerService)ServiceManager.getService("activity")).setWindowManager(wm);
                         ...
                         ActivityManagerNative.getDefault().systemReady();         
  runSelectLoopMode();
    done = peers.get(index).runOnce();
      forkAndSpecialize()   //Zygote.java (dalvik\libcore\dalvik\src\main\java\dalvik\system)
        Dalvik_dalvik_system_Zygote_forkAndSpecialize() //dalvik_system_Zygote.c (dalvik\vm\native)
          forkAndSpecializeCommon()      
            setSignalHandler()
          RETURN_INT(pid);               
  closeServerSocket();
见附A
主進程runSelectLoopMode()
5.Runs the zygote process's select loop runSelectLoopMode(), Accepts new connections as they happen, and
reads commands from connections one spawn-request's worth at a time.
如果运行正常,则zygote进程会在runSelectLoopMode()中循环:
zygote 被siganl(11)终止
在  dalvik_system_Zygote.c (dalvik\vm\native)
的 static void sigchldHandler(int s) 函数中打印:              
"Process %d terminated by signal (%d)\n",
"Exit zygote because system server (%d) has terminated\n",
startSystemServer() ZygoteInit.java (frameworks\base\core\java\com\android\internal\os)
SystemServer 的mian()函数会调用
SystemServer.java (frameworks\base\services\java\com\android\server)中的 init1()函数。
init1()实际执行的是com_android_server_SystemServer.cpp (frameworks\base\services\jni)
中的 android_server_SystemServer_init1()。
android_server_SystemServer_init1()调用的是
System_init.cpp (frameworks\base\cmds\system_server\library) 中的 system_init()函数
system_init()函数定义如下:
extern "C" status_t system_init(){
    ...
    sp sm = defaultServiceManager();
    ...
    property_get("system_init.startsurfaceflinger", propBuf, "1");
    if (strcmp(propBuf, "1") == 0) {
        //读取属性服务器,开启启动 SurfaceFlinger服务
        //接着会开始显示机器人图标
        //BootAnimation.cpp (frameworks\base\libs\surfaceflinger):status_t BootAnimation::readyToRun()
        SurfaceFlinger::instantiate();
    }
    //在模拟器上 audioflinger 等几个服务与设备上的启动过程不一样,所以
    //我们在这里启动他们。
    if (!proc->supportsProcesses()) {
        //启动 AudioFlinger,media playback service,camera service服务
        AudioFlinger::instantiate();
        MediaPlayerService::instantiate();
        CameraService::instantiate();
    }
    //现在开始运行 the Android runtime ,我们这样做的目的是因为必须在 core system services
    //起来以后才能 Android runtime initialization,其他服务在调用他们自己的main()时,都会
    //调用 Android runtime
    //before calling the init function.
    LOGI("System server: starting Android runtime.\n");
    AndroidRuntime* runtime = AndroidRuntime::getRuntime();
    LOGI("System server: starting Android services.\n");
    //调用 SystemServer.java (frameworks\base\services\java\com\android\server)
    //中的init2函数
    runtime->callStatic("com/android/server/SystemServer", "init2");
      
    // If running in our own process, just go into the thread
    // pool.  Otherwise, call the initialization finished
    // func to let this process continue its initilization.
    if (proc->supportsProcesses()) {
        LOGI("System server: entering thread pool.\n");
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
        LOGI("System server: exiting thread pool.\n");
    }
    return NO_ERROR;
}
System server: entering thread pool 表明已经进入服务线程 ServerThread在 ServerThread 类的run 服务中开启核心服务:
    @Override
    public void run() {
        EventLog.writeEvent(LOG_BOOT_PROGRESS_SYSTEM_RUN,
            SystemClock.uptimeMillis());
        ActivityManagerService.prepareTraceFile(false);     // create dir
        Looper.prepare();
    //设置线程的优先级
        android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);
    ...
        //关键(核心)服务
        try {
            Log.i(TAG, "Starting Power Manager.");
            Log.i(TAG, "Starting activity Manager.");
            Log.i(TAG, "Starting telephony registry");
            Log.i(TAG, "Starting Package Manager.");
            Log.i(TAG, "tarting Content Manager.");
            Log.i(TAG, "Starting System Content Providers.");
            Log.i(TAG, "Starting Battery Service.");
            Log.i(TAG, "Starting Alarm Manager.");
            Log.i(TAG, "Starting Sensor Service.");
            Log.i(TAG, "Starting Window Manager.");
            Log.i(TAG, "Starting Bluetooth Service.");
            //如果是模拟器,那么跳过蓝牙服务。
            // Skip Bluetooth if we have an emulator kernel
         //其他的服务
            Log.i(TAG, "Starting Status Bar Service.");
            Log.i(TAG, "Starting Clipboard Service.");
            Log.i(TAG, "Starting Input Method Service.");
            Log.i(TAG, "Starting Hardware Service.");
            Log.i(TAG, "Starting NetStat Service.");
            Log.i(TAG, "Starting Connectivity Service.");
            Log.i(TAG, "Starting Notification Manager.");
            // MountService must start after NotificationManagerService
            Log.i(TAG, "Starting Mount Service.");
        Log.i(TAG, "Starting DeviceStorageMonitor service");
            Log.i(TAG, "Starting Location Manager.");
            Log.i(TAG, "Starting Search Service.");
            ...
            if (INCLUDE_DEMO) {
                Log.i(TAG, "Installing demo data...");
                (new DemoThread(context)).start();
            }
            try {
                Log.i(TAG, "Starting Checkin Service.");
                Intent intent = new Intent().setComponent(new ComponentName(
                        "com.google.android.server.checkin",
                        "com.google.android.server.checkin.CheckinService"));
                if (context.startService(intent) == null) {
                    Log.w(TAG, "Using fallback Checkin Service.");
                    ServiceManager.addService("checkin", new FallbackCheckinService(context));
                }
            } catch (Throwable e) {
                Log.e(TAG, "Failure starting Checkin Service", e);
            }
            Log.i(TAG, "Starting Wallpaper Service");
        Log.i(TAG, "Starting Audio Service");
            Log.i(TAG, "Starting HeadsetObserver");
            Log.i(TAG, "Starting AppWidget Service");
        ...
            try {
                com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);
            } catch (Throwable e) {
                Log.e(TAG, "Failure installing status bar icons", e);
            }
        }
        // make sure the ADB_ENABLED setting value matches the secure property value
        Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED,
                "1".equals(SystemProperties.get("persist.service.adb.enable")) ? 1 : 0);
        // register observer to listen for settings changes
        mContentResolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
                false, new AdbSettingsObserver());
        // It is now time to start up the app processes...
        boolean safeMode = wm.detectSafeMode();
        if (statusBar != null) {
            statusBar.systemReady();
        }
        if (imm != null) {
            imm.systemReady();
        }
        wm.systemReady();
        power.systemReady();
        try {
            pm.systemReady();
        } catch (RemoteException e) {
        }
        if (appWidget != null) {
            appWidget.systemReady(safeMode);
        }
        // After making the following code, third party code may be running...
        try {
            ActivityManagerNative.getDefault().systemReady();
        } catch (RemoteException e) {
        }
        Watchdog.getInstance().start();
        Looper.loop();
        Log.d(TAG, "System ServerThread is exiting!");
    }
startActivity()
  mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);

ActivityManagerService.java 3136p (frameworks\base\services\java\com\android\server\am)
  startActivity()
    startActivityLocked() //3184
    int res = startActivityLocked(caller, intent, resolvedType,grantedUriPermissions, grantedMode, aInfo,
                    resultTo, resultWho, requestCode, -1, -1,
                    onlyIfNeeded, componentSpecified);
public abstract class ActivityManagerNative extends Binder implements IActivityManager
ActivityManagerService.java 1071p  (frameworks\base\services\java\com\android\server\am)
ActivityManagerService.main()
  //ActivityManagerService.java 7375p (frameworks\base\services\java\com\android\server\am)
  m.startRunning(null, null, null, null);
    //ActivityManagerService.java 7421p (frameworks\base\services\java\com\android\server\am)
    systemReady();
ActivityManagerService.java 3136p (frameworks\base\services\java\com\android\server\am)
  startActivity(IApplicationThread caller,Intent intent,...)
    int startActivityLocked(caller, intent,...)    //3184L 定义:2691L
      void startActivityLocked()       //3132L 定义:2445L
        resumeTopActivityLocked(null); //2562p 定义:2176L
        if(next=NULL)
        {
          intent.addCategory(Intent.CATEGORY_HOME);
          startActivityLocked(null, intent, null, null, 0, aInfo,null, null, 0, 0, 0, false, false);
        }
        else
        {
          startSpecificActivityLocked(next, true, false); //2439L 定义:1628L
            realStartActivityLocked() //1640L    定义:1524L
            //1651L 定义:1654L
            startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity", r.intent.getComponent());
              //1717L 定义:1721L
              startProcessLocked(app, hostingType, hostingNameStr);
                //1768L  定义:Process.java 222L(frameworks\base\core\java\android\os)
                int pid = Process.start("android.app.ActivityThread",...)
                  startViaZygote(processClass, niceName, uid, gid, gids,debugFlags, zygoteArgs);
                    pid = zygoteSendArgsAndGetPid(argsForZygote);
                      sZygoteWriter.write(Integer.toString(args.size()));
        }

  runSelectLoopMode();
    done = peers.get(index).runOnce();
      forkAndSpecialize()   //Zygote.java (dalvik\libcore\dalvik\src\main\java\dalvik\system)
        Dalvik_dalvik_system_Zygote_forkAndSpecialize() //dalvik_system_Zygote.c (dalvik\vm\native)
          forkAndSpecializeCommon()      
            setSignalHandler()
          RETURN_INT(pid);
           
       ActivityThread main()
         ActivityThread attach() //ActivityThread.java 3870p (frameworks\base\core\java\android\app)     
           mgr.attachApplication(mAppThread)
           //ActivityManagerService.java 4677p (frameworks\base\services\java\com\android\server\am)
           attachApplication()
             //ActivityManagerService.java 4677p (frameworks\base\services\java\com\android\server\am)
             attachApplicationLocked()
               if (realStartActivityLocked(hr, app, true, true)) //ActivityManagerService.java 4609p
                                                                   //(frameworks\base\services\java\com\android\server\am)
               realStartActivityLocked()
                 //ActivityManagerService.java (frameworks\base\services\java\com\android\server\am)
                 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,r.info, r.icicle, results, newIntents, \
                    !andResume,isNextTransitionForward());
                 scheduleLaunchActivity()
                   queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
                     ActivityThread.H.handleMessage()
                       handleLaunchActivity()    //ActivityThread.java (frameworks\base\core\java\android\app)
                         performLaunchActivity() //ActivityThread.java (frameworks\base\core\java\android\app)
                           activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
     
            
/////////////////////////////////////////////////      
init 守护进程:
//andriod init 函数启动过程分析:
在main循环中会重复调用
drain_action_queue();
restart_processes();
static void restart_processes()
{
    process_needs_restart = 0;
    service_for_each_flags(SVC_RESTARTING,
                           restart_service_if_needed);
}
通过循环检测服务列表service_list 中每个服务的 svc->flags 标记,如果为 SVC_RESTARTING,
那么在满足条件的情况下调用:restart_service_if_needed
通过 service_start 来再次启动该服务。
ActivityManagerService.main
I/SystemServer(   45): Starting Power Manager.
I/ServiceManager(   26): service 'SurfaceFlinger' died
D/Zygote  (   30): Process 45 terminated by signal (11)
I/Zygote  (   30): Exit zygote because system server (45) has terminated
通过错误信息发现程序在调用 SurfaceFlinger服务的时候被中止。
Service_manager.c (frameworks\base\cmds\servicemanager):
LOGI("service '%s' died\n", str8(si->name));
Binder.c (frameworks\base\cmds\servicemanager):
death->func(bs, death->ptr);
Binder.c (kernel\drivers\misc)中的函数
binder_thread_read()
struct binder_work *w;
switch (w->type)
为 BINDER_WORK_DEAD_BINDER 的时候binder_parse()中
当 cmd 为 BR_DEAD_BINDER的时候
执行 death->func(bs, death->ptr)
因为函数
int do_add_service(struct binder_state *bs,
                   uint16_t *s, unsigned len,
                   void *ptr, unsigned uid)
的 si->death.func = svcinfo_death;

所以 death->func(bs, death->ptr) 实际上执行的是
svcinfo_death()//Service_manager.c (frameworks\base\cmds\servicemanager)

================================================
=================================================
 linux下svn使用指南

服务器端配置说明
ubuntu-8.10 svn服务器安装
sudo apt-get install subversion

建立版本库(Repository)
运行Subversion服务器需要首先要建立一个版本库(Repository),可以看作服务器上存放数据的数据库,在安装了Subversion服务器之后,可以直接运行
cd path_to_svn_root  例如:/home/svn
svnadmin create --fs-type=fsfs  smartphone
--fs-type 指定仓库类型,可以为fsfs或bdb 如果没有指定默认创建为fsfs类型  smartphone为仓库名称

配置用户和权限
修改 path_to_svn_repos/conf/svnserve.conf 文件,打开下面配置项
---------------------------
#anon-access = read
anon-access = none
auth-access = write
password-db = passwd
authz-db = authz
anon-access 应设置等于 none ,否则没有log信息
修改  path_to_svn_repos/conf/passwd 文件,添加用户和密码
----------------------------
[users]
wanghui=wanghui

导入工程到仓库中
svn import  smartphone/  svn://192.168.2.148/smartphone

运行svn服务器
svnserve -d -r  path_to_svn_root  例如:/home/svn

客户端操作指南及使用规范
以我们服务器上 android 源代码为例,介绍svn常用操作。
检出工作拷贝
检出工作拷贝到 ~/svn/cupcake-jiangping
使用svn co url
cd ~/svn
svn co svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping  cupcake-jianping
svn update 更新别人做的更改
svn update 获取最新版本
svn update cupcake-jiangping
或者进入目录更新
cd cupcake-jiangping
svn update
如果负责的应用与系统的关联性不是很大,通常不建议频繁进行更新。
svn update  -r 获取特定的版本
直接在某目录下执行 svn update 获取当前目录下所有文件的最新版本,如果我们只需要获取某个文件或者目录的特定版本,可以通过-r 和 名称进行指定:
svn update –r 5  cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java
svn st 查看文件状态信息
M  cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java
?  cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
M  表明文件已经有修改     ? 表明文件没有受版本控制
svn log 查看log信息
svn log -r        查看所有版本的log信息
svn log -r 5      查看某一版本的log信息
svn log -r 5:19   查看某区间一系列版本的log信息
如果要查看log的详细信息可以加上 –v 选项,如:
svn log –v -r 5
svn diff 查看文件修改详情
显示单个文件或者某目录下所有文件的修改详情
svn diff有三种不同的用法
1. 检查本地修改
2. 比较工作拷贝与版本库
3. 比较版本库与版本库
不使用任何参数调用时,svn diff将会比较你的工作文件与缓存在.svn的“原始”拷贝,如:
svn diff cupcake-jianping/packages/apps/Phone
svn diff cupcake-jianping/packages/apps/Phone/src/com/android/phone/zzzz.java
如果传递一个—revision –r 参数,你的工作拷贝会与指定的版本比较。
svn diff -r 3 cupcake-jianping/packages/apps/Phone
如果通过--revision –r 传递两个通过冒号分开的版本号,这两个版本会进行比较。
svn diff -r 2:3 cupcake-jianping/packages/apps/Phone
如果你在本机没有工作拷贝,还是可以比较版本库的修订版本,只需要在命令行中输入合适的URL:
svn diff -r 33 svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping/packages/apps/Phone
svn list 显示版本库的文件列表
svn list svn://192.168.2.148/smartphone/td0901
design/
hedoc/
pm/
release/
tag/
trunk/
svn list svn://192.168.2.148/smartphone/td0901/trunk
3src/
boot-a1/
cupcake-jianping/
linux-2.6.28-a1/
svn list 类似本机的ls命令,它查看的是服务器端的目录结构。
svn info 查看版本库信息
cd ~/svn/cupcake-jianping
svn infos
路径: .
URL: svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping
版本库根: svn://192.168.2.148/smartphone
版本库 UUID: 1fac82c5-1665-442c-a8d6-2b3dd850438a
版本: 146
节点种类: 目录
调度: 正常
最后修改的作者: tangligang
最后修改的版本: 145
最后修改的时间: 2009-07-31 15:40:50 +0800 (五, 2009-07-31)
svn add 增加目录或者文件
svn add cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx
svn add cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
svn delete 删除目录或者文件
svn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx
svn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
在进行删除操作的时候要非常小心,假设我们要添加一个文件:
cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
但是在提交之前我们发现并不需要这个文件,这时候我们经常通过 svn delete 来撤销之前添加的文件:
svn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
这样操作的后果往往导致本地的文件yyyy.java 被误删除掉,所以我们正确的做法是:
svnn delete cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java –keep-local

svn revert 取消本地修改
1.当你发现对某个文件的所有修改都是错误的,或许你根本不应该修改这个文件,或者是从开头重新修改会更加容易的时候可以用这个命令。
2.通过svn add 添加了一个项目,如果想取消可以通过该命令。
svn commit 提交本地做的更改
通常只对自己负责的模块进行提交,如果负责电话模块,那么提交命令如下:
svn commit cupcake-jiangping/packages/apps/Phone
在提交之前建议用命令:
svn st cupcake-jiangping/packages/apps/Phone 查看状态
M cupcake-jianping/packages/apps/Phone/src/com/android/phone/xxxx.java
?  cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java
M  表明文件已经有修改
? 表明文件没有受版本控制
1. 如果有 “?”存在,并且该文件或者目录是自己添加并且是工程的一部分,那么在提交之前必须先执行svn add 操作:svn add cupcake-jianping/packages/apps/Phone/src/com/android/phone/yyyy.java ;
2. 提交之前也必须解决冲突,否则会提交失败。
3. 提交之前必须写log

文件更新,提交时的冲突处理
$ svn update
U  xxxx
G  yyyy
C  xxxx.c
1. 更新的时候如果前面的状态为:C 表示有冲突存在。
2. 工作拷贝里做过修改,且服务器版本库在修改前工作拷贝的版本后被提交过其他修改;那么svn commit首先会失败并要求update,此时便会出现版本冲突的情况。
当你Update出现了冲突时,Subversion会产生三个文件
filename.mine   :  你更新前的文件,没有冲突标志,只是你最新更改的内容。
Filename.roldrev:  就是你在上次更新之后未作更改的版本。
Filename.rnewrev:  客户端从服务器刚刚收到的版本,这个文件对应版本库的HEAD版本。
冲突的文件内容,在冲突的地方将被使用“>>>>”标志出来,用户自己进行合并的取舍。
解决冲突之后,svn resolved path_to_name,Subversion删除冲突所产生三个文件删除,此时你才可以进行提交。( 也可以手动删除此三个文件。)

打标签
svn 的标签是通过copy命令完成,但是操作的路径必须是服务器的路径,打标签实际上类似于创建一个到特定版本的链接,如:
svn cp svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping  \
svn://192.168.2.148/smartphone/td0901/tags/cupcake-1.0.6
如果 svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping 的当前版本为 5 ,\
那么 svn://192.168.2.148/smartphone/td0901/tags/cupcake-1.0.6 实际 \
上就是 svn://192.168.2.148/smartphone/td0901/trunk/cupcake-jianping 版本5的一个标签。
 

清除缓存的认证信息,重新输入用户名和密码
一个具有权限控制的 svn 版本库在第一次 checkout 工作拷贝的时候会要求输入用户名和密码:
认证领域:  176512f1-51ee-4947-8c07-88c90ab77ac5
“$USER”的密码:
认证领域:  d3216b51-7915-4881-bf30-02e0672c61cd
用户名: xxxxx
“xxxxx”的密码:
这些信息被缓存在 ~/.subversion/auth/svn.simple/ 如果需要更换另一个用户登录,必须先清除缓存的认证信息:
rm ~/.subversion/auth/svn.simple/* -rf

 


为规避风险,建议遵守以下规范
提交前审查修改情况, 用命令svn status浏览所做的修改,svn diff检查修改的详细信息
提交时,必须填写注释,注释内容清晰描述本次提交内容,变动信息。
做较大修改时,和项目组其他同事的工作相关时,必须通知对方。
纳入版本控制的项目必须定期提交,至少一周提交一次,避免意外事故导致代码丢失。
每次提交后,必须确认工程可正常运行,即SVN里保存的是可以正确运行的代码,否则恢复至稳定版本。
编译过程动态产生的东西不要提交到服务器
每次提交前先更新,这样能在提交前发现是否和别人的冲突
filelist=`find ./ -name "*.conf"`;svn add $filelist; svn commit  $filelist
filelist=`find ./ -name "*.conf"`;svn delete $filelist --force --keep-local
=================================================
================================================
LFS 相关
 LFS──Linux from Scratch,就是一种从网上直接下载源码,从头编译LINUX的安装方式。它不是发行版,只是一个菜谱,告诉你到哪里去买菜(下载源码),怎么把这些生东西( raw code) 作成符合自己口味的菜肴──个性化的linux,不单单是个性的桌面。
LFS 有什么优势呢?现在看来,它可以提供最快和最小的 Linux。但是最大的优势就是,安装LFS是菜鸟变成高手的捷径。
第一次安装,需要按照LFS文档安装,如果在此期间所有文档内容你都认真的阅读,保证你受益匪浅;然后发现很多地方可以不按照别人的老路操作,这个时候用自己的方式参考第一次安装的经验,再一次建立linux,完成的时候,你会发现你在 LinuxSir.Org 上已经再也不是菜鸟了。

lfs 相关资源
官方网站:
http://www.linuxfromscratch.org/
lfs中文网站
http://lfs.linuxsir.org/main/
Linux From Scratch版本 6.2
http://lamp.linux.gov.cn/Linux/LFS-6.2/index.html
Linux From Scratch 版本 6.4
http://www.bitctp.org/lfsbook-6.4/index.html
Linux 发行版 LFS 讨论区
http://www.linuxsir.org/bbs/forumdisplay.php?f=58

LFS问题解答

构建LFS的过程中遇到一些问题,总体来说还算顺利,但是还有一些不明白的地方,这里总结一下:

1./etc/fstab是否在开机就执行,是被谁调用执行的。

2.为什么系统启动之后就要自动挂載/proc 和/sys,这两个目录有什么作用;devpts和tmpfs有什么作用。
参考章节:文件系统概述

3.关于文件系统:按照我的理解,文件系统是内核提供支持的,可以看作是一种协议,提供一种数据组织方式,每个设备必须有自己的文件系统。
不同文件系统的存储设备的数据组织形式不同。mke2fs -jv /dev/默认在上面创建EXT3的文件系统吗?既然这样的话为什么我们还需要把以ext3挂载到一个目录呢?如果不是的话,又是创建什么文件系统呢?为什么第六章中挂载了虚拟内核文件系统之后才能进入chroot环境呢?
参考章节:文件系统概述

4.虚拟文件系统.作用.什么?
虚拟内核文件系统(Virtual Kernel File Systems),是指那些是由内核产生但并不存在于硬盘上(存在于内存中)的文件系统,他们被用来与内核进行通信。

5.符号链接和硬链接的区别是什么?什么是符号链接?什么是硬链接?为什么liinux上都使用符号链接,而不是硬链接?

linux上很多地方使用了链接,是为了组织清晰系统的结构和节省空间吗?硬连接和软连接的区别, 硬连接和复制的区别?硬连接记录的是目标的 inode;软连接记录的是目标的 path。hard link 由于 inode 的缘故,只能在本分区中做 link;soft link 可以做跨分区的 link。硬连接因为记录的是 inode,所以不怕改名,比如ln aaa bbb, mv aaa ccc, 这时 bbb 仍然可以访问;soft-link 就不行:source 的名字改变后,所有链接到这里的 soft-link 全部变为 broken。事实上,即使所有指向该 inode 的 hard-link 的文件名都变了,每一个仍然都可以访问。我想这是它最大的优点吧。
硬连接和复制的区别:几个硬连接=几个名字的同一个房子,这些名字可以相同或不同但地址(i-node)是一样的, 所以硬连接被删除只是把相应名字抹去,只有最后一个名字被抹去你才会找不到房子;而复制是建造一个一模一样的房子,当然地址(i-node)就不同的了。

6.工作平台中由Glibc提供的动态连接器与Binutils里面的标准连接器有什么区别?
参考章节: 链接器和加载器

7.$LFS/tools 目录的所有者是仅存在于宿主环境中的 lfs 用户。如果保留 $LFS/tools 目录,那么该目录内文件的所有者的 user ID 就没有对应的账号 ?为什么没有帐户,难道不是LFS?
查看 /etc/password /etc/group  两个文件 分别记录 用户和组的信息
如果用户名和用户ID 组名和组ID 的对应关系分别存在上面两个文件中,那么ls -ls 的时候就可以查看到用户信息,而不再是ID等数字信息

8.系统的环境变量保存在哪个文件?
保存在tty中

9。配置参数脚本时[alias1] [alias2 ...]什么时候用到?
别名的意思
alias ls='ls --color=auto'
/etc/skel/.bashrc:81:    #alias dir='dir --color=auto'
/etc/skel/.bashrc:82:    #alias vdir='vdir --color=auto'
/etc/skel/.bashrc:84:    #alias grep='grep --color=auto'
/etc/skel/.bashrc:85:    #alias fgrep='fgrep --color=auto'
/etc/skel/.bashrc:86:    #alias egrep='egrep --color=auto'
/etc/skel/.bashrc:89:# some more ls aliases
/etc/skel/.bashrc:90:#alias ll='ls -l'
/etc/skel/.bashrc:91:#alias la='ls -A'
/etc/skel/.bashrc:92:#alias l='ls -CF'
alias mohuifu='ls -l'
========================
9. linux 内核的初步理解
编译内核
此处内核编译主要针对驱动组之外的同事
1> 设置工具链
内核的 linux-2.6.28-a1/Makefile 中设定了:
CROSS_COMPILE        ?= arm-linux-
所以设置PATH环境变量,保证能找到正确的工具链
假设工具链位于: /usr/local/marvell-arm-linux-4.1.1/ 设置为:
export PATH:=/usr/local/marvell-arm-linux-4.1.1/bin/:$PATH
2> 更改编译选项(网络启动或者本机启动)
内核顶层目录执行:
make menuconfig
General setup  --->
  

  • Initial RAM filesystem and RAM disk (initramfs/initrd) support
        ()    Initramfs source file(s) (NEW)
    如果需要支持网络启动反选  [] Initial RAM filesystem and RAM disk (initramfs/initrd) support
    如果需要支持本地启动选中  
  • Initial RAM filesystem and RAM disk (initramfs/initrd) support
    设置 ()    Initramfs source file(s) (NEW) 为 root
    拷贝  cupcake 编译结果  out/target/product/littleton/root/  到内核顶层目录
    3> 编译
    内核顶层目录执行 make zImage
    编译好的内核:
    arch/arm/boot/zImage
    initramfs与initrd
    1. initrd是一个单独的文件;initramfs和Linux内核链接在一起(/usr目录下的程序负责生成initramfs文档)。
    2. initrd是一个压缩的文件系统映像(可以是ext2等,需要内核的驱动);initramfs是类似tar的cpio压缩文档。
    内核中的cpio解压缩代码很小,而且init数据在boot后可以丢弃。
    3. initrd运行的程序(initd,不是init)进行部分setup后返回内核;initramfs执行的init程序不返回内核
    (如果/init需要向内核传递控制权,可以再次安装在/目录下一个新的root设备并且启动一个新的init程序)。
    编译脚本及系统变量
    initramfs与initrd的区别
    1. initrd是一个单独的文件;initramfs和Linux内核链接在一起(/usr目录下的程序负责生成initramfs文档)。
    2. initrd是一个压缩的文件系统映像(可以是ext2等,需要内核的驱动);initramfs是类似tar的cpio压缩文档。
    内核中的cpio解压缩代码很小,而且init数据在boot后可以丢弃。
    3. initrd运行的程序(initd,不是init)进行部分setup后返回内核;initramfs执行的init程序不返回内核
    (如果/init需要向内核传递控制权,可以再次安装在/目录下一个新的root设备并且启动一个新的init程序)。
    4. 切换到另一个root设备时,initrd执行pivot_root后,卸载ramdisk;initramfs是rootfs,既不能
    pivot_root,也不能卸载。initramfs会删掉rootfs的所有内容(find -xdev / -exec rm '{}' ';'),
    再次安装root到rootfs(cd /newmount; mount --move . /; chroot .),把stdin/sdout/stderr挂在
    新的/dev/console上,重新执行init。由于这是一个相当困难的实现过程(包括在使用一个命令之前把它删除),所以
    klibc工具包引入一个帮助程序/utils/run_init.c来执行上述过程。其他大部分工具包(包括busybox) 把这个命令
    称为"switch_root"。
  • 原创粉丝点击