Android系统广播Broadcast机制分析

        在Android系统中,广播(Broadcast)是在组件之间传播数据(Intent)的一种机制;这些组件甚至是可以位于不同的进程中,这样它就像Binder机制一样,起到进程间通信的作用;本文通过一个简单的例子来学习Android系统的广播机制,为后续分析广播机制的源代码作准备。

        第一部分:android系统广播机制的简要介绍

        在Android系统中,为什么需要广播机制呢?广播机制,本质上它就是一种组件间的通信方式,如果是两个组件位于不同的进程当中,那么可以用Binder机制来实现,如果两个组件是在同一个进程中,那么它们之间可以用来通信的方式就更多了,这样看来,广播机制似乎是多余的。然而,广播机制却是不可替代的,它和Binder机制不一样的地方在于,广播的发送者和接收者事先是不需要知道对方的存在的,这样带来的好处便是,系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。

        在软件工程中,是非常强调模块之间的高内聚低耦合性的,不然的话,随着系统越来越庞大,就会面临着越来越难维护的风险,最后导致整个项目的失败。Android应用程序的组织方式,可以说是把这种高内聚低耦合性的思想贯彻得非常透彻,在任何一个Activity中,都可以使用一个简单的Intent,通过startActivity或者startService,就可以把另外一个Activity或者Service启动起来为它服务,而且它根本上不依赖这个Activity或者Service的实现,只需要知道它的字符串形式的名字即可,而广播机制更绝,它连接收者的名字都不需要知道。

        不过话又说回来,广播机制在Android系统中,也不算是什么创新的东西。如果读者了解J2EE或者COM,就会知道,在J2EE中,提供了消息驱动Bean(Message-Driven Bean),用来实现应用程序各个组件之间的消息传递;而在COM中,提供了连接点(Connection Point)的概念,也是用来在应用程序各个组间间进行消息传递。无论是J2EE中的消息驱动Bean,还是COM中的连接点,或者Android系统的广播机制,它们的实现机理都是消息发布/订阅模式的事件驱动模型,消息的生产者发布事件,而使用者订阅感兴趣的事件。

        废话说了一大堆,现在开始进入主题了,和前面的文章一样,我们通过具体的例子来介绍Android系统的广播机制。在这个例子中,有一个Service,它在另外一个线程中实现了一个计数器服务,每隔一秒钟就自动加1,然后将结果不断地反馈给应用程序中的界面线程,而界面线程中的Activity在得到这个反馈后,就会把结果显示在界面上。为什么要把计数器服务放在另外一个线程中进行呢?我们可以把这个计数器服务想象成是一个耗时的计算型逻辑,如果放在界面线程中去实现,那么势必就会导致应用程序不能响应界面事件,最后导致应用程序产生ANR(Application Not Responding)问题。计数器线程为了把加1后的数字源源不断地反馈给界面线程,这时候就可以考虑使用广播机制了。

        首先在Android源代码工程中创建一个Android应用程序工程,名字就称为Broadcast吧。关于如何获得Android源代码工程,请参考在Ubuntu上下载、编译和安装Android最新源代码一文;关于如何在Android源代码工程中创建应用程序工程,请参考在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务一文。这个应用程序工程定义了一个名为shy.luo.broadcast的package,这个例子的源代码主要就是实现在这里了。下面,将会逐一介绍这个package里面的文件。 

        首先,我们在src/shy/luo/broadcast/ICounterService.java文件中定义计数器的服务接口:

package shy.luo.broadcast;

public interface ICounterService {
        public void startCounter(int initVal);
        public void stopCounter();
}


       这个接口很简单,它只有两个成员函数,分别用来启动和停止计数器;启动计数时,还可以指定计数器的初始值。

       接着,我们来看一个应用程序的默认Activity的实现,在src/shy/luo/broadcast/MainActivity.java文件中:

package shy.luo.broadcast;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener {
	private final static String LOG_TAG = "shy.luo.broadcast.MainActivity";
	   
	private Button startButton = null;
	private Button stopButton = null;
	private TextView counterText = null;
	
	private ICounterService counterService = null;
	
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
        
            startButton = (Button)findViewById(R.id.button_start);
            stopButton = (Button)findViewById(R.id.button_stop);
            counterText = (TextView)findViewById(R.id.textview_counter);
        
            startButton.setOnClickListener(this);
            stopButton.setOnClickListener(this);
        
            startButton.setEnabled(true);
            stopButton.setEnabled(false);
        
            Intent bindIntent = new Intent(MainActivity.this, CounterService.class);
            bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
        
            Log.i(LOG_TAG, "Main Activity Created.");
        }
    
        @Override 
        public void onResume() {
    	    super.onResume();
    	
    	    IntentFilter counterActionFilter = new IntentFilter(CounterService.BROADCAST_COUNTER_ACTION);
	    registerReceiver(counterActionReceiver, counterActionFilter);
        }
    
        @Override
        public void onPause() {
    	    super.onPause();
    	    unregisterReceiver(counterActionReceiver);
        }
    
        @Override
        public void onDestroy() {
    	    super.onDestroy();
    	    unbindService(serviceConnection);
        }
    
        @Override
        public void onClick(View v) {
    	    if(v.equals(startButton)) {
    		if(counterService != null) {
    			counterService.startCounter(0);
    			
	    		startButton.setEnabled(false);
	                stopButton.setEnabled(true);
    		}
    	    } else if(v.equals(stopButton)) {
    		if(counterService != null) {
    			counterService.stopCounter();
    			
    			startButton.setEnabled(true);
    			stopButton.setEnabled(false);
    		}
    	    }
        }
    
        private BroadcastReceiver counterActionReceiver = new BroadcastReceiver(){
		public void onReceive(Context context, Intent intent) {
			int counter = intent.getIntExtra(CounterService.COUNTER_VALUE, 0);
			String text = String.valueOf(counter);
			counterText.setText(text);
			
			Log.i(LOG_TAG, "Receive counter event");
		}
	};
	
	private ServiceConnection serviceConnection = new ServiceConnection() {
    	    public void onServiceConnected(ComponentName className, IBinder service) {
    		counterService = ((CounterService.CounterBinder)service).getService();
    		
    		Log.i(LOG_TAG, "Counter Service Connected");
    	    }
     	    public void onServiceDisconnected(ComponentName className) {
    		counterService = null;
    		Log.i(LOG_TAG, "Counter Service Disconnected");
    	    }
        };
}


        MainActivity的实现也很简单,它在创建(onCreate)的时候,会调用bindService函数来把计数器服务(CounterService)启动起来,它的第二个参数serviceConnection是一个ServiceConnection实例。计数器服务启动起来后,系统会调用这个实例的onServiceConnected函数将一个Binder对象传回来,通过调用这个Binder对象的getService函数,就可以获得计数器服务接口。这里,把这个计数器服务接口保存在MainActivity的counterService成员变量中。同样,当我们调用unbindService停止计数器服务时,系统会调用这个实例的onServiceDisconnected函数告诉MainActivity,它与计数器服务的连接断开了。

        注意,这里通过调用bindService函数来启动Service时,这个Service与启动它的Activity是位于同一个进程中,它不像我们在前面一篇文章Android系统在新进程中启动自定义服务过程(startService)的原理分析中所描述那样在新的进程中启动服务,后面我们再写一篇文章来分析bindService启动服务的过程。

        在MainActivity的onResume函数中,通过调用registerReceiver函数注册了一个广播接收器counterActionReceiver,它是一个BroadcastReceiver实例,并且指定了这个广播接收器只对CounterService.BROADCAST_COUNTER_ACTION类型的广播感兴趣。当CounterService发出一个CounterService.BROADCAST_COUNTER_ACTION类型的广播时,系统就会把这个广播发送到counterActionReceiver实例的onReceiver函数中去。在onReceive函数中,从参数intent中取出计数器当前的值,显示在界面上。

       MainActivity界面上有两个按钮,分别是Start Counter和Stop Counter按钮,点击前者开始计数,而点击后者则停止计数。

       计数器服务CounterService实现在src/shy/luo/broadcast/CounterService.java文件中:

package shy.luo.broadcast;

import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class CounterService extends Service implements ICounterService {
	private final static String LOG_TAG = "shy.luo.broadcast.CounterService";
	
	public final static String BROADCAST_COUNTER_ACTION = "shy.luo.broadcast.COUNTER_ACTION";
	public final static String COUNTER_VALUE = "shy.luo.broadcast.counter.value";
	
	private boolean stop = false;
	
	private final IBinder binder = new CounterBinder();
	
	public class CounterBinder extends Binder {
		public CounterService getService() {
			return CounterService.this;
		}
	}
	
	@Override
        public IBinder onBind(Intent intent) {
                return binder;
        }
	
	@Override
	public void onCreate() {
		super.onCreate();
		
		Log.i(LOG_TAG, "Counter Service Created.");
	}
	
	@Override
        public void onDestroy() {
    	        Log.i(LOG_TAG, "Counter Service Destroyed.");
        }
	
	public void startCounter(int initVal) {
    	        AsyncTask<Integer, Integer, Integer> task = new AsyncTask<Integer, Integer, Integer>() {	
			@Override
			protected Integer doInBackground(Integer... vals) {
				Integer initCounter = vals[0];
				
				stop = false;
				while(!stop) {
					publishProgress(initCounter);
					
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
					initCounter++;
				}
				
				return initCounter;
			}
			
			@Override 
			protected void onProgressUpdate(Integer... values) {
				super.onProgressUpdate(values);
				
				int counter = values[0];
				
				Intent intent = new Intent(BROADCAST_COUNTER_ACTION);
				intent.putExtra(COUNTER_VALUE, counter);
				
				sendBroadcast(intent);
			}
			
			@Override
			protected void onPostExecute(Integer val) {
				int counter = val;
				
				Intent intent = new Intent(BROADCAST_COUNTER_ACTION);
				intent.putExtra(COUNTER_VALUE, counter);
				
				sendBroadcast(intent);
			}
		
    	        };
			
    	        task.execute(0);	
        }

	public void stopCounter() {
		stop = true;
	}
}


        这个计数器服务实现了ICounterService接口。当这个服务被binderService函数启动时,系统会调用它的onBind函数,这个函数返回一个Binder对象给系统。上面我们说到,当MainActivity调用bindService函数来启动计数器服务器时,系统会调用MainActivity的ServiceConnection实例serviceConnection的onServiceConnected函数通知MainActivity,这个服务已经连接上了,并且会通过这个函数传进来一个Binder远程对象,这个Binder远程对象就是来源于这里的onBind的返回值了。

        函数onBind返回的Binder对象是一个自定义的CounterBinder实例,它实现了一个getService成员函数。当系统通知MainActivity,计数器服务已经启动起来并且连接成功后,并且将这个Binder对象传给MainActivity时,MainActivity就会把这个Binder对象强制转换为CounterBinder实例,然后调用它的getService函数获得服务接口。这样,MainActivity就通过这个Binder对象和CounterService关联起来了。

        当MainActivity调用计数器服务接口的startCounter函数时,计数器服务并不是直接进入计数状态,而是通过使用异步任务(AsyncTask)在后台线程中进行计数。这里为什么要使用异步任务来在后台线程中进行计数呢?前面我们说过,这个计数过程是一个耗时的计算型逻辑,不能把它放在界面线程中进行,因为这里的CounterService启动时,并没有在新的进程中启动,它与MainActivity一样,运行在应用程序的界面线程中,因此,这里需要使用异步任务在在后台线程中进行计数。

        异步任务AsyncTask的具体用法可以参考官方文档http://developer.android.com/reference/android/os/AsyncTask.html。它的大概用法是,当我们调用异步任务实例的execute(task.execute)方法时,当前调用线程就返回了,系统启动一个后台线程来执行这个异步任务实例的doInBackground函数,这个函数就是我们用来执行耗时计算的地方了,它会进入到一个循环中,每隔1秒钟就把计数器加1,然后进入休眠(Thread.sleep),醒过来,再重新这个计算过程。在计算的过程中,可以通过调用publishProgress函数来通知调用者当前计算的进度,好让调用者来更新界面,调用publishProgress函数的效果最终就是直入到这个异步任务实例的onProgressUpdate函数中,这里就可以把这个进度值以广播的形式(sendBroadcast)发送出去了,这里的进度值就定义为当前计数服务的计数值。

        当MainActivity调用计数器服务接口的stopCounter函数时,会告诉函数doInBackground停止执行计数(stop = true),于是,函数doInBackground就退出计数循环,然后将最终计数结果返回了,返回的结果最后进入到onPostExecute函数中,这个函数同样通过广播的形式(sendBroadcast)把这个计数结果广播出去。

        计算器服务就介绍到这里了,下面我们看看应用程序的配置文件AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="shy.luo.broadcast"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MainActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
	<service android:name=".CounterService"
		 android:enabled="true">
	</service>
    </application>
</manifest> 


        这个配置文件很简单,只是告诉系统,它有一个Activity和一个Service。

        再来看MainActivity的界面文件,它定义在res/layout/main.xml文件中:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:gravity="center">
    <LinearLayout
    	android:layout_width="fill_parent"
    	android:layout_height="wrap_content"
    	android:layout_marginBottom="10px"
    	android:orientation="horizontal" 
    	android:gravity="center">
	    <TextView  
	   	android:layout_width="wrap_content" 
	    	android:layout_height="wrap_content" 
	    	android:layout_marginRight="4px"
	    	android:gravity="center"
	    	android:text="@string/counter">
	    </TextView>
	    <TextView  
	    	android:id="@+id/textview_counter"
	   	android:layout_width="wrap_content" 
	    	android:layout_height="wrap_content" 
	    	android:gravity="center"
	    	android:text="0">
	    </TextView>
    </LinearLayout>
    <LinearLayout
    	android:layout_width="fill_parent"
    	android:layout_height="wrap_content"
    	android:orientation="horizontal" 
    	android:gravity="center">
	    <Button 
	    	android:id="@+id/button_start"
	    	android:layout_width="wrap_content"
	    	android:layout_height="wrap_content"
	    	android:gravity="center"
	    	android:text="@string/start">
	    </Button>
	    <Button 
	    	android:id="@+id/button_stop"
	    	android:layout_width="wrap_content"
	    	android:layout_height="wrap_content"
	    	android:gravity="center"
	    	android:text="@string/stop" >
	    </Button>
     </LinearLayout>  
</LinearLayout>


        这个界面配置文件也很简单,等一下我们在模拟器把这个应用程序启动起来后,就可以看到它的截图了。

        应用程序用到的字符串资源文件位于res/values/strings.xml文件中:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Broadcast</string>
    <string name="counter">Counter: </string>
    <string name="start">Start Counter</string>
    <string name="stop">Stop Counter</string>
</resources>


         最后,我们还要在工程目录下放置一个编译脚本文件Android.mk:

