Can't run Panda3d on Android

First of all, the names of the packages that must be installed are different now:

pkg install python ndk-sysroot clang bison freetype harfbuzz libpng eigen openal-soft opusfile libvorbis assimp libopus ecj dx patchelf aapt apksigner libcrypt openssl netcat

After a successful build using python makepanda/makepanda.py --everything --target android-21 --no-tiff --installer --threads=4, I could install the APK using the files app (xdg-open didn’t work).

After running ./run_pview.sh /sdcard/models/panda.egg from the panda/src/android folder, I get the following in logcat:

08-25 15:03:57.258   918  6831 I ActivityManager: START u0 {act=android.intent.action.VIEW dat=file:///storage/emulated/0/models/panda.egg flg=0x10008003 cmp=org.panda3d.sdk/org.panda3d.android.PandaActivity (has extras)} from uid 10104
08-25 15:03:57.295 28913 28913 D AndroidRuntime: Shutting down VM
08-25 15:03:57.318   918   957 I ActivityManager: Start proc 28925:org.panda3d.sdk/u0a105 for activity org.panda3d.sdk/org.panda3d.android.PandaActivity
08-25 15:03:57.332 28925 28925 I org.panda3d.sd: Late-enabling -Xcheck:jni
08-25 15:03:57.412   918  1728 I InputReader: Reconfiguring input devices.  changes=0x00000004
08-25 15:03:57.617 28925 28925 D AndroidRuntime: Shutting down VM
08-25 15:03:57.625 28925 28925 E AndroidRuntime: FATAL EXCEPTION: main
08-25 15:03:57.625 28925 28925 E AndroidRuntime: Process: org.panda3d.sdk, PID: 28925
08-25 15:03:57.625 28925 28925 E AndroidRuntime: java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at java.lang.System.loadLibrary(System.java:1669)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at org.panda3d.android.PandaActivity.<clinit>(PandaActivity.java:117)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at java.lang.Class.newInstance(Native Method)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:69)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at android.app.Instrumentation.newActivity(Instrumentation.java:1215)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2869)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3086)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1816)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:106)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:193)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:6718)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
08-25 15:03:57.625 28925 28925 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
08-25 15:03:57.636   918  6831 W ActivityManager:   Force finishing activity org.panda3d.sdk/org.panda3d.android.PandaActivity
08-25 15:03:57.648 28925 28925 I Process : Sending signal. PID: 28925 SIG: 9
08-25 15:03:57.676   918  2660 I ActivityManager: Process org.panda3d.sdk (pid 28925) has died: fore TPSL
08-25 15:03:57.678   918   958 W libprocessgroup: kill(-28925, 9) failed: No such process
08-25 15:03:57.678   720   720 I Zygote  : Process 28925 exited due to signal (9)
08-25 15:03:57.678   918   958 I libprocessgroup: Successfully killed process cgroup uid 10105 pid 28925 in 0ms
08-25 15:03:57.698   669   686 W SurfaceFlinger: Attempting to destroy on removed layer: AppWindowToken{dc8351e token=Token{be52559 ActivityRecord{27915a0 u0 org.panda3d.sdk/org.panda3d.android.PandaActivity t86}}}#0

After a quick find, I found that file at “/data/data/com.termux/files/usr/lib/libc++_shared.so” and copied it into built/lib. After re-running the build and reinstalling the app, I get AndroidRuntime: java.lang.UnsatisfiedLinkError: dlopen failed: library "libfreetype.so" not found

I could keep drilling in and looking up each one, but perhaps there is a better way? Is something wrong with the build system?

Okay, so the problem there was that it didn’t look at the linker paths correctly, only using the LD_LIBRARY_PATH environment variable. Finally I added a mildly dirty fix to the makepanda/makepackage.py file:

diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py
index 9994b8fe7..1f0ecf2e0 100755
--- a/makepanda/makepackage.py
+++ b/makepanda/makepackage.py
@@ -850,6 +850,16 @@ def MakeInstallerAndroid(version, **kwargs):
             dir = os.path.realpath(dir)
             if not dir.startswith("/system") and not dir.startswith("/vendor"):
                 libpath.append(dir)
