深入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
- 深入MountService、vold(五) MountService中通信(NativeDaemonConnector)(and5.1)
- 深入解析vold、MountService(二)(and5.1)
- 深入解析MountService、vold(三)--fuse_sdcard1(and5.1)
- 深入Mountservice vold(六) handleDiskRemoved handlePartitionRemoved(and5.1)
- 深入MountService、vold(四) 大容量存储和MountService的消息机制(and5.1)
- 深入分析vold、MountService(and5.1)
- Android6.0 MountService和vold详解(一)Mountservice的初始化
- android(ics)vold,mountservice
- vold/mountservice框架
- Android6.0 MountService和vold详解(二) vold的emulatedvolume
- Android6.0 MountService和vold详解(三) vold SD卡、otg
- Android vold进程三 MountService介绍
- Android的存储系统—Vold与MountService分析
- android6.0 sm进程(获取MountService信息)
- MountService初探
- MountService整理
- Android7.0 Vold 进程工作机制分析之由MountService发起挂载请求
- and5.1PowerManagerService深入分析(二)PowerManager中各函数
- hdu5371Hotaru's problem
- 关于树莓派的一些事
- 侧滑删除进阶(三)
- Extjs中的success和failure
- 由于csdn网站太,所以以后开始写笔记了。
- 深入MountService、vold(五) MountService中通信(NativeDaemonConnector)(and5.1)
- [leetcode]Binary Tree Maximum Path Sum
- Android Binder设计原理
- Java中string 创建对象时 “”和null的区别
- VB.NET通过PID(ProcessID)获得某进程的CPU使用率
- 逻辑层对策略模式的使用
- AC自动机步骤详解
- Windows上安装配置RabbitMQ快速指南
- leetcode 130 —— Sum Root to Leaf Numbers