Exploring Android Telephony Internals

A lot of code lies between creating an ACTION_CALL Intent object and dialing a call. Here we will go even deeper into Android's telephony system to see what Android is telling the mobile radio, and match that up with what we have done in the example application earlier in this chapter.

To see how, and when, Android actually commands the hardware to dial a number, we can use Android's logging system. To access the log buffer for information about the traffic between Android software and the mobile radio, we will also have to use the Android Debug Bridge, adb. We will start a shell that can run commands in the emulator, and we will use the logcat utility to display logging information as it becomes available.

First, set a breakpoint in the example application on line 25, where the Intent object is created and before the call to the startActivity method.

Then, start the application with the debugger: Select Run —• Debug. When the "Debug as" dialog appears, select Android Application.

The application will run and stop at the breakpoint.

Now look at the log. Open a command-line window and change your working directory to the directory where you have put the Android SDK. There you should see a directory named tools. Change your working directory to tools. You should see a program there named adb.

Next, use adb to find the name of the emulator that is running as a result of starting the application with the debugger. Type the following: ./adb devices adb will list all the emulators running, which should be just one. The output will look something like this:

emulator-5554 device

Now use adb to start a shell that can run programs in the emulator (if adb finds an emulator with a different name on your system, use that name instead of "emulator-5554"):

./adb -s emulator-5554 shell

This will result in a shell prompt: #

The shell you are now typing commands into is executing those commands in the emulator. Now use the logcat command to show the log of traffic between the mobile radio and the RIL: # logcat -b radio

This will result in a lengthy listing of AT commands and responses. For the most part, they are asking for and reporting the signal strength. This is what the RIL and the mobile radio are doing when nothing else is going on.

The lines tagged D/AT are the verbatim AT commands exchanged between the mobile radio and the RIL. The ones labeled AT> are from the RIL to the mobile radio, and the ones labeled AT< are from the mobile radio to the RIL. The other lines in the log are a more-readable decoding of the information in the AT commands. You can see the part of the RIL interface in Java logging requests sent to the RIL daemon, RILD, and the RIL code in RILD logging as it sends the appropriate AT commands to the mobile radio and decodes the results.

Now use the Eclipse debugger to step over the line where the Intent object is created. Looking at the log output, you see that nothing interesting has happened yet: the RIL and the mobile radio (really, an emulation of a mobile radio) are polling the signal strength. Step over the next line, where the phone number is added to the Intent object and, similarly, nothing has happened yet.

Now step over the next line, which should look like this: startActivity(callIntent);

Here we get quite a bit of interesting output from the logger. It should look something like this:

D/GSM ( 85): [GSMConn] update: parent=DIALING, hasNewParent=false, wasConnectingInOrOut=true, wasHolding=false, isConnectingInOrOut=true,changed=false D/RILJ ( 85): [0161]> SET_MUTE false D/RIL ( 22): onRequest: SET_MUTE D/RILJ ( 85): [0161]< SET_MUTE error:

com.android.internal.telephony.gsm.CommandException: REQUEST_NOT_SUPPORTED D/RIL] ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0162]> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC

D/AT ( 22): AT< +CLCC: 1,0,2,0,0,"9785551212",129 D/AT ( 22): AT< OK

D/RILJ ( 85): [0162]< GET_CURRENT_CALLS [id=1,mo,DIALING,voice,norm,129,0] D/GSM ( 85): [GSMConn] update: parent=DIALING, hasNewParent=false, wasConnectingInOrOut=true, wasHolding=false, isConnectingInOrOut=true, changed=false D/AT ( 22): AT< RING

D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0163> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC

D/AT ( 22): AT< +CLCC: 1,0,3,0,0,"9785551212",129 D/AT ( 22): AT< OK

D/RILJ ( 85): [0163]< GET_CURRENT_CALLS [id=1,mo,ALERTING,voice,norm,129,0] D/GSM ( 85): [GSMConn] update: parent=ALERTING, hasNewParent=false, wasConnectingInOrOut=true, wasHolding=false, isConnectingInOrOut=true, changed=true D/RILJ ( 85): [0164]> SET_MUTE false D/RIL ( 22): onRequest: SET_MUTE D/RILJ ( 85): [0164]< SET_MUTE error: com.android.internal.telephony.gsm.CommandException: REQUEST_NOT_SUPPORTED D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0165> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC

D/AT ( 22): AT< +CLCC: 1,0,3,0,0,"9785551212",129 D/AT ( 22): AT< OK

D/RILJ ( 85): [0165]< GET_CURRENT_CALLS [id=1,mo,ALERTING,voice,norm,129,0] D/GSM ( 85): [GSMConn] update: parent=ALERTING, hasNewParent=false, wasConnectingInOrOut=true, wasHolding=false, isConnectingInOrOut=true, changed=false D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0166]> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC

D/AT ( 22): AT< +CLCC: 1,0,3,0,0,"9785551212",129 D/AT ( 22): AT< OK

D/RILJ ( 85): [0166]< GET_CURRENT_CALLS [id=1,mo,ALERTING,voice,norm,129,0] D/GSM ( 85): [GSMConn] update: parent=ALERTING, hasNewParent=false, wasConnectingInOrOut=true, wasHolding=false, isConnectingInOrOut=true, changed=false D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0167]> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC D/AT ( 22): AT< RING

D/AT ( 22): AT< +CLCC: 1,0,0,0,0,"9785551212",129 D/AT ( 22): AT< OK

D/RILJ ( 85): [0167]< GET_CURRENT_CALLS [id=1,mo,ACTIVE,voice,norm,129,0] D/RILJ ( 85): [0168]> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC

D/AT ( 22): AT< +CLCC: 1,0,0,0,0,"9785551212",129 D/AT ( 22): AT< OK

D/RILJ ( 85): [0168]< GET_CURRENT_CALLS [id=1,mo,ACTIVE,voice,norm,129,0]

D/GSM ( 85): [GSMConn] update: parent=ACTIVE, hasNewParent=false, wasConnectingInOrOut=true, wasHolding=false, isConnectingInOrOut=false, changed=true D/GSM ( 85): [GSMConn] onConnectedInOrOut: connectTime=1225978001674 D/RILJ ( 85): [UNSL]< CALL_STATE_CHANGED D/RILJ ( 85): [0169]> SET_MUTE false D/RIL ( 22): onRequest: SET_MUTE D/RILJ ( 85): [0169]< SET_MUTE error: com.android.internal.telephony.gsm.CommandException: REQUEST_NOT_SUPPORTED D/RILJ ( 85): [0170]> GET_CURRENT_CALLS D/RIL ( 22): onRequest: GET_CURRENT_CALLS D/AT ( 22): AT> AT+CLCC

D/AT ( 22): AT< +CLCC: 1,0,0,0,0,"9785551212",129 D/AT ( 22): AT< OK

D/RILJ ( 85): [0170]< GET_CURRENT_CALLS [id=1,mo,ACTIVE,voice,norm,129,0] D/GSM ( 85): [GSMConn] update: parent=ACTIVE, hasNewParent=false, wasConnectingInOrOut=false, wasHolding=false, isConnectingInOrOut=false, changed=false

What you are seeing here is a mobile call being started. The call goes through three states: "dialing," "alerting," and "active." Take a look at how the mobile radio reports the state of a call. Here the call is in the "dialing" state:

+CLCC: 1,0,2,0,0,"9785551212",129 Here the call is in the "alerting" state:

+CLCC: 1,0,3,0,0,"9785551212",129 Here the call is in the "active" state: +CLCC: 1,0,0,0,0,"9785551212",129

The third number in the list of parameters in the AT command response indicates the state of this call. The classes that model the connection, call, and network state in PhoneApp and the TelephonyManager API keep track of what RILD is telling the mobile radio and what the mobile radio is telling RILD, and this is where that information comes from.

Now press the red End button (the one with the picture of a telephone receiver) to end the call. Look for the AT commands that read the state change from the mobile radio, and at the corresponding TelephonyManager method call that notifies the application of the change.

+2 -1

Post a comment