Android4.4----Vold挂载管理分析USB挂载(四)
2015-06-05 14:55
447 查看
在上一篇Android4.4----Vold挂载管理分析USB挂载(三)中,介绍了VolumeManager接收到kernel发出的uevent事件后,向上层发送了VolumeStateChange和VolumeDiskInserted两个广播,这里我们研究一下framework接收到这两个广播后的处理动作!
Volume发出广播后,会在jb4.4-kikat/frameworks/base/services/java/com/android/server/MountService.java中的onEvent()方法中接收!
先分析VolumeStateChange!
查看notifyVolumeStateChange函数
在SystemUI\src\com\android\systemui\usb\StorageNotification.java中
接着我们再分析VolumeDiskInserted
同样也是在MountService中的onEvent()中
Volume发出广播后,会在jb4.4-kikat/frameworks/base/services/java/com/android/server/MountService.java中的onEvent()方法中接收!
先分析VolumeStateChange!
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) { /* * 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]));//重点分析一下这个函数,通过打印我们可以知道cooked[2]=CAA5-CD0B, cooked[3]=/mnt/usb/sda1,Integer.parseInt(cooked[7])=0, Integer.parseInt(cooked[10])=1
</pre><pre>加打印可以看到在onEvent中接收到的信息如下:
I/MountService( 1419): onEvent:: raw= 605 Volume CAA5-CD0B /mnt/usb/sda1 state changed from 0 (No-Media) to 1 (Idle-Unmounted) cooked = 605 Volume CAA5-CD0B /mnt/usb/sda1 state changed from 0 (No-Media) to 1 (Idle-Unmounted)其中605就是VolumeStateChange;
public static final int VolumeStateChange = 605; public static final int VolumeUuidChange = 613; public static final int VolumeUserLabelChange = 614; public static final int VolumeDiskInserted = 630; public static final int VolumeDiskRemoved = 631; public static final int VolumeBadRemoval = 632;
查看notifyVolumeStateChange函数
private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { // MStar Android Patch Begin StorageVolume volume = null; String state; // MStar Android Patch End synchronized (mVolumesLock) { volume = mVolumesByPath.get(path); state = getVolumeState(path); } if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChange::" + state);//查看state为:notifyVolumeStateChange::removed String action = null; .................... else if (newState == VolumeState.Idle) { /* * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or * if we're in the process of enabling UMS */ if (!state.equals( Environment.MEDIA_BAD_REMOVAL) && !state.equals( Environment.MEDIA_NOFS) && !state.equals( Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) { if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable"); // MStar Android Patch Begin synchronized (mVolumesLock) { if (volume == null) { volume = StorageVolume.fromTemplate(mSecondStorageTemplate, new File(path), null); addVolumeLocked(volume); } } // MStar Android Patch End updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); action = Intent.ACTION_MEDIA_UNMOUNTED; } .................. if (action != null) { sendStorageIntent(action, volume, UserHandle.ALL); }
private void updatePublicVolumeState(StorageVolume volume, String state) { final String path = volume.getPath(); // MStar Android Patch Begin String oldState; synchronized (mVolumesLock) { oldState = mVolumeStates.put(path, state); volume.setState(state); if (oldState == null) { oldState = Environment.MEDIA_REMOVED; } } if (state.equals(oldState)) { Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s", state, state, path)); return; } ............. if (Environment.MEDIA_UNMOUNTED.equals(state)) { pmGuardThread.registerMediaEvents(PMGuardThread.MEDIA_UNMOUNT_EVENT); /* * Some OBBs might have been unmounted when this volume was * unmounted, so send a message to the handler to let it know to * remove those from the list of mounted OBBS. */ mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage( OBB_FLUSH_MOUNT_STATE, path)); } .................. synchronized (mListeners) { for (int i = mListeners.size() -1; i >= 0; i--) { MountServiceBinderListener bl = mListeners.get(i); try { bl.mListener.onStorageStateChanged(path, oldState, state);//这里就会通过onStorageStateChanged函数来把挂载状态变化发出去,其他重写了这个函数的地方就能接收的到,比如systemUI中的StorageNotification中 } catch (RemoteException rex) { Slog.e(TAG, "Listener dead"); mListeners.remove(i); } catch (Exception ex) { Slog.e(TAG, "Listener failed", ex); } } }
private void sendStorageIntent(String action, StorageVolume volume, UserHandle user) { final Intent intent = new Intent(action, Uri.parse("file://" + volume.getPath())); intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, volume); Slog.d(TAG, "sendStorageIntent " + intent + " to " + user); mContext.sendBroadcastAsUser(intent, user);//这里会把相应的广播发出去 }
在SystemUI\src\com\android\systemui\usb\StorageNotification.java中
public void onStorageStateChanged(final String path, final String oldState, final String newState) { Log.d(TAG,"Javen.tang onStorageStateChanged path="+path+"oldState="+oldState+"newState="+newState); mAsyncEventHandler.post(new Runnable() { @Override public void run() { onStorageStateChangedAsync(path, oldState, newState); } }); } }这样就把挂载状态信息就传递到应用层了!
接着我们再分析VolumeDiskInserted
同样也是在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()); } ..................... else if ((code == VoldResponseCode.VolumeDiskInserted) || (code == VoldResponseCode.VolumeDiskRemoved) || (code == VoldResponseCode.VolumeBadRemoval)) { // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>) // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>) // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>) String action = null; final String label = cooked[2]; final String path = cooked[3]; int major = -1; int minor = -1; try { String devComp = cooked[6].substring(1, cooked[6].length() -1); String[] devTok = devComp.split(":"); major = Integer.parseInt(devTok[0]); minor = Integer.parseInt(devTok[1]); } catch (Exception ex) { Slog.e(TAG, "Failed to parse major/minor", ex); } final StorageVolume volume; final String state; synchronized (mVolumesLock) { volume = mVolumesByPath.get(path); state = mVolumeStates.get(path); } if (code == VoldResponseCode.VolumeDiskInserted) { new Thread("MountService#VolumeDiskInserted") { @Override public void run() { try { int rc; if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {//执行doMountVolume(path) Slog.w(TAG, String.format("Insertion mount failed (%d)", rc)); } } catch (Exception ex) { Slog.w(TAG, "Failed to mount media on insertion", ex); } } }.start(); }查看一下在onEvent()中接收到的数据打印:
I/MountService( 1419): onEvent:: raw= 630 Volume CAA5-CD0B /mnt/usb/sda1 Partition Added (8:1) cooked = 630 Volume CAA5-CD0B /mnt/usb/sda1 Partition Added (8:1)
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);//发送命令 } catch (NativeDaemonConnectorException e) { /* * Mount failed for some reason */
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 { Slog.d(TAG,"mOutputStream.write rawCmd="+rawCmd);//这里看打印为mOutputStream.write rawCmd=5 volume mount /mnt/usb/sda1 mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { throw new NativeDaemonConnectorException("problem sending command", e); } } }这里通过NativeDaemonConnector向Vold发送命令,在system/core/libsysutils/src/SocketListener.cpp中有个runListener()函数一直在监听socket,接收从上层发送过来的指令,跟着会调用到FrameworkListener::onDataAvailable()来处理接收到的消息。
相关文章推荐
- android设置背景色为透明
- android paint 研究总结
- 中国气象网 气象数据开放平台 API使用方法 (Android)
- android 无法生成R文件的原因剖析
- Android中滑屏实现----手把手教你如何实现触摸滑屏以及Scroller类详解
- Android定位开发之百度定位、高德定位、腾讯定位,三足鼎立一起为我所用!
- android 常用方法集合
- Android Studio快捷键大全
- 关于Android中各种尺寸的总结
- Android批量图片加载经典系列——使用LruCache、AsyncTask缓存并异步加载图片
- Android Studio之版本管理工具Git (图文教程)附连接到Git@OSC教程
- Android 得到当前已连接的wifi的信号强度
- Android批量图片加载经典系列——使用LruCache、AsyncTask缓存并异步加载图片
- Android-理解PendingIntent
- 给iOS开发者的Android开发建议
- Android开发详解之onTouch, onLongClick和onClick详解
- android 多屏幕适配 : 第一部分
- android的消息处理机制(图文+源码分析)—Looper/Handler/Message
- Android 问题解决方法(一)
- Android 4.0系统源码目录结构详解