LOCAL_PATH:= $(call my-dir)      
include $(CLEAR_VARS)      
      
LOCAL_MODULE_TAGS := optional      
      
LOCAL_SRC_FILES := $(call all-subdir-java-files)      
      
LOCAL_PACKAGE_NAME := Broadcast      
      
include $(BUILD_PACKAGE)  


          接下来就要编译了。有关如何单独编译Android源代码工程的模块,以及如何打包system.img,请参考如何单独编译Android源代码中的模块一文。
          执行以下命令进行编译和打包:

USER-NAME@MACHINE-NAME:~/Android$ mmm packages/experimental/Broadcast        
USER-NAME@MACHINE-NAME:~/Android$ make snod   


         这样,打包好的Android系统镜像文件system.img就包含我们前面创建的Broadcast应用程序了。
         再接下来,就是运行模拟器来运行我们的例子了。关于如何在Android源代码工程中运行模拟器,请参考在Ubuntu上下载、编译和安装Android最新源代码一文。
         执行以下命令启动模拟器:

USER-NAME@MACHINE-NAME:~/Android$ emulator


        模拟器启动起,就可以App Launcher中找到Broadcast应用程序图标,接着把它启动起来,然后点击界面上的Start Counter按钮,就可以把计数器服务启动起来了,计数器服务又通过广播把计数值反馈给MainActivity,于是,我们就会在MainActivity界面看到计数器的值不断地增加了:

        这样,使用广播的例子就介绍完了。回顾一下,使用广播的两个步骤:

        1. 广播的接收者需要通过调用registerReceiver函数告诉系统,它对什么样的广播有兴趣,即指定IntentFilter,并且向系统注册广播接收器,即指定BroadcastReceiver:

IntentFilter counterActionFilter = new IntentFilter(CounterService.BROADCAST_COUNTER_ACTION);
registerReceiver(counterActionReceiver, counterActionFilter);


        这里,指定感兴趣的广播就是CounterService.BROADCAST_COUNTER_ACTION了,而指定的广播接收器就是counterActonReceiver,它是一个BroadcastReceiver类型的实例。

        2. 广播的发送者通过调用sendBroadcast函数来发送一个指定的广播,并且可以指定广播的相关参数:

Intent intent = new Intent(BROADCAST_COUNTER_ACTION);
intent.putExtra(COUNTER_VALUE, counter);
sendBroadcast(intent)


        这里,指定的广播为CounterService.BROADCAST_COUNTER_ACTION,并且附带的带参数当前的计数器值counter。调用了sendBroadcast函数之后,所有注册了CounterService.BROADCAST_COUNTER_ACTION广播的接收者便可以收到这个广播了。

        在第1步中,广播的接收者把广播接收器注册到ActivityManagerService中;在第2步中,广播的发送者同样是把广播发送到ActivityManagerService中,由ActivityManagerService去查找注册了这个广播的接收者,然后把广播分发给它们。

        在第2步的分发的过程,其实就是把这个广播转换成一个消息,然后放入到接收器所在的线程消息队列中去,最后就可以在消息循环中调用接收器的onReceive函数了。这里有一个要非常注意的地方是,由于ActivityManagerService把这个广播放进接收器所在的线程消息队列后,就返回了,它不关心这个消息什么时候会被处理,因此,对广播的处理是异步的,即调用sendBroadcast时,这个函数不会等待这个广播被处理完后才返回。

        下面,我们以一个序列图来总结一下,广播的注册和发送的过程:


        虚线上面Step 1到Step 4步是注册广播接收器的过程,其中Step 2通过LoadedApk.getReceiverDispatcher在LoadedApk内部创建了一个IIntentReceiver接口,并且传递给ActivityManagerService;虚线下面的Step 5到Step 11是发送广播的过程,在Step 8中,ActivityManagerService利用上面得到的IIntentReceiver远程接口,调用LoadedApk.performReceiver接口,LoadedApk.performReceiver接口通过ActivityThread.H接口的post函数将这个广播消息放入到ActivityThread的消息队列中去,最后这个消息在LoadedApk的Args.run函数中处理,LoadedApk.Args.run函数接着调用MainActivity.BroadcastReceiver的onReceive函数来最终处理这个广播。

        第二部分:android应用程序注册广播接收器流程分析

        前面我们介绍了Android系统的广播机制,从本质来说,它是一种消息订阅/发布机制,因此,使用这种消息驱动模型的第一步便是订阅消息;而对Android应用程序来说,订阅消息其实就是注册广播接收器,本文将探讨Android应用程序是如何注册广播接收器以及把广播接收器注册到哪里去的。

        在Android的广播机制中,ActivityManagerService扮演着广播中心的角色,负责系统中所有广播的注册和发布操作,因此,Android应用程序注册广播接收器的过程就把是广播接收器注册到ActivityManagerService的过程。Android应用程序是通过调用ContextWrapper类的registerReceiver函数来把广播接收器BroadcastReceiver注册到ActivityManagerService中去的,而ContextWrapper类本身又借助ContextImpl类来注册广播接收器。

        在Android应用程序框架中,Activity和Service类都继承了ContextWrapper类,因此,我们可以在Activity或者Service的子类中调用registerReceiver函数来注册广播接收器。Activity、Service、ContextWrapper和ContextImpl这四个类的关系可以参考前面Android系统在新进程中启动自定义服务过程(startService)的原理分析一文中描述的Activity类图。

        这篇文章还是继续以实例来进行情景分析,所用到的例子便是上一篇文章Android系统中的广播(Broadcast)机制简要介绍和学习计划里面介绍的应用程序了,所以希望读者在继续阅读本文之前,先看看这篇文章;又由于Android应用程序是把广播接器注册到ActivityManagerService中去的,因此,这里又会涉入到Binder进程间通信机制,所以希望读者对Android系统的Binder进程间通信机制有所了解,具体请参考Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。

        开始进入主题了,在Android系统中的广播(Broadcast)机制简要介绍和学习计划一文所介绍的例子中,注册广播接收器的操作是MainActivity发起的,我们先来看看注册过程的序列图:


        在分析这个序列图之前,我们先来看一下MainActivity是如何调用registerReceiver函数来注册广播接收器的:

public class MainActivity extends Activity implements OnClickListener {  
	......

	@Override   
	public void onResume() {  
		super.onResume();  

		IntentFilter counterActionFilter = new IntentFilter(CounterService.BROADCAST_COUNTER_ACTION);  
		registerReceiver(counterActionReceiver, counterActionFilter);  
	} 

	......

}


        MainActivity在onResume函数里,通过其父类ContextWrapper的registerReceiver函数注册了一个BroadcastReceiver实例counterActionReceiver,并且通过IntentFilter实例counterActionFilter告诉ActivityManagerService,它要订阅的广播是CounterService.BROADCAST_COUNTER_ACTION类型的,这样,ActivityManagerService在收到CounterService.BROADCAST_COUNTER_ACTION类型的广播时,就会分发给counterActionReceiver实例的onReceive函数。

        接下来,就开始分析注册过程中的每一个步骤了。

        Step 1. ContextWrapper.registerReceiver

        这个函数实现在frameworks/base/core/java/android/content/ContextWrapper.java文件中:

public class ContextWrapper extends Context {
	Context mBase;
	......

	@Override
	public Intent registerReceiver(
		BroadcastReceiver receiver, IntentFilter filter) {
		return mBase.registerReceiver(receiver, filter);
	}

