android存储系统源码走读

android存储系统源码走读

1、storageManagerservice的启动:

在SystemServer的startOtherServices中,storageManagerservice启动。

private void startOtherServices() {
        final Context context = mSystemContext;
        VibratorService vibrator = null;
        IStorageManager storageManager = null;
        ......(省略N多代码)
        启动storageManagerservice启动服务
        mSystemServiceManager.startService(STORAGE_MANAGER_SERVICE_CLASS);
        ......(省略N多代码)
2、StorageManagerService服务分析

由Lifecycle启动:

public void onStart() {
            mStorageManagerService = new StorageManagerService(getContext());
            publishBinderService("mount", mStorageManagerService);
            mStorageManagerService.start();
        }
public StorageManagerService(Context context) {
        ......忽略部分代码
        //新建handle,多数操作经此流转
        mHandler = new StorageManagerServiceHandler(hthread.getLooper());

        // Add OBB Action Handler to StorageManagerService thread.
        mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());

        // Initialize the last-fstrim tracking if necessary
        File dataDir = Environment.getDataDirectory();
        File systemDir = new File(dataDir, "system");
        mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
        if (!mLastMaintenanceFile.exists()) {
            // Not setting mLastMaintenance here means that we will force an
            // fstrim during reboot following the OTA that installs this code.
            try {
                (new FileOutputStream(mLastMaintenanceFile)).close();
            } catch (IOException e) {
                Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
            }
        } else {
            mLastMaintenance = mLastMaintenanceFile.lastModified();
        }

        mSettingsFile = new AtomicFile(
                new File(Environment.getDataSystemDirectory(), "storage.xml"));

        synchronized (mLock) {
            readSettingsLocked();
        }

        LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal);

        //新建vold与cryptd线程,大部分与存储有关操作都是通过这两个线程与远程socket通信完成,会在连接成功和有消息返回时候回调
        mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
                null);
        mConnector.setDebug(true);
        mConnector.setWarnIfHeld(mLock);
        mConnectorThread = new Thread(mConnector, VOLD_TAG);

        // Reuse parameters from first connector since they are tested and safe
        mCryptConnector = new NativeDaemonConnector(this, "cryptd",
                MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
        mCryptConnector.setDebug(true);
        mCryptConnectorThread = new Thread(mCryptConnector, CRYPTD_TAG);

        final IntentFilter userFilter = new IntentFilter();
        userFilter.addAction(Intent.ACTION_USER_ADDED);
        userFilter.addAction(Intent.ACTION_USER_REMOVED);
        mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);

        synchronized (mLock) {
            addInternalVolumeLocked();
        }

        //添到watchdog监视队列中
        if (WATCHDOG_ENABLE) {
            Watchdog.getInstance().addMonitor(this);
        }
    }

构造函数完成后立即启动vold跟cryptd线程:

private void start() {
        mConnectorThread.start();
        mCryptConnectorThread.start();
    }

NativeDaemonConnector:启动后连接并且监听socket返回信息

@Override
    public void run() {
        mCallbackHandler = new Handler(mLooper, this);

        while (true) {
            try {
                listenToSocket();
            } catch (Exception e) {
                loge("Error in NativeDaemonConnector: " + e);
                SystemClock.sleep(5000);
            }
        }
    }
    
