天天看點

Android系統啟動之SystemServer(一)

在《Android系統啟動之Zygote》的中,我們知道SystemServer程序(程序名為system_server)是由Zygote程序fork出來的,但當時并沒有說明SystemServer.main()方法是怎樣被調用的,說到這裡不知道大家有沒有想過一個問題,我們在寫一個Android demo應用的時候,為什麼都沒見過main()方法,而在寫一個java demo時就要實作main()方法。這個問題大家可以想一想,以後有機會再講解。那麼還是回歸正題,這篇文章我們還是來了解下SystemServer.main()是怎樣被調用的。

 我們知道system_server程序是有Zygote fork出來的,在ZygoteInit.forkSystemServer()方法中完成了具體的實作,關于fork出system_server的後續流程,我們先放一張時序圖總結下。

Android系統啟動之SystemServer(一)

 接下來,我們從ZygoteInit.forSystemServer()方法一步步往下分析

forSystemServer

//framework/base/core/java/com/android/internal/os/ZygoteInit.java
/**
 * Prepare the arguments and forks for the system server process.
 *
 * Returns an {@code Runnable} that provides an entrypoint into system_server code in the
 * child process, and {@code null} in the parent.
 */
private static Runnable forkSystemServer(String abiList, String socketName,
        ZygoteServer zygoteServer) {
    long capabilities = posixCapabilitiesAsBits(
        OsConstants.CAP_IPC_LOCK,
        OsConstants.CAP_KILL,
        OsConstants.CAP_NET_ADMIN,
        OsConstants.CAP_NET_BIND_SERVICE,
        OsConstants.CAP_NET_BROADCAST,
        OsConstants.CAP_NET_RAW,
        OsConstants.CAP_SYS_MODULE,
        OsConstants.CAP_SYS_NICE,
        OsConstants.CAP_SYS_PTRACE,
        OsConstants.CAP_SYS_TIME,
        OsConstants.CAP_SYS_TTY_CONFIG,
        OsConstants.CAP_WAKE_ALARM
    );
    /* Containers run without this capability, so avoid setting it in that case */
    if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
        capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
    }
    /* 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,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
        "--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server", //system_server就是程序名
        "--runtime-args",
        "com.android.server.SystemServer",
    };
    ZygoteConnection.Arguments parsedArgs = null;

    int pid;

    try {
        parsedArgs = new ZygoteConnection.Arguments(args);
        ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
        ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

        /* Request to fork the system server process */
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    /* For child process */
    //Zygote.forkSystemServer會傳回兩次,分别是在子程序和父程序中
    //pid ==0 表示目前在子程序,也就是fork出來的system_server程序。
    if (pid == 0) {
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }
        zygoteServer.closeServerSocket();
        return handleSystemServerProcess(parsedArgs);
    }
   return null;
}

           

關于Zygote.forkSystemServer()具體流程就不展開,感興趣的可以可以根據《Android系統啟動之Zygote》文章最後的時序圖看下有關方法的具體實作。目前在子線程也就是system_server中時,就會進入上面的

if(pid==0)

判斷語句。

handleSystemServerProcess

private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
   // set umask to 0077 so new files and directories will default to owner-only permissions.
   Os.umask(S_IRWXG | S_IRWXO);
   if (parsedArgs.niceName != null) {
       Process.setArgV0(parsedArgs.niceName);
   }
   final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
   if (systemServerClasspath != null) {
       //執行dex優化操作
       performSystemServerDexOpt(systemServerClasspath);
       // Capturing profiles is only supported for debug or eng builds since selinux normally
       // prevents it.
       boolean profileSystemServer = SystemProperties.getBoolean(
               "dalvik.vm.profilesystemserver", false);
       if (profileSystemServer && (Build.IS_USERDEBUG || Build.IS_ENG)) {
           try {
               File profileDir = Environment.getDataProfilesDePackageDirectory(
                       Process.SYSTEM_UID, "system_server");
               File profile = new File(profileDir, "primary.prof");
               profile.getParentFile().mkdirs();
               profile.createNewFile();
               String[] codePaths = systemServerClasspath.split(":");
               VMRuntime.registerAppInfo(profile.getPath(), codePaths);
           } catch (Exception e) {
               Log.wtf(TAG, "Failed to set up system server profile", e);
           }
       }
   }
   //在forkSystemServer()方法中沒有配置“--invoke-with",是以此時parsedArgs.invokeWith = null;
   if (parsedArgs.invokeWith != null) {
       String[] args = parsedArgs.remainingArgs;
       // If we have a non-null system server class path, we'll have to duplicate the
       // existing arguments and append the classpath to it. ART will handle the classpath
       // correctly when we exec a new process.
       if (systemServerClasspath != null) {
           String[] amendedArgs = new String[args.length + 2];
           amendedArgs[0] = "-cp";
           amendedArgs[1] = systemServerClasspath;
           System.arraycopy(args, 0, amendedArgs, 2, args.length);
           args = amendedArgs;
       }
       WrapperInit.execApplication(parsedArgs.invokeWith,
               parsedArgs.niceName, parsedArgs.targetSdkVersion,
               VMRuntime.getCurrentInstructionSet(), null, args);
       throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
   } else {
       ClassLoader cl = null;
       if (systemServerClasspath != null) {
           cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
           Thread.currentThread().setContextClassLoader(cl);
       }
       /*
        * Pass the remaining arguments to SystemServer.
        */
       return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
   }
   /* should never reach here */
}
           