	......

}


        这里的成员变量mBase是一个ContextImpl实例,想知道为什么,可以回过头去看看Android应用程序启动过程源代码分析这篇文章>~<。

        Step 2. ContextImpl.registerReceiver

        这个函数实现在frameworks/base/core/java/android/app/ContextImpl.java文件中:

class ContextImpl extends Context {
	......

	@Override
	public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
		return registerReceiver(receiver, filter, null, null);
	}

	@Override
	public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
			String broadcastPermission, Handler scheduler) {
		return registerReceiverInternal(receiver, filter, broadcastPermission,
			scheduler, getOuterContext());
	}

	private Intent registerReceiverInternal(BroadcastReceiver receiver,
			IntentFilter filter, String broadcastPermission,
			Handler scheduler, Context context) {
		IIntentReceiver rd = null;
		if (receiver != null) {
			if (mPackageInfo != null && context != null) {
				if (scheduler == null) {
					scheduler = mMainThread.getHandler();
				}
				rd = mPackageInfo.getReceiverDispatcher(
					receiver, context, scheduler,
					mMainThread.getInstrumentation(), true);
			} else {
				......
			}
		}
		try {
			return ActivityManagerNative.getDefault().registerReceiver(
					mMainThread.getApplicationThread(),
					rd, filter, broadcastPermission);
		} catch (RemoteException e) {
				return null;
		}
	}

	......

}


        通过两个函数的中转,最终就进入到ContextImpl.registerReceiverInternal这个函数来了。这里的成员变量mPackageInfo是一个LoadedApk实例,它是用来负责处理广播的接收的,在后面一篇文章讲到广播的发送时(sendBroadcast),会详细描述。参数broadcastPermission和scheduler都为null,而参数context是上面的函数通过调用函数getOuterContext得到的,这里它就是指向MainActivity了,因为MainActivity是继承于Context类的,因此,这里用Context类型来引用。

        由于条件mPackageInfo != null和context != null都成立,而且条件scheduler == null也成立,于是就调用mMainThread.getHandler来获得一个Handler了,这个Hanlder是后面用来分发ActivityManagerService发送过的广播用的。这里的成员变量mMainThread是一个ActivityThread实例,在前面Android应用程序启动过程源代码分析这篇文章也描述过了。我们先来看看ActivityThread.getHandler函数的实现,然后再回过头来继续分析ContextImpl.registerReceiverInternal函数。

        Step 3. ActivityThread.getHandler

        这个函数实现在frameworks/base/core/java/android/app/ActivityThread.java文件中:

public final class ActivityThread {
	......

	final H mH = new H();

	private final class H extends Handler {
		......

		public void handleMessage(Message msg) {
			......

			switch (msg.what) {
			......
			}

			......
		}

		......

	}

	......

	final Handler getHandler() {
		return mH;
	}

	......

}


        有了这个Handler之后,就可以分发消息给应用程序处理了。

        再回到上一步的ContextImpl.registerReceiverInternal函数中,它通过mPackageInfo.getReceiverDispatcher函数获得一个IIntentReceiver接口对象rd,这是一个Binder对象,接下来会把它传给ActivityManagerService,ActivityManagerService在收到相应的广播时,就是通过这个Binder对象来通知MainActivity来接收的。

        我们也是先来看一下mPackageInfo.getReceiverDispatcher函数的实现,然后再回过头来继续分析ContextImpl.registerReceiverInternal函数。

        Step 4. LoadedApk.getReceiverDispatcher

        这个函数实现在frameworks/base/core/java/android/app/LoadedApk.java文件中:

final class LoadedApk {
	......

	public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
			Context context, Handler handler,
			Instrumentation instrumentation, boolean registered) {
		synchronized (mReceivers) {
			LoadedApk.ReceiverDispatcher rd = null;
			HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
			if (registered) {
				map = mReceivers.get(context);
				if (map != null) {
					rd = map.get(r);
				}
			}
			if (rd == null) {
				rd = new ReceiverDispatcher(r, context, handler,
					instrumentation, registered);
				if (registered) {
					if (map == null) {
						map = new HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
						mReceivers.put(context, map);
					}
					map.put(r, rd);
				}
			} else {
				rd.validate(context, handler);
			}
			return rd.getIIntentReceiver();
		}
	}

	......

	static final class ReceiverDispatcher {

		final static class InnerReceiver extends IIntentReceiver.Stub {
			final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
			......

			InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
				mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
				......
			}

			......
		}

		......

		final IIntentReceiver.Stub mIIntentReceiver;
		final Handler mActivityThread;

		......

		ReceiverDispatcher(BroadcastReceiver receiver, Context context,
				Handler activityThread, Instrumentation instrumentation,
				boolean registered) {
			......

			mIIntentReceiver = new InnerReceiver(this, !registered);
			mActivityThread = activityThread;
			
			......
		}

		......

		IIntentReceiver getIIntentReceiver() {
			return mIIntentReceiver;
		}

	}

	......

}


 

        在LoadedApk.getReceiverDispatcher函数中,首先看一下参数r是不是已经有相应的ReceiverDispatcher存在了,如果有,就直接返回了,否则就新建一个ReceiverDispatcher,并且以r为Key值保在一个HashMap中,而这个HashMap以Context,这里即为MainActivity为Key值保存在LoadedApk的成员变量mReceivers中,这样,只要给定一个Activity和BroadcastReceiver,就可以查看LoadedApk里面是否已经存在相应的广播接收发布器ReceiverDispatcher了。

        在新建广播接收发布器ReceiverDispatcher时,会在构造函数里面创建一个InnerReceiver实例,这是一个Binder对象,实现了IIntentReceiver接口,可以通过ReceiverDispatcher.getIIntentReceiver函数来获得,获得后就会把它传给ActivityManagerService,以便接收广播。在ReceiverDispatcher类的构造函数中,还会把传进来的Handle类型的参数activityThread保存下来,以便后面在分发广播的时候使用。

        现在,再回到ContextImpl.registerReceiverInternal函数,在获得了IIntentReceiver类型的Binder对象后,就开始要把它注册到ActivityManagerService中去了。

        Step 5. ActivityManagerProxy.registerReceiver

        这个函数实现在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:

class ActivityManagerProxy implements IActivityManager
{
	......

	public Intent registerReceiver(IApplicationThread caller,
			IIntentReceiver receiver,
			IntentFilter filter, String perm) throws RemoteException
	{
		Parcel data = Parcel.obtain();
		Parcel reply = Parcel.obtain();
		data.writeInterfaceToken(IActivityManager.descriptor);
		data.writeStrongBinder(caller != null ? caller.asBinder() : null);
		data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
		filter.writeToParcel(data, 0);
		data.writeString(perm);
		mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
		reply.readException();
		Intent intent = null;
		int haveIntent = reply.readInt();
		if (haveIntent != 0) {
			intent = Intent.CREATOR.createFromParcel(reply);
		}
		reply.recycle();
		data.recycle();
		return intent;
	}

	......

}


         这个函数通过Binder驱动程序就进入到ActivityManagerService中的registerReceiver函数中去了。

         Step 6. ActivityManagerService.registerReceiver

         这个函数实现在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

