当前位置: 首页 > 工具软件 > pf-kernel > 使用案例 >

知其然也要知其所以然---上层监听Kernel上报的UEvent事件流程分析(一)

万俟渝
2023-12-01

 

1,涉及到的文件 frameworks:

frameworks/base/core/java/android/os/UEventObserver.java

frameworks/base/core/jni/android_os_UEventObserver.cpp

要监听kernel层上报的的uevent事件,

首先要做的是自定义一个类继承UEventObserver类并实现其抽象方法onUEvent方法;

  public abstract void onUEvent(UEvent event);

其次是调用 mUEventObserver.startObserving(“XXXX”);方法

 

先看其startObserving方法:

      public final void startObserving(String match) {
          if (match == null || match.isEmpty()) {
              throw new IllegalArgumentException("match substring must be non-empty");
          }
  
          final UEventThread t = getThread();
          t.addObserver(match, this);
      }

通过getThread方法创建了一个单例模式的UEventThread 线程,并调用了start方法。

同时将我们需要监听的event实践添加到观察表中

 

继续看线程的run方法:

177          @Override
178          public void run() {
179              nativeSetup();
180  
181              while (true) {
182                  String message = nativeWaitForNextEvent();
183                  if (message != null) {
184                      if (DEBUG) {
185                          Log.d(TAG, message);
186                      }
187                      sendEvent(message);
188                  }
189              }
190          }

在run方法中调用一个nativeSetup()一看名字,就知道这里是跑到Jni中去了

然后就是一个while死循环中无限调用nativeWaitForNextEvent,如果返回的message不为空,调用sendEvent;

来看看nativeSetup具体是做了什么?

frameworks/base/core/jni/android_os_UEventObserver.cpp

37  static void nativeSetup(JNIEnv *env, jclass clazz) {
38      if (!uevent_init()) {
39          jniThrowException(env, "java/lang/RuntimeException",
40                  "Unable to open socket for UEventObserver");
41      }
42  }

hardware/libhardware_legacy/uevent.c

43  int uevent_init()
44  {
45      struct sockaddr_nl addr;
46      int sz = 64*1024;
47      int s;
48  
49      memset(&addr, 0, sizeof(addr));
50      addr.nl_family = AF_NETLINK;
51      addr.nl_pid = getpid();
52      addr.nl_groups = 0xffffffff;
53  
54      s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
55      if(s < 0)
56          return 0;
57  
58      setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
59  
60      if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
61          close(s);
62          return 0;
63      }
64  
65      fd = s;
66      return (fd > 0);
67  }

使用netlink与底层kernel通信

接着回去看nativeWaitForNextEvent

64  static jstring nativeWaitForNextEvent(JNIEnv *env, jclass clazz) {
65      char buffer[1024];
66  
67      for (;;) {
68          int length = uevent_next_event(buffer, sizeof(buffer) - 1);
69          if (length <= 0) {
70              return NULL;
71          }
72          buffer[length] = '\0';
73  
74          ALOGV("Received uevent message: %s", buffer);
75  
76          if (isMatch(buffer, length)) {
77              // Assume the message is ASCII.
78              jchar message[length];
79              for (int i = 0; i < length; i++) {
80                  message[i] = buffer[i];
81              }
82              return env->NewString(message, length);
83          }
84      }
85  }

 

74  int uevent_next_event(char* buffer, int buffer_length)
75  {
76      while (1) {
77          struct pollfd fds;
78          int nr;
79  
80          fds.fd = fd;
81          fds.events = POLLIN;
82          fds.revents = 0;
83          nr = poll(&fds, 1, -1);
84  
85          if(nr > 0 && (fds.revents & POLLIN)) {
86              int count = recv(fd, buffer, buffer_length, 0);
87              if (count > 0) {
88                  struct uevent_handler *h;
89                  pthread_mutex_lock(&uevent_handler_list_lock);
90                  LIST_FOREACH(h, &uevent_handler_list, list)
91                      h->handler(h->handler_data, buffer, buffer_length);
92                  pthread_mutex_unlock(&uevent_handler_list_lock);
93  
94                  return count;
95              }
96          }
97      }
98  
99      // won't get here
100      return 0;
101  }

