安卓启动相关以及架构设计相关

我们知道安卓大多数是服务等的启动是伴随着init进程启动一起启动,这个init进程类似于linux的init,进程pid为1。

读过安卓源代码的人都应该非常熟悉init会读取init.rc和init.xxx.rc等,想必也读取过关于rc的相关readme。文档中介绍了Actions、Service、Command、Options。当中我仅仅摘取Service的一段原文介绍(此service非framework层的service,安卓把每一个由init执行的程序或者进程叫做服务,):

Services

----------------------------------------------------------------------------------------------------------------

Services are programs which init launches and(optionally) restarts when they exit. Services take the form of:

service<name> <pathname> [ <argument> ]* <option>

<option>

...

Options

----------------------------------------------------------------------------------------------------------------

介绍的非常明了,服务是init执行起来的程序或者可选地重新启动当它们退出的时候。服务格式例如以下:

service <name> <pathname> [<argument> ]*

<option>

<option>

...

Options当中option是选项

在init中service结构体(仅仅显示重要部分):

struct service {

/* list of all services */

struct listnode slist;服务链表,内核结构应该是双向链表

const char *name;服务名称

const char *classname;服务相应的class类

unsigned flags;

pid_t pid;进程id

uid_t uid;用户uid

gid_t gid;组id

char *seclabel;

struct socketinfo *sockets;

struct svcenvinfo *envvars;

struct action onrestart;  /* Actions to execute on restart. */

};

好我们如今理解了服务,那在看看init.rc中包括的一个我们比較关注的服务(也算一个样例):

service zygote/system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

socket zygote 666

启动一个名字为zygote的服务,它的路径名为/system/bin/app_process,參数为

-Xzygote /system/bin--zygote --start-system-server,选项为socket zygote 666(打开socket)

// Everything upto '--' or first non '-' arg goes to the vm这句摘自app_main.cpp

这句是对參数-Xzygote /system/bin --zygote的一个非常好的诠释,-Xzygote是传递给vm的參数,而--zygote --start-system-server是传递给/system/bin的參数,意思是启动system_server,其父进程是zygote。

zygote作为一个service底层通过对应的alloc和fork实现。

用adb连接我自己的htc设备,然后ps显示zygote和system_server进程例如以下:

从上图看到system_server的ppid为1527,zygote的pid为1527而ppid为1,得出zygote是由init进程fork出来的,而system_server由zygote进程fork出来的。

Service启动的四种模式

Zygote、SystemServer、Application、Tool

全部这一切构成了安卓系统的服务,在init启动时会都被启动起来。

从Zygote開始

zygote代码集合

查看过源代码的人能够了解到,zygote重要的相关代码包括例如以下:

framework/base/cmds/app_main.cpp

fremework/base/core/java/com/android/internal/os/ZygoteInit.java

fremework/base/core/java/com/android/internal/os/ZygoteConnection.java

libcore/dalvik/java/dalvik/system/Zygote.java

dalvik/vm/native/ dalvik_system_Zygote.cpp

frameworks/base/core/jni/com_android_internal_os_ZygoteInit.cpp

当然zygote相关代码比显示的要多,可是上面这些已经足够你了解zygote了。

如今我们来解说一下zygote究竟做了什么,当然这些解说的根据是上面讲到的相关zygote源代码。可是我不会详细列出流程出自哪个文件,由于这样讲起来比較费力气,所以我这里仅仅是解说流程逻辑。

app_process创造了zygote

能够从上面的init.rc和相关Readme介绍得到,zygote是由/system/app_process这个bin加一些參数创造出来的,所以你不用在纠结什么zygote和app_process关系。

另外一方面init进程fork出来了zygote进程,而zygote进程又相继孵化出来了system_server进程等其它进程。

那是不是能够理解app_process就是init进程呢?这个问题我用一个样例回答你。我们从7岁開始上学到20多岁毕业,这段时间中我们经历了小学九年义务教育,经历了高中三年教育,经历了大学四年教育。然后我问你,你读高一,那么这个高一能代表你的全部学习经历吗?学习就好比init进程,我们学习经历的小学中学高中大学,就好比init一点一点一步一步做的事情,那么通过一个可运行bin app_process启动zygote也是当中之中的一个的工作,当然init的工作可远不止如此。相同app_process也不仅仅创造了zygote,还做了其它事情。