public final class ActivityManagerService extends ActivityManagerNative
		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	......

	public Intent registerReceiver(IApplicationThread caller,
			IIntentReceiver receiver, IntentFilter filter, String permission) {
		synchronized(this) {
			ProcessRecord callerApp = null;
			if (caller != null) {
				callerApp = getRecordForAppLocked(caller);
				if (callerApp == null) {
					......
				}
			}

			List allSticky = null;

			// Look for any matching sticky broadcasts...
			Iterator actions = filter.actionsIterator();
			if (actions != null) {
				while (actions.hasNext()) {
					String action = (String)actions.next();
					allSticky = getStickiesLocked(action, filter, allSticky);
				}
			} else {
				......
			}

			// The first sticky in the list is returned directly back to
			// the client.
			Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;

			......

			if (receiver == null) {
				return sticky;
			}

			ReceiverList rl
				= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
			if (rl == null) {
				rl = new ReceiverList(this, callerApp,
					Binder.getCallingPid(),
					Binder.getCallingUid(), receiver);

				if (rl.app != null) {
					rl.app.receivers.add(rl);
				} else {
					......
				}
				mRegisteredReceivers.put(receiver.asBinder(), rl);
			}

			BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
			rl.add(bf);
			......
			mReceiverResolver.addFilter(bf);

			// Enqueue broadcasts for all existing stickies that match
			// this filter.
			if (allSticky != null) {
				......
			}

			return sticky;
		}
	}

	......

}


         函数首先是获得调用registerReceiver函数的应用程序进程记录块:

    ProcessRecord callerApp = null;
    if (caller != null) {
	callerApp = getRecordForAppLocked(caller);
	if (callerApp == null) {
	    ......
        }
    }


        这里得到的便是上一篇文章Android系统中的广播(Broadcast)机制简要介绍和学习计划里面介绍的应用程序Broadcast的进程记录块了,MainActivity就是在里面启动起来的。

    List allSticky = null;

    // Look for any matching sticky broadcasts...
    Iterator actions = filter.actionsIterator();
    if (actions != null) {
	while (actions.hasNext()) {
		String action = (String)actions.next();
		allSticky = getStickiesLocked(action, filter, allSticky);
	}
    } else {
	......
    }

    // The first sticky in the list is returned directly back to
    // the client.
    Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;


        这里传进来的filter只有一个action,就是前面描述的CounterService.BROADCAST_COUNTER_ACTION了,这里先通过getStickiesLocked函数查找一下有没有对应的sticky intent列表存在。什么是Sticky Intent呢?我们在最后一次调用sendStickyBroadcast函数来发送某个Action类型的广播时,系统会把代表这个广播的Intent保存下来,这样,后来调用registerReceiver来注册相同Action类型的广播接收器,就会得到这个最后发出的广播。这就是为什么叫做Sticky Intent了,这个最后发出的广播虽然被处理完了,但是仍然被粘住在ActivityManagerService中,以便下一个注册相应Action类型的广播接收器还能继承处理。

        这里,假设我们不使用sendStickyBroadcast来发送CounterService.BROADCAST_COUNTER_ACTION类型的广播,于是,这里得到的allSticky和sticky都为null了。

        继续往下看,这里传进来的receiver不为null,于是,继续往下执行:

    ReceiverList rl
	= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
    if (rl == null) {
	rl = new ReceiverList(this, callerApp,
		Binder.getCallingPid(),
		Binder.getCallingUid(), receiver);

	if (rl.app != null) {
		rl.app.receivers.add(rl);
	} else {
		......
	}
	mRegisteredReceivers.put(receiver.asBinder(), rl);
    }


        这里其实就是把广播接收器receiver保存一个ReceiverList列表中,这个列表的宿主进程是rl.app,这里就是MainActivity所在的进程了,在ActivityManagerService中,用一个进程记录块来表示这个应用程序进程,它里面有一个列表receivers,专门用来保存这个进程注册的广播接收器。接着,又把这个ReceiverList列表以receiver为Key值保存在ActivityManagerService的成员变量mRegisteredReceivers中,这些都是为了方便在收到广播时,快速找到对应的广播接收器的。

        再往下看:

    BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
    rl.add(bf);
    ......
    mReceiverResolver.addFilter(bf);


        上面只是把广播接收器receiver保存起来了,但是还没有把它和filter关联起来,这里就创建一个BroadcastFilter来把广播接收器列表rl和filter关联起来,然后保存在ActivityManagerService中的成员变量mReceiverResolver中去。

        这样,广播接收器注册的过程就介绍完了,比较简单,但是工作又比较琐碎,主要就是将广播接收器receiver及其要接收的广播类型filter保存在ActivityManagerService中,以便以后能够接收到相应的广播并进行处理。

        第三部分:android应用程序发送广播流程分析

        前面我们分析了Android应用程序注册广播接收器的过程,这个过程只完成了万里长征的第一步,接下来它还要等待ActivityManagerService将广播分发过来。ActivityManagerService是如何得到广播并把它分发出去的呢?这就是本文要介绍的广播发送过程了。

        广播的发送过程比广播接收器的注册过程要复杂得多了,不过这个过程仍然是以ActivityManagerService为中心。广播的发送者将广播发送到ActivityManagerService,ActivityManagerService接收到这个广播以后,就会在自己的注册中心查看有哪些广播接收器订阅了该广播,然后把这个广播逐一发送到这些广播接收器中,但是ActivityManagerService并不等待广播接收器处理这些广播就返回了,因此,广播的发送和处理是异步的。概括来说,广播的发送路径就是从发送者到ActivityManagerService,再从ActivityManagerService到接收者,这中间的两个过程都是通过Binder进程间通信机制来完成的,因此,希望读者在继续阅读本文之前,对Android系统的Binder进程间通信机制有所了解,具体可以参考Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。

        本文继续以Android系统中的广播(Broadcast)机制简要介绍和学习计划一文中所开发的应用程序为例子,并且结合上文Android应用程序注册广播接收器(registerReceiver)的过程分析的内容,一起来分析Android应用程序发送广播的过程。

        回顾一下Android系统中的广播(Broadcast)机制简要介绍和学习计划一文中所开发的应用程序的组织架构,MainActivity向ActivityManagerService注册了一个CounterService.BROADCAST_COUNTER_ACTION类型的计数器服务广播接收器,计数器服务CounterService在后台线程中启动了一个异步任务(AsyncTask),这个异步任务负责不断地增加计数,并且不断地将当前计数值通过广播的形式发送出去,以便MainActivity可以将当前计数值在应用程序的界面线程中显示出来。

        计数器服务CounterService发送广播的代码如下所示:

public class CounterService extends Service implements ICounterService {  
	...... 

	public void startCounter(int initVal) {  
		AsyncTask<Integer, Integer, Integer> task = new AsyncTask<Integer, Integer, Integer>() {      
			@Override  
			protected Integer doInBackground(Integer... vals) {  
				......  
			}  

			@Override   
			protected void onProgressUpdate(Integer... values) {  
				super.onProgressUpdate(values);  

				int counter = values[0];  

				Intent intent = new Intent(BROADCAST_COUNTER_ACTION);  
				intent.putExtra(COUNTER_VALUE, counter);  

				sendBroadcast(intent);  
			}  

			@Override  
			protected void onPostExecute(Integer val) {  
				...... 
			}  

		};  

		task.execute(0);      
	}  

	......
}


        在onProgressUpdate函数中,创建了一个BROADCAST_COUNTER_ACTION类型的Intent,并且在这里个Intent中附加上当前的计数器值,然后通过CounterService类的成员函数sendBroadcast将这个Intent发送出去。CounterService类继承了Service类,Service类又继承了ContextWrapper类,成员函数sendBroadcast就是从ContextWrapper类继承下来的,因此,我们就从ContextWrapper类的sendBroadcast函数开始,分析广播发送的过程。

        在继承分析广播的发送过程前,我们先来看一下广播发送过程的序列图,然后按照这个序图中的步骤来一步一步分析整个过程。


        Step 1. ContextWrapper.sendBroadcast

        这个函数定义在frameworks/base/core/java/android/content/ContextWrapper.java文件中:

public class ContextWrapper extends Context {
	Context mBase;

	......

	@Override
	public void sendBroadcast(Intent intent) {
		mBase.sendBroadcast(intent);
	}

	......

}


         这里的成员变量mBase是一个ContextImpl实例,这里只简单地调用ContextImpl.sendBroadcast进一行操作。

         Step 2. ContextImpl.sendBroadcast

         这个函数定义在frameworks/base/core/java/android/app/ContextImpl.java文件中:

class ContextImpl extends Context {
	......

	@Override
	public void sendBroadcast(Intent intent) {
		String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
		try {
			ActivityManagerNative.getDefault().broadcastIntent(
				mMainThread.getApplicationThread(), intent, resolvedType, null,
				Activity.RESULT_OK, null, null, null, false, false);
		} catch (RemoteException e) {
		}
	}

	......

}


        这里的resolvedType表示这个Intent的MIME类型,我们没有设置这个Intent的MIME类型,因此,这里的resolvedType为null。接下来就调用ActivityManagerService的远程接口ActivityManagerProxy把这个广播发送给ActivityManagerService了。

        Step 3. ActivityManagerProxy.broadcastIntent

        这个函数定义在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:

class ActivityManagerProxy implements IActivityManager
{
	......

	public int broadcastIntent(IApplicationThread caller,
		Intent intent, String resolvedType,  IIntentReceiver resultTo,
		int resultCode, String resultData, Bundle map,
		String requiredPermission, boolean serialized,
		boolean sticky) throws RemoteException
	{
		Parcel data = Parcel.obtain();
		Parcel reply = Parcel.obtain();
		data.writeInterfaceToken(IActivityManager.descriptor);
		data.writeStrongBinder(caller != null ? caller.asBinder() : null);
		intent.writeToParcel(data, 0);
		data.writeString(resolvedType);
		data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null);
		data.writeInt(resultCode);
		data.writeString(resultData);
		data.writeBundle(map);
		data.writeString(requiredPermission);
		data.writeInt(serialized ? 1 : 0);
		data.writeInt(sticky ? 1 : 0);
		mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
		reply.readException();
		int res = reply.readInt();
		reply.recycle();
		data.recycle();
		return res;
	}

	......

}


         这里的实现比较简单,把要传递的参数封装好,然后通过Binder驱动程序进入到ActivityManagerService的broadcastIntent函数中。

         Step 4. ctivityManagerService.broadcastIntent

         这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

public final class ActivityManagerService extends ActivityManagerNative
		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	......

	public final int broadcastIntent(IApplicationThread caller,
			Intent intent, String resolvedType, IIntentReceiver resultTo,
			int resultCode, String resultData, Bundle map,
			String requiredPermission, boolean serialized, boolean sticky) {
		synchronized(this) {
			intent = verifyBroadcastLocked(intent);

			final ProcessRecord callerApp = getRecordForAppLocked(caller);
			final int callingPid = Binder.getCallingPid();
			final int callingUid = Binder.getCallingUid();
			final long origId = Binder.clearCallingIdentity();
			int res = broadcastIntentLocked(callerApp,
				callerApp != null ? callerApp.info.packageName : null,
				intent, resolvedType, resultTo,
				resultCode, resultData, map, requiredPermission, serialized,
				sticky, callingPid, callingUid);
			Binder.restoreCallingIdentity(origId);
			return res;
		}
	}

	......
}


         这里调用broadcastIntentLocked函数来进一步处理。

         Step 5. ActivityManagerService.broadcastIntentLocked

         这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

public final class ActivityManagerService extends ActivityManagerNative
		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	......

	private final int broadcastIntentLocked(ProcessRecord callerApp,
			String callerPackage, Intent intent, String resolvedType,
			IIntentReceiver resultTo, int resultCode, String resultData,
			Bundle map, String requiredPermission,
			boolean ordered, boolean sticky, int callingPid, int callingUid) {
		intent = new Intent(intent);

		......

		// Figure out who all will receive this broadcast.
		List receivers = null;
		List<BroadcastFilter> registeredReceivers = null;
		try {
			if (intent.getComponent() != null) {
				......
			} else {
				......
				registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
			}
		} catch (RemoteException ex) {
			......
		}

		final boolean replacePending =
			(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

		int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
		if (!ordered && NR > 0) {
			// If we are not serializing this broadcast, then send the
			// registered receivers separately so they don't wait for the
			// components to be launched.
			BroadcastRecord r = new BroadcastRecord(intent, callerApp,
				callerPackage, callingPid, callingUid, requiredPermission,
				registeredReceivers, resultTo, resultCode, resultData, map,
				ordered, sticky, false);
			......
			boolean replaced = false;
			if (replacePending) {
				for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
					if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
						......
						mParallelBroadcasts.set(i, r);
						replaced = true;
						break;
					}
				}
			}

			if (!replaced) {
				mParallelBroadcasts.add(r);

				scheduleBroadcastsLocked();
			}

			registeredReceivers = null;
			NR = 0;
		}

		......

	}

	......
}


         这个函数首先是根据intent找出相应的广播接收器:

    // Figure out who all will receive this broadcast.
    List receivers = null;
    List<BroadcastFilter> registeredReceivers = null;
    try {
	if (intent.getComponent() != null) {
	        ......
	} else {
		......
		registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
	}
    } catch (RemoteException ex) {
	......
    }


        回忆一下前面一篇文章Android应用程序注册广播接收器(registerReceiver)的过程分析中的Step 6(ActivityManagerService.registerReceiver)中,我们将一个filter类型为BROADCAST_COUNTER_ACTION类型的BroadcastFilter实例保存在了ActivityManagerService的成员变量mReceiverResolver中,这个BroadcastFilter实例包含了我们所注册的广播接收器,这里就通过mReceiverResolver.queryIntent函数将这个BroadcastFilter实例取回来。由于注册一个广播类型的接收器可能有多个,所以这里把所有符合条件的的BroadcastFilter实例放在一个List中,然后返回来。在我们这个场景中,这个List就只有一个BroadcastFilter实例了,就是MainActivity注册的那个广播接收器。

       继续往下看:

   final boolean replacePending =
	    (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;


       这里是查看一下这个intent的Intent.FLAG_RECEIVER_REPLACE_PENDING位有没有设置,如果设置了的话,ActivityManagerService就会在当前的系统中查看有没有相同的intent还未被处理,如果有的话,就有当前这个新的intent来替换旧的intent。这里,我们没有设置intent的Intent.FLAG_RECEIVER_REPLACE_PENDING位,因此,这里的replacePending变量为false。

       再接着往下看:

   int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
   if (!ordered && NR > 0) {
	// If we are not serializing this broadcast, then send the
	// registered receivers separately so they don't wait for the
	// components to be launched.
	BroadcastRecord r = new BroadcastRecord(intent, callerApp,
		callerPackage, callingPid, callingUid, requiredPermission,
		registeredReceivers, resultTo, resultCode, resultData, map,
		ordered, sticky, false);
	......
	boolean replaced = false;
	if (replacePending) {
		for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
			if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
				......
				mParallelBroadcasts.set(i, r);
				replaced = true;
				break;
			}
		}
	}

	if (!replaced) {
		mParallelBroadcasts.add(r);

		scheduleBroadcastsLocked();
	}

	registeredReceivers = null;
	NR = 0;
    }


        前面我们说到,这里得到的列表registeredReceivers的大小为1,且传进来的参数ordered为false,表示要将这个广播发送给所有注册了BROADCAST_COUNTER_ACTION类型广播的接收器,因此,会执行下面的if语句。这个if语句首先创建一个广播记录块BroadcastRecord,里面记录了这个广播是由谁发出的以及要发给谁等相关信息。由于前面得到的replacePending变量为false,因此,不会执行接下来的if语句,即不会检查系统中是否有相同类型的未处理的广播。

        这样,这里得到的replaced变量的值也为false,于是,就会把这个广播记录块r放在ActivityManagerService的成员变量mParcelBroadcasts中,等待进一步处理;进一步处理的操作由函数scheduleBroadcastsLocked进行。

        Step 6. ActivityManagerService.scheduleBroadcastsLocked

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

