android挂载usb设备,android usb挂载分析---MountService启动

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

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

[cpp] view plain copy print ?

try{

/*

* NotificationManagerService is dependant on MountService,

* (for media / usb notifications) so we must start MountService first.

*/

Slog.i(TAG, "Mount Service");

ServiceManager.addService("mount",newMountService(context));

} catch(Throwable e) {

Slog.e(TAG, "Failure starting Mount Service", e);

} 这里new 了一个

MountService,并把service添加到了

ServiceManager,我们看下MountService的构造函数:

[cpp] view plain copy print ?

/**

* Constructs a new MountService instance

*

* @param context  Binder context for this service

*/

publicMountService(Context context) {

mContext = context;

// XXX: This will go away soon in favor of IMountServiceObserver

mPms = (PackageManagerService) ServiceManager.getService("package");//获取包管理服务

mContext.registerReceiver(mBroadcastReceiver,

newIntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);//注册广播接收器

mHandlerThread = newHandlerThread("MountService");//处理消息

mHandlerThread.start();

mHandler = newMountServiceHandler(mHandlerThread.getLooper());

// Add OBB Action Handler to MountService thread.

mObbActionHandler = newObbActionHandler(mHandlerThread.getLooper());

/*

* Vold does not run in the simulator, so pretend the connector thread

* ran and did its thing.

*/

if("simulator".equals(SystemProperties.get("ro.product.device"))) {

mReady = true;

mUmsEnabling = true;

return;

}

/*

* 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 = newNativeDaemonConnector(this,"vold",

PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG);

mReady = false;

Thread thread=newThread(mConnector, VOLD_TAG);

thread.start();

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

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

[cpp] view plain copy print ?

publicvoidrun() {

while(true) {

try{

listenToSocket();

} catch(Exception e) {

Slog.e(TAG, "Error in NativeDaemonConnector", e);

SystemClock.sleep(5000);

}

}

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

[cpp] view plain copy print ?

privatevoidlistenToSocket() throws IOException {

LocalSocket socket = null;

try{

socket = newLocalSocket();

LocalSocketAddress address = newLocalSocketAddress(mSocket,//这里mSocket=“vold"

LocalSocketAddress.Namespace.RESERVED);              //注意这里的RESERVED

socket.connect(address);              //连接到vold模块监听的套接字处

mCallbacks.onDaemonConnected();       //实现在MountService中

InputStream inputStream = socket.getInputStream();

mOutputStream = socket.getOutputStream();

byte[] buffer = newbyte[BUFFER_SIZE];

intstart = 0;

while(true) {

intcount = inputStream.read(buffer, start, BUFFER_SIZE - start);//读取消息

if(count break;

// Add our starting point to the count and reset the start.

count += start;

start = 0;

for(inti = 0; i

if(buffer[i] == 0) {

String event = newString(buffer, start, i - start);

if(LOCAL_LOGD) Slog.d(TAG, String.format("RCV , event));

String[] tokens = event.split(" ");

try{

intcode = Integer.parseInt(tokens[0]);

if(code >= ResponseCode.UnsolicitedInformational) {

try{

if(!mCallbacks.onEvent(code, event, tokens)) {//实现在MountService中

Slog.w(TAG, String.format(

"Unhandled event (%s)", event));

}

} catch(Exception ex) {

Slog.e(TAG, String.format(

"Error handling '%s'", event), ex);

}

}

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 intremaining = BUFFER_SIZE - start;

System.arraycopy(buffer, start, buffer, 0, remaining);

start = remaining;

} else{

start = 0;

}

}

} catch(IOException ex) {

Slog.e(TAG, "Communications error", ex);

throwex;

} finally {

synchronized (this) {

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);

}

}

}

onDaemonConnected的实现在MountServices吕,将向下下发volume list消息 获取到了磁盘的标签,挂载点与状态,调用connect函数连接到vold模块,connetc最终调用native函数connectLocal进行连接工作,我们看下他的jni层代码,最后调用的:

[cpp] view plain copy print ?

intsocket_local_client_connect(intfd,constchar*name,intnamespaceId,

inttype)

{

structsockaddr_un addr;

socklen_t alen;

size_tnamelen;

interr;

err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);

if(err

gotoerror;

}

if(connect(fd, (structsockaddr *) &addr, alen)

gotoerror;

}

returnfd;

error:

return-1;

}

/**

* connect to peer named "name"

* returns fd or -1 on error

*/

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

[cpp] view plain copy print ?

caseANDROID_SOCKET_NAMESPACE_RESERVED:

namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);

/* unix_path_max appears to be missing on linux */

if(namelen >sizeof(*p_addr)

- offsetof(structsockaddr_un, sun_path) - 1) {

gotoerror;

}

strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);  //  ANDROID_RESERVED_SOCKET_PREFIX="/dev/socket/"

strcat(p_addr->sun_path, name);

break;

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

[cpp] view plain copy print ?

intsocket_local_client(constchar*name,intnamespaceId,inttype)

{

ints;

s = socket("color:#ff0000;">AF_LOCAL, type, 0);

if(s return-1;

if( 0 > socket_local_client_connect(s, name, namespaceId, type)) {

close(s);

return-1;

}

returns;

} 这样,就建立了一条从FrameWork层到vold层的通信链路,后面FrameWork层就等待Vold发送消息过来了。。。FrameWork层的通信也ok了,就可以等待U盘挂载了。。

转自:http://blog.csdn.net/new_abc/article/details/7400740

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 设备通过 USB 连接外部存储设备时,外部存储设备的名称和所在位置可能会有所不同,取决于具体设备Android 版本。下面是一些常见的外部存储设备名称和所在位置: - USB 设备:通常以 "usb" 开头,例如 "/storage/usb0"。 - SD 卡:通常以 "sd" 或 "extSdCard" 开头,例如 "/storage/sdcard1" 或 "/storage/extSdCard"。 - OTG 设备:通常以 "sda" 或 "sdb" 开头,例如 "/storage/sda1"。 通过以下代码可以获取外部存储设备的名称和路径: ```java File[] files = new File("/storage/").listFiles(); for (File file : files) { if (file.isDirectory() && file.canRead() && !file.isHidden()) { String name = file.getName(); if (name.startsWith("usb") || name.startsWith("sd") || name.startsWith("sda") || name.startsWith("sdb") || name.startsWith("extSdCard")) { // 这里的 name 就是外部存储设备的名称 // 这里的 file.getAbsolutePath() 就是外部存储设备的路径 } } } ``` 在上面的代码中,我们遍历了 `/storage/` 目录下的所有文件和文件夹,找到名称以 "usb"、"sd"、"sda"、"sdb" 或 "extSdCard" 开头的文件夹,就可以确定这个文件夹是外部存储设备的根目录,进而获取外部存储设备的名称和路径。其中,`file.getAbsolutePath()` 方法可以获取到外部存储设备的绝对路径,包括设备名称在内。 需要注意的是,不同的 Android 设备可能会有不同的外部存储设备名称和路径,因此在开发应用时需要考虑到兼容性问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值