实现需求:设备端连接pc后,mtp模式开启并映射到外置sdcard某一目录,同时在pc这边的设备管理可以以CD Rom的形式访问设备端相关的ISO镜像。
软件平台:android4.4
硬件环境:MTK
分两步来实现,首先打开MTP模式,就需要在projectconfig.mk里边添加相关的配置信息,mtk平台使用的是MTK_MASS_STORAGE开关,当value为yes时,USB打开MASS_STORAGE模式,反之,则打开MTP模式,build下的main.mk会判断此开关的值,然后设置persist.sys.usb.config,这只是打开MTP的前提,
下面我们关注一下mtp模式打开的流程:
USB连接之后,底层会有uevent事件上报,UsbManager监测到之后,会发出USB_CONNECT广播,MtpReceiver会监听该广播,将相关状态改变交给handler处理,其实就是判断系统是否打开MTP模式,如果是的话,就开启MtpService,该service的onStartCommand会创建相关目录,
--- a/packages/providers/MediaProvider/src/com/android/providers/media/MtpService.java
+++ b/packages/providers/MediaProvider/src/com/android/providers/media/MtpService.java
@@ -54,6 +54,9 @@ public class MtpService extends Service {
Environment.DIRECTORY_PICTURES,
};
+ private static final String USER_SPACE = "/storage/sdcard1/我导入的音乐";
+ private static final String STORE_IN = "/storage/sdcard0";
+
/// M: Added Modification for ALPS00255822, bug from WHQL test @{
private static final String MTP_OPERATION_DEV_PATH =
"DEVPATH=/devices/virtual/misc/mtp_usb";
@@ -260,6 +263,10 @@ public class MtpService extends Service {
file.mkdirs();
subdirs[i] = file.getPath();
}
+ } else {
+ File file = new File(USER_SPACE);
+ file.mkdirs();
+ subdirs = new String[]{USER_SPACE};
}
/*Fix ALPS00444854
MtpService process is killed by VOLD when user plug out SD card(USB will disconnect)
@@ -404,6 +411,7 @@ public class MtpService extends Service {
}
private void volumeMountedLocked(String path) {
+ if (path.equals(STORE_IN)) return; //屏蔽外置存储的处理。
// Add for update Storage
StorageVolume[] volumes = mStorageManager.getVolumeList();
mVolumes = volumes;
@@ -428,9 +436,8 @@ public class MtpService extends Service {
String PATH_SDCARD0 = "/storage/sdcard0";
String PATH_SDCARD1 = "/storage/sdcard1";
if (storage.getPath().equals(PATH_SDCARD0) && !storage.isRemovable()){
-
StorageVolume[] volumes = mStorageManager.getVolumeList();
for (int i = 0; i < volumes.length; i++) {
代码中USER_SPACE定义的目录结构即为pc端映射的目录,由于要求pc端只映射该目录,而默认会有内置的存储卡也会体现出来,因此需要将内置存储的信息屏蔽掉,见代码中注释,在onStartCommand方法的末端,会创建MtpDatabase,同时启动MtpServer,后者就是设备端的守护进程,负责处理pc端发过来的命令请求之类,与pc端交互。
产品需求是pc的设备目录不可以重命名,不能创建与其同级的目录,可以在该目录下创建子目录,可重命名,则还需对代码进行如下修改:
--- a/frameworks/base/media/java/android/mtp/MtpDatabase.java
+++ b/frameworks/base/media/java/android/mtp/MtpDatabase.java
@@ -124,6 +124,9 @@ public class MtpDatabase {
private static final String STORAGE_FORMAT_PARENT_WHERE = STORAGE_FORMAT_WHERE + " AND "
+ Files.FileColumns.PARENT + "=?";
+ private static final String VINCI_DIR = "/storage/sdcard1/我导入的音乐";
+
+
private final MediaScanner mMediaScanner;
static {
@@ -258,12 +261,16 @@ public class MtpDatabase {
// check to see if the path matches one of our storage subdirectories
// returns true if we have no special subdirectories
private boolean isStorageSubDirectory(String path) {
- if (mSubDirectories == null) return false;
- for (int i = 0; i < mSubDirectories.length; i++) {
+ if (mSubDirectories == null) return false;
+ /*
+ for (int i = 0; i < mSubDirectories.length; i++) {
if (path.equals(mSubDirectories[i])) {
return true;
}
}
+ */
+ if (path.equals(VINCI_DIR)) return true;
+
return false;
}
上述逻辑处理是新建目录及重命名目录名时根据logcat捕获到的程序流,因此做了相关处理。
至此,MTP模式正式开挂。
下边将pc端挂载设备端ISO文件的流程做如下总结:
diff --git a/build/core/main.mk b/build/core/main.mk
index 10923ee..49a3b2c 100644
--- a/build/core/main.mk
+++ b/build/core/main.mk
@@ -374,11 +374,9 @@ else # !enable_target_debugging
ADDITIONAL_DEFAULT_PROPERTIES += ro.adb.secure=1
endif # !enable_target_debugging
-# default usb function
-ifeq ($(strip $(MTK_MASS_STORAGE)),yes)
- ADDITIONAL_DEFAULT_PROPERTIES += persist.sys.usb.config=mass_storage
-else
- ADDITIONAL_DEFAULT_PROPERTIES += persist.sys.usb.config=mtp
+# kongbo change usb function
+ifeq ($(strip $(MTK_STORAGE_MTP)),yes)
+ ADDITIONAL_DEFAULT_PROPERTIES += persist.sys.usb.config=mtp,mass_storage
endif
# serial port open or not
diff --git a/mediatek/config/mt6572/init.usb.rc b/mediatek/config/mt6572/init.usb.rc
index ae45808..b32d072 100755
--- a/mediatek/config/mt6572/init.usb.rc
+++ b/mediatek/config/mt6572/init.usb.rc
@@ -15,6 +15,7 @@ on post-fs-data
write /sys/class/android_usb/android0/f_rndis/wceis 1
write /sys/class/android_usb/android0/f_rndis/manufacturer Vinci
write /sys/class/android_usb/android0/f_rndis/vendorID $sys.usb.vid
+ write /sys/class/android_usb/android0/f_mass_storage/lun2/file "/dev/block/loop0"
# Used to set USB configuration at boot and to switch the configuration
# when changing the default configuration
--- a/mediatek/config/vinci_mtk/ProjectConfig.mk
+++ b/mediatek/config/vinci_mtk/ProjectConfig.mk
+# add by kongbo for our device support mtp&&mass_storage
+MTK_STORAGE_MTP=yes
+
# MTK_MATV_PARALLEL_IF_SUPPORT is used to define mATV video path interface is parallel interface or serial interface.
MTK_MATV_SERIAL_IF_SUPPORT=yes
MTK_MAV_PLAYBACK_SUPPORT=no
这是产品配置这方面的改动,此外外挂的ISO镜像文件可能会根据自己的需求去制作,mtk方案的ISO模块是在system/mobile_toolkit目录下生成,开机的时候该ISO文件会被挂载,执行该挂载的命令在init.rc中:
mount iso9660 loop@/system/mobile_toolkit/iAmCdRom.iso /mnt/cd-rom ro
此外,kernel的USB驱动部分,还需做配置调整。
把LUN改成3个,并且最后一个定义为CDROM
kernel\drivers\usb\gadget\android.c
static int mass_storage_function_init(struct android_usb_function *f,
struct usb_composite_dev *cdev)
{
struct mass_storage_function_config *config;
struct fsg_common *common;
int err;
int i;
config = kzalloc(sizeof(struct mass_storage_function_config),
GFP_KERNEL);
if (!config)
return -ENOMEM;
#ifdef MTK_MULTI_STORAGE_SUPPORT
#ifdef MTK_SHARED_SDCARD
#define NLUN_STORAGE 1
#else
#define NLUN_STORAGE 2
#endif
#else
#define NLUN_STORAGE 1
#endif
#define NLUN_STORAGE 3 //add 1/2
config->fsg.nluns = NLUN_STORAGE;
for(i = 0; i < config->fsg.nluns; i++) {
config->fsg.luns[i].removable = 1;
config->fsg.luns[i].nofua = 1;
}
config->fsg.luns[NLUN_STORAGE-1].cdrom = 1; //add 2/2
common = fsg_common_init(NULL, cdev, &config->fsg);
if (IS_ERR(common)) {
kfree(config);
return PTR_ERR(common);
}
err = sysfs_create_link(&f->dev->kobj,
&common->luns[0].dev.kobj,
"lun");
if (err) {
kfree(config);
return err;
}
/*
* "i" starts from "1", cuz dont want to change the naming of
* the original path of "lun0".
*/
for(i = 1; i < config->fsg.nluns; i++) {
char string_lun[5]={0};
sprintf(string_lun, "lun%d",i);
err = sysfs_create_link(&f->dev->kobj,
&common->luns[i].dev.kobj,
string_lun);
if (err) {
kfree(config);
return err;
}
}
common->android_callback = &mass_storage_callback;
config->common = common;
f->config = config;
return 0;
}
至此,CD Rom外挂完成,注:pc端显示的CD Rom名称与制作ISO镜像时命名的文件名一致。完工,欢迎列位点评切磋啊~~~~~~