Friday, April 27, 2012

Deep look at Android Networking. Part 1. Introduction.

Most modern applications are actively using internet to interact with outer world. Internet has become an integral part of mobile development. Android OS is based on the Linux kernel and contains mighty set of networking capabilities inherent from it lower layer.
This topic is not about application layer of network stack. Examples about how to get content of some url or download file can be easily found in internet (including android developers). Purpose of the topic is to consider basic points of network stack in context of android and java.
Lets start from Network Interface - point of interconnection between a your device and a private or public network. It's generally a network interface card (NIC), but doesn't have to have a physical form - network interface can be implemented in software layer. For example, every android device (even when wifi is disabled and no mobile network configured) has the loopback interface (127.0.0.1 for IPv4 and ::1 for IPv6) - it's not a physical device but a piece of software which simulating a network interface.
To get list of available interfaces use NetworkInterface#getNetworkInterfaces:
 NetworkInterface.getNetworkInterfaces()  
Width disabled wifi and mobile connection you will typically get only one network interface - loopback interface lo0. NetworkInterface doesn't provide any particular information about network interface card (NIC) which it represents (however, it is worth noting that since sdk 9 a few additional method were added). Only things you can get - local name of interface and assigned ip address (like pdo0 and 46.133.18.123). Considering fact that only 'raised' interface will be found by NetworkInterface#getNetworkInterfaces it's hard to find any practical use of NetworkInterface (it can't be used to figure out connected or interface which performs data transmission or to check metric of interface) - it's interesting only in theoretical context (it's must less functional than NetworkInterface from java SE sdk).
Unfortunately, android shell (adb shell) doen't provide all linux network commands (like ifconfig). But even supported commands, like, netcfg, not always works like expected. For example, with enabled (and connected wifi) we will see:
$ netcfg
lo       UP    127.0.0.1       255.0.0.0       0x00000049
usb0     DOWN  0.0.0.0         0.0.0.0         0x00001002
tunl0    DOWN  0.0.0.0         0.0.0.0         0x00000080
gre0     DOWN  0.0.0.0         0.0.0.0         0x00000080
sit0     DOWN  0.0.0.0         0.0.0.0         0x00000080
svnet0   UP    0.0.0.0         0.0.0.0         0x000000d1
eth0     UP    192.168.100.163 255.255.255.0   0x00001043
while with wifi disabled:
$ netcfg
lo       UP    127.0.0.1       255.0.0.0       0x00000049
usb0     DOWN  0.0.0.0         0.0.0.0         0x00001002
tunl0    DOWN  0.0.0.0         0.0.0.0         0x00000080
gre0     DOWN  0.0.0.0         0.0.0.0         0x00000080
sit0     DOWN  0.0.0.0         0.0.0.0         0x00000080
svnet0   UP    0.0.0.0         0.0.0.0         0x000000d1
So, we can see the same problem that we had for NetworkInterface - disabled interface not found.
Let's try to understand why.
Here is what we can see (in logcat) when we try to enable wifi on device with wifi disabled:
I/WifiHW  ( 3643): [WIFI] Load Driver
I/WifiHW  ( 3643): [WiFi.c] insmod() Start!! 
I/WifiHW  ( 3643): [WiFi.c] start init_module() Start!! 
I/WifiHW  ( 3643): [WIFI] DRIVER OK
I/WifiHW  ( 3643): wifi_start_supplicant: Enter
D/WifiHW  ( 3643): /data/wifi/bcm_supp.conf exits
E/WifiHW  ( 3643): wifi_start_supplicant: pi->serial=117440528, serial=0
I/WifiHW  ( 3643): wifi_start_supplicant: Exit. supp_status=running
...
end when wifi is enabled and connected and we are disabling it:
I/WifiHW  ( 3643): wifi_stop_supplicant: Enter
I/WifiHW  ( 3643): wifi_stop_supplicant: connecting supplicant is done
I/WifiHW  ( 3643): wifi_stop_supplicant: status of  supplicant(connected), count(49) 
I/wpa_supplicant( 5070): CTRL-EVENT-TERMINATING - signal 15 received
I/wpa_supplicant( 5070): CTRL-EVENT-TERMINATING - signal 0 received
I/WifiHW  ( 3643): wifi_stop_supplicant: exit normally
D/WifiStateTracker( 3643): Reset connections and stopping DHCP
I/WifiHW  ( 3643): wifi_close_supplicant_connection: enter
I/WifiHW  ( 3643): wifi_close_supplicant_connection: exit
...
I/WifiHW  ( 3643): wifi_unload_driver: enter
...
E/WifiHW  ( 3643): [WIFI] Unload Driver
I/WifiHW  ( 3643): wifi_unload_driver: exit
What we have here? Assuming that WifiHW tag is used to mark operations related to wifi stuff (quite logical assumption) we can see, that in wifi disabled state not just supplicant is 'stopped', but even wifi driver is unloaded (insmod is used to load it). Otherwise, supplicant received signal 15 (termination signal) and then wifi driver is unloaded. Please note once again: all this assumptions are based on logs of devices.
What does this tell us? This tells us, that Android is quite smart and economical (at least battery) system ... and that most like we not able to write application to monitor network interfaces (at least list all of them) of our device - when NIC is not used it's 'unloaded' from system. As far as you know, it's not possible to keep 2 network connections (wifi and mobile) raised in simultaneously (w.o. some funny tricks i'm going to show later in next topics) - system will disable mobile connection when wifi is connected. Obviously, this is correct behavior - save your battery and save your money (mobile internet sometimes very expensive). So that's why, apparently, we are not able to get all out network interfaces using sdk api.
Also we are not able to manage our network interfaces with this basic api. Fortunately Android sdk provides WifiManager to help us with wifi stuff. A bit more complicated to work with mobile networks (but possible). And finally vpn api is introduced in sdk 14. I'm going to talk about these things in the next few chapters.

No comments:

Post a Comment