Android源码剖析之Framework层实战版

本文来自 http://blog.csdn.net/liuxian13183/ 

讲到实战,就不得不拿两个例子来说明,本篇想拿的是应用最广泛的两个:Ams和Wms,一个管理activity,一个管理窗口,而前面 我们已经讲了不少,本篇不再赘述。

关于Ams对activity的管理,无非这几个方面: 启动哪个activity、物理按键对activity处理、内存骤减时activity的回收规则,以及暂停activity的一系列操作 。

先说如何启动activity?有哪些知识点。

Ams调度activity,运行某activity需要通过Ams决定,一般情况下仅限允许均可执行;记录运行的页面, 保存activity一些状态,以便下次启动更加快速,一般放在ActivityRecord,以前叫HistoryRecord; 做进程管理,清楚运行哪些进程,各自的状态和信息集合

当然Ams除了管理activity,还会管理其他两个主要数据类,如Process和Task;Process同样也有个ProcessRecord用来记录进程运行信息和状态以及内部有哪些组件(指service、provider这样的),多个apk可以运行在同一进程中,可以通过android:process来设置,一般情况下还是不要,因为手机默认64M内存(不同分辨率不同),内存一般也仅够一个apk使用;而TaskRecord记录activity所在的栈的id、intent和activity的数量,用于对栈进行管理。

AMS常见的默认系统常量:

1、MAX_ACTIVITIES=20: 通过硬件设置,当前页面仅有一个activity存活,其他20个被缓存起来,超过则杀死 优先低的

2、MAX_RECENT_TASKS=20:通过硬件设置,栈最多存储20个,超过后最先舍弃最早的栈

3、PAUSE_TIMEOUT=500:启动activity最长时间为500ms,否则关闭该页面,一般表现是“屏幕黑一下”

4、LAUNCH_TIMEOUT=10*1000:启动进程最长10s,否则舍弃

5、PROC_START_TIMEOUT=10*1000:启动进程后10s内必须报告AMS启动状态,否则AMS不承认此进程的存在

以上是最基础的变量,相信在多年开发中,大家对其引起的现象已经历历在目

其次在启动和暂停activity过程中,需要一些变量来保存状态,主要因为AMS是通过Service机制动作,比如

1、mPendingActivityLaunched:即将启动的activity列表

2、mStoppingActivities:A跳入B,B启动后A即被加入此队列,区别于mHistory的A跳入即加入

3、mHistory:所有后台activity,A跳入B即A被加入,或按Home键B被加入,回来按回退键则B被清除;finishing=true

4、mFinishingActivities:上面列表中执行完finish方法的activity,此时并未完全杀死等待被回收

5、mLRUActivities:最近使用的activity,包含mHistory里的activity和已经清除的activity

此外还有HistroyRecord记录mPausingActivity(record对象,记录执行onPause方法的activity),mResumeActivity、mFocusedActvity和mLastPausedActivity等。

上面讲完基础,接下来进程流程,讲讲如何启动Activity?

一般调用方式有四种,点击手机图标、执行startActivityForResult(startActivity同理)、注册硬件监听启动、被action启动

以下是启动Activity的过程和startActivityForResult的启动(startActivity传一个默认的requestCode-1,最后仍然调用startActivityForResult方法,所以放在一起讲)

启动前的权限检查和准备工作

启动Activity的时候往往还需要进行权限检查,以查看其是否符合启动条件。查询不满足条件则返回,否则继续;检查Component是否存在,不满足返回,满足继续,启动startActivityLocked(caller,intent)方法,完成以下几件事

1、检查如果启动自己则直接返回

2、会更INTENT_FLAG_FORWARD_RESULT标志,用于从C直接返回结果给A,使用方法A调用startActivityForResut->B调用startActivity->C调用setResult直接回到A

3、检查call-ActivityRecord是否存在且有指定权限

4、如果Ams中有IActivityController对象,则通知Controller进行相应控制

5、创建临时HistoryRecord对象,不一定加入mHistory列表

6、检查是否允许切换activity,否则加入mPendingActivityLaunched

7、判断pendingActivity是否有要启动的activity,有则先执行,无则执行该intent

