深入MountService、vold(五) MountService中通信(NativeDaemonConnector)(and5.1)

来源:互联网 发布:锐捷mac客户端最新 编辑:程序博客网 时间:2024/05/19 10:36

整个MountService和vold是使用NativeDaemonConnector,今天分析下:

在MountService的构造函数中有如下:


        mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,                null);//新建NativeDaemonConnector        Thread thread = new Thread(mConnector, VOLD_TAG);        thread.start();

看看NativeDaemonConnector的构造函数,MountService 是callbacks回调,"vold"是socket的名字

    NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,            int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) {        this(callbacks, socket, responseQueueSize, logTag, maxLogSize, wl,                FgThread.get().getLooper());    }    NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,            int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl,            Looper looper) {        mCallbacks = callbacks;        mSocket = socket;        mResponseQueue = new ResponseQueue(responseQueueSize);        mWakeLock = wl;        if (mWakeLock != null) {            mWakeLock.setReferenceCounted(true);        }        mLooper = looper;        mSequenceNumber = new AtomicInteger(0);        TAG = logTag != null ? logTag : "NativeDaemonConnector";        mLocalLog = new LocalLog(maxLogSize);    }

又因为NativeDaemonConnector 继承Runnable,所以在MountService中开启一个线程,会执行NativeDaemonConnector 的run函数

final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor {

NativeDaemonConnector 的run函数

    public void run() {        mCallbackHandler = new Handler(mLooper, this);        while (true) {            try {                listenToSocket();            } catch (Exception e) {                loge("Error in NativeDaemonConnector: " + e);                SystemClock.sleep(5000);            }        }    }

再来看看listenToSocket函数

    private void listenToSocket() throws IOException {        LocalSocket socket = null;        try {            socket = new LocalSocket();// 用localsocket的            LocalSocketAddress address = determineSocketAddress();            socket.connect(address);            InputStream inputStream = socket.getInputStream();            synchronized (mDaemonLock) {                mOutputStream = socket.getOutputStream();            }            mCallbacks.onDaemonConnected();            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;                }                // 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(//解析成NativeDaemonEvent                                     rawEvent);                            log("RCV <- {" + event + "}");                            if (event.isClassUnsolicited()) {根据返回的code,这是600-700                                // TODO: migrate to sending NativeDaemonEvent instances                                if (mCallbacks.onCheckHoldWakeLock(event.getCode())                                        && mWakeLock != null) {                                    mWakeLock.acquire();                                    releaseWl = true;                                }                                if (mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage(//发消息,这个消息最后会调到MountService的OnEvent                                        event.getCode(), event.getRawEvent()))) {                                    releaseWl = false;                                }                            } else {//另外一种是将event加到mResponseQueue,这是是MountService主动发起和vold的通信,等待结果的                                mResponseQueue.add(event.getCmdNumber(), event);                            }                        } catch (IllegalArgumentException e) {                            log("Problem parsing message " + e);                        } finally {                            if (releaseWl) {                                mWakeLock.acquire();                            }                        }                        start = i + 1;                    }                }。。。。。。。。。。。。。    }

先看消息,直接是调用了mCallbacks.onEvent,前面看了mCallBacks是MountService,所以这就调了MountService的OnEvent

    @Override    public boolean handleMessage(Message msg) {        String event = (String) msg.obj;        try {            if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) {                log(String.format("Unhandled event '%s'", event));            }        } catch (Exception e) {            loge("Error handling '" + event + "': " + e);        } finally {            if (mCallbacks.onCheckHoldWakeLock(msg.what) && mWakeLock != null) {                mWakeLock.release();            }        }        return true;    }

而mResponseQueue.add如下

        public void add(int cmdNum, NativeDaemonEvent response) {            PendingCmd found = null;            synchronized (mPendingCmds) {                for (PendingCmd pendingCmd : mPendingCmds) {                    if (pendingCmd.cmdNum == cmdNum) {                        found = pendingCmd;                        break;                    }                }                if (found == null) {                    // didn't find it - make sure our queue isn't too big before adding                    while (mPendingCmds.size() >= mMaxCount) {                        Slog.e("NativeDaemonConnector.ResponseQueue",                                "more buffered than allowed: " + mPendingCmds.size() +                                " >= " + mMaxCount);                        // let any waiter timeout waiting for this                        PendingCmd pendingCmd = mPendingCmds.remove();                        Slog.e("NativeDaemonConnector.ResponseQueue",                                "Removing request: " + pendingCmd.logCmd + " (" +                                pendingCmd.cmdNum + ")");                    }                    found = new PendingCmd(cmdNum, null);                    mPendingCmds.add(found);                }                found.availableResponseCount++;                // if a matching remove call has already retrieved this we can remove this                // instance from our list                if (found.availableResponseCount == 0) mPendingCmds.remove(found);            }            try {                found.responses.put(response);//将NativeDaemonEvent 放到对应的PendingCmd的responses中,            } catch (InterruptedException e) { }        }

这里的response是BlockingQueue<NativeDaemonEvent>,这是是FIFO一样的数据结果,取值的时候没有数据的话会阻塞。


而当MountService主动发起的通信会调execute函数

   public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args)            throws NativeDaemonConnectorException {        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 {                    mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8));//往vold写                } catch (IOException e) {                    throw new NativeDaemonConnectorException("problem sending command", e);                }            }        }        NativeDaemonEvent event = null;        do {            event = mResponseQueue.remove(sequenceNumber, timeout, logCmd);            if (event == null) {                loge("timed-out waiting for response to " + logCmd);                throw new NativeDaemonFailureException(logCmd, event);//抛出异常结束            }            if (VDBG) log("RMV <- {" + event + "}");            events.add(event);        } while (event.isClassContinue());//这里是一个死循环,而且根据vold的返回值是否已经结束。。。。。。
NativeDaemonEvent 的remove函数就从对应的pendingcmd中responses中取NativeDaemonEvent ,只是用了poll这个接口,可以用timeout
        public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String logCmd) {            PendingCmd found = null;            synchronized (mPendingCmds) {                for (PendingCmd pendingCmd : mPendingCmds) {                    if (pendingCmd.cmdNum == cmdNum) {                        found = pendingCmd;                        break;                    }                }                if (found == null) {                    found = new PendingCmd(cmdNum, logCmd);                    mPendingCmds.add(found);                }                found.availableResponseCount--;                // if a matching add call has already retrieved this we can remove this                // instance from our list                if (found.availableResponseCount == 0) mPendingCmds.remove(found);            }            NativeDaemonEvent result = null;            try {                result = found.responses.poll(timeoutMs, TimeUnit.MILLISECONDS);            } catch (InterruptedException e) {}            if (result == null) {                Slog.e("NativeDaemonConnector.ResponseQueue", "Timeout waiting for response");            }            return result;        }

这样上面的MountService分析完了,而vold和上面的通信在SocketListener中,是起了一个Thread,然后用IO复用select实现,因此当vold执行到每个耗时操作卡住了,上层再往底层发,也会卡住,因为这个时候一个select还没执行完呢!



1 0
原创粉丝点击