OnObbStateChangeListener not called when mounting .obb - android

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.

Related

Can't boot Android device after replacing system.img

I am working on a custom android device using the i.MX53 board from NXP (formerly Freescale). I have the OS source code, various intermediate files, and the final resulting files once produced by another developer (who customized the OS, but has since left our company). I now need to modify the contents of the system partition on these devices. I have attempted to build and load a new system.img file using make_ext4fs.exe and the directory which contains the original collection of files the prior developer must have used. I believe I have created a nearly identical system image, as the one previously used. They are both ext4, 200MB.
There is a utility for this board (called MfgTool) which copies and mounts images automatically for you at the click of a button. That MfgTool successfully writes my image to the device. When I try to boot, however, it fails and just loops with the custom boot image being displayed. If I swap out the new system image and restore the prior one in this process, everything works again. So it has to simply be a matter of getting this system image built correctly.
What might be the cause? What difference in the images might cause this? Is it possible there is a signature needed, or some other kind of protection which I'm failing to account for?
Replace one of the system image service executable with a shell that dump kmsg and logcat to a file (in data partition or external storage for example) and then call the original executable. Then, boot to your previous system and collect those logs.
It turned out that my primary problem was that I need to set the mount point for the image to "system" NOT "/system" when it was created via make_ext4fs despite all documentation out there to the contrary! I figured this out by carefully reading the ASOP source: ...build\tools\releasetools\img_from_target_files.
Of note, after this hurdle, I ran it another problem where the device was acting funky. That turned out to be the result of not having any symbolic links in the image. It seems like at the least you normally have symbolic links directing your "bash" commands to the toolbox binary in system/bin. I don't know how you normally get those, but creating those links and then bundling them into the image fixed that. I suggest checking the bin directory for symbolic links if you manually create a system image like this.

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.

How can I access and present android_asset resources from a Cordova application?

I am porting an iOS application to Android and have run into resource access issues.
Ideally, I'd like to open supplemental files (in this case PDFs, MP4 movies, etc.) in the application; however, I have discovered that Android+Cordova does not work as seamlessly as iOS+Cordova in this fashion.
Knowing (and accepting) that I need to pass files of this sort off to a secondary application, I have encountered the obvious permissions issues (i.e. external resources cannot see inside the resource bundle/APK).
I figured I could copy the resource out to a user folder on the device using the Cordova File plugin, and then use something like the FileOpener plugin; however, the File plugin can access the device file system -- but not pull from the APK.
I have hopes that the Asset2SD plugin (https://github.com/gkcgautam/Asset2SD) may help here, since it has been recently updated to Cordova 3.
Is there a more appropriate/preferred means of doing this kind of thing? I have to think it's a relatively common task, but there doesn't seem to be much on the topic (short of "find another way...").
NOTE: I've already reached out to the PhoneGap/Cordova community (https://groups.google.com/forum/#!topic/phonegap/xh_4UrEl9Gw), but haven't had much success there.
EDIT-1: Additionally, file size on the APK is going to exceed the 50MB cap, requiring extension APKs. I've mentioned this in the off chance that this might make things simpler.
EDIT-2: I've managed to get my base APK size down and have redistributed some resources so that an expansion APK (OBB) isn't necessary. I have also managed to make use of Asset2SD to successfully extract resource. My remaining issue is pathing.
The code looks like so...
window.plugins.asset2sd.startActivity(
{
asset_file: "www/folder/" + filename,
destination_file_location: "MyApp/myfolder/",
destination_file: filename
},
// success on saving file
function(filename) {
window.plugins.fileOpener.open("file:///" + filename);
},
// failure on saving file
function() {
console.log("Could not open file");
}
);
I know that Asset2SD uses getExternalStorageDirectory() [Google seems to advocate using getExternalFilesDir() in their discussion on expansion APKs].
EDIT-3: Sorted out return value from Asset2SD (i.e. filename + path) which can be pushed to FileOpener. Code updated accordingly.

Android context.getFilesDir() sometimes returns root folder

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.

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.

Categories

Resources