Skip to content

Rs232 101

16-Jan-12

RS232 focusses on the connection of DTE, data terminal equipment (computers, printers, etc.) with DCE, data communication equipment (modems).RS232 cables can use DB25 or DB9 connectors. DB25 connectors have provision for two RS232 connections, but the single connection DB9 is most commonly used.

RS323 DB9 pinout

1 DCD Data carrier detect
2 RD Receive data
3 TD Transmit data
4 DTR Data terminal ready
5 SG Signal ground
6 DSR Data set ready
7 RTS Request to send
8 CTS Clear to send
9 RI Ring indicator

DTE to DTE connections through a null modem cable (PC to PC)

The purpose of a null-modem cable is to permit two RS-232 DTE devices to communicate with each other without modems or other communication devices (i.e., DCEs ) between them.

A null modem cable is an RS232 serial cable where the transmit and receive lines are crosslinked. In some cables there are also handshake lines crosslinked. In many situations a straight through serial cable is used, together with a null modem adapter. The adapter contains the necessary crosslinks between the signals.

Null modem without handshaking

Connector 1 Connector 2> Function
2 3 Rx -> Tx>
3 2 >Tx> -> Rx
5 5 Signal ground

Null modem with loop back handshaking

Connector 1 Connector 2 Function
2 3 Rx -> Tx
3 2 Tx -> Rx
5 5 Signal ground
1 + 4 + 6 - DTR -> >CD + DSR
- 1 + 4 + 6 DTR -> CD + DSR
7 + 8 - RTS -> CTS
- 7 + 8 >RTS -> CTS

Null modem with partial handshaking

Connector 1 Connector 2 Function
1 7 + 8 RTS2 -> CTS2 + CD1
2 3 Rx -> Tx
3 2 Tx -> Rx
4 6 DTR -> DSR
5 5 Signal ground
6 4 >DSR -> DTR
7 + 8 1 RTS1 -> CTS1 + CD2

Null modem with full handshaking

Connector 1 Connector 2 Function
2 3 Rx -> Tx
3 2 Tx -> Rx
4 6 DTR -> DSR
5 5 Signal ground
6 4 DSR -> DTR
7 8 RTS -> CTS
8 7 CTS -> RTS

Software flow control (XOFF/XON)

When one end of a data link is unable to accept any more data (or approaching that point), it sends XOFF to the other end. The other end receives the XOFF code, and suspends transmission.

Once the first end is ready to accept data again, it sends XON, and the other end resumes transmission.

Requires less wiring and is slower, as sending XOFF requires at least one character time to transmit, it may be queued, has to be done in software and has the overhead of escaping the control codes so that they are not confused with data.

XOFF/XON representations in ASCII

Code Meaning ASCII Dec Hex Keyboard
XOFF Pause transmission DC3 19 0×13 CTRL+S
XON Resume transmission DC1 17 0×11 CTRL+Q

Hardware flow control

In common RS232 there are pairs of control lines:

  • RTS flow control, RTS/CTS
  • DTR flow control, DTR/DSR

Hardware flow control is typically handled by the DTE or “master end”, as it is first raising or asserting its line to command the other side.

In case of RTS control flow, DTE sets its RTS, which signals the opposite end (the slave end such as a DCE) to begin monitoring its data input line. When ready for data, the slave end will raise its complementary line,

CTS in this example, which signals the master to start sending data, and for the master to begin monitoring the slave’s data output line. If either end needs to stop the data, it lowers its respective “data readyness” line.

For PC-to-modem and similar links, the case of DTR flow control, DTR/DSR are raised for the entire modem session (say a dialup internet call), and RTS/CTS are raised for each block of data.

Testing serial ports with stty

Print configuration

user@computer:$
stty -F /dev/ttyS0 -a

Set to 38400, no flow control, one stop bit, odd parity, 8 bit, disable special characters

On target,

user@computer:$
stty -F /dev/ttyS1 speed 38400 raw -echo -echoe -echok -echoctl -echoke -cstopb -parenb -parodd cs8 -crtscts icanon

