0

I am trying to develop an android application by using some native libraries.However, the system shared libraries on android 4.0 and android 4.1.2 are different. To ensure the compatibility, I get the libskia.so file from platform 4.0, and import it into my project. I wish to load this shared library just like using a 3rd party shared library. Unfortunately, while running on android 4.1.2, my application seems still call the system skia library. I have no idea about this and the followings are my Android.mk file

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := sample
LOCAL_SRC_FILES := sample-jni.cpp

LOCAL_CFLAGS    := -I /home/WORKING_DIRECTORY/external/skia/include \
-I /home/WORKING_DIRECTORY/external/skia/include/core \
-I /home/WORKING_DIRECTORY/frameworks/base/core/jni/android/graphics  \
-I /home/WORKING_DIRECTORY/frameworks/base/include \
-I /home/WORKING_DIRECTORY/frameworks/base/native/include/android \
-I /home/WORKING_DIRECTORY/system/core/include \
-I /home/WORKING_DIRECTORY/external/skia/include/xml \
-I /home/WORKING_DIRECTORY/external/skia/include/images \
-I /home/WORKING_DIRECTORY/external/skia/include/views \

 LOCAL_SHARED_LIBRARIES :=skia jnigraphics
 include $(BUILD_SHARED_LIBRARY)
 include $(LOCAL_PATH)/prebuilt/Android.mk

and the prebuilt makefile

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := skia
LOCAL_SRC_FILES := libskia.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := jnigraphics
LOCAL_SRC_FILES := libjnigraphics.so
include $(PREBUILT_SHARED_LIBRARY)

Any ideas? Or, are there any other methods to ensure compatibility?

Vito Li
  • 23
  • 1
  • 6

2 Answers2

0

I hope you understand that it is not recommended to have any dependencies on the system libraries beyond the stable API. But the open nature of Android allows (both technically and in terms of licensing) to introduce such dependencies. Essentially it means sailing in the non-chartered waters, and being prepared to API changes not only in the next version of the platform, but also in a vendor-provided (i.e. non-AOSP) setups of the same platform level.

Theoretically, you can put a copy of your variation of a system lib into the libs/armeabi-v7a folder of your app, and load it with System.load(fullPath) instead of loadLibrary().

But in practice I believe that system/lib/libskia.so will be loaded in your process before you have a chance to execute your code, and you cannot load two version of the same lib in the same process. Also, an older version of libskia will most likely fail to load on the system because it depends on other system libraries.

The safest way to ensure forward (and vendor) compatibility is to use dynamic linking for the undocumented system features, and perform careful error checking on the way.

But in many cases, the system undocumented APIs are actually quite stable, and the nice people in the Android team of Google do not make breaking changes too often. Therefore, if you link against the 4.0 version of skia your code will most likely simply work on 4.1.2 and on...

Update: In your particular case, when an extra field fTextLocale was added to an old class, you should first of all bless the developers who did not insert this field in the middle of the class declaration. Because now you have a reasonable strategy: use the 4.1.2 headers (with the extra field), link against the 4.0 library (that does not introduce the accessor methods to the new field), and your code will hopefully just work.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • Thanks! I think I understand the risk of dependencies on unstable APIs, but the requirement force me to use these undocumented features. I can't fully understand the way of `dynamic linking` you mentioned. When I link against the 4.0 version of skia, my application always crashes on 4.1.2 due to the different implement of some functions. – Vito Li Feb 04 '13 at 02:26
  • If you experience crashes on 4.1.2, you can debug them. You can download the sources of skia lib of 4.1.2, or even of the whole platform. But to start with, I would try to pull **libskia.so** from a 4.1.2 device, and try to link against it. Will the application still crash the same way on 4.1.2 when linked with a 4.1.2 version of the lib? – Alex Cohn Feb 04 '13 at 07:25
  • It worked well when linked with a 4.1.2 version of skia. I have download the source code of both two platforms and I do find some changes in the function where my application always crashes. In this case, should I build a certain version of static skia lib from the android source tree? I believe this will be workable but also needs larger effort. – Vito Li Feb 05 '13 at 01:59
  • I would appreciate if you share more info about the function and the change. Without that, I cannot give you an educated advice. – Alex Cohn Feb 05 '13 at 04:58
  • A new member variable named `fTextLocale` is declared in SkPaint.h of platform 4.1.2 which is not exist in 4.0 and the constructor of SkPaint will use this variable. So when I linked against the 4.0 version of skia and run a simple code of `SkPaint paint;` on android 4.1.2, the application crashed because symbol `fTextLocale` can not be found in lib 4.0. – Vito Li Feb 05 '13 at 14:11
0

You can use a different version of libskia by using dlopen in your native code with parameter RTLD_DEEPBIND. This will overwrite the global symbol table.

Jeff
  • 1
  • Jeff, in theory this is true. But in practice, `dlopen()` is not the way. First of all, `/system/lib/libskia.so` is probably loaded into the process before the APK has the chance to load the custom `libsample.so`. Second, the older version of `libskia.so` will probably look for wrong versions of other system libraries, and fail to load. Third, it's not very practical to replace all calls to C++ API of `libskia` with `dlsym()`. – Alex Cohn Sep 01 '14 at 08:41