Skip to content

Commit b50a430

Browse files
committed
bootstrap: if there is any jni available in bootstrap, compile it + fix loading of native activity with linked python2.7.so by creating a class and System.loadLibrary the python before the native library is loaded. See http://stackoverflow.com/questions/22686900/java-lang-illegalargumentexception-unable-to-load-native-library
1 parent dc45700 commit b50a430

File tree

5 files changed

+163
-14
lines changed

5 files changed

+163
-14
lines changed
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
bootstrap.entrypoint=android.app.NativeActivity
2-
bootstrap.hascode=false
1+
bootstrap.entrypoint=org.p4a.minimal.PythonActivity
32
bootstrap.lib_name=native-activity

bootstrap/minimal/jni/Android.mk

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@ include $(CLEAR_VARS)
1818

1919
LOCAL_MODULE := native-activity
2020
LOCAL_SRC_FILES := main.c
21-
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM
21+
LOCAL_LDLIBS := -lpython2.7 -ldl -llog -lz -landroid
2222
LOCAL_STATIC_LIBRARIES := android_native_app_glue
23+
LOCAL_CFLAGS := \
24+
-I$(LOCAL_PATH)/../../../build/python-install/include/python2.7
25+
LOCAL_LDFLAGS := \
26+
-L$(LOCAL_PATH)/../../../build/python-install/lib
2327

2428
include $(BUILD_SHARED_LIBRARY)
2529

bootstrap/minimal/jni/main.c

Lines changed: 134 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,142 @@
33
#include <android/log.h>
44
#include <android_native_app_glue.h>
55

6-
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
7-
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
6+
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "python", __VA_ARGS__))
7+
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "python", __VA_ARGS__))
8+
9+
#define PY_SSIZE_T_CLEAN
10+
#include "Python.h"
11+
#ifndef Py_PYTHON_H
12+
#error Python headers needed to compile C extensions, please install development version of Python.
13+
#endif
14+
15+
static PyObject *androidembed_log(PyObject *self, PyObject *args) {
16+
char *logstr = NULL;
17+
if (!PyArg_ParseTuple(args, "s", &logstr)) {
18+
return NULL;
19+
}
20+
__android_log_print(ANDROID_LOG_INFO, "python", "%s", logstr);
21+
Py_RETURN_NONE;
22+
}
23+
24+
static PyMethodDef AndroidEmbedMethods[] = {
25+
{"log", androidembed_log, METH_VARARGS,
26+
"Log on android platform"},
27+
{NULL, NULL, 0, NULL}
28+
};
29+
30+
PyMODINIT_FUNC initandroidembed(void) {
31+
(void) Py_InitModule("androidembed", AndroidEmbedMethods);
32+
}
33+
34+
int file_exists(const char * filename)
35+
{
36+
FILE *file;
37+
if (file = fopen(filename, "r")) {
38+
fclose(file);
39+
return 1;
40+
}
41+
return 0;
42+
}
843

944