如想了解launchMode,请移步:

Android基础之Activity launchMode详解

以上是对intent的介绍,接下来会再介绍一下task,也就是如何启动,以什么样的规则启动和退出。以下均指launchFlag,标记均以FLAG_ACTIVITY_开头,介绍时会忽略,请注意一下;启动时会依次判断如下标识

1、NO_USER_ACTION:含义无用户交互;基本不用,主要防止 一段时间后执行onUserLeaving方法;接下来如果立即启动,就把r.delay.Resume设为true

2、PREVIOUS_IS_TOP:上个标识是否用到,基本不用;然后为activity赋予权限加入缓存;此时区别于launchMode和launchFlag,前者指activity自己声明的启动方式,后者是明显启动者想让activity如何启动,能过intent设置,但两者有相通性

3、NEW_TASK、SINGLE_TASK、SINGLE_INSTANCE:使用这三者均不建议使用startActivityForResut,而只限于使用startActivity即r.resultTo=0,不需要回传数据的情况下;第1个是会新起一个task,即两个task之间最好不进行数据回传;2和3的相同在于,如果已经存在这样的task和component以及其他相同数据如intent,则均跳到相应栈中,不存在则声明一个新的task;不同点在于:2的task里可以包含多个activity,而3仅能包含一个;可能跟每个task内存大小有关,不同功用的activity可以申请不同的task使用,这一点也可以看上面“ Android基本之Activity LaunchMode详解

4、CLEAR_TOP、 REORDER_TO_FRONT :前者如自己存在,则清除该栈上面的其他activity;后者仅把自己放在最上面;举例A1->A2->A3,前者启动A2则变成A1->A2,后者启动则变成A1->A3->A2

5、NO_HISTORY:不要保存自己,A1->A2要启动A3然后A4,执行完还是A1->A2。

以上如果调整栈的顺序,那么是可以执行的;如A、B、C三个栈,分别有2个activity,如果从C切换到B,那么是这样的

A1->A2->B1->B2->C1->C2,调整后A1->A2->C1->C2->B1->B2。

系统还提供另外一种办法来设置activity的启动方式,那就是

1、android:clearTaskOnLaunch=true/false:是否清除task里的其他activity

2、android:finishOnTaskLaunch:是否关闭task中已有的此activity

3、android:allowTaskReparetn:是否将自己带入启动本task的task中

4、android:alwaysRetainTaskState:是否由系统维护activity状态;一般应用在根activity,每次可以打开最后打开的页面

最近讲的几个东西之间的关系,画了一张图,如下所示

正式启动工作(主要流程均为ActivityThread执行-在attach时初始化)

一、暂停当前activity

1、判断该activity是否存在;然后执行onUserLeaving方法,避免此activity再与物理按键交互,如后退键

2、调用performPauseActivity(告知暂停而非超时等情况,将prev指向自己),先onSaveInstanceState,再执行onPause

·3、报告AMS暂停完毕,通过IPC调用AMS的completePauseActivity方法

二、调用resumeTopActivity方法:

1、如果mHistory有记录且直接启动,否则执行startHomeActivityLocked方法启动主界面程序;

2、系统处于睡眠状态或当前activity未被暂停,则停止;

3、从mStoppingActivities和mWarningVisibleActivities里移除目标对象;

4、将被停止的activity设置为不可见状态,通知activty或task切换

5、判断目录进程是否存在并且activityThread存活,否则执行startSpecificActivityLocked方法;如果进程不存在,则调用

Process类启动新进程,设置pid加入ProcessRecord,启动完之后再通知Ams启动目标Activity,至于启动Process的过程跟调用

暂停 或启用activity的过程无异,仅仅参数发生变化而已,以及变量不同和意义不同。当然我们再讲一点,启动进程毕竟是个重要

流程,提取odex文件,前面几篇文章有过介绍,指已经优化过的dex文件,通过Service、Provider和Broadcast加入引用,创建

完成。

6、最终调用performLaunchActivity,执行attach,执行setTheme,几个on方法,拿到decorView加入Wms,设置可见

接下来咱们讲讲停止工作: 一般情况下是长时间不使用,或者应用内存紧张,或者启动时设置no_history才会执行,执行过程

