IT_Programming/Android_Java

Android 확장(추가) SDCard 경로 얻기.

JJun ™ 2013. 7. 16. 07:50

 


 출처: http://lsit81.tistory.com/entry/추가-Micro-SD-Card-경로-얻기


 

 

안녕하세요. 

최근에 출시된 Android 단말기들은 Micro SD Card를 삽입하지 않아도 

기본적으로 내장 메모리를 가지고 있으며, 추가적으로 sd card를 삽입할 수도 있게

되었습니다.

 

문제는 Android 기본 API로는 이 추가적으로 삽입된 sd card의 경로는 알수가 없다는 것 입니다. 

일반적으로는 /mnt/sdcard/external_sd/ 라는 경로를 가지고 있게되는데요...

문제는 이 경로는 제조사측에서 마음이 바뀌면 충분히 경로 명이 바뀔 수 있다는 것 입니다. 

그래서 추가적으로 삽입된 sd card의 경로를 가져올 수 있는 코드를 한번 작성해 보았습니다

 

동작방식


     1. Android는 리눅스 커널기반에서 동작되므로 모든 장치는 mount 되어야만
        사용할 수 있습니다.

    

     2. mount에 대한 정보는 "/system/etc/vold.fstab", "/proc/mounts" 파일로

         관리하고 있습니다.

 

     3. 이 두가지 파일을 이용하여 mount된 Filesystem의 Path를 얻어 옵니다.

 

     4. 추출된 Filesystem List에서 disk의 크기를 구하여 1Gbyte 미만의 Filesystem은

         리스트에서 제거합니다. 

 

     5. 얻고자 하는 Filesystem만 올수 있도록 알려진 filesystem이 포함된 경우

         해당 filsystem을 list에서 제거합니다. 


 

 

 

소스 보기 

 

/**

 * 추가 적인 외부 확장 SDCard path 얻기.
 * 조건으로 걸러진 최종 String List size가 1이 아니면 null 리턴
 * @return
 */
public static String getMicroSDCardDirectory() {
    List<String> mMounts = readMountsFile();
    List<String> mVold = readVoldFile();
     
    for (int i=0; i < mMounts.size(); i++) {
        String mount = mMounts.get(i);
         
        if (!mVold.contains(mount)) {
            mMounts.remove(i--);
            continue;
        }
         
        File root = new File(mount);
        if (!root.exists() || !root.isDirectory()) {
            mMounts.remove(i--);
            continue;
        }
         
        if (!isAvailableFileSystem(mount)) {
            mMounts.remove(i--);
            continue;
        }
         
        if (!checkMicroSDCard(mount)) {
            mMounts.remove(i--);
        }
    }
     
    if (mMounts.size() == 1) {
        return mMounts.get(0);
    }
     
    return null;
}
 
private static List<String> readMountsFile() {
    /**
     * Scan the /proc/mounts file and look for lines like this:
     * /dev/block/vold/179:1 /mnt/sdcard

     * vfatrw,dirsync,nosuid,nodev,noexec,relatime,uid=1000,gid=1015,

     * fmask=0602,dmask=0602,allow_utime=0020,codepage=cp437,

     * iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0

     

     * When one is found, split it into its elements
     * and then pull out the path to the that mount point
     * and add it to the arraylist
     */
    List<String> mMounts = new ArrayList<String>();
 
    try {
        Scanner scanner = new Scanner(new File("/proc/mounts"));
         
        while (scanner.hasNext()) {
            String line = scanner.nextLine();
             
            if (line.startsWith("/dev/block/vold/")) {
                String[] lineElements = line.split("[ \t]+");
                String element = lineElements[1];
                                     
                mMounts.add(element);
            }
        }
    } catch (Exception e) {
        // Auto-generated catch block
        e.printStackTrace();
    }
     
    return mMounts;
}
 
private static List<String> readVoldFile() {
    /**
     * Scan the /system/etc/vold.fstab file and look for lines like this:
     * dev_mount sdcard /mnt/sdcard 1 /devices/platform/

     * s3c-sdhci.0/mmc_host/mmc0

     *

     * When one is found, split it into its elements
     * and then pull out the path to the that mount point
     * and add it to the arraylist
     */
     
    List<String> mVold = new ArrayList<String>();
     
    try {
        Scanner scanner = new Scanner(new File("/system/etc/vold.fstab"));
         
        while (scanner.hasNext()) {
            String line = scanner.nextLine();
             
            if (line.startsWith("dev_mount")) {
                String[] lineElements = line.split("[ \t]+");
                String element = lineElements[2];
                 
                if (element.contains(":")) {
                    element = element.substring(0, element.indexOf(":"));
                }
 
                mVold.add(element);
            }
        }
    } catch (Exception e) {
        // Auto-generated catch block
        e.printStackTrace();
    }
     
    return mVold;
}
 
private static boolean checkMicroSDCard(String fileSystemName) {
    StatFs statFs = new StatFs(fileSystemName);
     
    long totalSize = (long)statFs.getBlockSize() * statFs.getBlockCount();
     
    if (totalSize < onE_GIGABYTE) {
        return false;
    }
         
    return true;
}
 
private static boolean isAvailableFileSystem(String fileSystemName) {
    final String[]  unAvailableFileSystemList = {"/dev", "/mnt/asec", "/mnt/obb", "/system", "/data", "/cache", "/efs", "/firmware"};  

 

// 알려진 File System List입니다.

     
    for (String name : unAvailableFileSystemList) {
        if (fileSystemName.contains(name) == true) {
            return false;
        }
    }
     
    if (Environment.getExternalStorageDirectory().getAbsolutePath().equals(fileSystemName) == true) {
        /** 안드로이드에서 제공되는 getExternalStorageDirectory() 경로와 같은 경로일 경우에는 추가로 삽입된 SDCard가 아니라고 판단하였습니다. **/
        return false;
    }
     
    return true;
}

 

 

 

History

 

* 아래는 2012.05.14일에 작성된 내용으로 df 명령을 통해 외부 sdcard 경로를

   가져왔으나 일부 디바이스에서 문제가 발견되어 위 내용으로 수정하였으며,

   이 내용은 History를 관리하기위해 남겨둔 글 입니다. 

 

그래서 df 명령을 이용하여 mount된 File System 정보를 얻어 아래는 "df" 시

넘어오는 데이터 입니다. 기준은 갤럭시 s3입니다.


Filesystem             Size   Used   Free   Blksize

/dev                     389M    84K   389M   4096

/mnt/asec            389M     0K   389M    4096

/mnt/obb              389M     0K   389M    4096

/system                   1G     1G   605M    4096

/data                     10G     1G     9G      4096

/cache               1007M    17M   990M   4096

/efs                      19M     8M    11M    4096

/mnt/sdcard           10G     1G     9G     4096

/mnt/extSdCard        6G     1G     5G     4096


 

위 내용을 parsing하여 추가 sd card가 존재하는지 여부를 판단하여 존재할 경우

해당 위치를 가져올 수 있게 하였습니다.  다만 추가 sd card의 위치는 "android.os.Environment.getExternalStorageDirectory()"로 얻은 경로 밑에 있다고 가정하였습니다. 그리고 알려진 File System에 대한 정보는 무시 처리하였습니다.

 

 

* 최종 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
public static String getMicroSDCardDirectory() {
    InputStreamReader   inputStream = null;
    BufferedReader      reader = null;
     
    try {
        Process             dfProcess = Runtime.getRuntime().exec("df");
        String              string = null;
        String[]            column;
         
        final int       indexOfFileSystem = 0;
        final int       indexOfSize = 1;
 
        inputStream = new InputStreamReader(dfProcess.getInputStream());
        reader      = new BufferedReader(inputStream);
         
        long    startTime   = System.currentTimeMillis();
        long    endTime     = startTime;
         
        while (true) {
            if (!reader.ready()) {
                endTime = System.currentTimeMillis();
                if (endTime - startTime <= 100) {
                    continue;
                }
 
                break;
            }
             
            string = reader.readLine();
             
            if (string == null) {
                break;
            }
             
            column = string.split("[ \t]+");
             
            if (column.length < 4) {
                /**
                 * df명령 실행시 아래와 같은 포멧으로 column이 구성된다.
                 * Filesystem  Size   Used   Free   Blksize
                 **/
                continue;
            }
             
            if (column[indexOfSize].toUpperCase().contains("G") == false) {
                /** File System의 크기가 Giga byte 이하는 무시한다. **/
                continue;
            }
             
            if (isAvailableFileSystem(column[indexOfFileSystem]) == true) {
                return column[indexOfFileSystem];
            }
        }
         
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            inputStream = null;
        }
         
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
     
    return null;
}
 
private static boolean isAvailableFileSystem(String fileSystemName) {
    final String[]  unAvailableFileSystemList = {"/dev", "/mnt/asec", "/mnt/obb", "/system", "/data", "/cache", "/efs"};        // 알려진 File System List입니다.
     
    for (String name : unAvailableFileSystemList) {
        if (fileSystemName.contains(name) == true) {
            return false;
        }
    }
     
    if (Environment.getExternalStorageDirectory().getAbsolutePath().equals(fileSystemName) == true) {
        /** 안드로이드에서 제공되는 getExternalStorageDirectory() 경로와 같은 경로일 경우에는 추가로 삽입된 SDCard가 아니라고 판단하였습니다. **/
        return false;
    }
     
    return true;
}