+    for dir in subprocess.check_output("ld --verbose | grep SEARCH_DIR | sed 's#SEARCH_DIR(\"##g' | tr -s '\"); ' ':'", shell=True).decode("utf-8").split(':'):
+        dir = dir.strip()
+        if not dir:
+            continue
+        dir = os.path.expandvars(dir)
+        dir = os.path.expanduser(dir)
+        if os.path.isdir(dir):
+            dir = os.path.realpath(dir)
+            if not dir.startswith("/system") and not dir.startswith("/vendor"):
+                libpath.append(dir)
 
     def copy_library(source, base):
         # Copy file to destination, stripping version suffix.

Now I get the following issue:

08-25 18:42:23.665  2380  2380 E AndroidRuntime: java.lang.UnsatisfiedLinkError: dlopen failed: cannot find "libssl.so" from verneed[0] in DT_NEEDED list for "/data/app/org.panda3d.sdk-e0VkIIJU3JLNCbUBj9_YFw==/lib/arm64/libpandaexpress.so"
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at java.lang.System.loadLibrary(System.java:1669)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at org.panda3d.android.PandaActivity.<clinit>(PandaActivity.java:117)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at java.lang.Class.newInstance(Native Method)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:69)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at android.app.Instrumentation.newActivity(Instrumentation.java:1215)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2869)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3086)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1816)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:106)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:193)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:6718)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
08-25 18:42:23.665  2380  2380 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
08-25 18:42:23.671   918 21252 W ActivityManager:   Force finishing activity org.panda3d.sdk/org.panda3d.android.PandaActivity

What’s interesting here is that when I checked the directory that the app was installed to (/data/app/org.panda3d.sdk-e0VkIIJU3JLNCbUBj9_YFw==/lib/arm64), I found libssl.so there. So now I got no idea why its not finding it.

BINGO! Turns out I also had to change the SONAME of all the libraries to match their new names.

Here is the final patch:

diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py
index 9994b8fe7..7e653bcef 100755
--- a/makepanda/makepackage.py
+++ b/makepanda/makepackage.py
@@ -850,6 +850,19 @@ def MakeInstallerAndroid(version, **kwargs):
             dir = os.path.realpath(dir)
             if not dir.startswith("/system") and not dir.startswith("/vendor"):
                 libpath.append(dir)
+    handle = subprocess.Popen(['ld', '--verbose'], stdout=subprocess.PIPE)
+    globalLDDirs = []
+    for line in handle.communicate()[0].splitlines():
+        strLine = line.decode('utf-8')
+        if "SEARCH_DIR" in strLine:
+            globalLDDirs += re.findall('SEARCH_DIR\("([^"]+)"\); ?', strLine)
+    for dir in globalLDDirs:
+        dir = os.path.expandvars(dir)
+        dir = os.path.expanduser(dir)
+        if os.path.isdir(dir):
+            dir = os.path.realpath(dir)
+            if not dir.startswith("/system") and not dir.startswith("/vendor"):
+                libpath.append(dir)
 
     def copy_library(source, base):
         # Copy file to destination, stripping version suffix.
@@ -862,6 +875,7 @@ def MakeInstallerAndroid(version, **kwargs):
             return
 
         shutil.copy(source, target)
+        subprocess.call(['patchelf', '--set-soname', os.path.basename(target), target])
 
         # Walk through the library dependencies.
         handle = subprocess.Popen(['readelf', '--dynamic', target], stdout=subprocess.PIPE)

@rdb Is this good enough for a PR or should I attempt to clean up the ld parsing?

EDIT: Cleaned it up a bit so opening a PR.

1 Like

Hi, usually libssl may get old on device that’s why you may want to use a newer one and embark it in the app/lib folder. cpython has also some specific requirements about ssl support since 3.7+.

Are you interested in cross compilation of CPython and Panda3D ? Api 19 (kitkat 4.4) has some support and also basic support for non native application ( eg Panda3D on SurfaceView )

Why not use the very quiet space https://gitter.im/panda3d/panda3d for talking about android plumbing ?