菜鸟学Android源码-Android System StartUp Process

2024-05-06 20:48

本文主要是介绍菜鸟学Android源码-Android System StartUp Process,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

(PS:本篇为翻译文章,英文原文链接:The Android Booting process)

关于Android 系统启动流程我们有很多疑问,比如说什么是Zygote?什么是init.rc?Linux kernel和Android Linux Kernel有什么区别?这片文章就是为了说明这些问题。

下面这张图详细描述了开机过程:
开机流程

第一步:电源以及系统启动

在按下Power键时,引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序到RAM,然后执行。

第二步:引导程序

引导程序是在Android操作系统开始运行前的一个小程序。引导程序是运行的第一个程序,因此它是针对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如redboot、uboot、qi bootloader或者开发自己的引导程序,它不是Android操作系统的一部分。引导程序是OEM厂商或者运营商加锁和限制的地方。

引导程序分两个阶段执行。第一个阶段,检测外部的RAM以及加载对第二阶段有用的程序;第二阶段,引导程序设置网络、内存等等。这些对于运行内核是必要的,为了达到特殊的目标,引导程序可以根据配置参数或者输入数据设置内核。

Android引导程序可以在源码/bootable/bootloader/legacy/usbloader找到。
传统的加载器包含的2个重要文件,需要在这里说明:

init.s初始化堆栈,清零BBS段,调用main.c的_main()函数;
main.c初始化硬件(闹钟、主板、键盘、控制台),创建linux标签。

第三步:Linux Kernel

Android内核与桌面linux内核启动的方式差不多。内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。

以下是Android Linux Kernel和Linux Kernel的几点区别:

  • Binder: 它是Android Linux Kernel独有的跨进程交互机制
  • ashmem:Android 共享内存
  • pmem: Process memory allocator
  • logger: 底层的Logcat支持
  • wakelocks:电源的唤醒服务
  • oom handling: 当内存过低时,杀死部分进程
  • alarm manager:定时任务
  • RAM_CONSOLE:
  • USB gadget driver for ADB
  • yaffs2 flash filesystem

第四步:Init进程

init是第一个进程,我们可以说它是root进程或者说有进程的父进程。init进程有两个责任,一是挂载目录,比如/sys、/dev、/proc,二是运行init.rc脚本。

init进程可以在/system/core/init找到。
init.rc文件可以在/system/core/rootdir/init.rc找到。
readme.txt可以在/system/core/init/readme.txt找到。

对于init.rc文件,Android中有特定的格式以及规则。在Android中,我们叫做Android初始化语言。
Android初始化语言由四大类型的声明组成,即Actions(动作)、Commands(命令)、Services(服务)、以及Options(选项)。
Action(动作):动作是以命令流程命名的,有一个触发器决定动作是否发生。
Service(服务):服务是init进程启动的程序、当服务退出时init进程会视情况重启服务。
语法
Options(选项)
选项是对服务的描述。它们影响init进程如何以及何时启动服务。
咱们来看看默认的init.rc文件。这里我只列出了主要的事件以及服务。

Action/Service 描述
on early-init 设置init进程以及它创建的子进程的优先级,设置init进程的安全环境
on init 设置全局环境,为cpu accounting创建cgroup(资源控制)挂载点
on fs 挂载mtd分区
on post-fs 改变系统目录的访问权限
on post-fs-data 改变/data目录以及它的子目录的访问权限
on boot 基本网络的初始化,内存管理等等
service servicemanager 启动系统管理器管理所有的本地服务,比如位置、音频、Shared preference等等…
service zygote 启动zygote作为应用进程

在这个阶段你可以在设备的屏幕上看到“Android”logo了。

第五步:Zygote and Dalvik

