分类: android框架 u盘挂载2012-03-27 23:00 11799人阅读 评论(4) 收藏 举报

android usb挂载分析----vold启动,我们的vold模块已经启动了,通信的机制也已经建立起来了,接下来我们分析一下MountService的启动,也就是我们FrameWork层的启动,首先看下其大概流程:

MountService的启动在SystemServer.java中,有如下代码:

  1. try {
  2. /*
  3. * NotificationManagerService is dependant on MountService,
  4. * (for media / usb notifications) so we must start MountService first.
  5. */
  6. Slog.i(TAG, "Mount Service");
  7. ServiceManager.addService("mount", new MountService(context));
  8. } catch (Throwable e) {
  9. Slog.e(TAG, "Failure starting Mount Service", e);
  10. }

这里new 了一个MountService,并把service添加到了ServiceManager,我们看下MountService的构造函数:

  1. /**
  2. * Constructs a new MountService instance
  3. *
  4. * @param context  Binder context for this service
  5. */
  6. public MountService(Context context) {
  7. mContext = context;
  8. // XXX: This will go away soon in favor of IMountServiceObserver
  9. mPms = (PackageManagerService) ServiceManager.getService("package");//获取包管理服务
  10. mContext.registerReceiver(mBroadcastReceiver,
  11. new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);//注册广播接收器
  12. mHandlerThread = new HandlerThread("MountService");//处理消息
  13. mHandlerThread.start();
  14. mHandler = new MountServiceHandler(mHandlerThread.getLooper());
  15. // Add OBB Action Handler to MountService thread.
  16. mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
  17. /*
  18. * Vold does not run in the simulator, so pretend the connector thread
  19. * ran and did its thing.
  20. */
  21. if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
  22. mReady = true;
  23. mUmsEnabling = true;
  24. return;
  25. }
  26. /*
  27. * Create the connection to vold with a maximum queue of twice the
  28. * amount of containers we'd ever expect to have. This keeps an
  29. * "asec list" from blocking a thread repeatedly.
  30. */
  31. mConnector = new NativeDaemonConnector(this, "vold",
  32. PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG);
  33. mReady = false;
  34. Thread thread = new Thread(mConnector, VOLD_TAG);
  35. thread.start();
  36. }

后面new 了一个NativeDaemonConnector,注意这里传递了一个"vold"字符串,跟我们在vold启动的时候传给CommandListener是一样的。NativeDaemonConnector实现了Runnable接口

接下来调用 thread.start()启动线程,我们看下它的run函数

  1. public void run() {
  2. while (true) {
  3. try {
  4. listenToSocket();
  5. } catch (Exception e) {
  6. Slog.e(TAG, "Error in NativeDaemonConnector", e);
  7. SystemClock.sleep(5000);
  8. }
  9. }
  10. }

在循环中调用listenToSocket函数,看下这个函数

  1. private void listenToSocket() throws IOException {
  2. LocalSocket socket = null;
  3. try {
  4. socket = new LocalSocket();
  5. LocalSocketAddress address = new LocalSocketAddress(mSocket,   //这里mSocket=“vold"
  6. LocalSocketAddress.Namespace.RESERVED);              //注意这里的RESERVED
  7. socket.connect(address);              //连接到vold模块监听的套接字处
  8. mCallbacks.onDaemonConnected();       //实现在MountService中
  9. InputStream inputStream = socket.getInputStream();
  10. mOutputStream = socket.getOutputStream();
  11. byte[] buffer = new byte[BUFFER_SIZE];
  12. int start = 0;
  13. while (true) {
  14. int count = inputStream.read(buffer, start, BUFFER_SIZE - start); //读取消息
  15. if (count < 0) break;
  16. // Add our starting point to the count and reset the start.
  17. count += start;
  18. start = 0;
  19. for (int i = 0; i < count; i++) {
  20. if (buffer[i] == 0) {
  21. String event = new String(buffer, start, i - start);
  22. if (LOCAL_LOGD) Slog.d(TAG, String.format("RCV <- {%s}", event));
  23. String[] tokens = event.split(" ");
  24. try {
  25. int code = Integer.parseInt(tokens[0]);
  26. if (code >= ResponseCode.UnsolicitedInformational) {
  27. try {
  28. if (!mCallbacks.onEvent(code, event, tokens)) {//实现在MountService中
  29. Slog.w(TAG, String.format(
  30. "Unhandled event (%s)", event));
  31. }
  32. } catch (Exception ex) {
  33. Slog.e(TAG, String.format(
  34. "Error handling '%s'", event), ex);
  35. }
  36. }
  37. try {
  38. mResponseQueue.put(event);
  39. } catch (InterruptedException ex) {
  40. Slog.e(TAG, "Failed to put response onto queue", ex);
  41. }
  42. } catch (NumberFormatException nfe) {
  43. Slog.w(TAG, String.format("Bad msg (%s)", event));
  44. }
  45. start = i + 1;
  46. }
  47. }
  48. // We should end at the amount we read. If not, compact then
  49. // buffer and read again.
  50. if (start != count) {
  51. final int remaining = BUFFER_SIZE - start;
  52. System.arraycopy(buffer, start, buffer, 0, remaining);
  53. start = remaining;
  54. } else {
  55. start = 0;
  56. }
  57. }
  58. } catch (IOException ex) {
  59. Slog.e(TAG, "Communications error", ex);
  60. throw ex;
  61. } finally {
  62. synchronized (this) {
  63. if (mOutputStream != null) {
  64. try {
  65. mOutputStream.close();
  66. } catch (IOException e) {
  67. Slog.w(TAG, "Failed closing output stream", e);
  68. }
  69. mOutputStream = null;
  70. }
  71. }
  72. try {
  73. if (socket != null) {
  74. socket.close();
  75. }
  76. } catch (IOException ex) {
  77. Slog.w(TAG, "Failed closing socket", ex);
  78. }
  79. }
  80. }

onDaemonConnected的实现在MountServices中,将向下下发volume list消息 获取到了磁盘的标签,挂载点与状态,调用connect函数连接到vold模块,connetc最终调用native函数connectLocal(

system/core/libcutils/socket_local_client.c)进行连接工作,我们看下他的jni层代码,最后调用的:

  1. int socket_local_client_connect(int fd, const char *name, int namespaceId,
  2. int type)
  3. {
  4. struct sockaddr_un addr;
  5. socklen_t alen;
  6. size_t namelen;
  7. int err;
  8. err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
  9. if (err < 0) {
  10. goto error;
  11. }
  12. if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
  13. goto error;
  14. }
  15. return fd;
  16. error:
  17. return -1;
  18. }
  19. /**
  20. * connect to peer named "name"
  21. * returns fd or -1 on error
  22. */

我们再跟进socket_make_sockaddr_un函数,这时namespaceId传的ANDROID_SOCKET_NAMESPACE_RESERVED,所以会执行下面几句:

  1. case ANDROID_SOCKET_NAMESPACE_RESERVED:
  2. namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
  3. /* unix_path_max appears to be missing on linux */
  4. if (namelen > sizeof(*p_addr)
  5. - offsetof(struct sockaddr_un, sun_path) - 1) {
  6. goto error;
  7. }
  8. strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);  //  ANDROID_RESERVED_SOCKET_PREFIX="/dev/socket/"
  9. strcat(p_addr->sun_path, name);
  10. break;

注意在前面 connect  函数中的套接字的构造,使用了AF_LOCAL:

  1. int socket_local_client(const char *name, int namespaceId, int type)
  2. {
  3. int s;
  4. s = socket(<span style="color:#ff0000;">AF_LOCAL</span>, type, 0);
  5. if(s < 0) return -1;
  6. if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
  7. close(s);
  8. return -1;
  9. }
  10. return s;
  11. }

这样,就建立了一条从FrameWork层到vold层的通信链路,后面FrameWork层就等待Vold发送消息过来了。。。

FrameWork层的通信也ok了,就可以等待U盘挂载了。。

android usb挂载分析---MountService启动的更多相关文章

  1. android usb挂载分析----vold启动

    http://blog.csdn.net/new_abc/article/details/7396733 前段时间做了下usb挂载的,现在出了几个bug,又要把流程给梳理下,顺便也把相关的知识总结下, ...

  2. android usb挂载分析---vold处理内核消息

    android usb挂载分析---vold处理内核消息 分类: u盘挂载2012-03-29 22:25 3215人阅读 评论(0) 收藏 举报 androidactioniteratordiskd ...

  3. android usb挂载分析

    http://blog.csdn.net/new_abc/article/details/7409018

  4. [Openwrt 扩展上篇]USB挂载&U盘启动&Samba共享

    最近偷懒,没学习,反想起自己的路由刷了Openwrt,正好闲置了一个硬盘想拿来做个网络硬盘,于是开始了折腾....这里将不谈论如何刷Openwrt,如何ssh,如何添加PPOE,如何添加相对应服务的包 ...

  5. [Openwrt 项目开发笔记]:USB挂载& U盘启动(三)

    [Openwrt项目开发笔记]系列文章传送门:http://www.cnblogs.com/double-win/p/3888399.html 正文: 在上一篇中,我结合Netgear Wndr370 ...

  6. Appium Android Bootstrap源代码分析之启动执行

    通过前面的两篇文章<Appium Android Bootstrap源代码分析之控件AndroidElement>和<Appium Android Bootstrap源代码分析之命令 ...

  7. android文件系统挂载分析(1)---正常开机挂载

    未完,更新中 ... "android"系列分为三部分: 1.正常开机挂载 2.encryption 3.dm-verity 我们知道android有很多分区,如"sys ...

  8. Appium Android Bootstrap源码分析之启动运行

    通过前面的两篇文章<Appium Android Bootstrap源码分析之控件AndroidElement>和<Appium Android Bootstrap源码分析之命令解析 ...

  9. Android USB驱动源码分析(-)

    Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c.这个文件实现USB的上层应用协议. 首先包含了一些 ...

随机推荐

  1. htaccess 实现网址缩短

    访问 :app.xxx.com/a 解析到:app.xxx.com/index.php/app/a <IfModule mod_rewrite.c> RewriteEngine on Re ...

  2. sqldeveloper连接mysql

    sqldeveloper连接mysql 腑镜诏 钌d 汁叁ㄧ勋 佚蔡弥噙 不仅仅是越南帮和戴爷的事情还有谢婉莹的条 炔验遒其 倒扇油┣ 砹笄谤 几句话孟飞的信心大增兴奋不已换句话说 谠诂k厝 ...

  3. onPostCreate——Activity彻底运行起来之后的回调

    记得之前想要在Activity布局完成,彻底跑起来之后,再获取当前Activity的窗口中,某个View的宽高,之前用的办法很土,弄个Handler,发个Message出来,使用sendMessage ...

  4. 笨方法学python--多行,转义序列

    1 输入多行字符串的方法有2个,一个是使用换行符 \n.另一个是使用 "三引号". 2 针对不同的符号,有很多这样的"转义序列"(escape sequence ...

  5. Jquery-获取勾选的checkbox的同级节点数量

    // 获取勾选的标签值得上一个兄弟节点 var groups = []; $('input[name="group_name"]:checked').siblings(" ...

  6. sql-删除delete涉及到三个表,这个时候就要使用from,比如这样

    delete y from dbo.XZXK_BANJIE b ,YJDC_YELLOWRED_CONTENT y , dbo.XZXK_SHOULI s where b.shoulioid=s.sh ...

  7. win10怎么启用网络发现,网络发现已关闭怎么办

    脑和电脑之间传输文件的方式很多,其中一种就是使用局域网,在网络中我们的电脑应该可以被其他电脑发现是非常方便使用文件共享的,尤其是在使用家庭组网络的时候,那么win10里面怎么启用网络发现呢? 工具/原 ...

  8. 3.1 cron表达式

    1.Cron在线生成网址:      http://cron.qqe2.com/   http://www.pdtools.net/tools/becron.jsp#cron 2.Cron 概要 3. ...

  9. Openlays 3 绘制基本图形

    <body> <div id="menu"> <label>几何图形类型:</label> <select id=" ...

  10. http://www.iteye.com/job/topic/1133159

    Lucene 的索引体系是一个写独占,读共享的结构,这意味着,我们在使用多线程进行添加索引时,性能并不会得到明显的提升,所以任何时刻只能有一个线程对索引进行写 入操作,而保障这个操作的安全性则是来自于 ...