http://www.cnblogs.com/TerryBlog/archive/2012/03/22/2411628.html
Android SDCard框架
Android SDCard框架,我们修改一般涉及到四大模块
Linux Kernel 用于检测热拔插,作为框架开发者来说,这者不用涉及
Vold 作为Kernel 与 Framework 之间的桥梁
Framework 操作Vold ,给Vold 下发操作命令
UI 与Framework 交互,用于挂载/卸载SD卡
框架涉及的源码位置
Vold :System/vold
为vold 提供接口:System/Netd
其他涉及的部分:System/core/libsysutils/src
System/core/include/sysutils
Framework:frameworks/base/services/java/com/android/server
访问和提供接口类:framework/base/core/java/android/os/storage/
可能还要参考的库:framework/base/libs/storage
framework/base/native
UI:Settings/src/com/android/setting/deviceinfo
SDCard UnMounted流程分析
初始化
VolumeManager, CommandListener, NetlinkManager 都是在 main()函数里面初始化的。
其中 VolumeManager,NetlinkManager 内部采用单例模式。
(1) Class NetlinkManager 主要是创建于内核通信的 socket,接收来自底层的信息,然后传交给VolumeManager 处理。
(2) class CommandListener 主要收到上层 MountService 通过 doMountVolume 发来的命令,分析后,转交给 VolumeManager 处理;VolumeManager 处理信息后,或报告给上层 MountService,
或交给 volume 执行具体操作。CommandListener在main()初始化后,之后开始监听,会开一个线程不停的监听来自内核的消息。
深入main文件
在Vold 的main.cpp里面,启动一个线程用来监听kernel 发出unMounted 的uevent事件,代码:
NetlinkManager *nm;
//
NetlinkManager内部使用的单例模式
if (!(nm = NetlinkManager::Instance())) {
SLOGE(
"
Unable to create NetlinkManager
" );
exit(
1 );
};
//
开始监听,从服务启动就一直监听
if (
nm->start ()) {
SLOGE(
"
Unable to start NetlinkManager (%s)
" , strerror(errno));
exit(
1 );
}
NetlinkManager的start 函数是实例化了一个NetlinkHandler(继承关系:NetlinkHandler->NetlinkListener->SocketLinstener),并调用handler 的start方法,如下代码:
mHandler =
new NetlinkHandler(mSock);
if (
mHandler->start ()) {
SLOGE(
"
Unable to start NetlinkHandler: %s
" , strerror(errno));
return -
1 ;
}
深入NetlinkHandler 的start函数,见代码:
int NetlinkHandler::start() {
return
this ->
startListener ();
}
上面有说过NetlinkHandler其实是SocketLinstener的子类,NetlinkHandler直接调用父类的startListener 方法,startListener开启了一个线程用来执行threadStart函数,代码太多,贴出主心代码:
if (pthread_create(&mThread, NULL,
SocketListener::threadStart ,
this )) {
SLOGE(
"
pthread_create (%s)
" , strerror(errno));
return -
1 ;
}
而threadStart函数则调用了runListener方法,代码如下:
void *SocketListener::threadStart(
void *obj) {
SocketListener *me = reinterpret_cast(obj);
me->runListener();
pthread_exit(NULL);
return NULL;
}
runListener会判断socket 有无信息可读,不会阻滞UI,最后调用onDataAvailable函数,代码:
void SocketListener::runListener() {
SocketClientCollection *pendingList =
new SocketClientCollection();
//代码有所省略
while (!pendingList->empty()) {
/* Pop the first item from the list */
it = pendingList->begin();
SocketClient* c = *it;
pendingList->erase(it);
/* Process it, if false is returned and our sockets are
* connection-based, remove and destroy it */
if (!
onDataAvailable (c) && mListen) {
/* Remove the client from our array */
pthread_mutex_lock(&mClientsLock);
for (it = mClients->begin(); it != mClients->end(); ++it) {
if (*it == c) {
mClients->erase(it);
break;
}
}
pthread_mutex_unlock(&mClientsLock);
/* Remove our reference to the client */
c->decRef();
}
}
}
}
onDataAvailable会处理来自uEvent 的命令,并最终调用onEvent函数,onDataAvailable 位于System/core/libsysutils/src/NetlinkListener.cpp 这个主要处理一些socket方法的知识,一般不用修改。
最后由Netlinklinstener 来解析 ,代码:
bool NetlinkListener::onDataAvailable(SocketClient *cli)
{
int socket = cli->getSocket();
ssize_t count;
count = TEMP_FAILURE_RETRY(
uevent_kernel_multicast_recv (socket, mBuffer,
sizeof (mBuffer)));
if (count <
0 ) {
SLOGE(
"
recvmsg failed (%s)
" , strerror(errno));
return
false ;
}
NetlinkEvent *evt =
new NetlinkEvent();
if (!evt->decode(mBuffer, count, mFormat)) {
SLOGE(
"
Error decoding NetlinkEvent
" );
}
else {
onEvent (evt);
}
delete evt;
return
true ;
}
小结
NetlinkManager其实就是用来处理uEvent 命令,并最终发送到vold/NetlinkHandler 的onEvent 。
上一篇讲到通过NetlinkManager发送uevent 命令到NetlinkHandler 的onEvent,代码如下:
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
VolumeManager *vm = VolumeManager::Instance();
const
char *subsys = evt->getSubsystem();
if (!subsys) {
SLOGW(
"
No subsystem found in netlink event
" );
return ;
}
SLOGD(
"
NetlinkHandler:OnEvent subsys values is %s
" ,subsys);
if (!strcmp(subsys,
"
block
" )) {
SLOGD(
"
NetlinkHandler:onEvent
" );
vm->handleBlockEvent(evt);
}
}
在NetlinkHandler 里面得一个VolumeManager,当收到的命令为block时调用VolumnManager的handleBlockEvent,如上加红加粗的代码。
handleBlockEvent实则是通过一个循环将事先将main事先读取的配置文件:etc/vold.fstab存进VolumeCollection,得到VolumeCollection的对象,然后调用Volume 的handleBlockEvent,如代码:
void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
const
char *devpath = evt->findParam(
"
DEVPATH
" );
/*
Lookup a volume to handle this device
*/
VolumeCollection::iterator it;
bool hit =
false ;
for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
if (!
(*it)->handleBlockEvent(evt) ) {
#ifdef NETLINK_DEBUG
SLOGD(
"
Device '%s' event handled by volume %s\n
" , devpath, (*it)->getLabel());
#endif
hit =
true ;
break ;
}
}
if (!hit) {
#ifdef NETLINK_DEBUG
SLOGW(
"
No volumes handled block event for '%s'
" , devpath);
#endif
}
看一下Volume 的handleblockEvent代码:
int Volume::handleBlockEvent(NetlinkEvent *evt) {
errno = ENOSYS;
return -
1 ;
看起来好像没做什么事,其实真的实现在于Volume 的子类,DirectVolume,DirectVolme 中重写了handleBlockEvent,看代码:
int DirectVolume::handleBlockEvent(NetlinkEvent *evt) {
const
char *dp = evt->findParam(
"
DEVPATH
" );
PathCollection::iterator it;
for (it = mPaths->begin(); it != mPaths->end(); ++it) {
if (!strncmp(dp, *it, strlen(*it))) {
/*
We can handle this disk
*/
int action = evt->getAction();
const
char *devtype = evt->findParam(
"
DEVTYPE
" );
if (action == NetlinkEvent::NlActionAdd) {
int major = atoi(evt->findParam(
"
MAJOR
" ));
int minor = atoi(evt->findParam(
"
MINOR
" ));
char nodepath[
255 ];
snprintf(nodepath,
sizeof (nodepath),
"
/dev/block/vold/%d:%d
" ,
major, minor);
if (createDeviceNode(nodepath, major, minor)) {
SLOGE(
"
Error making device node '%s' (%s)
" , nodepath,
strerror(errno));
}
if (!strcmp(devtype,
"
disk
" )) {
handleDiskAdded(dp, evt);
}
else {
handlePartitionAdded(dp, evt);
}
}
else
if (action == NetlinkEvent::NlActionRemove) {
if (!strcmp(devtype,
"
disk
" )) {
handleDiskRemoved (dp, evt);
}
else {
SLOGD(
"
DirectVolume:handleBlockEvent--->handlePartitionRemoved
" );
handlePartitionRemoved (dp, evt);
}
}
else
if (action == NetlinkEvent::NlActionChange) {
if (!strcmp(devtype,
"
disk
" )) {
handleDiskChanged(dp, evt);
}
else {
handlePartitionChanged(dp, evt);
}
}
else {
SLOGW(
"
Ignoring non add/remove/change event
" );
}
return
0 ;
}
}
errno = ENODEV;
return -
1 ;
}
因为我的板子还未完善,所以这里它认为我的sdcard是一个分区,但无关紧要,原理一样,就根据分区的代码跟踪。:handlePartitionRemoved, 由于代码过多,只贴出核心代码:
void DirectVolume::handlePartitionRemoved(
const
char *devpath, NetlinkEvent *evt) {
if ((dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev) {
/*
* Yikes, our mounted partition is going away!
*/
snprintf(msg,
sizeof (msg),
"
Volume %s %s bad removal (%d:%d)
" ,
getLabel(), getMountpoint(), major, minor);
SLOGD(
"
DirectVolume:(dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev:%d,msg is :%s.
" ,mCurrentlyMountedKdev,msg);
mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval, msg, false );
if (mVm->cleanupAsec(
this ,
true )) {
SLOGE(
"
Failed to cleanup ASEC - unmount will probably fail!
" );
}
if (
Volume::unmountVol(true , false ) ) {
SLOGE(
"
Failed to unmount volume on bad removal (%s)
" ,
strerror(errno));
//
XXX: At this point we're screwed for now
}
else {
SLOGD(
"
Crisis averted
" );
}
}
}
到此,直接调用父类的unmountVol方法,unmountVol会通过setState通知框架状态改变。代码太多,只推荐核心代码:
int Volume::unmountVol(
bool force,
bool revert) {
setState(Volume::State_Unmounting);
}
而setState会通过socket将msg消息传给框架
mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,
msg,
false );
接下去的步骤是关于socket的操作,就不深入了。
小结
到了这一步,Vold 向上层反馈的动作基本己经完成,下一篇文章将会讲解Framework 如何取得Vold 反馈过来的数据。
前一篇讲到SDCard unmout onEvent 发送socket 到框架层,接下来分析框架层得到数据后的流程。
MoutService
当android 系统启动时,system将MountService 添加到启动服务里面,而MountService 会开启一个线程来运行NativeDaemonConnector,由它来监听vold的消息,代码:
mConnector =
new NativeDaemonConnector(
this ,
"
vold
" , MAX_CONTAINERS *
2 , VOLD_TAG);
mReady =
false ;
Thread thread =
new Thread(mConnector, VOLD_TAG);
thread.start();
该函数运行在MountService的构造函数里面,而NativeDaemonConnector 本身就是继承自Runnable。
NativeDaemonConnector
Framework与vold 的通信是通过socket来实现的,不过该socket 由 android做了一个封装,LocalSocket 实现的socket功能。
NativeDaecomConnector 位于framework/base/service/java/com/android/server目录下, 监听vold 的消息代码在继承自Runnable对象的run方法里面 :
@Override
public
void run() {
HandlerThread thread =
new HandlerThread(TAG +
"
.CallbackHandler
" );
thread.start();
mCallbackHandler =
new Handler(thread.getLooper(),
this );
while (
true ) {
try {
listenToSocket ();
}
catch (Exception e) {
Slog.e(TAG,
"
Error in NativeDaemonConnector
" , e);
SystemClock.sleep(
5000 );
}
}
}
NativeDaemonConnector 类实例化了一个LocalSocket来与vold 通信。LocalSocket 里面有一个类LocalSocketImpl,该类部分是通过JNI实现的。
关于socket 内部如何通信,这个不是我们所关心的内容,因为如果要深入进去估计没完没了,有兴趣的朋友可以参考源码进入SocketListener查看:
建立连接
SocketListener::SocketListener
当main初始化CommandListener 后,会为socketName 传入一个叫vold 的字符串
SocketListener::startListener
等待并接收连接请求
SocketListener::runListener
获得命令参数
bool FrameworkListener::onDataAvailable
dispatchCommand 到相应的命令类,并返回一部分消息给上层
FrameworkListener::dispatchCommand
再回过头看NativeDaemonConnector 的listenToSocket,代码中实例化了一个LocalSocketAddress的实例,并传入一个叫"vold"字符串的socket 名称,这与CommandListener中继承了FrameworkListener时给的"vold"名称是一致的,两个socket名称一致则可以互相进行通讯了,代码如下:
private
void listenToSocket() throws IOException {
LocalSocket socket =
null ;
Slog.w(TAG,String.format(
"
NativeDaemonConnector--->listenToSocket:start
" ));
try {
socket =
new LocalSocket();
LocalSocketAddress address = new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED);
socket.connect(address);
InputStream inputStream = socket.getInputStream();
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 )
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 ) {
String event = new String(buffer, start, i - start);//解析socket 的数据并获取event
if (LOCAL_LOGD) Slog.d(TAG, String.format(
"
RCV <- {%s}
" ,
event ));
String[] tokens =
event .split(
"
" ,
2 );
try {
int code = Integer.parseInt(tokens[
0 ]);
if (code >= ResponseCode.UnsolicitedInformational) {
mCallbackHandler.sendMessage(
mCallbackHandler.obtainMessage(code,
event ));//发送消息给handler
}
else {
try {
mResponseQueue.put(
event );
}
catch (InterruptedException ex) {
Slog.e(TAG,
"
Failed to put response onto queue
" , ex);
}
}
}
catch (NumberFormatException nfe) {
Slog.w(TAG, String.format(
"
Bad msg (%s)
" ,
event ));
}
start = i +
1 ;
}
}
//
We should end at the amount we read. If not, compact then
//
buffer and read again.
if (start != count) {
final
int remaining = BUFFER_SIZE - start;
System.arraycopy(buffer, start, buffer,
0 , remaining);
start = remaining;
}
else {
start =
0 ;
}
}
}
catch (IOException ex) {
Slog.e(TAG,
"
Communications error
" , ex);
throw ex;
}
finally {
synchronized (mDaemonLock) {
if (mOutputStream !=
null ) {
try {
mOutputStream.close();
}
catch (IOException e) {
Slog.w(TAG,
"
Failed closing output stream
" , e);
}
mOutputStream =
null ;
}
}
try {
if (socket !=
null ) {
socket.close();
}
}
catch (IOException ex) {
Slog.w(TAG,
"
Failed closing socket
" , ex);
}
}
}
上面代码,通过socket 并event 解析出来,并通handler 发送到handleMessage 中,当handleMessage接收到传过来的消息时,会调用MountService 的onEvent 方法将code和event和sdcard 的状态传递进去。代码如下:
public boolean handleMessage(Message msg) {
String
event = (String) msg.obj;
Slog.w(TAG,String.format(
"
NativeDaemonConnector--->handleMessage the event value is
" +
event ));
try {
if (!
mCallbacks.onEvent(msg.what, event , event .split(" " )) ) {
Slog.w(TAG, String.format(
"
Unhandled event '%s'
" ,
event ));
}
}
catch (Exception e) {
Slog.e(TAG, String.format(
"
Error handling '%s'
" ,
event ), e);
}
return
true ;
}
又回到MountService ,在onEvent里面当接收到的code ==VoldResponseCode.VolumeBadRemoval时会调用updatePublicVolumeState,发送unmount改变的广播,代码如下:
else
if (code == VoldResponseCode.VolumeBadRemoval) {
if (DEBUG_EVENTS) Slog.i(TAG,
"
Sending unmounted event first
" );
/*
Send the media unmounted event first
*/
updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
action = Intent.ACTION_MEDIA_UNMOUNTED;
if (DEBUG_EVENTS) Slog.i(TAG,
"
Sending media bad removal
" );
updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
action = Intent.ACTION_MEDIA_BAD_REMOVAL;}
到这里,进入updatePublicVolumeState看该函数里的主要代码:
synchronized (mListeners) {
for (
int i = mListeners.size() -
1 ; i >=
0 ; i--) {
MountServiceBinderListener bl = mListeners.
get (i);
try {
Slog.w(TAG,
"
MountService--->updatePublicVolumeState-->bl.mListener.onStorageStateChanged
" );
bl.mListener.onStorageStateChanged(path, oldState, state);
}
catch (RemoteException rex) {
Slog.e(TAG,
"
Listener dead
" );
mListeners.remove(i);
}
catch (Exception ex) {
Slog.e(TAG,
"
Listener failed
" , ex);
}
}
}
}
并且调用sendStorageIntent 方法将SDCard的Action:android.intent.action.MEDIA_BAD_REMOVAL 和dat:file:///mnt/sdcard 通过这个广播发送出去,代码如下:
private
void sendStorageIntent(String action, String path) {
Intent intent =
new Intent(action, Uri.parse(
"
file://
" + path));
//
add StorageVolume extra
intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mVolumeMap.
get (path));
Slog.d(TAG,
"
sendStorageIntent
" + intent);
mContext.sendBroadcast(intent);
}
再回到 updatePublicVolumeState ,调用了stateChange 后,将状态为632的标识发送到NativeDaemonConnector 的handlemessage,当NativeDaemonConnector 发现SDCard的状态发送改变时,比如unmount 的时候,从632(VolumeBadRemoval)变到605(VolumeStateChange)到onEvent,当onEvent再次得到请求时,进入判断会直接执行notifyVolumeStateChange 函数,代码如下:
if (code == VoldResponseCode.VolumeStateChange) {
/*
* One of the volumes we're managing has changed state. * Format: "NNN Volume state changed * from () to ()"
*/
notifyVolumeStateChange(
cooked[
2 ], cooked[
3 ], Integer.parseInt(cooked[
7 ]),
Integer.parseInt(cooked[
10 ]));
}
notifyStateChange 会调用updatePublicVolumeState通知packageManger SDCard己经unmount.
再回到Vold
由于vold 启动文件一开始就启动了CommandListener的runcommand由于socket 一直在通讯,当发现值改变后,进入以下代码runCommand 方法里面:
else
if (!strcmp(argv[
1 ],
"
unmount
" )) {
if (argc <
3 || argc >
4 ||
((argc ==
4 && strcmp(argv[
3 ],
"
force
" )) &&
(argc ==
4 && strcmp(argv[
3 ],
"
force_and_revert
" )))) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"
Usage: volume unmount [force|force_and_revert]
" ,
false );
return
0 ;
}
bool force =
false ;
bool revert =
false ;
if (argc >=
4 && !strcmp(argv[
3 ],
"
force
" )) {
force =
true ;
}
else
if (argc >=
4 && !strcmp(argv[
3 ],
"
force_and_revert
" )) {
force =
true ;
revert =
true ;
}
rc =
vm->unmountVolume (argv[
2 ], force, revert);
}
这时调用VolumeManage的unmoutVolume。该方法来源于Volume 的unmountVol,调用这个函数会unmount 三个挂载点,并同时调用setState通知框架unmount 成功,可以改变UI等一系列动作。
最后总结
MountService: 实现用于管理存储设备的后台服务
StorageManage:访问MountService 接口,并向应用层提供接口
PackageMangeService:是用于管理系统中所有apk,当SDCard发生变化时,向应用层发送消息
NativeDaemonConnector:创建socket实现mountservice 和vold 的通信
可以这么说:当vold 捕获到uevent 事件,会将事件消息通知framework,framework 进行判断,然后再下发执行命令。
粗糙图
最后附一张比较粗糙的结构图,时间较急,没仔细画好