Android线程管理之ActivityThread
activitythread功能
它管理应用进程的主线程的执行(相当于普通java程序的main入口函数),并根据ams的要求(通过iapplicationthread接口,ams为client、activitythread.applicationthread为server)负责调度和执行activities、broadcasts和其它操作。
在android系统中,在默认情况下,一个应用程序内的各个组件(如activity、broadcastreceiver、service)都会在同一个进程(process)里执行,且由此进程的【主线程】负责执行。
在android系统中,如果有特别指定(通过android:process),也可以让特定组件在不同的进程中运行。无论组件在哪一个进程中运行,默认情况下,他们都由此进程的【主线程】负责执行。
【主线程】既要处理activity组件的ui事件,又要处理service后台服务工作,通常会忙不过来。为了解决此问题,主线程可以创建多个子线程来处理后台服务工作,而本身专心处理ui画面的事件。
【主线程】的主要责任:
• 快速处理ui事件。而且只有它才处理ui事件, 其它线程还不能存取ui画面上的对象(如textview等),此时, 主线程就叫做ui线程。基本上,android希望ui线程能根据用户的要求做出快速响应,如果ui线程花太多时间处理后台的工作,当ui事件发生时,让用户等待时间超过5秒而未处理,android系统就会给用户显示anr提示信息。
只有ui线程才能执行view派生类的ondraw()函数。
• 快速处理broadcast消息。【主线程】除了处理ui事件之外,还要处理broadcast消息。所以在broadcastreceiver的onreceive()函数中,不宜占用太长的时间,否则导致【主线程】无法处理其它的broadcast消息或ui事件。如果占用时间超过10秒, android系统就会给用户显示anr提示信息。
注意事项:
• 尽量避免让【主线程】执行耗时的操作,让它能快速处理ui事件和broadcast消息。
• broadcastreceiver的子类都是无状态的,即每次启动时,才会创建其对象,然后调用它的onreceive()函数,当执行完onreceive()函数时,就立即删除此对象。由于每次调用其函数时,会重新创建一个新的对象,所以对象里的属性值,是无法让各函数所共享。
一:线程通信、activitythread及thread类是理解android线程管理的关键。
线程,作为cpu调度资源的基本单位,在android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用。本小节主要从以下三个方面进行分析:
1.《android线程管理——线程通信》
2.《android线程管理——activitythread》
3.《android线程管理——thread类的内部原理、休眠及唤醒》
--------------------------------------------------------------------------------
二、activitythread的主要工作及实现机制
activitythread是android应用的主线程(ui线程),说起activitythread,不得不提到activity的创建、启动过程以及activitymanagerservice,但本文将仅从线程管理的角度来分析activitythread。activitymanagerservice、activitystack、applicationthread等会在后续文章中详细分析,敬请期待喔~~不过为了说清楚activitythread的由来,还是需要简单介绍下。
以下引用自罗升阳大师的博客:《android应用程序的activity启动过程简要介绍和学习计划》
step 1. 无论是通过launcher来启动activity,还是通过activity内部调用startactivity接口来启动新的activity,都通过binder进程间通信进入到activitymanagerservice进程中,并且调用activitymanagerservice.startactivity接口;
step 2. activitymanagerservice调用activitystack.startactivitymaywait来做准备要启动的activity的相关信息;
step 3. activitystack通知applicationthread要进行activity启动调度了,这里的applicationthread代表的是调用activitymanagerservice.startactivity接口的进程,对于通过点击应用程序图标的情景来说,这个进程就是launcher了,而对于通过在activity内部调用startactivity的情景来说,这个进程就是这个activity所在的进程了;
step 4. applicationthread不执行真正的启动操作,它通过调用activitymanagerservice.activitypaused接口进入到activitymanagerservice进程中,看看是否需要创建新的进程来启动activity;
step 5. 对于通过点击应用程序图标来启动activity的情景来说,activitymanagerservice在这一步中,会调用startprocesslocked来创建一个新的进程,而对于通过在activity内部调用startactivity来启动新的activity来说,这一步是不需要执行的,因为新的activity就在原来的activity所在的进程中进行启动;
step 6. activitymanagerservic调用applicationthread.schedulelaunchactivity接口,通知相应的进程执行启动activity的操作;
step 7. applicationthread把这个启动activity的操作转发给activitythread,activitythread通过classloader导入相应的activity类,然后把它启动起来。
大师的这段描述把activitymanagerservice、activitystack、applicationthread及activitythread的调用关系讲的很清楚,本文将从activitythread的main()方法开始分析其主要工作及实现机制。
activitythread源码来自:https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/activitythread.java
public static void main(string[] args) { trace.tracebegin(trace.trace_tag_activity_manager, "activitythreadmain"); samplingprofilerintegration.start(); // closeguard defaults to true and can be quite spammy. we // disable it here, but selectively enable it later (via // strictmode) on debug builds, but using dropbox, not logs. closeguard.setenabled(false); environment.initforcurrentuser(); // set the reporter for event logging in libcore eventlogger.setreporter(new eventloggingreporter()); androidkeystoreprovider.install(); // make sure trustedcertificatestore looks in the right place for ca certificates final file configdir = environment.getuserconfigdirectory(userhandle.myuserid()); trustedcertificatestore.setdefaultuserdirectory(configdir); process.setargv0("<pre-initialized>"); looper.preparemainlooper(); activitythread thread = new activitythread(); thread.attach(false); if (smainthreadhandler == null) { smainthreadhandler = thread.gethandler(); } if (false) { looper.mylooper().setmessagelogging(new logprinter(log.debug, "activitythread")); } // end of event activitythreadmain. trace.traceend(trace.trace_tag_activity_manager); looper.loop(); throw new runtimeexception("main thread loop unexpectedly exited"); }
上述代码中,红色部分之前的代码主要用于环境初始化、androidkeystoreprovider安装等,这里不做重点说明。红色部分的代码主要分为两个功能块:1)绑定应用进程到activitymanagerservice;2)主线程handler消息处理。
关于线程通信机制,handler、messagequeue、message及looper四者的关系请参考上一篇文章《android线程管理——线程通信》。
2.1 应用进程绑定
main()方法通过thread.attach(false)绑定应用进程。activitymanagernative通过getdefault()方法返回activitymanagerservice实例,activitymanagerservice通过attachapplication将applicationthread对象绑定到activitymanagerservice,而applicationthread作为binder实现activitymanagerservice对应用进程的通信和控制。
private void attach(boolean system) { scurrentactivitythread = this; msystemthread = system; if (!system) { …… runtimeinit.setapplicationobject(mappthread.asbinder()); final iactivitymanager mgr = activitymanagernative.getdefault(); try { mgr.attachapplication(mappthread); } catch (remoteexception ex) { // ignore } …… } else { …… } }
在activitymanagerservice内部,attachapplication实际是通过调用attachapplicationlocked实现的,这里采用了synchronized关键字保证同步。
@override public final void attachapplication(iapplicationthread thread) { synchronized (this) { int callingpid = binder.getcallingpid(); final long origid = binder.clearcallingidentity(); attachapplicationlocked(thread, callingpid); binder.restorecallingidentity(origid); } }
attachapplicationlocked的实现较为复杂,其主要功能分为两部分:
thread.bindapplication
mstacksupervisor.attachapplicationlocked(app)
private final boolean attachapplicationlocked(iapplicationthread thread, int pid) { // find the application record that is being attached... either via // the pid if we are running in multiple processes, or just pull the // next app record if we are emulating process with anonymous threads. processrecord app; if (pid != my_pid && pid >= 0) { synchronized (mpidsselflocked) { app = mpidsselflocked.get(pid); } } else { app = null; } // …… try { // …… thread.bindapplication(processname, appinfo, providers, app.instrumentationclass, profilerinfo, app.instrumentationarguments, app.instrumentationwatcher, app.instrumentationuiautomationconnection, testmode, enableopengltrace, enabletrackallocation, isrestrictedbackupmode || !normalmode, app.persistent, new configuration(mconfiguration), app.compat, getcommonserviceslocked(app.isolated), mcoresettingsobserver.getcoresettingslocked()); updatelruprocesslocked(app, false, null); app.lastrequestedgc = app.lastlowmemory = systemclock.uptimemillis(); } catch (exception e) { // todo: yikes! what should we do? for now we will try to // start another process, but that could easily get us in // an infinite loop of restarting processes... slog.wtf(tag, "exception thrown during bind of " + app, e); app.resetpackagelist(mprocessstats); app.unlinkdeathrecipient(); startprocesslocked(app, "bind fail", processname); return false; } // see if the top visible activity is waiting to run in this process... if (normalmode) { try { if (mstacksupervisor.attachapplicationlocked(app)) { didsomething = true; } } catch (exception e) { slog.wtf(tag, "exception thrown launching activities in " + app, e); badapp = true; } } // …… }
thread对象其实是activitythread里applicationthread对象在activitymanagerservice的代理对象,故此执行thread.bindapplication,最终会调用applicationthread的bindapplication方法。该bindapplication方法的实质是通过向activitythread的消息队列发送bind_application消息,消息的处理调用handlebindapplication方法,handlebindapplication方法比较重要的是会调用如下方法:
minstrumentation.callapplicationoncreate(app);
callapplicationoncreate即调用应用程序application的oncreate()方法,说明application的oncreate()方法会比所有activity的oncreate()方法先调用。
mstacksupervisor为activitymanagerservice的成员变量,类型为activitystacksupervisor。
/** run all activitystacks through this */
activitystacksupervisor mstacksupervisor;
从注释可以看出,mstacksupervisor为activity堆栈管理辅助类实例。activitystacksupervisor的attachapplicationlocked()方法的调用了realstartactivitylocked()方法,在realstartactivitylocked()方法中,会调用schedulelaunchactivity()方法:
final boolean realstartactivitylocked(activityrecord r, processrecord app, boolean andresume, boolean checkconfig) throws remoteexception { //... try { //... app.thread.schedulelaunchactivity(new intent(r.intent), r.apptoken, system.identityhashcode(r), r.info, new configuration(mservice.mconfiguration), r.compat, r.icicle, results, newintents, !andresume, mservice.isnexttransitionforward(), profilefile, profilefd, profileautostop); //... } catch (remoteexception e) { //... } //... return true; }
app.thread也是applicationthread对象在activitymanagerservice的一个代理对象,最终会调用applicationthread的schedulelaunchactivity方法。
// we use token to identify this activity without having to send the // activity itself back to the activity manager. (matters more with ipc) @override public final void schedulelaunchactivity(intent intent, ibinder token, int ident, activityinfo info, configuration curconfig, configuration overrideconfig, compatibilityinfo compatinfo, string referrer, ivoiceinteractor voiceinteractor, int procstate, bundle state, persistablebundle persistentstate, list<resultinfo> pendingresults, list<referrerintent> pendingnewintents, boolean notresumed, boolean isforward, profilerinfo profilerinfo) { updateprocessstate(procstate, false); activityclientrecord r = new activityclientrecord(); …… sendmessage(h.launch_activity, r); }
同bindapplication()方法,最终是通过向activitythread的消息队列发送消息,在activitythread完成实际的launch_activity的操作。
public void handlemessage(message msg) { if (debug_messages) slog.v(tag, ">>> handling: " + codetostring(msg.what)); switch (msg.what) { case launch_activity: { trace.tracebegin(trace.trace_tag_activity_manager, "activitystart"); final activityclientrecord r = (activityclientrecord) msg.obj; r.packageinfo = getpackageinfonocheck( r.activityinfo.applicationinfo, r.compatinfo); handlelaunchactivity(r, null); trace.traceend(trace.trace_tag_activity_manager); } break; …… }
handlelaunchactivity()用于启动activity。具体的启动流程不在这里详述了,这里重点说明applicationthread及activitythread的线程通信机制。
2.2 主线程消息处理
在《android线程管理——线程通信》中谈到了普通线程中handler、messagequeue、message及looper四者的关系,那么,activitythread中的线程通信又有什么不同呢?不同之处主要表现为两点:1)looper的初始化方式;2)handler生成。
首先,activitythread通过looper.preparemainlooper()初始化looper,为了直观比较activitythread与普通线程初始化looper的区别,把两种初始化方法放在一起:
/** initialize the current thread as a looper. * this gives you a chance to create handlers that then reference * this looper, before actually starting the loop. be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ public static void prepare() { prepare(true); } private static void prepare(boolean quitallowed) { if (sthreadlocal.get() != null) { throw new runtimeexception("only one looper may be created per thread"); } sthreadlocal.set(new looper(quitallowed)); } /** * initialize the current thread as a looper, marking it as an * application's main looper. the main looper for your application * is created by the android environment, so you should never need * to call this function yourself. see also: {@link #prepare()} */ public static void preparemainlooper() { prepare(false); synchronized (looper.class) { if (smainlooper != null) { throw new illegalstateexception("the main looper has already been prepared."); } smainlooper = mylooper(); } }
•普通线程的prepare()方法默认quitallowed参数为true,表示允许退出,activitythread在preparemainlooper()方法中调用prepare()方法,参数为false,表示主线程不允许退出。
•普通线程只调用prepare()方法,activitythread在调用完prepare()方法之后,会通过mylooper()方法将本地线程<threadlocal>的looper对象的引用交给smainlooper。mylooper()其实就是调用sthreadlocal的get()方法实现的。
/** * return the looper object associated with the current thread. returns * null if the calling thread is not associated with a looper. */ public static looper mylooper() { return sthreadlocal.get(); }
•之所以要通过smainlooper指向activitythread的looper对象,就是希望通过getmainlooper()方法将主线程的looper对象开放给其他线程。
/** returns the application's main looper, which lives in the main thread of the application. */ public static looper getmainlooper() { synchronized (looper.class) { return smainlooper; } }
其次,activitythread与普通线程的handler生成方式也不一样。普通线程生成一个与looper绑定的handler即可,activitythread通过smainthreadhandler指向gethandler()的返回值,而gethandler()方法返回的其实是一个继承handler的h对象。。
private class h extends handler { …… } final h mh = new h(); final handler gethandler() { return mh; }
真正实现消息机制“通”信的其实是looper的loop()方法,loop()方法的核心实现如下:
/** * run the message queue in this thread. be sure to call * {@link #quit()} to end the loop. */ public static void loop() { final looper me = mylooper(); if (me == null) { throw new runtimeexception("no looper; looper.prepare() wasn't called on this thread."); } final messagequeue queue = me.mqueue; // make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. binder.clearcallingidentity(); final long ident = binder.clearcallingidentity(); for (;;) { message msg = queue.next(); // might block if (msg == null) { // no message indicates that the message queue is quitting. return; } // this must be in a local variable, in case a ui event sets the logger printer logging = me.mlogging; if (logging != null) { logging.println(">>>>> dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } msg.target.dispatchmessage(msg); if (logging != null) { logging.println("<<<<< finished to " + msg.target + " " + msg.callback); } // make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newident = binder.clearcallingidentity(); if (ident != newident) { log.wtf(tag, "thread identity changed from 0x" + long.tohexstring(ident) + " to 0x" + long.tohexstring(newident) + " while dispatching to " + msg.target.getclass().getname() + " " + msg.callback + " what=" + msg.what); } msg.recycle(); } }
大致流程如下:
•首先通过上述mylooper()方法获取looper对象,取出looper持有的messagequeue;
•然后从messagequeue取出message,如果message为null,说明线程正在退出;
•message不为空,则调用message的target handler对该message进行分发,具体分发、处理流程可参考《android线程管理——线程通信》;
•消息处理完毕,调用recycle()方法进行回收。
上一篇: 老生常谈Java动态编译(必看篇)