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

本文深入剖析了Android系统中UEvent事件监听机制,从自定义UEventObserver类开始,详细介绍了startObserving方法的实现,以及如何通过UEventThread线程和netlink通信接收内核层上报的uevent事件。此外,还分析了usb热插拔事件的处理流程,展示了UEvent构造函数如何解析事件消息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

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  }

 

 

<think>好的,我现在需要帮助用户了解Android系统中Kernel层healthd的上报流程以及系统健康状态监测。首先,我要回忆下相关知识点,并查看用户提供的引用内容。 根据引用[2],healthd是Native层的系统服务,负责监听Kerneluevent,监控电池电量。引用[3]提到,当Kernel上报uevent属于电源子系统(power_supply)时,会触发healthd_battery_update(),进而调用Health::update()方法。引用[4]说明了Android启动流程,其中Kernel启动后是Native层,这里包括init进程,可能涉及healthd的初始化。 首先,Kernel中的电源子系统(如电池驱动)会在电量变化时生成uevent事件。这些事件通过Netlink套接字发送到用户空间。然后,healthd服务(位于Native层)会监听这些uevent事件。当检测到属于电源子系统的uevent时,healthd解析事件内容,更新电池状态,并可能记录日志或通知上层服务。 用户提供的代码示例中,healthd_board_init和healthd_board_battery_update函数可能负责初始化和处理电池更新。根据引用[1],healthd_board_battery_update返回0时会记录电池状态到内核日志。 需要确保回答结构清晰,分步骤说明流程,并正确引用提供的资料。另外,生成相关问题时要围绕healthd的工作机制、与其他组件的关系、日志分析以及启动流程中的位置等方面。</think>### Kernel中healthd的上报流程及Android健康状态监测 #### 1. **Kernel事件触发** Linux内核的电源子系统(`power_supply`)会监测硬件状态(如电池电量、温度等),当状态变化时,驱动会通过`uevent`机制向用户空间发送事件。例如: ```cpp // 内核驱动示例(伪代码) power_supply_changed(battery_device); // 触发uevent ``` 该事件包含属性如`POWER_SUPPLY_CAPACITY`(电量百分比)[^3]。 #### 2. **Native层监听与处理** Android的`healthd`服务在Native层通过`init`进程启动,注册`uevent`监听: ```cpp // healthd初始化流程(简化) void healthd_main() { uevent_init(); // 初始化uevent监听 while (true) { uevent_poll(); // 阻塞等待事件 if (event.subsystem == POWER_SUPPLY_SUBSYSTEM) { healthd_battery_update(); // 解析并更新电池状态 } } } ``` `healthd_battery_update()`会调用`Health::update()`,最终通过`BatteryProperties`结构体存储数据[^2]。 #### 3. **数据上报与日志记录** 更新后的电池状态会通过以下两种方式传递: - **内核日志**:若`healthd_board_battery_update()`返回0,会定期记录到`/proc/kmsg`[^1]。 - **Binder通信**:通过`batteryproperties`服务将数据传递到Framework层(如`BatteryService`)[^2]。 #### 4. **Framework层响应** Java层的`BatteryService`接收到数据后,会广播`ACTION_BATTERY_CHANGED`意图,通知应用电量变化。 #### 流程总结图 ``` Kernel电源驱动 → uevent → healthd监听 → 解析数据 → 更新状态 → 日志/Binder → Framework ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值