Android UEvent事件分析之Kernel上报电量

本文深入探讨了Android系统中,当电量信息发生变化时,Kernel如何通过UEvent事件通知用户空间。从kernel的power_supply_core.c驱动开始,讲解了power_supply_changed_work工作队列和kobject_uevent函数的使用,进而分析了kobject_uevent_env如何将状态信息存储,并通过netlink_broadcast_filtered发送给用户空间。在用户空间,healthd_common.cpp接收uevent信息,经过一系列处理后,最终由BatteryService更新电量状态并发送ACTION_BATTERY_CHANGED广播。

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

kernel-4.4\drivers\power\power_supply_core.c

当电量信息需要更新的时候,kernel会调用power_supply_changed_work这个工作队列,使用kobject_uevent函数往上发送uevent事件,action是KOBJ_CHANGE;

static void power_supply_changed_work(struct work_struct *work)
{
    unsigned long flags;
    struct power_supply *psy = container_of(work, struct power_supply,
                        changed_work);
 
    dev_dbg(&psy->dev, "%s\n", __func__);
 
    spin_lock_irqsave(&psy->changed_lock, flags);
    /*
     * Check 'changed' here to avoid issues due to race between
     * power_supply_changed() and this routine. In worst case
     * power_supply_changed() can be called again just before we take above
     * lock. During the first call of this routine we will mark 'changed' as
     * false and it will stay false for the next call as well.
     */
    if (likely(psy->changed)) {
        printk("power_supply_changed_work 1111 \n" );
        psy->changed = false;
        spin_unlock_irqrestore(&psy->changed_lock, flags);
        class_for_each_device(power_supply_class, NULL, psy,
                      __power_supply_changed_work);
        power_supply_update_leds(psy);
        atomic_notifier_call_chain(&power_supply_notifier,
                PSY_EVENT_PROP_CHANGED, psy);
        kobject_uevent(&psy->dev.kobj, KOBJ_CHANGE);
        spin_lock_irqsave(&psy->changed_lock, flags);
    }
 
    /*
     * Hold the wakeup_source until all events are processed.
     * power_supply_changed() might have called again and have set 'changed'
     * to true.
     */
    if (likely(!psy->changed))
        pm_relax(&psy->dev);
    spin_unlock_irqrestore(&psy->changed_lock, flags);
}


 

来看看kobject_uevent(&psy->dev.kobj, KOBJ_CHANGE);

/kernel-4.4/lib/kobject_uevent.c

372  int kobject_uevent(struct kobject *kobj, enum kobject_action action)
373  {
374      return kobject_uevent_env(kobj, action, NULL);
375  }


kobject_uevent_env代码相当长,由于已经配置了CONFIG_NET,在这里就只需要看netlink部分。



154  /**
155   * kobject_uevent_env - send an uevent with environmental data
156   *
157   * @action: action that is happening
158   * @kobj: struct kobject that the action is happening to
159   * @envp_ext: pointer to environmental data
160   *
161   * Returns 0 if kobject_uevent_env() is completed with success or the
162   * corresponding error when it fails.
163   */
164  int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
165                 char *envp_ext[])
166  {
167      struct kobj_uevent_env *env;
168      const char *action_string = kobject_actions[action];
169      const char *devpath = NULL;
170      const char *subsystem;
171      struct kobject *top_kobj;
172      struct kset *kset;
173      const struct kset_uevent_ops *uevent_ops;
174      int i = 0;
175      int retval = 0;
176  #ifdef CONFIG_NET
177      struct uevent_sock *ue_sk;
178  #endif
179  
180      pr_debug("kobject: '%s' (%p): %s\n",
181           kobject_name(kobj), kobj, __func__);
182  
183      /* search the kset we belong to */
184      top_kobj = kobj;
185      while (!top_kobj->kset && top_kobj->parent)
186          top_kobj = top_kobj->parent;
187  
188      if (!top_kobj->kset) {
189          pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
190               "without kset!\n", kobject_name(kobj), kobj,
191               __func__);
192          return -EINVAL;
193      }
194  
195      kset = top_kobj->kset;
196      uevent_ops = kset->uevent_ops;
197  
198      /* skip the event, if uevent_suppress is set*/
199      if (kobj->uevent_suppress) {
200          pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
201                   "caused the event to drop!\n",
202                   kobject_name(kobj), kobj, __func__);
203          return 0;
204      }
205      /* skip the event, if the filter returns zero. */
206      if (uevent_ops && uevent_ops->filter)
207          if (!uevent_ops->filter(kset, kobj)) {
208              pr_debug("kobject: '%s' (%p): %s: filter function "
209                   "caused the event to drop!\n",
210                   kobject_name(kobj), kobj, __func__);
211              return 0;
212          }
213  
214      /* originating subsystem */
215      if (uevent_ops && uevent_ops->name)
216          subsystem = uevent_ops->name(kset, kobj);
217      else
218          subsystem = kobject_name(&kset->kobj);
219      if (!subsystem) {
220          pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
221               "event to drop!\n", kobject_name(kobj), kobj,
222               __func__);
223          return 0;
224      }
225  
226      /* environment buffer */
227      env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
228      if (!env)
229          return -ENOMEM;
230  
231      /* complete object path */
232      devpath &
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值