热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

androidsystemserver启动详解

文章出处:https://blog.csdn.net/shift_wwx/article/details/45561633 前言:之前an

文章出处:https://blog.csdn.net/shift_wwx/article/details/45561633

 

前言:之前android zygote之启动过程分析中分析了一下zygote启动的过程,其中涉及的重要部分有三个:一是创建了一个socket,方便了后期AMS与zygote的通讯,为什么一定要zygote通讯其实说白了就是zygote拥有的东西太多,需要分享一下它;二是启动了system_server进程,而这个进程就是用户基本所有service创建和启动的地方,也是android系统启动的关键一步;三是创建了一个loop,处理AMS发到zygote的一些进程处理信息。

 

@/frameworks/vase/core/java/com/android/internal/os/ZygoteInit.java

public class ZygoteInit {
    ......
    
    public static void main(String argv[]) {
        try {
            ......
            
            registerZygoteSocket();
            ......
            
            if (argv[1].equals("start-system-server")) {
                startSystemServer();
            } else if (!argv[1].equals("")) {         
                throw new RuntimeException(argv[0] + USAGE_STRING);
            }
            
            ......
            
            runSelectLoop();
            ......
        } catch (MethodAndArgsCaller caller) {
            ......
        }catch (RuntimeException ex) {
            ......
        }
    }
}

来看一下startSystemServer:

/**
* Prepare the arguments and fork for the system server process.
*/
private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException {
long capabilities = posixCapabilitiesAsBits(
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_RESOURCE,
OsConstants.CAP_SYS_TIME,
OsConstants.CAP_SYS_TTY_CONFIG
);//没看懂,POSIX接口性能?
/* 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,1032,3001,3002,3003,3006,3007",
"--capabilities=" + capabilities + "," + capabilities,
"--runtime-init",
"--nice-name=system_server",
"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 */
if (pid == 0) {
handleSystemServerProcess(parsedArgs);
}
return true;
}

详细分析:

 

1、args

下面会出现parsedArgs = new ZygoteConnection.Arguments(args);

处理过程是在:

@/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

private void parseArgs(String args[])
throws IllegalArgumentException {
......
}

 

1)uid=1000 

@/frameworks/base/core/java/android/os/Process.java

/**
* Defines the UID/GID under which system code runs.
*/
public static final int SYSTEM_UID = 1000;

还有其他特殊的uid定义:

/**
* Defines the UID/GID under which the telephony code runs.
*/
public static final int PHONE_UID = 1001;
/**
* Defines the UID/GID for the user shell.
* @hide
*/
public static final int SHELL_UID = 2000;
/**
* Defines the UID/GID for the log group.
* @hide
*/
public static final int LOG_UID = 1007;
/**
* Defines the UID/GID for the WIFI supplicant process.
* @hide
*/
public static final int WIFI_UID = 1010;
......
 

2)gid=1000

3)niceName=system_server这里的niceName就是需要创建的进程名,系统起来ps会看到

4)remainingArgs = new String[args.length - curArg];生下来的应该就是args最后的,这边应该是SystemServer的类名

 

2、forkSystemServer

pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);

@/libcore/dalvik/src/main/java/dalvik/system/Zygote.java

public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
preFork();
int pid = nativeForkSystemServer(
uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
postFork();
return pid;
}
native public static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);

@/dalvik/vm/native/dalvik_system_Zygote.cpp

/*
* native public static int nativeForkSystemServer(int uid, int gid,
* int[] gids, int debugFlags, int[][] rlimits,
* long permittedCapabilities, long effectiveCapabilities);
*/
static void Dalvik_dalvik_system_Zygote_forkSystemServer(
const u4* args, JValue* pResult)
{
pid_t pid;
pid = forkAndSpecializeCommon(args, true);
/* The zygote process checks whether the child process has died or not. */
if (pid > 0) {
int status;
ALOGI("System server process %d has been created", pid);
gDvm.systemServerPid = pid;
/* There is a slight window that the system server process has crashed
* but it went unnoticed because we haven't published its pid yet. So
* we recheck here just to make sure that all is well.
*/
if (waitpid(pid, &status, WNOHANG) == pid) {
ALOGE("System server process %d has died. Restarting Zygote!", pid);
kill(getpid(), SIGKILL);
}
}
RETURN_INT(pid);
}

看一下forkAndSpecializeCommon(args, true);其实就是两句话:

dvmDumpLoaderStats("zygote");
pid = fork();

system_server就是由zygote fork而来的。

