您的位置:首页 > 移动开发 > Android开发

四极管:android4.0 实现U盘挂载PC (一)

2013-10-25 10:49 225 查看

 

USB On-The-Go and Embedded Host

 

    Virtually every portable device now uses USB for PC connectivity. As these products increase in popularity, there is a growing need for them to communicate both with USB peripherals and directly with each other when a PC
is not available. There is also an increase in the number of other, non-PC hosts (Embedded Hosts) which support USB in order to connect to USB peripherals.

详细英文文档请查看:

http://www.usb.org/developers/onthego/

下面具体看代码:

先看vold:android在vold里处理otg。即将设备写到一个标志文件,再进行广播大容量存储的状态。

vim  /vold/CommandListener.cpp

int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
dumpArgs(argc, argv, -1);

if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
return 0;
}

VolumeManager *vm = VolumeManager::Instance();
int rc = 0;

if (!strcmp(argv[1], "list")) {
return vm->listVolumes(cli);
} else if (!strcmp(argv[1], "debug")) {
if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);
return 0;
}
vm->setDebug(!strcmp(argv[2], "on") ? true : false);
} else if (!strcmp(argv[1], "mount")) {
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
return 0;
}
rc = vm->mountVolume(argv[2]);
} 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 <path> [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);
} else if (!strcmp(argv[1], "format")) {
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path>", false);
return 0;
}
rc = vm->formatVolume(argv[2]);
} else if (!strcmp(argv[1], "share")) {
if (argc != 4) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: volume share <path> <method>", false);
return 0;
}
rc = vm->shareVolume(argv[2], argv[3]);    //该函数判断SD卡状态,若不存在或处于忙状态,怎返回失败值。
} else if (!strcmp(argv[1], "unshare")) {
if (argc != 4) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: volume unshare <path> <method>", false);
return 0;
}
rc = vm->unshareVolume(argv[2], argv[3]);
} else if (!strcmp(argv[1], "shared")) {
bool enabled = false;
if (argc != 4) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: volume shared <path> <method>", false);
return 0;
}

if (vm->shareEnabled(argv[2], argv[3], &enabled)) {
cli->sendMsg(
ResponseCode::OperationFailed, "Failed to determine share enable state", true);
} else {
cli->sendMsg(ResponseCode::ShareEnabledResult,
(enabled ? "Share enabled" : "Share disabled"), false);
}
return 0;
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
}

if (!rc) {
cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
} else {
int erno = errno;
rc = ResponseCode::convertFromErrno();
cli->sendMsg(rc, "volume operation failed", true);
}

return 0;
}

往下继续:

vi ./VolumeManager.cpp

 

#define MASS_STORAGE_FILE_PATH  "/sys/class/android_usb/android0/f_mass_storage/lun/file"



1、连接PC机


int VolumeManager::shareVolume(const char *label, const char *method) {
Volume *v = lookupVolume(label);

if (!v) {
errno = ENOENT;
return -1;
}

/*
* Eventually, we'll want to support additional share back-ends,
* some of which may work while the media is mounted. For now,
* we just support UMS
*/
if (strcmp(method, "ums")) {
errno = ENOSYS;
return -1;
}

if (v->getState() == Volume::State_NoMedia) {
errno = ENODEV;
return -1;
}

if (v->getState() != Volume::State_Idle) {
// You need to unmount manually befoe sharing
errno = EBUSY;
return -1;
}

if (mVolManagerDisabled) {
errno = EBUSY;
return -1;
}
/*getShareDevice该函数直接返回SD卡的设备号,部分版本使用函数getDiskDevice函数名*/
dev_t d = v->getShareDevice();
if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
// This volume does not support raw disk access
errno = EINVAL;
return -1;
}

int fd;
char nodepath[255];
snprintf(nodepath,
sizeof(nodepath), "/dev/block/vold/%d:%d",
MAJOR(d), MINOR(d));
/*这里是该文件关键之处,想要让PC机识别到设备上的SD卡或者Iland,那么就必须将SD卡的设备节点路径写到以下文件中去,这样才能打开大容量存储功能*/
if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
return -1;
}

if (write(fd, nodepath, strlen(nodepath)) < 0) {
SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
close(fd);
return -1;
}

close(fd);

/**handleVolumeShared 函数在Volume中,是一个虚函数,在子类DirectVolume中实现,也就是广播ums状态/
v->handleVolumeShared();

/*注:adnroid4.0以上版本增加了以下判断*/
if (mUmsSharingCount++ == 0) {
FILE* fp;
mSavedDirtyRatio = -1; // in case we fail
if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
char line[16];
if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
fprintf(fp, "%d\n", mUmsDirtyRatio);
} else {
SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
}
fclose(fp);
} else {
SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
}
}
return 0;
}


2、断开PC机

int VolumeManager::unshareVolume(const char *label, const char *method) {
Volume *v = lookupVolume(label);

if (!v) {
errno = ENOENT;
return -1;
}

if (strcmp(method, "ums")) {
errno = ENOSYS;
return -1;
}

if (v->getState() != Volume::State_Shared) {
errno = EINVAL;
return -1;
}

int fd;
if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
return -1;
}
/*2.3版本使用ums模式,断开连接时可以在PC端进行断开,android设备会自动挂载SD,这是使用ums的弊端,PC和androd设备不能同时对SD卡进行操作。andorid4.0以上版本升级为MTP模式,可以同时操作,后期再升级。

断开电脑,进行android设备端操作时,会将MASS_STORAGE_FILE_PATH写为空*/
char ch = 0;
if (write(fd, &ch, 1) < 0) {
SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
close(fd);
return -1;
}

close(fd);
/*同连接状态一样,断开U盘挂载模式*/

v->handleVolumeUnshared();
if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
FILE* fp;
if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
fprintf(fp, "%d\n", mSavedDirtyRatio);
fclose(fp);
} else {
SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
}
mSavedDirtyRatio = -1;
}
return 0;
}

3、在处理好后,vold将继续向上Framework汇报处理结果

for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
char *buffer;
asprintf(&buffer, "%s %s %d",
(*i)->getLabel(), (*i)->getMountpoint(),
(*i)->getState());
cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
free(buffer);
}
cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);

以vold为突破点,继续往下看,看看kernel如何处理。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: