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.
Related
I have an Android app (developed under Xamarin.Android) which works fine when I test it locally on both emulators and physical devices. However, it fails on two physical devices (Moto G4, API 23, and Huawei Mate 9, API 24) when it goes through automatic testing on the Google Play Console. The problem arises when trying to create a log file in external storage. I have been running various tests under Firebase on the Moto G4, but cannot work out where the problem lies. I would be really grateful for at least one more pair of eyes on what I’m doing.
I check Android.OS.Environment.ExternalStorageState, which returns “MediaMounted”. I then use GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads) to work out where to create my log file. This returns “/storage/emulated/0/Download”. I next check that read/write permission has been granted. ContextCompat.CheckSelfPermission(this, Android.Manifest.Permission.ReadExternalStorage) and ContextCompat.CheckSelfPermission(this, Android.Manifest.Permission.WriteExternalStorage) both return Android.Content.PM.Permission.Granted. (In AndroidManifest.xml, I list <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />.)
At this point, I have established (I think) that the directory exists and that I have permission to write to it, so I try to create my log file, /storage/emulated/0/Download/LogFile.txt. This works fine locally, on both emulators and physical devices. It also works on most of the devices that the Google Console test puts to test. However, on the Moto G4 (physical device), file creation fails with the error “Could not find part of the path”.
I have also tried writing to DirectoryDocuments instead of DirectoryDownloads, which the Android documentation tells me is the “standard directory in which to place documents that have been created by the user”. The path returned for this is /storage/emulated/0/documents. When I try to write to that directory, it fails saying that the directory does not exist (which I believe is true).
Enumerating the contents of the Download directory, I noticed that there is a “Documents” directory inside the Download directory, i.e. /storage/emulated/0/Download/Documents. Writing to this directory again gives me the error “could not find part of the path”, same as writing to the Download directory itself.
My app absolutely has to store files somewhere (not just the log file). It is also important that the user can copy these files to/from the device, and I don’t want the files to be deleted, even if the app is uninstalled. For these reasons, I believe that external storage is the right (only) place for them.
I am at a loss to know what to try next. (I am wondering now whether there is actually an issue with the device, like a disk format issue.) If anyone has any suggestions on where to go from here, I would be really grateful! Extensive searches have not thrown up anything that I'm doing wrong, or any suggestion that the directory structure may be different on a Moto G4.
My issue is that on some devices, in this particular case on Android 10, stock Huawei p30 EMUI 10, I cannot create a new SD card file. documentFile.createFile(...) returns null, DocumentsContract.createDocument(...) throws a weird exception that I cannot find anywhere. It says "java.lang.IllegalArgumentException: Requested path ... doesn't appear under ...", as seen on the attached image.
Both mentioned functions have proper arguments, like mimetype and path. I don't have the device myself, I'm debugging it with a guy via email. At listing his storages there is no "/mnt/media_rw" mentioned anywhere, the SD card partition seems to be called "/storage/0123-4567". All other SD card file operations work, those extra SAF permissions are requested and handled properly. The code itself works just fine on the vast majority of devices, on my Android 10 too. I have target, compile SDKs set to 28, build tools 28.0.3.
Has anyone encountered such an issue? Any ideas how could it be solved? I'm afraid that it will be happening always more often as Android 10 grows and manufacturers continue doing things differently. Not to talk about the changes coming from SDK 29. Thanks
alright, so it looks like documentFile.createFile actually works, but it returns null. So just creating a brand new DocumentFile with the targeted path seems to work just fine.
Some additional info if someone encounters the same problem:
Context: As many Huawei users have noticed, the update from EMUI 9 to EMUI 10 has broken a number of apps that rely on write access to the SD card. The problem has been reported to Huawei, who shifted the blame onto Google and does not seem to be taking any further action. The developer of the app Total Commander, which was affected by the problem, found out that
On Huawei devices with Android 10, DocumentsContract.createDocument successfully creates the file, but then causes an exception
and suspects that
apparently Huawei hardcoded some paths where the user should be allowed to create files, but made a mistake.
Solution: As the question's author has already found, even though calling createFile() returns null, the file has been properly created. You can use findFile() to get it, for example:
// treeUri comes from the file picker
DocumentFile directory = DocumentFile.fromTreeUri(context, treeUri);
DocumentFile file = docFile.createFile(mimeType, filename);
if (file == null) {
file = docFile.findFile(filename + "." + mimeTypeExtension);
}
If at that point file is still null, then I think it's another issue.
We have a cross platform mobile app that uses a native C library to read some data (among other things). On Android the data is in a obb file that we get using the Expansion APK mechanism. This has been working very well for us. However, we've found that on the 2nd generation (2013) Nexus 7 table and on Nexus 5 phones, we are reading some data from the obb that is corrupted. The actual obb file is not corrupted, but what we read from it is.
The best example I have is with WebView reading an HTML file from the mounted obb. The first part of the HTML will be fine and then there is gibberish in the second part. Interestingly, the gibberish is recognizable as binary data from elsewhere in the obb. It is almost like the Android code that reads the obb is getting the block mapping wrong.
I've narrowed it down to being triggered by some C code that reads objects out of the obb. If I comment this out, the HTML will be fine when I later access it. Now it is possible there are bugs in the C code, but this library has been used on two other platforms without issues. It also works just fine on a first generation Nexus 7 and on other non-Nexus devices.
So does anyone have any thoughts about what this could be? It seems to happen with both Android 4.3.x and Android 4.4.x on these Nexus devices. What could be different hardware-wise that could cause this corruption? I assume things like the C library come with Android and aren't built into the firmware somehow?
I had the exact same problem, randomly corrupted assets when reading from the OBB in a native C library using stdio functions. Segments of 128 bytes were consistently corrupted in the mounted OBB. Any changes in the data would shift the byte segment, resulting in a different asset being corrupted. This was only a problem for phones running O/S v.4.4.x(KitKat) and v.5.x.x(Lollipop), phones running 6.x.x(Marshmallow) and later are unaffected as far as I know.
To circumvent this, rather than mounting the .obb, I ended up using the alternate .zip method as outlined here: https://developer.android.com/google/play/expansion-files.html.
I simply packed the data into a .zip with 0 compression(store), renamed to .obb, uploaded it to google play. When the user first starts the app, I extract the file to external storage using the APK Expansion Zip Library and then read the files directly rather than via mounting. This results in the app being twice the size on the phone, but it's preferable to being completely broken on some systems due to corrupted data.
I am not a new developer to android. I have an application on the market. However, sometimes I get reported strange exceptions to have occured:
java.io.FileNotFoundException: res/drawable-mdpi/background.png
android.content.res.Resources$NotFoundException: File res/drawable-mdpi/background.png from drawable resource ID #0x7f02001f
This is by all means untrue because otherwise I wouldn;t have compiled or run the program myself. Also I am sure the resources are there. This is just one of the exception I have been reported. There are same exceptions for other resources mainly layouts.
So my question is how would this happen? Is it because the android system has failed installing correctly my app? I almost sure this must be the case because I have many users who use it without problem.
Please help regarding this.
There can be several possible reasons:
Moving application to SD card.
There was some problem in downloading or installing APK from market (file can be corrupted).
User get APK with corrupted file from other source (for example via bluetooth from other user)
Some system bug (from software, to brocken hardware)
Any way You can't do anything with this problem.
Could it be that the application was pushed to SD Card and something happens to the drawable while on SD. I saw similar issues with layouts rather drawable and it was because the application was pushed to SD.
Maybe you have included certain codes that reference content from Android SDK.
In my case, I faced similar issue and when I removed the line
android:background="?android:attr/actionBarItemBackground"
from my xml, everything works fine again.
I installed my app on the emulator with 2.2 and onto the sdcard. When I browse via adb shell, I can see that the encrypted app file lies under /mnt/secure/asec/com.myapp-1.asec but it also lies as plain apk file unencrypted at /mnt/asec/com.myapp-1/pkg.apk as well and I can do a 'adb pull' without special permissions and unzip it to see it's content.
Unfortuntately my N1 is in repair and I cannot check on a real device right now - but wondering, why can I still access the plain apk so easily (at least on the emulator)?
(Not sure if this question is supposed to be asked on StackOverflow or on ForceClose.com, but I figured it's more related to development and how to secure/encrypt your app as a developer, therefore I'm posting it here.)
Got the answer from the Android dev mailing list:
http://groups.google.com/group/android-developers/browse_frm/thread/f7d11237744fe5fa/0e92cb2905632408#0e92cb2905632408
Apps on SD card are stored in an
encrypted container for platform
security purposes -- so that other
applications can not modify or corrupt
them. When mounting the SD card,
these containers are mounted so that
they can be accessed in the same way
as apps stored in internal storage.
Thanks to Dianne Hackborn/hackbod