Android 线程间通信 - Java 层

2,004 阅读5分钟

源码基于 Android S AOSP,源码在线查看地址: cs.android.com/android/pla…

线程间通信在 Android 系统中应用十分广泛,本文是一个系列文章,主要梳理了Android Java层的线程间通信机制-Handler。

一个 Java 层简单的 Handler 示例如下:

public void egHandler() {
    Looper.prepare();
    Looper.loop();
    
    Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            // TODO; 处理 Event
        }
    };

    new Thread() {
        @Override
        public void run() {
            Message msg = new Message();
            msg.what = 0;
            handler.sendMessage(msg);
        }
    }.start();
}

Java 层的线程通信主要涉及到了Handler、MessageQueue、Message、Looper。

主线程创建的时候默认会执行Looper.prepare()、Looper.loop()方法,即默认会创建Looper

Looper

源码路径frameworks/base/core/java/android/os/Looper.java

Looper.prepare

public static void prepare() {
    // 调用Looper.prepare
    prepare(true);
}

private static void prepare(boolean quitAllowed) { // 默认传入 true, 允许中断
    // 从ThreadLocal中尝试拿出Looper对象
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    
    // ThreadLocal中没有Looper对象则进行创建
    sThreadLocal.set(new Looper(quitAllowed));
}

Looper.Looper

private Looper(boolean quitAllowed) {
    // 搞出来一个MessageQueue
    mQueue = new MessageQueue(quitAllowed);
    // 用一个变量保存当前线程(对应上面的示例也就是主线程)
    mThread = Thread.currentThread();
}

MessageQueue.MessageQueue

MessageQueue(boolean quitAllowed) {
    // 接收Looper传进的参数,默认允许中断
    mQuitAllowed = quitAllowed;
    // 初始化native方法,下一篇文章会说到
    mPtr = nativeInit();
}

Looper.loop

@SuppressWarnings("AndroidFrameworkBinderIdentity")
public static void loop() {
    // 从当前线程拿到 looper 对象
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    if (me.mInLoop) {
        Slog.w(TAG, "Loop again would have the queued messages be executed"
               + " before this one completed.");
    }
	
    // 标识 Looper 开始 loop
    me.mInLoop = true;

    // 清空远程调用端的pid和uid,使用本地进程的pid和uid代替
    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);

    me.mSlowDeliveryDetected = false;
	
    // 无线循环,调用loopOnce
    for (;;) {
        if (!loopOnce(me, ident, thresholdOverride)) {
            return;
        }
    }
}

Looper.myLooper

public static @Nullable Looper myLooper() {
    // 从当前线程中拿出 Looper 对象
    return sThreadLocal.get();
}

Looper.loopOnce

@SuppressWarnings("AndroidFrameworkBinderIdentity")
private static boolean loopOnce(final Looper me,
                                final long ident, final int thresholdOverride) {
    Message msg = me.mQueue.next(); // 从MessageQueue中取出Message,当MessageQueue中没有消息时,此处会阻塞
    
    // ......
    
    // Make sure the observer won't change while processing a transaction.
    final Observer observer = sObserver;

	// ......
    
    Object token = null;
    if (observer != null) {
        // 当注册了观察者时,调用观察者messageDispatchStarting方法
        token = observer.messageDispatchStarting();
    }
    long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
    try {
        // 调用消息的dispatchMessage方法,默认为Handler.dispatchMessage方法
        msg.target.dispatchMessage(msg);
        if (observer != null) {
            // 调用观察者 messageDispatched方法
            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);
        }
    }
    // ......
    
	// 回收消息
    msg.recycleUnchecked();

    return true;
}

Looper.java中还有一些不常用的方法

Looper.myLooper

public static @Nullable Looper myLooper() {
	return sThreadLocal.get();
}

Looper.myQueue

public static @NonNull MessageQueue myQueue() {
    return myLooper().mQueue;
}

Looper.isCurrentThread

public boolean isCurrentThread() {
    return Thread.currentThread() == mThread;
}

Looper.quit

public void quit() {
    mQueue.quit(false);
}

Looper.quitSafely

public void quitSafely() {
    mQueue.quit(true);
}

Looper.getQueue

public @NonNull MessageQueue getQueue() {
    return mQueue;
}

Observer

