HTC OTA updates

by on Jul.31, 2010

I’m a little bored, and the whole internet (well, at least the portion of it composed of Desire owners) seems to be going crazy waiting around for the recently-announced rolling out of the Android 2.2 update for the HTC Desire, so I thought I’d poke around a little in the OTA update process.

UPDATE (2010/08/03): The update seems to be rolling out to most people, but some people still aren’t getting it, even though they have unlocked/unbranded phones. From what I’ve been able to discover, HTC appears to be employing an IMEI “blacklist” of some kind; checkins with specific IMEI values fail to return the 2.2 update, but anything else (including completely invalid IMEI values) returns the update. I’m still not sure whether this is just their way of staggering the update, or if there is some other reason for withholding the update from the affected devices.

UPDATE (2010/08/05): HTC now seems to either have a bad content server, or be in the process of pulling the update from their servers, including the update file itself on If it is deliberate, I have no idea why they’re doing it, and I can’t currently find any information that sheds any light.

The process seems to be relatively straightforward: when you hit “Check now”, the phone sends an HTTP POST to (not https, thus all in the clear, making it easy for me to sniff :P), with a Content-Type of “org/x-json” (wat), and a JSON-encoded payload. The payload looks as follows (I’ve pretty-printed it and stripped personal identifiers, but it’s still good enough to get a response):

  "locale": "en_GB",
  "checkin": {
    "build": {
      "product": "bravo",
      "serialno": "HTXXXXXXXXXX",
      "changelist": "174215",
      "build_type": "user",
      "carrier": "htc_wwe",
      "radio": "",
      "firmware_version": "1.21.405.2 CL174215 release-keys",
      "bootloader": "0.80.0000",
      "id": "htc_wwe/htc_bravo/bravo/bravo:2.1-update1/ERE27/174215:user/release-keys",
      "revision": "129"
  "model_number": "HTC Desire",
  "logging_id": 0,
  "imei": "",
  "id": 0,
  "digest": "8fccfd93dcbe837d072e5f1494da2"

Note the “carrier” value there; this is “htc_wwe” for phones that are not carrier-locked / otherwise carrier-customized. If you had a Sprint phone, for example, this would be “sprint”. I believe this value is ultimately determined by the the “androidboot.carrier” kernel parameter passed to the kernel by the boot loader.

I’m not sure what “digest” is of; it is 29 hex digits long, which doesn’t make any sense for a cryptographic digest. It doesn’t seem to be a personal identifier of any kind, though; if you modify it, you get some “upload crash” response back, which contains (among other things) the correct digest, so I can only guess that it corresponds to the product information in some way. I’ll be interested to see if it changes once I have the new update installed.

The response that comes back looks like this:


The “intent” part will probably be obvious to Android developers (it’s specifying what the UI should do next), and time_msec is a UNIX timestamp in milliseconds, corresponding to the time the response was sent.

If an update *is* available, the response looks like this instead:

  "stats_ok": true,
  "intent": [
      "action": "android.server.checkin.FOTA_UPDATE",
      "data_uri": "",
      "extra": [
          "name": "promptMessage",
          "value": "System Upgrade"
          "name": "promptFeature",
          "value": "Update:HTC application improvement"
          "name": "promptVersion",
          "value": "System upgrade1.21.405.2 (27.07 MB)We would recommend using a free Wi-Fi hotspot or an unlimited data plan to apply this update. If not, standard data connection charges may apply. Any questions? Contact us via"
          "name": "promptSize",
          "value": "27.07 MB"
          "name": "promptMinutes",
          "value": "30,..."
          "name": "timeoutSeconds",
          "value": "120"
          "name": "force_update",
          "value": "false"
  "time_msec": "1280513282008"

Now, it seems as if they are planning to do a rolling release of the 2.2 update, somehow. I assume this means that they will only be responding with the updated version to some requests, but I don’t know exactly what mechanism they’ll be using to do that. Oh well…

:, , ,

  • Snark

    I did the same analysis yesterday evening and made a Python script to check for an update every 5 minutes and alert me when an update is found (something else than FOTA_CANCEL received).

    Didn’t go as far as checking what is the answer if an update is found though.

  • mithrandi

    Yay, update is out :) (I just woke up, still waiting for it to download…)