Previous section   Next section

Mobile Phone Handheld Hardware Hardware Rick Rogers John Lombardo O'Reilly Media, Inc. O'Reilly Media Android Application Development, 1st Edition

15.2. Android Telephony Internals

The rest of this chapter covers telephony-related classes in the internals package that only PhoneApp uses, android.internal.telephony. This package is layered over an implementation of telephony internals for a particular telephony technology, such as GSM or CDMA. That layer, in turn, communicates with a Radio Interface Layer (RIL) that is implemented as a daemon in Android.

Figure 15-1 shows the architecture of the Android telephony system. PhoneApp supports an Intent that enables other applications to start phone calls. The Telephony Manager is available through Listeners, as shown in the previous section.

Figure 15-1. Layers of telephony packages


15.2.1. Inter-Process Communication and AIDL in the android.internal.telephony Package

Many of the internal packages use the remote methods feature discussed in Section 13.2. The TelephonyManager and PhoneStateListener classes rely on this to communicate with PhoneApp. The ServiceManager class is also used.

To marshall data for remote methods, the package includes AIDL files. For instance, the following AIDL comes from IPhoneStateListener.aidl:

oneway interface IPhoneStateListener {
    void onServiceStateChanged(in ServiceState serviceState);
    void onSignalStrengthChanged(int asu);
    void onMessageWaitingIndicatorChanged(boolean mwi);
    void onCallForwardingIndicatorChanged(boolean cfi);

    // we use bundle here instead of CellLocation so it can get the right subclass
    void onCellLocationChanged(in Bundle location);
    void onCallStateChanged(int state, String incomingNumber);
    void onDataConnectionStateChanged(int state);
    void onDataActivity(int direction);
}

15.2.2. The android.internal.telephony Package

This package contains the classes and interfaces PhoneApp uses to provide services to other applications that want to start phone calls, and classes that define an API to the RIL.

PhoneApp, like all parts of Android, is theoretically replaceable. If your application needs to modify the classes used by PhoneApp, your application will probably have to replace or modify PhoneApp, and should provide the same services to other applications, using the classes in this package.

The description of these classes should help you understand how Android interfaces to a mobile radio, and the capabilities that are exposed—and not exposed—by PhoneApp to other applications. This is a large and complex package, and a complete understanding will require reading the Android source code. These descriptions will help you find where to start for your purposes:


ATParseEx

Extends RuntimeException and is thrown by methods of the ATResponseParser class.


ATResponseParser

This class parses part of the AT command syntax used to communicate with the mobile radio hardware in a mobile handset. This is, in fact, a command syntax very much like the AT command syntax used by modems, a standard described in the 3GPP document number TS 27.007 and related specifications. This protocol for controlling mobile radios is widely used.


Call

This class is an abstract base class. Other classes use it as a basis for objects that represent phone calls and the state of those calls.


CallerInfo

This class holds information about the party that originated an incoming call. This class starts with caller ID information from the mobile network interface and looks up other information about a caller in the database of contacts.


CallerInfoAsyncQuery

This class enables asynchronous database queries for information that could be found about a caller based on the caller ID information.


CallStateException

The class extends Exception and is thrown by methods that maintain call state in cases where state is inconsistent.


Connection

This class is an abstract base class used by other classes, and is a basis for objects that represent connections on the mobile network and the state of these connections. Connection objects can be associated with a Call object, but they can also exist independently. The data in a Connection object can be especially useful in diagnosing the reason a call failed.


DefaultPhoneNotifier

This class implements the PhoneNotifier interface in order to receive notifications from a Phone object. It then uses the Android service system to communicate state to Activity instances that have registered to receive those notifications. See the Handler and Mailbox classes for information on how to receive notifications.


IPhoneStateListener

This interface defines the signatures of methods an application implements to receive notification of call state change, and changes to forwarding and message-waiting states.


IPhoneSubInfo

This interface is used to obtain subscriber information.


ITelephony

This interface defines the inter-process interface used in TelephonyManager to enable applications to communicate with PhoneApp.


ITelephonyRegistry

This interface is the callback interface from the RIL daemon.


MmiCode

This interface defines callbacks related to "MMI codes." These are special numbers a user can dial and key sequences that a user can enter during a call to access, control, and administer supplementary services, such as call waiting, call hold, etc. MMI codes and related functionality are described in the 3GPP document number TS 22.030.


Phone

This interface includes callbacks and methods for accessing the state of a mobile phone.


PhoneBase

This class is an abstract base class that implements the Phone interface.


PhoneFactory

This class contains methods used to create instances of the GSMPhone class, a subclass of the Phone class.


PhoneNotifier

This interface specifies the API a telephony implementation uses to notify a phone state listener of state changes.


PhoneStateIntentReceiver

This class handles Intent objects that have intent types specified in the Tele⁠pho⁠nyIn⁠tents class. This class enables Android applications to use the Intents system to obtain phone state information.


PhoneSubInfo

This class contains methods for obtaining information about a mobile service subscriber, such as the unique identifying number for the handset (IMEI), the unique identifying number for the subscriber (IMSI), the serial number of the SIM card, etc.


SimCard

This interface defines the API for accessing the SIM card.


TelephonyIntents

This class defines constants for broadcast intents that have similar functionality to the TelephonyManager API.


TelephonyProperties

This class defines the constants used with the SystemProperties class for setting and getting telephony-related properties.

These classes are not documented in the Android SDK documentation, but the descriptions here should give you some understanding of the source code for these classes.

15.2.3. The android.internal.telephony.gsm Package

Many of the classes and interfaces in the previous section are typical of a Java API that can have multiple implementations. The implementations of the API defined in the telephony.internal package correspond to a library used in the RIL. To better understand this API, we will look at one implementation here that supports GSM.

Thus, this section delves further into the telephony internals of Android, looking especially at how the interfaces and abstract base classes are implemented and subclassed to enable access to the functionality of GSM telephony. Although it may seem that specifications such as TS 27.007 cover mobile telephony in general, this layer of Android actually has to accommodate variations in mobile telephony standards. In CDMA telephony, for instance, the SIM card is an optional part of the standard and is rarely present in CDMA handsets. In this case, the package described in this section would be replaced by a CDMA-oriented package with a similar architectural relationship to the higher-level classes described in the previous section. The RIL code is also specific to the type of telephony in the handset.

At the RIL layer, the differences between GSM and CDMA are mainly outside the core functionality of making phone calls, so you may be wondering why all these layers and APIs are necessary. But, as the description of the classes specific to communicating with a GSM RIL will show, there are plenty of differences in detail, such as SIM cards, the type of mobile data network, etc. These make it impractical to design a universal interface to mobile radios, despite the use of a standard protocol for communicating with them:


AdnRecord

This class is used to load and store Abbreviated Dialing Numbers (ADNs) to and from the SIM card. ADNs are short numbers used for information calls, emergency calls, etc.


AdnRecordCache

This class caches and enables access to ADNs.


ApnSetting

This class holds data specifying the access point name (APN) and other parameters for connecting to General Packet Radio Service (GPRS) and 3G mobile data networks. This mobile data technology is specific to GSM networks.


BaseCommands

This class implements the CommandsInterface interface, which is used throughout the GSM telephony classes to communicate with the GSM radio.


CallFailCause

This interface defines constants for decoding failure cause codes.


CallForwardInfo

This class holds data that corresponds to the parameters of a call-forwarding command to the RIL.


CallTracker

This class maps information from the RIL to state transitions for the GSMCall class.


CommandException

This class is an exception thrown when the RIL reports an error from a command.


CommandsInterface

This interface defines the API to the GSM RIL. This interface is implemented by the BaseCommands class.


DataConnectionTracker

This tracks the state of GPRS packet data protocol (PDP) connections. This type of connection is specific to GSM mobile data.


DataLink

This class implements the DataLinkInterface interface and is used in the PPPLink class, which manages point to point protocol (PPP) links in GPRS networking.


