UDP Multicast on Android

Estimated read time: 3 min

Originally published on September 4th, 2012 (Last updated on July 3rd, 2020)

I start­ed work­ing on a small inven­to­ry sys­tem, that keeps track of all the things I buy. To enter new items quick­ly into the sys­tem, I need­ed a bar­code-scan­ner to scan new arti­cles, trans­fer them to my com­put­er and allow me to (for exam­ple) paste them into a focused input-field.

I wrote a small Android appli­ca­tion, that uses zxing to scan the bar­codes and a sim­ple mul­ti­cas­t­ed UDP net­work con­nec­tion to broad­cast the con­tents of the code to all lis­ten­ing net­work devices. This way, I don’t need to enter any IP address­es or host-names in the app to reach the lis­ten­ing serv­er appli­ca­tion on my com­put­er. The MulticastSocket of the java stan­dard library seemed per­fect for this purpose.

When Android interferes #

After the appli­ca­tion was cre­at­ed, I tried it out, just to real­ize that… well, noth­ing hap­pened. After some research on the inter­net, I found out that Android itself was the source of the problem:

pub­lic class WifiManager.MulticastLock

Allows an appli­ca­tion to receive Wifi Mul­ti­cast pack­ets. Nor­mal­ly the Wifi stack fil­ters out pack­ets not explic­it­ly addressed to this device. Acqur­ing a Mul­ti­cas­t­Lock will cause the stack to receive pack­ets addressed to mul­ti­cast address­es. Pro­cess­ing these extra pack­ets can cause a not­i­ca­ble bat­tery drain and should be dis­abled when not needed.

Even though the doc­u­men­ta­tion only talks about receiv­ing mul­ti­cast pack­ages, the same applies for send­ing them: You need to obtain the MulticastLock in order to work with mul­ti­cast packages.

Acquir­ing a lock #

Actu­al­ly get­ting the required lock isn’t that much trou­ble at all. Declared the fol­low­ing per­mis­sions in your manifest:

<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

Then use the WifiManager to acquire the lock:

WifiManager wifi = (WifiManager)getSystemService( Context.WIFI_SERVICE );
if(wifi != null){
    WifiManager.MulticastLock lock = wifi.createMulticastLock("Log_Tag");
    lock.acquire();
}

The mul­ti­cast-lock is acquired until:

Locks Wifi Mul­ti­cast on until release() is called. […] When an app exits or crash­es, any Mul­ti­cast locks will [also] be released.

Sending/​receiving should work now. Unless…

Device prob­lems #

… you run into the sit­u­a­tion where you have a device that just can’t do it.

Read­ing mul­ti­ple top­ics, blog-posts and bug-reports, it turns out that some devices don’t (or don’t ful­ly) sup­port mul­ti­cast. Whether they do or don’t depends on both the ven­dor (because they build/​optimize the ker­nel) and the Android version.

To quote from an Issue regard­ing Android 1.5 — 2.1

I’ve spent quite a bit of time debug­ging mDNS issues with JmDNS on my Evo and HTC Hero (CDMA). What I found is there appears to be a fil­ter in place in the broad­com wire­less dri­ver on the Evo (and since I’m get­ting a sim­i­lar report from an HTC Desire user — with the same chipset, pre­sum­ably that hand­set as well). The fil­ter, by default, blocks any non-uni­cast or net­work broad­cast traf­fic, includ­ing mul­ti­cast. Appar­ent­ly the the­o­ry was it’s a bat­tery saver. 

The prob­lem appears to be the wpa_supplicant on the Evo does not sup­port remov­ing those fil­ters when you get a Mul­ti­cas­t­Lock. (Check the log out­put right after you get the lock and you’ll see what I mean). Unfor­tu­nate­ly what has hap­pened is the hard­ware ven­dors have frag­ment­ed mul­ti­cast support.… :(

It has been report­ed that switch­ing the /system/bin/wpa_supplicant-bina­ry to a new­er ver­sion has fixed the issue for those devices, but this comes with two big downsides:

  1. The phone needs to be rooted
  2. You can’t rely on your users to pro­vide a work­ing envi­ron­ment for your application

If you’re curi­ous, the Issue with the sug­gest­ed workaround can be found here: Android Issue #8407

Anoth­er pos­si­ble cause might be a prob­lem with the imple­men­ta­tion of IGMP on those devices, as sug­gest­ed in Isaac Tay­lor’s blog-post: Mul­ti­cast and Android – A Big Headache 

Check if it works #

Well, if it’s bro­ken on some devices, there should be a way to tell if it isn’t work­ing on the cur­rent one, or is there? The answer here is no.

There seems to be no reli­able way of telling if mul­ti­cast works on the cur­rent device. Some devices give error-mes­sages in their log-cat out­put, some sim­ply fail silent­ly (like my HTC Desire HD).

What makes deter­min­ing a work­ing envi­ron­ment even hard­er is, that the prob­lem results from mul­ti­ple sources. It might be the low­er-lev­el net­work imple­men­ta­tion, the ker­nels net­work dri­vers or the IGMP imple­men­ta­tion. And there is cur­rent­ly no reli­able way of test­ing for all those cases.

The same code that fails on my HTC Desire HD (Android 2.3.5) works fine on my Motoro­la Xoom (Android 4.0.4).

Con­clu­sion #

  • Try avoid­ing mul­ti­cast in deployed appli­ca­tions for end-users or pro­vide alter­na­tives (direct com­mu­ni­ca­tion still works fine).
  • Acquire the MulticastLock so the sys­tem does not ignore the pack­ages send/​received
  • If you’re hav­ing prob­lems, check the net­work-traf­fic with tools like Wire­Shark or tcp­dump.

Posted by Lukas Knuth

Comments

No com­ment sec­tion here 😄

You can reach me over at @knuth_dev or send me an Email.