Android context.getFilesDir() sometimes returns root folder - android

On first time app launch I create a file using context.getFilesDir() to get the storage path.
This works fine, except for a very small number of cases this method returns the "/" root folder. As a result the app crashes with:
java.io.FileNotFoundException: /my_filename (Read-only file system)
When I debug on my device the file path is:
/data/data/my.package/files/my_filename
This code is called in the onCreate of a SherlockActivity. So the context is that of the activity. Strangely, the failure is rare and there is no commonality among the devices where it is failing.
Update:
Based on the feedback so far, this code is supposed to work and the occasional failures may be due to odd devices. Trying to work around this issue is an overkill for my use case where file storage is not really mandatory. I'll try to migrate my code to use SharedPreferences.

There is a confirmed bug in all pre-4.4 Android devices, which occurs rarely. The reason for the bug is a racing condition in creating app private directory on first launch.
The suggested fix (by Google Android team member) is to try the Context.getFilesDir() method again after first one failed with a "null" return value.

use
Environment.getExternalStorageDirectory().getAbsolutePath();
to get the external storage directory.
use
Environment.getCacheDir();
for using the application's sandboxed cache directory.

Related

Ionic File Read / Write issue when uninstall / reinstall app (Android)

I have an app that write JSON backups and read them in production since december 2020.
Lately, without any update for this part, the behaviour of Ionic File changed.
I figured out in another thread that apps aren't allowed anymore to read and write in root directory since Android 11, so I changed it to the root/Documents directory, but I sitll have a strange issue.
Here's the behaviour: the app can write and read the file, and re-write it if necessary.
Everything's going well until I uninstall and reinstall the app, then neither read or write work.
In this case, IonicFile.readAsText returns null even if the file exists and is filled.
https://github.com/sebferrer/life-notes/blob/master/front/src/app/infra/importer-exporter.service.ts#L86
And IonicFile.writeExistingFile returns an error with the message "undefinedNaN".
https://github.com/sebferrer/life-notes/blob/master/front/src/app/infra/importer-exporter.service.ts#L146
Here's a workflow to help understand the issue:
I install the app. The file doesn't exist yet.
I try to read the file via IonicFile.readAsText: that throws the NOT_FOUND_ERR error. This is the expected behaviour as the file doesn't exist yet.
I create the file with IonicFile.createFile. Success.
I write on it via IonicFile.writeExistingFile. Success.
I write on it again via IonicFile.writeExistingFile. Success.
I read it via IonicFile.readAsText. Success: IonicFile.readAsText returns the file content.
I uninstall the app. The file created before still exists and didn't change.
I reinstall the app. The file created before still exists and didn't change.
I try to read the file as before via IonicFile.readAsText. Unexpected behaviour: no error is thrown, but IonicFile.readAsText returns null instead of the file content.
I try to write on the file as before via IonicFile.writeExistingFile. Unexpected behaviour: IonicFile.writeExistingFile throws an error this "undefinedNaN" message.
It's like when I uninstall and reinstall the app, the reinstalled app haven't any R/W right about the files generated before. But it worked perfectly before.
I'm so confused right now, any help would be more than welcome.
Edit:
It appears to be a permission issue introduced by the newer versions of Android (see comments below).

Unremovable 0 byte file in data dir

A working app of mine started throwing warnings to logcat all of a sudden on my 4.4.4 Kitkat device:
W/ContextImpl﹕ Failed to ensure directory: /storage/emulated/0/Android/data/com.example.app/files/Pictures
All the photos and other data are unaccessable to the app.
After some digging it turns out that there's a seemingly 0 byte file in /storage/emulated/0/Android/data with the package name of my app: com.example.app. No wonder that Android can't create a directory with the same name.
I have absolutely no idea how, when and this file got created. Or better to say, how, when and why the original directory got corrupted.
The strange thing is, that even though it's listed when I call either list() or listFiles() on the data dir itself, calling exists(), isFile(), isDirectory() on the file itself will all return false.
The file seems to have no uid or gid and no date/time associated with it. It can neither be renamed nor deleted. Trying to clear the data of the app will also not remove it, nor will uninstalling the app.
What to do now? Changing the package name of the app so that a new directory can be created is obviously not an option here.
Rebooting removed the file, solving the problem. Still no idea how and why this happened though.

OnObbStateChangeListener not called when mounting .obb

We've been successfully using the APK expansion file technology in our app for some time by expanding the .obb file into another directory for reading of the various pieces. We finally decided to try reading directly out of the bob by mounting it using StorageManager. The code we are using seems pretty common on the net.
We make the call:
if ( storageManager.mountObb( obbFile.getAbsolutePath(), null, obbListener ) )
{
Log.d( "STORAGE_MNT", "SUCCESSFULLY QUEUED" );
}
else
{
Log.d( "STORAGE_MNT", "FAILED" );
}
and this succeeds as "SUCCESSFULLY QUEUED". However the obbListener is never called afterwards. If you look in the LogCat you do see the following:
Calling a method in the system process without a qualified user:
android.app.ContextImpl.bindService:1543
com.android.server.MountService$ObbActionHandler.connectToService:2458
com.android.server.MountService$ObbActionHandler.handleMessage:2337
android.os.Handler.dispatchMessage:102 android.os.Looper.loop:136
I assume this is related to the problem but I have been unable to find much on why there is no "qualified user". Can someone please explain what could be going on here?
We have verified that obbFile.exists() is true. This file is there.
While searching for an answer I've see lots of references to broken a JOBB tool. It also seems like Android 4.4 had a bug that prevented this from working (although I'm using 4.4.2 right now). I'm wondering if this is stable enough to use for production code.
Well, I think I finally figured out what is happening. It looks like the obb file in question was already mounted. The file was an APK expansion file and it would appear this is automatically mounted for you by the system.
If, before trying to mount it, I execute:
if (storageManager.isObbMounted( obbFile.getAbsolutePath() ))
{
Log.d("", "obb file mounted at " + storageManager.getMountedObbPath( obbFile.getAbsolutePath() ));
}
without first explicitly mounting it, I get a valid mount path. I really wish the docs (or LogCat messages) were more explicit about this. It took me about a day to discover this. It wasn't until I explicitly used an (necessary) encryption key on the obb that I saw a message in LogCat saying the file was already mounted.
Another reason for the listener not being called is if the OBB is invalid - such as not being created with JOBB using the correct package name. In my case I messed up creating the test environment and so was attempting to mount a pre-Storage Manage / JOBB expansion file created the old way with zip. I once got an internal error event, but only once out of hundreds of hair-pulling attempts. It seems that the Storage Manager will fail silently after successfully queuing the mount and never call the listener. As soon as I went back to basics and redid everything from scratch I spotted the invalid .obb file, fixed it, and it all worked as documented.
Note that I also have a background task that tests for the expansion file being mounted as a fallback running once a second. I found this idea from a web article somewhere. Often the background task spots the OBB expansion is mounted way before the Storage Manager listener callback is invoked.

Android SD card writing fails, but not consistently

I've got a pretty thorny problem with Android 2.3: I have an app that gathers various logs for debugging and support purposes (my company does Linux for rugged hardware), and has stopped working lately, because it's failing to write to the SD card. Here are the symptoms I've seen and the investigations I've carried out:
Happens across multiple devices of multiple types with different SD cards, all of which have been checked for filesystem corruption (no issues found).
All devices report: Environment.getExternalStorageState() equals Environment.MEDIA_MOUNTED.
All devices also report that Environment.getExternalStorageDirectory().getAbsolutePath().canWrite() is false.
Via PackageManager.checkPermission(), my app reports that it has the WRITE_EXTERNAL_STORAGE permission.
OI File Manager is able to create directories and move files on the SD card; my app can do neither.
This code is sufficient to cause a failure:
String sdcardDirectory = Environment.getExternalStorageDirectory().getAbsolutePath();
File directory = new File(sdcardDirectory + "/logger");
if(!directory.mkdirs()){
//fails here.
Log.w("Logger", "Could not create logger directory.");
}
Since I have access to the keys for this device, I even went so far as to sign the app with the platform key and run it as android.uid.system, with no luck. Anyone have any ideas?
It turns out this is a case partly of bad diagnosis on my part, and partly an apparent change in 2.1 to 2.3.
The bad diagnosis was that the directory above was indeed being created. The apparent change between 2.1 and 2.3 may be Android internally, or it may be the way we're setting up paths, PATH, and symbolic links in our own builds. Further down from the code in the original post, there are a few calls to exec() to get e.g. output from logcat and copies of various bits of useful information in /proc; using absolute paths to the commands fixed the problem.
Thanks for the help in ruling things out.

Android NDK file access (package name issue)

In an Android app, using NDK, I'm accessing a local file using fopen, fclose, etc. My app started out as HellloJNI (the supplied example). Accessing the file actually worked initially. The file path I used was "/data/data/com.example.hellojni/files/Test.txt".
Naturally I don't want my app to be called HelloJNI forever, so I changed the package name (manifest/#package in AndroidManifest.xml) from com.example.hellojni to com.example.mytest. Accordingly, I use a different file path: "/data/data/com.example.mytest/files/Test.txt". But the same call to fopen("[...]", "w+") that used to succeed now fails.
Any ideas?
It works after manually creating the files folder below /data/data/com.example.mytest. In a way, it's obvious, but I still don't fully understand it, because I never created explicitly the files folder below /data/data/com.example.hellojni. So where did that one come from?
Edit:
Apparently calling getFilesDir creates the Files folder implicitly, so that mystery is solved :-)

Categories

Resources