android底层的通信方式采用C++实现消息机制,简单来说就是ALooper-AHandler-AMessage机制。其能实现异步处理消息队列中的消息。具体的点就是AMessage是作为消息传递类、ALooper维持一个线程函数,接受来自不同地方的消息,之后将消息队列中消息分配给消息绑定的Handler处理、AHandler是针对不同消息进行具体处理的类。实际上消息机制不仅仅用在android底层多媒体中,其还用于其他地方,所以明白消息机制是学习android底层多媒体的重中之重。
具体的处理流程可以用下图简单的表示:
AMessage是整个框架中的消息载体,其源码的存放路径如下:
libstagefright\foundation\AMessage.cppmedia\stagefright\foundation\AMessage.h
AMessage消息类是整个消息处理机制的桥梁作用。具体源码如下:
struct AMessage : public RefBase {
AMessage();
AMessage(uint32_t what, const sp<const AHandler> &handler);
static sp<AMessage> FromParcel(const Parcel &parcel,
size_t maxNestingLevel = 255);
void writeToParcel(Parcel *parcel) const;
void setWhat(uint32_t what);
uint32_t what() const;
void setTarget(const sp<const AHandler> &handler);
void clear();
void setInt32(const char *name, int32_t value);
void setInt64(const char *name, int64_t value);
void setSize(const char *name, size_t value);
void setFloat(const char *name, float value);
void setDouble(const char *name, double value);
void setPointer(const char *name, void *value);
void setString(const char *name, const char *s, ssize_t len = -1);
void setString(const char *name, const AString &s);
void setObject(const char *name, const sp<RefBase> &obj);
void setBuffer(const char *name, const sp<ABuffer> &buffer);
void setMessage(const char *name, const sp<AMessage> &obj);
void setRect(const char *name,int32_t left, int32_t top, int32_t right, int32_t bottom);
bool contains(const char *name) const;
bool findInt32(const char *name, int32_t *value) const;
bool findInt64(const char *name, int64_t *value) const;
bool findSize(const char *name, size_t *value) const;
bool findFloat(const char *name, float *value) const;
bool findDouble(const char *name, double *value) const;
bool findPointer(const char *name, void **value) const;
bool findString(const char *name, AString *value) const;
bool findObject(const char *name, sp<RefBase> *obj) const;
bool findBuffer(const char *name, sp<ABuffer> *buffer) const;
bool findMessage(const char *name, sp<AMessage> *obj) const;
bool findAsInt64(const char *name, int64_t *value) const;
bool findAsFloat(const char *name, float *value) const;
bool findRect( const char *name, int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const;
status_t post(int64_t delayUs = 0);
status_t postAndAwaitResponse(sp<AMessage> *response);
bool senderAwaitsResponse(sp<AReplyToken> *replyID);
void extend(const sp<AMessage> &other);
sp<AMessage> changesFrom(const sp<const AMessage> &other, bool deep = false) const;
AString debugString(int32_t indent = 0) const;
enum Type {
kTypeInt32,
kTypeInt64,
kTypeSize,
kTypeFloat,
kTypeDouble,
kTypePointer,
kTypeString,
kTypeObject,
kTypeMessage,
kTypeRect,
kTypeBuffer,
};
struct Rect {
int32_t mLeft, mTop, mRight, mBottom;
};
size_t countEntries() const;
const char *getEntryNameAt(size_t index, Type *type) const;
typedef AData<
int32_t, int64_t, size_t, float, double, Rect, AString,
void *, sp<AMessage>, sp<ABuffer>, sp<RefBase>>::Basic ItemData;
ItemData findItem(const char *name) const;
void setItem(const char *name, const ItemData &item);
ItemData getEntryAt(size_t index) const;
size_t findEntryByName(const char *name) const;
status_t setEntryNameAt(size_t index, const char *name);
status_t setEntryAt(size_t index, const ItemData &item);
status_t removeEntryAt(size_t index);
protected:
virtual ~AMessage();
private:
friend struct ALooper;
uint32_t mWhat;
ALooper::handler_id mTarget;
wp<AHandler> mHandler;
wp<ALooper> mLooper;
struct Item {
union {
int32_t int32Value;
int64_t int64Value;
size_t sizeValue;
float floatValue;
double doubleValue;
void *ptrValue;
RefBase *refValue;
AString *stringValue;
Rect rectValue;
} u;
const char *mName;
size_t mNameLength;
Type mType;
void setName(const char *name, size_t len);
};
enum {
kMaxNumItems = 64
};
Item mItems[kMaxNumItems];
size_t mNumItems;
Item *allocateItem(const char *name);
void freeItemValue(Item *item);
const Item *findItem(const char *name, Type type) const;
void setObjectInternal(
const char *name, const sp<RefBase> &obj, Type type);
size_t findItemIndex(const char *name, size_t len) const;
void deliver();
DISALLOW_EVIL_CONSTRUCTORS(AMessage);
};
其中 AMessage有AMessage和AMessage(uint32_t what, const sp &handler)两套构造函数。可以直接的第二个构造函数使用AMessage指定消息并初始化其handler,非常的银性。当然,如果没有采用第二个构造函数,也可以调用类的函数setWhat和setTarget指定what和handler。具体的在如下:
AMessage(uint32_t what, const sp<const AHandler> &handler);
void setWhat(uint32_t what);
void setTarget(const sp<const AHandler> &handler);
AMessage构造完成之后,可以调用其setXXX设置对应的参数,针对不同的消息,更是有不同的函数。最后通过post(调用mLooper.promote()->post)即可将消息投递到AHandler的消息队列中。在我们的接收端呢,也是通过findXXX获取传递的参数。
void setString(const char *name, const AString &s);
void setPointer(const char *name, void *value);
bool findString(const char *name, AString *value) const;
bool findPointer(const char *name, void **value) const;
AMessage属性中存在指向 wp mHandler 和 wp mLooper的指针,用于绑定AHandler和ALooper。
Post发送消息到ALooper中。具体如下:
wp<AHandler> mHandler;
wp<ALooper> mLooper;
AMessage的Post函数是调用其绑定的mLooper的post函数。传递的参数是AMessage和delayUs。具体的ALooper的post函数的处理过程在下面的Alooper中有分析。
status_t AMessage::post(int64_t delayUs) {
sp<ALooper> looper = mLooper.promote();
if (looper == NULL) {
ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
return -ENOENT;
}
looper->post(this, delayUs);
return OK;
}
AMessage中deliver()是获取AHandler对象调用其deliverMessage()函数,传递AMessage给Handler。
void AMessage::deliver() {
sp<AHandler> handler = mHandler.promote();
if (handler == NULL) {
ALOGW("failed to deliver message as target handler %d is gone.", mTarget);
return;
}
handler->deliverMessage(this);
}
如上文得知ALooper是维护消息传递的类,其源码路径如下:
frameworks/av/media/libstagefright/foundation/include/media/stagefright/foundation/ALooper.h
ALooper接口分析
struct ALooper : public RefBase {
typedef int32_t event_id;
typedef int32_t handler_id;
ALooper();
void setName(const char *name);
handler_id registerHandler(const sp<AHandler> &handler);
void unregisterHandler(handler_id handlerID);
status_t start(
bool runOnCallingThread = false,
bool canCallJava = false,
int32_t priority = PRIORITY_DEFAULT
);
status_t stop();
static int64_t GetNowUs();
const char *getName() const {
return mName.c_str();
}
protected:
virtual ~ALooper();
private:
friend struct AMessage;// post()
struct Event {
int64_t mWhenUs;
sp<AMessage> mMessage;
};
Mutex mLock;
Condition mQueueChangedCondition;
AString mName;
List<Event> mEventQueue;
struct LooperThread;
sp<LooperThread> mThread;
bool mRunningLocally;
Mutex mRepliesLock;
Condition mRepliesCondition;
void post(const sp<AMessage> &msg, int64_t delayUs);
sp<AReplyToken> createReplyToken();
status_t awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response);
status_t postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &msg);
bool loop();
DISALLOW_EVIL_CONSTRUCT
};
ALooper本身是维持消息传递的类,它的使用方法比较简单,具体流程就是初始化ALooper对象,接着调用setName和start函数,最后完成的是AHandler注册。具体的使用如下:
mLooper(new ALooper);
mLooper->setName("XXX ALooper");
mLooper->start(
false,/*runOnCallingThread*/
true,/*canCallJava*/
PRIORITY_AUDIO);
mLooper->registerHandler(Handler);
ALooper中的start函数中会创建一个线程,如下所示:
status_t ALooper::start(
bool runOnCallingThread, bool canCallJava, int32_t priority) {
if (runOnCallingThread) {
{
Mutex::Autolock autoLock(mLock);
if (mThread != NULL || mRunningLocally) {
return INVALID_OPERATION;
}
mRunningLocally = true;
}
do {
} while (loop());
return OK;
}
Mutex::Autolock autoLock(mLock);
if (mThread != NULL || mRunningLocally) {
return INVALID_OPERATION;
}
mThread = new LooperThread(this, canCallJava);
status_t err = mThread->run(
mName.empty() ? "ALooper" : mName.c_str(), priority);
if (err != OK) {
mThread.clear();
}
return err;
}
线程中,主要是调用的是Loop函数,具体loop函数源码如下:
bool ALooper::loop() {
Event event;
{
Mutex::Autolock autoLock(mLock);
if (mThread == NULL && !mRunningLocally) {
return false;
}
if (mEventQueue.empty()) {
mQueueChangedCondition.wait(mLock);
return true;
}
int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
int64_t nowUs = GetNowUs();
if (whenUs > nowUs) {
int64_t delayUs = whenUs - nowUs;
if (delayUs > INT64_MAX / 1000) {
delayUs = INT64_MAX / 1000;
}
mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
return true;
}
event = *mEventQueue.begin();
mEventQueue.erase(mEventQueue.begin());
}
event.mMessage->deliver();
return true;
}
那么到了这一步,已经可以看到了,需要把上文介绍的消息添加进ALooper的mEventQueue链表中了。上文AMessage调用post函数是调用ALooper的Post函数,通过Post函数将AMessage添加到链表中,具体Post函数如下:
void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
Mutex::Autolock autoLock(mLock);
int64_t whenUs;
if (delayUs > 0) {
int64_t nowUs = GetNowUs();
whenUs = (delayUs > INT64_MAX - nowUs ? INT64_MAX : nowUs + delayUs);
} else {
whenUs = GetNowUs();
}
List<Event>::iterator it = mEventQueue.begin();
while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {
++it;
}
Event event;
event.mWhenUs = whenUs;
event.mMessage = msg;
if (it == mEventQueue.begin()) {
mQueueChangedCondition.signal();
}
mEventQueue.insert(it, event);
}
在ALooper::loop()函数会一直的监听这个mEventQueue链表,如果里面有消息的话,就会取出来,接着调用AMessage的deliver函数。AMessage::deliver()函数中,就会去获取这个AMessage的Ahandler,然后调用对应AHandler的deliverMessage函数:handler->deliverMessage(this)。
在AHandler::deliverMessage(const sp &msg)函数中,就会调用AHandler中的onMessageReceived(msg)函数,如果这时候传入的是AHandler子类的话,就会去调用AHandler子类的onMessageReceived(msg)函数。这里的流程具体在下面AHandler有详细分析。
ALooperRooster的源码路径如下:
/frameworks/av/media/libstagefright/foundation/include/media/stagefright/foundation/ALooperRoster.h
struct ALooperRoster {
ALooperRoster();
ALooper::handler_id registerHandler(
const sp<ALooper> &looper, const sp<AHandler> &handler);
void unregisterHandler(ALooper::handler_id handlerID);
void unregisterStaleHandlers();
void dump(int fd, const Vector<String16>& args);
private:
struct HandlerInfo {
wp<ALooper> mLooper;
wp<AHandler> mHandler;
};
Mutex mLock;
KeyedVector<ALooper::handler_id, HandlerInfo> mHandlers;
ALooper::handler_id mNextHandlerID;
DISALLOW_EVIL_CONSTRUCTORS(ALooperRoster);
};
}
上面需要注意的点是 KeyedVector
ALooper::handler_id ALooperRoster::registerHandler(
const sp<ALooper> &looper, const sp<AHandler> &handler) {
Mutex::Autolock autoLock(mLock);
if (handler->id() != 0) {
CHECK(!"A handler must only be registered once.");
return INVALID_OPERATION;
}
HandlerInfo info;
info.mLooper = looper;
info.mHandler = handler;
ALooper::handler_id handlerID = mNextHandlerID++;
mHandlers.add(handlerID, info);
handler->setID(handlerID, looper);
return handlerID;
}
AHandler作为消息处理的类,简单来说就是处理分发的各种消息。具体源码路径如下:
frameworks/av/include/media/stagefright/foundation/AHandler.h
struct AHandler : public RefBase {
AHandler()
: mID(0),
mVerboseStats(false),
mMessageCounter(0) {
}
ALooper::handler_id id() const {
return mID;
}
sp<ALooper> looper() const {
return mLooper.promote();
}
wp<ALooper> getLooper() const {
return mLooper;
}
wp<AHandler> getHandler() const {
// allow getting a weak reference to a const handler
return const_cast<AHandler *>(this);
}
protected:
virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
private:
friend struct AMessage; // deliverMessage()
friend struct ALooperRoster; // setID()
ALooper::handler_id mID;
wp<ALooper> mLooper;
inline void setID(ALooper::handler_id id, const wp<ALooper> &looper) {
mID = id;
mLooper = looper;
}
bool mVerboseStats;
uint32_t mMessageCounter;
KeyedVector<uint32_t, uint32_t> mMessages;
void deliverMessage(const sp<AMessage> &msg);
DISALLOW_EVIL_CONSTRUCTORS(AHandler);
};
从上面的定义中,需要格外注意的是virtual void onMessageReceived(const sp &msg)函数,这个是子类继承AHandler接受消息的接口函数,并且是处理消息的重点。
其中,ALooper::handler_id mID是区分AHandler的标识。mMessages是存放接受消息的容器。AHandler中的deliverMessage函数是调用子类的onMessageReceived的。
具体如下:
void AHandler::deliverMessage(const sp<AMessage> &msg) {
onMessageReceived(msg);
mMessageCounter++;
if (mVerboseStats) {
uint32_t what = msg->what();
ssize_t idx = mMessages.indexOfKey(what);
if (idx < 0) {
mMessages.add(what, 1);
} else {
mMessages.editValueAt(idx)++;
}
}
}
接着上文ALooper中的loop函数监听mEventQueue,如果有消息时,调用消息的deliver函数。而在上面的AMessage分析中,AMessage的deliver()调用的是AHandler的deliverMessage函数。
简单的调用逻辑如下:
ALooper::loop()->AMessage::deliver()->AHandler::deliverMessage->AHandler::onMessageReceived()
AHandler中也有 AMessage 的有元 和 mLooper 指定相关的AMessage和ALooper。
并且在setID的时候是指了mLooper。
整个机制不是特别复杂,先单个类进行分析之后按照消息流动过程串起来就能明白具体原因了。这里借鉴一句别人说话,阅读源码不能将其看成静态的状态,而是每个消息,每个机制都是流动的,按照流的思想阅读便会事半功倍。到此,就整个流程就分析完了,如果有什么不对的地方,望大佬斧正啦。