Android 저장 장치 관리 - Vold 처리 커 널 메시지
MountService 가 시 작 된 후에 모든 준비 작업 이 다 되 었 고 u 디스크 에 부 딪 혀 꽂 히 기 를 기 다 렸 습 니 다. 우 리 는 먼저 커 널, vold, Frame Work 의 통신 절 차 를 살 펴 보 겠 습 니 다.
여기 서 말 하고 자 하 는 것 은 커 널 이 vold 에 메 시 지 를 보 내 는 것 이다. 즉, 위 에 표 시 된 ①, 우 리 는... vold 는 커 널 에 등 록 된 UEvent 사건 을 시작 한 적 이 있 습 니 다. u 디스크 가 삽입 되 었 을 때 우 리 는 이 소켓 에서 커 널 에서 보 낸 메 시 지 를 받 을 수 있 습 니 다. 그러면 vold 의 메시지 처 리 를 시작 합 니 다.
먼저 메시지 처리 절 차 를 보십시오.
SocketListener:: runListener () 함수 에서 저 희 는 select 에서 특정한 연결 이 오 거나 이미 연결 되 어 있 는 소켓 의 데이터 가 오 기 를 기다 리 고 있 습 니 다. 코드 를 보 세 요.
if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
SLOGE("select failed (%s)", strerror(errno));
sleep(1);
continue;
} else if (!rc)
continue;
if (FD_ISSET(mCtrlPipe[0], &read_fds))
break;
if (mListen && FD_ISSET(mSock, &read_fds)) {
struct sockaddr addr;
socklen_t alen = sizeof(addr);
int c;
if ((c = accept(mSock, &addr, &alen)) < 0) {
SLOGE("accept failed (%s)", strerror(errno));
sleep(1);
continue;
}
pthread_mutex_lock(&mClientsLock);
mClients->push_back(new SocketClient(c));
pthread_mutex_unlock(&mClientsLock);
}
do {
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it != mClients->end(); ++it) {
int fd = (*it)->getSocket();
if (FD_ISSET(fd, &read_fds)) {
pthread_mutex_unlock(&mClientsLock);
if (!onDataAvailable(*it)) {
close(fd);
pthread_mutex_lock(&mClientsLock);
delete *it;
it = mClients->erase(it);
pthread_mutex_unlock(&mClientsLock);
}
FD_CLR(fd, &read_fds);
pthread_mutex_lock(&mClientsLock);
continue;
}
}
pthread_mutex_unlock(&mClientsLock);
} while (0);
}
어떤 소켓 에 데이터 가 왔 을 때 먼저 이 소켓 이 listen 의 소켓 인지 확인 하 십시오. 만약 에 연결 을 받 고 mClient 링크 에 추가 하지 않 으 면 특정한 소켓 에 데이터 가 왔 다 는 것 을 설명 합 니 다. 이때 우리 가 커 널 에 등 록 된 소켓 입 니 다. 호출 합 니 다.onDataAvailable 함수 입 니 다. 여기 서 다 중 호출 된 것 은 NetlinkListener:: onDataAvailable 의 이 함수 입 니 다.
bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
int socket = cli->getSocket();
int count;
if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) {
SLOGE("recv failed (%s)", strerror(errno));
return false;
}
NetlinkEvent *evt = new NetlinkEvent();
if (!evt->decode(mBuffer, count)) {
SLOGE("Error decoding NetlinkEvent");
goto out;
}
onEvent(evt);
out:
delete evt;
return true;
}
recv 수신 데 이 터 를 호출 하고 new NetlinkEvent 에 이 어 decode 함수 로 받 은 데 이 터 를 분석 합 니 다.
bool NetlinkEvent::decode(char *buffer, int size) {
char *s = buffer;
char *end;
int param_idx = 0;
int i;
int first = 1;
end = s + size;
while (s < end) {
if (first) {
char *p;
for (p = s; *p != '@'; p++);
p++;
mPath = strdup(p);
first = 0;
} else {
if (!strncmp(s, "ACTION=", strlen("ACTION="))) {
char *a = s + strlen("ACTION=");
if (!strcmp(a, "add"))
mAction = NlActionAdd;
else if (!strcmp(a, "remove"))
mAction = NlActionRemove;
else if (!strcmp(a, "change"))
mAction = NlActionChange;
} else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM=")))
mSeq = atoi(s + strlen("SEQNUM="));
else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM=")))
mSubsystem = strdup(s + strlen("SUBSYSTEM="));
else
mParams[param_idx++] = strdup(s);
}
s+= strlen(s) + 1;
}
return true;
}
여기 서 메 시 지 를 분석 하고 ACTION, DEVPATH, SUBSYSTEM 등 을 분석 합 니 다. 다음은 제 가 잡 은 u 판 삽입 잡 은 log 를 보 겠 습 니 다.D/NetlinkEvent( 946): s = add@/devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/host1/target1:0:0/1:0:0:0/block/sda
D/NetlinkEvent( 946): s = ACTION=add
D/NetlinkEvent( 946): s = DEVPATH=/devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/host1/target1:0:0/1:0:0:0/block/sda
D/NetlinkEvent( 946): s = SUBSYSTEM=block
D/NetlinkEvent( 946): s = MAJOR=8
D/NetlinkEvent( 946): s = MINOR=0
D/NetlinkEvent( 946): s = DEVNAME=sda
D/NetlinkEvent( 946): s = DEVTYPE=disk
D/NetlinkEvent( 946): s = NPARTS=1
D/NetlinkEvent( 946): s = SEQNUM=1058
D/NetlinkEvent( 1206): s = DEVPATH=/devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/host1/target1:0:0/1:0:0:0/block/sda/sda1
D/NetlinkEvent( 1206): s = SUBSYSTEM=block
D/NetlinkEvent( 1206): s = MAJOR=8
D/NetlinkEvent( 1206): s = MINOR=1
D/NetlinkEvent( 1206): s = DEVNAME=sda1
D/NetlinkEvent( 1206): s = DEVTYPE=partition
D/NetlinkEvent( 1206): s = PARTN=1
D/NetlinkEvent( 1206): s = SEQNUM=1059
이 u 판 은 한 개의 구역 만 있 고 아래 는 두 개의 구역 이 있 는 log (일부분) 입 니 다.D/NetlinkEvent( 1207): s = ACTION=add
D/NetlinkEvent( 1207): s = DEVPATH=/devices/platform/hiusb-ehci.0/usb1/1-2/1-2.2/1-2.2:1.0/host2/target2:0:0/2:0:0:0/block/sdb
D/NetlinkEvent( 1207): s = SUBSYSTEM=block
D/NetlinkEvent( 1207): s = MAJOR=8
D/NetlinkEvent( 1207): s = MINOR=16
D/NetlinkEvent( 1207): s = DEVNAME=sdb
D/NetlinkEvent( 1207): s = DEVTYPE=disk
D/NetlinkEvent( 1207): s = NPARTS=2
D/NetlinkEvent( 1207): s = SEQNUM=1086
커 널 에서 받 은 소식 에서 우 리 는 많은 정 보 를 얻 을 수 있다.분석 이 끝나 면 onEvent 함 수 를 호출 하여 메 시 지 를 처리 합 니 다. 여 기 는 NetlinkHandler 의 onEvent 함 수 를 호출 합 니 다.
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm = VolumeManager::Instance();
const char *subsys = evt->getSubsystem();
if (!subsys) {
SLOGW("No subsystem found in netlink event");
return;
}
if (!strcmp(subsys, "block")) {
vm->handleBlockEvent(evt);
} else if (!strcmp(subsys, "switch")) {
vm->handleSwitchEvent(evt);
} else if (!strcmp(subsys, "usb_composite")) {
vm->handleUsbCompositeEvent(evt);
} else if (!strcmp(subsys, "battery")) {
} else if (!strcmp(subsys, "power_supply")) {
}
}
위의 log 에서 알 수 있 듯 이 subsys 는 block 이 므 로 호출 합 니 다.handleBlockEvent 함수
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
const char *devpath = evt->findParam("DEVPATH");
/* Lookup a volume to handle this device */
VolumeCollection::iterator it;
bool hit = false;
for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
if (!(*it)->handleBlockEvent(evt)) {
#ifdef NETLINK_DEBUG
SLOGD("Device '%s' event handled by volume %s
", devpath, (*it)->getLabel());
#endif
hit = true;
break;
}
}
if (!hit) {
#ifdef NETLINK_DEBUG
SLOGW("No volumes handled block event for '%s'", devpath);
#endif
}
}
mVolumes 에서 초기 화 할 때 DirectVolume 을 추가 하 였 습 니 다. 그래서 여기 서 DirectVolume: handle BlockEvent 를 호출 합 니 다.
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
const char *dp = evt->findParam("DEVPATH");
PathCollection::iterator it;
for (it = mPaths->begin(); it != mPaths->end(); ++it) {
if (!strncmp(dp, *it, strlen(*it))) {
/* We can handle this disk */
int action = evt->getAction();
const char *devtype = evt->findParam("DEVTYPE");
if (action == NetlinkEvent::NlActionAdd) {
int major = atoi(evt->findParam("MAJOR"));
int minor = atoi(evt->findParam("MINOR"));
char nodepath[255];
snprintf(nodepath,
sizeof(nodepath), "/dev/block/vold/%d:%d",
major, minor);
if (createDeviceNode(nodepath, major, minor)) {
SLOGE("Error making device node '%s' (%s)", nodepath,
strerror(errno));
}
if (!strcmp(devtype, "disk")) {
handleDiskAdded(dp, evt);
} else {
handlePartitionAdded(dp, evt);
}
} else if (action == NetlinkEvent::NlActionRemove) {
if (!strcmp(devtype, "disk")) {
handleDiskRemoved(dp, evt);
} else {
handlePartitionRemoved(dp, evt);
}
} else if (action == NetlinkEvent::NlActionChange) {
if (!strcmp(devtype, "disk")) {
handleDiskChanged(dp, evt);
} else {
handlePartitionChanged(dp, evt);
}
} else {
SLOGW("Ignoring non add/remove/change event");
}
return 0;
}
}
errno = ENODEV;
return -1;
}
mPaths 는 parse vold. fstab 에서 해당 하 는 해석 경 로 를 추가 하 였 습 니 다. 이 스 크 립 트 를 보 겠 습 니 다.dev_mount sdcard /mnt/sdcard auto /devices/platform/hiusb-ehci.0 /devices/platform/hi_godbox-ehci.0
이 add 의 경 로 는 위의 log 에서 나 온 경로 와 일치 합 니 다. 먼저 실행 되 는 handle Disk 추가, 즉 / block / sda 라 는 메 시 지 를 받 았 을 때 디스크 삽입 을 알 립 니 다.
void DirectVolume::handleDiskAdded(const char *devpath, NetlinkEvent *evt) {
mDiskMajor = atoi(evt->findParam("MAJOR"));
mDiskMinor = atoi(evt->findParam("MINOR"));
const char *tmp = evt->findParam("NPARTS");
if (tmp) {
mDiskNumParts = atoi(tmp);
} else {
SLOGW("Kernel block uevent missing 'NPARTS'");
mDiskNumParts = 1;
}
char msg[255];
int partmask = 0;
int i;
for (i = 1; i <= mDiskNumParts; i++) {
partmask |= (1 << i);
}
mPendingPartMap = partmask;
if (mDiskNumParts == 0) {
#ifdef PARTITION_DEBUG
SLOGD("Dv::diskIns - No partitions - good to go son!");
#endif
setState(Volume::State_Idle);
} else {
#ifdef PARTITION_DEBUG
SLOGD("Dv::diskIns - waiting for %d partitions (mask 0x%x)",
mDiskNumParts, mPendingPartMap);
#endif
setState(Volume::State_Pending);
}
snprintf(msg, sizeof(msg), "Volume %s %s disk inserted (%d:%d)",
getLabel(), getMountpoint(), mDiskMajor, mDiskMinor);
mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskInserted,
msg, false);
}
mDiskNumParts 0 이 아 닌 Volume 의 상 태 를 State 로 설정Pending 은 FrameWork 층 에 VolumeDiskInserted 메 시 지 를 방송 하고 setState 함수 에서 도 VolumeState Change 메 시 지 를 상부 에 방송 합 니 다.
다음은 handle Partition Added 입 니 다. add / block / sda / sda * 와 같은 메 시 지 를 처리 합 니 다.
void DirectVolume::handlePartitionAdded(const char *devpath, NetlinkEvent *evt) {
int major = atoi(evt->findParam("MAJOR"));
int minor = atoi(evt->findParam("MINOR"));
int part_num;
const char *tmp = evt->findParam("PARTN");
if (tmp) {
part_num = atoi(tmp);
} else {
SLOGW("Kernel block uevent missing 'PARTN'");
part_num = 1;
}
if (part_num > mDiskNumParts) {
mDiskNumParts = part_num;
}
if (major != mDiskMajor) {
SLOGE("Partition '%s' has a different major than its disk!", devpath);
return;
}
#ifdef PARTITION_DEBUG
SLOGD("Dv:partAdd: part_num = %d, minor = %d
", part_num, minor);
#endif
mPartMinors[part_num -1] = minor;
mPendingPartMap &= ~(1 << part_num);
if (!mPendingPartMap) {
#ifdef PARTITION_DEBUG
SLOGD("Dv:partAdd: Got all partitions - ready to rock!");
#endif
if (getState() != Volume::State_Formatting) {
setState(Volume::State_Idle);
}
} else {
#ifdef PARTITION_DEBUG
SLOGD("Dv:partAdd: pending mask now = 0x%x", mPendingPartMap);
#endif
}
}
mPendingPartMap 이 0 으로 줄 었 을 때 Volume 의 상 태 는 State 가 아 닙 니 다.Formatting, VolumeState Change 메 시 지 를 방송 합 니 다.
여기까지 커 널 의 소식 은 기본적으로 처리 되 었 습 니 다. 물론 여기 서 말 하 는 것 은 add 의 소식, 그리고 reove, change 메시지 등 입 니 다.여기 소개 안 할 게 요.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.