您的位置:首页 > 移动开发 > Android开发

android 4.4的耳机插入检测流程

2014-05-06 10:46 267 查看
base/services/java/com/android/server/SystemServer.java

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



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

public static void main(String[] args) {
............................................
.............................................
        Environment.setUserRequired(true);

        System.loadLibrary("android_servers");

        Slog.i(TAG, "Entered the Android system server!");

        // Initialize native services.
        nativeInit();

        // This used to be its own separate thread, but now it is
        // just the loop we run on the main thread.
        ServerThread thr = new ServerThread();
        thr.initAndLoop();
    }    
}


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

if (!disableMedia) {
                try {
                    Slog.i(TAG, "Wired Accessory Manager");
                    // Listen for wired headset changes
                    inputManager.setWiredAccessoryCallbacks(
                            new WiredAccessoryManager(context, inputManager));
                } catch (Throwable e) {
                    reportWtf("starting WiredAccessoryManager", e);
                }
            }


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

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

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

public WiredAccessoryManager(Context context, InputManagerService inputManager) {
        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryManager");
        mWakeLock.setReferenceCounted(false);
        mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
        mInputManager = inputManager;
        mContext= context;  
        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);

        mObserver = new WiredAccessoryObserver();

        context.registerReceiver(new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context ctx, Intent intent) {
                        bootCompleted();
                    }   
                },  
                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
    }


在启动完成后就开启监听,注册了开机广播,开机后,会开始所有相关的UEvent,并且开始监听。在private void bootCompleted()中
private void bootCompleted() {
        if (mUseDevInputEventForAudioJack) {
           //inputEvent方式
            int switchValues = 0;
            if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) {
                switchValues |= SW_HEADPHONE_INSERT_BIT;
            }
            if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) {
                switchValues |= SW_MICROPHONE_INSERT_BIT;
            }
            notifyWiredAccessoryChanged(0, switchValues,
                    SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT);
        }

        mObserver.init();
        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
        mHdmiWakeLock=pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE
, "HdmiWakeLock");
        mHdmiWakeLock.setReferenceCounted(false);       
    }
在WiredAccessoryManager中实例化了一个WiredAccessoryObserver,其就是通过UEvent方式来检测耳机的插入拔出状态,

mObserver = new WiredAccessoryObserver();
class WiredAccessoryObserver extends UEventObserver {
        private final List<UEventInfo> mUEventInfo;

        public WiredAccessoryObserver() {
            mUEventInfo = makeObservedUEventList();
        }


在WiredAccessoryObserver中,

private List<UEventInfo> makeObservedUEventList() {
            List<UEventInfo> retVal = new ArrayList<UEventInfo>();
            UEventInfo uei;

            // Monitor h2w
            if (!mUseDevInputEventForAudioJack) {
                uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC);
                if (uei.checkSwitchExists()) {
                    retVal.add(uei);
                } else {
                    Slog.w(TAG, "This kernel does not have wired headset support");
                }
            }

            // Monitor USB
            uei = new UEventInfo(NAME_USB_AUDIO, BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL);
            if (uei.checkSwitchExists()) {
                retVal.add(uei);
            } else {
                Slog.w(TAG, "This kernel does not have usb audio support");
            }
            // Monitor HDMI
            //
            // If the kernel has support for the "hdmi_audio" switch, use that.  It will be
            // signalled only when the HDMI driver has a video mode configured, and the downstream
            // sink indicates support for audio in its EDID.
            //
            // If the kernel does not have an "hdmi_audio" switch, just fall back on the older
            // "hdmi" switch instead.
            uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0);
            if (uei.checkSwitchExists()) {
                retVal.add(uei);
            } else {
                uei = new UEventInfo(NAME_HDMI, BIT_HDMI_AUDIO, 0);
                if (uei.checkSwitchExists()) {
                    retVal.add(uei);
                } else {
                    Slog.w(TAG, "This kernel does not have HDMI audio support");
                }
            }

            return retVal;
        }


在WiredAccessoryObserver 的init中

void init() {
            synchronized (mLock) {
                if (LOG) Slog.v(TAG, "init()");
                char[] buffer = new char[1024];

                for (int i = 0; i < mUEventInfo.size(); ++i) {
                    UEventInfo uei = mUEventInfo.get(i);
                    try {
                        int curState;
                        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) {
                            updateStateLocked(uei.getDevPath(), uei.getDevName(), curState);
                        }
                    } catch (FileNotFoundException e) {
                        Slog.w(TAG, uei.getSwitchStatePath() +
                                " not found while attempting to determine initial switch state");
                    } catch (Exception e) {
                        Slog.e(TAG, "" , e);
                    }
                }
            }
            // At any given time accessories could be inserted
            // one on the board, one on the dock and one on HDMI:
            // observe three UEVENTs
            for (int i = 0; i < mUEventInfo.size(); ++i) {
                UEventInfo uei = mUEventInfo.get(i);
                startObserving("DEVPATH="+uei.getDevPath());
            }
        }


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

