Android emulator and the SIM card serial number

After publishing the post about changing the IMEI number, I was asked about modifying the SIM card serial number. Yes, it is perfectly possible, but requires a bit more investigation.

In general, the mechanism used is the same (i.e. AT commands sent to the emulated GSM modem). The telephony subsystem sends the following command to the emulated modem to retrieve the SIM card serial number (use any GSM modem manual for reference):

AT+CRSM=176,12258,0,0,10

The first numerical parameter denotes a command to execute on the SIM card, 176 stands for READ BINARY. Second parameter is the field identifier – Integrated Circuit Card identification, that is the SIM card serial number (for the full list of fields, called Elementary Files, refer to 3GPP TS 51.011 specification). Emulated modem responds with the following hard-coded response:

+CRSM: 144,0,98101430121181157002

The string of digits following the second comma is what we’re looking for, however, with every pair of digits swapped. All the SIM card commands and responses can be found in external/qemu/telephony/sim_card.c.

Changing the emulated SIM card serial number is now as easy changing the IMEI. To change the SIM card serial to e.g. 12345678901234567890, one has to:

  • backup the emulator binary 😉
  • open the binary in the hex editor
  • search for 98101430121181157002
  • replace it with 21436587092143658709 (remember about swapping)
Advertisements
Posted in Android. Tags: , . 2 Comments »

Android’s HTTPS implementation slow under debugger

Update: I’ve just discovered that the problem described below only affects Android 1.5 (which is the target platform for my project). Thus another solution is to use AVD configured with Android 1.6 or higher for debugging, and use version 1.5 otherwise to ensure compatibility.

The project I’m working on now communicates with server via custom protocol on top of HTTP and HTTPS (using org.apache.http.client.HttpClient as a HTTP/HTTPS implementation provider). Recently I’ve observed interesting problem of HTTPS requests taking ages to complete if application is executing under debugger control. It makes debugging the code quite frustrating.

To investigate the problem let’s use the following code snippet:

		HttpResponse response = null;
		HttpClient httpClient = new DefaultHttpClient();
		HttpContext localContext = new BasicHttpContext();

		Log.d("--------", "1. Sending http request");
		try {
			response = httpClient.execute(new HttpGet("http://www.apache-ssl.org/"), localContext);
		} catch (Exception e) {
			Log.d("--------", "Request failed", e);
		}
		Log.d("--------", "2. Request finished, status = " + response.getStatusLine().getStatusCode());

		Log.d("--------", "3. Sending https request");
		try {
			response = httpClient.execute(new HttpGet("https://www.apache-ssl.org/"), localContext);
		} catch (Exception e) {
			Log.d("--------", "Request failed", e);
		}
		Log.d("--------", "4. Request finished, status = " + response.getStatusLine().getStatusCode());

This code snippet has been executed on Android emulator (I’ve no device at hand at the moment to try it), platform version 1.5, running on Windows Vista. To make results more dependable the code has been executed five times and average times have been calculated. Sure, it’s not a serious benchmark of any kind, but we only want to have a rough idea what’s going on, right?

A bit of log post-processing reveals the following average times:

  • HTTP, no debugger: 0.80s
  • HTTPS, no debugger: 3.32s
  • HTTP, with debugger: 3.15s
  • HTTPS, with debugger: 142.16s

HTTPS request takes ~45 times longer to complete compared to HTTP, with debugger attached. Without debugger the factor is ~4, which is acceptable.

For the time being I have no explanation for such a big difference. Looking at the stack trace of the thread paused while performing the HTTPS request shows a lot of classes from Bouncy Castle project, as well as classes from org.apache.harmony.xnet.provider.jsse package – JNI interface to OpenSSL library. Some profiling would be necessary…

In case of my application (which always connects to the same, HTTPS-only server) I’ve decided to use the good old stunnel running on my Linux box. It is enough to change the URL in the example above to http://linuxbox:8888 and start stunnel as follows:

czajnik@czajnik:~$ sudo stunnel -c -d 8888 -r www.apache-ssl.org:443

However, it only works for hosts that accept Host: HTTP header value different from actual host name. Ideally, we should be able to leave the original URL and only redirect the socket connection to a different IP and port. And in fact we are, using HttpClient’s proxy settings:

		HttpParams params = httpClient.getParams();
		params.setParameter(ConnRoutePNames.DEFAULT_PROXY, new HttpHost("linuxbox", 8888));

