Android. NDK. How to log calling destructor of global variable? - android

As we all know android doesn't unload *.so after close application. I had found the solve by adding "exit(0)" at the end, that is solved problem, but I wanna know exactly that all are OK.
The code is work fine as expected after solving the problem:
static int value = 0;
// In android_main
LOGI("value = %d", value); // always print 0, but not 1 after second run of
// application as it was without "exit(0)" at the end
value = 1;
I wanna to test that on class like:
class A {
A() {
LOGI("Constructor");
}
~A() {
LOGI("Destructor");
}
statis A a;
In such way prints only "Constructor".
Maybe because of destructor is calling after when LOGI isn't working more for application that will be closed ?
Question: why LOGI in destructor isn't working? According to first example on top destructor is calling really.

This is not only pointless, but quite possibly counterproductive. If android wants the memory utilized by your process, it will terminate the process to reclaim it; if it doesn't, it won't.
To specifically address your question, killing or exiting a process does not invoke destructors, it merely terminates execution and the kernel bulk-releases all memory and (conventional) resources.
Do not try to second guess the system, as that can frequently result in killing a process only to have android immediately restart it. Further, it can allegedly cause problems with a few Android IPC resources (like the camera) which may not be freed up when the process of a utilizing application unexpectedly dies.

Related

Android - JNI / NDK - crash with SIGSEV - signal handling not triggered

I have Android native C++ code. However, sometimes when I send app to background and back, it crash with SIGSEGV. I want to debug it using my own signal handling and print stack trace, however, when this error occurs, my signal handling is not triggered at all.
To JNI_OnLoad method, I have added:
struct sigaction sighandler;
memset (&sighandler, '\0', sizeof(sighandler));
sighandler.sa_sigaction = &android_sigaction;
sighandler.sa_flags = SA_SIGINFO;
int watched_signals[] = { SIGABRT, SIGILL, SIGSEGV, SIGINT, SIGKILL };
for(int signal : watched_signals)
{
sigaction(signal, &sighandler, &old_sa[signal]);
}
And I have:
static struct sigaction old_sa[NSIG];
static void android_sigaction(int signal, siginfo_t *siginfo, void *context)
{
MY_LOG("Sending PID: %ld, UID: %ld\n", (long)siginfo->si_pid, (long)siginfo->si_uid);
old_sa[signal].sa_handler(signal);
}
However, android_sigaction is never trigerred for the error, when app goes from background. I have tried to create bug in code (writing outside array bounds), trigger it with button push and the callback is correctly called.
What is going on?
Assuming that you're using Android 5.0+ device, your problem may be caused by ART. It exposes own signal() and sigaction() so it has a chance to steal signal and pass it somewhere else.
For debugging purposes you could try direct syscall:
for(int signal : watched_signals)
{
syscall(_NR_sigaction, signal, &sighandler, &old_sa[signal]);
}
So now your handler goes directly to kernel and ART shouldn't change it.
Of course it is OK only for debugging. If you want to go with this for a prod - you need to develop some logic that will respect previous handler.
P.S. also checking returned value and errno is a good idea as well.

How to detect process foreground for Android O

On our application there's a service that is normally started during Application.OnCreate (directly calling context.startService) and also later on via AlarmManager (refactor is in progress to migrate some of its work to JobScheduler).
Our application also have a BroadcastReceiver that gets launched with its direct intent.
Given the new limitations in Android Oreo (https://developer.android.com/about/versions/oreo/android-8.0-changes.html) we're having an issue as follows:
app/process is in background/dead
BroadcastReceiver gets fired by the OS
Application.onCreate() executes before the BroadcastReceiver
Application.onCreate() code tries to run the Service
this leads to crash with "IllegalStateException: Not allowed to start service Intent".
I'm aware of the new recommended ways of launching a Service as answered by CommonsWare here https://stackoverflow.com/a/44505719/906362, but for this specific case, I simply want to have if(process in foreground) { startService }. I'm currently using the following method and it seems to work:
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static boolean isProcessInForeground_V21(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.AppTask> tasks = am.getAppTasks();
return tasks.size() > 0;
}
But I can't find the exact checks Android Oreo is doing (I got as far as here https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/ContextImpl.java on the startServiceCommon method, but from there requireForeground flag seems to go to some native implementation)
So my question:
For the specific purpose of Android Oreo new limitations, how to check if my process is foreground before calling startService?
To continue your investigation: (TL;DR: see between horizontal lines at the bottom)
Disclaimer, I don't know too much about Android, I just like digging in the source code.
Note: you can also navigate the code in Android Studio if you jump to file instead of class:
or searching for text in Project and Libraries.
IActivityManager is defined by AIDL, that's why there are no sources for it:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/app/IActivityManager.aidl#145
Based on how AIDL needs to be implemented I found that ActivityManagerService extends IActivityManager.Stub (God bless Google indexing).
Note I also found this, which might be an interesting read if you're really interested how things work internally.
https://programmer.group/android-9.0-source-app-startup-process.html
ActivityManagerService sources reveal that in Oreo startService is forwarded to ActiveServices which is located in the same package.
Assuming we're looking for an exception like this:
java.lang.IllegalStateException: Not allowed to start service Intent {...}: app is in background uid UidRecord{af72e61 u0a229 CAC bg:+3m52s273ms idle procs:1 seq(0,0,0)}
we have to continue down the rabbit hole: requireForeground gets assigned to fgRequired parameter and the message is here. The condition to allow this depends on the start mode returned by ActivityManagerService.getAppStartModeLocked(packageTargetSdk = 26 or greater, disabledOnly = false, forcedStandby = false).
There are 4 start modes:
APP_START_MODE_NORMAL (needs to be different than this, i.e. !=)
APP_START_MODE_DELAYED (this is ok, i.e. return null)
APP_START_MODE_DELAYED_RIGID
APP_START_MODE_DISABLED
Ephemeral apps will immediately return APP_START_MODE_DISABLED, but assuming this is a normal app, we end up in appServicesRestrictedInBackgroundLocked.
Note: this is where some of the whitelist mentioned in https://stackoverflow.com/a/46445436/253468 is decided.
Since all branches but last return APP_START_MODE_NORMAL, this redirects to appRestrictedInBackgroundLocked where we find our most likely suspect:
int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
// Apps that target O+ are always subject to background check
if (packageTargetSdk >= Build.VERSION_CODES.O) {
return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
So the reason for denial is simply targeting O. I think the final answer to your question of how the OS decides if your app is foreground or background is this condition in getAppStartModeLocked
UidRecord uidRec = mActiveUids.get(uid);
if (uidRec == null || alwaysRestrict || uidRec.idle) {
My guess is that a missing record means it's not running (but then how is it starting a service?!), and idle means it's backgrounded. Notice that in my exception message the UidRecord is saying that it's idle and has been backgrounded for 3m52s.
I peeked into your getAppTasks and it's based on TaskRecord.effectiveUid, so I'm guessing that's quite close to listing UidRecords for your app.
Not sure if this helps, but I'll post it anyway, so if anyone wants to investigate more, they have more info.

Can't execute JavaVM->DetachCurrentThread(): "attempting to detach while still running code"

I have an Android app that uses NDK - a regular Android Java app with regular UI and C++ core. There are places in the core where I need to call Java methods, which means I need a JNIEnv* for that thread, which in turn means that I need to call JavaVM->AttachCurrentThread() to get the valid env.
Previously, was just doing AttachCurrentThread and didn't bother to detach at all. It worked fine in Dalvik, but ART aborts the application as soon as a thread that has called AttachCurrentThread exits without calling DetachCurrentThread. So I've read the JNI reference, and indeed it says that I must call DetachCurrentThread. But when I do that, ART aborts the app with the following message:
attempting to detach while still running code
What's the problem here, and how to call DetachCurrentThread properly?
Dalvik will also abort if the thread exits without detaching. This is implemented through a pthread key -- see threadExitCheck() in Thread.cpp.
A thread may not detach unless its call stack is empty. The reasoning behind this is to ensure that any resources like monitor locks (i.e. synchronized statements) are properly released as the stack unwinds.
The second and subsequent attach calls are, as defined by the spec, low-cost no-ops. There's no reference counting, so detach always detaches, no matter how many attaches have happened. One solution is to add your own reference-counted wrapper.
Another approach is to attach and detach every time. This is used by the app framework on certain callbacks. This wasn't so much a deliberate choice as a side-effect of wrapping Java sources around code developed primarily in C++, and trying to shoe-horn the functionality in. If you look at SurfaceTexture.cpp, particularly JNISurfaceTextureContext::onFrameAvailable(), you can see that when SurfaceTexture needs to invoke a Java-language callback function, it will attach the thread, invoke the callback, and then if the thread was just attached it will immediately detach it. The "needsDetach" flag is set by calling GetEnv to see if the thread was previously attached.
This isn't a great thing performance-wise, as each attach needs to allocate a Thread object and do some internal VM housekeeping, but it does yield the correct behavior.
I'll try a direct and practical approach (with sample code, without use of classes) answering this question for the occasional developer that came up with this error in android, in cases where they had it working and after a OS or framework update (Qt?) it started to give problems with that error and message.
JNIEXPORT void Java_com_package_class_function(JNIEnv* env.... {
JavaVM* jvm;
env->GetJavaVM(&jvm);
JNIEnv* myNewEnv; // as the code to run might be in a different thread (connections to signals for example) we will have a 'new one'
JavaVMAttachArgs jvmArgs;
jvmArgs.version = JNI_VERSION_1_6;
int attachedHere = 0; // know if detaching at the end is necessary
jint res = jvm->GetEnv((void**)&myNewEnv, JNI_VERSION_1_6); // checks if current env needs attaching or it is already attached
if (JNI_EDETACHED == res) {
// Supported but not attached yet, needs to call AttachCurrentThread
res = jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&myNewEnv), &jvmArgs);
if (JNI_OK == res) {
attachedHere = 1;
} else {
// Failed to attach, cancel
return;
}
} else if (JNI_OK == res) {
// Current thread already attached, do not attach 'again' (just to save the attachedHere flag)
// We make sure to keep attachedHere = 0
} else {
// JNI_EVERSION, specified version is not supported cancel this..
return;
}
// Execute code using myNewEnv
// ...
if (attachedHere) { // Key check
jvm->DetachCurrentThread(); // Done only when attachment was done here
}
}
Everything made sense after seeing the The Invocation API docs for GetEnv:
RETURNS:
If the current thread is not attached to the VM, sets *env to NULL, and returns JNI_EDETACHED. If the specified version is not supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise, sets *env to the appropriate interface, and returns JNI_OK.
Credits to:
- This question Getting error "attempting to detach while still running code" when calling JavaVm->DetachCurrentThread that in its example made it clear that it was necessary to double check every time (even though before calling detach it doesn't do it).
- #Michael that in this question comments he notes it clearly about not calling detach.
- What #fadden said: "There's no reference counting, so detach always detaches, no matter how many attaches have happened."

App using Mobile Android GNSK crashes when identifyAlbumAsync() is called before audioProcessStart()

I have being upgrading an application to use the new Mobile Android GNSK but I have noticed that using the new MusicID-Stream is a little bit tricky. If the "identifyAlbumAsync" method get executed before the "audioProcessStart" method(since this need to be executed in a different thread), the application just crashes. In the Gracenote Demo application, the "audioProcessStart" method is continuously running so there is no need to synchronize its execution with the "identifyAlbumAsync" method call. Is it the way it is supposed to be used? It will be convenient if the application didn't crashed at least when the methods are not executed in order. Also in our application, we don't want to have the "audioProcessStart" method continuously like it is done in the demo application. We only want to run the "audioProcessStart" method when the user request identification and when the song playing gets identified , we want to stop the audio processing by calling "audioProcessStop". Is there an easy way to do this? Right now, we are getting the Thread where "identifyAlbumAsync" is running to sleep for 2 seconds in order to make sure that the Thread where the "audioProcessStart" method is supposed to run has time to get executed. Thank you in advance for your prompt response
In the upcoming 1.2 release, IGnMusicIdStreamEvents includes a callback that signals audio-processing has started, and an ID can be synced with this, e.g.:
#Override
public void musicIdStreamProcessingStatusEvent( GnMusicIdStreamProcessingStatus status, IGnCancellable canceller ) {
if (GnMusicIdStreamProcessingStatus.kStatusProcessingAudioStarted.compareTo(status) == 0) {
try {
gnMusicIdStream.identifyAlbumAsync();
} catch (GnException e) { }
}
}
Thanks for the feedback, you're right about this issue. Unfortunately right now sleeping is the best solution. But we are adding support for an explicit sync event in an upcoming release, please stay tuned.

Runtime.exec() bug: hangs without providing a Process object

Whether I use this:
process = Runtime.getRuntime().exec("logcat -d time");
or that:
process = new ProcessBuilder()
.command("logcat", "-d", "time")
.redirectErrorStream(true)
.start();
I get the same results: it often hangs within the exec() or start() call, no matter what I tried to do!
The thread running this cannot even be interrupted with Thread.interrupt()! The child process is definitely started and if killed the above commands return.
These calls may fail on first attempt, so THERE IS NO WAY TO READ THEIR OUTPUT! I can also use a simple "su -c kill xxx" command line, same result!
EDIT: Started debugging the java_lang_ProcessManager.cpp file in an NDK project with some debugging logs! So here is what I found so far, after the fork() the parent does this:
int result;
int count = read(statusIn, &result, sizeof(int)); <- hangs there
close(statusIn);
Though the child process is not supposed to block on it: That's what the child does (if started at all!):
// Make statusOut automatically close if execvp() succeeds.
fcntl(statusOut, F_SETFD, FD_CLOEXEC); <- make the parent will not block
// Close remaining unwanted open fds.
closeNonStandardFds(statusOut, androidSystemPropertiesFd); <- hangs here sometimes
...
execvp(commands[0], commands);
// If we got here, execvp() failed or the working dir was invalid.
execFailed:
int error = errno;
write(statusOut, &error, sizeof(int));
close(statusOut);
exit(error);
The child can fail for 2 reproducible reasons:
1- child code is not running, but the parent believes it is!
2- child blocks on
closeNonStandardFds(statusOut, androidSystemPropertiesFd);
In either case the read(statusIn...) in the parent ends in deadlock! and a child process is left dead (and cannot be accessed, pid unknown, no Process object)!
This problem is fixed in Jelly Bean (Android 4.1) but not in ICS (4.0.4) and I guess it will never be fixed in ICS.
Above solution didn't prove to be reliable in any ways, causing more issues on some devices!
So I reverted back to the standard .exec() and kept digging...
Looking at the child code that hangs, I noticed the child process will hang while trying to close all file descriptors inherited from the parent (except the one created within the exec() call) !
So I search the whole app code for any BufferedReader/Writer and similar classes to make sure those would be closed when calling exec()!
The frequency of the issue was considerably reduced, and actually never occured again when I removed the last opened file descriptor before calling exec().
NB: Make sure SU binary is up-to-date, it can actually cause this issue too!
Enjoy your search ;)
Bug fix in Bionic was commited monthes ago, but it still hasn't been included in Android 4.0.4.
I have the same problem on ICS (seem to works fine on Android < 4). Did you find a solution?
A simple workaround could be to call the "exec" method in a dedicated thread with a timeout-join so that this situation could be "detected" (yes I know it's not very elegant...)

Categories

Resources