I have a C thread that is making requests and receiving updates from a server. The updates are sent to Java through JNI calls. My problem happens when I'm receiving a player's inventory which can contain up to 100 items (100 responses from the server, I cannot modify this part). Sometimes the problem happens, sometimes not but the bigger the inventory is, the more often I have this issue.
I don't get any exception in the logcat except the following message :
06-10 10:09:46.085: I/Choreographer(23815): Skipped 87 frames! The application may be doing too much work on its main thread.
And then my app closes. I also need to say that even when I comment the lines where I update the UI with runOnUiThread the app crash.
I tried to check if I'm on the UI Thread when I return to Java with JNI but Looper.myLooper() == Looper.getMainLooper() return false.
Anyone experienced the same problem ? Are the C threads related to the main thread somehow ? Thanks
EDIT
When I receive an update from the server the following calls are made :
From a Java Thread (not the UI thread) : call a C function named notifyAll
From notifyAll call a C function named update which will call its equivalent in Java (see code below)
void UpdateListenerWrapper::update(Update& u) {
// Retrieve the current JNIEnv* with the cached JVM
int status;
JNIEnv* env;
bool isAttached = false;
status = gCachedJVM->GetEnv((void **) &env, JNI_VERSION_1_2);
if(status < 0) {
__android_log_print(ANDROID_LOG_ERROR, "UpdateListenerWrapper", "Failed to get JNI environment");
status = gCachedJVM->AttachCurrentThread(&env, NULL);
if(status < 0) {
__android_log_print(ANDROID_LOG_ERROR, "UpdateListenerWrapper", "Failed to attach current thread");
return;
}
isAttached = true;
}
jmethodID update = env->GetMethodID(gClazzUpdateListenerWrapper, "update", "(J)V"); // J stands for Java long type
// Call Java method update from jUpdateListener object
env->CallVoidMethod(jUpdateListener, update, (jlong)(intptr_t)&u); // Pointer as agument, we'll build the Update object in Java
if (isAttached) {
gCachedJVM->DetachCurrentThread();
}
}
I think the problem is at this line gCachedJVM->GetEnv((void **) &env, JNI_VERSION_1_2); and maybe GetEnv return a pointer for the UI thread. Could that be the problem ? How can I fix this ?
The app crash is unrelated to the Choreographer complaints. Those are just a warning that indicates the animation is being starved.
You really want to be viewing the logcat output in a mode that shows thread IDs. I recommend adb logcat -v threadtime from the command line. If you put a log message at the start of your server interaction you can easily see if it's running on the UI thread (thread ID and process ID are the same -- not guaranteed by the system, but reliably true in apps).
Never do network or database I/O on the main thread. If it takes too long, the system gets bored and decides that your app is not responding.
Calling into native code through JNI does not switch you to a different thread. There are not C threads and Java threads, just threads, which can call in and out of code written in C and Java.
Re: question updates...
GetEnv always returns a pointer to data for the current thread. Also, CallVoidMethod always happens in the current thread; even if you passed in the wrong JNIEnv it wouldn't "jump" threads.
The GetMethodID call can be expensive in a class with a lot of methods, so you should try to cache that at the same point where gClassUpdateListenerWrapper is set up. Attaching and detaching the thread from the VM can also be expensive and is something best avoided -- and if you're calling here from a Java method, then by definition it's attached already. I would guess that isAttached is never being set.
That doesn't really explain why the Choreographer is starving though. I think you still need to add a log message to C update() and use logcat -v threadtime to get a sense for what is happening on which threads, and use traceview to see where the time is going.
I found the solution to my problem but it's kind of specific to my app. In the update function (Java side), I had a case which had no break and each updates were triggering new network calls (not in the UI thread). Nasty to find but thanks for your time and your answers, you helped me to solve this :)
Related
I have simple Activity that calls AsyncTask, so I print some id's regarding Proces and Thread:
From onCreate android.os.Process.myUid(): 10137
From onCreate android.os.Process.myPid(): 29776
From onCreate android.os.Process.myTid(): 29776
From onCreate Thread.currentThread().getId(): 1
/****************************************************************/
From Async doInBackground android.os.Process.myUid(): 10137
From Async doInBackground android.os.Process.myPid(): 29776
From Async doInBackground android.os.Process.myTid(): 30426
From Async doInBackground Thread.currentThread().getId(): 12556
Uid is same because its app-specific sandbox
Similar with Pid: Each app is one Process
3rd line in onCreate same as Pid because it's the UIThread and in Android OS as based on Linux we know that issue regarding Process is actually Thread etc... And in the Async the ThreadId is different because AsyncTask runs on different Thread rather then the UIThread
The thing I'm struggling to understand is Thread.currentThread().getId(). What I expect is to get same id as Thread.currentThread().getId() for the same execution environment. e.g. for onCreate I want lines 3,4 to be same (29776), and for Async I expect lines 3,4 to be the same (30426). What is going on here?
Thanks,
Very interesting question by the OP and I decided to dig (love open source).
The short answer is: they're different because they're different, because they were never meant to be the same.
Process.myTid() is the linux thread ID
Thread.getId() is a simple sequential long number.
But the short answer is boring, so let's explore where the answer comes from (links in the answer points to the relevant source codes).
In Process.myTid(), you'll see that is simply calls from Os.gettid() that in itself calls a native method on Libcore for that method is below:
public static int gettid() { return Libcore.os.gettid(); }
furthermore the docs for Os.gettid(); you'll find a link to Linux Programmer's Manual
gettid() returns the caller's thread ID (TID). In a single-threaded
process, the thread ID is equal to the process ID (PID, as returned
by getpid(2)). In a multithreaded process, all threads have the same
PID, but each one has a unique TID.
That means, Process.myTid() returns the thread ID as given by the Linux kernel.
On the other hand Thread.getId() is simply returning a long. This long is assigned during init(...) as tid = nextThreadId();. Then the last piece of this puzzle, below is the code for nextThreadId()
/* For generating thread ID */
private static long threadSeqNumber;
private static synchronized long More ...nextThreadID() {
return ++threadSeqNumber;
}
That means, Thread.getId() is simply a "java layer" static long being auto-increment for each thread.
I'm pretty new to jni.
I need to invoke a native method from java code, which should perform a time-consuming operation asynchronously (in another thread), and at the end it should invoke a java callback. However I need this callback to be invoked in the same java thread that originated the operation. That is, the java application should be single-threaded, and all callbacks should be invoked in the context of this thread.
I've read tutorials on callback invocations, the stuff about keeping global refs to the object, getting the appropriate methodid and invoking it.
I've also found stuff about how to call a java method from another thread (AttachCurrentThread), however this is not what I need. I need to make the java call within the originating thread, so the question is how do I switch to that thread?
For instance, in Win32 I'd use something like PostMessage/PostThreadMessage to invoke a code in the specified thread, assuming it runs the message-loop. There're also alternatives like QueueUserAPC which is applicable if the thread waits for events in an alertable state.
So, what are the options at my disposal? Is there a jni method for posting execution of a java method in the specified thread? Or perhaps a linux equivalent of PostThreadMessage? I can also think about workarounds within the java code, but prefer to solve this on the native side.
Thanks in advance.
Please see a relevant recent discussion: How do I post code to be run on the Android main thread from a separate thread in C++?. The most interesting part is this thread in android-ndk group from 2012.
TL;NR: from JNI_OnLoad() or other call that happens early enough, and comes from the UI thread, you call
pipe2(messagePipe, O_NONBLOCK | O_CLOEXEC);
ALooper_addFd(ALooper_forThread(), messagePipe[0], 0, ALOOPER_EVENT_INPUT, handler, data);
Elsewhere you define a simple handler function:
int handler(int fd, int, void* pHandler) {
int what = 0;
read(fd, &what, sizeof(what));
static_cast<MyHandler *>(pHandler)->handle(what));
return 1;
}
Now the native version of Handler.sendEmptyMessage(), and a close analog of CWinThread::PostThreadMessage() (without wParam and lParam), could then be as simple as
MyHandler::sendEmptyMessage(int what) {
write(messagePipe[1], &what, sizeof(what));
}
With reference to the following code.
for (Future<Long> future : list) {
try {
sum += future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
Now when i call future.get will this be blocking call? So if i am executing this on the Main Thread of and android application will this cause an ANR exception ? I notice the Interrupted exception is also thrown, so does this mean their is a sleep called on the thread in the get function ?
Yes, documentation of Future.get() says:
Waits if necessary for the computation to complete, and then retrieves its result.
so, it will block until results of computation are available, or the computation was interrupted (cancelled or resulting in exception).
It may cause ANR if your computations take long time to finish.
Again, from documentation of Future.get():
#throws InterruptedException if the current thread was interrupted while waiting
Now, since you call Future.get() from main thread, I suspect that it is the Android system which interrupts your main thread in an attempt to make it responsive again. But it may also be caused by another thread of your application - it's hard to tell, since you haven't specified what your application does, what threads does it create, when, do you use ExecutorService (and if so, which implementation), and so on.
No, FutureTask.get() (which I believe is the implementation of Future you're using) does not call Thread.sleep(). Instead, putting the thread in waiting mode is done via thread parking which causes it to not be scheduled for execution until a signal is given. This may cause in ANR error if done in the main thread. For details of parking mechanism consider reading documentation and this question
You can simply check if future "is done" by calling future.isDone(). Code example:
String result = "";
if (myFuture.isDone()) result = (String) myFuture.get();
You will probably want to check it in an endless loop.
Beware of deadlock with future.get(). If both the MainThread, that call future.get(), and the WorkerThread is synchronized (on the same object) then you get a deadlock.
My program is sending data to web server when accelerometer datas exceed the threshold which determined by me. So , I used thread mechanism for sending operation :
if( threshold is exceeded )
thread_send .start();
But this usage cause "Thread Already Used" error. So I used a method that I think is bad is below and it works :
if( threshold is exceeded ) {
thread_send = new Thread(this);
send_thread.start();
}
New thread is created at every turn. Does that usage cause negative results? (For example, memory problem or performance problem etc.)
What are your suggestions?
Editted :
My program should send data to web server very often. The most important thing is working correctly.So slow working is allowable , as long as the program can't stop suddenly..
I used ExecutorService in line with your suggestions :
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
........
if( threshold is exceeded ) {
threadExecutor.execute(this);
}
But errors occured : RecejtedExecutionException..
What can I do ?
The second code looks correct, though it may slow it down if too many threads are running in parallel. Depending on the application, it might be appropriate to have threads run one-at-a-time in a queue, using Executors.newSingleThreadExecutor.
One idea is creating a singleton like service that runs the thread, that way if one isn't running, then it starts one, otherwise it ignores it.
If you want multiple running at the same time, what you have is correct. Remember a thread can only be ran once per new Thread()
I have a client software (on Android) that listens to incoming messages. The messages are received in a while loop that waits for messages to come. When a message is found, it updates the GUI. [Since in Android, GUI can not be updated directly ] A thread is called to do this. My problem is, if there are many messages, results in many threads! And it creates a clumsy situation. My abstract code is,
My_Client()
{
send_text_function() // My question is not about it
in_a_thread_Call_receive_from_others_function() [see 1]
}
receiving_funtion() // [this function is mentioned above as (see 1), called in a thread]
{
while( waiting for new message)
{
>>A new message found >> create a thread to update the GUI. // << Here is my question. see 2
//android.os.Handler.thread type thread!
}
}
label 2: Now this thread is created each time there is a message. How can I just create one thread and keep using it again and again? Any idea?
Create a new Thread.
In the run() method of the Thread create a new Handler.
When you want to do something on the target thread, use the Handler's post() method.
You can create a Handler on the Main thread to post-back operations that update the GUI.
Also consider using AsyncTask<>.