ueventd 启动慢分析

1.ueventd 启动


init.c的main()函数中有一个巧妙的处理:可以通过判断第一个运行参数来启动不同的进程:

如果执行“./ueventd”,进入第一个条件分支,执行uevent_main()函数;
如果执行“./watchdog”,进入第二个条件分支,执行watchdogd_main()函数;
如果执行”./init”,跳过所有分支条件,继续执行main()函数。

system/core/init/main.cpp

51  int main(int argc, char** argv) {
52  #if __has_feature(address_sanitizer)
53      __asan_set_error_report_callback(AsanReportCallback);
54  #endif
55  
56      if (!strcmp(basename(argv[0]), "ueventd")) { //判断是否是ueventd 进程
57          return ueventd_main(argc, argv);
58      }
59  
60      if (argc > 1) {
61          if (!strcmp(argv[1], "subcontext")) {
62              android::base::InitLogging(argv, &android::base::KernelLogger);
63              const BuiltinFunctionMap function_map;
64  
65              return SubcontextMain(argc, argv, &function_map);
66          }
67  
68          if (!strcmp(argv[1], "selinux_setup")) {
69              return SetupSelinux(argv);
70          }
71  
72          if (!strcmp(argv[1], "second_stage")) {
73              return SecondStageMain(argc, argv);
74          }
75      }
76  
77      return FirstStageMain(argc, argv);
78  }

 

# Make a symlink from /sbin/ueventd and /sbin/watchdogd to /init
SYMLINKS := \
    $(TARGET_ROOT_OUT)/sbin/ueventd \
    $(TARGET_ROOT_OUT)/sbin/watchdogd

 

system/core/rootdir/init.rc

15 on early-init
16     # Disable sysrq from keyboard
17     write /proc/sys/kernel/sysrq 0
18 
19     # Set the security context of /adb_keys if present.
20     restorecon /adb_keys
21 
22     # Set the security context of /postinstall if present.
23     restorecon /postinstall
24 
25     mkdir /acct/uid
26 
27     # memory.pressure_level used by lmkd
28     chown root system /dev/memcg/memory.pressure_level
29     chmod 0040 /dev/memcg/memory.pressure_level
30     start ueventd

 

 

system/core/init/ueventd.cpp

220  int ueventd_main(int argc, char** argv) {
221      /*
222       * init sets the umask to 077 for forked processes. We need to
223       * create files with exact permissions, without modification by
224       * the umask.
225       */
226      umask(000);
227  
228      android::base::InitLogging(argv, &android::base::KernelLogger);
229  
230      LOG(INFO) << "ueventd started!";
231  
232      SelinuxSetupKernelLogging();
233      SelabelInitialize();
234  
235      std::vector<std::unique_ptr<UeventHandler>> uevent_handlers;
236  
237      // Keep the current product name base configuration so we remain backwards compatible and
238      // allow it to override everything.
239      // TODO: cleanup platform ueventd.rc to remove vendor specific device node entries (b/34968103)
240      auto hardware = android::base::GetProperty("ro.hardware", "");
241  
242      auto ueventd_configuration = ParseConfig({"/ueventd.rc", "/vendor/ueventd.rc",
243                                                "/odm/ueventd.rc", "/ueventd." + hardware + ".rc"});
244  
245      uevent_handlers.emplace_back(std::make_unique<DeviceHandler>(
246              std::move(ueventd_configuration.dev_permissions),
247              std::move(ueventd_configuration.sysfs_permissions),
248              std::move(ueventd_configuration.subsystems), android::fs_mgr::GetBootDevices(), true));
249      uevent_handlers.emplace_back(std::make_unique<FirmwareHandler>(
250              std::move(ueventd_configuration.firmware_directories)));
251  
252      if (ueventd_configuration.enable_modalias_handling) {
253          uevent_handlers.emplace_back(std::make_unique<ModaliasHandler>());
254      }
255      UeventListener uevent_listener(ueventd_configuration.uevent_socket_rcvbuf_size);
256  
257      if (access(COLDBOOT_DONE, F_OK) != 0) {//热启动就不进这里
258          ColdBoot cold_boot(uevent_listener, uevent_handlers);
259          cold_boot.Run();
260      }
261  
262      for (auto& uevent_handler : uevent_handlers) {
263          uevent_handler->ColdbootDone();
264      }
265  
266      // We use waitpid() in ColdBoot, so we can't ignore SIGCHLD until now.
267      signal(SIGCHLD, SIG_IGN);
268      // Reap and pending children that exited between the last call to waitpid() and setting SIG_IGN
269      // for SIGCHLD above.
270      while (waitpid(-1, nullptr, WNOHANG) > 0) {
271      }
272  
273      uevent_listener.Poll([&uevent_handlers](const Uevent& uevent) {
274          for (auto& uevent_handler : uevent_handlers) {
275              uevent_handler->HandleUevent(uevent);
276          }
277          return ListenerAction::kContinue;
278      });
279  
280      return 0;
281  }
282  
283  }  // namespace init
284  }  // namespace android

