private static final int BIT_HEADSET = (1 << 0); private static final int BIT_HEADSET_NO_MIC = (1 << 1); private static final int BIT_USB_HEADSET_ANLG = (1 << 2); private static final int BIT_USB_HEADSET_DGTL = (1 << 3); private static final int BIT_HDMI_AUDIO = (1 << 4); private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC| BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL| BIT_HDMI_AUDIO); private static final int HEADSETS_WITH_MIC = BIT_HEADSET;
[SystemServer.java-->ServerThread.run()] try { new WiredAccessoryObserver(context); } catch (Throwable e) { reportWtf("starting WiredAccessoryObserver", e); }
[WiredAccessoryObserver.java-->BootCompletedReceiver.onReceive()] public void onReceive(Context context, Intent intent) { // 初始化 init(); // 开始对所有感兴趣的UEvent进行监听 for (int i = 0; i < uEventInfo.size(); ++i) { UEventInfo uei = uEventInfo.get(i); startObserving("DEVPATH="+uei.getDevPath()); } } 这里的init()函数的作用是为了在开机后对外设的状态进行初始化。 [WiredAccessoryObserver.java-->WiredAccessoryObserver.init()] private synchronized final void init() { char[] buffer = new char[1024]; mPrevHeadsetState = mHeadsetState; for (int i = 0; i < uEventInfo.size(); ++i) { UEventInfo uei = uEventInfo.get(i); try { int curState; /* 打开状态文件并从中读取状态信息。状态文件中保存着一个整数,非0则表示设备已插入。 通过UEventInfo的定义可以知道,有线耳机的状态文件路径为 /sys/class/switch/h2w/state */ FileReader file = new FileReader(uei.getSwitchStatePath()); int len = file.read(buffer, 0, 1024); file.close(); curState = Integer.valueOf((new String(buffer, 0, len)).trim()); // 如果设备已插入,则更新设备的状态,否则不作处理 if (curState > 0) { updateState(uei.getDevPath(), uei.getDevName(), curState); } } catch (Exception e) { ...... } } }
[WiredAccessoryObserver.java-->WiredAccessoryObserver.onUEvent()] public void onUEvent(UEventObserver.UEvent event) { try { // UEvent事件的路径 String devPath = event.get("DEVPATH"); // 这个name其实就是UEventInfo中的mDevName,通过这个变量确定发生状态变化的设备名字 String name = event.get("SWITCH_NAME"); // 这个state与保存在状态文件中的数值的意义是一致的 // 事实上,当这条UEvent上报时,状态文件中的值也被更新成这个值 int state = Integer.parseInt(event.get("SWITCH_STATE")); // 像初始化的init()函数一样,调用updateState()进行状态更新 updateState(devPath, name, state); } catch (NumberFormatException e) { ...... } } [WiredAccessoryObserver.java-->WiredAccessoryObserver.updateState()] private synchronized final void updateState(String devPath, String name, int state) { for (int i = 0; i < uEventInfo.size(); ++i) { UEventInfo uei = uEventInfo.get(i); if (devPath.equals(uei.getDevPath())) { // 找到状态发生变化的外设所对应的UEventInfo并更新状态 update(name, uei.computeNewHeadsetState(mHeadsetState, state)); return; } } }
[WiredAccessoryObserver.java-->WiredAccessoryObserver.update()] private synchronized final void update(String newName, int newState) { /* 从headsetState中去掉不支持的外设,所以,如果不希望手机支持某种外设,比 如说USB_HEADSET,不需要从kernel改起,只要将其从SUPPORTED_HEADSETS中去 掉即可 */ int headsetState = newState & SUPPORTED_HEADSETS; int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC); boolean h2wStateChange = true; // 下面这行代码比较有意思,首先我们的目的是判断有线耳机的状态是否发生了变化 // mHeadsetState == headsetState这种条件很好理解,可是后面那个条件呢 if (mHeadsetState == headsetState || ((h2w_headset & (h2w_headset - 1)) != 0)) { h2wStateChange = false; } // 如果是不正确的状态转换则直接忽略 if (!h2wStateChange) { return; } // 更新可用外设列表 mHeadsetName = newName; mPrevHeadsetState = mHeadsetState; mHeadsetState = headsetState; // 为什么要申请一个电源锁呢 mWakeLock.acquire(); // 状态已经更新完毕,发送消息给mHandler,我们可以想象出接下来要做什么了,通知AudioSevicervice // 注意mHandler的定义,可以看出它运行在创建WiredAccessoryObserver的ServerThread中 mHandler.sendMessage(mHandler.obtainMessage(0, mHeadsetState, mPrevHeadsetState, mHeadsetName)); }
[WiredAccessoryObserver.java-->WiredAccessoryObserver.setDeviceState()] private final void setDeviceState(int headset, int headsetState, int prevHeadsetState, String headsetName) { if ((headsetState & headset) != (prevHeadsetState & headset)) { // 只有当这个外设的接入状态发生变化时才会继续 int device; int state; // 1表示可用,0表示不可用 if ((headsetState & headset) != 0) { state = 1; } else { state = 0; } // 翻译可用外设列表中的外设为Audio系统的设备号 if (headset == BIT_HEADSET) { device = AudioManager.DEVICE_OUT_WIRED_HEADSET; } else if (headset == BIT_HEADSET_NO_MIC){ device = AudioManager.DEVICE_OUT_WIRED_HEADPHONE; } else if (headset == BIT_USB_HEADSET_ANLG) { device = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET; } else if (headset == BIT_USB_HEADSET_DGTL) { device = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET; } else if (headset == BIT_HDMI_AUDIO) { device = AudioManager.DEVICE_OUT_AUX_DIGITAL; } else { Slog.e(TAG, "setDeviceState() invalid headset type: "+headset); return; } // 通知AudioService mAudioManager.setWiredDeviceConnectionState(device, state, headsetName); } }