当前位置: 移动技术网 > 移动技术>移动开发>Android > Android线程管理之ActivityThread

Android线程管理之ActivityThread

2019年07月24日  | 移动技术网移动技术  | 我要评论

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()方法进行回收。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网