在上面Looper.loopOnce中提到了Observer,该接口定义在Looper.java中,共三个方法

public interface Observer {
    Object messageDispatchStarting();

    void messageDispatched(Object token, Message msg);

    void dispatchingThrewException(Object token, Message msg, Exception exception);
}

可以实现该接口,通过setObserver方法注册进去

public static void setObserver(@Nullable Observer observer) {
    sObserver = observer;
}

Handler

源码路径:frameworks/base/core/java/android/os/Handler.java

Handler.Handler

@Deprecated
public Handler() {
	this(null, false);
}

@Deprecated
public Handler(@Nullable Callback callback) {
    this(callback, false);
}

// 指定Looper
public Handler(@NonNull Looper looper) {
    this(looper, null, false);
}

// 指定Looper和Callback
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
    this(looper, callback, false);
}

public Handler(@Nullable Callback callback, boolean async) {
    // ......

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
            + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

@UnsupportedAppUsage // 此注解表示App无法使用该构造方法
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

Handler.sendMessage

public final boolean sendMessage(@NonNull Message msg) {
    return sendMessageDelayed(msg, 0);
}

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

// 定时发送消息,sendMessage代表now发送消息
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
            this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    
    // 调用MessageQueue方法,将Message加入到MessageQueue中
    return enqueueMessage(queue, msg, uptimeMillis);
}

还有另外一种发送消息的方法,且消息中带有Callback

Handler.post

public final boolean post(@NonNull Runnable r) {
    return  sendMessageDelayed(getPostMessage(r), 0);
}

// token 即为message携带的数据
public final boolean postAtTime(
    @NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
    return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}

Handler.getPosrMessage

private static Message getPostMessage(Runnable r) {
    // 从消息池中取出一个空白消息
    Message m = Message.obtain();
    // 给message设置callback
    m.callback = r;
    return m;
}

@UnsupportedAppUsage
private static Message getPostMessage(Runnable r, Object token) {
    Message m = Message.obtain();
    // 给message设置obj数据
    m.obj = token;
    m.callback = r;
    return m;
}

Handler.obtainMessage

// 从消息池中取出一个Message使用
public final Message obtainMessage()
{
    return Message.obtain(this);
}

Handler.dispatchMessage

// Looper.loopOnce中调用过来的,处理消息
public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        // message有callback,直接走callback
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            // handler有callback,走callback,callback内返回true则直接return,不会执行handlerMessage方法
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

Handler.handleMessage

// 由Handler的子类实现,用来处理消息,不实现则不会做任何事,空函数
public void handleMessage(@NonNull Message msg) {
}

MessageQueue

源码路径:frameworks/base/core/java/android/os/MessageQueue.java

