This blog has moved

I decided to transfer the blog to my own server. I’m going to leave all the content here for some time (there are websites with links to my posts already). For all the new content, however, please follow the link: http://blog.codepainters.com.

Advertisements

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!

Why ‘make’ must die…

One of my tasks at work is maintaining a make-based build system.  It is required to build our software properly on Linux and Windows (cross-compilation, our target CPU is Hitachi SH4). Anytime I have to dive into makefiles, I’m wondering why a tool like that is still in widespread use. Please note, that I’m quite familiar with make, I’ve done some reading and feel more or less comfortable with what I’m doing. However, I can probably name a few obvious problems of make. The problems I list here are of different caliber, but those are the most annoying ones from my (and my team) perspective.

  • The first issue is makefile syntax. It requires some time to get used to (yes, it is possible). However, if the type of whitespace used in a file matters, there’s something wrong.
  • The next (little) flaw is the way make handles shell commands.  If you write a multi-line script inside a makefile rule, make spawns a new shell for each line. It is a common mistake, to write a rule like that:
    foo: bar
           cd some_dir
           do_something
    

    In this example cd command has just no effect, as do_something is executed in a brand new shell process. Sure, it is very easy to workaround this issue, still you need to be aware. Surprisingly high amount of questions I get form other team members deal with this particular issue.

  • In my opinion the biggest issue is the way make supports recursive builds. Virtually every serious project contains some hierarchy of directories with source code. On the other hand, make gives little support for recursive compilation. Either you need to literally spawn make recursively for each subdirectory, which is just silly, or you have to use various tricks in your Makefile to collect all the sources form subdirectories (it is well described in a book). Why should I really care?
  • Finally, make gives little support for cross-platform builds, beyond the fact that make itself is available on many platforms. Unfortunately, even the things like path separator slashes need to be handled manually in many cases. I don’t even want to mention autotools here, that’s another painful story.

Fortunately, there are alternatives. At the moment I’m evaluating SCons, and I’m quite satisfied. I’ll share my experience soon.