android tablet의 최초 OS는 Honeycomb이 였습니다.
Honeycomb은 MTP가 default입니다.
그래서 이전에 Mass Storage로 변경해도 USB Mass Storage connection Notification이 오지 않습니다.
그래서 Tablet인 경우 Mass Storage로 변경 시 PC와 연결하는 UMS를 사용할 수 없는 문제가 발생합니다.
원인을 찾아 보니 phone UI만 com.android.systemui.usb.StorageNotification에 대한 listener가 등록되어 있어서 tablet UI에서는 event를 받지 못하는 상황이 였습니다.
framework/base/packages/SystemUI/src/com/android/systemui/statusbar 폴더를 보시면
phone, tablet이란 폴더가 있습니다.
여기서 grep -nr mStorageManager를 검색하여 보시면 PhoneStatusBarPolicy class에서만 listener를 등록해 주도록 되어 있습니다.
tablet에서 적절한 위치에 mStorageManager.registerListener()를 추가해 주셔야 합니다.
아래 capture를 보시면 ui가 설렁합니다.
tablet UI에서 Mass Storage 연결에 대해 고민하지 않는 듯한 인상입니다.
2012년 2월 13일 월요일
2012년 2월 9일 목요일
android MTP <-> Mass Storage
android ICS부터 MTP를 지원합니다.
Gingerbread의 Mass Storage 방식으로 수정해 보겠습니다.
overlay/frameworks/base/core/res/xml/storage_list.xml 입니다.
<StorageList xmlns:android="http://schemas.android.com/apk/res/android">
<!-- removable is not set in nosdcard product -->
<storage android:mountPoint="/mnt/sdcard"
android:storageDescription="@string/storage_usb"
android:primary="true"
android:emulated="true"
android:mtpReserve="100" />
</StorageList>
아래와 같이 바꿉니다.
<StorageList xmlns:android="http://schemas.android.com/apk/res/android">
<!-- removable is not set in nosdcard product -->
<storage android:mountPoint="/mnt/sdcard"
android:storageDescription="@string/storage_internal"
android:primary="true"
android:emulated="false"
android:allowMassStorage="true" />
</StorageList>
init.[PRODUCT_NAME].rc
fuse 관련된 부분 삭제 합니다.
on post-fs-data
# we will remap this as /mnt/sdcard with the sdcard fuse tool
mkdir /data/media 0775 media_rw media_rw
chown media_rw media_rw /data/media
on fs
mount ext4 ...
mount ext4 ...
mount ext4 ...
setprop ro.crypto.fuse_sdcard true
#/sdcard
export EXTERNAL_STORAGE /mnt/sdcard
mkdir /mnt/sdcard 0000 system system
symlink /mnt/sdcard /sdcard
# create virtual SD card at /mnt/sdcard, based on the /data/media directory
# daemon will drop to user/group system/media_rw after initializing
# underlying files in /data/media will be created with user and group media_rw (1023)
service sdcard /system/bin/sdcard /data/media 1023 1023
class late_start
init.[PRODUCT_NAME].usb.rc
on property:sys.usb.config=mtp
write /sys/class/android_usb/android0/enable 0
...
...
setprop sys.usb.state $sys.usb.config
on property:sys.usb.config=mtp,adb
...
...
start adbd
## Vold 2.0 Generic fstab
## - San Mehat (san@android.com)
##
#######################
## Regular device mount
##
## Format: dev_mount <label> <mount_point> <part> <sysfs_path1...>
## label - Label for the volume
## mount_point - Where the volume will be mounted
## part - Partition # (1 based), or 'auto' for first usable partition.
## <sysfs_path> - List of sysfs paths to source devices, must start with '/' character
## flags - (optional) Comma separated list of flags, must not contain '/' character
######################
dev_mount sdcard /mnt/sdcard auto [vfat mount 할 node] nonremovable,encryptable
그리고 BoardCongig.mk 또는 device.mk에 vold.fstab를 복사하는 문장 추가합니다.
PRODUCT_COPY_FILES += \
device/hardkernel/odroida4/vold.fstab:system/etc/vold.fstab \
...
persist.sys.usb.config=mtp를 mass_storage로 변경...
# Set default USB interface
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += \
persist.sys.usb.config=mass_storage
이렇게 수정하면 ICS에서도 Gingerbread의 화면을 보실 수 있습니다.
http://source.android.com/devices/tech/storage/config-example.html
Gingerbread의 Mass Storage 방식으로 수정해 보겠습니다.
overlay/frameworks/base/core/res/xml/storage_list.xml 입니다.
<StorageList xmlns:android="http://schemas.android.com/apk/res/android">
<!-- removable is not set in nosdcard product -->
<storage android:mountPoint="/mnt/sdcard"
android:storageDescription="@string/storage_usb"
android:primary="true"
android:emulated="true"
android:mtpReserve="100" />
</StorageList>
아래와 같이 바꿉니다.
<StorageList xmlns:android="http://schemas.android.com/apk/res/android">
<!-- removable is not set in nosdcard product -->
<storage android:mountPoint="/mnt/sdcard"
android:storageDescription="@string/storage_internal"
android:primary="true"
android:emulated="false"
android:allowMassStorage="true" />
</StorageList>
init.[PRODUCT_NAME].rc
fuse 관련된 부분 삭제 합니다.
on post-fs-data
# we will remap this as /mnt/sdcard with the sdcard fuse tool
mkdir /data/media 0775 media_rw media_rw
chown media_rw media_rw /data/media
on fs
mount ext4 ...
mount ext4 ...
mount ext4 ...
setprop ro.crypto.fuse_sdcard true
#/sdcard
export EXTERNAL_STORAGE /mnt/sdcard
mkdir /mnt/sdcard 0000 system system
symlink /mnt/sdcard /sdcard
# create virtual SD card at /mnt/sdcard, based on the /data/media directory
# daemon will drop to user/group system/media_rw after initializing
# underlying files in /data/media will be created with user and group media_rw (1023)
service sdcard /system/bin/sdcard /data/media 1023 1023
class late_start
init.[PRODUCT_NAME].usb.rc
on property:sys.usb.config=mtp
write /sys/class/android_usb/android0/enable 0
...
...
setprop sys.usb.state $sys.usb.config
on property:sys.usb.config=mtp,adb
...
...
start adbd
mtp를 mass_storage로 바꿉니다.
그리고 vold.fstab을 만듭니다.
## Vold 2.0 Generic fstab
## - San Mehat (san@android.com)
##
#######################
## Regular device mount
##
## Format: dev_mount <label> <mount_point> <part> <sysfs_path1...>
## label - Label for the volume
## mount_point - Where the volume will be mounted
## part - Partition # (1 based), or 'auto' for first usable partition.
## <sysfs_path> - List of sysfs paths to source devices, must start with '/' character
## flags - (optional) Comma separated list of flags, must not contain '/' character
######################
dev_mount sdcard /mnt/sdcard auto [vfat mount 할 node] nonremovable,encryptable
그리고 BoardCongig.mk 또는 device.mk에 vold.fstab를 복사하는 문장 추가합니다.
PRODUCT_COPY_FILES += \
device/hardkernel/odroida4/vold.fstab:system/etc/vold.fstab \
...
persist.sys.usb.config=mtp를 mass_storage로 변경...
# Set default USB interface
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += \
persist.sys.usb.config=mass_storage
이렇게 수정하면 ICS에서도 Gingerbread의 화면을 보실 수 있습니다.
2011년 11월 24일 목요일
android에서 USB Mass Storage 사용하기
ODROID-7/A에 USB Host가 있습니다.
거기에 USB 저장장치를 연결하여 자동으로 mnt/sdcard/external_storage란 폴더에 자동으로 마운트가 되도록 수정해 보려고 합니다.
ODROID-A에는 두개의 mmc가 있어서 galaxy s처럼 추가 외부 저장장치를 지원합니다.
vold와 MountService.java를 수정하였습니다.
vold.fstab에 bus node를 등록하면 UMS까지 지원하려고 했지만 usb mass 장치를 붙일때 마다 bus node의 인덱싱이 host1, host2 처럼 증가합니다.
vold의 구조가 동적 증가하는 장치를 지원하지 않는 구조 입니다.
fstab에 등록되어 있는 노드 객체를 만들고 등록된 Volume이 NetlinkEvent의 DEVPATH와 동일하면 처리합니다. 따라서 USB Host에 연결하는 장치와 같이 bus 이름이 증가하는 구조에는 적용이 안됩니다.
그리서 vold에서 강제로 mount 하도록 해 봤습니다.
kernel에 USB Mass Storage support를 추가 한다.
<*> USB Mass Storage support
그리고 system/vold/VolumeManager.cpp에 handleBlockEvent() 함수를 다음과 같이 수정합니다.
bool usb_storage_mounted = false;
bool second_netlinkevent = false;
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
거기에 USB 저장장치를 연결하여 자동으로 mnt/sdcard/external_storage란 폴더에 자동으로 마운트가 되도록 수정해 보려고 합니다.
ODROID-A에는 두개의 mmc가 있어서 galaxy s처럼 추가 외부 저장장치를 지원합니다.
vold와 MountService.java를 수정하였습니다.
vold.fstab에 bus node를 등록하면 UMS까지 지원하려고 했지만 usb mass 장치를 붙일때 마다 bus node의 인덱싱이 host1, host2 처럼 증가합니다.
vold의 구조가 동적 증가하는 장치를 지원하지 않는 구조 입니다.
fstab에 등록되어 있는 노드 객체를 만들고 등록된 Volume이 NetlinkEvent의 DEVPATH와 동일하면 처리합니다. 따라서 USB Host에 연결하는 장치와 같이 bus 이름이 증가하는 구조에는 적용이 안됩니다.
그리서 vold에서 강제로 mount 하도록 해 봤습니다.
kernel에 USB Mass Storage support를 추가 한다.
<*> USB Mass Storage support
그리고 system/vold/VolumeManager.cpp에 handleBlockEvent() 함수를 다음과 같이 수정합니다.
bool usb_storage_mounted = false;
bool second_netlinkevent = false;
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
if (second_netlinkevent) {
second_netlinkevent = false;
return;
}
char *usb_mass_node = "/devices/platform/s5p-ehci/usb";
if (usb_storage_mounted) {
umount("/mnt/sdcard/external_storage");
usb_storage_mounted = false;
SLOGE("unmounted USB Mass Storage");
} else {
int len = strlen(usb_mass_node);
if (strncmp(devpath, usb_mass_node, len) == 0) {
usleep(5000);
if (Fat::doMount("/dev/block/sda1", "/mnt/sdcard/external_storage", false, false, false,
1000, 1015, 0702, true)) {
SLOGE("%s failed to mount via VFAT (%s)\n", devpath, strerror(errno));
} else {
SLOGE("mounted USB Mass Storage");
usb_storage_mounted = true;
}
} else {
SLOGE("not USB Mass Storage");
}
}
second_netlinkevent = true;
}
코드를 조금 설명 드리면 USB Mass는 event가 두번 발생하여 second_netlinkevent를 통해 한번만 처리되도록 하였습니다.
usleep은 event가 발생시점에는 node가 없을 수 있기 때문에 대기 하였다 mount 시킵니다.
devpath가 "/devices/platform/s5p-ehci/usb" 까지 동일하고 usb1,2,3... 이렇게 증가 하기 때문에 여기까지 같다면 usb mass storage 장치가 연결된 걸로 처리 합니다.
물론 init.rc에 external_storage 노드를 처리하여야 합니다.
40 # create mountpoints
41 mkdir /mnt 0775 root system
42 mkdir /mnt/sdcard 0000 system system
43 mkdir /mnt/sdcard/external_storage 0000 system system
44
45 # Create cgroup mount point for cpu accounting
46 mkdir /acct
47 mount cgroup none /acct cpuacct
48 mkdir /acct/uid
49
50 # Backwards Compat - XXX: Going away in G*
51 symlink /mnt/sdcard /sdcard
52 symlink /mnt/sdcard/external_storage /sdcard1
그리고 vold에서 external_storage를 만드는 코드를 추가 합니다.
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 ", 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 ", false);
return 0;
}
rc = vm->mountVolume(argv[2]);
//codewalker
mkdir("/mnt/sdcard/external_storage", 0777);
} else if (!strcmp(argv[1], "unmount")) {
if (argc < 3 || argc > 4 || (argc == 4 && strcmp(argv[3], "force"))) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount [force]", false);
return 0;
}
bool force = false;
if (argc >= 4 && !strcmp(argv[3], "force")) {
이렇게 하면 Media Scan이 안되는 문제와 UMS가 안되는 문제가 있습니다.
Astro FileManager 같은데서 직접 폴더를 열어서 사용하는 상황에 맞겠죠.
그리고 여럿 예외 처리가 필요할 걸로 판단됩니다.
피드 구독하기:
글 (Atom)