startObserving("DEVPATH="+uei.getDevPath());


监听的节点是

shell@hammerhead:/ $ ls sys/class/switch/ -l                                   
lrwxrwxrwx root     root              2014-05-06 09:44 h2w -> ../../devices/virtual/switch/h2w
lrwxrwxrwx root     root              2014-05-06 09:44 hdmi -> ../../devices/virtual/switch/hdmi
lrwxrwxrwx root     root              2014-05-06 09:44 hdmi_audio -> ../../devices/virtual/switch/hdmi_audio
lrwxrwxrwx root     root              2014-05-06 09:44 usb_audio -> ../../devices/virtual/switch/usb_audio
lrwxrwxrwx root     root              2014-05-06 09:44 wfd -> ../../devices/virtual/switch/wfd


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

public void onUEvent(UEventObserver.UEvent event) {
            if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());

            try {
                String devPath = event.get("DEVPATH");
                String name = event.get("SWITCH_NAME");
                int state = Integer.parseInt(event.get("SWITCH_STATE"));
                synchronized (mLock) {
                    updateStateLocked(devPath, name, state);
                }
            } catch (NumberFormatException e) {
                Slog.e(TAG, "Could not parse switch state from event " + event);
            }
        }


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

private void setDeviceStateLocked(int headset,
            int headsetState, int prevHeadsetState, String headsetName) {
        if ((headsetState & headset) != (prevHeadsetState & headset)) {
            int device;
            int state;

            if ((headsetState & headset) != 0) {
                state = 1;
            } else {
                state = 0;
            }   

            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;
            } 
            if (LOG)
                Slog.v(TAG, "device "+headsetName+((state == 1) ? " connected" : " disconnected"));
            if(headsetName.equals("hdmi")&&state==1){
                           Intent intent=new Intent("android.intent.action.HDMI_PLUG");
                           intent.putExtra("state", 1);
                           intent.putExtra("name", "hdmi");
                           mContext.sendBroadcast(intent);
                           mHdmiWakeLock.acquire();
                           Log.d(TAG,"--- hdmi connect ");
                        }else if(headsetName.equals("hdmi")&&state==0){
                                   Log.d(TAG,"--- hdmi disconnect ");
                                   Intent intent=new Intent("android.intent.action.HDMI_PLUG");
                                   intent.putExtra("state", 0);
                                   intent.putExtra("name", "hdmi");
                                   mContext.sendBroadcast(intent);
                                   mHdmiWakeLock.release();
                                }
            mAudioManager.setWiredDeviceConnectionState(device, state, headsetName);
        }
    }


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

2796     public void setWiredDeviceConnectionState(int device, int state, String name) {
2797         synchronized (mConnectedDevices) {
2798             int delay = checkSendBecomingNoisyIntent(device, state);
2799             queueMsgUnderWakeLock(mAudioHandler,
2800                     MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
2801                     device,
2802                     state,
2803                     name,
2804                     delay);
2805         }
2806     }


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

private void sendDeviceConnectionIntent(int device, int state, String name)
3924     {
3925         Intent intent = new Intent();
3926 
3927         intent.putExtra("state", state);
3928         intent.putExtra("name", name);
3929         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
3930 
3931         int connType = 0;
3932 
3933         if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
3934             connType = AudioRoutesInfo.MAIN_HEADSET;
3935             intent.setAction(Intent.ACTION_HEADSET_PLUG);
3936             intent.putExtra("microphone", 1);
3937         } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
3938             connType = AudioRoutesInfo.MAIN_HEADPHONES;
3939             intent.setAction(Intent.ACTION_HEADSET_PLUG);
3940             intent.putExtra("microphone", 0);
3941         } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
3942             connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3943             intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
3944         } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
3945             connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3946             intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
3947         } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) {
3948             connType = AudioRoutesInfo.MAIN_HDMI;
3949             intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
3950         }
3951 
3952         synchronized (mCurAudioRoutes) {
3953             if (connType != 0) {
3954                 int newConn = mCurAudioRoutes.mMainType;
3955                 if (state != 0) {
3956                     newConn |= connType;
3957                 } else {
3958                     newConn &= ~connType;
3959                 }
3960                 if (newConn != mCurAudioRoutes.mMainType) {
3961                     mCurAudioRoutes.mMainType = newConn;
3962                     sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3963                             SENDMSG_NOOP, 0, 0, null, 0);
3964                 }
3965             }
3966         }
3967 
3968         final long ident = Binder.clearCallingIdentity();
3969         try {
3970             ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
3971         } finally {
3972             Binder.restoreCallingIdentity(ident);
3973         }
3974     }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: