Monday, May 18, 2015

Trouble with Versioned Shared Libraries and Android

In one of my projects I am currently working on, I need to build libwebsocket  for Android platform.  libwebsockets needs OpenSSL or an alternative.  Luckily, some nice person has built OpenSSL for Android.  It's looked that this was going to be a straight forward task.

Actually, it was not.

In Linux, share libraries have versions, and they usually haven file names such as "libssl.so.1.0.0", and "libwebsockets.so.5".   Since building tools in Linux will generate symbolic "libssl.so" and "libwebsockets.so" for them respectively, everything works out fine.

One the other hand, Android does not use versioned shared libs, and valid shared lib file names must end with ".so".  So, we have to change file names accordingly, and everything should be with Android, right?

Not really.

After I change "libssl.so.1.0.0" to "libssl.so" (actually, it was changed at the above mentioned site already), it still have property called SONAME, "libssl.so.1.0.0".  libwebsockets.so I built, re-named from "libwebsockets.so.5", will ask for "libssl.so.1.0.0", when it is loaded into Android.  Just change the file names is not enough.

Here comes the hack as the last resort.  We can edit ".so" files such that SONAME's will end with ".so", and they will only ask for shared libs ended with ".so".  Two powerful tools needed are "objdump" and "rpl".  ".so" files are for machine consumption, and therefore not meant to be edited manually. You should use "rpl" with extra care.  Here is the example of "libssl.so", before and after the delicate operations.

Before:
huiying@huiying-PORTEGE-R835:~$ objdump -p libssl.so | grep so
libssl.so:     file format elf32-little
  NEEDED               libcrypto.so.1.0.0
  NEEDED               libdl.so
  NEEDED               libc.so
  SONAME               libssl.so.1.0.0

After: 
huiying@huiying-PORTEGE-R835:~$ rpl -R -e .so.1.0.0 "_1_0_0.so" libssl.so 
Replacing ".so.1.0.0" with "_1_0_0.so" (case sensitive) (partial words matched)
.
A Total of 2 matches replaced in 1 file searched.
huiying@huiying-PORTEGE-R835:~$ objdump -p libssl.so | grep so
libssl.so:     file format elf32-little
  NEEDED               libcrypto_1_0_0.so
  NEEDED               libdl.so
  NEEDED               libc.so
  SONAME               libssl_1_0_0.so

And don't forget to change file name "libssl.so" to "libssl_1_0_0.so".

You may ask, why I change from "libcrypto.so.1.0.0" to "libssl_1_0_0.so".  This is because they are of the same length.  If the replacement string is not of the same length, the library will be corrupted.

There are several websites describing the problem of SONAME, but none mentioned NEEDED field in .so files.  This is hack, but it works.  I have a running Android app to prove it.  I hope my experience will be helpful for others who come across similar situations.