看一段代码(摘自app_main.cpp):

classAppRuntime:publicAndroidRuntime{……}

AppRuntimeruntime;

if (zygote) {

runtime.start("com.android.internal.os.ZygoteInit",

startSystemServer ? "start-system-server":"");

} elseif(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");

}

上面代码(app_process)说明了AppRuntime继承自AndroidRuntime,同一时候获得AndroidRuntime实例。假设是zygote启动它,怎么启动runtime.start("com.android.internal.os.ZygoteInit",

startSystemServer ? "start-system-server":"");

假设不是通过传递过来的类的參数启动它runtime.start("com.android.internal.os.RuntimeInit",

application ? "application":"tool");

做完这些事情app_process就寿终正寝了。

Zygote做了些什么,ZygoteInit

init进程启动的时候zygote被作为一种服务启动起来,而且赋予了进程名字为zygote。

所做之事:

n  SamplingProfilerIntegration.start();开启性能监控,这个对解说没什么意义

n  registerZygoteSocket();注冊socket

n  preloadClasses();在preloaded-classes文件里,这里面包名了全部安卓环境须要的服务和工具和全部类,有兴趣的能够去看看这个文件。

n  preloadResources();准备preloadClasses()须要的资源。

n  startSystemServer();启动system_server

n  假设是zygote 模式,runForkMode();

n  否则runSelectLoopMode();

n  closeServerSocket();关闭socket

n  Exception运行caller.run();

上面proloadclasses实际上并没有真正的实例化类,而是只载入类的vm中。

runForkMode

while (true) {

ZygoteConnection peer = acceptCommandPeer();

int pid;

pid = Zygote.fork();

if (pid == 0) {

……

peer.run();

break;

}

runForkMode 方法首先fork新的进程,而且对fork出来的进程运行run方法,那么Zygote.fork做了什么呢?

首先它运行nativeFork然后调用dalvik native代码forkAndSpecializeCommon这里我仅仅选择了最重要的大家能看懂的一行代码,其它代码有兴趣的能够去源代码中研究:

pid = fork();Linux中的经典fork。

从上面代码能够看出Zygote确实是fork出来了进程,当中包括system_server,并且zygote作为后台进程无限的从socket接收到fork请求,来fork出新的进程。

fork出来的进程运行run方法,run方法运行runOnce,runOnce做了什么,请看下一节。实际这里调用这种方法它什么都没做。

runSelectLoopMode

这里最基本的是它调用了runOnce,而runOnce最核心的一行代码是:

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName);

这种方法调用nativeForkAndSpecialize在调用Dalvik_dalvik_system_Zygote_fork,这里仅仅是常规的fork。

SystemServer为一切安卓环境做准备

zygote启动完毕之后,它启动了system_server,然后自己进入了fork模式等待fork新的进程。

启动system_server

n  Zygote.forkSystemServer//终于调用forkAndSpecializeCommon fork出system_server

n  handleSystemServerProcess//由于invokeWith为空所以它运行了RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs)-------------------->

redirectLogStreams();//重置输入错误流

commonInit();//设置时区,http代理,安装NetworkManagementSocketTagger

nativeZygoteInit();//终于调用onZygoteInit

||sp<ProcessState>proc = ProcessState::self();

||proc->startThreadPool();//创建线程,启动

applicationInit(targetSdkVersion,argv);//运行SystemServer的main函数,看到了没才刚刚開始哦。

进入SystemServer类的main函数,当中主要运行了下面方法:

n  System.loadLibrary("android_servers");//载入libandroid_servers.so

n  init1(args);//掉用system_init();

调用system_init

sp<ProcessState> proc(ProcessState::self());

sp<IServiceManager> sm = defaultServiceManager();

获得processstate实例,获得servicemanager实例。

……