private void listenToSocket() throws IOException {
        LocalSocket socket = null;

        try {
            socket = new LocalSocket();
            LocalSocketAddress address = determineSocketAddress();

            socket.connect(address);

            InputStream inputStream = socket.getInputStream();
            synchronized (mDaemonLock) {
                mOutputStream = socket.getOutputStream();
            }
            //连接上socket之后回调storagemanagerservice
            mCallbacks.onDaemonConnected();

            FileDescriptor[] fdList = null;
            byte[] buffer = new byte[BUFFER_SIZE];
            int start = 0;

            while (true) {
                int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
                if (count < 0) {
                    loge("got " + count + " reading with start = " + start);
                    break;
                }
                fdList = socket.getAncillaryFileDescriptors();

                // Add our starting point to the count and reset the start.
                count += start;
                start = 0;

                for (int i = 0; i < count; i++) {
                    if (buffer[i] == 0) {
                        // Note - do not log this raw message since it may contain
                        // sensitive data
                        final String rawEvent = new String(
                                buffer, start, i - start, StandardCharsets.UTF_8);

                        boolean releaseWl = false;
                        try {
                            final NativeDaemonEvent event =
                                    NativeDaemonEvent.parseRawEvent(rawEvent, fdList);

                            log("RCV <- {" + event + "}");

                            if (event.isClassUnsolicited()) {
                                // TODO: migrate to sending NativeDaemonEvent instances
                                if (mCallbacks.onCheckHoldWakeLock(event.getCode())
                                        && mWakeLock != null) {
                                    mWakeLock.acquire();
                                    releaseWl = true;
                                }
                                Message msg = mCallbackHandler.obtainMessage(
                                        event.getCode(), uptimeMillisInt(), 0, event.getRawEvent());
                                if (mCallbackHandler.sendMessage(msg)) {
                                    releaseWl = false;
                                }
                            } else {
                                mResponseQueue.add(event.getCmdNumber(), event);
                            }
                        } catch (IllegalArgumentException e) {
                            log("Problem parsing message " + e);
                        } finally {
                            if (releaseWl) {
                                mWakeLock.release();
                            }
                        }

                        start = i + 1;
                    }
                }

                if (start == 0) {
                    log("RCV incomplete");
                }

                // We should end at the amount we read. If not, compact then
                // buffer and read again.
                if (start != count) {
                    final int remaining = BUFFER_SIZE - start;
                    System.arraycopy(buffer, start, buffer, 0, remaining);
                    start = remaining;
                } else {
                    start = 0;
                }
            }
        } catch (IOException ex) {
            loge("Communications error: " + ex);
            throw ex;
        } finally {
            synchronized (mDaemonLock) {
                if (mOutputStream != null) {
                    try {
                        loge("closing stream for " + mSocket);
                        mOutputStream.close();
                    } catch (IOException e) {
                        loge("Failed closing output stream: " + e);
                    }
                    mOutputStream = null;
                }
            }

            try {
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException ex) {
                loge("Failed closing socket: " + ex);
            }
        }
    }

与vold跟crypted通信返回的数据格式都是使用的:NativeDaemonEvent,通过将从数据流中获取到的string资源解析成NativeDaemonEvent对象。

private NativeDaemonEvent(int cmdNumber, int code, String message,
                              String rawEvent, String logMessage, FileDescriptor[] fdList) {
        mCmdNumber = cmdNumber;
        mCode = code;
        mMessage = message;
        mRawEvent = rawEvent;
        mLogMessage = logMessage;
        mParsed = null;
        mFdList = fdList;
    }
    
public static NativeDaemonEvent parseRawEvent(String rawEvent, FileDescriptor[] fdList) {
        final String[] parsed = rawEvent.split(" ");
        if (parsed.length < 2) {
            throw new IllegalArgumentException("Insufficient arguments");
        }

        int skiplength = 0;

        final int code;
        try {
            code = Integer.parseInt(parsed[0]);
            skiplength = parsed[0].length() + 1;
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("problem parsing code", e);
        }

        int cmdNumber = -1;
        if (isClassUnsolicited(code) == false) {
            if (parsed.length < 3) {
                throw new IllegalArgumentException("Insufficient arguemnts");
            }
            try {
                cmdNumber = Integer.parseInt(parsed[1]);
                skiplength += parsed[1].length() + 1;
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("problem parsing cmdNumber", e);
            }
        }

        String logMessage = rawEvent;
        if (parsed.length > 2 && parsed[2].equals(SENSITIVE_MARKER)) {
            skiplength += parsed[2].length() + 1;
            logMessage = parsed[0] + " " + parsed[1] + " {}";
        }

        final String message = rawEvent.substring(skiplength);

        return new NativeDaemonEvent(cmdNumber, code, message, rawEvent, logMessage, fdList);
    }

