欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android线程管理之ActivityThread

程序员文章站 2024-02-19 11:49:34
activitythread功能 它管理应用进程的主线程的执行(相当于普通java程序的main入口函数),并根据ams的要求(通过iapplicationthread接...

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