Android—— 4.2 Vold挂载管理_MountService (六)
整个Vold机制应该算system层,与framwork层的交互在Android—— 4.2 Vold挂载管理_CommandListener (二)中有提到过,是通过一个"vold"的socket进行通信的,这里分析一下framework中负责与Vold通信的:MountService
撰写不易,转载请注明出处:http://blog.csdn.net/jscese/article/details/38978387
一.MountService启动:
在/frameworks/base/services/java/com/android/server/SystemServer.java中有:
if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) { try { /* * NotificationManagerService is dependant on MountService, * (for media / usb notifications) so we must start MountService first. */ Slog.i(TAG, "Mount Service"); mountService = new MountService(context); ServiceManager.addService("mount", mountService); } catch (Throwable e) { reportWtf("starting Mount Service", e); } }
开机启动的系统服务之一,关于系统初始启动详情可参考:Android——启动过程详析
public MountService(Context context) { mContext = context; synchronized (mVolumesLock) { readStorageListLocked(); // 解析/frameworks/base/core/res/res/xml/storage_list.xml保存volume到 MountService的list :mVolumes中 } // XXX: This will go away soon in favor of IMountServiceObserver mPms = (PackageManagerService) ServiceManager.getService("package"); mHandlerThread = new HandlerThread("MountService"); mHandlerThread.start(); mHandler = new MountServiceHandler(mHandlerThread.getLooper());//新建消息处理handler // Watch for user changes final IntentFilter userFilter = new IntentFilter(); userFilter.addAction(Intent.ACTION_USER_ADDED); userFilter.addAction(Intent.ACTION_USER_REMOVED); mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);//注册广播接收 // Watch for USB changes on primary volume final StorageVolume primary = getPrimaryPhysicalVolume(); if (primary != null && primary.allowMassStorage()) { mContext.registerReceiver( mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler); } // Add OBB Action Handler to MountService thread. mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper()); /* * Create the connection to vold with a maximum queue of twice the * amount of containers we'd ever expect to have. This keeps an * "asec list" from blocking a thread repeatedly. */ mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);//创建 vold 的监听接收,用于接收system中Vold的socket消息 Thread thread = new Thread(mConnector, VOLD_TAG); thread.start();//启动线程,NativeDaemonConnector实现了Runnable接口,实现在 run中 // Add ourself to the Watchdog monitors if enabled. if (WATCHDOG_ENABLE) { Watchdog.getInstance().addMonitor(this); } }
二.MountService接收Socket:
上面有看到构造了NativeDaemonConnector用来接收来自下层的socket消息,先看构造:
NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, int responseQueueSize, String logTag, int maxLogSize) { mCallbacks = callbacks; //回调 mSocket = socket; // socket名称 mResponseQueue = new ResponseQueue(responseQueueSize);//构建一个响应队列 mSequenceNumber = new AtomicInteger(0); TAG = logTag != null ? logTag : "NativeDaemonConnector"; mLocalLog = new LocalLog(maxLogSize); }
在上面开启监测线程的run方法:
public void run() { HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler"); //TAG 为 VoldConnector,这里新建一个名为VoldConnector.CallbackHandler的消息处理线程,用于下面接收到vold 的socket之后的处理 thread.start(); mCallbackHandler = new Handler(thread.getLooper(), this); //创建handler 用于分发消息 while (true) { try { listenToSocket();// while 循环 监听socket } catch (Exception e) { loge("Error in NativeDaemonConnector: " + e); SystemClock.sleep(5000); } } }
往里看listenToSocket:
private void listenToSocket() throws IOException { LocalSocket socket = null; try { socket = new LocalSocket(); //创建本地socket LocalSocketAddress address = new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED);//获得服务端vold socket的地址 socket.connect(address);//连接 InputStream inputStream = socket.getInputStream(); synchronized (mDaemonLock) { mOutputStream = socket.getOutputStream(); }//获取输入输出流 mCallbacks.onDaemonConnected();//回调,在MountService中执行,初始化一些Volume状态信息 byte[] buffer = new byte[BUFFER_SIZE]; int start = 0; while (true) { int count = inputStream.read(buffer, start, BUFFER_SIZE - start);//读取数据到buffer if (count < 0) {//连接断开,跳出当前while ,外部while循环 重新调用该函数连接 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) { final String rawEvent = new String( buffer, start, i - start, Charsets.UTF_8); log("RCV <- {" + rawEvent + "}"); try { final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent( rawEvent); //解析成event 保存 if (event.isClassUnsolicited()) { //判断event的code范围 code >= 600 && code < 700 // TODO: migrate to sending NativeDaemonEvent instances mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( //发送消息,把event交给handle来分发处理 event.getCode(), event.getRawEvent())); } else { mResponseQueue.add(event.getCmdNumber(), event);//加入到响应队列 } } catch (IllegalArgumentException e) { log("Problem parsing message: " + rawEvent + " - " + e); } start = i + 1; } } ... } } }
在NativeDaemonConnector中的handle处理为:
@Override public boolean handleMessage(Message msg) { String event = (String) msg.obj; try { if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) { //回调到MountService 的onEent函数 log(String.format("Unhandled event '%s'", event)); } } catch (Exception e) { loge("Error handling '" + event + "': " + e); } return true; }
到MountService中onEvent:
public boolean onEvent(int code, String raw, String[] cooked) { if (DEBUG_EVENTS) { StringBuilder builder = new StringBuilder(); builder.append("onEvent::"); builder.append(" raw= " + raw); if (cooked != null) { builder.append(" cooked = " ); for (String str : cooked) { builder.append(" " + str); } } Slog.i(TAG, builder.toString()); } if (code == VoldResponseCode.VolumeStateChange) { //根据 Vold的Code 执行 /* * One of the volumes we're managing has changed state. * Format: "NNN Volume <label> <path> state changed * from <old_#> (<old_str>) to <new_#> (<new_str>)" */ notifyVolumeStateChange( cooked[2], cooked[3], Integer.parseInt(cooked[7]), Integer.parseInt(cooked[10])); //更新状态 } else if ((code == VoldResponseCode.VolumeDiskInserted) || (code == VoldResponseCode.VolumeDiskRemoved) || (code == VoldResponseCode.VolumeBadRemoval)) ... if (code == VoldResponseCode.VolumeDiskInserted) { //如果接收到的是插入disk的消息,则执行挂载操作 new Thread() { @Override public void run() { try { int rc; if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { Slog.w(TAG, String.format("Insertion mount failed (%d)", rc)); } } catch (Exception ex) { Slog.w(TAG, "Failed to mount media on insertion", ex); } } }.start(); } ... }
可以看到根据code值执行相对应的操作,在Android—— 4.2 Vold挂载管理_DirectVolume/Volume (五)中的DirectVolume中
DirectVolume::handleBlockEvent中就发送了ResponseCode::VolumeDiskInserted
MountService中对Vold的socket接收大体就是这样!
三.MountService下发Command:
就从上面doMountVolume来解析,MountService中对Volume的各种操作都是需要转换成符合Vold中socket command,这样Vold中才能正确的解析识别调用!
private int doMountVolume(String path) { int rc = StorageResultCode.OperationSucceeded; final StorageVolume volume; synchronized (mVolumesLock) { volume = mVolumesByPath.get(path); } if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path); try { mConnector.execute("volume", "mount", path);// 调用到NativeDaemonConnector中的execute } ... }
NativeDaemonConnector中:
public NativeDaemonEvent execute(String cmd, Object... args) throws NativeDaemonConnectorException { final NativeDaemonEvent[] events = executeForList(cmd, args);//由executeForList发送,返回NativeDaemonEent事件 if (events.length != 1) { throw new NativeDaemonConnectorException( "Expected exactly one response, but received " + events.length); } return events[0]; }
最终调用到:
public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args) throws NativeDaemonConnectorException { final ArrayList<NativeDaemonEvent> events = Lists.newArrayList(); final int sequenceNumber = mSequenceNumber.incrementAndGet(); final StringBuilder cmdBuilder = new StringBuilder(Integer.toString(sequenceNumber)).append(' '); final long startTime = SystemClock.elapsedRealtime(); makeCommand(cmdBuilder, cmd, args); //转换制作成标准的Command final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */ log("SND -> {" + logCmd + "}"); cmdBuilder.append('\0'); final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */ synchronized (mDaemonLock) { if (mOutputStream == null) { throw new NativeDaemonConnectorException("missing output stream"); } else { try { mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8)); //通过在listenToSocket中获取的输出流,写入转换好的sentCmd } catch (IOException e) { throw new NativeDaemonConnectorException("problem sending command", e); } } } ... }
MountService 中往下发command的流程大体就是这样!
简单流程图:
至此,framework与Vold的分析就到这里!
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。