Android消息循环机制(一)android app 是怎么启动起来的以及Looper、MessageQueue和Handler机制的源码分析

    xiaoxiao2022-07-14  149

    我们都知道点击icon图标可以启动app,那这个过程到底做了什么呢?

    展示所有app icon图标的app叫launcher,也是一个app,点击某个app的icon,逻辑在launcher的进程中处理,其实就是调用startActivity,startActivity其实封装了binder机制,实现进程调用,通知到ActivityManagerService(AMS,AMS是framework框架提供的),AMS在另一个进程中(它是在SystemServer进程中的,而SystemServer进程是被zygote进程启动的超级进程,也是被zygote启动的第一个进程,它启动所有系统核心服务,AMS只是其中之一),AMS拿到从startActivity传过来的Intent,解析后,创建一个新的进程(通过linux的fork函数复制zygote进程实现的),然后就会创建一个主线程,加载ActivityThread.class文件,里面有main方法,程序就真正从这里执行。

    主线程和ActivityThread的关系。Android的UI主线程是ActivityThread吗?

    ActivityManagerService是在FrameWork层的,出于安全考虑不对外暴露,不过提供ActivityManager类变相的和ActivityManagerService打交道。看看文档对ActivityManager的定义。Interact with the overall activities running in the system.

    详细完整的app启动过程,看这篇文章Android启动流程 、app安装和启动原理

    我们先提出几个问题,后续的分析,就为了回答这些问题,这样目的性强。如果没有目的的分析,最终只能是似懂非懂。

    (1)为什么说默认new出来的Handler是运行在主线程中的?

    (2)一个线程可以有几个Looper?几个MessageQueue?几个Handler?

    (3)Looper、MessageQueue、Handler之间运行的原理?

    (4)主线程是怎么运行的?

    (5)为什么主线程中的Looper.loop()死循环不会导致程序卡死(ANR)呢?

    我们就从ActivityThread的main函数开始,顺着执行顺序分析

    6041 public static void main(String[] args) { 6042 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); 6043 SamplingProfilerIntegration.start(); 6044 6045 // CloseGuard defaults to true and can be quite spammy. We 6046 // disable it here, but selectively enable it later (via 6047 // StrictMode) on debug builds, but using DropBox, not logs. 6048 CloseGuard.setEnabled(false); 6049 6050 Environment.initForCurrentUser(); 6051 6052 // Set the reporter for event logging in libcore 6053 EventLogger.setReporter(new EventLoggingReporter()); 6054 6055 // Make sure TrustedCertificateStore looks in the right place for CA certificates 6056 final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); 6057 TrustedCertificateStore.setDefaultUserDirectory(configDir); 6058 6059 Process.setArgV0("<pre-initialized>"); 6060 6061 Looper.prepareMainLooper(); 6062 6063 ActivityThread thread = new ActivityThread(); 6064 thread.attach(false); 6065 6066 if (sMainThreadHandler == null) { 6067 sMainThreadHandler = thread.getHandler(); //其实获取到的就是mH 6068 } 6069 6070 if (false) { 6071 Looper.myLooper().setMessageLogging(new 6072 LogPrinter(Log.DEBUG, "ActivityThread")); 6073 } 6074 6075 // End of event ActivityThreadMain. 6076 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 6077 Looper.loop(); 6078 6079 throw new RuntimeException("Main thread loop unexpectedly exited"); 6080 }

    (1)分析Looper.prepareMainLooper(); 

    prepareMainLooper是Looper的静态方法,Looper代码不多,而且里面的代码都很重要,索性就都粘过来。

    17package android.os; 18 19import android.util.Log; 20import android.util.Printer; 21import android.util.PrefixPrinter; 22 23/** 24 * Class used to run a message loop for a thread. Threads by default do 25 * not have a message loop associated with them; to create one, call 26 * {@link #prepare} in the thread that is to run the loop, and then 27 * {@link #loop} to have it process messages until the loop is stopped. 28 * 29 * <p>Most interaction with a message loop is through the 30 * {@link Handler} class. 31 * 32 * <p>This is a typical example of the implementation of a Looper thread, 33 * using the separation of {@link #prepare} and {@link #loop} to create an 34 * initial Handler to communicate with the Looper. 35 * 36 * <pre> 37 * class LooperThread extends Thread { 38 * public Handler mHandler; 39 * 40 * public void run() { 41 * Looper.prepare(); 42 * 43 * mHandler = new Handler() { 44 * public void handleMessage(Message msg) { 45 * // process incoming messages here 46 * } 47 * }; 48 * 49 * Looper.loop(); 50 * } 51 * }</pre> 52 */ 53public class Looper { 54 private static final String TAG = "Looper"; 55 56 // sThreadLocal.get() will return null unless you've called prepare(). 57 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 58 59 final MessageQueue mQueue; 60 final Thread mThread; 61 volatile boolean mRun; 62 63 private Printer mLogging = null; 64 private static Looper mMainLooper = null; // guarded by Looper.class 65 66 /** Initialize the current thread as a looper. 67 * This gives you a chance to create handlers that then reference 68 * this looper, before actually starting the loop. Be sure to call 69 * {@link #loop()} after calling this method, and end it by calling 70 * {@link #quit()}. 71 */ 72 public static void prepare() { 73 if (sThreadLocal.get() != null) { 74 throw new RuntimeException("Only one Looper may be created per thread"); 75 } 76 sThreadLocal.set(new Looper()); 77 } 78 79 /** 80 * Initialize the current thread as a looper, marking it as an 81 * application's main looper. The main looper for your application 82 * is created by the Android environment, so you should never need 83 * to call this function yourself. See also: {@link #prepare()} 84 */ 85 public static void prepareMainLooper() { 86 prepare(); 87 setMainLooper(myLooper()); 88 myLooper().mQueue.mQuitAllowed = false; 89 } 90 91 private synchronized static void setMainLooper(Looper looper) { 92 mMainLooper = looper; 93 } 94 95 /** Returns the application's main looper, which lives in the main thread of the application. 96 */ 97 public synchronized static Looper getMainLooper() { 98 return mMainLooper; 99 } 100 101 /** 102 * Run the message queue in this thread. Be sure to call 103 * {@link #quit()} to end the loop. 104 */ 105 public static void loop() { 106 Looper me = myLooper(); 107 if (me == null) { 108 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 109 } 110 MessageQueue queue = me.mQueue; 111 112 // Make sure the identity of this thread is that of the local process, 113 // and keep track of what that identity token actually is. 114 Binder.clearCallingIdentity(); 115 final long ident = Binder.clearCallingIdentity(); 116 117 while (true) { 118 Message msg = queue.next(); // might block 119 if (msg != null) { 120 if (msg.target == null) { 121 // No target is a magic identifier for the quit message. 122 return; 123 } 124 125 long wallStart = 0; 126 long threadStart = 0; 127 128 // This must be in a local variable, in case a UI event sets the logger 129 Printer logging = me.mLogging; 130 if (logging != null) { 131 logging.println(">>>>> Dispatching to " + msg.target + " " + 132 msg.callback + ": " + msg.what); 133 wallStart = SystemClock.currentTimeMicro(); 134 threadStart = SystemClock.currentThreadTimeMicro(); 135 } 136 137 msg.target.dispatchMessage(msg); 138 139 if (logging != null) { 140 long wallTime = SystemClock.currentTimeMicro() - wallStart; 141 long threadTime = SystemClock.currentThreadTimeMicro() - threadStart; 142 143 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); 144 if (logging instanceof Profiler) { 145 ((Profiler) logging).profile(msg, wallStart, wallTime, 146 threadStart, threadTime); 147 } 148 } 149 150 // Make sure that during the course of dispatching the 151 // identity of the thread wasn't corrupted. 152 final long newIdent = Binder.clearCallingIdentity(); 153 if (ident != newIdent) { 154 Log.wtf(TAG, "Thread identity changed from 0x" 155 + Long.toHexString(ident) + " to 0x" 156 + Long.toHexString(newIdent) + " while dispatching to " 157 + msg.target.getClass().getName() + " " 158 + msg.callback + " what=" + msg.what); 159 } 160 161 msg.recycle(); //注意这里,将这个msg进行回收,放到消息缓冲池里 162 } 163 } 164 } 165 166 /** 167 * Return the Looper object associated with the current thread. Returns 168 * null if the calling thread is not associated with a Looper. 169 */ 170 public static Looper myLooper() { 171 return sThreadLocal.get(); 172 } 173 174 /** 175 * Control logging of messages as they are processed by this Looper. If 176 * enabled, a log message will be written to <var>printer</var> 177 * at the beginning and ending of each message dispatch, identifying the 178 * target Handler and message contents. 179 * 180 * @param printer A Printer object that will receive log messages, or 181 * null to disable message logging. 182 */ 183 public void setMessageLogging(Printer printer) { 184 mLogging = printer; 185 } 186 187 /** 188 * Return the {@link MessageQueue} object associated with the current 189 * thread. This must be called from a thread running a Looper, or a 190 * NullPointerException will be thrown. 191 */ 192 public static MessageQueue myQueue() { 193 return myLooper().mQueue; 194 } 195 196 private Looper() { 197 mQueue = new MessageQueue(); 198 mRun = true; 199 mThread = Thread.currentThread(); 200 } 201 202 public void quit() { 203 Message msg = Message.obtain(); 204 // NOTE: By enqueueing directly into the message queue, the 205 // message is left with a null target. This is how we know it is 206 // a quit message. 207 mQueue.enqueueMessage(msg, 0); 208 } 209 210 /** 211 * Return the Thread associated with this Looper. 212 */ 213 public Thread getThread() { 214 return mThread; 215 } 216 217 /** @hide */ 218 public MessageQueue getQueue() { 219 return mQueue; 220 } 221 222 public void dump(Printer pw, String prefix) { 223 pw = PrefixPrinter.create(pw, prefix); 224 pw.println(this.toString()); 225 pw.println("mRun=" + mRun); 226 pw.println("mThread=" + mThread); 227 pw.println("mQueue=" + ((mQueue != null) ? mQueue : "(null")); 228 if (mQueue != null) { 229 synchronized (mQueue) { 230 long now = SystemClock.uptimeMillis(); 231 Message msg = mQueue.mMessages; 232 int n = 0; 233 while (msg != null) { 234 pw.println(" Message " + n + ": " + msg.toString(now)); 235 n++; 236 msg = msg.next; 237 } 238 pw.println("(Total messages: " + n + ")"); 239 } 240 } 241 } 242 243 public String toString() { 244 return "Looper{" + Integer.toHexString(System.identityHashCode(this)) + "}"; 245 } 246 247 /** 248 * @hide 249 */ 250 public static interface Profiler { 251 void profile(Message message, long wallStart, long wallTime, 252 long threadStart, long threadTime); 253 } 254}

    prepareMainLooper调用prepare,prepare里面采用“线程共享变量”(ThreadLocal,参考ThreadLocal用法详解和原理)的方式在主线程中保存了一个Looper对象,这也就是为什么只是简单地调用了Looper.prepare(),就让当前线程和Looper对象扯上了关系。Looper的构造方法中实例化了MessageQueue,也就是说Looper对象持有MessageQueue对象mQueue,同时Looper对象也持用它所属线程的实例mThread。

    prepareMainLooper中还调用了setMainLooper(myLooper()),首先setMainLooper()是private,此时的myLooper()获取到的Looper对象是主线程中的Looper,setMainLooper就是把主线程中的Looper对象赋给Looper类的static mMainLooper变量。

    我们总结一下,

    (1)Looper类中的mMainLooper引用了主线程的Looper对象 (2)Looper类中有个static final的sThreadLocal字段。通过它能获取到每个线程专属的Looper对象。

    这里说一下,为了要采用ThreadLocal机制保存Looper对象,而不是简单的static变量来持有Looper对象呢?这是因为每个线程都可能有Looper对象,为了保证在当前线程中调用Looper.myLooper()能获取到对应正确的Looper对象。

    分析完Looper的prepareMainLooper方法,我们紧接着先分析一下loop()方法,这个方法是重量级的方法。

    (2)分析Looper.loop()

    我只保留loop方法中的关键代码

    105 public static void loop() { 106 Looper me = myLooper(); 110 MessageQueue queue = me.mQueue; 111 117 while (true) { 118 Message msg = queue.next(); // might block 119 if (msg != null) { 136 .... 137 msg.target.dispatchMessage(msg); 138 .... 161 msg.recycle(); 162 } 163 } 164 }

    先获取到当前线程的Looper实例me,进而获得MessageQueue对象queue,这里面有个死循环,next获得消息队列中的下一个消息,messsage的target其实就是把此message放到MessageQueue中的Handler对象,这点我们会在后续的分析中看到的,所以dispatchMessage是Handler中的方法。如果next没有取到mssage的话,线程就会block。这种消息循环机制让线程中的message顺序执行。

    Androi主线程的这种设计,我觉得是参考了javascript天生的“事件循环”(event loop)的设计,为什么说js的event loop是天生的,是js是单线程的。

    (3)分析thread.attach(false);

    我们看一下简化后的源码

    5041 private void attach(boolean system) { 5042 sCurrentActivityThread = this; 5043 mSystemThread = system; 5044 if (!system) { ... 5054 final IActivityManager mgr = ActivityManagerNative.getDefault(); 5055 try { 5056 mgr.attachApplication(mAppThread); 5057 } catch (RemoteException ex) { 5058 // Ignore 5059 } ... 5081 } else { ... 5096 } 5097 ... 5127 }

    ActivityManagerNative是Android8.0之前的源码,8.0之后已经改成AIDL的方式了。

    ActivityManagerNative为ActivityManagerService的本地调用类,也就是说它是AMS所在进程SystemServer中的Binder服务端,通过ActivityManagerNative.getDefault()返回获取ActivityManagerProxy实例,AMP是AMS在用户进程中的代码,也就是说上面代码中就是远程调用AMS的attachApplication方法。

    先说一下mAppThread是什么和在哪里定义的

    final ApplicationThread mAppThread = new ApplicationThread();

    mAppThread是ActivityThread的成员变量,是ApplicationThread的实例,ApplicationThread是ActivityThread的私有内部类。ApplicationThread继承自ApplicationThreadNative,ApplicationThreadNative是个抽象类,继承自Binder,实现了IApplicationThread接口。ApplicationThreadNative是Android 8.0之前的代码,8.0之后采用了AIDL的实现方式,本质上是一样的,就是实现了一个Binder服务端。

    下面我们分析AMS的attachApplication方法,方法里面调用attachApplicationLocked,这个方法很长,我们依旧是只看我们关系的部分,即和主线程交互的部分

    6029 private final boolean attachApplicationLocked(IApplicationThread thread, 6030 int pid) { ... 6107 try { ... 6160 thread.bindApplication(processName, appInfo, providers, app.instrumentationClass, 6161 profilerInfo, app.instrumentationArguments, app.instrumentationWatcher, 6162 app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace, 6163 isRestrictedBackupMode || !normalMode, app.persistent, 6164 new Configuration(mConfiguration), app.compat, getCommonServicesLocked(), 6165 mCoreSettingsObserver.getCoreSettingsLocked()); ... 6168 } catch (Exception e) { ... 6178 } ... 6247 }

    attachApplicationLocked方法内部调用了IApplicationThread的bindApplication方法,上面已经说过了IApplicationThread是怎么来的了。IApplicationThread其实是ApplicationThread的本地远程调用类(注意:当前是在AMS所在的SystemServer进程中,ApplicationThread是在app进程中),即ActivityManagerService(AMS)进程中调用bindApplication方法最终会通过Binder机制调用到ApplicationThread中的bindApplication方法,上面说过ApplicationThread是ActivityThread的内部类。

    我们看看ApplicationThread中的bindApplication方法

    739 public final void bindApplication(String processName, ApplicationInfo appInfo, 740 List<ProviderInfo> providers, ComponentName instrumentationName, 741 ProfilerInfo profilerInfo, Bundle instrumentationArgs, 742 IInstrumentationWatcher instrumentationWatcher, 743 IUiAutomationConnection instrumentationUiConnection, int debugMode, 744 boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent, 745 Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services, 746 Bundle coreSettings) { 747 ... 791 792 AppBindData data = new AppBindData(); 793 data.processName = processName; 794 data.appInfo = appInfo; 795 data.providers = providers; 796 data.instrumentationName = instrumentationName; 797 data.instrumentationArgs = instrumentationArgs; 798 data.instrumentationWatcher = instrumentationWatcher; 799 data.instrumentationUiAutomationConnection = instrumentationUiConnection; 800 data.debugMode = debugMode; 801 data.enableOpenGlTrace = enableOpenGlTrace; 802 data.restrictedBackupMode = isRestrictedBackupMode; 803 data.persistent = persistent; 804 data.config = config; 805 data.compatInfo = compatInfo; 806 data.initProfilerInfo = profilerInfo; 807 sendMessage(H.BIND_APPLICATION, data); 808 }

    sendMessage(H.BIND_APPLICATION, data)是关键性代码

    2139 private void sendMessage(int what, Object obj) { 2140 sendMessage(what, obj, 0, 0, false); 2141 } 2151 private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) { 2152 if (DEBUG_MESSAGES) Slog.v( 2153 TAG, "SCHEDULE " + what + " " + mH.codeToString(what) 2154 + ": " + arg1 + " / " + obj); 2155 Message msg = Message.obtain(); 2156 msg.what = what; 2157 msg.obj = obj; 2158 msg.arg1 = arg1; 2159 msg.arg2 = arg2; 2160 if (async) { 2161 msg.setAsynchronous(true); 2162 } 2163 mH.sendMessage(msg); 2164 }

    看到这块,我们是不是有种熟悉感,这个是Handler发消息的用法,我们猜想mH应该是一个Handler,确实是这样

    1161 private class H extends Handler { ... 1172 public static final int BIND_APPLICATION = 110; ... 1269 public void handleMessage(Message msg) { 1271 switch (msg.what) { ... 1336 case BIND_APPLICATION: 1337 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication"); 1338 AppBindData data = (AppBindData)msg.obj; 1339 handleBindApplication(data); 1340 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 1341 break; ... 1494 } 1496 } 1497 1523 }

    一开始的时候,我们分析了Looper机制,说明了主线程中是怎么和在什么时候创建Looper和messageQueue的,以及Looper是怎么处理messageQueue中的message的。这个只说了一半,还没有说message是怎么放到messageQueue中的,这个是Handler做的事情,我们接下来分析一下Handler。

    首先从Handler的sendMessage方法分析起,所有的send方法最终都会调用sendMessageAtTime方法,我们直接分析这个方法

    592 public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 593 MessageQueue queue = mQueue; 594 if (queue == null) { 595 RuntimeException e = new RuntimeException( 596 this + " sendMessageAtTime() called with no mQueue"); 597 Log.w("Looper", e.getMessage(), e); 598 return false; 599 } 600 return enqueueMessage(queue, msg, uptimeMillis); 601 }

    这里有个mQueue,这个MessageQueue是怎么来的?从一开始的分析,我们知道MessageQueue是属于Looper的,那我们得先获得Looper。

    我们用Handler最多的方式是new Handler(),注意这种用法是在主线程中用的,子线程一般不这样用。

    113 public Handler() { 114 this(null, false); 115 } 188 public Handler(Callback callback, boolean async) { 189 if (FIND_POTENTIAL_LEAKS) { 190 final Class<? extends Handler> klass = getClass(); 191 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 192 (klass.getModifiers() & Modifier.STATIC) == 0) { 193 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 194 klass.getCanonicalName()); 195 } 196 } 197 198 mLooper = Looper.myLooper(); 199 if (mLooper == null) { 200 throw new RuntimeException( 201 "Can't create handler inside thread that has not called Looper.prepare()"); 202 } 203 mQueue = mLooper.mQueue; 204 mCallback = callback; 205 mAsynchronous = async; 206 }

    通过Looper.myLooper()获得当前线程的Looper,注意我这里说的是当前线程而不是主线程,如果是在主线程中,获得是主线程的Looper,上面说过主线程的Looper是怎么来的了,如果是在子线程中new Handler(),Looper.myLooper()很可能是null,除非你是在HandlerThread中调用Looper.myLooper(),或者自己在Thread中调用过Looper.prepare()和Looper.loop()方法。

    Handler还有提供传入Looper的构造函数,这个是和HandlerThread结合使用的,这个大家都用过,这里就不再赘述。

    回到sendMessageAtTime方法中,调用了enqueueMessage方法

    626 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { 627 msg.target = this; 628 if (mAsynchronous) { 629 msg.setAsynchronous(true); 630 } 631 return queue.enqueueMessage(msg, uptimeMillis); 632 }

    msg.target = this;这句话是把this这个handler引用付值给了message的target变量,我们在之前分析Looper的loop方法时提到过这个target的。

    总结一下,Handler的sendMessage方法其实就是把msg给放到对应线程的messageQueue中。

    Message和MessageQueue的相关知识也是重点,需要掌握。请看Meassage、MessageQueue源码解析

    handler把msg放到MessageQueue中,在Looper的loop()方法中的死循环中会把这个msg取出来,然后调用msg.target.dispatchMessage(msg);也就是调用handler的dispatchMessage方法

    93 public void dispatchMessage(Message msg) { 94 if (msg.callback != null) { 95 handleCallback(msg); 96 } else { 97 if (mCallback != null) { 98 if (mCallback.handleMessage(msg)) { 99 return; 100 } 101 } 102 handleMessage(msg); 103 } 104 }

    在dispatchMessage中调用了handleMessage方法,handleMessage就是我们在Handler中重写的方法。

    那我们看看H的handleMessage方法,在这个方法中what为BIND_APPLICATION时调用了handleBindApplication方法

    4254 private void handleBindApplication(AppBindData data) { ... 4488 try { 4489 // If the app is being launched for full backup or restore, bring it up in 4490 // a restricted environment with the base application class. 4491 Application app = data.info.makeApplication(data.restrictedBackupMode, null); 4492 mInitialApplication = app; .... 4517 try { 4518 mInstrumentation.callApplicationOnCreate(app); 4519 } catch (Exception e) { ... 4525 } 4526 } 4529 }

    handleBindApplication中调用makeApplication函数,该函数中根据app信息中Application类的路径加载并创建对象,然后调用callApplicationOnCreate函数。callApplicationOnCreate中调用Application对象的onCreate函数。我们开发中常用的Application的onCreate就是在这里调用的。

    到此,我们的第一个消息处理完了。

     

    Android主线程到底是什么(一)

    ActivityManagerService简析

    ActivityThread源码

    Handler源码

    MessageQueue源码

    Message源码

    ServiceManager,SystemServer,SystemServiceManager,SystemService—简述这个几个类的关系

    Handler sync barrier

    Android IdleHandler 原理浅析

     

    最新回复(0)