SoC : RK3288
Platform : Android 5.1
现状:开发板板载7个USB口(3路host),但是只能识别一路作为U盘挂载。
需求:支持三个U盘同时挂载
一、问题集锦
1.U盘不能自动挂载
将U盘插入开发板,在资源管理器中打开USB存储器显示”USB已被卸载”,问题源于fstab分区文件:
/devices/ff540000.usb /mnt/usb_storage vfat defaults voldmanaged=usb_storage:auto -->HOST挂载
/devices/ff500000.usb /mnt/usb_storage vfat defaults voldmanaged=usb_storage:auto --> HUB挂载
usb挂载总线地址和PCB设计有关,将对应的HOST—XXXX,和HUB–xxx两路打开,其他不需要的全部注释掉。
结论:上述操作后,只能识别一路U盘(自动挂载),另一路能识别,但是不会挂载,可以手动挂载。
2.Nand falsh挂载出错
手动点击设置–存储下的挂载nand flash出错:
D/VoldCmdListener( 156): volume mount /mnt/internal_sd
D/Vold ( 156): volume status = 1----------------------
D/DirectVolume( 156): getDeviceNodes mPartIdx = 15, mDiskNumParts = 14.
E/Vold ( 156): deviceNodes[0]= 0xffffffff,[1]= 0x00000000,[2]= 0x00000000,[3]= 0x00000000
I/Vold ( 156): /dev/block/vold/4095:1048575 being considered for volume internal_sd,1
I/Vold ( 156):
D/Vold ( 156): Volume internal_sd state changing 1 (Idle-Unmounted) -> 3 (Checking)
I/MountService( 455): onEvent:: raw= 605 Volume internal_sd /mnt/internal_sd state changed from 1 (Idle-Unmounted) to 3 (Checking) cooked = 605 Volume internal_sd /mnt/internal_sd state changed from 1 (Idle-Unmounted) to 3 (Checking)
I/MountService( 455): notifyVolumeStateChange::unmounted
I/MountService( 455): updating volume state checking
D/MountService( 455): volume state changed for /mnt/internal_sd (unmounted -> checking)
W/AudioTrack( 455): AUDIO_OUTPUT_FLAG_FAST denied by client
D/MountService( 455): sendStorageIntent Intent { act=android.intent.action.MEDIA_CHECKING dat=file:///mnt/internal_sd flg=0x4000000 (has extras) } to UserHandle{-1}
I/fsck_msdos( 156): ** /dev/block/vold/4095:1048575
I/fsck_msdos( 156): Can't open: No such file or directory
I/fsck_msdos( 156): fsck_msdos terminated by exit(8)
E/Vold ( 156): Filesystem check failed (unknown exit code 8)
E/Vold ( 156): /dev/block/vold/4095:1048575 failed to mount via VFAT (No such file or directory)
E/Vold ( 156): ---------set mSkipAsec to disable app2sd because mount Vfat fail for internal_sd, mountpoint =/mnt/internal_sd
I/ValidateNoPeople( 455): skipping global notification
D/NTFS-3G ( 1403): ntfs-3g: Failed to access volume '/dev/block/vold/4095:1048575'
D/NTFS-3G ( 1403):
D/NTFS-3G ( 1403): ntfs-3g 2015.3.14 integrated FUSE 27 - Third Generation NTFS Driver
D/NTFS-3G ( 1403): Configuration type 1, XATTRS are on, POSIX ACLS are off
D/NTFS-3G ( 1403):
D/NTFS-3G ( 1403): Copyright (C) 2005-2007 Yura Pakhuchiy
D/NTFS-3G ( 1403): Copyright (C) 2006-2009 Szabolcs Szakacsits
D/NTFS-3G ( 1403): Copyright (C) 2007-2015 Jean-Pierre Andre
D/NTFS-3G ( 1403): Co
I/ntfs-3g ( 156): ntfs-3g terminated by exit(11)
I/Vold ( 156): /system/bin/ntfs-3g /dev/block/vold/4095:1048575 /mnt/internal_sd
E/Vold ( 156): ntfs-3g fail WEXITSTATUS 11
E/Vold ( 156): /dev/block/vold/4095:1048575 failed to mount via VNTFS (No such file or directory)
E/Vold ( 156): Volume internal_sd found no suitable devices for mounting :(
D/Vold ( 156): Volume internal_sd state changing 3 (Checking) -> 1 (Idle-Unmounted)
W/Vold ( 156): Returning OperationFailed - no handler for errno 0
I/MountService( 455): onEvent:: raw= 605 Volume internal_sd /mnt/internal_sd state changed from 3 (Checking) to 1 (Idle-Unmounted) cooked = 605 Volume internal_sd /mnt/internal_sd state changed from 3 (Checking) to 1 (Idle-Unmounted)
I/MountService( 455): notifyVolumeStateChange::checking
I/MountService( 455): updating volume state for media bad removal nofs and unmountable
D/MountService( 455): volume state changed for /mnt/internal_sd (checking -> unmounted)
I/PackageManager( 455): Updating external media status from unmounted to unmounted
I/MemorySettings( 1081): Received storage state changed notification that /mnt/internal_sd changed state from unmounted to checking
D/MountService( 455): sendStorageIntent Intent { act=android.intent.action.MEDIA_UNMOUNTED dat=file:///mnt/internal_sd flg=0x4000000 (has extras) } to UserHandle{-1}
D/MediaPlaybackService( 965): EJECT/UNMOUNT received. current unmount action is at /mnt/internal_sd...
D/ExternalStorage( 694): After updating volumes, found 0 active roots
W/AppOps ( 455): Bad call: specified package media under uid 1000 but it is really 1013
D/AudioHardwareTiny( 163): start_output_stream
D/AudioHardwareTiny( 163): Device : 0x400
D/AudioHardwareTiny( 163): SampleRate : 44100
D/AudioHardwareTiny( 163): Channels : 2
D/AudioHardwareTiny( 163): Formate : 0
D/AudioHardwareTiny( 163): PreiodSize : 2048
D/AudioHardwareTiny( 163): The current HDMI is DVI mode
E/AudioHardwareTiny( 163): pcm_open(PCM_CARD) failed: cannot open device '/dev/snd/pcmC0D0p': No such file or directory
I/MemorySettings( 1081): Received storage state changed notification that /mnt/internal_sd changed state from checking to unmounted
D/MediaScannerReceiver( 572): action: android.intent.action.MEDIA_UNMOUNTED path: /mnt/internal_sd
D/RKUpdateReceiver( 659): action = android.intent.action.MEDIA_UNMOUNTED
D/StorageMeasurement( 1081): getDirectorySize(/mnt/internal_sd/Ringtones) returned 0
D/StorageMeasurement( 1081): getDirectorySize(/mnt/internal_sd/Pictures) returned 0
D/StorageMeasurement( 1081): getDirectorySize(/mnt/internal_sd/DCIM) returned 0
D/StorageMeasurement( 1081): getDirectorySize(/mnt/internal_sd/Podcasts) returned 0
D/StorageMeasurement( 1081): getDirectorySize(/mnt/internal_sd/Notifications) returned 0
D/AudioHardwareTiny( 163): start_output_stream
D/AudioHardwareTiny( 163): Device : 0x400
D/AudioHardwareTiny( 163): SampleRate : 44100
D/AudioHardwareTiny( 163): Channels : 2
D/AudioHardwareTiny( 163): Formate : 0
D/AudioHardwareTiny( 163): PreiodSize : 2048
D/AudioHardwareTiny( 163): The current HDMI is DVI mode
E/AudioHardwareTiny( 163): pcm_open(PCM_CARD) failed: cannot open device '/dev/snd/pcmC0D0p': No such file or directory
D/StorageMeasurement( 1081): getDirectorySize(/mnt/internal_sd/Music) returned 0
D/StorageMeasurement( 1081): getDirectorySize(/mnt/internal_sd/Movies) returned 0
D/StorageMeasurement( 1081): getDirectorySize(/mnt/internal_sd/Android) returned 0
D/StorageMeasurement( 1081): getDirectorySize(/mnt/internal_sd/Download) returned 0
D/StorageMeasurement( 1081): getDirectorySize(/mnt/internal_sd/Alarms) returned 0
I/DefContainer-JNI( 1344): error opening: /mnt/internal_sd: Permission denied
D/StorageMeasurement( 1081): getDirectorySize(/mnt/internal_sd) returned 0
问题在于fstab分区文件出错:
/devices/ff0f0000.rksdmmc/mmc_host/mmc /mnt/internal_sd vfat defaults voldmanaged=internal_sd:15,noemulatedsd
从fstab中发现/mnt/internal_sd挂载项为15号分区:
cat /proc/partitions
major minor #blocks name
254 0 520912 zram0
179 0 7634944 mmcblk0 总容量 8G
179 1 4096 mmcblk0p1 uboot
179 2 4096 mmcblk0p2 misc
179 3 16384 mmcblk0p3 resource
179 4 16384 mmcblk0p4 kernel
179 5 32768 mmcblk0p5 boot
179 6 32768 mmcblk0p6 recovery
179 7 53248 mmcblk0p7 backup
179 8 131072 mmcblk0p8 cache
179 9 4096 mmcblk0p9 kpanic
179 10 524288 mmcblk0p10 system 512M
179 11 4096 mmcblk0p11 metadata
179 12 1048576 mmcblk0p12 userdata 1G ---> /data
179 13 65536 mmcblk0p13 radical_update 64M
179 14 5689344 mmcblk0p14 user 5.4G ----> /sdcard
8 0 31266648 sda
8 1 30541784 sda1
但是根本没有15号分区,而user是14号分区,因此将15改为14。
二、overlay机制
在修改支持多个U盘时,设置–存储下也需要做相应的修改来显示多个U盘的挂载详情,这就需要学习新的知识:overlay机制
Android overlay机制允许在不修改packages中apk的情况下,来自定义framework和package中的资源文件,实现资源的定制,来达到显示不同UI的目的。
比如,这里需要添加多个U盘的支持,首先在"设置"---"存储"下可以显示多个USB存储器,最后对每个显示的"USB存储器"对应不同的物理设备即可。
Product overlay和device overlay:有两种不同的overlay来决定最终的UI效果
其中DEVICE_PACKAGE_OVERLAYS += device/rockchip/common/overlay
PRODUCT_PACKAGE_OVERLAYS += device/rockchip/rk3288/overlay
由此可见是两个不同目录下的overlay,有何区别呢?
如果包含了同一资源,那么PRODUCT_PACKAGE_OVERLAYS将覆盖DEVICE_PACKAGE_OVERLAYS中的,定义如下build/core/package_internal.mk(Line 90):
# LOCAL_RESOURCE_DIR may point to resource generated during the build
need_compile_res :=
ifeq (,$(LOCAL_RESOURCE_DIR))
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
else
need_compile_res := true
endif
package_resource_overlays := $(strip \
$(wildcard $(foreach dir, $(PRODUCT_PACKAGE_OVERLAYS), \
$(addprefix $(dir)/, $(LOCAL_RESOURCE_DIR)))) \
$(wildcard $(foreach dir, $(DEVICE_PACKAGE_OVERLAYS), \
$(addprefix $(dir)/, $(LOCAL_RESOURCE_DIR)))))
LOCAL_RESOURCE_DIR := $(package_resource_overlays) $(LOCAL_RESOURCE_DIR)
PRODUCT_PACKAGE_OVERLAYS和DEVICE_PACKAGE_OVERLAYS功能一样,只是优先级不一样。PRODUCT_PACKAGE_OVERLAYS优先于DEVICE_PACKAGE_OVERLAYS
在这里,两个定义的资源文件并不同(只关注USB存储的),因此两个都会被加载进去:
PRODUCT_PACKAGE_OVERLAYS --> storage_list_box.xml
DEVICE_PACKAGE_OVERLAYS --> storage_list.xml
那究竟使用的是哪一个呢?先查查加载storage_list.xml的地方。在frameworks/base/core/res/res/values/symbols.xml中有:
type="xml" name="storage_list" />
type="xml" name="storage_list_box" />
MountService会解析配置storage_list.xml,
在frameworks/base/services/core/java/com/android/server/MountService.java中:
private void readStorageListLocked() {
mVolumes.clear();
mVolumeStates.clear();
Resources resources = mContext.getResources();
boolean isTablet = "tablet".equals(SystemProperties.get("ro.target.product", "tablet"));
int id = com.android.internal.R.xml.storage_list;
int boxid = com.android.internal.R.xml.storage_list_box;
XmlResourceParser parser = resources.getXml(isTablet ?id:boxid);
AttributeSet attrs = Xml.asAttributeSet(parser);
String enableUms= SystemProperties.get("ro.factory.hasUMS","false");
try {
XmlUtils.beginDocument(parser, TAG_STORAGE_LIST);
while (true) {
XmlUtils.nextElement(parser);
String element = parser.getName();
if (element == null) break;
if (TAG_STORAGE.equals(element)) {
TypedArray a = resources.obtainAttributes(attrs,
com.android.internal.R.styleable.Storage);
...
...
}
...
}
从代码中可以看到,首先判断ro.target.product的值,这里:ro.target.product=tablet
因此,加载的是storage_list.xml,如果ro.target.product=box,加载的就是storage_list_box.xml
同样的,在MountService.java中,readStorageListLocked()函数中也有与ro.factory.hasUMS相关的东西,有待研究。
因此,我们需要修改storage_list.xml,如下:
<StorageList xmlns:android="http://schemas.android.com/apk/res/android">
<storage android:mountPoint="/storage/sdcard0"
android:storageDescription="@string/storage_internal"
android:primary="true"
android:emulated="true"
android:allowMassStorage="false"
android:removable="true"
android:mtpReserve="100" />
<storage android:mountPoint="/mnt/internal_sd"
android:storageDescription="@string/storage_nand_flash"
android:primary="false"
android:emulated="false"
android:allowMassStorage="true"
android:removable="true"
android:mtpReserve="100" />
<storage android:mountPoint="/mnt/external_sd"
android:storageDescription="@string/storage_sd_card"
android:primary="false"
android:allowMassStorage="true"
android:removable="true"
android:mtpReserve="100" />
<storage android:mountPoint="/mnt/usb_storage/USB_DISK0"
android:storageDescription="@string/storage_usb0"
android:primary="false"
android:allowMassStorage="true"
android:removable="true"
android:mtpReserve="100" />
<storage android:mountPoint="/mnt/usb_storage/USB_DISK1"
android:storageDescription="@string/storage_usb1"
android:primary="false"
android:allowMassStorage="true"
android:removable="true"
android:mtpReserve="100" />
<storage android:mountPoint="/mnt/usb_storage/USB_DISK2"
android:storageDescription="@string/storage_usb2"
android:primary="false"
android:allowMassStorage="true"
android:removable="true"
android:mtpReserve="100" />
StorageList>
三、挂载配置修改
主要修改两个:fstab.rk30board.bootmode.emmc、init.rockchip.rc
sed -i '27s/^#//' $OUT_DIR/root/fstab.rk30board.bootmode.emmc
sed -i '28s/^#//' $OUT_DIR/root/fstab.rk30board.bootmode.emmc
sed -i '29s/^#//' $OUT_DIR/root/fstab.rk30board.bootmode.emmc
sed -i '27s/^/#/' $OUT_DIR/root/fstab.rk30board.bootmode.emmc
sed -i '28s/^/#/' $OUT_DIR/root/fstab.rk30board.bootmode.emmc
sed -i '29s/^/#/' $OUT_DIR/root/fstab.rk30board.bootmode.emmc
sed -i "s/\/devices\/ff580000.usb \/mnt\/usb_storage vfat defaults voldmanaged=usb_storage:auto/\/devices\/ff580000.usb \/mnt\/usb_storage\/USB_DISK2 vfat defaults voldmanaged=usb_storage\/USB_DISK2:auto/g" $OUT_DIR/root/fstab.rk30board.bootmode.emmc
sed -i "s/\/devices\/ff500000.usb \/mnt\/usb_storage vfat defaults voldmanaged=usb_storage:auto/\/devices\/ff500000.usb \/mnt\/usb_storage\/USB_DISK1 vfat defaults voldmanaged=usb_storage\/USB_DISK1:auto/g" $OUT_DIR/root/fstab.rk30board.bootmode.emmc
sed -i "s/\/devices\/ff540000.usb \/mnt\/usb_storage vfat defaults voldmanaged=usb_storage:auto/\/devices\/ff540000.usb \/mnt\/usb_storage\/USB_DISK0 vfat defaults voldmanaged=usb_storage\/USB_DISK0:auto/g" $OUT_DIR/root/fstab.rk30board.bootmode.emmc
sed -i -e "/mkdir \/mnt\/usb_storage 0000 system system/a\ mkdir /mnt/usb_storage/USB_DISK0 0000 system system" $OUT_DIR/root/init.rockchip.rc
sed -i -e "/mkdir \/mnt\/usb_storage 0000 system system/a\ mkdir /mnt/usb_storage/USB_DISK1 0000 system system" $OUT_DIR/root/init.rockchip.rc
sed -i -e "/mkdir \/mnt\/usb_storage 0000 system system/a\ mkdir /mnt/usb_storage/USB_DISK2 0000 system system" $OUT_DIR/root/init.rockchip.rc
sed -i 's/on property:ro.target.product=box/on property:ro.target.product=tablet/g' $OUT_DIR/root/init.rockchip.rc
sed -i '/export THIRD_VOLUME_STORAGE \/mnt\/USB_DISK0/c\ mkdir \/mnt\/usb_storage\/USB_DISK0 0755 system system' $OUT_DIR/root/init.rockchip.rc
sed -i '/mkdir \/mnt\/usb_storage 0755 system system/c\ mkdir \/mnt\/usb_storage\/USB_DISK1 0755 system system' $OUT_DIR/root/init.rockchip.rc
sed -i -e "/mkdir \/mnt\/usb_storage\/USB_DISK1 0755 system system/a\ mkdir /mnt/usb_storage/USB_DISK2 0755 system system" $OUT_DIR/root/init.rockchip.rc