Android Native层异步消息处理框架

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Native层异步消息处理框架相关的知识,希望对你有一定的参考价值。

 

一、前言

  在NuPlayer中,可以发现许多类似于下面的代码:

技术分享
 1 //=======================================//
 2 NuPlayerDriver::NuPlayerDriver(pid_t pid)
 3     : ......
 4      mLooper(new ALooper) 
 5       ......{
 6     mLooper->setName("NuPlayerDriver Looper");
 7     mLooper->start(
 8             false, /* runOnCallingThread */
 9             true,  /* canCallJava */
10             PRIORITY_AUDIO);
11 
12     mPlayer = new NuPlayer(pid);
13     mLooper->registerHandler(mPlayer) 
14 } 
15 
16 //=======================================//
17 sp<AMessage> msg = new AMessage(kWhatPerformSeek, this);
18 msg->setInt32("generation", ++mSeekGeneration);
19 msg->setInt64("timeUs", seekTimeUs);
20 status_t err = msg->postAndAwaitResponse(&response);
21 
22 //=======================================//
23 void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
24     switch (what) {
25         case XXX:
26         case YYY:
27         ......
28         default:
29     }
30 }
View Code

   这就是android在native层实现的一个异步消息处理机制,在这个机制中所有的处理都是异步的。其基本的处理流程可概述如下:

  • 将变量封装到一个消息AMessage结构体中,然后放到消息队列中去,后台专门有一个线程会从这个队列中取出消息并发送给指定的AHandler处理,在handler的onMessageReceived函数中根据AMessage的mWhat字段转向对应的分支进行处理。

  在这里我们可能会产生这样的疑问:在很多类中都会有各种消息post出来,而后台的异步消息处理线程又是怎么知道将一个消息发送给哪个类的onMessageReceived函数处理呢?

  要搞明白这个问题,就需要分析android在native层的异步消息处理框架。

二、基础类分析

  在android native层的异步消息处理框架中涉及到的类主要有:ALooper、AHandler、AMessage、ALooperRoster、LooperThread等。

  在android开源代码中,这些类的声明头文件位于:/frameworks/av/include/media/stagefright/foundation/ ,实现功能的源代码位于:/frameworks/av/media/libstagefright/foundation/ ,下面就分别对这些类进行分析。

  1、AMessage -- 消息的载体

  结构体AMessage是消息的载体,在传递消息的过程中可以携带各种信息。

技术分享
 1 //AMessage类简析
 2 struct AMessage : public RefBase {
 3     //构造函数,在其中会对AMessage的两个重要数据成员mWhat和mTarget进行初始化设置。
 4     AMessage();
 5     AMessage(uint32_t what, const sp<const AHandler> &handler);
 6     void setWhat(uint32_t what);//设置mWhat
 7     uint32_t what() const;//返回mWhat
 8     void setTarget(const sp<const AHandler> &handler);//设置mTarget
 9     //一系列的set和find函数,用于在传递消息的过程中携带各种信息
10     void setInt32(const char *name, int32_t value);
11     void setInt64(const char *name, int64_t value);
12     //....
13     bool findInt32(const char *name, int32_t *value) const;
14     bool findInt64(const char *name, int64_t *value) const;
15     //投递消息到消息队列中
16     status_t post(int64_t delayUs = 0);
17     // Posts the message to its target and waits for a response (or error) before returning.
18     status_t postAndAwaitResponse(sp<AMessage> *response);
19 protected:
20     virtual ~AMessage();//析构函数
21 private:
22     friend struct ALooper; // deliver()
23     //两个重要的私有数据成员:
24     //mWhat指明这是一个什么消息,用于在onMessageReceived处理分支中进行匹配。
25     //mTarget用于后台线程在处理这个消息时判断发送给哪一个类处理。
26     uint32_t mWhat;
27     ALooper::handler_id mTarget;
28 
29     wp<AHandler> mHandler;
30     wp<ALooper> mLooper;
View Code

  进一步分析AMessage对象的构造函数,首先我们查看AMessage的source code,如下:

技术分享
 1 AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler)
 2     : mWhat(what),
 3       mNumItems(0) {
 4     setTarget(handler);
 5 }
 6 
 7 void AMessage::setTarget(const sp<const AHandler> &handler) {
 8     if (handler == NULL) {
 9         mTarget = 0;
10         mHandler.clear();
11         mLooper.clear();
12     } else {
13         mTarget = handler->id();
14         mHandler = handler->getHandler();
15         mLooper = handler->getLooper();
16     }
17 }
View Code

  在构造函数中设置mWhat的值为指定的what值,用于指明这是一个什么消息,以便在onMessageReceived函数中找到匹配的分支进行处理。然后会调用setTarget函数,来设置mTarget为指定handler的mID值,mHandler为指定的handler,mLooper为与handler相关的ALooper,这样后台处理线程就可以据此判断将该消息发送给哪一个类(handler)进行处理了。

  构造消息并投递出去的过程,如下示例:

1 void NuPlayer::start() {
2     (new AMessage(kWhatStart, this))->post();
3 }

   2、ALooper类

  这个类定义了消息循环和后台处理线程。

技术分享
 1 //ALooper类简析
 2 struct ALooper : public RefBase {
 3     //定义的两个整型变量类型
 4     typedef int32_t event_id;//event id
 5     typedef int32_t handler_id;//handler id
 6     
 7     ALooper();//构造函数
 8     
 9     // Takes effect in a subsequent call to start().
10     void setName(const char *name); 
11 
12     handler_id registerHandler(const sp<AHandler> &handler);//注册handler
13     void unregisterHandler(handler_id handlerID);//注销handler
14     //启动后台处理线程处理事件
15     status_t start(
16             bool runOnCallingThread = false,
17             bool canCallJava = false,
18             int32_t priority = PRIORITY_DEFAULT
19             );
20 protected:
21     virtual ~ALooper();    
22 private:
23     friend struct AMessage;       // post()
24     //事件的结构体封装
25     struct Event {  
26         int64_t mWhenUs;
27         sp<AMessage> mMessage;
28     };
29     AString mName;
30     List<Event> mEventQueue;
31     struct LooperThread;
32     sp<LooperThread> mThread;//后台处理线程
33     // posts a message on this looper with the given timeout
34     void post(const sp<AMessage> &msg, int64_t delayUs);
35     bool loop();
36 }
View Code

  3、LooperThread

  4、AHandler -- 消息处理类的父类

  AHandler类用于对接收到的消息进行对应的处理。下面我们结合source code进行分析如下:

技术分享
 1 struct AHandler : public RefBase {
 2     AHandler()    //构造函数
 3         : mID(0),    //初始化mID为0
 4           mVerboseStats(false),
 5           mMessageCounter(0) {
 6     }
 7 
 8     ALooper::handler_id id() const {//这个函数用于返回内部变量mID的值,其初始值为0,但是可以通过setID()设置
 9         return mID;
10     }
11 
12 
13 protected:
14     virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
15 
16 private:
17     friend struct AMessage;      // deliverMessage()
18     friend struct ALooperRoster; // setID()
19 
20     ALooper::handler_id mID;
21     wp<ALooper> mLooper;
22     //setID()在其友元类ALooperRoster的registerHandler()函数中调用。
23     inline void setID(ALooper::handler_id id, wp<ALooper> looper) {
24         mID = id;
25         mLooper = looper;
26     }
27 
28 };
View Code

  5、ALooperRoster类

  ALooperRoster可以看做是ALooper的一个辅助类,主要用于完成消息handler的注册与注销工作。下面结合source code分析如下:

 

三、异步消息处理框架

  首先我们先copy一段代码来看一看异步消息处理框架的搭建过程:

1 sp<ALooper> mLooper;
2 mLooper(new ALooper)//构造函数的初始化列表中
3 mLooper->setName("NuPlayerDriver Looper");
4 mLooper->start(false, true, PRIORITY_AUDIO);
5 mPlayer = new NuPlayer;// struct NuPlayer : public AHandler
6 mLooper->registerHandler(mPlayer);

 

  搭建框架1

  调用ALooper的构造函数,实例化一个新的ALooper对象:

1 ALooper::ALooper()
2     : mRunningLocally(false) {
3     // clean up stale AHandlers. Doing it here instead of in the destructor avoids
4     // the side effect of objects being deleted from the unregister function recursively.
5     gLooperRoster.unregisterStaleHandlers();
6 }

 

  搭建框架2

  调用ALooper::setName(const char *name)设置ALooper的名字:

1 void ALooper::setName(const char *name) {
2     mName = name;
3 }

 

  搭建框架3

  调用ALooper::start()启动异步消息处理后台线程:

 1 status_t ALooper::start(
 2         bool runOnCallingThread, bool canCallJava, int32_t priority) {
 3     // ......
 4     
 5     if (mThread != NULL || mRunningLocally) {
 6         return INVALID_OPERATION;
 7     }
 8     mThread = new LooperThread(this, canCallJava);//构造LooperThread对象
 9     status_t err = mThread->run( //run()之后就会执行LooperThread::threadLooper()函数,在threadlooper()函数中又会调用ALooper::loop()函数
10             mName.empty() ? "ALooper" : mName.c_str(), priority);
11     if (err != OK) {
12         mThread.clear();
13     }
14     return err;
15 }

 

  搭建框架4

  调用ALooper::registerHandler()注册消息处理器类AHandler:

1 ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
2     return gLooperRoster.registerHandler(this, handler);
3 }

 

  从这个函数的定义可以看出,能作为handler进行注册的类都必须继承自AHandler这个类,注册的过程也是交给了gLooperRoster处理的。

 

以上是关于Android Native层异步消息处理框架的主要内容,如果未能解决你的问题,请参考以下文章

JNI 异常捕获与处理

[Android]使用函数指针实现native层异步回调

Handler与异步消息处理

Handler与异步消息处理

后台消息队列处理简易框架

Android基础进阶 - 消息机制 之Native层分析