使用poll机制来监测我们的事件节点

当我们的节点信息发生改变时,在nativeWaitForNextEvent中会收到如下log:
2019-07-24 10:39:02.148 914-988/system_process D/LGY_HAL: Received uevent message: change@/devices/platform/battery/power_supply/battery

2019-07-24 11:31:56.979 914-988/system_process D/LGY_HAL: Received uevent message: change@/devices/virtual/lgy_class/lgy

然后调用isMatch()来判断该类型的事件是否已经注册了,

44  static bool isMatch(const char* buffer, size_t length) {
45      AutoMutex _l(gMatchesMutex);
46  
47      for (size_t i = 0; i < gMatches.size(); i++) {
48          const String8& match = gMatches.itemAt(i);
49  
50          // Consider all zero-delimited fields of the buffer.
51          const char* field = buffer;
52          const char* end = buffer + length + 1;
53          do {
54              if (strstr(field, match.string())) {
55                  ALOGV("Matched uevent message with pattern: %s", match.string());
56                  return true;
57              }
58              field += strlen(field) + 1;
59          } while (field != end);
60      }
61      return false;
62  }

我们要监听的事件在startObserving里调用t.addObserver时就已经加上了。

216          public void addObserver(String match, UEventObserver observer) {
217              synchronized (mKeysAndObservers) {
218                  mKeysAndObservers.add(match);
219                  mKeysAndObservers.add(observer);
220                  nativeAddMatch(match);
221              }
222          }

将nativeWaitForNextEvent返回的message 通过sendEvent发送出去:

这里的message是如下类型的字符串:

sendEvent message =  change@/devices/virtual/misc/cpu_loading��ACTION=change��DEVPATH=/devices/virtual/misc/cpu_loading��SUBSYSTEM=misc��lower=2��MAJOR=10��MINOR=0��DEVNAME=cpu_loading��SEQNUM=4674��

这里的��乱码其实是'\0';

192          private void sendEvent(String message) {
193              synchronized (mKeysAndObservers) {
194                  final int N = mKeysAndObservers.size();
195                  for (int i = 0; i < N; i += 2) {
196                      final String key = (String)mKeysAndObservers.get(i);
197                      if (message.contains(key)) {
198                          final UEventObserver observer =
199                                  (UEventObserver)mKeysAndObservers.get(i + 1);
200                          mTempObserversToSignal.add(observer);
201                      }
202                  }
203              }
204  
205              if (!mTempObserversToSignal.isEmpty()) {
206                  final UEvent event = new UEvent(message);
207                  final int N = mTempObserversToSignal.size();
208                  for (int i = 0; i < N; i++) {
209                      final UEventObserver observer = mTempObserversToSignal.get(i);
210                      observer.onUEvent(event);
211                  }
212                  mTempObserversToSignal.clear();
213              }
214          }

其中 observer.onUEvent(event);调用各自的onUEvent方法。

所以我们自定义的继承UEventObserver类并实现其抽象方法onUEvent方法,就是在这里触发调用的。

 

看看系统是在onUEvent中如何处理usb热插拔事件的

frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java

215      /*
216       * Listens for uevent messages from the kernel to monitor the USB state
217       */
218      private final class UsbUEventObserver extends UEventObserver {
219          @Override
220          public void onUEvent(UEventObserver.UEvent event) {
221              if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());
222  
223              String state = event.get("USB_STATE");
224              String accessory = event.get("ACCESSORY");
225              if (state != null) {
226                  mHandler.updateState(state);
227              } else if ("START".equals(accessory)) {
228                  if (DEBUG) Slog.d(TAG, "got accessory start");
229                  startAccessoryMode();
230              }
231          }
232      }

看样子很明确了,在onUEvent中只是通过state和accessory两个String的值判断状态的。

223              String state = event.get("USB_STATE");
224              String accessory = event.get("ACCESSORY");

原理是什么呢?那就要来看UEvent 这个UEventObserver.java中的内部类了

126      public static final class UEvent {
127          // collection of key=value pairs parsed from the uevent message
128          private final HashMap<String,String> mMap = new HashMap<String,String>();
129  
130          public UEvent(String message) {
131              int offset = 0;
132              int length = message.length();
133  
134              while (offset < length) {
135                  int equals = message.indexOf('=', offset);
136                  int at = message.indexOf('\0', offset);
137                  if (at < 0) break;
138  
139                  if (equals > offset && equals < at) {
140                      // key is before the equals sign, and value is after
141                      mMap.put(message.substring(offset, equals),
142                              message.substring(equals + 1, at));
143                  }
144  
145                  offset = at + 1;
146              }
147          }
148  
149          public String get(String key) {
150              return mMap.get(key);
151          }
152  
153          public String get(String key, String defaultValue) {
154              String result = mMap.get(key);
155              return (result == null ? defaultValue : result);
156          }
157  
158          public String toString() {
159              return mMap.toString();
160          }
161      }

构造函数很简单,是什么意思呢?

就是将字符串中等于符号'='两边的值,前者为key,后者为value存储在map中。

插拔usb时,通过sendEvent发送出去的message是什么样子的吗?

插入usb:USB_STATE=CONNECTED

sendEvent message =  change@/devices/virtual/android_usb/android0??ACTION=change??DEVPATH=/devices/virtual/android_usb/android0??SUBSYSTEM=android_usb??USB_STATE=CONNECTED??SEQNUM=5484??

拔出usb:USB_STATE=DISCONNECTED

sendEvent message =  change@/devices/virtual/android_usb/android0??ACTION=change??DEVPATH=/devices/virtual/android_usb/android0??SUBSYSTEM=android_usb??USB_STATE=DISCONNECTED??SEQNUM=5485??

除此之外还有另外一种状态:USB_STATE=CONFIGURED

sendEvent message =  change@/devices/virtual/android_usb/android0??ACTION=change??DEVPATH=/devices/virtual/android_usb/android0??SUBSYSTEM=android_usb??USB_STATE=CONFIGURED??SEQNUM=5487??

这一字符串中显示??的地方其实是‘\0’,也在UEvent构造函数中有所处理了哈。

所以String state = event.get("USB_STATE");只会出现三种情况,通过state的值就可以判断usb是处于什么样的状态了。

 

那么底层kernel是如何传usb的状态的呢?

是通过kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);传递给用户层的

状态值存在uevent_envp这个二级指针中。kobject_uevent_env的分析在知其然也要知其所以然---Kernel上报电量UEvent事件流程分析一文中有说道。

172  static void android_work(struct work_struct *data)
173  {
174  	struct android_dev *dev = container_of(data, struct android_dev, work);
175  	struct usb_composite_dev *cdev = dev->cdev;
176  	char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL };
177  	char *connected[2]    = { "USB_STATE=CONNECTED", NULL };
178  	char *configured[2]   = { "USB_STATE=CONFIGURED", NULL };
179  	char **uevent_envp = NULL;
180  	unsigned long flags;
181  
182  	if (!cdev) {
183  		pr_notice("android_work, !cdev\n");
184  		return;
185  	}
186  
187  	spin_lock_irqsave(&cdev->lock, flags);
188  	if (cdev->config)
189  		uevent_envp = configured;
190  	else if (dev->connected != dev->sw_connected)
191  		uevent_envp = dev->connected ? connected : disconnected;
192  	dev->sw_connected = dev->connected;
193  	spin_unlock_irqrestore(&cdev->lock, flags);
194  
195  	if (uevent_envp) {
196  		kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);
197  		pr_notice("%s: sent uevent %s\n", __func__, uevent_envp[0]);
198  #ifdef CONFIG_MTPROF
199  		if (uevent_envp == configured) {
200  			static int first_shot = 1;
201  
202  			if (first_shot) {
203  				log_boot("USB configured");
204  				first_shot = 0;
205  			}
206  		}
207  #endif
208  	} else {
209  		pr_notice("%s: did not send uevent (%d %d %p)\n", __func__,
210  			 dev->connected, dev->sw_connected, cdev->config);
211  	}
212  }

 

 

 类似资料: