android的system_server进程的启动

android的system_server进程的启动

android的system_server进程的启动的简单介绍

system_server是Zygote的fork的第一个Java进程相当于它的大儿子,这个进程非常重要的,这里这个进程提供了很多系统线程,提供了所有的核心的系统服务。比如,WindowManager,ActivityManager等,这些都是运行在system_server的进程里。还有很多“Binder-x"的线程,这些线程是各个服Service为了响应应用程序远程调用请求而创建的。除此之外,还有很多内部线程,比如”UI thread“,”InputReader","InputDispatch"等等。我们要了解system_server创建和启动流程

new SystemServer().run();

(源码地址:http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/java/com/android/server/SystemServer.java)

 public static void main(String[] args) {
        new SystemServer().run();
 }

private void run() {
       。。。。。
}

这里需要注意一下由于这个run比较长,可以到网址里去看,是在第307行。

run()

在run()主要是做了一些初始化工作,现在我们来看看初始化的:
(1)初始化必要的SystemServer环境参数,比如系统时间,默认时区,语言,load一些Library等等,
(2)初始化Looper,在主线程中使用的looper就是在SystemServer进行初始化,
(3)初始化Context,只有初始化一个Context才能启动Service的操作。
android的system_server进程的启动_第1张图片

 private void createSystemContext() {
522        ActivityThread activityThread = ActivityThread.systemMain();
523        mSystemContext = activityThread.getSystemContext();
524        mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
525
526        final Context systemUiContext = activityThread.getSystemUiContext();
527        systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
528    }

在这里我们以清楚看看到ActivityThread就是在这里初始化的,也可以看到ActivityThread是如何生成的SystemContext系统上下文的,主要是通过ActivityThread里的getSystemContext()生成的。
其对应的代码的位置:http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/app/ActivityThread.java

    public ContextImpl getSystemContext() {
        synchronized (this) {
            if (mSystemContext == null) {
                mSystemContext = ContextImpl.createSystemContext(this);
            }
            return mSystemContext;
        }
    }

ContextImpl是Context类的具体实现,里面封装完成了生成几种常用的createContext的方法:
代码位置:http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/app/ContextImpl.java

2318    static ContextImpl createSystemContext(ActivityThread mainThread) {
2319        LoadedApk packageInfo = new LoadedApk(mainThread);
2320        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
2321                null);
2322        context.setResources(packageInfo.getResources());
2323        context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
2324                context.mResourcesManager.getDisplayMetrics());
2325        return context;
2326    }
2327
2328    /**
2329     * System Context to be used for UI. This Context has resources that can be themed.
2330     * Make sure that the created system UI context shares the same LoadedApk as the system context.
2331     */
2332    static ContextImpl createSystemUiContext(ContextImpl systemContext) {
2333        final LoadedApk packageInfo = systemContext.mPackageInfo;
2334        ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null,
2335                null, null, 0, null);
2336        context.setResources(createResources(null, packageInfo, null, Display.DEFAULT_DISPLAY, null,
2337                packageInfo.getCompatibilityInfo()));
2338        return context;
2339    }
2340
2341    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
2342        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
2343        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
2344                null);
2345        context.setResources(packageInfo.getResources());
2346        return context;
2347    }
2348
2349    static ContextImpl createActivityContext(ActivityThread mainThread,
2350            LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
2351            Configuration overrideConfiguration) {
2352        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
2353
2354        String[] splitDirs = packageInfo.getSplitResDirs();
2355        ClassLoader classLoader = packageInfo.getClassLoader();
2356
2357        if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
2358            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies");
2359            try {
2360                classLoader = packageInfo.getSplitClassLoader(activityInfo.splitName);
2361                splitDirs = packageInfo.getSplitPaths(activityInfo.splitName);
2362            } catch (NameNotFoundException e) {
2363                // Nothing above us can handle a NameNotFoundException, better crash.
2364                throw new RuntimeException(e);
2365            } finally {
2366                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
2367            }
2368        }
2369
2370        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
2371                activityToken, null, 0, classLoader);
2372
2373        // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
2374        displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
2375
2376        final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)
2377                ? packageInfo.getCompatibilityInfo()
2378                : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
2379
2380        final ResourcesManager resourcesManager = ResourcesManager.getInstance();
2381
2382        // Create the base resources for which all configuration contexts for this Activity
2383        // will be rebased upon.
2384        context.setResources(resourcesManager.createBaseActivityResources(activityToken,
2385                packageInfo.getResDir(),
2386                splitDirs,
2387                packageInfo.getOverlayDirs(),
2388                packageInfo.getApplicationInfo().sharedLibraryFiles,
2389                displayId,
2390                overrideConfiguration,
2391                compatInfo,
2392                classLoader));
2393        context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
2394                context.getResources());
2395        return context;
2396    }

