OP asked how to give access to a file in the following hierarchy: appdir/files/subdir/myfile
.
The answers provided here don't take subfolder into account, so I feel there's a room for improvement.
In order to access file in hierarchy, a consumer should have execute permission on each folder in a path in order to access (read, write, execute) files underneath it.
For API >= 24
Starting from API 24, Android restricts access to appdir
(a.k.a /data/data/appdir):
In order to improve the security of private files, the private
directory of apps targeting Android 7.0 or higher has restricted
access (0700). This setting prevents leakage of metadata of private
files, such as their size or existence.
The appdir
doesn't have world-execute permission, and therefore you can't cd
into it:
angler:/ $ cd /data/data
angler:/data/data $ cd com.myapp
/system/bin/sh: cd: /data/data/com.myapp: Permission denied
Bottom line: you can give world-readable permission to one of the files in your app's folder, but no other app (as long as they don't share the same Linux user ID) will be able to read them.
Not only that: attempt to pass a file://
URI to external app will trigger a FileUriExposedException.
For API < 24
The appdir
folder has world-execute permission by default:
shell:/ $ cd /data/data
shell:/data/data $ cd com.myapp
shell:/data/data/com.myapp $
Note that even the appdir/files
folder has world-execute permission:
shell:/data/data/com.myapp $ cd files
shell:/data/data/com.myapp/files $
But if you'll try to create a sub-folder (underneath files
folder), using this code:
File subdir = new File(context.getFilesDir(), "subfolder");
subdir.mkdir();
it won't have world-execute permission:
shell:/ $ cd /data/data/com.myapp/files
shell:/data/data/com.myapp/files $ cd subfolder
/system/bin/sh: cd: /data/data/com.myapp/files/subfolder: Permission denied
shell:/data/data/com.myapp/files $ run-as com.myapp
shell:/data/data/com.myapp $ cd files
shell:/data/data/com.myapp/files $ ls -l
total 72
drwx------ 3 u0_a226 u0_a226 4096 2016-11-06 11:49 subfolder
shell:/data/data/com.myapp/files $
Therefore, you have to explicitly give your newly created folder world-execute permission using File#setExecutable method (added in API 9):
subdir.setExecutable(true, false);
And only then, as suggested by others, you can create your file and give it world-readable permission:
File file = new File(subdir, "newfile");
if(!file.exists()) {
file.createNewFile();
file.setReadable(true, false);
}
Doing that will allow any external application read your file:
shell:/ $ cd /data/data/com.myapp/files
shell:/data/data/com.myapp/files $ cd subfolder
shell:/data/data/com.myapp/files/subfolder $ cat newfile > /sdcard/1
shell:/data/data/com.myapp/files/subfolder $ cd /sdcard
shell:/sdcard $ ls 1
1