3、unmount流程framework层流程分析:

@Override
    public void unmount(String volId) {
        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
        waitForReady();
        //查找卷信息
        final VolumeInfo vol = findVolumeByIdOrThrow(volId);

        //通知pms卷设备变化信息
        if (vol.isPrimaryPhysical()) {
            final long ident = Binder.clearCallingIdentity();
            try {
                synchronized (mUnmountLock) {
                    mUnmountSignal = new CountDownLatch(1);
                    mPms.updateExternalMediaStatus(false, true);
                    waitForLatch(mUnmountSignal, "mUnmountSignal");
                    mUnmountSignal = null;
                }
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }

        try {
        //连接socket执行unmount命令
            mConnector.execute("volume", "unmount", vol.id);
        } catch (NativeDaemonConnectorException e) {
            throw e.rethrowAsParcelableException();
        }
    }
    
    public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args)
            throws NativeDaemonConnectorException {
        if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
            Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
                    + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
        }

        final long startTime = SystemClock.elapsedRealtime();

        final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();

        final StringBuilder rawBuilder = new StringBuilder();
        final StringBuilder logBuilder = new StringBuilder();
        final int sequenceNumber = mSequenceNumber.incrementAndGet();

        makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args);

        final String rawCmd = rawBuilder.toString();
        final String logCmd = logBuilder.toString();

        log("SND -> {" + logCmd + "}");

        synchronized (mDaemonLock) {
            if (mOutputStream == null) {
                throw new NativeDaemonConnectorException("missing output stream");
            } else {
                try {
                    //将命令写入到socket流中 mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));
                } catch (IOException e) {
                    throw new NativeDaemonConnectorException("problem sending command", e);
                }
            }
        }
        ......

流程如图:
unmount流程图

4、底层实现:

底层实现主要涉及四大类:
VolumeManager
CommandListener
CryptCommandListener
NetlinkManager首先分析commandListener:
main.cpp

int main(int argc, char** argv) {
    ......省略部分代码
    VolumeManager *vm;
    CommandListener *cl;
    CryptCommandListener *ccl;
    NetlinkManager *nm;
    //初始化
    cl = new CommandListener();
    //启动监听
    if (cl->startListener()) {
        PLOG(ERROR) << "Unable to start CommandListener";
        exit(1);
    }

    ......
}

CommandListener.cpp
在初始化过程中将部分命令添加到mCommands命令列表中,同时调用父类初始化方法,出入参数:vold,也就是即将要连接的socket名称:

CommandListener::CommandListener() :
                 FrameworkListener("vold", true) {
    registerCmd(new DumpCmd());
    registerCmd(new VolumeCmd());
    registerCmd(new AsecCmd());
    registerCmd(new ObbCmd());
    registerCmd(new StorageCmd());
    registerCmd(new FstrimCmd());
    registerCmd(new AppFuseCmd());
}


FrameworkCommandCollection *mCommands;
void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
    mCommands->push_back(cmd);
}

启动监听,在SocketListener中:

int SocketListener::startListener(int backlog) {
    此处mSocketName已经设置为了vold
    if (!mSocketName && mSock == -1) {
        SLOGE("Failed to start unbound listener");
        errno = EINVAL;
        return -1;
    } else if (mSocketName) {
        if ((mSock = android_get_control_socket(mSocketName)) < 0) {
            SLOGE("Obtaining file descriptor socket '%s' failed: %s",
                 mSocketName, strerror(errno));
            return -1;
        }
        SLOGV("got mSock = %d for %s", mSock, mSocketName);
        fcntl(mSock, F_SETFD, FD_CLOEXEC);
    }

    if (mListen && listen(mSock, backlog) < 0) {
        SLOGE("Unable to listen on socket (%s)", strerror(errno));
        return -1;
    } else if (!mListen)
        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));

    if (pipe(mCtrlPipe)) {
        SLOGE("pipe failed (%s)", strerror(errno));
        return -1;
    }
    //启动监听线程
    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
        SLOGE("pthread_create (%s)", strerror(errno));
        return -1;
    }

    return 0;
}