接着是初始化SystemServiceManager,,这个主要是为了用来管理启动service,SystemServiceManager中封装了启动Service的,所以为了,可以看看startService方法,启动系统必要的Service,代码位置如下:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/java/com/android/server/SystemServer.java

// Start services.
427        try {
428            traceBeginAndSlog("StartServices");
429            startBootstrapServices();
430            startCoreServices();
431            startOtherServices();
432            SystemServerInitThreadPool.shutdown();
433        } catch (Throwable ex) {
434            Slog.e("System", "******************************************");
435            Slog.e("System", "************ Failure starting system services", ex);
436            throw ex;
437        } finally {
438            traceEnd();
439        }

在这里可以很明显看到startBootstrapServices(),startCoreServices(),startOtherServices(),这里三个方法启动了很多Android服务,现在我们分别介绍一下,这三个方法:
startBootstrapServices():是Android系统中SystemServer.java类中的一个方法,用于启动系统启动时必要的服务。
android的system_server进程的启动_第2张图片
startBootstrapServices()方法会在系统启动时被调用,以确保这些服务在系统其他部分调用它们之前就已经启动并正常运行。
startCoreServices():是Android系统中SystemServer.java类中的一个方法,用于启动系统的核心服务。
android的system_server进程的启动_第3张图片
startOtherServices():是Android系统中SystemServer.java类中的一个方法,用于启动系统的其他服务。
android的system_server进程的启动_第4张图片
android的system_server进程的启动_第5张图片
android的system_server进程的启动_第6张图片
android的system_server进程的启动_第7张图片
android的system_server进程的启动_第8张图片
android的system_server进程的启动_第9张图片
android的system_server进程的启动_第10张图片
最后一个服务,不再贴图片,直接上文字:
RetailDemoModeService是Android系统中的一个服务,用于在零售演示模式下控制设备的行为。该服务主要用于在零售店等场合展示Android设备的功能和应用程序,以便吸引用户购买。
RetailDemoModeService服务在系统启动时自动启动,其主要作用包括:
控制设备的屏幕亮度、音量、循环播放视频等。
配置设备的网络连接,以便在演示时展示网络功能。
配置应用程序的布局和内容,以便在演示时展示应用程序功能。
监听设备的按键事件和触摸事件,以便在演示时进行交互操作。
提供API供应用程序调用,以便在演示时控制设备的行为。
该服务仅适用于特定的设备和场合,一般用户无需关心或使用该服务。
(备注:参考的博客:https://www.jianshu.com/p/9912a556734f)

最后Zygote的善后工作

代码位置:dalvik/vm/native/dalvik_system_zygote.cpp
Zygote监视system_server进程,一旦发现SystemServer 挂掉了,将其回收,然后将自己杀掉,重新开始。

static void Dalvik_dalvik_system_Zygote_forkSystemServer(
2 const u4* args, JValue* pResult){ 3 ... 4 pid_t pid;
5 pid = forkAndSpecializeCommon(args, true); 6 ... 7 if (pid > 0) {
8 int status;
9 gDvm.systemServerPid = pid;
10 /* WNOHANG 会让waitpid 立即返回,这里只是为了预防上面的赋值语句没有完成之前
SystemServer就crash 了*/
11 if (waitpid(pid, &status, WNOHANG) == pid) {
12 ALOGE("System server process %d has died. Restarting Zygote!",
pid);
13 kill(getpid(), SIGKILL); 14
}
15 }
16 RETURN_INT(pid); 17
}
18
19 /* 真正的处理在这里 */
20 static void sigchldHandler(int s){ 21
... 22 pid_t pid;
23 int status;
24 ...
25 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { 26
...
27 if (pid == gDvm.systemServerPid) { 28
...
29 kill(getpid(), SIGKILL); 30
}
31 }
32 ...
33 }
34
35 static void Dalvik_dalvik_system_Zygote_fork(const u4* args, JValue* pResult){
36 pid_t pid;
37 ...
38 setSignalHandler(); //signalHandler 在这里注册
39 ...
40 pid = fork();
41 ...
42 RETURN_INT(pid);
1 pid_t fork(void)
43 }

在Unix-like系统,父进程必须用 waitpid 等待子进程的退出,否则子进程将变成”
Zombie” (僵尸)进
程,不仅系统资源泄漏,而且系统将崩溃(没有system server,所有Android应用程序都无法运行)。
但是waitpid() 是一个阻塞函数(WNOHANG参数除外),所以通常做法是在signal 处理函数里进行无阻
塞的处理,因为每个子进程退出的时候,系统会发出 SIGCHID 信号。Zygote会把自己杀掉, 那父亲死
了,所有的应用程序不就成为孤儿了? 不会,因为父进程被杀掉后系统会自动给所有的子进程发生
SIGHUP信号,该信号的默认处理就是将杀掉自己退出当前进程。但是一些后台进程(Daemon)可以通 过设
置SIG_IGN参数来忽略这个信号,从而得以在后台继续运行。

总结

  1. init 根据init.rc 运行 app_process, 并携带‘–zygote’ 和 ’–startSystemServer’ 参
    数。
  2. AndroidRuntime.cpp::start() 里将启动JavaVM,并且注册所有framework相关的系统JNI接口。
  3. 第一次进入Java世界,运行ZygoteInit.java::main() 函数初始化Zygote. Zygote 并创建Socket

    server 端。
  4. 然后fork一个新的进程并在新进程里初始化SystemServer. Fork之前,Zygote是preload常用的
    Java类库,以及系统的resources,同时GC()清理内存空间,为子进程省去重复的工作。
  5. SystemServer 里将所有的系统Service初始化,包括ActivityManager 和 WindowManager, 他们
    是应用程序运行起来的前提。
  6. 依次同时,Zygote监听服务端Socket,等待新的应用启动请求。
  7. ActivityManager ready 之后寻找系统的“Startup” Application, 将请求发给Zygote。
  8. Zygote收到请求后,fork出一个新的进程。
  9. Zygote监听并处理SystemServer 的 SIGCHID 信号,一旦System Server崩溃,立即将自己杀死。
    init会重启Zygote
    (这里参考了相关问答)

在Android 10中,Dalvik已经被ART所取代,因此没有dalvik_system_zygote.cpp文件了。如果您需要查看ART的系统进程启动代码,可以参考art/runtime/runtime.cc文件中的Runtime::Start函数。这个函数是ART的入口点之一,负责启动ART虚拟机,并初始化系统进程和应用程序进程。

在Android 10中,ART的实现代码位于art/runtime目录下。其中,art/runtime/entrypoints目录下的文件包含了ART的入口点代码,art/runtime/gc目录下的文件包含了ART的垃圾回收器实现代码,art/runtime/interpreter目录下的文件包含了ART的解释器实现代码,art/runtime/mirror目录下的文件包含了ART的对象模型实现代码。如果您需要查看ART的具体实现细节,可以参考这些目录下的文件。

Android 10中的ART和之前的Dalvik相比有三个主要变化:

从JIT(Just-In-Time)编译器到AOT编译器
在Dalvik中,应用程序的字节码是在运行时通过JIT编译器动态地转换为本地代码,这会导致应用程序启动时的延迟。而在ART中,应用程序的字节码在安装时就全部编译为本地代码,这样应用程序的启动速度大大提高。

优化的垃圾回收器
ART中使用了一种新的垃圾回收器,称为CC(Concurrent Compact)垃圾回收器。这种垃圾回收器可以在不影响应用程序性能的情况下,对内存进行高效的回收和整理。相比之下,Dalvik中的垃圾回收器是基于标记-清除算法的,效率较低。

更好的性能和稳定性
ART将应用程序的字节码预先编译为本地代码,因此在应用程序运行时不再需要进行JIT编译,这样可以提高性能。此外,ART还采用了一些新的技术,如栈上分配、类初始化和方法内联等,来进一步提高应用程序的性能和稳定性。

总之,Android 10中的ART相比Dalvik有着更好的性能和稳定性,并且能够更快地启动应用程序。

你可能感兴趣的:(android,java,jvm)