AndroidRuntime* runtime = AndroidRuntime::getRuntime();

获得启动安卓的vm

JNIEnv* env = runtime->getJNIEnv();

jclass clazz = env->FindClass("com/android/server/SystemServer");

jmethodID methodId = env->GetStaticMethodID(clazz, "init2","()V");

env->CallStaticVoidMethod(clazz, methodId);

载入SystemServer类并运行init2方法

ProcessState::self()->startThreadPool();

创建一个线程,不知道为什么google的project师把它命名为startThreadPool

,pool非常easy影响人的思维,可是当你查看代码的时候发现它终于就调用了一个pthread_create无非就是创建一个线程。

IPCThreadState::self()->joinThreadPool();

joinThreadPool实现有点复杂,我摘几行最重要的代码:

do {

……

int32_t cmd;

result = talkWithDriver();

if (result >= NO_ERROR) {

result = executeCommand(cmd);

}

……

if(result == TIMED_OUT &&!isMain) {

break;

}

……

} while (result != -ECONNREFUSED && result != -EBADF);

talkWithDriver(false);

这个函数在循环中反复运行下列动作:
  1.talkWithDriver 通过ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr)读取请求和写回结果。
 2.executeCommand 运行对应的请求,反正也是和binder相关的

凡是程序中包括有joinThreadPool这段代码,它就具备和binder通讯的能力了。

有些人总是看到pool就喜欢和什么池联系起来,可是我看了几遍源代码都没看见对于池的操作,至于google为什么这么设计我不知道。

init2

代码来源于SystemServer

Thread thr = new ServerThread();

thr.start();

首先ServerThread是继承自Thread的,那么上面这两行我们已经非常清楚了就是启动一个线程。

在线程里做了什么呢,记得之前zygote启动的时候proload中的proclasses吗,当时仅仅是载入了全部的class到vm中,可是并没有实例化并投入到工作中,并且zygote启动之后进入了loop模式等待socket请求来fock新的进程,其它的事情它就撒手无论了,就交给了system_server。到如今为止,安卓的环境还没有准备充足,什么我们平时经常听到了ActivityManagerService呀,什么PackageManagerService呀,各种服务各种应用吧,凡是为安卓大多数安卓的环境这里差点儿都准备了。

run方法

以下让我们看一些重要的源代码吧(感兴趣的能够自己细致研习代码):

……

Looper.prepareMainLooper();

准备loop,进入loop

android.os.Process.setThreadPriority(

android.os.Process.THREAD_PRIORITY_FOREGROUND);

BinderInternal.disableBackgroundScheduling(true);

设置进程优先权,设置binder禁止内部后台调度

……

HandlerThread uiHandlerThread = newHandlerThread("UI");

uiHandlerThread.start();

Handler uiHandler = new Handler(uiHandlerThread.getLooper());

uiHandler.post();

HandlerThread wmHandlerThread = newHandlerThread("WindowManager");

wmHandlerThread.start();

Handler wmHandler = newHandler(wmHandlerThread.getLooper());

wmHandler.post();

UI和WindowManager进入handle状态

以下就是实例化各种服务了,当中包括实例化,向ServiceManager中注冊服务,调用各种服务类的核心方法等。代码太一目了然了,顺着代码你能够去相关类去看详细方法,从而能得知全部启动过程和调用方法运行了什么。

installer = new Installer();

installer.ping();

ServiceManager.addService("entropy",newEntropyMixer());

power = new PowerManagerService();

//电源管理

ServiceManager.addService(Context.POWER_SERVICE,power);

context =ActivityManagerService.main(factoryTest);

display = newDisplayManagerService(context, wmHandler, uiHandler);

ServiceManager.addService(Context.DISPLAY_SERVICE,display, true);

telephonyRegistry = newTelephonyRegistry(context);

ServiceManager.addService("telephony.registry",telephonyRegistry);

ServiceManager.addService(Context.SCHEDULING_POLICY_SERVICE,

new SchedulingPolicyService());

……

pm =PackageManagerService.main(context, installer,

factoryTest !=SystemServer.FACTORY_TEST_OFF,

onlyCore);

//包管理

ActivityManagerService.setSystemProcess();

ServiceManager.addService(Context.USER_SERVICE,

UserManagerService.getInstance());

mContentResolver= context.getContentResolver();

accountManager = newAccountManagerService(context);

ServiceManager.addService(Context.ACCOUNT_SERVICE,accountManager);

……实在是太多ManagerService和太多的Service了,不写了自己去看吧

power.systemReady(twilight, dreamy);

pm.systemReady();

……各种ready各种初始化各种调用主要函数不写了

startSystemUi(contextF);

context.startServiceAsUser(intent,UserHandle.OWNER);

启动系统UI

Looper.loop();

进入loop模式,handleMessage去了。后面略。

至此SystemServer就算讲完了,通过上面你应该知道它是什么时候被启动的已经启动后它做了些什么。

ServiceManager

ServiceManager是做什么的呢,事实上它就是一个管理framework层各种服务的。它内部有一个结构体,是一个链表结构,每一个节点相应一个服务,当运行SystemServer时它的run方法里面的全部服务都会向ServiceManager进行注冊。

一个服务本身并不全然由纯java编写,也许有一些是这样,由于我并没有看过全部代码不敢妄断,可是通常一个服务是由java和jni和native代码一起编写。并且通常状态下假设一个service会为上层应用提供服务那么这个service一般会有一个binder的stub,这个stub叫做桩,类似于代理可是又不能说是代理,这是rpc协议和机理所致。假设做过java rpc的人也许会对此并不陌生。

通用规则:

全部的XXXManager都是作为XXX的管理者。

全部的XXXManagerService或者XXXService差点儿都是作为XXX类型对上层通过binder通讯而为其服务的独立进程。

svcinfo结构体

struct svcinfo

{

structsvcinfo *next;下一个服务

void*ptr;服务指向的地址

structbinder_deathdeath;

intallow_isolated;

unsignedlen;

uint16_t name[0];服务名称

};

structsvcinfo *svclist = 0;

这个结构体就是一个相应service list的结构体,它里面包括全部服务。初始时这个链表为0也就是NULL。

servicemanager提供的方法

查找服务、加入服务、释放svc结构、处理svc当中包括(查找服务、加入服务、检查服务、列出全部服务、获得服务)。

通过读取servicemanager的main函数我们得知它首先打开了binder,而且把自己变成了BINDER_SERVICE_MANAGER,然后进入了无限循环状态,等待其它service的binder通讯,它负责各个service之间的通讯通过binder,它作为了一个桥梁。

binder相关

首先binder作为一种驱动设计,用于进程间通讯,使用rpc协议。遵循linux驱动设计。在类unix世界一切皆文件,全部你能在binder相关源文件看到,訪问binder和訪问文件一样通过一个open就能够了,用户层和binder的通讯命令借助底层实现的ioctl函数。

由于安卓世界里,差点儿每个service都是作为独立进程执行的,都是由zygote进程fork出来的,全部各个进程是独立的,他们有自己的进程空间,所以为了彼此通讯,安卓设计了有别的binder机制。

转载于:https://www.cnblogs.com/blfshiye/p/4059163.html