With this setting HttpClient connects to our stunnel process, but still uses original URL – exactly what we need. Of course, URL has to be changed from https:// to http://, as the connection between HttpClient and stunnel is obviously not encrypted. Also, resist the temptation to use localhost 😉

First Android platform build

After playing with Android SDK for a while, now it’s time to try to build the platform. Unfortunately, Android documentation is not the best one I’ve ever seen, and some research is needed. Do they try to promote their web search engine this way? 😉

Fist step is to clone the repository, as described in this guide (I’m going to use donut branch). It goes smoothly, but takes a lot of time (my Internet link goes up to 120kB/s only):

czajnik@czajnik:~/mydroid$ repo init -u git://android.git.kernel.org/platform/manifest.git -bdonut
czajnik@czajnik:~/mydroid$ time repo sync

Next step would be to select the JDK version (android seem to require JDK 1.5), and set basic environment by sourcing one of the shell scripts:

czajnik@czajnik:~$ export JAVA_HOME=/usr/share/jdk1.5.0_22/
czajnik@czajnik:~$ export ANDROID_JAVA_HOME=$JAVA_HOME
czajnik@czajnik:~$ export PATH=/usr/share/jdk1.5.0_22/bin/:$PATH
czajnik@czajnik:~$ cd mydroid
czajnik@czajnik:~/mydroid$ . build/envsetup.sh
including vendor/aosp/vendorsetup.sh
czajnik@czajnik:~/mydroid$

Now we need to select a particular build configuration to be used. On this page (which is a must-read anyway) they mention choosecombo, let’s use it to select generic device debug build (there is also a tool called lunch which allows to select one of the common build types, call it without any parameters to get the list of possibilities and select one interactively):

czajnik@czajnik:~/mydroid$ choosecombo
Build for the simulator or the device?
     1. Device
     2. Simulator

Which would you like? [1]


Build type choices are:
     1. release
     2. debug

Which would you like? [1] 2


Which product would you like? [generic]


Variant choices are:
     1. user
     2. userdebug
     3. eng
Which would you like? [eng]

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=1.6
TARGET_PRODUCT=generic
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=false
TARGET_BUILD_TYPE=debug
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=Donut
============================================

Finally we reached the point where we can start actual build by issuing make -j2. First attempt fails with the following error message:

development/emulator/qtools/trace_reader.cpp: In function ‘char* ExtractDexPathFromMmap(const char*)’:
development/emulator/qtools/trace_reader.cpp:1012: error: invalid conversion from ‘const char*’ to ‘char*’
development/emulator/qtools/trace_reader.cpp:1015: error: invalid conversion from ‘const char*’ to ‘char*’

It’s time for a first useful hint – if you want to see the exact commands executed, invoke make showcommands. Armed with this weapon it’s pretty easy to track the problem. It seems that trace_reader.cpp is expecting C-like string function prototypes in string.h, while string.h on my system exports a C++-compatible declaration. In this particular case:

// C way
char *rindex(const char *s, int c);
// C++ way (overload)
char *rindex (char *s, int c);
const char *rindex (const char *s, int c);

My Linux distribution (Kubuntu 9.10) has switched from glibc to eglibc, included /usr/include/string.h file uses the second type of declaration if used inside a C++ source file, causing the compilation failure. Look at this fragment of string.h:

/* Tell the caller that we provide correct C++ prototypes.  */
#if defined __cplusplus && __GNUC_PREREQ (4, 4)
# define __CORRECT_ISO_CPP_STRING_H_PROTO
#endif

Obviously, there are at least the following solutions:

  • fix Android code (it’s a C++ file, it should expect C++ prototypes)
  • use a system that uses regular glibc
  • use GCC compiler version lower than 4.4
  • comment out #define line above

Of course, I’ve chosen the last option. And that was enough, after almost 80 minutes I’ve got my first own Android image. Now it’s time to hack it a bit – stay tuned!

Posted in Android. Tags: . 2 Comments »

Android 1.5 and ListView’s choiceMode

