Android 저장 장치 관리 - Vold 처리 커 널 메시지

13232 단어 androidvold
다음으로 이동:http://blog.csdn.net/new_abc/article/details/7409018
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 메시지 등 입 니 다.여기 소개 안 할 게 요.

좋은 웹페이지 즐겨찾기