Android Java System Service - Beyond system_server


   To start with, this post is for developers who work on android platform and not for application developers. The default version of android open source platform has system services coded in both Java (services hosted by system_server) and C,C++ (media services hosted by mediaserver).

     Recently, i came across requests to have Java based customized services hosted in their own process (and definitely not by system_server). Personally, i preferred all customized services to be in their own process, that way any service specific exception is just going to bring down the respective process and wouldn't trigger a framework reboot and offer a better user experience, opportunity for graceful handling.
Besides, i don't like bloatware services being added to system_server just because its open source. These bloatware services when buggy (memory references, exceptions) has a direct negative impact on the android framework and is a big negative PR for android platform as such. Having said that, there are reasons to add custom services to android framework and it would only make more sense to have these changes reviewed by the Android Community and possibly be reused by various OEMs, Chip makers.

   Anyways, now to the real world, I just managed to create a custom java service hosted in its own process, with few cons. I just added the source code of the service to existing services directory,

      frameworks/base/services/java/com/android/server/NumberGeneratorService.java
       frameworks/base/core/java/android/os/INumberGeneratorService.aidl
       frameworks/base/Android.mk

The aidl is just to expose APIs and Android.mk is just to generate code from the aidl. Android's build system adds this new class to framework.jar.

    Next, the instance of the service isn't created by system_server. NumberGeneratorService.java has its own public static void main(), which creates the service and registers it with servicemanager. The process is  not forked by zygote instead is forked by init, similar to native services being forked by init and it needed the changes to init.rc,

     service number /system/bin/app_process /system/framework com.android.server.NumberGeneratorService
     class main
     user system
     group system
     onrestart restart number

    And there is the NumberGeneratorService in its own process space and yes this approach has its own drawbacks. The first being that the Java process is being forked by init and doesn't get to take advantage of the warm boot of zygote and the memory cost of shared classes too, but it was fun and i just hope bloatware services just move out of system_server.

Java - Redirect library logs to application's destination

     Application developers would often like to view the logs of dependency library (jars) in sequence to that of application logs and having the library's log redirected to the same destination (files, console, logcat etc) as that of the appplication's log helps achieve sequenced logs and isolate root cause among library and applications. Java's java.util.logging.Logger helps in quick implementation of the need,

Library:

   The sample library has two components and lets applications control the logs of whichever component is needed.

// Class Focus's code

public static String FOCUS_COMPONENT_NAME = "com.android.camera.focus";
Logger componentLogger = Logger.getLogger(FOCUS_COMPONENT_NAME);
componentLogger.setUseParentHandlers(false);
Logger libraryLogger = componentLogger.getParent();



// Class Zoom's code


public static String ZOOM_COMPONENT_NAME = "com.android.camera.zoom";
Logger componentLogger = Logger.getLogger(ZOOM_COMPONENT_NAME);
componentLogger.setUseParentHandlers(false);
Logger libraryLogger = componentLogger.getParent();



// Common Logging function in library



void Log(Level level, String message) {
    libraryLogger.log(level, message);
    componentLogger.log(level, message);
}


componentLogger redirects logs to applications which specify the exact component name like (com.android.camera.zoom or com.android.camera.focus) libraryLogger redirects logs to applications which specify a part of the component name like (com or com.android or com.android.camera)

Application:

    Application needs to setup a handler to receive the logs redirected from the library.

// Disable root logger's ConsoleHandler (System.err)
LogManager.getLogManager().reset();

// Specify the component name to control library logs
Logger logger = Logger.getLogger("com.android.camera");

Handler handler = new Handler() {
@Override
public void publish(LogRecord logRecord) {
   System.out.println("Thread [" + Thread.currentThread().getId() + "] " +
   logRecord.getSourceClassName() + " : " + logRecord.getMessage());
}

@Override
public void flush() {
   System.out.flush();
}
};

logger.addHandler(handler);

Applications can control the redirected logs from library.

Disable all logs redirected from library

// void or any string which doesn't match with that of the library
Logger.getLogger("void");

Enable all logs redirected from library

Logger.getLogger("com.android.camera");
or
Logger.getLogger("com.android");
or
Logger.getLogger("com");

Enable logs of specific component of the library

Logger.getLogger("com.android.camera.focus");
or
Logger.getLogger("com.android.camera.zoom");

Control the logging level of the library

logger.setLevel(Level.ALL);
or
logger.setLevel(Level.OFF);