UML中的分区暂时无法挂载。
2. 挂载流程函数调用流程:
InitRequiredDevices()--->uevent_callback()--->UeventCallback()
在init/first_stage_mount.cpp中
415 ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) {
416 // Ignores everything that is not a block device.
417 if (uevent.subsystem != "block") {
418 return ListenerAction::kContinue;
419 }
420
421 if (!uevent.partition_name.empty()) {
422 if ( (uevent.partition_name == "super") || (uevent.partition_name == "vbmeta")) {
423 LOG(INFO) << "tom action=" << uevent.action<<" path="<<uevent.path<<" subsystem="<<uevent.subsystem;
424 LOG(INFO) << "tom firmware=" << uevent.firmware<<" p_name="<<uevent.partition_name;
425 LOG(INFO) << "tom device_name=" << uevent.device_name<<" modifies="<<uevent.modalias;
426 LOG(INFO) << "tom partition_num=" << uevent.partition_num<<" major="<<uevent.major<<" minor="<<uevent.minor;
427 }
428 return HandleBlockDevice(uevent.partition_name, uevent);
429 } else {
430 size_t base_idx = uevent.path.rfind('/');
431 if (base_idx != std::string::npos) {
432 return HandleBlockDevice(uevent.path.substr(base_idx + 1), uevent);
433 }
434 }
435 // Not found a partition or find an unneeded partition, continue to find others.
436 return ListenerAction::kContinue;
437 }
打印信息:
[ 1.370375] init: tom action=add path=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda2 subsystem=block
[ 1.372134] init: tom firmware= p_name=super
[ 1.372457] init: tom device_name=vda2 modifies=
[ 1.372838] init: tom partition_num=2 major=253 minor=2
[ 1.373596] tom F=kobject_uevent_env subsystem=block
[ 1.373597] tom F=kobject_uevent_env devpath=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1
[ 1.374069] init: tom action=add path=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1 subsystem=block
[ 1.375689] init: tom firmware= p_name=vbmeta
[ 1.376047] init: tom device_name=vda1 modifies=
[ 1.376420] init: tom partition_num=1 major=253 minor=1
分析,在uevent事件中,接受到partion_name的super和vbmeta时候,就加载system分区。
启动信息如下:
[ 0.000000] Command line: qemu=1 no_timer_check androidboot.hardware=ranchu androidboot.serialno=EMULATOR29X0X1X0 clocksource=pit no-kvmclock console=ttyS0,38400 android.qemud=1 android.checkjni=1 qemu.gles=1 qemu.settings.system.screen_off_timeout=2147483647 qemu.encrypt=1 qemu.opengles.version=196609 qemu.uirenderer=skiagl cma=262M@0-4G qemu.wifi=1 mac80211_hwsim.channels=2 loop.max_part=7 androidboot.vbmeta.size=4352 androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.digest=de63a9b7482880698b68084b079c251fb974d1c7f06d588865f1ddd5a866008c androidboot.boot_devices=pci0000:00/0000:00:03.0 ramoops.mem_address=0xff018000 ramoops.mem_size=0x10000 memmap=0x10000$0xff018000 qemu.dalvik.vm.heapsize=192m mac80211_hwsim.mac_prefix=5554
可以看出b
3. 问题1)这个uevent消息是谁发出的?
2)uevent消息中partition_name是哪里来的?
在uevent_listener.cpp中,通过ReadUevent函数,给msg赋值,调用 ParseEvent(msg, uevent)。
98 bool UeventListener::ReadUevent(Uevent* uevent) const {
99 char msg[UEVENT_MSG_LEN + 2];
100 int n = uevent_kernel_multicast_recv(device_fd_, msg, UEVENT_MSG_LEN);
101 if (n <= 0) {
102 if (errno != EAGAIN && errno != EWOULDBLOCK) {
103 LOG(ERROR) <= UEVENT_MSG_LEN) {
108 LOG(ERROR) << "Uevent overflowed buffer, discarding";
109 // Return true here even if we discard as we may have more uevents pending and we
110 // want to keep processing them.
111 return true;
112 }
113
114 msg[n] = '\0';
115 msg[n + 1] = '\0';
116
117 ParseEvent(msg, uevent);
118
119 return true;
120 }
函数uevent_kernel_multicast_recv中,调用uevent_kernel_multicast_uid_recv,主要看buffer的赋值。
35 ssize_t uevent_kernel_multicast_recv(int socket, void* buffer, size_t length) {
36 uid_t uid = -1;
37 return uevent_kernel_multicast_uid_recv(socket, buffer, length, &uid);
38 }
uevent_kernel_multicast_uid_recv函数:
49 ssize_t uevent_kernel_multicast_uid_recv(int socket, void* buffer, size_t length, uid_t* uid) {
50 return uevent_kernel_recv(socket, buffer, length, true, uid);
51 }
函数uevent_kernel_recv的定义如下:
53 ssize_t uevent_kernel_recv(int socket, void* buffer, size_t length, bool require_group, uid_t* uid) {
54 struct iovec iov = {buffer, length};
55 struct sockaddr_nl addr;
56 char control[CMSG_SPACE(sizeof(struct ucred))];
57 struct msghdr hdr = {
58 &addr, sizeof(addr), &iov, 1, control, sizeof(control), 0,
59 };
60 struct ucred* cred;
61
62 *uid = -1;
63 ssize_t n = recvmsg(socket, &hdr, 0);
64 if (n cmsg_type != SCM_CREDENTIALS) {
70 /* ignoring netlink message with no sender credentials */
71 goto out;
72 }
73
74 cred = (struct ucred*)CMSG_DATA(cmsg);
75 *uid = cred->uid;
76
77 if (addr.nl_pid != 0) {
78 /* ignore non-kernel */
79 goto out;
80 }
81 if (require_group && addr.nl_groups == 0) {
82 /* ignore unicast messages when requested */
83 goto out;
84 }
85
86 return n;
87
88 out:
89 /* clear residual potentially malicious data */
90 bzero(buffer, length);
91 errno = EIO;
92 return -1;
93 }
在uevent_listener.cpp中:
在文件lib/kobject_uevent.c的kobject_uevent_env的函数中:
481 list_for_each_entry(ue_sk, &uevent_sock_list, list) {
482 struct sock *uevent_sock = ue_sk->sk;
483 struct sk_buff *skb;
484 size_t len;
485
486 if (!netlink_has_listeners(uevent_sock, 1))
487 continue;
488
489 /* allocate message with the maximum possible size */
490 len = strlen(action_string) + strlen(devpath) + 2;
491 skb = alloc_skb(len + env->buflen, GFP_KERNEL);
492 if (skb) {
493 char *scratch;
494
495 /* add header */
496 scratch = skb_put(skb, len);
497 sprintf(scratch, "%s@%s", action_string, devpath);
498
499 /* copy keys to our continuous event payload buffer */
500 for (i = 0; i envp_idx; i++) {
501 len = strlen(env->envp[i]) + 1;
502 scratch = skb_put(skb, len);
503 strcpy(scratch, env->envp[i]);
504 if(!strncmp(subsystem,"block",5)) {
505 printk(KERN_ERR "tom F=%s env1->envp[%d]=%s",__FUNCTION__,i,env->envp[i]);
506 }
507 }
508
509 NETLINK_CB(skb).dst_group = 1;
510 retval = netlink_broadcast_filtered(uevent_sock, skb,
511 0, 1, GFP_KERNEL,
512 kobj_bcast_filter,
513 kobj);
514 /* ENOBUFS should be handled in userspace */
515 if (retval == -ENOBUFS || retval == -ESRCH)
516 retval = 0;
517 } else
518 retval = -ENOMEM;
519 }
调试记录:
[ 1.391153] tom F=kobject_uevent_env env1->envp[0]=ACTION=add
[ 1.391630] tom F=kobject_uevent_env env1->envp[1]=DEVPATH=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda2
[ 1.392211] tom F=kobject_uevent_env env1->envp[2]=SUBSYSTEM=block
[ 1.393073] tom F=kobject_uevent_env env1->envp[3]=SYNTH_UUID=0
[ 1.393574] tom F=kobject_uevent_env env1->envp[4]=MAJOR=253
[ 1.394135] tom F=kobject_uevent_env env1->envp[5]=MINOR=2
[ 1.394748] tom F=kobject_uevent_env env1->envp[6]=DEVNAME=vda2
[ 1.395193] tom F=kobject_uevent_env env1->envp[7]=DEVTYPE=partition
[ 1.395670] tom F=kobject_uevent_env env1->envp[8]=PARTN=2
[ 1.396199] tom F=kobject_uevent_env env1->envp[9]=PARTNAME=super
[ 1.396732] tom F=kobject_uevent_env env1->envp[10]=SEQNUM=1035
[ 1.397385] init: tom action=add path=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda2 subsystem=block
[ 1.398695] init: tom firmware= p_name=super
[ 1.399152] init: tom device_name=vda2 modifies=
[ 1.399540] init: tom partition_num=2 major=253 minor=2
[ 1.400378] tom F=kobject_uevent_env subsystem=block
[ 1.400379] tom F=kobject_uevent_env devpath=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1
[ 1.400864] tom F=kobject_uevent_env envp=SYNTH_UUID=0
[ 1.401666] tom F=kobject_uevent_env env1->envp[0]=ACTION=add
[ 1.402088] tom F=kobject_uevent_env env1->envp[1]=DEVPATH=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1
[ 1.402559] tom F=kobject_uevent_env env1->envp[2]=SUBSYSTEM=block
[ 1.403382] tom F=kobject_uevent_env env1->envp[3]=SYNTH_UUID=0
[ 1.403995] tom F=kobject_uevent_env env1->envp[4]=MAJOR=253
[ 1.404501] tom F=kobject_uevent_env env1->envp[5]=MINOR=1
[ 1.404957] tom F=kobject_uevent_env env1->envp[6]=DEVNAME=vda1
[ 1.405399] tom F=kobject_uevent_env env1->envp[7]=DEVTYPE=partition
[ 1.405878] tom F=kobject_uevent_env env1->envp[8]=PARTN=1
[ 1.406393] tom F=kobject_uevent_env env1->envp[9]=PARTNAME=vbmeta
[ 1.406838] tom F=kobject_uevent_env env1->envp[10]=SEQNUM=1036
[ 1.407369] init: tom action=add path=/devices/pci0000:00/0000:00:03.0/virtio0/block/vda/vda1 subsystem=block
[ 1.408748] init: tom firmware= p_name=vbmeta
[ 1.409110] init: tom device_name=vda1 modifies=
[ 1.409495] init: tom partition_num=1 major=253 minor=1
调试纪录:
可以看出,在kernel中传递了PARTNAME、DEVPATH和DEVTYPE等变量
在core/init/uevent_listener.cpp的ParseEvent函数中:
32 static void ParseEvent(const char* msg, Uevent* uevent) {
33 uevent->partition_num = -1;
34 uevent->major = -1;
35 uevent->minor = -1;
36 uevent->action.clear();
37 uevent->path.clear();
38 uevent->subsystem.clear();
39 uevent->firmware.clear();
40 uevent->partition_name.clear();
41 uevent->device_name.clear();
42 uevent->modalias.clear();
43 // currently ignoring SEQNUM
44 while (*msg) {
45 if (!strncmp(msg, "ACTION=", 7)) {
46 msg += 7;
47 uevent->action = msg;
48 } else if (!strncmp(msg, "DEVPATH=", 8)) {
49 msg += 8;
50 uevent->path = msg;
51 } else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
52 msg += 10;
53 uevent->subsystem = msg;
54 } else if (!strncmp(msg, "FIRMWARE=", 9)) {
55 msg += 9;
56 uevent->firmware = msg;
57 } else if (!strncmp(msg, "MAJOR=", 6)) {
58 msg += 6;
59 uevent->major = atoi(msg);
60 } else if (!strncmp(msg, "MINOR=", 6)) {
61 msg += 6;
62 uevent->minor = atoi(msg);
63 } else if (!strncmp(msg, "PARTN=", 6)) {
64 msg += 6;
65 uevent->partition_num = atoi(msg);
66 } else if (!strncmp(msg, "PARTNAME=", 9)) {
67 msg += 9;
68 uevent->partition_name = msg;
69 } else if (!strncmp(msg, "DEVNAME=", 8)) {
70 msg += 8;
71 uevent->device_name = msg;
72 } else if (!strncmp(msg, "MODALIAS=", 9)) {
73 msg += 9;
74 uevent->modalias = msg;
75 }
76
77 // advance to after the next \0
78 while (*msg++)
79 ;
80 }
日志的LOG如下:
[ 4.010992] ueventd: Parsing file /ueventd.rc...
[ 4.011884] ueventd: Parsing file /vendor/ueventd.rc...
[ 4.012737] ueventd: /vendor/ueventd.rc: 5: Invalid section keyword found
[ 4.013573] ueventd: Parsing file /odm/ueventd.rc...
[ 4.014157] ueventd: Unable to read config file '/odm/ueventd.rc': open() failed: No such file or directory
[ 4.015320] ueventd: Parsing file /ueventd.ranchu.rc...
[ 4.015675] apexd: Bootstrap subcommand detected
[ 4.015942] ueventd: Unable to read config file '/ueventd.ranchu.rc': open() failed: No such file or directory
[ 4.020488] tom F=kobject_uevent_env subsystem=block
[ 4.020489] tom F=kobject_uevent_env devpath=/devices/pci0000:00/0000:00:04.0/virtio1/block/vdb
[ 4.020974] tom F=kobject_uevent_env envp=SYNTH_UUID=0
[ 4.021778] tom F=kobject_uevent_env env1->envp[0]=ACTION=add
[ 4.022217] tom F=kobject_uevent_env env1->envp[1]=DEVPATH=/devices/pci0000:00/0000:00:04.0/virtio1/block/vdb
[ 4.022764] tom F=kobject_uevent_env env1->envp[2]=SUBSYSTEM=block
[ 4.023604] tom F=kobject_uevent_env env1->envp[3]=SYNTH_UUID=0
[ 4.024107] tom F=kobject_uevent_env env1->envp[4]=MAJOR=253
[ 4.024609] tom F=kobject_uevent_env env1->envp[5]=MINOR=16
[ 4.025077] tom F=kobject_uevent_env env1->envp[6]=DEVNAME=vdb
[ 4.025552] tom F=kobject_uevent_env env1->envp[7]=DEVTYPE=disk
[ 4.026064] tom F=kobject_uevent_env env1->envp[8]=SEQNUM=1105
[ 4.026988] tom F=kobject_uevent_env subsystem=block