public final class ActivityManagerService extends ActivityManagerNative
		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	......

	private final void scheduleBroadcastsLocked() {
		......

		if (mBroadcastsScheduled) {
			return;
		}

		mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
		mBroadcastsScheduled = true;
	}

	......
}


        这里的mBroadcastsScheduled表示ActivityManagerService当前是不是正在处理其它广播,如果是的话,这里就先不处理直接返回了,保证所有广播串行处理。

        注意这里处理广播的方式,它是通过消息循环来处理,每当ActivityManagerService接收到一个广播时,它就把这个广播放进自己的消息队列去就完事了,根本不管这个广播后续是处理的,因此,这里我们可以看出广播的发送和处理是异步的。

        这里的成员变量mHandler是一个在ActivityManagerService内部定义的Handler类变量,通过它的sendEmptyMessage函数把一个类型为BROADCAST_INTENT_MSG的空消息放进ActivityManagerService的消息队列中去。这里的空消息是指这个消息除了有类型信息之外,没有任何其它额外的信息,因为前面已经把要处理的广播信息都保存在mParcelBroadcasts中了,等处理这个消息时,从mParcelBroadcasts就可以读回相关的广播信息了,因此,这里不需要把广播信息再放在消息内容中。

        Step 7. Handler.sendEmptyMessage

        这个自定义的Handler类实现在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中,它是ActivityManagerService的内部类,调用了它的sendEmptyMessage函数来把一个消息放到消息队列后,一会就会调用它的handleMessage函数来真正处理这个消息:

public final class ActivityManagerService extends ActivityManagerNative
		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	......

	final Handler mHandler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
			......
			case BROADCAST_INTENT_MSG: {
				......
				processNextBroadcast(true);
			} break;
			......
			}
		}
	}

	......
} 


        这里又调用了ActivityManagerService的processNextBroadcast函数来处理下一个未处理的广播。

        Step 8. ActivityManagerService.processNextBroadcast

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

public final class ActivityManagerService extends ActivityManagerNative
		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	......

	private final void processNextBroadcast(boolean fromMsg) {
		synchronized(this) {
			BroadcastRecord r;

			......

			if (fromMsg) {
				mBroadcastsScheduled = false;
			}

			// First, deliver any non-serialized broadcasts right away.
			while (mParallelBroadcasts.size() > 0) {
				r = mParallelBroadcasts.remove(0);
				......
				final int N = r.receivers.size();
				......
				for (int i=0; i<N; i++) {
					Object target = r.receivers.get(i);
					......

					deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
				}
				addBroadcastToHistoryLocked(r);
				......
			}

			......

		}
	}

	......
}


        这里传进来的参数fromMsg为true,于是把mBroadcastScheduled重新设为false,这样,下一个广播就能进入到消息队列中进行处理了。前面我们在Step 5中,把一个广播记录块BroadcastRecord放在了mParallelBroadcasts中,因此,这里就把它取出来进行处理了。广播记录块BroadcastRecord的receivers列表中包含了要接收这个广播的目标列表,即前面我们注册的广播接收器,用BroadcastFilter来表示,这里while循环中的for循环就是把这个广播发送给每一个订阅了该广播的接收器了,通过deliverToRegisteredReceiverLocked函数执行。

        Step 9. ActivityManagerService.deliverToRegisteredReceiverLocked

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

public final class ActivityManagerService extends ActivityManagerNative
		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	......

	private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
			BroadcastFilter filter, boolean ordered) {
		boolean skip = false;
		if (filter.requiredPermission != null) {
			......
		}
		if (r.requiredPermission != null) {
			......
		}

		if (!skip) {
			// If this is not being sent as an ordered broadcast, then we
			// don't want to touch the fields that keep track of the current
			// state of ordered broadcasts.
			if (ordered) {
				......
			}

			try {
				......
				performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
					new Intent(r.intent), r.resultCode,
					r.resultData, r.resultExtras, r.ordered, r.initialSticky);
				......
			} catch (RemoteException e) {
				......
			}
		}

	}

	......
}


         函数首先是检查一下广播发送和接收的权限,在我们分析的这个场景中,没有设置权限,因此,这个权限检查就跳过了,这里得到的skip为false,于是进入下面的if语句中。由于上面传时来的ordered参数为false,因此,直接就调用performReceiveLocked函数来进一步执行广播发送的操作了。

        Step 10. ActivityManagerService.performReceiveLocked

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

public final class ActivityManagerService extends ActivityManagerNative
		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	......

	static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
			Intent intent, int resultCode, String data, Bundle extras,
			boolean ordered, boolean sticky) throws RemoteException {
		// Send the intent to the receiver asynchronously using one-way binder calls.
		if (app != null && app.thread != null) {
			// If we have an app thread, do the call through that so it is
			// correctly ordered with other one-way calls.
			app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
					data, extras, ordered, sticky);
		} else {
			......
		}
	}

	......
}


        注意,这里传进来的参数app是注册广播接收器的Activity所在的进程记录块,在我们分析的这个场景中,由于是MainActivity调用registerReceiver函数来注册这个广播接收器的,因此,参数app所代表的ProcessRecord就是MainActivity所在的进程记录块了;而参数receiver也是注册广播接收器时传给ActivityManagerService的一个Binder对象,它的类型是IIntentReceiver,具体可以参考上一篇文章Android应用程序注册广播接收器(registerReceiver)的过程分析中的Step 2。

       MainActivity在注册广播接收器时,已经把自己的ProcessRecord记录下来了,所以这里的参数app和app.thread均不为null,于是,ActivityManagerService就调用app.thread.scheduleRegisteredReceiver函数来把这个广播分发给MainActivity了。这里的app.thread是一个Binder远程对象,它的类型是ApplicationThreadProxy,我们在前面介绍应用程序的Activity启动过程时,已经多次看到了,具体可以参考主题Android应用程序的Activity启动过程简要介绍和学习计划

       Step 11. ApplicationThreadProxy.scheduleRegisteredReceiver
       这个函数定义在frameworks/base/core/java/android/app/ApplicationThreadNative.java文件中:

class ApplicationThreadProxy implements IApplicationThread {
	......