I’ve just discovered that setting the choiceMode attribute of the ListView element in the XML layout doesn’t work on Android 1.5. Comparing ListView.java from 1.5 and 1.6 releases reveals the following difference (among others):

@@ -166,6 +174,8 @@
             setDividerHeight(dividerHeight);
         }

+        setChoiceMode(a.getInt(R.styleable.ListView_choiceMode, CHOICE_MODE_NONE));
+        
         mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true);
         mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, true);

The change is inside ListView‘s constructor. Looks like someone has forgotten to add the code to retrieve the choiceMode attribute, and that was fixed in 1.6. I’ve found no ticket for that in the Android tracker, however.

Anyway, if you want your code to be 1.5-compatible, you’d rather call setChoiceMode() explicitly in your code.

Posted in Android. Tags: , . 2 Comments »

Android platform guide

After playing with Android SDK for some time, now I’m trying to make my own platform build and hack around a bit. Recently I’ve found the Android Platform Developer’s Guide site. It contains some very useful hints, but the site doesn’t seem referenced from neither http://developer.android.com/ nor http://source.android.com/. Serious oversight, isn’t it? Or did I overlook something?

Android: IMEI number and the emulator

Update: Please see my latest post about this topic.

It is a common practice for mobile applications to identify the user by IMSI number (associated with the SIM card) or IMEI number (unique ID of the device). Of course, it is also possible on Android:

TelehponyManager manager = (TelehponyManager)getSystemService(TELEPHONY_SERVICE);
String imei = manager.getDeviceId();
String imsi = manager.getSubscriberId();

This code works perfectly fine on a real device, however under emulator IMEI is always all-zero and it’s not configurable. It quickly becomes awkward when debugging a network-enabled application which uses IMEI as a user ID.

Trying to resolve the problem I first looked at the TelephonyManager service, just to find the following snippet:

    private IPhoneSubInfo getSubscriberInfo() {
        // get it each time because that process crashes a lot
        return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
    }

Fair comment, isn’t it? It really made my day 🙂

Anyway, code analysis shows that IMEI/IMSI request goes down through all the telephony layers (see the diagram), eventually getting to  the baseband device. In case of emulated system, rild daemon is used together with libreference-ril.so – reference Vendor RIL library which talks to the baseband modem device using plain, old AT commands.

The modem device itself is emulated outside the Android system, as part of qemu (which is the heart of the emulator). Details of the communication between the emulator and the Android system running inside the emulator are interesting on its own (all the communication goes through a virtual serial port, Android system’s qemud daemon is used to (de)multiplex the data). I’ll try to post a brief introduction to the topic soon.

Virtual modem implementation can be found in external/qemu/telephony/android_modem.c. The most important part of the file is this function:

const char*  amodem_send( AModem  modem, const char*  cmd );

This function is called for each received AT command. For each command sDefaultResponses array is searched for a given command and either predefined response is sent, or a command handler is executed. The array itself looks like:

static const struct {
    const char*      cmd;     /* command coming from libreference-ril.so, if first
                                 character is '!', then the rest is a prefix only */

    const char*      answer;  /* default answer, NULL if needs specific handling or
                                 if OK is good enough */

    ResponseHandler  handler; /* specific handler, ignored if 'answer' is not NULL,
                                 NULL if OK is good enough */
} sDefaultResponses[] =
{
    /* ... */
    { "+CIMI", OPERATOR_HOME_MCCMNC "000000000", NULL },   /* request internation subscriber identification number */
    { "+CGSN", "000000000000000", NULL },   /* request model version */
    /* ... */
};

Two array rows cited above are responsible for IMSI and IMEI retrieval. As you can see, both values are hardcoded and there is no chance to modify them without recompiling the emulator.

However, an old-school hack comes in handy. The emulator binary is not encrypted nor compressed, so the string literals should be visible inside the emulator binary. In fact they are, and IMEI number can be modified in a few simple steps:

  • backup the emulator binary
  • open the binary with your favourite hex editor
  • search for +CGSN string followed by a null byte, it should be followed by 15 digits of the IMEI number
  • edit the number, be careful not to change the number of digits
  • save the file, that’s all!

Sure, it’s not a perfectly comfortable solution, yet better than nothing. In the next part I’ll explain how to make IMEI number a configurable option. Enjoy!