有点不明白,fork出来应该是子进程,pid应该是0,那么这个if是什么时候调用的呢?

应该是作为父进程的时候,会提示,然后对system_server做监控,出问题的时候,会kill掉system_server,然后restart zygote,需要确认一下。

这里有几篇好文章,可以参考一下。

在系统起来之后ps一下看看吧:

root1741 627992 19028 ffffffff 400d88f0 S zygote
drm 1751 12560 4908 ffffffff b6e9c7a4 S /system/bin/drmserver
media 1761 82836 27872 ffffffff b6e9d7a4 S /system/bin/mediaserver
root1771 1004220c057e4b8 b6f344e0 S /system/bin/installd
keystore 1791 33721012 c038b40c b6ee77a4 S /system/bin/keystore
root1801 1908492c00dde38 b6f898f0 S /system/bin/pppoe_wrapper
root1811 61328 37876 ffffffff b6efa7a4 S /system/bin/imageserver
media_rw 1831 3528440ffffffff b6f4a4e0 S /system/bin/sdcard
root1852 00 c0041a1c 00000000 S kworker/3:1H
root1982 00 c0041a1c 00000000 S kworker/1:1H
root4552 00 c039b180 00000000 S aml_buf_toggle
system 508174732700 40224 ffffffff 400d9954 S system_server
u0_a8 610174684360 61076 ffffffff 400d9954 S com.android.systemui

system_server pid是508,ppid是174,而174确实是zygote进程
 

3、handleSystemServerProcess

/**
* Finish remaining work for the newly forked system server process.
*/
private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller {
closeServerSocket();
// set umask to 0077 so new files and directories will default to owner-only permissions.
Libcore.os.umask(S_IRWXG | S_IRWXO);
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
null, parsedArgs.remainingArgs);
} else {
/*
* Pass the remaining arguments to SystemServer.
*/
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
}
/* should never reach here */
}

 由于由Zygote进程创建的子进程会继承Zygote进程中创建的Socket文件描述符,而这里的子进程又不会用到它,因此,这里就调用closeServerSocket函数来关闭它。这个函数接着调用RuntimeInit.zygoteInit函数来进一步执行启动SystemServer组件的操作。

public static final void zygoteInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
redirectLogStreams();//把system.out和system.err输出重定向到android log中
commonInit();
nativeZygoteInit();
applicationInit(targetSdkVersion, argv);
}

1)commonInit()

这里很关键哦,很多log中都会看到:

private static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
/* set default handler; this applies to all threads in the VM */
Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
/*
* Install a TimezoneGetter subclass for ZoneInfo.db
*/
TimezoneGetter.setInstance(new TimezoneGetter() {
@Override
public String getId() {
return SystemProperties.get("persist.sys.timezone");
}
});
TimeZone.setDefault(null);
/*
* Sets handler for java.util.logging to use Android log facilities.
* The odd "new instance-and-then-throw-away" is a mirror of how
* the "java.util.logging.config.class" system property works. We
* can't use the system property here since the logger has almost
* certainly already been initialized.
*/
LogManager.getLogManager().reset();
new AndroidConfig();
/*
* Sets the default HTTP User-Agent used by HttpURLConnection.
*/
String userAgent = getDefaultUserAgent();
System.setProperty("http.agent", userAgent);
/*
* Wire socket tagging to traffic stats.
*/
NetworkManagementSocketTagger.install();
/*
* If we're running in an emulator launched with "-trace", put the
* VM into emulator trace profiling mode so that the user can hit
* F9/F10 at any time to capture traces. This has performance
* consequences, so it's not something you want to do always.
*/
String trace = SystemProperties.get("ro.kernel.android.tracing");
if (trace.equals("1")) {
Slog.i(TAG, "NOTE: emulator trace profiling enabled");
Debug.enableEmulatorTraceOutput();
}
initialized = true;
}

第一句话加了一个异常捕获的handler:UncaughtHandler

private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
try {
// Don't re-enter -- avoid infinite loops if crash-reporting crashes.
if (mCrashing) return;
mCrashing = true;
if (mApplicationObject == null) {
Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
} else {
StringBuilder message = new StringBuilder();
message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");
final String processName = ActivityThread.currentProcessName();
if (processName != null) {
message.append("Process: ").append(processName).append(", ");
}
message.append("PID: ").append(Process.myPid());
Slog.e(TAG, message.toString(), e);
}
// Bring up crash dialog, wait for it to be dismissed
ActivityManagerNative.getDefault().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
} catch (Throwable t2) {
try {
Slog.e(TAG, "Error reporting crash", t2);
} catch (Throwable t3) {
// Even Slog.e() fails! Oh well.
}
} finally {
// Try everything to make sure this process goes away.
Process.killProcess(Process.myPid());
System.exit(10);
}
}
}

