3131#define  ENTRYPOINT_MAXLEN  128
3232#define  LOG (n , x ) __android_log_write(ANDROID_LOG_INFO, (n), (x))
3333#define  LOGP (x ) LOG("python", (x))
34+ #define  P4A_MIN_VER  11
3435
3536static  PyObject  * androidembed_log (PyObject  * self , PyObject  * args ) {
3637  char  * logstr  =  NULL ;
@@ -154,11 +155,6 @@ int main(int argc, char *argv[]) {
154155  Py_NoSiteFlag = 1 ;
155156#endif 
156157
157- #if  PY_MAJOR_VERSION  <  3 
158-   Py_SetProgramName ("android_python" );
159- #else 
160-   Py_SetProgramName (L"android_python" );
161- #endif 
162158
163159#if  PY_MAJOR_VERSION  >= 3 
164160  /* our logging module for android 
@@ -174,40 +170,80 @@ int main(int argc, char *argv[]) {
174170  char  python_bundle_dir [256 ];
175171  snprintf (python_bundle_dir , 256 ,
176172           "%s/_python_bundle" , getenv ("ANDROID_UNPACK" ));
177-   if  (dir_exists (python_bundle_dir )) {
178-     LOGP ("_python_bundle dir exists" );
179-     snprintf (paths , 256 ,
180-             "%s/stdlib.zip:%s/modules" ,
181-             python_bundle_dir , python_bundle_dir );
182173
183-     LOGP ("calculated paths to be..." );
184-     LOGP (paths );
174+   #if  PY_MAJOR_VERSION  >= 3 
185175
186-     #if  PY_MAJOR_VERSION  >= 3 
187-         wchar_t  * wchar_paths  =  Py_DecodeLocale (paths , NULL );
188-         Py_SetPath (wchar_paths );
176+     #if  PY_MINOR_VERSION  >= P4A_MIN_VER 
177+       PyConfig  config ;
178+       PyConfig_InitPythonConfig (& config );
179+       config .program_name  =  L"android_python" ;
180+     #else 
181+       Py_SetProgramName (L"android_python" );
189182    #endif 
190183
191-         LOGP ("set wchar paths..." );
184+   #else 
185+     Py_SetProgramName ("android_python" );
186+   #endif 
187+ 
188+   if  (dir_exists (python_bundle_dir )) {
189+     LOGP ("_python_bundle dir exists" );
190+ 
191+       #if  PY_MAJOR_VERSION  >= 3 
192+           #if  PY_MINOR_VERSION  >= P4A_MIN_VER 
193+             
194+             wchar_t  wchar_zip_path [256 ];
195+             wchar_t  wchar_modules_path [256 ];
196+             swprintf (wchar_zip_path , 256 , L"%s/stdlib.zip" , python_bundle_dir );
197+             swprintf (wchar_modules_path , 256 , L"%s/modules" , python_bundle_dir );
198+ 
199+             config .module_search_paths_set  =  1 ;
200+             PyWideStringList_Append (& config .module_search_paths , wchar_zip_path );
201+             PyWideStringList_Append (& config .module_search_paths , wchar_modules_path );
202+         #else 
203+             char  paths [512 ];
204+             snprintf (paths , 512 , "%s/stdlib.zip:%s/modules" , python_bundle_dir , python_bundle_dir );
205+             wchar_t  * wchar_paths  =  Py_DecodeLocale (paths , NULL );
206+             Py_SetPath (wchar_paths );
207+         #endif 
208+       
209+       #endif 
210+ 
211+     LOGP ("set wchar paths..." );
192212  } else  {
193213      LOGP ("_python_bundle does not exist...this not looks good, all python" 
194-            " recipes should have this folder, should we expect a crash soon?" );
214+              " recipes should have this folder, should we expect a crash soon?" );
195215  }
196216
197-   Py_Initialize ();
217+ #if  PY_MAJOR_VERSION  >= 3  &&  PY_MINOR_VERSION  >= P4A_MIN_VER 
218+     PyStatus  status  =  Py_InitializeFromConfig (& config );
219+     if  (PyStatus_Exception (status )) {
220+         LOGP ("Python initialization failed:" );
221+         LOGP (status .err_msg );
222+     }
223+ #else 
224+     Py_Initialize ();
225+     LOGP ("Python initialized using legacy Py_Initialize()." );
226+ #endif 
227+ 
198228  LOGP ("Initialized python" );
199229
200-   /* ensure threads will work. 
201-    */ 
202-   LOGP ("AND: Init threads" );
203-   PyEval_InitThreads ();
230+   /* < 3.9 requires explicit GIL initialization 
231+   *  3.9+ PyEval_InitThreads() is deprecated and unnecessary 
232+   */ 
233+   #if  PY_VERSION_HEX  <  0x03090000 
234+     LOGP ("Initializing threads (required for Python < 3.9)" );
235+     PyEval_InitThreads ();
236+   #endif 
204237
205238#if  PY_MAJOR_VERSION  <  3 
206239  initandroidembed ();
207240#endif 
208241
209-   PyRun_SimpleString ("import androidembed\nandroidembed.log('testing python " 
210-                      "print redirection')" );
242+   PyRun_SimpleString (
243+       "import androidembed\n" 
244+       "androidembed.log('testing python print redirection')" 
245+ 
246+   );
211247
212248  /* inject our bootstrap code to redirect python stdin/stdout 
213249   * replace sys.path with our path 
@@ -325,20 +361,6 @@ int main(int argc, char *argv[]) {
325361
326362  LOGP ("Python for android ended." );
327363
328-   /* Shut down: since regular shutdown causes issues sometimes 
329-      (seems to be an incomplete shutdown breaking next launch) 
330-      we'll use sys.exit(ret) to shutdown, since that one works. 
331- 
332-      Reference discussion: 
333- 
334-      https://github.com/kivy/kivy/pull/6107#issue-246120816 
335-    */ 
336-   char  terminatecmd [256 ];
337-   snprintf (
338-     terminatecmd , sizeof (terminatecmd ),
339-     "import sys; sys.exit(%d)\n" , ret 
340-   );
341-   PyRun_SimpleString (terminatecmd );
342364
343365  /* This should never actually be reached, but we'll leave the clean-up 
344366   * here just to be safe. 
0 commit comments