user@computer:$
cat /dev/ttyS1

On host,

user@computer:$
stty -F /dev/ttyS1 speed 38400 raw -echo -echoe -echok -echoctl -echoke -cstopb -parenb -parodd cs8 -crtscts icanon

user@computer:$
for x in 1 2 3 4 5; do date > /dev/ttyS1;sleep 1;done

To turn on the hardware flow control, do:

user@computer:$
stty -F /dev/ttyS1 crtscts

user@computer:$
stty -F /dev/ttyS1 crtscts

Android battery support

30-Dec-11

The Android Gingerbread battery service has a JNI interface which supports a power supply class battery driver with hardcoded attributes. However, different platforms drivers may provide different attributes, so to allow for this configurability you can add platform specific system properties like:
devices/<manuf>/<platform>/system.prop

ro.power_supply.ac.online = online
ro.power_supply.usb.online is not supported
ro.power_supply.bat.status = status
ro.power_supply.bat.health is not supported
ro.power_supply.bat.present = present
ro.power_supply.bat.capacity = capacity
ro.power_supply.bat.voltage_now = voltage_avg
ro.power_supply.bat.temperature is not supported
ro.power_supply.bat.technology = technology

And then you retrive and use each of the properties, for example.

property_get("ro.power_supply.ac.online", value, "");
snprintf(path, sizeof(path), "%s/%s/%s", POWER_SUPPLY_PATH, name,value);

For the battery status to be updated by the Battery Service, it needs to receive a uevent from the Linux kernel driver. Verify that your battery driver does something like:

if( bat_status_old != bat_status.status )
    power_supply_changed(&amp;chg_device-&gt;psy);
bat_status_old = bat_status.status

At least on the status and capacity update functions.

The battery data is dumped into /data/system/batterystats.bin, a binary file that can be dumped using dumpsys.

user@computer:$
$~ adb shell dumpsys battery
Current Battery Service state:
AC powered: false
AC capacity: 500000
USB powered: true
status: 5
health: 2
present: true
level: 100
scale: 100
voltage:4201
temperature: 271
technology: Li-pol

Your app would need android.permission.DUMP to execute dumpsys.

GPIO (General Purpose Input/Output) interfaces in Linux

29-Dec-11

What are GPIOs?

GPIOs are very common in embedded hardware, representing pins connected to ball grid array (BGA)
packages.They are commonly used to provide flexibility in System On Chip (SOC), and
it is common for pins to be multiplexed and shared for different functionality. As such,
GPIOs are specific to each platform and we can only speak in generic terms.

Usually they can be used as writable output and readable inputs which can also be used
as IRQs.

Generic GPIO API

Linux platforms that support GPIO conventions declare GENERIC_GPIO, and drivers use the
interface in linux/gpio.h. GPIOs are identified by platform specific integer
numbers, with negative numbers being invalid.

int gpio_is_valid(int number);

Check whether a given number is a valid GPIO.

int gpio_request(unsigned gpio, const char *label);

Request a GPIO returning 0 on success or a negative error value.

void gpio_free(unsigned gpio);

Frees a previously requested GPIO.

int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);

Set the direction of the GPIO returning 0 on success or a negative error value.

int gpio_get_value(unsigned gpio);
void gpio_set_value(unsigned gpio, int value);

The getter return 0 or 1 (high or low), and the setter sets 0 or 1 (high or low).

Most GPIO controllers are accessed withouth the need for sleep and can be safely
accessed through IRQ handlers. Some use message buses like I2C or SPI which may sleep,
and this should be accessed by the following accessors:

int gpio_get_value_cansleep(unsigned gpio);
void gpio_set_value_cansleep(unsigned gpio, int value);

Platform code will have defined the mapping between the GPIOs and IRQs number
namespaces, so we can use the following functions to swap between them.

int gpio_to_irq(unsigned gpio);
int irq_to_gpio(unsigned irq);

Not al GPIOs can be configured as IRQs and in that case they will return a negative
errno.

GPIOLIB

