레이블이 mass storage인 게시물을 표시합니다. 모든 게시물 표시
레이블이 mass storage인 게시물을 표시합니다. 모든 게시물 표시

2012년 2월 13일 월요일

android tablet ICS에서 Mass Storage UI가 나오지 않는 문제 해결

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월 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

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의 화면을 보실 수 있습니다.








http://source.android.com/devices/tech/storage/config-example.html

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


        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 같은데서 직접 폴더를 열어서 사용하는 상황에 맞겠죠.

그리고 여럿 예외 처리가 필요할 걸로 판단됩니다.