Android系统流程 v1.3

Zygote的启动过程

1.系统启动init进程时会启动Zygote进程(负责Android运行时进程和应用进程的启动)
2.Zygote进程会首先启动SystemServer进程,SystemServer进程会启动系统的关键服务(PMS和AMS)
3.当启动应用程序时,AMS通过socket向Zygote通知创建新的进程

Android应用程序安装进程

  • 系统启动安装过程
  1. SystemServer进程启动PackageManagerService服务实例,添加到ServiceManager(负责管理系统中的Binder对象)

  2. PackageManagerService.main()扫描指定目录的apk归档文件

/system/framework
/system/app
/vendor/app
/data/app
/data/app-private
  1. 对apk文件解析AndroidManifest.xml各个标签,得到的package、provider、service、receiver和activity等信息保存在PackageManagerService服务的内存中。
  • 下载安装过程
    下载apk->拷贝到指定目录->解析apk归档文件的AndroidManifest.xml的应用程序的信息到packageManagerServices中

应用程序启动流程

  1. Launcher通过Binder进程间通信机制通知ActivityManagerService,它要启动一个Activity;
  2. ActivityManagerService通过Binder进程间通信机制通知Launcher进入Paused状态;
  3. Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态,于是ActivityManagerService就创建一个新的进程,用来启动一个ActivityThread实例,即将要启动的Activity就是在这个ActivityThread实例中运行;
  4. ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给ActivityManagerService,以便以后ActivityManagerService能够通过这个Binder对象和它进行通信;
  5. AMS通知ActivityThread对象中调用bindApplication()方法. 送到消息队列中, 最终通过handleBindApplication()方法处理该消息. 然后调用makeApplication()方法来加载Application的classes到内存中,然后通知AMS。
  6. ActivityManagerService通过Binder进程间通信机制通知ActivityThread,可以真正执行Activity的启动。

Launcher启动过程

  1. SystemServer进程启动ActivityManagerService服务实例,添加到ServiceManager(负责管理系统中的Binder对象)
  2. ActivityManagerService向PackageManagerService查询Category类型为HOME的Activity,通过 ActivityStack.startActivityLocked将Launcher启动起来
  3. Launcher在onCreate()中,通过这个PackageManagerService.queryIntentActivities接口来取回所有Action类型为Intent.ACTION_MAIN,并且Category类型为Intent.CATEGORY_LAUNCHER的Activity。显示这些到页面上。

Activity启动流程

  1. AMS创建新进程,创建ActivityThread实例,将ApplicationThread的Binder对象传递给AMS并且开始了消息循环。
  2. 从新进程调用到ActivityManagerService进程中,获取要在新进程启动的服务的相关信息;
  3. 从ActivityManagerService进程又回到新进程中,最终将服务启动起来。
    3.1. performLaunchActivity()初始化Activity
     3.1.1 classLoader加载Activity类,mInstrumentation.newActivity实例化Activity
     3.1.2 makeApplication如果进程中没有就重新创建
     3.1.3 Activity.attach()将上下文信息设置到Activity中 包括window创建
     3.1.4 mInstrumentation.callActivityOnCreate->onCreate()调用setContentView为decorView设置页面内容
     3.1.5 Instrumentation.callActivityOnStart->onStart() 初始化应用数据准备
    3.2 handleResumeActivity激活Activity
     3.2.1 mInstrumentation.callActivityOnResume->onResume()做准备显示到交互的处理
     3.2.2 wm.addView添加window的decorView开始绘制显示页面交互

Service启动流程

service将计算型的逻辑单独放在一个进程内执行提高用户体验。

start流程

  1. AMS创建新进程(会判断ProcessRecord不存在才去创建),创建ActivityThread实例,将ApplicationThread的Binder对象传递给AMS并且开始了消息循环。
  2. 从新进程调用到ActivityManagerService进程中,获取要在新进程启动的服务的相关信息;
  3. 从ActivityManagerService进程又回到新进程中,最终将服务启动起来。
    3.1 handleCreateService()初始化Service
     3.1.1 通过ClassLoader加载service类,然后的newInstance实例化Service
     3.1.2 makeApplication如果进程中没有就重新创建
     3.1.3 service.attach() 上下文信息设置到service中
     3.1.4 service.onCreate()回调
  4. 然后还会回新进程ApplicationThread.scheduleServiceArgs在主线程中回调onStartCommand

bind流程

  1. MainActivity调用bindService函数通知ActivityManagerService,它要启动CounterService这个服务,ActivityManagerService于是在MainActivity所在的进程内部把CounterService启动起来,并且调用它的onCreate函数;
  2. ActivityManagerService把CounterService启动起来后,继续调用CounterService的onBind函数,要求CounterService返回一个Binder对象给它;
  3. ActivityManagerService从CounterService处得到这个Binder对象后,就把它传给MainActivity,即把这个Binder对象作为参数传递给MainActivity内部定义的ServiceConnection对象的onServiceConnected函数;
  4. MainActivity内部定义的ServiceConnection对象的onServiceConnected函数在得到这个Binder对象后,就通过它的getService成同函数获得CounterService接口。

PhoneWindow流程

  1. 在Activity的attach中创建PhoneWindow并完成相关设置
    1.1 调用PolicyManager.makeNewWindow创建PhoneWindow,
    1.2 设置window的Calback将IO输入事件分发给Activity(softMode设置)
    1.3 设置windowManager,mAppToken为ActivityManagerService侧ActivityRecord(Binder对象),mAppName为Activity组件名称
  2. 在onCreate中的setContentView(rId)完成window的视图内容的设置
    2.1 installDecor()根据Theme和Feature完成window的顶级视图mDecor以及找到mContentParent
    2.2 通过mLayoutInflater.inflate(layoutResID, mContentParent)设置到mContentParent中
  3. 在handleResumeActivity()中wm.addView()将window的内容绘制出来
    3.1 WindowManagerImpl.addView将decorView、viewRoot、LayoutParamas分别添加到mViews[i]、mRoots[i]和mParams[I]中
    3.2 viewRootImpl.setView()完成相关成员的配置工作和绘制
     3.2.1 将decorView设置到mAttachInfo.mRootView上
     3.2.2 panelParentView不为空表示window是子窗口,需要保存ApplicationWindowToken到mAttachInfo中
     3.2.3 调用requestLayout()执行view树的绘制流程

View绘制流程

  1. viewRootImpl的requestLayout()和invalidateChildInParent()最终都调用performTraversals()开始执行测量、布局、绘制
  2. mView.measure测量所有view的宽高
    这里就比按照流程叙述了,按照我自己的通俗的理解来讲
    前言:view测量时有限制MeasureSpec。自己的申请(layout_)告诉父亲,父亲根据自己的情况计算家里的情况给出的钱(空间)的使用限制。Mode:家里的情况,Size:到手钱
    自己当爸爸了 viewGroup(详情getChildMeasureSpec)
      家里的情况 Mode,拿到手上有 size大小的钱
  1.不管家里任何情况,只要儿子申请花调固定的数字childDimension>=0,超过限制也给,
儿子的Mode=EXACTLY,Size=childDimension
  2.其他的话看家里情况
            都用掉 EXACTLY: 
                  儿子申请都给我吧 MATCH_PARENT:目标明确,给。儿子的Mode=EXACTLY,Size=size
                  儿子申请我自己算 WRAP_CONTENT:儿子的Model=AT_MOST,Size=size
        家里手头紧不能超过 AT_MOST:
                  不管儿子申请 MATCH_PARENT 还是 WRAP_CONTENT:告诉子孙们手头紧Mode=AT_MOST,Size=size
         不知道啥情况,但是手动有钱 UNSPECIFIED:
                 不管儿子申请 MATCH_PARENT 还是 WRAP_CONTENT:告诉子孙们家里不知道啥情况Mode=UNSPECIFIED,Size=size      

自己绝育了View,祖宗传下来过日子之法 (详情resolveSize)

看家里情况
            要你都用掉 EXACTLY: 
                  都用光
        家里手头紧不能超过 AT_MOST:
                  自己用多少算多少吧,不超过就行
         不知道啥情况,但是手动有钱 UNSPECIFIED:
                   没限制,自己用多少算多少
  1. mView.layout 递归View树 根据viewGroup的layout规则设置所有子View的位置
    3.1 ViewGroup必须重写onLayout,根据排列规则以及measure测量的宽高调用child.layout对子View进行设置
    3.2 View的layout中调用setFrame完成对mLeft、mTop、mRight和mBottom赋值
    总结:所有的View都得靠父布局通过自己的margin等相对规则确定位置
  2. mView.draw 递归View树绘制所有view到canvas上
    4.1 draw()控制整体绘制流程,可被重写
    4.2 drawBackground()绘制背景,不可被重写
    4.3 ondraw()绘制主体,可被重写
    4.4 dispatchDraw() 主要给ViewGroup重写分配给子View绘制,可重写
    4.5 绘制滚动条和前景 在6.0合并到onDrawForeground(),可被重写

ps:其实还有一个draw被ViewGroup通过drawChild调用,这个draw拿到的canvas是完整的父View的canvas,应用view动画的矩阵之后在整个canvas里裁剪对应view位置和大小的一块canvas交给处理view自身绘制流程的draw方法

应用事件分发流程

通过View树传递触摸事件,一旦有View消费掉事件就不会继续向下传递,如果没有消费掉就会往上抛交给父View处理。down事件被View消费之后,后面连续的事件都会交给它处理。

  • Activity事件分发
  1. phoneWindow将事件回调Activity的dispatchTouchEvent()分发事件
  2. 如果Event是ACTION_DOWN的情况下会接着触发onUserInteraction方法。
  3. 分发给mContentParent的子View处理事件
  4. 若子view拦截了事件(返回true)则Activity.onTouchEvent方法就不会执行。
  • ViewGroup事件分发
  1. dispatchTouchEvent 分发处理事件
  2. 通过disallowIntercept先判断子View是否不让ViewGroup拦截事件
  3. onInterceptTouchEvent()判断当前ViewGroup是否需要拦截该事件
  4. 不拦截就直接dispatchTransformedTouchEvent()分发给子View处理,如果子View没有处理就继续交给自己逻辑
  5. 拦截就交给自己处理,交给super.dispatchTochEvent()处理
  • View事件分发
  1. dispatchTouchEvent 分发处理事件
  2. 如果view可用则调用mOnTouchListener(可消费调触摸事件)
  3. 在onTochEvent中处理事件
    3.1 如果view是disable且是cliable 则直接消费调事件
    3.2 如果是enable且discliable直接返回 不消费事件
    3.3 如果是enable且cliable则处理消费事件逻辑,如up事件就会触发clickListner

总结:view要消费调Down事件才会接受到后续事件,而事件达到view时可以被责任链里的ViewGroup拦截掉,一旦拦截掉后续的任何一个事件对View来说就不完整了,所以为了保证view可以获取所有事件,可以声明不让他们拦截自己的事件。自己也不要在onTouchListner里随便拦截会影响onTouchEvent的正常处理的。如果没有view处理就会向上继续传播处理

部分学习自老罗的博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容