An optional framework to support diferrent GPIO controllers (packaged as a “struct
gpio_chip”) with the same API. With debugfs available, /sys/kernel/debug/gpio lists all
registered controllers and the state of used GPIOs. The platform will define
ARCH_REQUIRE_GPIOLIB to compile the framework in, ARCH_WANT_OPTIONAL_GPIOLIB to let the
user built it into the kernel optionally, or none if GPIOLIB is not supported.

SYSFS support

When using GPIOLIB, a sysfs interface can be enabled to control GPIO directon and value
from userspace. The control interface lives in /sys/class/gpio.

echo 19 &gt; /sys/class/gpio/export

Will create a gpio19 node and request the GPIO number 19.

echo 19 &gt; /sys/class/gpio/unexport

Will free the GPIO 19.

echo "in" &gt; /sys/class/gpio/gpio19/direction
echo "out" &gt; /sys/class/gpio/gpio19/direction

Will configure it as input or output.

cat /sys/class/gpio/gpio19/value

Will read from an input GPIO.

echo 0 &gt; /sys/class/gpio/gpio19/value
echo 1 &gt; /sys/class/gpio/gpio19/value

Will write to an output GPIO.

echo rising &gt; /sys/class/gpio/gpio19/edge
echo falling &gt; /sys/class/gpio/gpio19/edge
echo both &gt; /sys/class/gpio/gpio19/edge
echo none &gt; /sys/class/gpio/gpio19/edge

If the GPIO can be configured as IRQ,the above configure the signal edges.

Drivers can also make GPIOs available through sysfs using:

int gpio_export(unsigned gpio, bool direction_may_change);
void gpio_unexport();

And the following can be used to symlink to a different sysfs location to provide the
interface under a different device.

int gpio_export_link(struct device *dev, const char *name,unsigned gpio)

Android user space boot up process

28-Dec-11

The Linux kernel will launch the init process which is the parent of all othe processes in the system.

Init will execute the init.rc script launching the system service processes.

The first process to launch is Zygote, which will execute and initialize the Dalvik VM.

The first Java component to start is the system server. This in turn will launch all the rest of the Android services, which will run in the System Server context.

frameworks/base/services/java/com/android/server/SystemServer.java

The server loads a native android_servers library that provides interfaces to native funcitonality.

frameworks/base/services/jni/

Then init1(args), the native init method that starts up native services is called. This is implemented in system_init in frameworks/base/cmds/system_server/library/system_init.cpp

Once it finishes starting native services there is a callback to init2:

runtime-&gt;callStatic("com/android/server/SystemServer", "init2");

Which then creates the server thread. Each service started by the system server runs as a separate Dalvik thread in the SystemServer process. These can be analyzed using the DDMS tool.

After the system boot has completed there is a standard broadcast android.intent.action.BOOT_COMPLETED. This can be used to start a service or perform some action by an application if it includes a broadcast receiver that registers for this intent.

The Android property system

21-Dec-11

A property is a key/value pair, both of which are of string type. Many android applications and libraries directly or indirectly relies on this feature to determine their runtime behavior.

Properties are stored in a shared memory block which can only be written to by the property service process. This service, started by init, reads properties from persisten storage and writes them into memory.

To read properties a consumer process (via libcutil) loads the shared memory into its own virtual memory, using an enviromental variable called ANDROID_PROPERTY_WORKSPACE which keeps the fd for the shared memory area and its size.

user@computer:$ / # echo $ANDROID_PROPERTY_WORKSPACE
9,32768

To write properties a setter process will also load the shared memory into its virtual space, but will rely on a unix domain socket (/dev/socket/property_service) to tell the property service to change a property both in shared memory and in persistent storage.

The shared memory region is structured as follows:

count
serial
magic
version
reserved[4]
toc[1]
... starts at 1024 bytes offset.
prop_info[PA_COUNT_MAX]

Where PA_COUNT_MAX is defined in system\core\init\property_service.c, and it’s 247 by default.

After setting up the shared memory area,the init process will load properties from following files:

 /default.prop
 /system/build.prop
 /system/default.prop
 /data/local.prop