MessageQueue.enqueueMessage

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }

        synchronized (this) {
            if (msg.isInUse()) {
                // inUse 抛出异常
                throw new IllegalStateException(msg + " This message is already in use.");
            }

            if (mQuitting) {
                // 表示正在执行结束流程
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                // 回收掉此message,加入message池
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            // mMessages 为Message链表,MessageQueue的主要数据结构
            Message p = mMessages;
            // 唤醒标识
            boolean needWake;
            
            // 三种条件:
            // 1. MessageQueue中无Message
            // 2. 消息分发的时间为now
            // 3. 新消息的发送时间小于链表头部消息的时间
            if (p == null || when == 0 || when < p.when) {
                // 放在链表头
                msg.next = p;
                mMessages = msg;
                
                // 需要唤醒MessageQueue.next()
                needWake = mBlocked;
            } else {
                // 链表头不为空,则需要将Message插入到链表中
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // 需要唤醒则调用native方法唤醒MessageQueue.next
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

enqueueMessage中,新message的位置有两种可能:

  • 链表头为空、当前message的发送时间为0、message的发送时间小于链表头的message发送时间,满足任意一项则将message插入到链表头部
  • 循环遍历链表,找到链表节点中message的时间大于新message时间的位置 ,将新message插入该位置,找不到则插入到链表尾部

MessageQueue.next

@UnsupportedAppUsage
Message next() {
    // 此处保存的是native层NativeMessageQueue指针
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; 
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
		
        // 此处调用native方法,会阻塞,第一次调用会一直阻塞(pendingIdleHandlerCount = -1代表一直阻塞)
        nativePollOnce(ptr, nextPollTimeoutMillis);
		
        // 阻塞超时、MessageQueue中有新消息、发生ERROR 时调用以下方法
        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // MessageQueue中链表头结点的发送时间大于now,需要等待
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    // 取出MessageQueue链表的头节点,给Looper.loopOnce使用
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }

            // 如果MessageQueue中无Message或者链表头Message还没都发送的时间,从mIdleHandlers中获取到idleHandler个数
            // mIdleHandlers通过addIdleHandler添加
            if (pendingIdleHandlerCount < 0
                && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // 从mPendingIdleHandlers取出IdelHandler执行
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                // queueIdle返回false,则将当前IdelHandler从mIdleHandlers中彻底移除掉
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // 将pendingIdleHandlerCount置空
        pendingIdleHandlerCount = 0;

        // 在执行IdelHander的时候,可能MessageQueue中可能已经有消息到来或者原有消息分发时间已到,将等待时间变为0
        nextPollTimeoutMillis = 0;
    }
}

当MessageQueue中有消息时,会将消息返回Looper.loopOnce,如没有消息或分发时间未到,则会执行IdelHandler中方法(IdelHandler需要Api调用者通过addIdleHander手动add),不会浪费等待的时间。

MessageQueue.addIdleHandler

public void addIdleHandler(@NonNull IdleHandler handler) {
    if (handler == null) {
        throw new NullPointerException("Can't add a null IdleHandler");
    }
    synchronized (this) {
        mIdleHandlers.add(handler);
    }
}

MessageQueue.removeMessages

void removeMessages(Handler h, int what, Object object) {
    if (h == null) {
        return;
    }

    synchronized (this) {
        // Message链表头
        Message p = mMessages;

        // Remove all messages at front.
        while (p != null && p.target == h && p.what == what
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        // Remove all messages after front.
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && n.what == what
                    && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}

该函数的作用是从MessageQueue中清除条件满足msg.target = h && msg.what = what && (msg.obj == null || msg.obj = object)的message。

清除的方式也很特别,分为两段进行

  • 找到和给定条件相等的message
    • 找到则清除掉该msg,并让链表头和指向该节点的next
    • 找不到则退出循环
  • 从上一个循环的位置开始,接着遍历链表
    • 找到和给定条件相等的msg,清除掉msg
    • 找不到接着遍历,直到 p == null

MessageQueue.quit

void quit(boolean safe) {
    if (!mQuitAllowed) {
        // mQuitAllowed是构造方法传进来的,为true代表可以终止,为false在此方法内会抛出异常
        throw new IllegalStateException("Main thread not allowed to quit.");
    }

    synchronized (this) {
        if (mQuitting) {
            // 正在 quit,直接 return
            return;
        }
        mQuitting = true;

        if (safe) {
            removeAllFutureMessagesLocked();
        } else {
            removeAllMessagesLocked();
        }

        // We can assume mPtr != 0 because mQuitting was previously false.
        nativeWake(mPtr);
    }
}

quit方法主要作用是停掉MessageQueue,释放掉MessageQueue中的节点,而释放掉哪些节点是通过参数safe进行控制的。

当safe为true时,调用removeAllFutureMessagesLocked方法,该方法内部会判断链表头节点msg的when

  • 当msg.when > now时,证明链表中的所有节点都没有进行消息分发,可以全部释放
  • 当msg.when < now时,需要遍历链表,找到msg.when > now的节点,从该节点开始进行释放,该节点之前的节点不可以释放,可能该节点之前的节点已经被分发出去了

当safe为false时,调用removeAllMessagesLocked方法,暴力释放掉MessageQueue的所有节点

MessageQueue.removeAllMessagesLocked

private void removeAllMessagesLocked() {
    Message p = mMessages;
    while (p != null) {
        Message n = p.next;
        p.recycleUnchecked();
        p = n;
    }
    mMessages = null;
}

从链表中移除掉所有message,并且将链表头mMessages置为 null

MessageQueue.removeAllFutureMessagesLocked

private void removeAllFutureMessagesLocked() {
    // 获取当前时间
    final long now = SystemClock.uptimeMillis();
    // 拿到链表头
    Message p = mMessages;
    if (p != null) {
        if (p.when > now) {
            // 链表头的msg发送时间大于当前时间,那链表中所有节点msg的发送时间也一定大于now,具体可以看enqueueMessage方法的实现
            // 暴力移除全部节点
            removeAllMessagesLocked();
        } else {
            Message n;
            // 遍历链表,找到msg.when > now的节点
            for (;;) {
                n = p.next;
                if (n == null) {
                    return;
                }
                if (n.when > now) {
                    break;
                }
                p = n;
            }
            // 断开节点
            p.next = null;
            
            // 回收掉链表剩余节点
            do {
                p = n;
                n = p.next;
                // 回收节点
                p.recycleUnchecked();
            } while (n != null);
        }
    }
}

Message

源码路径:frameworks/base/core/java/android/os/Message.java

Filed

字段含义
what可以看做消息的类型,以此字段标识消息
arg1参数1
arg2参数2
obj消息携带的数据
when消息送给looper的时间
flag标识当前Message的状态,目前有FLAG_IN_USE、FLAG_ASYNCHRONOUS、FLAGS_TO_CLEAR_ON_COPY_FROM三种状态
nextMessagePool中链表节点链接指针

调用栈

-------------------------------------------- 向 MessageQueue 发送消息 -----------------------------------------------------
frameworks/base/core/java/android/os/Handler.java
    | ---> public final boolean sendMessage(@NonNull Message msg)
        | ---> return sendMessageDelayed(msg, 0);
            | ---> return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
                | ---> return enqueueMessage(queue, msg, uptimeMillis);
                    | ---> msg.target = this; // 将target指向当前 handler
                    | ---> return queue.enqueueMessage(msg, uptimeMillis);

frameworks/base/core/java/android/os/MessageQueue.java
                        | ---> msg.markInUse();
                        | ---> msg.when = when;
                        | ---> Message p = mMessages; // 拿到链表头
                        | ---> if (p == null || when == 0 || when < p.when) // 插在链表头部
                            | ---> msg.next = p;
                            | ---> mMessages = msg;
                            | ---> needWake = mBlocked;
                        | ---> else
                            | ---> for (;;) // 遍历链表,在链表中找到msg合适的插入位置
                            | ---> msg.next = p;
                            | ---> prev.next = msg; // 插入
                        | ---> nativeWake(mPtr); // if (needWake) 唤醒等待message的next()方法

------------------------------------------ Looper 循环从 MessageQueue 中拿到消息并处理 --------------------------------------
frameworks/base/core/java/android/os/Looper.java
    | ---> public static void loop()
        | ---> final Looper me = myLooper();
        | ---> for (;;)
            | ---> if (!loopOnce(me, ident, thresholdOverride)) // return;
                | ---> Message msg = me.mQueue.next(); // 从MessageQueue中拿到message,此处可能会阻塞

frameworks/base/core/java/android/os/MessageQueue.java
                    | ---> for (;;)
                        | ---> nativePollOnce(ptr, nextPollTimeoutMillis); // 可能会阻塞,需要nativeWake唤醒
                        | ---> Message msg = mMessages;
                        | ---> if (msg != null && msg.target == null)
                            | ---> while (msg != null && !msg.isAsynchronous());
                                | ---> prevMsg = msg;
                                | ---> msg = msg.next;
                        | ---> if (msg != null)
                            | ---> if (now < msg.when)
                                | ---> nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); // 计算需要等待的时间
                            | ---> else
                                | ---> prevMsg.next = msg.next; // if (prevMsg != null)
                                | ---> mMessages = msg.next; // else
                                | ---> msg.next = null;
                                | ---> msg.markInUse();
                                | ---> return msg; // 返回链表头节点

frameworks/base/core/java/android/os/Looper.java
                | ---> msg.target.dispatchMessage(msg); // target 指向自实现的 handler

frameworks/base/core/java/android/os/Handler.java
                    | ---> if (msg.callback != null)
                        | ---> handleCallback(msg);
                            | ---> message.callback.run();
                    | ---> else
                        | ---> if (mCallback != null)
                            | ---> if (mCallback.handleMessage(msg))
                                | ---> return // 上面的mCallback.handleMessage方法如返回true,则不会执行Handler.handleMessage方法
                        | ---> handleMessage(msg);

frameworks/base/core/java/android/os/Looper.java
                | ---> msg.recycleUnchecked(); // 回收掉message,将该msg加入到message poll