8.5.3耳麦拔插事件调用流程分析

在前面的小节中,我们编写了一个驱动程序,模拟耳机的插拔事件,其可以上报耳机的拔插事件,并且修改了android的源代码,可以根据耳机的拔插事件,在状态栏上现实或者消除耳麦的图标,这节视频我们讲解耳麦插拔事件导致的程序调用流程。

前面提到过,有两种上报插拔事件的方式,一种是使用输入子系统,另外一种是使用swith dev(实质是使用uevent,通过网络上报事件),那么我们的anroid系统最终是使用哪种方式呢?我们可以去配置android系统,可以去配置SDK/frameworks/base/core/res/res/values/config.xml
文件,或者:
SDK/device/rockchip/common/overlay/frameworks/base/core/res/res/values/config.xml
第二个文件会覆盖第一个文件,修改文件中的config_useDevInputEventForAudioJack变量,该值为true时使用input子系统, 为false时使用uevent机制。

下面是详细的调用流程:

input系统方法

我们先来讲解使用input子系统上报流程,后面再讲解uevent的调用流程:
1.input驱动上报
2.input系统上报给Audio系统。
3.Audio系统把事件发送给Activity(感兴趣的应用程序)
4.最终发送给某个APP(前面的小节为状态栏APP)

其上input系统是获取事件,然后上报事件,在输入子系统章节我们讲解过,有一个InputReader线程,存在成员EventHub,其会监测多个节点(使用poll机制),InputReader获得事件之后,发送给InputDispatcher线程,InputDispatcher程处理之后上报给InputManagerService,InputManagerService调用WiredAccessoryManager中CallBack(回调函数)函数,WiredAccessoryManager上报Andio系统了。

首先我们要确定CallBack函数,这样在输入子系统过得事件之后,才能进入音频子系统,根据时序图我们打开SystemServer.java文件:
 

private void startOtherServices() {
	// Listen for wired headset changes
    inputManager.setWiredAccessoryCallbacks(new WiredAccessoryManager(context, inputManager));
    	/*回调函数,当输入系统获得数据之后,调用callbacks函数*/
    	mWiredAccessoryCallbacks = callbacks;	

可以看到其中创建了一个WiredAccessoryManager对象,传递给inputManager.setWiredAccessoryCallbacks函数(设置回调函数)。

现在我们打开InputReader.cpp:

void InputReader::loopOnce() {
	/*获得事件,如果没有事件,则会进入休眠状态*/
	size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
	/*得到事件之后进行处理*/
	processEventsLocked(mEventBuffer, count);
		/*对于每一个输入设备都会创建一个InputDevice对象,还函数会调用InputDevice中的process方法*/
		processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
			/*调用InputDevice中的process*/
			device->process(rawEvents, count);
				/*InputDevice中存在InputMapper成员,调用该成员的process函数*/
				mapper->process(rawEvent);			

对于我们的开关事件,其对应的mapper->process(rawEvent)函数就是SwitchInputMapper::process函数:

/*对收到的事件分别进行处理*/
void SwitchInputMapper::process(const RawEvent* rawEvent) {
	/*记录驱动程序上报的code值(松开或者按下)*/
	processSwitch(rawEvent->code, rawEvent->value);
	/*当接受到同步信号之后,进行处理*/
	sync(rawEvent->when);
		/*获得监听器,调用监听器中的notifySwitch函数*/
		getListener()->notifySwitch(&args);

其中进行监听的为InputDispatcher线程,所以我们进入InputDispacher.cpp找到:

void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
	mPolicy->notifySwitch(args->eventTime,args->switchValues, args->switchMask, policyFlags);

其上mPolicy->notifySwitch实现与com_android_server_input_InputManagerService.cpp文件:

void NativeInputManager::notifySwitch()
	/*调用java中的同名函数notifySwitch*/
	env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifySwitch,when, switchValues, switchMask);

打开InputManagerService.java文件,找到其中的notifySwitch函数:

private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
	/*这个变量就是之前我们修改xml设置的变量*/
	if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
		mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,switchMask);

其上的notifyWiredAccessoryChanged实现与WiredAccessoryManager.java:

public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask)
	mSwitchValues = (mSwitchValues & ~switchMask) | switchValues;
		/*根据驱动程序上报的值确定headset变量*/
		......
		case SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT:
			headset = BIT_HEADSET;
		......
	/*更新状态*/
	updateLocked(NAME_H2W,(mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT)) | headset);

在updateLocked函数中,其将会进入audio系统,暂时我们不去分析该函数,我们先回过头UEvent方法。

UEvent方法
UEvent机制就是通过网络传输,把状态上报给应用程序,那么在android的UEnvet中必定有一个线程,这个线程称为UEventThread,其工作为1.等待Socket数据。2,收到数据之后发送数据/SendEvent(发送给感兴趣的进程:WiredAccessoryObserver)。下面是UEevent与Inpout系统对比的简单图示:

其中WiredAccessoryObserver属于文件WiredAccessoryManager.java,那么我们猜测WiredAccessoryManager.java文件中,其会去注册一个WiredAccessoryObserver,进入WiredAccessoryManager.java:
 

public WiredAccessoryManager(Context context, InputManagerService inputManager) {
	/*创建一个观察者*/
	mObserver = new WiredAccessoryObserver();

其中WiredAccessoryObserver的构造函数:

public WiredAccessoryObserver() {
	/*创建一个观察事件的列表,可以猜测到其回去关注多个文件*/
	mUEventInfo = makeObservedUEventList();
        // Monitor h2w
   	    if (!mUseDevInputEventForAudioJack) {
   	    	uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC, BIT_LINEOUT);
   	/*系统装备就绪之后,该函数会被调用*/
   	void init() {
   		/*开始观察*/
   		startObserving("DEVPATH="+uei.getDevPath());
   			final UEventThread t = getThread();
   			/*往UEventThread线程中添加观察者*/
        	t.addObserver(match, this);

所以UEventThread线程接受到数据之后,应该就上报给WiredAccessoryObserver,我们在UEventThreadObserver.java中可以找到方法:

private static final class UEventThread extends Thread {
	public void run() {
		/*调用C++中的函数,初始化网络*/
		nativeSetup();
		/*等待下一个事件,调用C++的同名函数,读取到数据时返回*/
		String message = nativeWaitForNextEvent();	
		/*发送数据*/
		sendEvent(message);
			/*获得observer*/
			final UEventObserver observer =(UEventObserver)mKeysAndObservers.get(i + 1);mTempObserversToSignal.add(observer);
			/*调用observer中的onUEvent方法,在这里我们的观察者是WiredAccessoryObserver*/
			observer.onUEvent(event);

其上的nativeSetup会调用C++文件中的android_os_UEventObserver.cpp文件中的:

/*网络初始化与绑定*/
static void nativeSetup(JNIEnv *env, jclass clazz) {
	uevent_init()
		s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
		bind(s, (struct sockaddr *) &addr, sizeof(addr))

nativeWaitForNextEvent也会调用C++的同名函数:

static jstring nativeWaitForNextEvent(JNIEnv *env, jclass clazz) {
	/*等待下一个事件*/
	length = uevent_next_event(buffer, sizeof(buffer) - 1)
		/*进入休眠。如果返回,代表接收到了数据*/
		nr = poll(&fds, 1, -1);
		/*读取数据*/
		int count = recv(fd, buffer, buffer_length, 0);

所以其最终会调用WiredAccessoryObserver中的onUEvent方法(WiredAccessoryManager.java中实现),

public void onUEvent(UEventObserver.UEvent event) {
	/*获取状态*/
	int state = Integer.parseInt(event.get("SWITCH_STATE"));
	/*更新状态*/
	updateStateLocked(devPath, name, state);

从这里我们可以知道,input系统方法与UEvent方法其最终都会调用到updateStateLocked函数去更新状态,

updateStateLocked

现在我们来查看一下updateStateLocked方法:

private void updateStateLocked(String devPath, String name, int state) {
	updateLocked(name, uei.computeNewHeadsetState(mHeadsetState, state));
		/*构造一个Message,其中含有headsetState*/
		Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState,mHeadsetState, "");
		/*发送消息*/
		mHandler.sendMessage(msg);

发送消息之后,会导致消息的处理函数被调用,在该文件搜索MSG_NEW_DEVICE_STATE:

private final Handler mHandler = new Handler(Looper.myLooper(), null, true)
	case MSG_NEW_DEVICE_STATE:
		setDevicesState(msg.arg1, msg.arg2, (String)msg.obj);
			setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName);
			/*一系列的设置*/
			.......
			/*最终设置有线设备的连接状态*/
			mAudioManager.setWiredDeviceConnectionState();

最看到mAudioManager我们知道,其进入Audio系统了,我们打开AudioManager文件:

public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
	/**/
	IAudioService service = getService();
	/*执行AudioService.java中的同名函数*/
	service.setWiredDeviceConnectionState(type, state, address, name,mApplicationContext.getOpPackageName());
	/**/
		int delay = checkSendBecomingNoisyIntent(type, state);
		/*构造一个消息,放入队列*/
		queueMsgUnderWakeLock(mAudioHandler,
                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
                    0,
                    0,
                    new WiredDeviceConnectionState(type, state, address, name, caller),
                    delay);

我们搜索MSG_SET_WIRED_DEVICE_CONNECTION_STATE,找到处理消息的方法:

public void handleMessage(Message msg) {
	case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
		onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
connectState.mAddress, connectState.mName, connectState.mCaller);
			sendDeviceConnectionIntent(device, state, address, deviceName);
				/*创建一个intent */
				Intent intent = new Intent();
				/*把状态放入intent*/
				intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
		        intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
		        intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
				......
				一系列的判断,如有没有mic等等
				......
				/*发送给应用程序的管理者,进行广播*/
				ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);

在前面的小节我们修改了状态栏的程序,添加的代码如下:

/*对耳机插拔感兴趣,当接受到ActivityManagerNative的广播的时候*/
filter.addAction(Intent.ACTION_HEADSET_PLUG);

/*取出广播,如果为ACTION_HEADSET_PLUG,执行updateHeadset函数*/
} else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
	updateHeadset(intent);

private final void updateHeadset(Intent intent) {
    final String action = intent.getAction();
    final int state = intent.getIntExtra("state", 4);
    final int mic = intent.getIntExtra("microphone", 4);
	/*从intent取出状态值,判断是拔出还是插入*/
    switch (state) {
        case 0:
        	/*消除图标*/
            mIconController.setIconVisibility("headset", false);
    break;
        case 1:
            if (mic == 1) {
                mIconController.setIcon("headset", R.drawable.stat_sys_headset_with_mic, null);
            } else {
                mIconController.setIcon("headset", R.drawable.stat_sys_headset_without_mic, null);
            }
            /*显示图标*/
            mIconController.setIconVisibility("headset", true);
            break;
    }
}

这样我们就讲解完成了,再次贴出模块的框图:

发布了241 篇原创文章 · 获赞 28 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_34738528/article/details/105044307