Search code examples
androidandroid-sourceopenvpn

How to reference libraries inside an APK, building an Android image


I need to build an Android 9 image which includes some prebuilt APKs (OpenVPNForAndroid, in this specific case).

The APK, downloaded from f-droid, includes some libraries that are loaded dynamically. I've added it to the image with the Android.mk file below; the app is installed and starts normally, but fails when I try to connect with this error:

Cannot run program "/system/app/OpenVPNForAndroid/lib/arm64/libovpnexec.so": error=2, No such file or directory
java.io.IOException: Cannot run program "/system/app/OpenVPNForAndroid/lib/arm64/libovpnexec.so": error=2, No such file or directory
        at java.lang.ProcessBuilder.start(ProcessBuilder.java:1050)
        at de.blinkt.openvpn.core.OpenVPNThread.startOpenVPNThreadArgs(OpenVPNThread.java:139)
        at de.blinkt.openvpn.core.OpenVPNThread.run(OpenVPNThread.java:68)
        at java.lang.Thread.run(Thread.java:764)
Caused by: java.io.IOException: error=2, No such file or directory
        at java.lang.VNIXProcess.forkAndExec(Native Method)
        at java.lang.VNIXProcess.<init>(VNIXProcess.java:133)
        at java.lang.ProcessImpl.start(ProcessImpl.java:132)
        at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
        ... 3 more
,Error reading from output of OpenVPN process
Attempt to invoke virtual method 'void java.lang.Process.destroy()' on a null object reference
java.lang.NullPointerException: Attempt to invoke virtual method 'void java.lang.Process.destroy()' on a null object reference
        at de.blinkt.openvpn.core.OpenVPNThread.stopProcess(OpenVPNThread.java:56)
        at de.blinkt.openvpn.core.OpenVPNThread.startOpenVPNThreadArgs(OpenVPNThread.java:194)
        at de.blinkt.openvpn.core.OpenVPNThread.run(OpenVPNThread.java:68)
        at java.lang.Thread.run(Thread.java:764)

Apparently, the libraries that are inside of the APK are ignored.

I'd like to avoid to extract the .so files to add them to the image (since I fear that on future updates I'll forget to also extract the libraries again) and I think it should be possible, but apparently something is still missing.

The used Android.mk file, generated using genandroidmk, is this:

LOCAL_PATH := $(call my-dir)

my_archs := arm x86 arm64
my_src_arch := $(call get-prebuilt-src-arch, $(my_archs))

include $(CLEAR_VARS)
LOCAL_MODULE := OpenVPNForAndroid
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_TAGS := optional
LOCAL_BUILT_MODULE_STEM := package.apk
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_SRC_FILES := de.blinkt.openvpn_175.apk

LOCAL_PREBUILT_JNI_LIBS := \
  @lib/arm64-v8a/libjbcrypto.so \
  @lib/arm64-v8a/libopenvpn.so \
  @lib/arm64-v8a/libopvpnutil.so \
  @lib/arm64-v8a/libosslspeedtest.so \
  @lib/arm64-v8a/libovpn3.so \
  @lib/arm64-v8a/libovpnexec.so

LOCAL_MODULE_TARGET_ARCH := $(my_src_arch)

include $(BUILD_PREBUILT)

and then, in my product definition I have:

PRODUCT_PACKAGES += OpenVPNForAndroid

Am I missing something or it's simply no longer possible to refer to libraries inside an APK, without extracting them?

Thanks in advance.


Solution

  • The embedded libs will not be extracted any more. See: Don't extract jni from prebuilt apks

    So you can extract it by LOCAL_POST_INSTALL_CMD. Try the following:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    LOCAL_MODULE := OpenVPNForAndroid
    LOCAL_MODULE_CLASS := APPS
    LOCAL_MODULE_TAGS := optional
    LOCAL_BUILT_MODULE_STEM := package.apk
    LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
    LOCAL_CERTIFICATE := PRESIGNED
    LOCAL_SRC_FILES := de.blinkt.openvpn_175.apk
    
    # use lib/armeabi-v7a and lib/arm respectively, for 32bit apps
    MY_PREBUILT_LIBS_SRC := lib/arm64-v8a
    MY_PREBUILT_LIBS_DST := lib/arm64
    
    ifeq ($(LOCAL_PRIVILEGED_MODULE),true)
    MY_TARGET_DST := $(TARGET_OUT_APPS_PRIVILEGED)
    else
    MY_TARGET_DST := $(TARGET_OUT_APPS)
    endif
    LOCAL_POST_INSTALL_CMD := unzip -o $(LOCAL_PATH)/$(LOCAL_SRC_FILES) $(MY_PREBUILT_LIBS_SRC)/* -d $(MY_TARGET_DST)/$(LOCAL_MODULE) ; \
        mv $(MY_TARGET_DST)/$(LOCAL_MODULE)/$(MY_PREBUILT_LIBS_SRC) $(MY_TARGET_DST)/$(LOCAL_MODULE)/$(MY_PREBUILT_LIBS_DST) ; \
        chmod 0755 $(MY_TARGET_DST)/$(LOCAL_MODULE)/$(MY_PREBUILT_LIBS_DST)/*
    
    include $(BUILD_PREBUILT)