承接上一章节分析:【若前一章节没看过,建议先看上一章节】
Android native层媒体通信架构AHandler/ALooper机制实现源码分析【Part 2】
本系列文章分析的安卓源码版本:【Android 10.0 版本】
3.3、AMessage post发送事件消息实现分析
其实在AMessage中可以有三种post方式,如下声明:
// [frameworks/av/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h]
struct AMessage : public RefBase {
// (可指定延迟时间)发送事件消息
// 见3.3.1小节分析
status_t post(int64_t delayUs = 0);
// 发送消息给目标handler id的AHandler实现者,返回一个执行状态,
// 并在返回应答值之前一直wait等待响应返回值(即AMessage消息)
// 见3.3.2小节分析
// Posts the message to its target and waits for a response (or error)
// before returning.
status_t postAndAwaitResponse(sp<AMessage> *response);
// 响应 postAndAwaitResponse() 的等待应答,并返回该AMessage给等待应答端作为响应返回值接收
// 此方法刚好和上面的方法形成一对应答
// 见3.3.3小节分析
// Posts the message as a response to a reply token. A reply token can
// only be used once. Returns OK if the response could be posted; otherwise,
// an error.
status_t postReply(const sp<AReplyToken> &replyID);
}
3.3.1、AMessage post(delayUs)方法实现:
(可指定延迟时间【默认为0】)发送事件消息
// [frameworks/av/media/libstagefright/foundation/AMessage.cpp]
status_t AMessage::post(int64_t delayUs) {
// 尝试提升缓存的ALooper当前弱引用指针对象为强引用指针对象
sp<ALooper> looper = mLooper.promote();
if (looper == NULL) {
// 提升失败时
// 发送消息失败,因为发送给handler id(mTarget)的目标ALooper对象已不存在即已被释放内存
// 注:mTarget为handler id
ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
return -ENOENT;
}
// 提升成功,则表明当前ALooper对象指针还被使用中即没有被释放,其引用计数不为0
// 执行ALooper的post方法
looper->post(this, delayUs);
return OK;
}
looper->post(this, delayUs) 实现分析:
(可指定延迟时间)发送事件消息
// [frameworks/av/media/libstagefright/foundation/ALooper.cpp]
void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
Mutex::Autolock autoLock(mLock);
int64_t whenUs;
if (delayUs > 0) {
// 指定延迟时间时
// 获取当前系统时间(微秒),该方法实现见前面已有的分析
int64_t nowUs = GetNowUs();
// 计算该事件消息(未来)执行时间点【nowUs + delayUs】
// 备注:注意此处对输入值的最大值限制处理
whenUs = (delayUs > INT64_MAX - nowUs ? INT64_MAX : nowUs + delayUs);
} else {
// 未指定延迟时间时【delayUs包括可能小于0,默认为0】
// 获取当前系统时间(微秒)作为该事件消息执行时间点
whenUs = GetNowUs();
}
// 消息队列从头开始迭代【迭代器】循环处理
// 注意:已加入到消息队列中的消息肯定是按照消息执行时间点的递增来排序好了的,
// 因此像此处处理,只需从头消息开始判断每个消息的执行时间点
// 和当前新加入的消息的执行时间点进行比较即可。
// 若队列中 it 该消息执行时间点大于当前新加入的消息的执行时间点,
// 则表明找到了当前队列中第一个比新消息执行时间点大的消息(位置)。
// NOTE:根据这个逻辑处理,可以知道若消息执行时间点相同,那么就根据先后顺序来执行。
List<Event>::iterator it = mEventQueue.begin();
while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {
++it;
}
// 创建新消息事件对象,并缓存新消息时间执行时间点和消息对象
Event event;
event.mWhenUs = whenUs;
event.mMessage = msg;
// 若此前消息队列为空时,则it为begin()即条件成立,
// 此时则执行 mQueueChangedCondition 条件变量发送信号,
// 从而唤醒等待在该条件变量上的其他线程。
// signal() 此方法只允许等待该条件变量的一个线程获取到该条件变量上的锁【mLock】,
// 当然在该ALooper消息循环线程实现中,该条件变量默认只会在同一个线程中执行wait。
if (it == mEventQueue.begin()) {
mQueueChangedCondition.signal();
}
// 往消息队列中插入新消息,插入位置为 it 的位置,然后 it 及其后面消息将会往后依次移动
// 见下面的分析
mEventQueue.insert(it, event);
// 因此如上分析可知,当该方法返回时会释放【mLock】锁,
// 然后等待该条件变量上获取锁的线程将获取该锁后继续执行
// 即前面分析的【ALooper::lo