void *SocketListener::threadStart(void *obj) {
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);

    me->runListener();
    pthread_exit(NULL);
    return NULL;
}

void SocketListener::runListener() {

    SocketClientCollection pendingList;

    while(1) {
        
        ......      
        /* Process the pending list, since it is owned by the thread,
         * there is no need to lock it */
        while (!pendingList.empty()) {
            /* Pop the first item from the list */
            it = pendingList.begin();
            SocketClient* c = *it;
            pendingList.erase(it);
            /* Process it, if false is returned, remove from list */
            if (!onDataAvailable(c)) {
                release(c, false);
            }
            c->decRef();
        }
    }
}

FrameworkListener具体执行从socket中接收到的数据

bool FrameworkListener::onDataAvailable(SocketClient *c) {
    ......
    for (i = 0; i < len; i++) {
        if (buffer[i] == '\0') {
            /* IMPORTANT: dispatchCommand() expects a zero-terminated string */
            if (mSkipToNextNullByte) {
                mSkipToNextNullByte = false;
            } else {
                dispatchCommand(c, buffer + offset);
            }
            offset = i + 1;
        }
    }

    mSkipToNextNullByte = false;
    return true;
}

void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
    FrameworkCommandCollection::iterator i;
    ......
    //mCommands是在commandListener初始化时候添加的一个命令列表,此处将列表中数据取出与命令对比,通过对比结果看使用哪个具体实现来实现socket发送过来的命令。
    for (i = mCommands->begin(); i != mCommands->end(); ++i) {
        FrameworkCommand *c = *i;

        if (!strcmp(argv[0], c->getCommand())) {
        //具体实现命令在runcommand
            if (c->runCommand(cli, argc, argv)) {
                SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
            }
            goto out;
        }
    }
    cli->sendMsg(500, "Command not recognized", false);
out:
    int j;
    for (j = 0; j < argc; j++)
        free(argv[j]);
    return;

overflow:
    cli->sendMsg(500, "Command too long", false);
    goto out;
}

VolumeCmd为例:

CommandListener::VolumeCmd::VolumeCmd() :
                 VoldCommand("volume") {
}

VoldCommand::VoldCommand(const char *cmd) :
              FrameworkCommand(cmd)  {
}

FrameworkCommand::FrameworkCommand(const char *cmd) {
    mCommand = cmd;
}

FrameworkCommand声明如下:
class FrameworkCommand { 
private:
    const char *mCommand;

public:

    FrameworkCommand(const char *cmd);
    virtual ~FrameworkCommand() { }

    virtual int runCommand(SocketClient *c, int argc, char **argv) = 0;

    const char *getCommand() { return mCommand; }
};

如果从socket中获取到的字符是是以volume开头,则会调用VolumeCmd中的runCommand方法,至此CommandListener主要通信流程分析结束。

NetlinkManager分析

int main(int argc, char** argv) {
    ......
    NetlinkManager *nm;
    ......
    if (!(nm = NetlinkManager::Instance())) {
        LOG(ERROR) << "Unable to create NetlinkManager";
        exit(1);
    }
    ......
    nm->setBroadcaster((SocketListener *) cl);
    ......
    //
    if (nm->start()) {
        PLOG(ERROR) << "Unable to start NetlinkManager";
        exit(1);
    }
}