而应用与上面生命周期无异,也就是设置不可见,加个mStoppingActivities,异步通知Ams停止,最后调用onStop方法等等,

关闭activity也同样如此; 至于关闭的 优先级前面似乎没讲, 接下来 会着重介绍一下。

Android系统如何管理自己内存的? 同样可以预习一下,原理协同,再做补充。

一般情况下优化级分为-16到15级,而android默认仅使用0-15级,越小优先级越高,当前可见activity最高为0。

为什么会产生这个优化级,主要android采用的是关闭而不退出,退出而不清理的原则,主要为了二次加载更加快速;其次是上面

停止activity的原因。而这个规则由Ams加权得出,有这样几个变量:是否展示在当前页或是持久化activity、相应的配合组件、剩余

内存量、HOME进程、活跃 activity数量和组件等,就像JVM的内存管理规则一样,详见: Java高级之虚拟机垃圾回收机制

由于Ams无法预知内存的变动(OOM除外),因而采用这套机制:最先是空进程(无activity进程),其次是activity,再次

是前台的配合组件,如Service、Receiver、Provider,最后才是前台activity;而这些操作由OOM Killer进程直接管理,关于

activity回收需要满足以下几种情况:

1、finish操作或crash或anr,通过updateOomAdjLocked方法让其指定优先级,动态调整

2、如果运行的activity超过20个,必须是已经stop的、不可见的、非常驻进程

因而不合理的手机架构也会造成系统的崩溃。PS:持久化对象的在ProcessRecord的persistent变量是否为true

LocalActivityManager存在于Activity内部,用来装载和管理activity以及各种状态,维持一个最低的内存消耗;核心在于它

使用UI线程的activityThread来装载指定的 activity;有同学可能会问task越少或者histroyRecord越小,内存会占用越小吗?这个

问题跟手机里装一个app和装n个app重量是否增加是一样的道理,但是越过限制以后(task允许)内存占用确实会变大,直到出现

OOM。

以下是按键方面的内容(锁屏下,基本均不操作)

1、后退键:Activity里监听到onBackPressed方法;一般执行的是finish动作,执行performDestroyActivity方法

2、Home键:Acitivty的onKey方法无法截取它,属于设计原因;Wms中使用PhoneWindowManager类中的interceptKeyTi截取

消息,发现是它,再执行launchHomeFromHotKey;2.0之后添加另一个Home键执行startDockOrHome方法来监听硬件。

与普通的启动区别在于,能启动特殊的intent,方法在ContextImpl里。而长按震动、关闭所有窗口、会弹出LRT-lasted recent 

task,可以调用Ams的getRecentTask来取出,通过弹出的窗体的点击事件,进入相应的应用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
千里马8年Android系统及应用开发经验,曾担任过美国unokiwi公司移动端技术总监兼架构师,对系统开发,性能优化,应用高级开发有深入的研究,Android开源定制ROM Lineage的贡献者之一,国内首家线下开辟培训Android Framework课程,拥有2年的Android系统培训经验。成为腾讯课堂专业负责android framework课程分享第一人,致力于提高国内android Framework水平Android Framework领域内是国内各大手机终端科技公司需要的人才,应用开发者都对Android系统充满着好奇,其中的binder是重中之重,都说无binder无Android,binde是Android系统的任督二脉。课程水平循序渐进,由中级再到高级,满足各个次水平的android开发者。1、灵活使用binder跨进程通信,在app端对它的任何api方法等使用自如2、可以单独分析android系统源码中任何binder部分,分析再也没有难度3、掌握binder驱动本质原理,及对应binder驱动怎么进行跨进程通信,及内存等拷贝方式数据等4、对binder从上的java app端一直到最底的内核binder驱动,都可以顺利理通5、针对系统开发过程中遇到的binder报错等分析方法,及binder bug案例学习6、针对面试官任何的binder问题都可以对答自如7、socket这种跨进程通信实战使用8、针对android源码中使用的socket源码轻松掌握9、android系统源码中最常见的socketpair中双向跨进程通信10、使用socket实现一个可以让app执行shell命令的程序

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值