安卓启动相关以及架构设计相关相关推荐

  1. Android App 架构设计相关资料汇总

    1. 前言 只要有1,2年工作经验的程序员,多多少少都会接触到架构东西.可能平时工作中不一定会有机会从0到1完完全全自己去设计一套架构出来,但是如果想成为高级工程师,技术专家,架构师--尽早接触架构方 ...

  2. MySQL架构设计相关的方式方法和软件介绍

    http://www.linuxidc.com/Linux/2011-08/40601.htm http://www.cnblogs.com/RicCC/archive/2009/09/28/mysq ...

  3. 前端架构设计第一课 CI环境npm/Yarn

    开篇词 像架构师一样思考,突破技术成长瓶颈 透过工程基建,架构有迹可循.你好,我是侯策(LucasHC),目前任职于某互联网独角兽公司,带领 6 条业务线前端团队,负责架构设计和核心开发.工程方案调研 ...

  4. 数据库架构设计——表结构设计

    摘要 如何打造出一个能支撑海量的并发访问的分布式 MySQL 架构,本系列博文将从一下多个方面来分析有关MYSQL系统的架构设计相关原理.实际的业务为案例分析,分析实际业务中表使用的字段类型是如何选型 ...

  5. 架构设计复杂度的6个来源

    谈到架构设计,相信每个技术人员都耳熟能详.我总结了三个架构设计相关的特性: 架构设计的思维和程序设计的思维差异很大. 架构设计没有体系化的培训和训练机制. 程序员对架构设计的理解存在很多误区. 所以, ...

  6. 小工匠聊架构 - 如何优雅的做系统架构设计01

    文章目录 目标 目标 清楚地理解架构设计相关的概念.本质.目的,避免架构师在实践过程中把握不住重点.分不清主次,眉毛胡子一把抓,导致架构设计变形或者"四不像" 掌握通用的架构设计原 ...

  7. java开发架构设计_跪了!阿里技术官出品:Java架构设计之完美,看完秒进大厂。...

    写在前面 "给我一个支点,我就能撬起地球".关键不在于力量有多大,而在于如何合理地利用力量.软件设计同样如此.思想的确立,技巧的把握,将在很大程度上决定软件架构的合理性.内容涵盖了 ...

  8. sql 拆分_实践参考:MySQL架构设计从开发规范、选型、拆分到减压实战指南

    导引 作者,李辉,原新浪爱彩票运维负责人,常用网名:门牙没了.曾主导新浪爱彩票的MySQL运维工作.培训合伙人.资深讲师,中国科学院大学在读研究生(大数据方向),擅长大型项目的关系型数据库运维和管理, ...

  9. 什么是系统架构设计:关于架构演进理论

    什么是系统架构设计:关于架构演进理论 在过去软件开发过程发展的很长一段时间内,软件架构表现为一种集中式的单块(Monolithic)式,即先对系统进行分层,然后通过单个进程进行部署和维护,典型的分层体 ...

最新文章

  1. 框架应用 : Spring - 开发详述
  2. reactor模型_Reactor模式以及Netty中的应用
  3. Django配置bootstrap
  4. 难道计算机专业真的没落
  5. aws rds监控慢sql_如何将AWS RDS SQL Server与AWS Glue连接
  6. 两表查询很慢mysql_影响mysql性能的方面
  7. 封装一个Automapper单例
  8. 深度学习框架PyTorch:入门与实践 学习(二)
  9. html请求接口_Python 如何使用 HttpRunner 做接口自动化测试
  10. 刀片服务器接显示器,认识刀片服务器
  11. SAP顾问简历中常见的英文说法,可能你不太熟悉哦~~
  12. win7 使用扫描仪扫描照片
  13. 关于python搞笑段子精选_搞笑却有哲理的段子
  14. 素食崇尚的是养身和修心的生活方式,鼎沐素食让你身心共融
  15. 前端日期选择器--只选择年或者年月的My97
  16. 详细介绍微软SQL Server 2008
  17. 撕开大促活动内核:前、中、后期的完美操作
  18. u9系统的使用方法仓库_晋江正版用友u9系统使用方法-好不好用
  19. OpenCv案例(一):OpenCvSharp识别图像中物体个数
  20. 使用内网穿透远程连接数据库

热门文章

  1. VUE项目启动:You may use special comments to disable some warnings
  2. centos7 安装nginx报错./configure: error: the HTTP rewrite module requires the PCRE library
  3. 福特牵手百度启动L4级自动驾驶联合测试,年底“上路”
  4. Ajax提交与传统表单提交的区别说明
  5. FRAMESET使用收集
  6. 关于IP SLA及与EEM联动的探讨
  7. django模型sqlserver_SQLServer数据库入门之django如何连接SQLServer
  8. 的input最大长度_LeetCode 84 | 单调栈解决最大矩形问题
  9. python数字替换成中文replace_Python3字符串替换replace(),translate(),re.sub()
  10. Spring-基础设施类