android R 预制文件到App的外部私有目录(Android/data/)

1.用户需求

android R 预制文件到App的外部私有目录(Android/data/xx------>xx指应用的包名);

1.App的外部私有目录普通应用是没有权限创建的,只能使用自己应用的私有目录,首先尝试一下在系统应用(看看是否有权限)里面直接进行copy;

public boolean copy() {
        final String FROMPATH = "xxxx";
        final String TOPATH = "/mnt/sdcard/Android/data/xxx/xxx/xxx/xxx";
        String[] dirname = null;
        String[] filename =null;
        File file = new File(FROMPATH);
        if (file.exists()) {
            filename = file.list();
            Log.d(TAG, "filename.length = " + filename.length);
        }
        File filestore = new File(TOPATH);
        if (!filestore.exists()) {
            filestore.mkdir();
        }
        for (int k = 0; k < filename.length; k++) {
            Log.d(TAG, "the filename is " + filename[k]);
            InputStream fosfrom = null;
            OutputStream fosto = null;
            try {
                fosfrom = new FileInputStream(FROMPATH + "/" + filename[k]);
                fosto = new FileOutputStream(TOPATH + "/" + filename[k]);
                byte[] bt = new byte[1024];
                int c;
                while ((c = fosfrom.read(bt)) > 0) {
                    fosto.write(bt, 0, c);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (fosfrom!=null) {
                    fosfrom.close();
                }
                if (fosto!=null) {
                    fosto.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if(k == filename.length - 1){
                copyDone = true;
                Log.d(TAG, "copyDone value is  " + copyDone);
            }
        }
        Log.d(TAG, "Copy file success");
        return copyDone;
    }

也是提示权限问题。

05-24 07:35:35.255   596  1988 D CopyFile: the filename is 1-100_24d7a41fcc56e8e00a317eeda9de68a3.jpg
05-24 07:35:35.265   596  1988 W System.err: java.io.FileNotFoundException: /mnt/sdcard/Android/data/xxx/xxx/xxx/xxx/1-100_24d7a41fcc56e8e00a317eeda9de68a3.jpg: open failed: EACCES (Permission denied)
05-24 07:35:35.266   596  1988 W System.err:    at libcore.io.IoBridge.open(IoBridge.java:492)
05-24 07:35:35.267   596  1988 W System.err:    at java.io.FileOutputStream.<init>(FileOutputStream.java:236)
05-24 07:35:35.267   596  1988 W System.err:    at java.io.FileOutputStream.<init>(FileOutputStream.java:125)
05-24 07:35:35.267   596  1988 W System.err:    at com.android.systemui.CopyFileInitReceiver.copy(CopyFileInitReceiver.java:115)
05-24 07:35:35.271   298   308 I adbd    : jdwp connection from 1989
05-24 07:35:35.274   596  1988 W System.err:    at com.android.systemui.CopyFileInitReceiver$CopyFileThread.run(CopyFileInitReceiver.java:62)
05-24 07:35:35.274   596  1988 W System.err:    at java.lang.Thread.run(Thread.java:923)
05-24 07:35:35.275   596  1988 W System.err: Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
05-24 07:35:35.275   596  1988 W System.err:    at libcore.io.Linux.open(Native Method)
05-24 07:35:35.276   596  1988 W System.err:    at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
05-24 07:35:35.276   596  1988 W System.err:    at libcore.io.BlockGuardOs.open(BlockGuardOs.java:254)
05-24 07:35:35.276   596  1988 W System.err:    at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
05-24 07:35:35.276   596  1988 W System.err:    at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7573)
05-24 07:35:35.276   596  1988 W System.err:    at libcore.io.IoBridge.open(IoBridge.java:478)

2.首先定位到App的外部私有目录(Android/data/)的创建位置:

grep "Android/data/" * -Rn

A100_R11.0\frameworks\base\services\core\java\com\android\server\StorageManagerService.java
==========================================================================

private final class StorageManagerInternalImpl extends StorageManagerInternal {
...
/**
         * Check if fuse is running in target user, if it's running then setup its storage dirs.
         * Return true if storage dirs are mounted.
         */
        @Override
        public boolean prepareStorageDirs(int userId, Set<String> packageList,
                String processName) {
            synchronized (mLock) {
                if (!mFuseMountedUser.contains(userId)) {
                    Slog.w(TAG, "User " + userId + " is not unlocked yet so skip mounting obb");
                    return false;
                }
            }
            try {
                final IVold vold = IVold.Stub.asInterface(
                        ServiceManager.getServiceOrThrow("vold"));
                for (String pkg : packageList) {
                    final String packageObbDir =
                            String.format("/storage/emulated/%d/Android/obb/%s/", userId, pkg);
                    final String packageDataDir =
                            String.format("/storage/emulated/%d/Android/data/%s/",
                                    userId, pkg);

                    // Create package obb and data dir if it doesn't exist.
                    int appUid = UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
                    File file = new File(packageObbDir);
                    if (!file.exists()) {
                        vold.setupAppDir(packageObbDir, appUid);
                    }
                    file = new File(packageDataDir);
                    if (!file.exists()) {
                        vold.setupAppDir(packageDataDir, appUid);
                    }
                }
            } catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
                Slog.e(TAG, "Unable to create obb and data directories for " + processName,e);
                return false;
            }
            return true;
        }
...
}
//那么就监听一下开机广播,然后创建客户需要的目录
private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
            Preconditions.checkArgument(userId >= 0);

            try {
                if (Intent.ACTION_USER_ADDED.equals(action)) {
                    final UserManager um = mContext.getSystemService(UserManager.class);
                    final int userSerialNumber = um.getUserSerialNumber(userId);
                    mVold.onUserAdded(userId, userSerialNumber);
                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                    synchronized (mVolumes) {
                        final int size = mVolumes.size();
                        for (int i = 0; i < size; i++) {
                            final VolumeInfo vol = mVolumes.valueAt(i);
                            if (vol.mountUserId == userId) {
                                vol.mountUserId = UserHandle.USER_NULL;
                                mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
                            }
                        }
                    }
                    mVold.onUserRemoved(userId);
                }else if(Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
                    try {
                            final IVold vold = IVold.Stub.asInterface(
                                    ServiceManager.getServiceOrThrow("vold"));
                            String pkg = "xxx";
                            Slog.e(TAG, "UserHandle.USER_SYSTEM= " +UserHandle.USER_SYSTEM +",userId="+userId);
                            // userId =UserHandle.USER_SYSTEM;
                            //int userId = 0;
                            final String packageObbDir =
                                    String.format("/storage/emulated/%d/Android/obb/%s/", userId, pkg);
                            final String packageDataDir1 =
                                    String.format("/storage/emulated/%d/Android/data/%s/sites/data/filepool",
                                            userId, pkg);

                            // Create package obb and data dir if it doesn't exist.
                            int appUid = UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
                            int appUid1 = UserHandle.getUid(UserHandle.USER_ALL, mPmInternal.getPackage(pkg).getUid());
                            Slog.e(TAG, "filestore appUid= " + appUid+",appUid1="+appUid1);
                            File file = new File(packageObbDir);
                            if (!file.exists()) {
                                vold.setupAppDir(packageObbDir, appUid);
                            }
                            file = new File(packageDataDir1);
                            if (!file.exists()) {
                                //不过这里创建了目录,但是权限不够,第三方应用无法进行文件读写,所以需要授权
                                vold.setupAppDir(packageDataDir1, appUid);
                                Slog.e(TAG, "packageDataDir1 appUid= " + appUid);
                                //创建完成后通知,系统应用copy资源到指定目录
                                Intent scanIntent = new Intent("android.djdg.setupAppDir");
                                mContext.sendBroadcast(scanIntent);
                            }

                    } catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
                        Slog.e(TAG, "Unable to create obb and data directories for " +e);
                    }
                }else if ("android.djdg.copy.success".equals(intent.getAction())) {
                    Slog.e(TAG, "接收广播 android.djdg.copy.success");
                    try {
                        final IVold vold = IVold.Stub.asInterface(
                                    ServiceManager.getServiceOrThrow("vold"));
                        String pkg = "com.mineduapp.aprendoencasa";
                        final String packageDataDir =
                                    String.format("/storage/emulated/%d/Android/data/%s/sites/data/filepool",
                                            userId, pkg);
                        // Create package obb and data dir if it doesn't exist.
                        int appUid = UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
                        Slog.e(TAG, "filestore appUid= " + appUid);
                        File file = new File(packageDataDir);
                        vold.fixupAppDir(packageDataDir, appUid);
                        Slog.e(TAG, "fixupAppDir packageDataDir appUid= " + appUid);
                    } catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
                        Slog.e(TAG, "Unable to create obb and data directories for " +e);
                    }
                }
            } catch (Exception e) {
                Slog.wtf(TAG, e);
            }
        }
    };

给文件夹授权,更具AIDL服务的方法定位

image.png


A100_R11.0\system\vold\VoldNativeService.cpp
=============================================================
binder::Status VoldNativeService::setupAppDir(const std::string& path, int32_t appUid) {
    ENFORCE_SYSTEM_OR_ROOT;
    CHECK_ARGUMENT_PATH(path);
    ACQUIRE_LOCK;

    return translate(VolumeManager::Instance()->setupAppDir(path, appUid));
}







A100_R11.0\system\vold\VolumeManager.cpp
=============================================================

int VolumeManager::setupAppDir(const std::string& path, int32_t appUid, bool fixupExistingOnly) {
    // Only offer to create directories for paths managed by vold
    if (!StartsWith(path, "/storage/")) {
        LOG(ERROR) << "Failed to find mounted volume for " << path;
        return -EINVAL;
    }

    // Find the volume it belongs to
    auto filter_fn = [&](const VolumeBase& vol) {
        if (vol.getState() != VolumeBase::State::kMounted) {
            // The volume must be mounted
            return false;
        }
        if ((vol.getMountFlags() & VolumeBase::MountFlags::kVisible) == 0) {
            // and visible
            return false;
        }
        if (vol.getInternalPath().empty()) {
            return false;
        }
        if (vol.getMountUserId() != USER_UNKNOWN &&
            vol.getMountUserId() != multiuser_get_user_id(appUid)) {
            // The app dir must be created on a volume with the same user-id
            return false;
        }
        if (!path.empty() && StartsWith(path, vol.getPath())) {
            return true;
        }

        return false;
    };
    auto volume = findVolumeWithFilter(filter_fn);
    if (volume == nullptr) {
        LOG(ERROR) << "Failed to find mounted volume for " << path;
        return -EINVAL;
    }
    // Convert paths to lower filesystem paths to avoid making FUSE requests for these reasons:
    // 1. A FUSE request from vold puts vold at risk of hanging if the FUSE daemon is down
    // 2. The FUSE daemon prevents requests on /mnt/user/0/emulated/<userid != 0> and a request
    // on /storage/emulated/10 means /mnt/user/0/emulated/10
    const std::string lowerPath =
            volume->getInternalPath() + path.substr(volume->getPath().length());

    const std::string volumeRoot = volume->getRootPath();  // eg /data/media/0

    if (fixupExistingOnly && (access(lowerPath.c_str(), F_OK) != 0)) {
        // Nothing to fixup
        return OK;
    }

    if (volume->getType() == VolumeBase::Type::kPublic) {
        // On public volumes, we don't need to setup permissions, as everything goes through
        // FUSE; just create the dirs and be done with it.
        return fs_mkdirs(lowerPath.c_str(), 0700);
    }

    // Create the app paths we need from the root
    return PrepareAppDirFromRoot(lowerPath, volumeRoot, appUid, fixupExistingOnly);
}

int VolumeManager::fixupAppDir(const std::string& path, int32_t appUid) {
    if (IsSdcardfsUsed()) {
        //sdcardfs magically does this for us
        return OK;
    }
    return setupAppDir(path, appUid, true /* fixupExistingOnly */);
}








##最后确认App的外部私有目录授权是在 A100_R11.0\system\vold\Utils.cpp文件
A100_R11.0\system\vold\Utils.cpp
=============================================================
int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid,
                          bool fixupExisting) {
    long projectId;
    size_t pos;
    int ret = 0;
    bool sdcardfsSupport = IsSdcardfsUsed();

    // Make sure the Android/ directories exist and are setup correctly
    ret = PrepareAndroidDirs(root);
    if (ret != 0) {
        LOG(ERROR) << "Failed to prepare Android/ directories.";
        return ret;
    }

    // Now create the application-specific subdir(s)
    // path is something like /data/media/0/Android/data/com.foo/files
    // First, chop off the volume root, eg /data/media/0
    std::string pathFromRoot = path.substr(root.length());

    uid_t uid = appUid;
    gid_t gid = AID_MEDIA_RW;
    std::vector<gid_t> additionalGids;
    std::string appDir;

    // Check that the next part matches one of the allowed Android/ dirs
    if (StartsWith(pathFromRoot, kAppDataDir)) {
        appDir = kAppDataDir;
        if (!sdcardfsSupport) {
            gid = AID_EXT_DATA_RW;
            // Also add the app's own UID as a group; since apps belong to a group
            // that matches their UID, this ensures that they will always have access to
            // the files created in these dirs, even if they are created by other processes
            additionalGids.push_back(uid);
        }
    } else if (StartsWith(pathFromRoot, kAppMediaDir)) {
        appDir = kAppMediaDir;
        if (!sdcardfsSupport) {
            gid = AID_MEDIA_RW;
        }
    } else if (StartsWith(pathFromRoot, kAppObbDir)) {
        appDir = kAppObbDir;
        if (!sdcardfsSupport) {
            gid = AID_EXT_OBB_RW;
            // See comments for kAppDataDir above
            additionalGids.push_back(uid);
        }
    } else {
        LOG(ERROR) << "Invalid application directory: " << path;
        return -EINVAL;
    }

    // mode = 770, plus sticky bit on directory to inherit GID when apps
    // create subdirs
    //在这里对文件进行授权
    /*mode_t  mode = S_IRWXU | S_IRWXG | S_ISGID ;*/
   /********update start ********/
    std::string::size_type n;
    mode_t mode ;
    if ((n = pathFromRoot.find("xxx")) != std::string::npos) {
        mode = S_IRWXU | S_IRWXG | S_ISGID | S_IRWXO ;
    }else{
        mode = S_IRWXU | S_IRWXG | S_ISGID ;
    }
    /********update end********/
      .............

    return OK;
}

mode_t 是文件权限值。

mode_t 是文件权限值1

#define S_IFMT 00170000
  13#define S_IFSOCK 0140000
  14#define S_IFLNK 0120000
  15#define S_IFREG 0100000
  16#define S_IFBLK 0060000
  17#define S_IFDIR 0040000
  18#define S_IFCHR 0020000
  19#define S_IFIFO 0010000
  20#define S_ISUID 0004000
  21#define S_ISGID 0002000
  22#define S_ISVTX 0001000
  23
  24#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
  25#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  26#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  27#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
  28#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
  29#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
  30#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
  31
  32#define S_IRWXU 00700
  33#define S_IRUSR 00400
  34#define S_IWUSR 00200
  35#define S_IXUSR 00100
  36
  37#define S_IRWXG 00070
  38#define S_IRGRP 00040
  39#define S_IWGRP 00020
  40#define S_IXGRP 00010
  41
  42#define S_IRWXO 00007
  43#define S_IROTH 00004
  44#define S_IWOTH 00002
  45#define S_IXOTH 00001
  46
  47#endif
  48
  49#ifdef __KERNEL__
  50#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
  51#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
  52#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
  53#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
  54#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
Linux
头文件库:
#include <sys/stat.h>
#include <sys/types.h>
函数原型:
int mkdir(const char *pathname, mode_t mode);
函数说明:
mkdir()函数以mode方式创建一个以参数pathname命名的目录,mode定义新创建目录的权限。
返回值:
若目录创建成功,则返回0;否则返回-1,并将错误记录到全局变量errno中。
mode方式:可多个权限相或,如0777表示mode = S_IRWXU | S_IRWXG | S_ISGID | S_IRWXO
代表:该文件所有者拥有读,写和执行操作的权限,该文件用户组拥有可读、可执行的权限,其他用户拥有可读、可执行的权限。

文件copy完成后,如果需要重新复原目录权限的话需要调用fixupAppDir方法来进行修正,可以自定义一个广播来通知修正

int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid,
                          bool fixupExisting) {

........

if (fixupExisting && access(pathToCreate.c_str(), F_OK) == 0) {
            // Fixup all files in this existing directory with the correct UID/GID
            // and project ID.
            mode = S_IRWXU | S_IRWXG | S_ISGID ;
            //LOG(ERROR) << "fixupExisting: " << pathToCreate.c_str();
            ret = FixupAppDir(pathToCreate, mode, uid, gid, projectId);
            ret = 0;//这里做一下修正处理,不做处理user版本会有些问题,应用读取不了数据
        } else {
            ret = PrepareDirWithProjectId(pathToCreate, mode, uid, gid, projectId);
        }
if (ret != 0) {
            return ret;
        }

        if (depth == 0) {
            // Set the default ACL on the top-level application-specific directories,
            // to ensure that even if applications run with a umask of 0077,
            // new directories within these directories will allow the GID
            // specified here to write; this is necessary for apps like
            // installers and MTP, that require access here.
            //
            // See man (5) acl for more details.
            ret = SetDefaultAcl(pathToCreate, mode, uid, gid, additionalGids);
            if (ret != 0) {
                return ret;
            }

            if (!sdcardfsSupport) {
                // Set project ID inheritance, so that future subdirectories inherit the
                // same project ID
                ret = SetQuotaInherit(pathToCreate);
                if (ret != 0) {
                    return ret;
                }
            }
        }

        depth++;
}

copy完成后通知一下服务进行修正,

try {
                Intent intent = new Intent("android.djdg.copy.success");
                //Intent.EXTRA_USER_HANDLE,StorageManagerService.java 广播接收器里面有做参数解析,所以带上参数避免导致系统重启
                intent.putExtra("android.intent.extra.user_handle",0);
                mContext.sendBroadcastAsUser(intent, new UserHandle(0));
                // mContext.sendBroadcast(intent);
            }catch (Exception e) {
                e.printStackTrace();
            } 
2022-05-28 09:50:52.057 7376-9977/system_process W/ActivityManager: Unable to start service Intent { act=android.media.IMediaScannerService cmp=com.android.providers.media/.MediaScannerService (has extras) } U=0: not found
2022-05-28 09:50:52.066 7376-9977/system_process E/ActivityManager: Sending non-protected broadcast android.djdg.copy.success from system 7532:com.android.systemui/u0a97 pkg com.android.systemui
    java.lang.Throwable
        at com.android.server.am.ActivityManagerService.checkBroadcastFromSystem(ActivityManagerService.java:15999)
        at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:16580)
        at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:16016)
        at com.android.server.am.ActivityManagerService.broadcastIntentWithFeature(ActivityManagerService.java:16832)
        at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2267)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2890)
        at android.os.Binder.execTransactInternal(Binder.java:1159)
        at android.os.Binder.execTransact(Binder.java:1123)
2022-05-28 09:50:52.068 7376-9977/system_process E/ActivityManager: Sending non-protected broadcast android.djdg.copy.success from system 7532:com.android.systemui/u0a97 pkg com.android.systemui
    java.lang.Throwable
        at com.android.server.am.ActivityManagerService.checkBroadcastFromSystem(ActivityManagerService.java:15999)
        at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:16676)
        at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:16016)
        at com.android.server.am.ActivityManagerService.broadcastIntentWithFeature(ActivityManagerService.java:16832)
        at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2267)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2890)
        at android.os.Binder.execTransactInternal(Binder.java:1159)
        at android.os.Binder.execTransact(Binder.java:1123)
2022-05-28 09:50:52.072 7376-7407/system_process I/DropBoxManagerService: add tag=system_server_wtf isTagEnabled=true flags=0x2
2022-05-28 09:50:52.084 7376-7460/system_process E/AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: StorageManagerService
    java.lang.RuntimeException: Error receiving broadcast Intent { act=android.djdg.copy.success flg=0x10 } in com.android.server.StorageManagerService$1@c560dac
        at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1590)
        at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.os.HandlerThread.run(HandlerThread.java:67)
     Caused by: java.lang.IllegalArgumentException
        at com.android.internal.util.Preconditions.checkArgument(Preconditions.java:37)
        at com.android.server.StorageManagerService$1.onReceive(StorageManagerService.java:852)
        at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1580)
        at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2) 
        at android.os.Handler.handleCallback(Handler.java:938) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.os.HandlerThread.run(HandlerThread.java:67) 

方式2:也可以直接更改映射地址到oem目录去,省去开机copy的步骤;

方式3:直接修改File.java文件,线判断(Android/data/)是否有文件存在,如果没有就去oem分区下查找数据,如果有则重定向目录至oem/下的位置(此方式未验证);

./libcore/ojluni/src/main/java/java/io/File.java
================================================================================
 /**
     * Creates a new <code>File</code> instance by converting the given
     * pathname string into an abstract pathname.  If the given string is
     * the empty string, then the result is the empty abstract pathname.
     *
     * @param   pathname  A pathname string
     * @throws  NullPointerException
     *          If the <code>pathname</code> argument is <code>null</code>
     */
    public File(String pathname) {
        if (pathname == null) {
            throw new NullPointerException();
        }
        String tempPath = fs.normalize(pathname);
        this.path = exitPath(tempPath);
        this.prefixLength = fs.prefixLength(this.path);
    }

    
    /**
     * Avoid dead cycles
     * @param path File path
     * @return File path
     */
    public File(String pathname,boolean bool) {
        if (pathname == null) {
            throw new NullPointerException();
        }
        this.path = fs.normalize(pathname);
        this.prefixLength = fs.prefixLength(this.path);
    }

其他几个构造函数也是这样处理
....

        String tempPath = fs.normalize(p);
        this.path = exitPath(tempPath);
        this.prefixLength = fs.prefixLength(this.path);
....

    /**
     * Partial address special handling
     * @param path File path
     * @return File path
     */
    private String exitPath(String path){
        String packageNameFile= "xxx/xxx";
        if (path.contains(packageNameFile) && path.contains("/Android/data/")){
            File file =new File(path,false);
            if (!file.exists()){
                String oem = "/mnt/oem/";
                int _pathIndex= path.indexOf("/Android/data/");
                String tmpTop = path.substring(0,_pathIndex);
                String pathTemp = path.replace(tmpTop,oem);
                java.lang.System.out.print("File pathTemp="+pathTemp);
                file = new File(pathTemp,false);
                if (file.exists()){
                    return file.getPath();
                }
            }

        }
        return path;
    }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容