DataLinkInterface

This class defines the API for connecting and disconnecting PPP links.


DriverCall

This class parses information, in AT command syntax, from the mobile radio, and turns it into call state information.


EncodeException

This class is an exception thrown by methods of the GSM alphabet class, which encodes UTF-16 (as used in Java) into the 7-bit SMS character set.


GSMAlphabet

This class is a utility class containing static methods for encoding UTF-16 to the 7-bit SMS character set.


GSMCall

This class extends the Call class, and implements the abstract methods of that class, thereby implementing parts of the Android telephony internals API. This class models calls in GSM telephony.


GSMConnection

This class extends the Connection class, and like the GSMCall class, implements the abstract methods of the Connection class. This class models connections in GSM telephony.


GSMPhone

This class extends the Phone class and, as with both the GSMCall and GSMConnection classes, implements the abstract methods of the Phone class.


GsmMmiCode

This class implements the MmiCode interface and the part of the telephony API defined in that interface.


GsmSimCard

This class implements the SimCard interface, another part of the implementation of the telephony internals API. This class enables access to data in the SIM card.


ISimPhoneBook

This interface defines an API for accessing ADN records stored in the SIM card.


ISms

This interface defines the API for sending SMS messages.


MccTable

This class is a utility class that contains a table of Mobile Country Codes (MCCs). In principle, these codes are not specific to a GSM RIL, but they are specific to this implementation of a GSM RIL.


NetworkInfo

This class is a container for network state information.


PDPContextState

This contains data about a PDP session, including the IP address.


PdpConnection

This class contains information about the data connection associated with a PDP context.


PppLink

This class extends DataLink and implements DataLinkInterface to provide an implementation of this part of the RIL interface.


RIL

This class extends the BaseCommands class and also implements the CommandsInterface interface, forming a complete implementation of the interface for sending commands to the RIL. This is where communication with the RIL takes place. An instance of the RIL class is created in the PhoneFactory class, in the course of creating an instance of the GSMPhone class.


RILConstants

This interface defines constants used in the RIL class.


ServiceStateTracker

This class polls the RIL daemon for signal strength and tracks other aspects of the state of mobile service.


SIMFileHandler

This enables access to the SIM filesystem.


SIMRecords

This class enables access to specific files in the SIM filesystem containing information such as the subscriber's IMSI.


SimConstants

This interface contains constants used in other classes accessing data in the SIM.


SimException

This class extends Exception and is used in other classes to throw an exception related to errors accessing data in the SIM.


SimFileNotFound

This class extends SimException and is used in the SimIoResult class in specific error conditions.


SimPhoneBookInterfaceManager

This class extends ISimPhoneBook and provides a service interface for accessing ADN records in the SIM.


SimProvider

This class extends ContentProvider and creates a content provider interface to SIM ADN/SDN/FDN records in the SIM.


SimSmsInterfaceManager

This class extends ISms and creates a service interface for accessing SMS messages stored in the SIM.


SimTlv

This class is an object interface for accessing tag-length-value records in the SIM, and is used in the SIMRecords class.


SimUtils

This class contains static utility methods for manipulating data encoded in binary-coded decimal and other encodings encountered in SIM data.


SMSDispatcher

This class implements the sending of SMS messages and notifies applications that use the Handler interface to this class regarding the status of SMS messages.


SmsHeader

This class contains constants and methods for decoding SMS headers.


SmsRawData

This class implements Parcelable and is used in implementing service interfaces for accessing SIM data.


SmsResponse

This class associates a message reference with an acknowledgment.


SuppServiceNotification

This class contains constants for decoding information about supplementary services.


VoiceMailConstants

This class parses information in the etc/voicemail-conf.xml file.

There is another package organized hierarchically under the internal.telephony.gsm package: the stk package, which contains classes for accessing the SIM. This package is not exposed outside the internal.telephony.gsm package and is beyond the scope of this chapter.

15.2.4. 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/RILJ ( 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): [UNSL]< CALL_STATE_CHANGED
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.

          
      Previous section   Next section