int NetlinkManager::start() {
    struct sockaddr_nl nladdr;
    int sz = 64 * 1024;
    int on = 1;

    memset(&nladdr, 0, sizeof(nladdr));
    nladdr.nl_family = AF_NETLINK;
    nladdr.nl_pid = getpid();
    nladdr.nl_groups = 0xffffffff;

    if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
            NETLINK_KOBJECT_UEVENT)) < 0) {
        SLOGE("Unable to create uevent socket: %s", strerror(errno));
        return -1;
    }
    //设置socket运行环境
    // When running in a net/user namespace, SO_RCVBUFFORCE is not available.
    // Try using SO_RCVBUF first.
    if ((setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0) &&
        (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0)) {
        SLOGE("Unable to set uevent socket SO_RCVBUF/SO_RCVBUFFORCE option: %s", strerror(errno));
        goto out;
    }

    if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
        SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
        goto out;
    }
    //绑定socket
    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
        SLOGE("Unable to bind uevent socket: %s", strerror(errno));
        goto out;
    }
    //启动监听handler流程
    mHandler = new NetlinkHandler(mSock);
    if (mHandler->start()) {
        SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
        goto out;
    }

    return 0;

out:
    close(mSock);
    return -1;
}

NetlinkHandler的初始化和start:

NetlinkHandler::NetlinkHandler(int listenerSocket) :
                NetlinkListener(listenerSocket) {
}

NetlinkListener::NetlinkListener(int socket) :
                            SocketListener(socket, false) {
    mFormat = NETLINK_FORMAT_ASCII;
}

至此将socket描述符传递给了SocketListener

int NetlinkHandler::start() {
    return this->startListener();
}

int SocketListener::startListener(int backlog) {

    if (!mSocketName && mSock == -1) {
        SLOGE("Failed to start unbound listener");
        errno = EINVAL;
        return -1;
    } else if (mSocketName) {
        if ((mSock = android_get_control_socket(mSocketName)) < 0) {
            SLOGE("Obtaining file descriptor socket '%s' failed: %s",
                 mSocketName, strerror(errno));
            return -1;
        }
        SLOGV("got mSock = %d for %s", mSock, mSocketName);
        fcntl(mSock, F_SETFD, FD_CLOEXEC);
    }

    if (mListen && listen(mSock, backlog) < 0) {
        SLOGE("Unable to listen on socket (%s)", strerror(errno));
        return -1;
    } else if (!mListen)
        mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));

    if (pipe(mCtrlPipe)) {
        SLOGE("pipe failed (%s)", strerror(errno));
        return -1;
    }

    if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
        SLOGE("pthread_create (%s)", strerror(errno));
        return -1;
    }

    return 0;
}

void *SocketListener::threadStart(void *obj) {
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);

    me->runListener();
    pthread_exit(NULL);
    return NULL;
}

SocketListener之后的运行过程与CommandLister一致,最终进入到子类的onDataAvailable中:

bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
    int socket = cli->getSocket();
    ssize_t count;
    uid_t uid = -1;

    bool require_group = true;
    if (mFormat == NETLINK_FORMAT_BINARY_UNICAST) {
        require_group = false;
    }

    count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket,
            mBuffer, sizeof(mBuffer), require_group, &uid));
    if (count < 0) {
        SLOGE("recvmsg failed (%s)", strerror(errno));
        return false;
    }

    NetlinkEvent *evt = new NetlinkEvent();
    if (evt->decode(mBuffer, count, mFormat)) {
        onEvent(evt);
    } else if (mFormat != NETLINK_FORMAT_BINARY) {
        // Don't complain if parseBinaryNetlinkMessage returns false. That can
        // just mean that the buffer contained no messages we're interested in.
        SLOGE("Error decoding NetlinkEvent");
    }

    delete evt;
    return true;
}

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);
    }
}



由此NetlinkManager通过连接socket来接收来自kernel层的sd插拔消息,收到消息后通过VolumeManager来更新当前的disk信息

VolumeManager真正负责处理存储相关消息,执行mount、unmount之类的命令,更新disk信息等。

猜你喜欢

转载自blog.csdn.net/thh159/article/details/88289549