log中经常出现的FATAL EXCEPTION:***就是从这里来的

 

回到commonInit(),其他就是一些初始化,例如时区等

2)nativeZygoteInit

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

看到这个onZygoteInit很是熟悉,在android zygote之启动过程分析中涉及到:

AppRuntime runtime

调用zygoteInitNative函数来执行一个Binder进程间通信机制的初始化工作,这个工作完成之后,这个进程中的Binder对象就可以方便地进行进程间通信了
3)applicationInit

    private static void applicationInit(int targetSdkVersion, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
        // 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;
        try {
            args = new Arguments(argv);
        } catch (IllegalArgumentException ex) {
            Slog.e(TAG, ex.getMessage());
            // let the process exit
            return;
        }
        // Remaining arguments are passed to the start class's static main
        invokeStaticMain(args.startClass, args.startArgs);
    }

invokeStaticMain:

private static void invokeStaticMain(String className, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
Class cl;
try {
cl = Class.forName(className);
} 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.
*/
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

这里会将systemserver的类名传进去,run是在ZygoteInit.main里面。

 

最终就会调用到SystemServer.main(),对于SystemServer后期也会继续分析。请参考android SystemServer详解

 

 

 

 

 


推荐阅读
  • 如何高效解决Android应用ANR问题?
    本文介绍了ANR(应用程序无响应)的基本概念、常见原因及其解决方案,并提供了实用的工具和技巧帮助开发者快速定位和解决ANR问题,提高应用的用户体验。 ... [详细]
  • 在尝试加载支持推送通知的iOS应用程序的Ad Hoc构建时,遇到了‘no valid aps-environment entitlement found for application’的错误提示。本文将探讨此错误的原因及多种可能的解决方案。 ... [详细]
  • 长期从事ABAP开发工作的专业人士,在面对行业新趋势时,往往需要重新审视自己的发展方向。本文探讨了几位资深专家对ABAP未来走向的看法,以及开发者应如何调整技能以适应新的技术环境。 ... [详细]
  • 二维码的实现与应用
    本文介绍了二维码的基本概念、分类及其优缺点,并详细描述了如何使用Java编程语言结合第三方库(如ZXing和qrcode.jar)来实现二维码的生成与解析。 ... [详细]
  • JUnit下的测试和suite
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 本文介绍了如何通过C#语言调用动态链接库(DLL)中的函数来实现IC卡的基本操作,包括初始化设备、设置密码模式、获取设备状态等,并详细展示了将TextBox中的数据写入IC卡的具体实现方法。 ... [详细]
  • importjava.io.*;importjava.util.*;publicclass五子棋游戏{staticintm1;staticintn1;staticfinalintS ... [详细]
  • 在处理大数据量的SQL分页查询时,通常需要执行两次查询来分别获取数据和总记录数。本文介绍了一种优化方法,通过单次查询同时返回分页数据和总记录数,从而提高查询效率。 ... [详细]
  • 在尝试使用 Android 发送 SOAP 请求时遇到错误,服务器返回 '无法处理请求' 的信息,并指出某个值不能为 null。本文探讨了可能的原因及解决方案。 ... [详细]
  • 问题描述现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能;在实际开发过程中 ... [详细]
  • 本文深入探讨了Go语言中的接口型函数,通过实例分析其灵活性和强大功能,帮助开发者更好地理解和运用这一特性。 ... [详细]
  • JUC并发编程——线程的基本方法使用
    目录一、线程名称设置和获取二、线程的sleep()三、线程的interrupt四、join()五、yield()六、wait(),notify(),notifyAll( ... [详细]
  • 树莓派4B:安装基础操作系统指南
    本文将详细介绍如何为树莓派4B安装基础操作系统,包括所需材料、镜像下载、镜像烧录以及更换国内源等步骤。 ... [详细]
  • 本文探讨了如何在游戏启动画面中移除广告,特别是在游戏数据加载期间(大约5-6秒)广告会短暂显示的问题。通过调整XML布局和代码逻辑,可以实现广告的延迟加载或完全移除。 ... [详细]
  • 本文介绍如何使用匿名内部类实现工厂模式,通过定义接口和工厂接口来创建不同的服务实现。 ... [详细]
author-avatar
手机用户2502861123
这个家伙很懒,什么也没留下!