Android应用获取外部盘符时,默认创建Android/data/包名/files目录

在应用App的代码中调用如下代码:
 

context.getExternalFilesDir("");

这段代码,会在主动创建目录:./Android/data/包名/files;

我们来一下这个调用栈:

buildPaths:934, Environment (android.os)
buildExternalStorageAppFilesDirs:131, Environment$UserEnvironment (android.os)
buildExternalStorageAppFilesDirs:686, Environment (android.os)
getExternalFilesDirs:633, ContextImpl (android.app)
getExternalFilesDir:626, ContextImpl (android.app)
getExternalFilesDir:242, ContextWrapper (android.content)
getFile:98, MainActivity (cn.rocky)
access$100:25, MainActivity (cn.rocky)
handleMessage:83, MainActivity$1 (cn.rocky)
dispatchMessage:106, Handler (android.os)
loop:164, Looper (android.os)
main:6548, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:438, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:857, ZygoteInit (com.android.internal.os)

这些代码一个来分析一下:
frameworks/base/core/java/android/content/Context.java

public abstract File getExternalFilesDir(@Nullable String type);

上面的实现代码:frameworks/base/core/java/android/app/ContextImpl.java

        @Override
    public File getExternalFilesDir(String type) {
        // Operates on primary external storage
        final File[] dirs = getExternalFilesDirs(type);
        return (dirs != null && dirs.length > 0) ? dirs[0] : null;
    }

    @Override
    public File[] getExternalFilesDirs(String type) {
        synchronized (mSync) {
            File[] dirs = Environment.buildExternalStorageAppFilesDirs(getPackageName());
            if (type != null) {
                dirs = Environment.buildPaths(dirs, type);
            }
            return ensureExternalDirsExistOrFilter(dirs);
        }
    }

    /**
     * Ensure that given directories exist, trying to create them if missing. If
     * unable to create, they are filtered by replacing with {@code null}.
     */
    private File[] ensureExternalDirsExistOrFilter(File[] dirs) {
        File[] result = new File[dirs.length];
        for (int i = 0; i < dirs.length; i++) {
            File dir = dirs[i];
            if (!dir.exists()) {//判断目录是否存在,如果不存在,走if
                if (!dir.mkdirs()) {//创建目录,创建目录失败,走if,否则走else
                    // recheck existence in case of cross-process race
                    if (!dir.exists()) {//再次判断目录是否存在,不存在,走if,通过binder服务来创建目录,因为可能是权限不够导致
                        // Failing to mkdir() may be okay, since we might not have
                        // enough permissions; ask vold to create on our behalf.
                        final IStorageManager storageManager = IStorageManager.Stub.asInterface(
                                ServiceManager.getService("mount"));
                        try {
                            final int res = storageManager.mkdirs(
                                    getPackageName(), dir.getAbsolutePath());
                            if (res != 0) {
                                Log.w(TAG, "Failed to ensure " + dir + ": " + res);
                                dir = null;
                            }
                        } catch (Exception e) {
                            Log.w(TAG, "Failed to ensure " + dir + ": " + e);
                            dir = null;
                        }
                    }
                }
            }
            result[i] = dir;
        }
        return result;
    }

frameworks/base/core/java/android/os/Environment.java

    public static final String DIR_ANDROID = "Android";
    private static final String DIR_DATA = "data";
    private static final String DIR_OBB = "obb";
    private static final String DIR_FILES = "files";

    /**
     * Generates the path to an application's files.
     * @hide
     */
    public static File[] buildExternalStorageAppFilesDirs(String packageName) {
        throwIfUserRequired();
        return sCurrentUser.buildExternalStorageAppFilesDirs(packageName);
    }

    /**
     * Append path segments to each given base path, returning result.
     *
     * @hide
     */
    public static File[] buildPaths(File[] base, String... segments) {
        File[] result = new File[base.length];
        for (int i = 0; i < base.length; i++) {
            result[i] = buildPath(base[i], segments);
        }
        return result;
    }
    /**
     * Append path segments to given base path, returning result.
     *  循环创建目录结构
     * @hide
     */
    public static File buildPath(File base, String... segments) {
        File cur = base;
        for (String segment : segments) {
            if (cur == null) {
                cur = new File(segment);
            } else {
                cur = new File(cur, segment);
            }
        }
        return cur;
    }

    /** {@hide} */
    public static class UserEnvironment {
        //获取外部的盘符根目录
        public File[] getExternalDirs() {
            final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId,
                    StorageManager.FLAG_FOR_WRITE);
            final File[] files = new File[volumes.length];
            for (int i = 0; i < volumes.length; i++) {
                files[i] = volumes[i].getPathFile();
            }
            return files;
        }
        //构造目录结构
        public File[] buildExternalStorageAppFilesDirs(String packageName) {
            return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);
        }
    }

 

这里的代码比较简单,至此,所有挂载的盘符都已经了对应用的Android/data/包名/files目录;

 

 

 

你可能感兴趣的:(Android框架)