	public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
			int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky)
			throws RemoteException {
		Parcel data = Parcel.obtain();
		data.writeInterfaceToken(IApplicationThread.descriptor);
		data.writeStrongBinder(receiver.asBinder());
		intent.writeToParcel(data, 0);
		data.writeInt(resultCode);
		data.writeString(dataStr);
		data.writeBundle(extras);
		data.writeInt(ordered ? 1 : 0);
		data.writeInt(sticky ? 1 : 0);
		mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null,
			IBinder.FLAG_ONEWAY);
		data.recycle();
	}

	......
}


        这里通过Binder驱动程序就进入到ApplicationThread.scheduleRegisteredReceiver函数去了。ApplicationThread是ActivityThread的一个内部类,具体可以参考Activity启动主题Android应用程序的Activity启动过程简要介绍和学习计划

        Step 12. ApplicaitonThread.scheduleRegisteredReceiver
        这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

public final class ActivityThread {
	......

	private final class ApplicationThread extends ApplicationThreadNative {
		......

		// This function exists to make sure all receiver dispatching is
		// correctly ordered, since these are one-way calls and the binder driver
		// applies transaction ordering per object for such calls.
		public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
				int resultCode, String dataStr, Bundle extras, boolean ordered,
				boolean sticky) throws RemoteException {
			receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky);
		}

		......
	}

	......

}


        这里的receiver是在前面一篇文章Android应用程序注册广播接收器(registerReceiver)的过程分析中的Step 4中创建的,它的具体类型是LoadedApk.ReceiverDispatcher.InnerReceiver,即定义在LoadedApk类的内部类ReceiverDispatcher里面的一个内部类InnerReceiver,这里调用它的performReceive函数。

        Step 13. InnerReceiver.performReceive

        这个函数定义在frameworks/base/core/java/android/app/LoadedApk.java文件中:

final class LoadedApk {  
	...... 

	static final class ReceiverDispatcher {  

		final static class InnerReceiver extends IIntentReceiver.Stub { 
			......

			public void performReceive(Intent intent, int resultCode,
					String data, Bundle extras, boolean ordered, boolean sticky) {
			
				LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
				......
				if (rd != null) {
					rd.performReceive(intent, resultCode, data, extras,
							ordered, sticky);
				} else {
					......
				}
			}
		}

		......
	}

	......
}


         这里,它只是简单地调用ReceiverDispatcher的performReceive函数来进一步处理,这里的ReceiverDispatcher类是LoadedApk类里面的一个内部类。

         Step 14. ReceiverDispatcher.performReceive

         这个函数定义在frameworks/base/core/java/android/app/LoadedApk.java文件中:

final class LoadedApk {  
	...... 

	static final class ReceiverDispatcher {  
		......

		public void performReceive(Intent intent, int resultCode,
				String data, Bundle extras, boolean ordered, boolean sticky) {
			......

			Args args = new Args();
			args.mCurIntent = intent;
			args.mCurCode = resultCode;
			args.mCurData = data;
			args.mCurMap = extras;
			args.mCurOrdered = ordered;
			args.mCurSticky = sticky;
			if (!mActivityThread.post(args)) {
				......
			} 
		}

		......
	}

	......
}


        这里mActivityThread成员变量的类型为Handler,它是前面MainActivity注册广播接收器时,从ActivityThread取得的,具体可以参考前面一篇文章Android应用程序注册广播接收器(registerReceiver)的过程分析中的Step 3。这里ReceiverDispatcher借助这个Handler,把这个广播以消息的形式放到MainActivity所在的这个ActivityThread的消息队列中去,因此,ReceiverDispatcher不等这个广播被MainActivity处理就返回了,这里也体现了广播的发送和处理是异步进行的。

        注意这里处理消息的方式是通过Handler.post函数进行的,post函数的参数是Runnable类型的,这个消息最终会调用这个这个参数的run成员函数来处理。这里的Args类是LoadedApk类的内部类ReceiverDispatcher的一个内部类,它继承于Runnable类,因此,可以作为mActivityThread.post的参数传进去,代表这个广播的intent也保存在这个Args实例中。

        Step 15. Hanlder.post

        这个函数定义在frameworks/base/core/java/android/os/Handler.java文件中,这个函数我们就不看了,有兴趣的读者可以自己研究一下,它的作用就是把消息放在消息队列中,然后就返回了,这个消息最终会在传进来的Runnable类型的参数的run成员函数中进行处理。

        Step 16. Args.run

        这个函数定义在frameworks/base/core/java/android/app/LoadedApk.java文件中:

final class LoadedApk {  
	...... 

	static final class ReceiverDispatcher {
		......

		final class Args implements Runnable {
			......

			public void run() {
				BroadcastReceiver receiver = mReceiver;

				......

				Intent intent = mCurIntent;
				
				......

				try {
					ClassLoader cl =  mReceiver.getClass().getClassLoader();
					intent.setExtrasClassLoader(cl);
					if (mCurMap != null) {
						mCurMap.setClassLoader(cl);
					}
					receiver.setOrderedHint(true);
					receiver.setResult(mCurCode, mCurData, mCurMap);
					receiver.clearAbortBroadcast();
					receiver.setOrderedHint(mCurOrdered);
					receiver.setInitialStickyHint(mCurSticky);
					receiver.onReceive(mContext, intent);
				} catch (Exception e) {
					......
				}

				......
			}

			......
		}

		......
	}

	......
}


        这里的mReceiver是ReceiverDispatcher类的成员变量,它的类型是BroadcastReceiver,这里它就是MainActivity注册广播接收器时创建的BroadcastReceiver实例了,具体可以参考前面一篇文章Android应用程序注册广播接收器(registerReceiver)的过程分析中的Step 2。

        有了这个ReceiverDispatcher实例之后,就可以调用它的onReceive函数把这个广播分发给它处理了。

        Step 17. BroadcastReceiver.onReceive

        这个函数定义Android系统中的广播(Broadcast)机制简要介绍和学习计划一文中所介绍的Android应用程序Broadcast的工程目录下的src/shy/luo/broadcast/MainActivity.java文件中:

public class MainActivity extends Activity implements OnClickListener {    
	......  

	private BroadcastReceiver counterActionReceiver = new BroadcastReceiver(){  
		public void onReceive(Context context, Intent intent) {  
			int counter = intent.getIntExtra(CounterService.COUNTER_VALUE, 0);  
			String text = String.valueOf(counter);  
			counterText.setText(text);  

			Log.i(LOG_TAG, "Receive counter event");  
		}    
	}

	......  

}


        这样,MainActivity里面的定义的BroadcastReceiver实例counterActionReceiver就收到这个广播并进行处理了。
        至此,Android应用程序发送广播的过程就分析完成了,结合前面这篇分析广播接收器注册过程的文章Android应用程序注册广播接收器(registerReceiver)的过程分析,就会对Android系统的广播机制且个更深刻的认识和理解了。

        最后,我们总结一下这个Android应用程序发送广播的过程:

        1. Step 1 - Step 7,计数器服务CounterService通过sendBroadcast把一个广播通过Binder进程间通信机制发送给ActivityManagerService,ActivityManagerService根据这个广播的Action类型找到相应的广播接收器,然后把这个广播放进自己的消息队列中去,就完成第一阶段对这个广播的异步分发了;

        2. Step 8 - Step 15,ActivityManagerService在消息循环中处理这个广播,并通过Binder进程间通信机制把这个广播分发给注册的广播接收分发器ReceiverDispatcher,ReceiverDispatcher把这个广播放进MainActivity所在的线程的消息队列中去,就完成第二阶段对这个广播的异步分发了;

        3. Step 16 - Step 17, ReceiverDispatcher的内部类Args在MainActivity所在的线程消息循环中处理这个广播,最终是将这个广播分发给所注册的BroadcastReceiver实例的onReceive函数进行处理。

        这样,Android系统广播机制就学习完成了,希望对读者有所帮助。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值