在Java中,我们知道不同的虚拟机实例会为不同的应用分配不同的内存。假如Android应用应该尽可能快地启动,但如果Android系统为每一个应用启动不同的Dalvik虚拟机实例,就会消耗大量的内存以及时间。因此,为了克服这个问题,Android系统创造了”Zygote”。Zygote让Dalvik虚拟机共享代码、低内存占用以及最小的启动时间成为可能。Zygote是一个虚拟器进程,正如我们在前一个步骤所说的在系统引导的时候启动。Zygote预加载以及初始化核心库类。通常,这些核心类一般是只读的,也是Android SDK或者核心框架的一部分。在Java虚拟机中,每一个实例都有它自己的核心库类文件和堆对象的拷贝。

Zygote加载进程

加载ZygoteInit类,源代码:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
registerZygoteSocket()为zygote命令连接注册一个服务器套接字。
preloadClassed “preloaded-classes”是一个简单的包含一系列需要预加载类的文本文件,你可以在/frameworks/base找到“preloaded-classes”文件。
preloadResources() preloadResources也意味着本地主题、布局以及android.R文件中包含的所有东西都会用这个方法加载。
在这个阶段,你可以看到启动动画。

第六步:系统服务或服务

完成了上面几步之后,运行环境请求Zygote运行系统服务。系统服务同时使用native以及java编写,系统服务可以认为是一个进程。同一个系统服务在Android SDK可以以System Services形式获得。系统服务包含了所有的System Services。

Zygote创建新的进程去启动系统服务。代码如下:

public static void main(String argv[]) {ZygoteServer zygoteServer = new ZygoteServer();// Mark zygote start. This ensures that thread creation will throw// an error.ZygoteHooks.startZygoteNoThreadCreation();// Zygote goes into its own process group.try {Os.setpgid(0, 0);} catch (ErrnoException ex) {throw new RuntimeException("Failed to setpgid(0,0)", ex);}try {Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");RuntimeInit.enableDdms();// Start profiling the zygote initialization.SamplingProfilerIntegration.start();boolean startSystemServer = false;String socketName = "zygote";String abiList = null;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]);}}if (abiList == null) {throw new RuntimeException("No ABI list supplied.");}zygoteServer.registerServerSocket(socketName);Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,SystemClock.uptimeMillis());preload();EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());Trace.traceEnd(Trace.TRACE_TAG_DALVIK);// Finish profiling the zygote initialization.SamplingProfilerIntegration.writeZygoteSnapshot();// Do an initial gc to clean up after startupTrace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");gcAndFinalize();Trace.traceEnd(Trace.TRACE_TAG_DALVIK);// Disable tracing so that forked processes do not inherit stale tracing tags from// Zygote.Trace.setTracingEnabled(false);// Zygote process unmounts root storage spaces.Zygote.nativeUnmountStorageOnInit();ZygoteHooks.stopZygoteNoThreadCreation();if (startSystemServer) {startSystemServer(abiList, socketName, zygoteServer);}Log.i(TAG, "Accepting command socket connections");zygoteServer.runSelectLoop(abiList);zygoteServer.closeServerSocket();} catch (Zygote.MethodAndArgsCaller caller) {caller.run();} catch (Throwable ex) {Log.e(TAG, "System zygote died with exception", ex);zygoteServer.closeServerSocket();throw ex;}}

可以看到在主main函数内部,调用了如下代码启动系统服务:

startSystemServer(abiList, socketName,zygoteServer);

进一步查看该函数:

 /*** Prepare the arguments and fork for the system server process.*/private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)throws Zygote.MethodAndArgsCaller, RuntimeException {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_RESOURCE,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,1032,3001,3002,3003,3006,3007,3009,3010","--capabilities=" + capabilities + "," + capabilities,"--nice-name=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 */if (pid == 0) {if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName);}zygoteServer.closeServerSocket();handleSystemServerProcess(parsedArgs);}return true;}

可以看到其最终调起的应该是com.android.server.SystemServer这个类,在这个类里面完成了各种系统服务的初始化。

参考链接:Android启动过程深入解析

这篇关于菜鸟学Android源码-Android System StartUp Process的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/965341

相关文章

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存