1045
void android_main(struct android_app* state) {
1146
app_dummy();
12-
LOGI("android_main: starting minimal bootstrap.");
47+
LOGI("Starting minimal bootstrap.");
48+
49+
char *env_argument = NULL;
50+
FILE *fd;
51+
52+
LOGI("Initialize Python for Android");
53+
//env_argument = getenv("ANDROID_ARGUMENT");
54+
//setenv("ANDROID_APP_PATH", env_argument, 1);
55+
//setenv("PYTHONVERBOSE", "2", 1);
56+
Py_SetProgramName("python-android");
57+
Py_Initialize();
58+
//PySys_SetArgv(argc, argv);
59+
60+
/* ensure threads will work.
61+
*/
62+
PyEval_InitThreads();
63+
64+
/* our logging module for android
65+
*/
66+
initandroidembed();
67+
68+
/* inject our bootstrap code to redirect python stdin/stdout
69+
* replace sys.path with our path
70+
*/
71+
#if 0
72+
PyRun_SimpleString(
73+
"import sys, posix\n" \
74+
"private = posix.environ['ANDROID_PRIVATE']\n" \
75+
"argument = posix.environ['ANDROID_ARGUMENT']\n" \
76+
"sys.path[:] = [ \n" \
77+
" private + '/lib/python27.zip', \n" \
78+
" private + '/lib/python2.7/', \n" \
79+
" private + '/lib/python2.7/lib-dynload/', \n" \
80+
" private + '/lib/python2.7/site-packages/', \n" \
81+
" argument ]\n")
82+
#endif
83+
84+
PyRun_SimpleString(
85+
"import sys, androidembed\n" \
86+
"class LogFile(object):\n" \
87+
" def __init__(self):\n" \
88+
" self.buffer = ''\n" \
89+
" def write(self, s):\n" \
90+
" s = self.buffer + s\n" \
91+
" lines = s.split(\"\\n\")\n" \
92+
" for l in lines[:-1]:\n" \
93+
" androidembed.log(l)\n" \
94+
" self.buffer = lines[-1]\n" \
95+
" def flush(self):\n" \
96+
" return\n" \
97+
"sys.stdout = sys.stderr = LogFile()\n" \
98+
"import site; print site.getsitepackages()\n"\
99+
"print 'Android path', sys.path\n" \
100+
"print 'Android kivy bootstrap done. __name__ is', __name__");
101+
102+
/* run it !
103+
*/
104+
LOGI("Run user program, change dir and execute main.py");
105+
//chdir(env_argument);
106+
107+
/* search the initial main.py
108+
*/
109+
char *main_py = "main.pyo";
110+
if ( file_exists(main_py) == 0 ) {
111+
if ( file_exists("main.py") )
112+
main_py = "main.py";
113+
else
114+
main_py = NULL;
115+
}
116+
117+
if ( main_py == NULL ) {
118+
LOGW("No main.pyo / main.py found.");
119+
return;
120+
}
121+
122+
fd = fopen(main_py, "r");
123+
if ( fd == NULL ) {
124+
LOGW("Open the main.py(o) failed");
125+
return;
126+
}
127+
128+
/* run python !
129+
*/
130+
PyRun_SimpleFile(fd, main_py);
131+
132+
if (PyErr_Occurred() != NULL) {
133+
PyErr_Print(); /* This exits with the right code if SystemExit. */
134+
if (Py_FlushLine())
135+
PyErr_Clear();
136+
}
137+
138+
/* close everything
139+
*/
140+
Py_Finalize();
141+
fclose(fd);
142+
143+
LOGW("Python for android ended.");
13144
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.p4a.minimal;
2+
3+
import android.app.NativeActivity;
4+
5+
public class PythonActivity extends android.app.NativeActivity {
6+
static {
7+
System.loadLibrary("python2.7");
8+
}
9+
}

distribute.sh

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,17 @@ function run_pymodules_install() {
734734

735735
}
736736

737+
function run_bootstrap_build() {
738+
info "Compile bootstrap"
739+
740+
if [ -d "$SRC_PATH/jni" ]; then
741+
cd "$SRC_PATH/jni"
742+
push_arm
743+
try ndk-build V=1
744+
pop_arm
745+
fi
746+
}
747+
737748
function run_distribute() {
738749
info "Run distribute"
739750

@@ -743,15 +754,9 @@ function run_distribute() {
743754
try mkdir assets bin private res templates
744755

745756
debug "Copy default files"
746-
try cp -a $SRC_PATH/default.properties .
747-
try cp -a $SRC_PATH/local.properties .
757+
try cp -a $BOOTSTRAP_COMMON_PATH/* .
758+
try cp -a $SRC_PATH/* .
748759
try cat $SRC_PATH/bootstrap.properties >> "local.properties"
749-
try cp -a $BOOTSTRAP_COMMON_PATH/build.py .
750-
try cp -a $BOOTSTRAP_COMMON_PATH/buildlib .
751-
try cp -a $BOOTSTRAP_COMMON_PATH/src .
752-
try cp -a $BOOTSTRAP_COMMON_PATH/templates .
753-
try cp -a $BOOTSTRAP_COMMON_PATH/res .
754-
try cp -a $SRC_PATH/src .
755760
try cp -a $BUILD_PATH/blacklist.txt .
756761
try cp -a $BUILD_PATH/whitelist.txt .
757762

@@ -812,6 +817,7 @@ function run() {
812817
run_biglink
813818
run_postbuild
814819
run_pymodules_install
820+
run_bootstrap_build
815821
run_distribute
816822
info "All done !"
817823
}

0 commit comments

Comments
 (0)