Then init starts the property service and waits polling on its socket.

To get or set properties:

Native code (linking against libcutils)


#include <cutils/properties.h>
property_get/property_set

Java code

System.getProperty/System.setProperty functions in the java.lang library. These are Java properties, stored on a hashtable.
android.os.SystemProperties can be used to access native properties through JNI. Anyone can read them, but only the system server UID can write to them. The class is defined in https://github.com/android/platform_frameworks_base/blob/master/core/java/android/os/SystemProperties.java

Currently, properties can’t be removed.

 

 

Mounting a dd’ed disk

14-Aug-11

When you duplicate a disk you do something like:

dd if=/dev/sda of=/tmp/mydisk.dd

When you receive an image file, you can check it with file:

mydisk.dd: x86 boot sector; partition 1: ID=0x83, starthead 0, startsector 15128,7722844 sectors, extended partition table (last)\011, code offset 0x0

And with fdisk:

fdisk -l -u mydisk.dd

You must set cylinders.
You can do this from the extra functions menu.

Disk mydisk.dd: 0 MB, 0 bytes
122 heads, 62 sectors/track, 0 cylinders, total 0 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0x674d869c

     Device Boot      Start         End      Blocks   Id  System
mydisk.ddp1           15128     7737971     3861422   83  Linux

To mount it, you need to specify the offset of the partition you want to mount, not in sectors but in bytes. So to mount sector 15128 the offset is 15128*512:

sudo mount -o loop,offset=7745536 -t auto /my/path/mydisk.dd /mnt

Looking at the kernel log from the bootloader

10-Aug-11

Assuming you have a bootloader that doesn't overwrite memory on boot (U-Boot is one that doesn't) you can warm reset your device and have a look at the kernel's log buffer from its shell.

The log is stored is:

user@computer:$ grep __log_buf System.map
c047ebf8 b __log_buf

To convert the virtual address to physical, you need to substract the kernel base. For ARM it's KERNEL_START:

#define KERNEL_START    KERNEL_RAM_VADDR

And KERNEL_RAM_VADDR:

#define KERNEL_RAM_VADDR        (PAGE_OFFSET + TEXT_OFFSET)

With PAGE_OFFSET defined in your configuration:

config PAGE_OFFSET
	hex
	default 0x40000000 if VMSPLIT_1G
	default 0x80000000 if VMSPLIT_2G
	default 0xC0000000

And TEXT_OFFSET:

# The byte offset of the kernel image in RAM from the start of RAM.
TEXT_OFFSET := $(textofs-y)

With textofs-y:

textofs-y	:= 0x00008000

So KERNEL_START = 0xC0000000 + 0×00008000 = 0xC0008000

And __log_buf = 0xc047ebf8 – 0xC0008000 = 0x00476BF8

So, after a warm reset you stop at the U-Boot prompt and you do:

md.l 0x00476BF8
00476bf8: 00000000 00000000 00000000 00000000    ................
00476c08: 00000000 00000000 00000000 00000000    ................
00476c18: 00000000 00000000 00000000 00000000    ................
00476c28: 00000000 00000000 00000000 00000000    ................
00476c38: 00000000 00000000 00000000 00000000    ................
00476c48: 00000000 00000000 00000001 000002ee    ................
00476c58: 00000000 00000002 c0476c60 c0476c60    ........`lG.`lG.
00476c68: c02a2424 c048355c c048355c ffffaaf2    $$*.\5H.\5H.....
00476c78: c0482dc0 c02a24b4 c0476bac 00000000    .-H..$*..kG.....
00476c88: 00000007 00000000 00000000 00000000    ................
00476c98: 00000000 00000000 00000000 00000000    ................
00476ca8: dc2da048 c0499eec 00000000 0002bf20    H.-...I..... ...
00476cb8: 00000001 c04782d8 c0476d0c 00000000    ......G..mG.....
00476cc8: 00000000 00000000 00000000 00000000    ................
00476cd8: c02b7914 c02b7928 c02b782c 00000000    .y+.(y+.,x+.....
00476ce8: 00000000 00000000 00000000 00000000    ................
00476cf8: 00000000 00000000 00000000 00000000    ................
00476d08: 00000000 c0476cbc c04782d8 00000001    .....lG...G.....
00476d18: 00000000 00000000 c02b7914 c02b7928    .........y+.(y+.
00476d28: c02b782c 00000000 00000000 00000000    ,x+.............

Which is garbage.

However, if you ignore the TEXT_OFFSET:

__log_buf = 0xc047ebf8 – 0xC0000000 = 0x0047ebf8

md.l 0x0047ebf8
0047ebf8: 6f695f75 3a6c7463 5d363633 5f555056    u_ioctl:366]VPU_
0047ec08: 5f434f49 474b4c43 5f455441 54544553    IOC_CLKGATE_SETT
0047ec18: 0a474e49 413e363c 765b2047 695f7570    ING.<6>AG [vpu_i
0047ec28: 6c74636f 3636333a 5550565d 434f495f    octl:366]VPU_IOC
0047ec38: 4b4c435f 45544147 5445535f 474e4954    _CLKGATE_SETTING
0047ec48: 3e363c0a 5b204741 5f757076 74636f69    .<6>AG [vpu_ioct
0047ec58: 36333a6c 50565d36 4f495f55 4c435f43    l:366]VPU_IOC_CL
0047ec68: 5441474b 45535f45 4e495454 363c0a47    KGATE_SETTING.<6
0047ec78: 2047413e 7570765b 636f695f 333a6c74    >AG [vpu_ioctl:3
0047ec88: 565d3636 495f5550 435f434f 41474b4c    66]VPU_IOC_CLKGA
0047ec98: 535f4554 49545445 3c0a474e 47413e36    TE_SETTING.<6>AG
0047eca8: 70765b20 6f695f75 3a6c7463 5d363633     [vpu_ioctl:366]
0047ecb8: 5f555056 5f434f49 474b4c43 5f455441    VPU_IOC_CLKGATE_
0047ecc8: 54544553 0a474e49 413e363c 765b2047    SETTING.<6>AG [v
0047ecd8: 695f7570 6c74636f 3636333a 5550565d    pu_ioctl:366]VPU
0047ece8: 434f495f 4b4c435f 45544147 5445535f    _IOC_CLKGATE_SET
0047ecf8: 474e4954 3e363c0a 5b204741 5f757076    TING.<6>AG [vpu_
0047ed08: 74636f69 36333a6c 50565d36 4f495f55    ioctl:366]VPU_IO
0047ed18: 4c435f43 5441474b 45535f45 4e495454    C_CLKGATE_SETTIN
0047ed28: 363c0a47 2047413e 7570765b 636f695f    G.<6>AG [vpu_ioc

Voila!

If anyone has an explanation as to why I need to omit the TEXT_OFFSET in the calculation it would be welcomed.

Using gdb to enable core dumps on a running process

09-Aug-11

From C we would call getrlimit

int getrlimit(int resource, struct rlimit *rlim);

Where resource:

#define RLIMIT_CORE 4

And rlimit:

struct rlimit {
    unsigned long   rlim_cur;
    unsigned long   rlim_max;
};

Calculating rlimit size from gdb:

user@computer:$ (gdb) print sizeof(struct rlimit)
$1 = 16

And mallocing the memory:

user@computer:$ (gdb) set $limit=(long long *)malloc(sizeof(struct rlimit))
user@computer:$ (gdb) print $limit
$2 = 0x805b428

Set both rlim_cur and rlim_max to RLIM_INFINITY.

user@computer:$ (gdb) set $limit[0]=0x7fffffffffffffff
(gdb) set $limit[1]=0x7fffffffffffffff

Call setrlimit. Note that 4 is RLIMIT_CORE.

user@computer:$ (gdb) call (int)setrlimit(4, $limit)
$1 = 0

Detach from the process and quit.

user@computer:$ (gdb) detach
(gdb) q

Now if you signal your process to core dump, it will

user@computer:$ killall -ABRT myprocess

If getrlimit is not callable but is linked in, you can try:

user@computer:$ (gdb) info function getrlimit
All functions matching regular expression "getrlimit":

Non-debugging symbols:
0x0079e930 __getrlimit
0x0079e930 __new_getrlimit
0x0079e930 getrlimit@@GLIBC_2.2
0x0079e9d0 __new_getrlimit64
0x0079e9d0 getrlimit64@@GLIBC_2.2
0x007a7380 __GI___old_getrlimit
0x007a7380 __old_getrlimit
0x007a7380 getrlimit@GLIBC_2.0
0x007e4250 __old_getrlimit64
0x007e4250 getrlimit64@GLIBC_2.1

Which would be callable by:

((int (*)(int, struct rlimit)) p)(resource, rlp)
user@computer:$ (gdb) print ((int (*)(int, struct rlimit)) 0x0079e930)(4, 0x805b428)
$6 = 0

Checking the malloced struct rlimit:

user@computer:$ (gdb) x/2xw 0x805b428
0x805b428: 0xffffffff 0xffffffff

Debugging Android core dumps

04-Aug-11

When a process crashes, a core dump (called Tombstone in Android) is printed out in the logcat and stored under /data/tombstones/tombstone_nn, where nn is just a counter.

To get some useful info out of it we need to dereference it with the source. The libraries on the target are stripped of symbols, so you'll need the unstripped ones from /out/product/name/symbols/system/libwhatever.so.

Then you can use the addr2line located in ${android-src}/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-addr2line to dereference it.

Getting hands on, the crash I am looking at looks like:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'unknown'
pid: 1384, tid: 1384  >>> /system/bin/mediaserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr e08f3007
 r0 69708128  r1 00000000  r2 00000002  r3 00000000
 r4 00000000  r5 69708128  r6 69709214  r7 0000adf8
 r8 00000000  r9 00000000  10 00000000  fp 00000000
 ip 697108f8  sp 7e8fca08  lr e08f3003  pc 4013eb04  cpsr 80000010
 d0  968f6dec00000000  d1  6f20656c69709214
 d2  6e6f635f726f6c62  d3  2e6e6f697372652f
 d4  0000000000000000  d5  0000000000000000
 d6  3f80000000000000  d7  00000000ced2e124
 d8  0000000000000000  d9  0000000000000000
 d10 0000000000000000  d11 0000000000000000
 d12 0000000000000000  d13 0000000000000000
 d14 0000000000000000  d15 0000000000000000
 d16 0000000000000000  d17 0000000000000000
 d18 0000000000000000  d19 0000000000000000
 d20 0000000000000000  d21 0000000000000000
 d22 0000000000000000  d23 0000000000000000
 d24 0000000000000000  d25 0000000000000000
 d26 0000000000000000  d27 0000000000000000
 d28 0000000000000000  d29 0000000000000000
 d30 0000000000000000  d31 0000000000000000
 scr 00000010

         #00  pc 0003eb04  /system/lib/libasound.so
         #01  pc 0003edc8  /system/lib/libasound.so
         #02  pc 0000a9bc  /system/lib/libaudio.so
         #03  pc 0000c2d8  /system/lib/libaudio.so
         #04  pc 000234f8  /system/lib/libaudioflinger.so
         #05  pc 00029a06  /system/lib/libaudioflinger.so
         #06  pc 000088f2  /system/bin/mediaserver
         #07  pc 000089e6  /system/bin/mediaserver
         #08  pc 00014b52  /system/lib/libc.so

code around pc:
4013eae4 e1a0e00f e59cf000 e8bd8010 e92d4010
4013eaf4 e590e010 e1a03001 e3a02002 e3a01000
4013eb04 e59ec004 e1a0e00f e59cf000 e8bd8010
4013eb14 e590c010 e1a03002 e92d4010 e59c2008
4013eb24 e3120008 03e00015 08bd8010 e1a02001

code around lr:
e08f2fe0 ffffffff ffffffff ffffffff ffffffff
e08f2ff0 ffffffff ffffffff ffffffff ffffffff
e08f3000 ffffffff ffffffff ffffffff ffffffff
e08f3010 ffffffff ffffffff ffffffff ffffffff
e08f3020 ffffffff ffffffff ffffffff ffffffff

stack:
    7e8fc9c8  0000aed0
    7e8fc9cc  697107b8
    7e8fc9d0  0000afa0
    7e8fc9d4  6970c17f  /system/lib/libaudio.so
    7e8fc9d8  00000000
    7e8fc9dc  0000aa98
    7e8fc9e0  0000aaf8
    7e8fc9e4  0000aac8
    7e8fc9e8  68223204
    7e8fc9ec  0000b854
    7e8fc9f0  0000aaf8
    7e8fc9f4  00000000
    7e8fc9f8  0000001b
    7e8fc9fc  0000aeb8
    7e8fca00  df002777
    7e8fca04  e3a070ad
#00 7e8fca08  00000000
    7e8fca0c  4013edcc  /system/lib/libasound.so
#01 7e8fca10  0000adc8
    7e8fca14  3f800000
    7e8fca18  00000000
    7e8fca1c  6970a9c0  /system/lib/libaudio.so
#02 7e8fca20  0000adc8
    7e8fca24  6970c2db  /system/lib/libaudio.so
#03 7e8fca28  0000adc8
    7e8fca2c  68d234fb  /system/lib/libaudioflinger.so
#04 7e8fca30  0000adc8
    7e8fca34  00000000
    7e8fca38  00000000
    7e8fca3c  3f800000
    7e8fca40  00000000
    7e8fca44  68d29a0b  /system/lib/libaudioflinger.so
#05 7e8fca48  00000000
    7e8fca4c  00000000
    7e8fca50  00000000
    7e8fca54  00000000
    7e8fca58  00000000
    7e8fca5c  00000000
    7e8fca60  00000000
    7e8fca64  00000000
    7e8fca68  7e8fcab4
    7e8fca6c  00000000
    7e8fca70  00000000
    7e8fca74  00000000
    7e8fca78  00000000
    7e8fca7c  0000adc8
    7e8fca80  6821764d  /system/lib/libbinder.so
    7e8fca84  0000ad50
    7e8fca88  7e8fcaec
    7e8fca8c  000088f5  /system/bin/mediaserver
#06 7e8fca90  00000019
    7e8fca94  7e8fc660
    7e8fca98  0000ad98
    7e8fca9c  0000ad50
    7e8fcaa0  7e8fcab4
    7e8fcaa4  7e8fcae4
    7e8fcaa8  00000001
    7e8fcaac  000089eb  /system/bin/mediaserver
#07 7e8fcab0  00000001
    7e8fcab4  7e8fcae4
    7e8fcab8  0000ad50
    7e8fcabc  0000b848
    7e8fcac0  00008894  /system/bin/mediaserver
    7e8fcac4  6fd14b55  /system/lib/libc.so
#08 7e8fcac8  00000000
    7e8fcacc  00000000
    7e8fcad0  00000000
    7e8fcad4  00000000
    7e8fcad8  00000000
    7e8fcadc  ffffffe4
    7e8fcae0  00000001
    7e8fcae4  7e8fcbf0
    7e8fcae8  00000000
    7e8fcaec  7e8fcc08
    7e8fcaf0  7e8fcc45
    7e8fcaf4  7e8fcc6d
    7e8fcaf8  7e8fcc80
    7e8fcafc  7e8fcc95
    7e8fcb00  7e8fccb0
    7e8fcb04  7e8fccc3
    7e8fcb08  7e8fcce0
    7e8fcb0c  7e8fcd00

Which can be dereferenced as follows:

#00  pc 0003eb04  /system/lib/libasound.so

${android-src}/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-addr2line -f -e out/target/product/imx51_ccwmx51js/symbols/system/lib/libasound.so 0003eb04

snd_mixer_selem_has_playback_channel
/home/alex/Projects/android/external/alsa-lib/src/mixer/simple.c:270

I'll omit the addr2line call from now on and just show the results.

#01  pc 0003edc8  /system/lib/libasound.so

snd_mixer_selem_set_playback_volume_all
/home/alex/Projects/android/external/alsa-lib/src/mixer/simple.c:478

#02  pc 0000a9bc  /system/lib/libaudio.so

_ZN7android9ALSAMixer15snd_mixer_selem_set_playback_volume_all
/home/alex/Projects/android/hardware/alsa_sound/ALSAMixer.cpp:237

#03  pc 0000c2d8  /system/lib/libaudio.so

_ZN7android18A2dpAudioInterface15setMasterVolumeEf
/home/alex/Projects/android/frameworks/base/services/audioflinger/A2dpAudioInterface.cpp
:210

#04  pc 000234f8  /system/lib/libaudioflinger.so

_ZN7android12AudioFlinger15setMasterVolumeEf
/home/alex/Projects/android/frameworks/base/services/audioflinger/AudioFlinger.cpp:445

#05  pc 00029a06  /system/lib/libaudioflinger.so

AudioFlinger
/home/alex/Projects/android/frameworks/base/services/audioflinger/AudioFlinger.cpp:144

#06  pc 000088f2  /system/bin/mediaserver

_ZN7android13BinderServiceINS_12AudioFlingerEE7publishEv
/home/alex/Projects/android/frameworks/base/include/binder/BinderService.h:39

#07  pc 000089e6  /system/bin/mediaserver

_ZN7android13BinderServiceINS_12AudioFlingerEE11instantiateEv
/home/alex/Projects/android/frameworks/base/include/binder/BinderService.h:50

#08  pc 00014b52  /system/lib/libc.so

__libc_init
/home/alex/Projects/android/bionic/libc/bionic/libc_init_dynamic.c:114

The netlink socket interface

26-May-11

Simply put Netlink is a communication channel between kernel and user space processes. Many applications that use the interface use the libnetlink library to abstract its API. I haven't found the library elsewhere, so recently I had to extract it from iproute. Here it is along with an usage example.

libnetlink.h (Right click and save as)

libnetlink.c (Right click and save as)

#include <stdio.h>
#include <stdlib.h>
#include <sys socket.h="">
#include <libnetlink.h>
 
#define RTNLGRP_MSGS \
(RTNLGRP_IPV4_IFADDR|RTNLGRP_IPV4_ROUTE|RTNLGRP_IPV6_IFADDR|RTNLGRP_IPV6_ROUTE)
 
int accept_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
	switch(n-&gt;nlmsg_type)
	{
		case RTM_NEWLINK:
			printf(&quot;Link state changed\n&quot;);
			break;
		case RTM_DELLINK:
			printf(&quot;Interface Down\n&quot;);
			break;
		case RTM_GETLINK:
		case RTM_SETLINK:
		case RTM_NEWADDR:
		case RTM_DELADDR:
		case RTM_GETADDR:
		case RTM_NEWROUTE:
		case RTM_DELROUTE:
		case RTM_GETROUTE:
		case RTM_NEWRULE:
		case RTM_DELRULE:
		case RTM_GETRULE:
		default:
			printf(&quot;other message: %d %p\n&quot;, n-&gt;nlmsg_type, arg);
			break;
	}
}
 
 
int main()
{
	int res;
	struct rtnl_handle rth;
	unsigned int groups = RTNLGRP_MSGS;
 
	if (rtnl_open(&amp;rth,groups) &lt; 0)
	{
		printf(&quot;rtnl_open() failed in %s %s\n&quot;,__FUNCTION__,__FILE__);
		return -1;
	}
	if (rtnl_listen(&amp;rth, accept_msg, &quot;cookie&quot;)&lt;0)
	{
		printf(&quot;failed in rtnl_listen()\n&quot;);
		return -1;
	}
	printf(&quot;main done.\n&quot;);
 
}
</libnetlink.h></sys></stdlib.h></stdio.h>

 

Just place all the files in the same folder and do:

user@computer:$ gcc libnetlink.c netmon.c -I. -o netmon

References:

netlink man page

Kernel Korner – Why and How to Use Netlink Socket