Chinaunix首页 | 论坛 | 博客
  • 博客访问: 24460
  • 博文数量: 26
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 270
  • 用 户 组: 普通用户
  • 注册时间: 2014-11-27 23:29
文章分类

全部博文(26)

文章存档

2017年(9)

2016年(13)

2014年(4)

我的朋友

分类: C#/.net

2017-10-31 21:33:37

注:此次分析以6.0源码为例。

android系统是从linux改过来的,因此这里从init进程开始进行分析。

init初始化过程

让我们进入init.cpp来看看,首先看main:
/Volumes/aosp/WORKING_DIRECTORY/system/core/init/init.cpp

int main(int argc, char** argv) { // 判断是否是启动的第一阶段,根据参数来判断 bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0); if (is_first_stage) { // 如果是第一阶段 mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); // 挂载tmpfs文件系统(快速的临时文件系统,建立在内存上,不可持久) mkdir("/dev/pts", 0755);
        mkdir("/dev/socket", 0755);
        mount("devpts", "/dev/pts", "devpts", 0, NULL); // 挂载devpts文件系统 mount("proc", "/proc", "proc", 0, NULL); // 挂载proc文件系统 mount("sysfs", "/sys", "sysfs", 0, NULL); // 挂载sysfs文件系统(设备结构) }
    
    ...... if (!is_first_stage) { // Indicate that booting is in progress to background fw loaders, etc. close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));


        property_init(); // 初始化属性域 system/core/init/Property_service.cpp // If arguments are passed both on the command line and in DT, // properties set in DT always have priority over the command-line ones. process_kernel_dt();
        process_kernel_cmdline(); // Propogate the kernel variables to internal variables // used by init as well as the current required properties. export_kernel_boot_props();
    }
    
    ...... if (is_first_stage) { if (restorecon("/init") == -1) {
            ERROR("restorecon failed: %s\n", strerror(errno));
            security_failure();
        } // 重入main,进入第二阶段 char* path = argv[0]; char* args[] = { path, const_cast<char*>("--second-stage"), nullptr }; if (execv(path, args) == -1) {
            ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));
            security_failure();
        }
    }
    
    ......
    
    epoll_fd = epoll_create1(EPOLL_CLOEXEC); // 创建epoll ......
    signal_handler_init(); // 初始化子进程处理器,防止僵尸进程。这里使用信号来监控子进程退出 ......
    start_property_service(); // 启动属性服务 init_parse_config_file("/init.rc"); // 解析init.rc文件 ...... // 不断监听执行上面rc解析出来的指令 while (true) { if (!waiting_for_exec) {
            execute_one_command(); // 执行指令 restart_processes();
        } int timeout = -1; if (process_needs_restart) {
            timeout = (process_needs_restart - gettime()) * 1000; if (timeout < 0)
                timeout = 0;
        } if (!action_queue_empty() || cur_action) {
            timeout = 0;
        }

        bootchart_sample(&timeout);

        epoll_event ev; int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout)); if (nr == -1) {
            ERROR("epoll_wait failed: %s\n", strerror(errno));
        } else if (nr == 1) { www.xsjdy.org ((void (*)()) ev.data.ptr)();
        }
    }
}

整个init阶段分为2个阶段,第一阶段主要是挂载文件系统等工作,然后这里会有个重入main的动作,这次重入后开始执行第二阶段,第二阶段主要处理各种属性域,epoll,启动属性服务,防止僵尸进程等琐碎的事情。然后开始执行init.rc中配置的指令。下面看看这个rc文件:

/Volumes/aosp/WORKING_DIRECTORY/system/core/rootdir/init.rc

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

可以看到这里引用了/init.${ro.zygote}.rc,对应的是类似init.zygote64.rc这些文件:

service zygote /system/bin/app_process64 -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
    writepid /dev/cpuset/foreground/tasks

这里实际执行的是app_main.cpp的main:
/Volumes/aosp/WORKING_DIRECTORY/frameworks/base/cmds/app_process/app_main.cpp

 // 根据参数设置类名 while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg); break;
        } else {
            --i; break;
        }
    }
    ...... if (zygote) { // 这里执行到ZygoteInit类中 runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } 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;
    }

根据参数判断,新视觉影院如果是zygote则在后面执行runtime.start,给定的参数是ZygoteInit这个类。
runtime实际执行的是AndroidRuntime.cpp中的代码:
/Volumes/aosp/WORKING_DIRECTORY/frameworks/base/core/jni

void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
    ......
    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);

#if 0 if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
        ......
}

实际执行的就是env->CallStaticVoidMethod(startClass, startMeth, strArray);这句话,调用的就是ZygoteInit.java中的main。至此,从init进入到Zygote中了。

Zygote孵化器(受精卵)

zygote名字是受精卵,其实就是帮助app或其他进程启动的一个玩意儿。内部就是走的fork分裂出一个进程来。

/Volumes/aosp/WORKING_DIRECTORY/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static void main(String argv[]) { try {
        ...... for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { // 这里传递的就是这个 startSystemServer = true;
            } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                abiList = argv[i].substring(ABI_LIST_ARG.length());
            } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                socketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } else { throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }
        ......
        registerZygoteSocket(socketName); // 注册并启动socket服务端,为zygote ...... if (startSystemServer) {
            startSystemServer(abiList, socketName); // 启动systemserver }
        ......
        runSelectLoop(abiList); // 进入looper,等待启动app的请求 } // 注意这里,是个关键点。异常发生的时候调用了MethodAndArgsCaller这个runnable的run catch (MethodAndArgsCaller caller) {      
        caller.run();
    }
    
}

基本就这些了,总结一下:
1.zygote使用本地socket进行通讯,并接受请求从而进行分裂的处理;
2.启动systemserver这个大户;
3.zygote永不退出,生命周期在系统启动一直到结束,并且从runSelectLoop开始彻底成为孵化器服务进程;
4.一旦发生MethodAndArgsCaller caller异常,调用MethodAndArgsCaller的call处理,后面我们会说到这个;

按照顺序,我们首先来看看startSystemServer。

1. startSystemServer启动系统服务

SystemServer是系统的2大核心之一,和Zygote一并重要,专管所有的系统服务。需要单独开篇来阐述。这里我们只说启动的过程。

private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException { ...... // fork SystemServer进程 pid = Zygote.forkSystemServer(
        parsedArgs.uid, parsedArgs.gid,
        parsedArgs.gids,
        parsedArgs.debugFlags, null,
        parsedArgs.permittedCapabilities,
        parsedArgs.effectiveCapabilities); ...... // 如果是子进程,就是SystemServer本身,执行 if (pid == 0) { if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        } // 如果是子进程,即systemserver,调用handleSystemServerProcess进行后面的收尾工作 handleSystemServerProcess(parsedArgs);
    }  
}

好吧,我们继续看handleSystemServerProcess:

private static void handleSystemServerProcess(  ZygoteConnection.Arguments parsedArgs) www.xsjdy.org throws ZygoteInit.MethodAndArgsCaller { ......
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
......   }

其实重要的就这一句话调用。继续往下跟踪:
/Volumes/aosp/WORKING_DIRECTORY/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
    ...... // 常规初始化,设置跟踪,设置网络代理 commonInit(); // AndroidRuntime.cpp c层函数 nativeZygoteInit(); // 应用程序初始化 applicationInit(targetSdkVersion, argv, classLoader);
                
}

基本上就是上面这3个调用最重要,我们依次看下:
/Volumes/aosp/WORKING_DIRECTORY/frameworks/base/core/jni/AndroidRuntime.cpp

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz) {
    gCurRuntime->onZygoteInit();
}

看到了吧,回到了app_main.cpp AppRuntime的onZygoteInit中:

virtual void onZygoteInit()
{
    sp proc = ProcessState::self();
    ALOGV("App process: starting thread pool.\n"); // 启动线程池,用于与binder通讯。每个进程都走这一步 proc->startThreadPool();
}

这个分支到此先不往下跟踪了,和启动的过程关系不大了。
下面我们回到RuntimeInit.java看下applicationInit:

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { // 设置关闭引用程序是是否调用AppRuntime.onExit(),默认调用 nativeSetExitWithoutCleanup(true);

        ...... // 传递参数,并调用类的main方法 invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }

关键方法是invokeStaticMain,执行类的main方法,这个类在前面的startSystemServer里面有参数传递,具体是这样的:

String args[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "com.android.server.SystemServer",
        };

所以这个类就是SystemServer,调用的就是他的main方法。
下面看看invokeStaticMain内部:

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
    throws ZygoteInit.MethodAndArgsCaller {
    Class cl; // 通过反射获取类名 try {
        cl = Class.forName(className, true, classLoader);
    } catch (ClassNotFoundException ex) { throw new RuntimeException( "Missing class when invoking static main " + className,
                ex);
    } // 获取该类的main方法 Method m; try {
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) { throw new RuntimeException( "Missing static main on " + className, ex);
    } catch (SecurityException ex) { throw new RuntimeException( "Problem getting static main on " + className, ex);
    }

    int modifiers = m.getModifiers(); if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) { throw new RuntimeException( "Main method is not public and static on " + className);
    } /*
     * This throw gets caught in ZygoteInit.main(), which responds
     * by invoking the exception's run() method. This arrangement
     * clears up all the stack frames that were required in setting
     * up the process.
     */ // 抛出异常 throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

看到这里一定会奇怪,为何在此处抛出一个异常:throw new ZygoteInit.MethodAndArgsCaller(m, argv);,这里我们需要往前回溯看看,到底在哪里捕获的异常。结果是发现在ZygoteInit.java的main中进行的捕获:

try {
    ...... if (startSystemServer) {
        startSystemServer(abiList, socketName);
    }
    ......
} catch (MethodAndArgsCaller caller) {
     caller.run();
}

调用的起始也是从这里开始的,好吧,我们看看捕获到异常之后做了什么。调用了caller.run()。抛出异常的时候已经new了一个throw new ZygoteInit.MethodAndArgsCaller(m, argv);这个对象了,并且参数给出的就是SystemServer类的main方法,那么继续看ZygoteInit.MethodAndArgsCaller:

 public static class MethodAndArgsCaller extends Exception implements Runnable { /** method to call */ private final Method mMethod; /** argument array */ private final String[] mArgs; public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        } public void run() { try {
                mMethod.invoke(null, new Object[] { mArgs });
            } catch (IllegalAccessException ex) { throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable cause = ex.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause;
                } else if (cause instanceof Error) { throw (Error) cause;
                } throw new RuntimeException(ex);
            }
        }
    }

run方法就是调用了一下这个方法,也就是调用了SystemServer的main方法,直接跳到main方法执行了。但是为何这么做呢?这里有个疑问。其实仔细想想也挺有意思。这一串调用从startSystemServer开始执行了比较深了,每次执行函数方法的时候都会伴随着出现局部变量,那么就会直接开辟在栈上,之后的SystemServer又是个常驻不退出的进程,那么栈上面的这些空间也就意味着并不会释放,而启动过程只会执行一次,后面没用了,这些东西没有清理就一直存在。这里直接抛出异常后,在startSystemServer这个最初的位置捕获,会导致异常发生后直接跳到捕获的地方,之前所有的栈全部被清空。这下子明白了吧。google很聪明的利用了异常的做法回溯了栈,释放不用的内存。真是非常聪明!

阅读(383) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~