在讲 LooperMonitor 之前,我们先来看看如何在Looper 中添加日志打印,
先来看看Looper 的部分源码
public final class Looper {
//设置打印的Printer
public void setMessageLogging(@Nullable Printer printer) {
mLogging = printer;
}
// 开启循环,处理消息
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();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
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
final Printer logging = me.mLogging;
// 开始处理消息时 如果有 logging 打印 >>>>
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
结束处理消息时 如果有 logging 打印 <<<<<
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.recycleUnchecked();
}
}
}
可以看到在Looper 中有一个 setMessageLogging 方法,这个方法是整个Looper单例的,在Looper 处理消息的开始和结束时会调用这个 mLogging 打印 >>> 与 <<< , 在没有看 Matrix 源码之前我们先提出两个问题,
1: 由于 setMessageLogging 是 Looper 的静态方法 Matrix 是如何保证自己添加的进去的 Printer 不被别人所替换,又同时保证其他给 setMessageLogging 赋值进去的 Printer 还能继续打印的,
2:在接收到了 Printer 的消息 ,Matrix 如何来判断这个消息是开始消息还是结束消息的,这对于整个 Matrix 架构至关重要
带着这两个问题,我们开始分析 LooperMonitor
先看他的构造方法
private LooperMonitor(Looper looper) {
Objects.requireNonNull(looper);
this.looper = looper;
resetPrinter();
addIdleHandler(looper);
}
在构造方法中保存了looper ,同时调用了 resetPrinter 方法, 并且向looper 的 MessageQueue 中添加了一个自身的 IdleCallback ,我们先来看看 resetPrinter 这个方法
private synchronized void resetPrinter() {
Printer originPrinter = null;
try {
if (!isReflectLoggingError) {
originPrinter = ReflectUtils.get(looper.getClass(), "mLogging", looper);
if (originPrinter == printer && null != printer) {
return;
}
// Fix issues that printer loaded by different classloader
if (originPrinter != null && printer != null) {
if (originPrinter.getClass().getName().equals(printer.getClass().getName())) {
MatrixLog.w(TAG, "LooperPrinter might be loaded by different classloader"
+ ", my = " + printer.getClass().getClassLoader()
+ ", other = " + originPrinter.getClass().getClassLoader());
return;
}
}
}
} catch (Exception e) {
isReflectLoggingError = true;
Log.e(TAG, "[resetPrinter] %s", e);
}
if (null != printer) {
MatrixLog.w(TAG, "maybe thread:%s printer[%s] was replace other[%s]!",
looper.getThread().getName(), printer, originPrinter);
}
looper.setMessageLogging(printer = new LooperPrinter(originPrinter));
if (null != originPrinter) {
MatrixLog.i(TAG, "reset printer, originPrinter[%s] in %s", originPrinter, looper.getThread().getName());
}
}
Matrix 使用了一个非常非常巧妙的方法,那就是反射Looper内的 mLogging ,如果mLogging 存在,并且不是我设置的,那么就会让自己的 LooperPrinter 包裹这个 mLogging ,在 LooperPrinter打印过程中先使用它持有Printer 打印,再来处理自己的逻辑,
再来看看 IdleCallback都干了啥
@Override
public boolean queueIdle() {
if (SystemClock.uptimeMillis() - lastCheckPrinterTime >= CHECK_TIME) {
resetPrinter();
lastCheckPrinterTime = SystemClock.uptimeMillis();
}
return true;
}
每1分钟调用一次 重置 resetPrinter ,来保证自身的正确运转, 看完这这里我们就将第一个问题分析清楚了,
关于第二个问题,再来看看LooperPrinter 这个类
class LooperPrinter implements Printer {
public Printer origin;
boolean isHasChecked = false;
boolean isValid = false;
LooperPrinter(Printer printer) {
this.origin = printer;
}
@Override
public void println(String x) {
if (null != origin) {
origin.println(x);
if (origin == this) {
throw new RuntimeException(TAG + " origin == this");
}
}
if (!isHasChecked) {
isValid = x.charAt(0) == '>' || x.charAt(0) == '<';
isHasChecked = true;
if (!isValid) {
MatrixLog.e(TAG, "[println] Printer is inValid! x:%s", x);
}
}
if (isValid) {
dispatch(x.charAt(0) == '>', x);
}
}
}
在他的println 方法内,调用了一个 dispatch 方法,这个方法第一个参数就是boolean 类型的是否是开始的标识,他使用的是 x是否是 '>'开头的, 剩下的事情就比较简单了,分发开始和结束事件 ,问题二我们也解释清楚了
private void dispatch(boolean isBegin, String log) {
if (isBegin) {
if (historyMsgRecorder) {
messageStartTime = System.currentTimeMillis();
latestMsgLog = log;
recentMCount++;
}
synchronized (oldListeners) {
for (LooperDispatchListener listener : oldListeners) {
if (listener.isValid()) {
listener.onDispatchStart(log);
}
}
}
synchronized (listeners) {
for (DispatchListenerWrapper listener : listeners.values()) {
if (listener.isValid()) {
listener.onDispatchBegin(log);
}
}
}
} else {
if (historyMsgRecorder) {
recordMsg(log, System.currentTimeMillis() - messageStartTime);
}
synchronized (oldListeners) {
for (LooperDispatchListener listener : oldListeners) {
if (listener.isValid()) {
listener.onDispatchEnd(log);
}
}
}
synchronized (listeners) {
for (DispatchListenerWrapper listener : listeners.values()) {
if (listener.isValid()) {
listener.onDispatchEnd(log);
}
}
}
}
}
到了这里整个 LooperMonitor 就分析完成了