Os.getenv("SYSTEMSERVERCLASSPATH");

會擷取SYSTEMSERVERCLASSPATH環境變量,最終實作是在libcore_io_Linux.cpp中的jni方法getenv()函數。也可以通過adb shell 環境下輸入env指令檢視,該指令可以檢視所有環境變量。

Android系統啟動之SystemServer(一)

在得到

SYSTEMSERVERCLASSPATH

值之後,會進行dex優化。

zygoteInit

//framework/base/core/java/com/android/internal/os/ZygoteInit.java
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
    if (RuntimeInit.DEBUG) {
        Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
    }

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
    //将log重定向到Android log輸出
    RuntimeInit.redirectLogStreams();
    //初始化,包括設定未捕獲異常處理,設定時區,重置log,設定Http user agent和設定socket的tag
    RuntimeInit.commonInit();
    ZygoteInit.nativeZygoteInit();
    return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
           

 在zygoteInit()方法中會調用靜态方法nativeZygoteInit(),該方法通過jni方式最終會調用app_main.cpp中的onZygoteInit()函數,在該函數中主要是打開binder驅動并建立binder線程。

//framework/base/cmd/app_process/app_main.cpp 
virtual void onZygoteInit()
 {
     sp<ProcessState> proc = ProcessState::self();
     ALOGV("App process: starting thread pool.\n");
     proc->startThreadPool();
 }
           
//framework/native/libs/binder/ProcessState.cpp
sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState("/dev/binder");
    return gProcess;
}
           

RuntimeInit.applicationInit()

 接下來我們看下Runtime.applicationInit()方法的實作,在該方法中先調用了nativeSetExitWithoutCleanup(),這會影響當應用退出時是否會調用AndroidRuntime::onExit()函數;然後設定了虛拟機記憶體使用率;最後調用findStaticMain()方法,通過反射的方式找到SystemServer.main()方法的Method對象,不過這個時候并沒有調用SystemServer.main()方法,而是将它的Method對象和argv封裝成MethodAndArgsCaller對象。

//framework/base/core/java/com/android/internal/os/RuntimeInit.java
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
        ClassLoader classLoader) {
    // If the application calls System.exit(), terminate the process
    // immediately without running any shutdown hooks.  It is not possible to
    // shutdown an Android application gracefully.  Among other things, the
    // Android runtime shutdown hooks close the Binder driver, which can cause
    // leftover running threads to crash before the process actually exits.
    nativeSetExitWithoutCleanup(true);

    // We want to be fairly aggressive about heap utilization, to avoid
    // holding on to a lot of memory that isn't needed.
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

    final Arguments args = new Arguments(argv);

    // The end of of the RuntimeInit event (see #zygoteInit).
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

    // Remaining arguments are passed to the start class's static main
    return findStaticMain(args.startClass, args.startArgs, classLoader);
}

private static Runnable findStaticMain(String className, String[] argv,
        ClassLoader classLoader) {
    Class<?> cl;

    try {
        cl = Class.forName(className, true, classLoader);
    } catch (ClassNotFoundException ex) {
        throw new RuntimeException(
                "Missing class when invoking static main " + className,
                ex);
    }

    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.
     */
    return new MethodAndArgsCaller(m, argv);
}
           

MethodAndArgsCaller實作了Runnable接口,在該對象的run()方法中才會通過Method.invoke()方法真正調用ZygoteInit.main()方法中。

//framework/base/core/java/com/android/internal/os/ZygoteInit.java
//main()方法調用MethodAndArgsCaller.run()
if (startSystemServer) {
     Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
     // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
     // child (system_server) process.
     if (r != null) {
         r.run();
         return;
     }
}
           

 不知道細心的同學有沒有發現一個小小的問題,在RuntimeInit.findStaticMain()方法的最後的注釋說抛出異常以便在ZygoteInit.main()方法中捕獲,然後調用MethodAndArgsCaller.run()方法,然而實際在findStaticMain()最後是傳回 MethodAndArgsCaller對象的,在ZygoteInit.main()方法中也不是在捕獲異常的時候調用MethodAndArgsCaller.run()方法的,而是在forkSystemServer()方法傳回Runnable對象後調用其run()方法,并不是如注釋中說明的那樣。這個地方其實是google工程師的鍋,在Android8.1之前是通過抛出異常,然後在ZygoteInit.main()方法中捕獲到異常後再調用MethodAndArgsCaller的run()方法(PS: Android8.1之前MethodAndArgsCaller繼承了Exception并實作了Runnable接口),但在Android8.1開始已修改為傳回MethodAndArgsCaller對象,然而注釋并沒有修改,其實直到Android10這個注釋也還沒修改。