android 4.4的耳机插入检测流程

来源:互联网 发布:淘宝客如何设置优惠券 编辑:程序博客网 时间:2024/04/30 15:58

base/services/java/com/android/server/SystemServer.java

System Server是Android系统的核心,他在Dalvik虚拟机启动后立即开始初始化和运行。其它的系统服务在System Server进程的环境中运行。

 

在main函数中,首先检查系统时间设置和SamplingProfiler。然后加载一个叫android_servers的本地库,他提供本地方法的接口(源程序在framework/base/services/jni/目录中)。然后调用本地方法设置服务。然后执行一个死循环线程,该线程中启动了很多服务。

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1.    public static void main(String[] args) {  
  2. ............................................  
  3. .............................................  
  4.         Environment.setUserRequired(true);  
  5.   
  6.         System.loadLibrary("android_servers");  
  7.   
  8.         Slog.i(TAG, "Entered the Android system server!");  
  9.   
  10.         // Initialize native services.  
  11.         nativeInit();  
  12.   
  13.         // This used to be its own separate thread, but now it is  
  14.         // just the loop we run on the main thread.  
  15.         ServerThread thr = new ServerThread();  
  16.         thr.initAndLoop();  
  17.     }      
  18. }  

在ServerThread中启动了监听有线耳机接入的服务。

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. if (!disableMedia) {  
  2.     try {  
  3.         Slog.i(TAG, "Wired Accessory Manager");  
  4.         // Listen for wired headset changes  
  5.         inputManager.setWiredAccessoryCallbacks(  
  6.                 new WiredAccessoryManager(context, inputManager));  
  7.     } catch (Throwable e) {  
  8.         reportWtf("starting WiredAccessoryManager", e);  
  9.     }  
  10. }  

在base/services/java/com/android/server/WiredAccessoryManager.java  中

WiredAccessoryManager中使用了两种方式监听耳机的状态

在起构造函数中获得mUseDevInputEventForAudioJack的状态,配置为false。

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public WiredAccessoryManager(Context context, InputManagerService inputManager) {  
  2.      PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);  
  3.      mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryManager");  
  4.      mWakeLock.setReferenceCounted(false);  
  5.      mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);  
  6.      mInputManager = inputManager;  
  7.      mContext= context;    
  8.      mUseDevInputEventForAudioJack =  
  9.              context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);  
  10.   
  11.      mObserver = new WiredAccessoryObserver();  
  12.   
  13.      context.registerReceiver(new BroadcastReceiver() {  
  14.                  @Override  
  15.                  public void onReceive(Context ctx, Intent intent) {  
  16.                      bootCompleted();  
  17.                  }     
  18.              },    
  19.              new IntentFilter(Intent.ACTION_BOOT_COMPLETED), nullnull);  
  20.  }     

在启动完成后就开启监听,注册了开机广播,开机后,会开始所有相关的UEvent,并且开始监听。在private void bootCompleted()中
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1.     private void bootCompleted() {  
  2.         if (mUseDevInputEventForAudioJack) {  
  3.            //inputEvent方式  
  4.             int switchValues = 0;  
  5.             if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) {  
  6.                 switchValues |= SW_HEADPHONE_INSERT_BIT;  
  7.             }  
  8.             if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) {  
  9.                 switchValues |= SW_MICROPHONE_INSERT_BIT;  
  10.             }  
  11.             notifyWiredAccessoryChanged(0, switchValues,  
  12.                     SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT);  
  13.         }  
  14.   
  15.         mObserver.init();  
  16.         PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);  
  17.         mHdmiWakeLock=pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE  
  18. "HdmiWakeLock");  
  19.         mHdmiWakeLock.setReferenceCounted(false);         
  20.     }      
在WiredAccessoryManager中实例化了一个WiredAccessoryObserver,其就是通过UEvent方式来检测耳机的插入拔出状态,

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. mObserver = new WiredAccessoryObserver();  
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. class WiredAccessoryObserver extends UEventObserver {  
  2.       private final List<UEventInfo> mUEventInfo;  
  3.   
  4.       public WiredAccessoryObserver() {  
  5.           mUEventInfo = makeObservedUEventList();  
  6.       }  

在WiredAccessoryObserver中,

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. private List<UEventInfo> makeObservedUEventList() {  
  2.     List<UEventInfo> retVal = new ArrayList<UEventInfo>();  
  3.     UEventInfo uei;  
  4.   
  5.     // Monitor h2w  
  6.     if (!mUseDevInputEventForAudioJack) {  
  7.         uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC);  
  8.         if (uei.checkSwitchExists()) {  
  9.             retVal.add(uei);  
  10.         } else {  
  11.             Slog.w(TAG, "This kernel does not have wired headset support");  
  12.         }  
  13.     }  
  14.   
  15.     // Monitor USB  
  16.     uei = new UEventInfo(NAME_USB_AUDIO, BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL);  
  17.     if (uei.checkSwitchExists()) {  
  18.         retVal.add(uei);  
  19.     } else {  
  20.         Slog.w(TAG, "This kernel does not have usb audio support");  
  21.     }  
  22.     // Monitor HDMI  
  23.     //  
  24.     // If the kernel has support for the "hdmi_audio" switch, use that.  It will be  
  25.     // signalled only when the HDMI driver has a video mode configured, and the downstream  
  26.     // sink indicates support for audio in its EDID.  
  27.     //  
  28.     // If the kernel does not have an "hdmi_audio" switch, just fall back on the older  
  29.     // "hdmi" switch instead.  
  30.     uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0);  
  31.     if (uei.checkSwitchExists()) {  
  32.         retVal.add(uei);  
  33.     } else {  
  34.         uei = new UEventInfo(NAME_HDMI, BIT_HDMI_AUDIO, 0);  
  35.         if (uei.checkSwitchExists()) {  
  36.             retVal.add(uei);  
  37.         } else {  
  38.             Slog.w(TAG, "This kernel does not have HDMI audio support");  
  39.         }  
  40.     }  
  41.   
  42.     return retVal;  
  43. }  

