Saturday, 5 May 2018

Handling exceptions thrown from ActivityThread in Android


Sometimes it is desired to prevent the default exception handler from terminating application. This may be done via setting custom default uncaught exception handler.

What happens if the caught exception is thrown from ActivityThread? See Android/Sdk/sources/android-26/android/app/ActivityThread.java for the source. When exception is thrown from ActivityThread the Looper.loop() cycle invoked from ActivityThread.main() method terminates. As the exception is caught by custom default exception handler, it does not instruct application to finish. However, application becomes frozen. Main looper no longer processes new messages.

To make application run again, the main looper needs to be revived. This can be done inside the custom exception handler:
    private void setOnErrorFailedExceptionHandler() {
        android.os.Handler handler = new android.os.Handler(Looper.getMainLooper());
        Thread.UncaughtExceptionHandler uncaughtExceptionHandler =
                                        Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler((t, e) -> {

            if (e instanceof AndroidRuntimeException 
                        /*&& e is a specific exception that needs treatment*/) {
                android.util.Log.e("error", "DefaultUncaughtExceptionHandler", e);
                Looper.loop() // Revive main looper 
            } else if (uncaughtExceptionHandler != null) {
                // All other exceptions should be treated by default
                uncaughtExceptionHandler.uncaughtException(t, e); 
            }
        });
    }


Some edge cases may be solved with this trick. For example, take the introduction of new exception in Android O "android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()". The stacktrace for this exception shows that is is thrown from ActivityThread:
"android.app.ActivityThread$H.handleMessage(ActivityThread.java:1775)"
"android.os.Handler.dispatchMessage(Handler.java:105)"
"android.os.Looper.loop(Looper.java:164)"
"android.app.ActivityThread.main(ActivityThread.java:6541)"
"java.lang.reflect.Method.invoke(Native Method)"
"com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)"
"com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)"


The android.app.RemoteServiceException is a private exception, that subclasses AndroidRuntimeException.

This exception is meant to terminate application, so that the developers should follow the new foreground service rules. If time span between the startForegroundService() and setForegorund() call in Service.onCreate() is longer than ANR period, then this exception is thrown. It was not designed to be caught. There are a few catches though, when terminating application with a crash is undesired, given that "startForegroundService() -> startForeground()" rule is already implemented.

1. During debug sessions this exception fires quite often, because of slower emulator - or just the breakpoints being hit.
2. When released, the actual user device may lag in the very unfortunate moment between those calls, and app will be hit with the crash.

Especially in the second case it would be much better to retry the service start, or opt it to be started later, instead of crashing app altogether. Catching such exception and reviving main loop afterwards is possible with this approach.

Sunday, 3 July 2016

Completion thread pool for C++


This is an implementation of a thread pool for c++ I wrote a month ago. It has two classes, the general ThreadPool that accepts new tasks and returns std::future to receive the result from them and the CompletionThreadPool that works more along the lines of ExecutionCompletionService from java. The CompletionThreadPool Based on regular thread pool allowa to retrieve tasks results in order of the completion. It can be used as follows. Create a task to be submitted to the pool:
int f(int sleep_time) {
    sleep(sleep_time);
    return sleep_time;
}
Create CompletionThreadPool instance with designated task result type:
CompletionThreadPool completionThreadPool;
Submit any number of tasks for execution (they will be enqueued for execution immediately):
completionThreadPool.Submit(f, 5);
completionThreadPool.Submit(f, 1);
Block waiting for the results in order of their completion:
std::future firstCompleted = completionThreadPool.Take();
std::future secondCompleted = completionThreadPool.Take();
The source is located at github. There is also a qt sample application that uses CompletionThreadPool to download images in separate threads and show them in a window in order of readiness.

Friday, 13 November 2015

How to link pre-built library with CMake


1. Provide path to library (for example, default path may be set to usr/local/lib on Linux, and the lib won't be found even when located in the same directory as CMakeLists.txt and even with full path provided inside target_link_libraries). Suppose library is in the subfolder /lib of the folder where CMakeLists.txt resides, then:
set(PATH_TO_LIB ${CMAKE_CURRENT_LIST_DIR}/lib/)
find_library(MyLibVariable NAMES "MyLibrary" PATHS ${PATH_TO_LIB} NO_DEFAULT_PATH)
NAMES should provide the name of library, without the lib prefix. So if there is libMyLibrary.so it shoud read "MyLibrary". NO_DEFAULT_PATH removes all default paths from search. CMAKE_CURRENT_LIST_DIR is the directory where CMakeLists.txt is located.

2. Use target_link_libraries on the found library, presented by MyLibVariable
target_link_libraries(${APP_NAME} 
    ${MyLibVariable}
)
APP_NAME is the name of application to link the library to, added with add_executable(${APP_NAME} ${SRC} ${HEADERS}) in this CMakeLists.txt
In case the library still cannot be located you can debug the path is really the one you suppose it should be, including in CMakeLists.txt the following:
MESSAGE('--- MyLibVariable ---')
MESSAGE(${MyLibVariable})
In case path is still wrong make sure to delete the CMakeCache.txt, as it might have cached previous value.