Archive for ‘System Service’

October 15, 2013

Zygote

Now, that’s a name. Zygote is a daemon whose goal is to launch Apps. The startup of the process is triggered by Init.rc after Service Manager and others but it is actually started by app_process. Here is the sequence used to start such special process

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd

You can see how Zygote is started as a system service. You can see also how app_process is the actual command that starts it.

As we said, Zygote is a daemon which only mission is to launch applications. This means that Zygote is the parent of all App process. When app_process launches Zygote, it creates the first Dalvik VM and calls Zygote’s main () method. Once Zygote starts, it preloads all necessary Java classes and resources, starts System Server and opens a socket /dev/socket/zygote to listen for requests for starting applications. System Server as we saw in previous post is a complete detached process from it’s parent. Once it’s created it goes initializing all the different System Services and starts the Activity Manager (will see this in a later posts). So, how does Zygote start new applications?

Zygote receives a request to launch an App through /dev/socket/zygote. Once it happens it trigger a fork() call. Here is where the virtues of a great design take action. When a process forks, it creates a clone of itself. It replicates itself in another memory space. This is done pretty efficiently. When this happens to Zygote, it creates an exact and clean new Dalvik VM, preloaded with all necessary classes and resources that any App will need. This makes the process of creating a VM and load resources pretty efficiently. But the design goes farther. As we know, Android runs on Linux. The Linux Kernel implements a strategy call Copy On Write (COW). What this means is that during the fork process, no memory is actually copy to another space. It is shared and marked as copy-on-write. Which means that when a process attempt to modify that memory, the kernel will intercept the call and do the copy of that piece of memory. In the case of Android those libraries are not writable. This means that all process forked from Zygote are using the exact same copy of the system classes and resources. Another benefit is the real memory saving. No matter how many applications are started the increase in memory usage will be a lot smaller.

If you are in an early stage of a porting process, Zygote is another big process that you don’t need to start. You can disable it by adding the keyword “disabled” at the end of the boot sequence in init.rc

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
disabled

AlBelow is a picture (from Embedded Android) on where can you place Zygote in the Android Platform

zygote

Android Boot Sequence (from Embedded Android)

Here is the Zygote main() method:

public static void main(String argv[]) {
 try {
     // Start profiling the zygote initialization.
     SamplingProfilerIntegration.start();

    registerZygoteSocket();
    EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
    SystemClock.uptimeMillis());
    preload();
    EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
    SystemClock.uptimeMillis());

    // Finish profiling the zygote initialization.
    SamplingProfilerIntegration.writeZygoteSnapshot();

    // Do an initial gc to clean up after startup
    gc();

    // Disable tracing so that forked processes do not inherit stale tracing tags from
    // Zygote.
    Trace.setTracingEnabled(false);

    // If requested, start system server directly from Zygote
    if (argv.length != 2) {
        throw new RuntimeException(argv[0] + USAGE_STRING);
    }

    if (argv[1].equals("start-system-server")) {
        startSystemServer();
    } else if (!argv[1].equals("")) {
        throw new RuntimeException(argv[0] + USAGE_STRING);
    }

    Log.i(TAG, "Accepting command socket connections");

    runSelectLoop();

    closeServerSocket();
 } catch (MethodAndArgsCaller caller) {
     caller.run();
 } catch (RuntimeException ex) {
     Log.e(TAG, "Zygote died with exception", ex);
     closeServerSocket();
     throw ex;
 }
}

Also, see below how Zygote starts the System Server:

/**
 * Prepare the arguments and fork for the system server process.
 */
 private static boolean startSystemServer()
 throws MethodAndArgsCaller, RuntimeException {
 /* Hardcoded command line to start the system server */
 String args[] = {
 "--setuid=1000",
 "--setgid=1000",
 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
 "--capabilities=130104352,130104352",
 "--runtime-init",
 "--nice-name=system_server",
 "com.android.server.SystemServer",
 };
 ZygoteConnection.Arguments parsedArgs = null;

int pid;

try {
 parsedArgs = new ZygoteConnection.Arguments(args);
 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

/* Request to fork the system server process */
 pid = Zygote.forkSystemServer(
 parsedArgs.uid, parsedArgs.gid,
 parsedArgs.gids,
 parsedArgs.debugFlags,
 null,
 parsedArgs.permittedCapabilities,
 parsedArgs.effectiveCapabilities);
 } catch (IllegalArgumentException ex) {
 throw new RuntimeException(ex);
 }

/* For child process */
 if (pid == 0) {
 handleSystemServerProcess(parsedArgs);
 }

return true;
 }
October 11, 2013

Service Manager

The Service Manager is like an information director. It is the Yellow Pages of all services available. It has a very close relationship with the Binder. In the Binder post you can see a picture with the Service Manager, and you can see that when an application wants to instantiate a service they first have to get a handler. That is, they have to ask the Service Manager for that handler, and they do it through the Binder.

It make sense then that the Service Manager is started before any other service. It is actually started by Init. At that time, the Service Manager request the Binder to be the “Binder Context Manager”, which is like to say I want to be the secretary of the boss. It does this through an ioctl() call. As we saw in the System Services the System Server will add all the spawn services to the Service Manager.

As you can imagine the Service Manager is not really visible by the developer, and most are unaware of it’s existence, but it is there to find your service. If Service Manager is the index to all the other System Service it makes sense that is tarted before any other. For that to happen there is only one place for this to happen, and that is in *init.rc*.  After it, follow Zygote, meda, surfaceflinger and drm. These are the first and most basic services started and they are natively implemented. The reason as we said in the first post, they have to be highly CPU efficient.

service servicemanager /system/bin/servicemanager class core user system group system critical
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
onrestart restart drm

You can see here ServiceManager.java, interface which implements the Java IServiceManager.java Interface. These are the method implemented at the Service Manager. You can find here IServiceManager.cpp the native code for this service, that is, the real service. It might look confusing. You should get familiar with Java Interfaces if you are not. It is very normal in Android. Each service has normally an Interface which is implemented in a class. The class can be the Java interface of a native service or a Java implemented service. Following you can see the Interface (you can not instantiate) of the ServiceManager to illustrate the methods implemented by the service.

public interface IServiceManager extends IInterface
{
/**
* Retrieve an existing service called @a name from the
* service manager.  Blocks for a few seconds waiting for it to be
* published if it does not already exist.
*/
public IBinder getService(String name) throws RemoteException;

/**
* Retrieve an existing service called @a name from the
* service manager.  Non-blocking.
*/
public IBinder checkService(String name) throws RemoteException;
/**
* Place a new @a service called @a name into the service
* manager.
*/
public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException;
/**
* Return a list of all currently running services.
*/
public String[] listServices() throws RemoteException;
/**
* Assign a permission controller to the service manager.  After set, this
* interface is checked before any services are added.
*/
public void setPermissionController(IPermissionController controller)
throws RemoteException;

static final String descriptor = "android.os.IServiceManager";
int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
int CHECK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
int ADD_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
int LIST_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
int CHECK_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
int SET_PERMISSION_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+5;
}