在WiredAccessoryObserver 的init中

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void init() {  
  2.     synchronized (mLock) {  
  3.         if (LOG) Slog.v(TAG, "init()");  
  4.         char[] buffer = new char[1024];  
  5.   
  6.         for (int i = 0; i < mUEventInfo.size(); ++i) {  
  7.             UEventInfo uei = mUEventInfo.get(i);  
  8.             try {  
  9.                 int curState;  
  10.                 FileReader file = new FileReader(uei.getSwitchStatePath());  
  11.                 int len = file.read(buffer, 01024);  
  12.                 file.close();  
  13.                 curState = Integer.valueOf((new String(buffer, 0, len)).trim());  
  14.   
  15.                 if (curState > 0) {  
  16.                     updateStateLocked(uei.getDevPath(), uei.getDevName(), curState);  
  17.                 }  
  18.             } catch (FileNotFoundException e) {  
  19.                 Slog.w(TAG, uei.getSwitchStatePath() +  
  20.                         " not found while attempting to determine initial switch state");  
  21.             } catch (Exception e) {  
  22.                 Slog.e(TAG, "" , e);  
  23.             }  
  24.         }  
  25.     }  
  26.     // At any given time accessories could be inserted  
  27.     // one on the board, one on the dock and one on HDMI:  
  28.     // observe three UEVENTs  
  29.     for (int i = 0; i < mUEventInfo.size(); ++i) {  
  30.         UEventInfo uei = mUEventInfo.get(i);  
  31.         startObserving("DEVPATH="+uei.getDevPath());  
  32.     }  
  33. }  

通过startObserving("DEVPATH="+uei.getDevPath()); 来进行监听

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. startObserving("DEVPATH="+uei.getDevPath());  

监听的节点是

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. shell@hammerhead:/ $ ls sys/class/switch/ -l                                     
  2. lrwxrwxrwx root     root              2014-05-06 09:44 h2w -> ../../devices/virtual/switch/h2w  
  3. lrwxrwxrwx root     root              2014-05-06 09:44 hdmi -> ../../devices/virtual/switch/hdmi  
  4. lrwxrwxrwx root     root              2014-05-06 09:44 hdmi_audio -> ../../devices/virtual/switch/hdmi_audio  
  5. lrwxrwxrwx root     root              2014-05-06 09:44 usb_audio -> ../../devices/virtual/switch/usb_audio  
  6. lrwxrwxrwx root     root              2014-05-06 09:44 wfd -> ../../devices/virtual/switch/wfd  

在onUEvent时间到来的时候更新state

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. public void onUEvent(UEventObserver.UEvent event) {  
  2.     if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());  
  3.   
  4.     try {  
  5.         String devPath = event.get("DEVPATH");  
  6.         String name = event.get("SWITCH_NAME");  
  7.         int state = Integer.parseInt(event.get("SWITCH_STATE"));  
  8.         synchronized (mLock) {  
  9.             updateStateLocked(devPath, name, state);  
  10.         }  
  11.     } catch (NumberFormatException e) {  
  12.         Slog.e(TAG, "Could not parse switch state from event " + event);  
  13.     }  
  14. }  

updateStateLocked(devPath, name, state) ->   updateLocked(String newName, int newState)  ->     setDevicesState(
            int headsetState, int prevHeadsetState, String headsetName)  -> setDeviceStateLocked() ->mAudioManager.setWiredDeviceConnectionState(device, state, headsetName);

在setDeviceStateLocked中会更新device的状态,并最终调用mAudioManager.setWiredDeviceConnectionState


[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. private void setDeviceStateLocked(int headset,  
  2.         int headsetState, int prevHeadsetState, String headsetName) {  
  3.     if ((headsetState & headset) != (prevHeadsetState & headset)) {  
  4.         int device;  
  5.         int state;  
  6.   
  7.         if ((headsetState & headset) != 0) {  
  8.             state = 1;  
  9.         } else {  
  10.             state = 0;  
  11.         }     
  12.   
  13.         if (headset == BIT_HEADSET) {  
  14.             device = AudioManager.DEVICE_OUT_WIRED_HEADSET;  
  15.         } else if (headset == BIT_HEADSET_NO_MIC){  
  16.             device = AudioManager.DEVICE_OUT_WIRED_HEADPHONE;  
  17.         } else if (headset == BIT_USB_HEADSET_ANLG) {  
  18.             device = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET;  
  19.         } else if (headset == BIT_USB_HEADSET_DGTL) {  
  20.             device = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET;  
  21.         } else if (headset == BIT_HDMI_AUDIO) {  
  22.             device = AudioManager.DEVICE_OUT_AUX_DIGITAL;  
  23.         } else {  
  24.             Slog.e(TAG, "setDeviceState() invalid headset type: "+headset);  
  25.             return;  
  26.         }   
  27.         if (LOG)  
  28.             Slog.v(TAG, "device "+headsetName+((state == 1) ? " connected" : " disconnected"));  
  29.         if(headsetName.equals("hdmi")&&state==1){  
  30.                        Intent intent=new Intent("android.intent.action.HDMI_PLUG");  
  31.                        intent.putExtra("state"1);  
  32.                        intent.putExtra("name""hdmi");  
  33.                        mContext.sendBroadcast(intent);  
  34.                        mHdmiWakeLock.acquire();  
  35.                        Log.d(TAG,"--- hdmi connect ");  
  36.                     }else if(headsetName.equals("hdmi")&&state==0){  
  37.                                Log.d(TAG,"--- hdmi disconnect ");  
  38.                                Intent intent=new Intent("android.intent.action.HDMI_PLUG");  
  39.                                intent.putExtra("state"0);  
  40.                                intent.putExtra("name""hdmi");  
  41.                                mContext.sendBroadcast(intent);  
  42.                                mHdmiWakeLock.release();  
  43.                             }  
  44.         mAudioManager.setWiredDeviceConnectionState(device, state, headsetName);  
  45.     }  
  46. }  

AudioManager的setWiredDeviceConnectionState实际是调用AudioService的setWiredDeviceConnectionState方法。


[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. 2796     public void setWiredDeviceConnectionState(int device, int state, String name) {  
  2. 2797         synchronized (mConnectedDevices) {  
  3. 2798             int delay = checkSendBecomingNoisyIntent(device, state);  
  4. 2799             queueMsgUnderWakeLock(mAudioHandler,  
  5. 2800                     MSG_SET_WIRED_DEVICE_CONNECTION_STATE,  
  6. 2801                     device,  
  7. 2802                     state,  
  8. 2803                     name,  
  9. 2804                     delay);  
  10. 2805         }  
  11. 2806     }  

最终会发送到上层一个广播:

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1.  private void sendDeviceConnectionIntent(int device, int state, String name)  
  2. 3924     {  
  3. 3925         Intent intent = new Intent();  
  4. 3926   
  5. 3927         intent.putExtra("state", state);  
  6. 3928         intent.putExtra("name", name);  
  7. 3929         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);  
  8. 3930   
  9. 3931         int connType = 0;  
  10. 3932   
  11. 3933         if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {  
  12. 3934             connType = AudioRoutesInfo.MAIN_HEADSET;  
  13. 3935             intent.setAction(Intent.ACTION_HEADSET_PLUG);  
  14. 3936             intent.putExtra("microphone"1);  
  15. 3937         } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {  
  16. 3938             connType = AudioRoutesInfo.MAIN_HEADPHONES;  
  17. 3939             intent.setAction(Intent.ACTION_HEADSET_PLUG);  
  18. 3940             intent.putExtra("microphone"0);  
  19. 3941         } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {  
  20. 3942             connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;  
  21. 3943             intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);  
  22. 3944         } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {  
  23. 3945             connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;  
  24. 3946             intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);  
  25. 3947         } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) {  
  26. 3948             connType = AudioRoutesInfo.MAIN_HDMI;  
  27. 3949             intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);  
  28. 3950         }  
  29. 3951   
  30. 3952         synchronized (mCurAudioRoutes) {  
  31. 3953             if (connType != 0) {  
  32. 3954                 int newConn = mCurAudioRoutes.mMainType;  
  33. 3955                 if (state != 0) {  
  34. 3956                     newConn |= connType;  
  35. 3957                 } else {  
  36. 3958                     newConn &= ~connType;  
  37. 3959                 }  
  38. 3960                 if (newConn != mCurAudioRoutes.mMainType) {  
  39. 3961                     mCurAudioRoutes.mMainType = newConn;  
  40. 3962                     sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,  
  41. 3963                             SENDMSG_NOOP, 00null0);  
  42. 3964                 }  
  43. 3965             }  
  44. 3966         }  
  45. 3967   
  46. 3968         final long ident = Binder.clearCallingIdentity();  
  47. 3969         try {  
  48. 3970             ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);  
  49. 3971         } finally {  
  50. 3972             Binder.restoreCallingIdentity(ident);  
  51. 3973         }  
  52. 3974     }  
0 0
原创粉丝点击