Android4.0耳机插入广播发送流程分析
1. 相关文件
a. frameworks/base/services/java/com/android/server/SystemServer.java
启动线程时新建WiredAccessoryObserver对象
b. framework/base/services/java/com/android/server/WiredAccessoryObserver.java
类WiredAccessoryObserver继承UeventObserver,处理耳机状态等
c. framework/base/core/java/android/os/UEventObserver.java
UEventObserver是Android Java层利用uevent获取Kernel层状态变化的机制
UEventObserver接收kernel的uevent信息的抽象类。
类UEventObserver提供了三个方法给子类来调用:
1、 onUEvent(UEvent event)
子类必须重写这个onUEvent来处理uevent。
2、startObserving(String match)
启动进程,要提供一个字符串参数。
3、stopObserving()
停止进程。
2. 流程分析
启动在 systemserver.java 中
public class SystemServer {
public static void main(String[] args) {
......
init1(args);
......
}
public static final void init2() {
Log.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}
}
init1 将会调用到 android_server_SystemServer_init1.cpp
extern "C" int system_init();
static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
{
system_init();
}
由上可以得到,将调用到 System_init.cpp
extern "C" status_t system_init()
{
......
runtime->callStatic("com/android/server/SystemServer", "init2");
......
}
由上可以看出,此时将调回到 SystemServer的init2启动ServerThread线程
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
下面来看下ServerThread中做了哪些操作
class ServerThread extends Thread {
......
public void run() {
.....
try {
Slog.i(TAG, "Wired Accessory Observer");
// Listen for wired headset changes
new WiredAccessoryObserver(context);
} catch (Throwable e) {
reportWtf("starting WiredAccessoryObserver", e);
}
}
}
这里我们看到在线程启动后run方法中新建了WiredAccessoryObserver。
class WiredAccessoryObserver extends UeventObserver {
private static final int MAX_AUDIO_PORTS = 3; /* h2w, USB Audio & hdmi */
private static final String uEventInfo[][] = {
{ "DEVPATH=/devices/virtual/switch/h2w","/sys/class/switch/h2w/state",
"/sys/class/switch/h2w/name"},
{ "DEVPATH=/devices/virtual/switch/usb_audio",
"/sys/class/switch/usb_audio/state",
"/sys/class/switch/usb_audio/name"},
{ "DEVPATH=/devices/virtual/switch/hdmi","/sys/class/switch/hdmi/state",
"/sys/class/switch/hdmi/name"}
};
public WiredAccessoryObserver(Context context) {
mContext = context;
………
context.registerReceiver(new BootCompletedReceiver(),
new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
}
private final class BootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
init(); // set initial status
for (int i = 0; i < MAX_AUDIO_PORTS; i++) {
startObserving(uEventInfo[i][0]);
}
}
}
在 WiredAccessoryObserver 的构造函数中注册开机完成广播,在BootCompletedReceiver接收器中循环检测数组uEventInfo,其中uEventInfo[0][0](即为DEVPATH=/devices/virtual/switch/h2w 为耳机设备路径),我们来看下函数 startObserving
该函数在其 WiredAccessoryObserver的父类UEventObserver中
public abstract class UEventObserver {
private static UEventThread sThread;
private static class UEventThread extends Thread {
private ArrayList<Object> mObservers = new ArrayList<Object>();
UEventThread() {
super("UEventObserver");
}
public void run() {
native_setup();//调用uevent.c中的API来打开socket
byte[] buffer = new byte[1024];
int len;
while (true) {
len = next_event(buffer); // 在uevent.c中用poll调用来获取event,会阻塞
if (len > 0) {
String bufferStr = new String(buffer, 0, len);
synchronized (mObservers) {
for (int i = 0; i < mObservers.size(); i += 2) {
// 找到匹配的match参数,说明某个observer的监听的event发生了
if (bufferStr.indexOf((String)mObservers.get(i)) != -1) {
((UEventObserver)mObservers.get(i+1))
.onUEvent(new UEvent(bufferStr));
}
}
}
}
}
}
public final synchronized void startObserving(String match) {
//确保sThread已经运行并且以字串参数作为匹配参数增加一个observer
ensureThreadStarted();
sThread.addObserver(match, this);
}
public void addObserver(String match, UEventObserver observer) {
synchronized(mObservers) {
mObservers.add(match);
mObservers.add(observer);
}
}
}
会循环调用onUEvent函数,此函数在 WiredAccessoryObserver 类中
@Override
public void onUEvent(UEventObserver.UEvent event) {
try {
String name = event.get("SWITCH_NAME");
int state = Integer.parseInt(event.get("SWITCH_STATE"));
//此处调用 updateState
updateState(name, state);
} catch (NumberFormatException e) {
Slog.e(TAG, "Could not parse switch state from event " + event);
}
}
private synchronized final void updateState(String name, int state)
{
if (name.equals("usb_audio")) {
…
} else if (name.equals("hdmi")) {
…
} else {
switchState = ((mHeadsetState & (BIT_HDMI_AUDIO|BIT_USB_HEADSET_ANLG|
BIT_USB_HEADSET_DGTL)) |
((state == 1) ? BIT_HEADSET :
((state == 2) ? BIT_HEADSET_NO_MIC : 0)));
}
//此处调用 update函数
update(name, switchState);
}
// update函数: 用来更新耳机状态发送消息
private synchronized final void update(String newName, int newState) {
// Retain only relevant bits
int headsetState = newState & SUPPORTED_HEADSETS;
int newOrOld = headsetState | mHeadsetState;
int delay = 0;
int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG;
int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL;
int h2w_headset = newOrOld & (BIT_HEADSET | BIT_HEADSET_NO_MIC);
int h2w_state = (headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC));
int h2w_mstate = (mHeadsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC));
boolean h2wStateChange = true;
if (h2w_mstate == h2w_state || ((h2w_headset & (h2w_headset - 1)) != 0)) {
Log.e(TAG, "unsetting h2w flag");
h2wStateChange = false;
}
mHeadsetName = newName;
mPrevHeadsetState = mHeadsetState;
mHeadsetState = headsetState;
if (headsetState == 0) {
Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
mContext.sendBroadcast(intent);
// It can take hundreds of ms flush the audio pipeline after
// apps pause audio playback, but audio route changes are
// immediate, so delay the route change by 1000ms.
// This could be improved once the audio sub-system provides an
// interface to clear the audio pipeline.
delay = 1000;
} else {
// Insert the same delay for headset connection so that the connection event is not
// broadcast before the disconnection event in case of fast removal/insertion
if (mHandler.hasMessages(0)) {
delay = 1000;
}
}
mWakeLock.acquire();
//此处会发送消息
mHandler.sendMessageDelayed(mHandler.obtainMessage(0,
mHeadsetState,
mPrevHeadsetState,
mHeadsetName),
delay);
}
//此处处理消息
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
sendIntents(msg.arg1, msg.arg2, (String)msg.obj);
}
};
private synchronized final void sendIntents(int headsetState, int prevHeadsetState, String headsetName) {
int allHeadsets = SUPPORTED_HEADSETS;
//for 循环有疑问
// int BIT_HEADSET = (1 << 0);
//int BIT_HEADSET_NO_MIC = (1 << 1);…
// BIT_USB_HEADSET_ANLG
// BIT_USB_HEADSET_DGTL
// int SUPPORTED_HEADSETS =
(BIT_HEADSET|
BIT_HEADSET_NO_MIC|
BIT_USB_HEADSET_ANLG|
BIT_USB_HEADSET_DGTL|
BIT_HDMI_AUDIO);
for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
if ((curHeadset & allHeadsets) != 0) {
sendIntent(curHeadset, headsetState, prevHeadsetState, headsetName);
allHeadsets &= ~curHeadset;
}
}
}
//此处填充 Intent , 并通过 ActivityManagerNative.broadcastStickyIntent来发送
private final void sendIntent(int headset, int headsetState, int prevHeadsetState, String headsetName) {
//判断什么类型耳机,并发送广播
if ((headsetState & headset) != (prevHeadsetState & headset)) {
int state = 0;
if ((headsetState & headset) != 0) {
state = 1;
}
if((headset == BIT_HEADSET) || (headset == BIT_HEADSET_NO_MIC)) {
// Pack up the values and broadcast them to everyone
Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
//int state = 0;
int microphone = 0;
if ((headset & HEADSETS_WITH_MIC) != 0) {
microphone = 1;
}
intent.putExtra("state", state);
intent.putExtra("name", headsetName);
intent.putExtra("microphone", microphone);
if (LOG) Slog.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+headsetName+" mic: "+microphone);
ActivityManagerNative.broadcastStickyIntent(intent, null);
}
}
}
//ACTION类别
/**
* Broadcast Action: Wired Headset plugged in or unplugged.
*
* <p>The intent will have the following extra values:
* <ul>
* <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
* <li><em>name</em> - Headset type, human readable string </li>
* <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>
* </ul>
* </ul>
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_HEADSET_PLUG =
"android.intent.action.HEADSET_PLUG";
/**
* Broadcast Action: An analog(<电脑>模拟的) audio speaker/headset plugged in or unplugged.
*
* <p>The intent will have the following extra values:
* <ul>
* <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
* <li><em>name</em> - Headset type, human readable string </li>
* </ul>
* </ul>
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_USB_ANLG_HEADSET_PLUG =
"android.intent.action.USB_ANLG_HEADSET_PLUG";
/**
* Broadcast Action: A digital audio speaker/headset plugged in or unplugged.
*
* <p>The intent will have the following extra values:
* <ul>
* <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
* <li><em>name</em> - Headset type, human readable string </li>
* </ul>
* </ul>
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_USB_DGTL_HEADSET_PLUG =
"android.intent.action.USB_DGTL_HEADSET_PLUG";
参考资料:
http://blog.csdn.net/tanxs001/article/details/7709208
http://blog.sina.com.cn/s/blog_40d475e901012jxh.html
http://blog.csdn.net/darkengine/article/details/7442359
后续继续整理