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 }