Archive for September, 2010

How to keep yourself in the Loop!

Posted: September 6, 2010 in Android
Tags:

Android has many background processing going on, however it is not very clear at first start how it works. The most general way of doing background tasks and preserving the UI thread is by using android.os.Handler instances. So what is this Handler all about!?

First of all we need to talk about the android.os.Looper class. It is literally a looper, which means that it loops inside a thread run() method waiting for messages to be posted at its message queue in order to be dispatched. Every Looper instance is composed of an andorid.os.MessageQueue instance that queues android.os.Message objects.

What links the Looper and the Handler classes together is the MessageQueue. Every handler is tightly related to a looper instance, dispatching all messages sent to it into the looper’s queue. As soon as the looper consumes the message from the queue, it will dispatch it to the message’s target handler. Note that every looper runs inside one thread and each thread can only have one associated looper, so all you need to do in order for handlers to work correctly is to make sure your handler is tightened to a looper running on the right thread instance.

See the Looper.loop(); method code bellow:

    /**
     *  Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static final void loop() {
        Looper me = myLooper();
        MessageQueue queue = me.mQueue;
        while (true) {
            Message msg = queue.next(); // might block
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                msg.target.dispatchMessage(msg);
                msg.recycle();
            }
        }
    }

So in order to create a Looper and attach it to a Thread instance see code bellow:

public void run() {
	Looper.prepare();
	mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			...
		}
	};
	Looper.loop();
}

The prepare method creates a Looper and associates it to the current running Thread. This is accomplished by using a java.lang.ThreadLocal field, which stores different Looper instances for each thread as shown bellow:

public static final void prepare() {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper());
}

Wait… When was the Handler instance attached to the Looper in the code above ??? The Handler object was not passed anywhere! Well, the magic happens inside the Handler class’ default constructor as shown bellow:

public Handler() {
	// Gets the looper associated to the current thread
	mLooper = Looper.myLooper();
	if (mLooper == null) {
		throw new RuntimeException(
			"Can't create handler inside thread that has not called Looper.prepare()");
	}
	// Gets the looper's queue in order to enqeue the
	// dispatched messages in. See sendMessage methods.
	mQueue = mLooper.mQueue;
	mCallback = null;
}

Now we have a Handler associated to the current thread’s looper message queue. Every sendMessage method will enqueue the message object and the looper will consume the enqueued message on its associated thread. See one of the many sendMessage method flavors bellow:

public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
	boolean sent = false;
	MessageQueue queue = mQueue;
	if (queue != null) {
		msg.target = this;
		sent = queue.enqueueMessage(msg, uptimeMillis);
	}
	else {
		RuntimeException e = new RuntimeException(
			this + " sendMessageAtTime() called with no mQueue");
		Log.w("Looper", e.getMessage(), e);
	}
	return sent;
}

Are you on the Loop now? I hope so!!!

After working with Android telephony for a while and learning about it mostly by looking at the code, I realized that there was not enough documentation about it besides the code itself. This post will provide detailed walk through about the java telephony internals.

The android telephony architecture is split between java and native code. As of today there is a clear documentation about the native layer (http://pdk.android.com/online-pdk/guide/telephony.html), however there is no documentation about the java layer architecture itself.

The android framework classes interact with the Phone API (com.android.internal.telephony.Phone) through two basic method types. Both are based on asynchronous message exchanges.

public void get[…](Message response);

The first type provides a way to get radio and/or network related information asynchronously by passing an android.os.Message class instance. The message will be delivered to the message’s handler when the response from the underlying radio interface layers becomes available.

public void registerFor[…](Handler h, int what, Object obj);

The second type provides a way to get radio/network state updates by registering to receive response messages of the specified type (what parameter) to the specified handler (h parameter) and an optional user object (obj parameter) within the message instance.

The first type of method will call the underlying com.android.internal.telephony.RIL class directly, passing down the message object to be dispatched when the response is available from the underlying layers. The second type may have one or more android.os.Handler instances registered for status updates, they are wrapped on android.os.Registrant objects as weak references in order to allow them to be garbage collected. Because they are not referenced anywhere else, it does not worth sending updates or keeping track of them. The registrants for each register method are stored on android.os.RegistrantList instances so they can be referenced for the future updates.

The communication between the java and native layers is done through a Linux local socket. Every request to the native layer is wrapped into an instance of the com.android.internal.telephony.RILRequest class in order to keep the request information stored until the response is returned the bottom layers. When the response arrives the RILRequest object for the original request will be retrieved from the pending requests list in order to resolve the destination handler to dispatch the response to. The RILRequest class has the following attributes in order to keep the request information:

  • int mSerial; // The request sequence number
  • int mRequest; // The request code
  • Message mResult; // The result message to be dispatched upon response
  • Parcel mp; // The parcel where the raw data will be written and sent though the socket

Once the request object is retrieved or created from the requests pool, every public void get[…](Message response); method will write its parameters (if any) into the request object’s Parcel instance field(mp) and send it to the com.android.internal.telephony.RIL.RILSender class. The RILSender class is a handler that runs on its own looper thread, waiting for new RIL requests to be sent to the native layers through the socket connected to the  RIL daemon as shown on the diagram above. The sender main responsibilities are to store the request object instance into the pending requests list, marshall the parcel into a raw byte array and send it through the socket. The raw request format is specified bellow:

Right now you already know how the requests are sent down to the native layers, but how the request handlers get the response messages back? The com.android.internal.telephony.RIL.RILReceiver class runs on its own thread listening on the RIL daemon socket for asynchronous responses. Its main responsibilities in opposition to the RILSender are to unmarshall the raw data into an android.os.Parcel, process the response and dispatch it inside a message object to its target handler.

There are two kinds of responses that come from the native RIL, solicited and unsolicited commands (see details at http://pdk.android.com/online-pdk/guide/telephony.html). The raw response format for the response types is specified bellow:

Solicited Commands:

Unsolicited Commands:

In conclusion, the java and native layers communicate with each other asynchronously through a socket passing requests/responses up and down the stack.

NOTE: All this article information is based on the Android Open Source Project source code. For details see http://source.android.com/.

Hope you all the best,

David Marques