一般情况ueventd启动到创建 /dev/.coldboot_done,只需要2秒。如果有异常可以在这里添加log,看是哪里耗时。

205  void ColdBoot::Run() {
206      android::base::Timer cold_boot_timer;
207  
208      RegenerateUevents();  //这个函数调用非常多的驱动接口,最容易出问题。99% ueventd耗时的就 
                                是这里导致
209  
210      ForkSubProcesses();
211  
212      DoRestoreCon();
213  
214      WaitForSubProcesses();
215  
216      close(open(COLDBOOT_DONE, O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
        创建 #define COLDBOOT_DONE "/dev/.coldboot_done"
217      LOG(INFO) << "Coldboot took " << cold_boot_timer.duration().count() / 1000.0f << " seconds";
218  }

 

2 .ueventd启动慢,或者ueventd耗时

 

system/core/init/ueventd.cpp
146  void ColdBoot::RegenerateUevents() {
147      uevent_listener_.RegenerateUevents([this](const Uevent& uevent) {//这个括号是一个回 
                                                                            调函数
148          uevent_queue_.emplace_back(std::move(uevent));
149          return ListenerAction::kContinue;
150      });
151  }

 这段代码,看起来比较多,其实就做了一件事情,就是找出{"/sys/class", "/sys/block", "/sys/devices"} 目录下面的所有的uevent文件,往文件中写 add. 驱动的属性文件uevent收到"add"之后,就会做各种事情,如果驱动工程师是水平不高,随便搞几个delay,或者是死锁,就在这里有延时了,就算你在open的时候加了O_NONBLOCK ,也不会返回。

出现延时最多的可能就是 write(fd, "add\n", 4);这个地方

system/core/init/uevent_listener.cpp
130  ListenerAction UeventListener::RegenerateUeventsForDir(DIR* d,
131                                                         const ListenerCallback& callback) const {
132      int dfd = dirfd(d);
133  
134      int fd = openat(dfd, "uevent", O_WRONLY);
135      if (fd >= 0) {
136          write(fd, "add\n", 4);
137          close(fd);
138  
139          Uevent uevent;
140          while (ReadUevent(&uevent)) {
141              if (callback(uevent) == ListenerAction::kStop) return ListenerAction::kStop;
142          }
143      }
144  
145      dirent* de;
146      while ((de = readdir(d)) != nullptr) {
147          if (de->d_type != DT_DIR || de->d_name[0] == '.') continue;
148  
149          fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
150          if (fd < 0) continue;
151  
152          std::unique_ptr<DIR, decltype(&closedir)> d2(fdopendir(fd), closedir);
153          if (d2 == 0) {
154              close(fd);
155          } else {
156              if (RegenerateUeventsForDir(d2.get(), callback) == ListenerAction::kStop) {
157                  return ListenerAction::kStop;
158              }
159          }
160      }
161  
162      // default is always to continue looking for uevents
163      return ListenerAction::kContinue;
164  }
165  
166  ListenerAction UeventListener::RegenerateUeventsForPath(const std::string& path,
167                                                          const ListenerCallback& callback) const {
168      std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
169      if (!d) return ListenerAction::kContinue;
170  
171      return RegenerateUeventsForDir(d.get(), callback);
172  }
173  
174  static const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"};
175  
176  void UeventListener::RegenerateUevents(const ListenerCallback& callback) const {
177      for (const auto path : kRegenerationPaths) {
178          if (RegenerateUeventsForPath(path, callback) == ListenerAction::kStop) return;
179      }
180  }

经过搜索之后,发现有3个地方实现了uevent的 store_uevent,就是 write(fd, "add\n", 4);要写的地方。

sys/module/  目录下面的uevent

kernel/msm-4.19/kernel/module.c
1201  static ssize_t store_uevent(struct module_attribute *mattr,
1202  			    struct module_kobject *mk,
1203  			    const char *buffer, size_t count)
1204  {
1205  	int rc;
1206  
1207  	rc = kobject_synth_uevent(&mk->kobj, buffer, count);
1208  	return rc ? rc : count;
1209  }
1210  
1211  struct module_attribute module_uevent =
1212  	__ATTR(uevent, 0200, NULL, store_uevent);

sys/bus  目录下面的uevent

kernel/msm-4.19/drivers/base/bus.c

833  static ssize_t bus_uevent_store(struct bus_type *bus,
834  				const char *buf, size_t count)
835  {
836  	int rc;
837  
838  	rc = kobject_synth_uevent(&bus->p->subsys.kobj, buf, count);
839  	return rc ? rc : count;
840  }
841  static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);

614  static ssize_t uevent_store(struct device_driver *drv, const char *buf,
615  			    size_t count)
616  {
617  	int rc;
618  
619  	rc = kobject_synth_uevent(&drv->p->kobj, buf, count);
620  	return rc ? rc : count;
621  }
622  static DRIVER_ATTR_WO(uevent);

其他路径下的 uevent

kernel/msm-4.19/drivers/base/core.c
1073  static ssize_t uevent_store(struct device *dev, struct device_attribute *attr,
1074  			    const char *buf, size_t count)
1075  {
1076  	int rc;
1077  
1078  	rc = kobject_synth_uevent(&dev->kobj, buf, count);
1079  
1080  	if (rc) {
1081  		dev_err(dev, "uevent: failed to send synthetic uevent\n");
1082  		return rc;
1083  	}
1084  
1085  	return count;
1086  }
1087  static DEVICE_ATTR_RW(uevent);

最终都是调

kobject_synth_uevent

kernel/msm-4.19/lib/kobject_uevent.c
192  int kobject_synth_uevent(struct kobject *kobj, const char *buf, size_t count)
193  {
194  	char *no_uuid_envp[] = { "SYNTH_UUID=0", NULL };
195  	enum kobject_action action;
196  	const char *action_args;
197  	struct kobj_uevent_env *env;
198  	const char *msg = NULL, *devpath;
199  	int r;
200  
201  	r = kobject_action_type(buf, count, &action, &action_args);
202  	if (r) {
203  		msg = "unknown uevent action string\n";
204  		goto out;
205  	}
206  
207  	if (!action_args) {
208  		r = kobject_uevent_env(kobj, action, no_uuid_envp);
209  		goto out;
210  	}
211  
212  	r = kobject_action_args(action_args,
213  				count - (action_args - buf), &env);
214  	if (r == -EINVAL) {
215  		msg = "incorrect uevent action arguments\n";
216  		goto out;
217  	}
218  
219  	if (r)
220  		goto out;
221  
222  	r = kobject_uevent_env(kobj, action, env->envp);
223  	kfree(env);
224  out:
225  	if (r) {
226  		devpath = kobject_get_path(kobj, GFP_KERNEL);
227  		printk(KERN_WARNING "synth uevent: %s: %s",
228  		       devpath ?: "unknown device",
229  		       msg ?: "failed to send uevent");
230  		kfree(devpath);
231  	}
232  	return r;
233  }

所有实现了uevent_ops->uevent方法的struct kobject都有可能导致延迟,或者是死锁。

把可以在这里把用时多的kobject就可以了。

454  int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
455  		       char *envp_ext[])
456  {

463  	const struct kset_uevent_ops *uevent_ops;
478  	top_kobj = kobj;
479  	while (!top_kobj->kset && top_kobj->parent)
480  		top_kobj = top_kobj->parent;
481  
482  	if (!top_kobj->kset) {
483  		pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
484  			 "without kset!\n", kobject_name(kobj), kobj,
485  			 __func__);
486  		return -EINVAL;
487  	}
488  
489  	kset = top_kobj->kset;
490  	uevent_ops = kset->uevent_ops;
553  	if (uevent_ops && uevent_ops->uevent) {
554  		retval = uevent_ops->uevent(kset, kobj, env);
555  		if (retval) {
556  			pr_debug("kobject: '%s' (%p): %s: uevent() returned "
557  				 "%d\n", kobject_name(kobj), kobj,
558  				 __func__, retval);
559  			goto exit;
560  		}
561  	}

init 进程会在这里等待60s,如果60秒ueventd还没起来,手机就会重启。

 

system/core/init/init.cpp

347  static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& args) {
348      Timer t;
349      std::chrono::nanoseconds timeout = 60s;
350  #ifdef SLOW_BOARD
351      timeout = 6000s;
352  #endif
353  
354      LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE "...";
355  
364      if (wait_for_file(COLDBOOT_DONE, timeout) < 0) {
365          LOG(FATAL) << "Timed out waiting for " COLDBOOT_DONE;
366      }
367  
368      property_set("ro.boottime.init.cold_boot_wait",         
         std::to_string(t.duration().count()));
369      return Success();
370  }

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值