'2017/02/25'에 해당되는 글 2건

  1. 2017.02.25 [android framework] Zygote란? #1 Zygote Class 실행까지
반응형

Zygote 는 자바로 작성되는 안드로이드 어플리케이션의 실행 속도를 빠르게 하기 위해서, 

 1) 어플리케이션이 실행되기 전에 가상 머신의 코드 및 메모리 정보를 공유함으로 어플리케이션의 실행을 단축시키고

 2) 안드로이드 프레임워크에서 필요로 하는 클래스와 자원을 미리 메모리에 로딩, 연결 정보를

구성한다.

 다음의 그림은 관련 프로세스 구조도이다.


 Zygote가 실행돠면 최종적으로는 다음과 같은 모습이 된다.



 Zygote는 init.rc 에 등록된 다음의 명령에 따라서 init process에서 실행된다.

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 는 app_process에서 실행된다. 그 이유는 Zygote가 자바로 작성되어 있어서 달빅 가상 머신이 생성되어 하고 생성된 가상 머신 위에서 ZygoteInit 클래스를 로딩하고 실행하는 구조이다. 이런 역활을 해주는 것이 app_process가 된다. zygote는 다음과 같이 실행된다.


 app_process는 frameworks/base/cmds/app_process/app_main.cpp 에서 그 소스를 확인할 수 있다.

int main(int argc, char* const argv[])

{

[--------------중략--------------]


    AppRuntime runtime;
[--------------중략--------------]

    int i = runtime.addVmArguments(argc, argv);
[--------------중략--------------]

    while (i < argc) {
        const char* arg = argv[i++];
        if (!parentDir) {
            parentDir = arg;
        } else if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = "zygote";
        } 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 = arg + 12;
        } else {
            className = arg;
            break;
        }
    }
[--------------중략--------------]

    runtime.mParentDir = parentDir;

    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit",
                startSystemServer ? "start-system-server" : "");
    } else if (className) {
        // Remainder of args get passed to startup class main()
        runtime.mClassName = className;
        runtime.mArgC = argc - i;
        runtime.mArgV = argv + i;
        runtime.start("com.android.internal.os.RuntimeInit",
                application ? "application" : "tool");
    } 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;
    }
}

 AppRuntime 은 AndroidRuntime 클래스를 상속하며, AndroidRuntime은 안드로이드 어플리케이션을 동작하기 위한 달빅 가상 머신을 초기화하고 실행하는 클래스이다. 그리고 여기에 VM Argument를 전달하고 있다.

 소스에서 볼수 있는 것처럼 zygote 및 start-system-server 옵션에 따라서 app_process가 다르게 동작한다는 것을 알 수 있다. 


 app_process로 전달되는 /system/bin 은 해당 클래스가 실행되는 폴더를 지정하는 것이며, zygote 옵션이 설정되어 있으면 com.android.internal.os.ZygoteInit을 실행하고 --start-system-server가 지정되어 있을 경우 runtime 실행시 start-system-server를 옵션으로 전달한다.


 다음은 AndroidRuntime.cpp 소스 코드의 일부이다. (frameworks/base/core/jni/AndroidRuntime.cpp)

void AndroidRuntime::start(const char* className, const char* options)

{

[--------------중략--------------]


    if (startVm(&mJavaVM, &env) != 0) { //1)

        return;

    }


[--------------중략--------------]

    if (startReg(env) < 0) { //2)
        ALOGE("Unable to register all android natives\n");
        return;
    }
[--------------중략--------------]

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); //3)

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
[--------------중략--------------]
}
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
{
[property_get 으로 VM실행 환경을 가져오는 코드]

    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed\n");
        goto bail;
    }

[--------------중략--------------]
}

 1) AndroidRuntime 의 start 함수는 startVM을 호출하는데, startVM에서는 property_get 함수로 VM 실행 환경을 가져와서 JNI_CreateJavaVM 으로 가상 머신을 생성한다. 

 2) startVM이 완료되고 나면, startReg 로 가상 머신에서 호출할 JNI 환경을 등록한다. 대상 JNI 함수는 해당 소스 코드의 다음의 구조체에 정의된다.

static const RegJNIRec gRegJNI[] = {

    REG_JNI(register_android_debug_JNITest),

    REG_JNI(register_com_android_internal_os_RuntimeInit),

    REG_JNI(register_android_os_SystemClock),

    REG_JNI(register_android_util_EventLog),

    REG_JNI(register_android_util_Log),

    REG_JNI(register_android_util_FloatMath),

    REG_JNI(register_android_text_format_Time),

    REG_JNI(register_android_content_AssetManager),

    REG_JNI(register_android_content_StringBlock),

    REG_JNI(register_android_content_XmlBlock),

    REG_JNI(register_android_emoji_EmojiFactory),

    REG_JNI(register_android_text_AndroidCharacter),

    REG_JNI(register_android_text_AndroidBidi),

    REG_JNI(register_android_view_InputDevice),

    REG_JNI(register_android_view_KeyCharacterMap),


[--------------중략--------------]

 3) 이후 VM에서 실행할 클래스를 로딩하고 해당 Static 메소드를 호출한다. 이떄부터는 가상 머신에서 코드가 수행된다.



반응형
Posted by alias
,