8000 WIP: workmanager and bound services support by rnixx · Pull Request #2464 · kivy/python-for-android · GitHub
[go: up one dir, main page]

Skip to content

WIP: workmanager and bound services support #2464

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 35 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e45a154
Add worker template
rnixx Jun 10, 2021
cb244b5
worker basics build successfully
rnixx Jun 10, 2021
015ed03
define package
rnixx Jun 10, 2021
6a81bfb
worker extends ListenableWorker. Add basic threading for worker
rnixx Jun 10, 2021
70dc848
worker WIP
rnixx Jun 10, 2021
b6ceca9
worker experiments
rnixx Jun 10, 2021
681cfeb
sometimes exit needed, sometimes not
rnixx Jun 10, 2021
e452095
cleanup log messages
rnixx Jun 11, 2021
efc150c
Move PythonActivityUtil.unpackData to PythonUtil.unpackData
rnixx Jun 11, 2021
146c781
Merge branch 'rnixx_unpack_data' into workmanager
rnixx Jun 11, 2021
c0c50de
Move toastError and some fixes
rnixx Jun 11, 2021
6e2b736
Merge branch 'rnixx_unpack_data' into workmanager
rnixx Jun 11, 2021
5b68bdc
unpack data in worker
rnixx Jun 11, 2021
4687ed1
support --worker command line option in build.py
rnixx Jun 11, 2021
7f9c00d
declare activity final in toastError
rnixx Jun 11, 2021
e394f38
Merge branch 'rnixx_unpack_data' into workmanager
rnixx Jun 11, 2021
ecea202
Add PythonBoundService stub
rnixx Jun 11, 2021
09ab20d
Remove PythonActivityUtil
rnixx Jun 12, 2021
8f2d569
Merge branch 'rnixx_unpack_data' into workmanager
rnixx Jun 12, 2021
19c00dd
Merge branch 'develop' of https://github.com/kivy/python-for-android …
rnixx Jun 15, 2021
430a7e7
bound service WIP
rnixx Jun 15, 2021
da130e8
Binder code lives in bound service template now
rnixx Jun 15, 2021
6283064
add native part for bound service
rnixx Jun 15, 2021
a012719
log messages
rnixx Jun 15, 2021
0a97b5b
log messages
rnixx Jun 15, 2021
35ed8b1
tests with RemoteListenableWorker
rnixx Jun 15, 2021
ea36543
Python worker basically runs in a service. XXX: dedicated service for…
rnixx Jun 15, 2021
f6fc1db
logging for unbind and rebind
zworkb Jun 17, 2021
12a0f37
use return code of python script
zworkb Jun 18, 2021
6ec1ac2
doStartForeground()
Jul 3, 2021
2d20e16
store worker params in class, added static mWorker in order to be abl…
Jul 10, 2021
0195537
join thread
Sep 25, 2021
5b6f5aa
restored main as entrypoint
Sep 26, 2021
550a2ce
make it work with android 12
zworkb Nov 22, 2022
20221aa
PendingIntent.FLAG_IMMUTABLE needed for sdk level 31+
zworkb Jan 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions pythonforandroid/bootstraps/common/build/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,14 +462,22 @@ def make_package(args):
foreground = 'foreground' in options
sticky = 'sticky' in options

bound = 'bound' in options

service_names.append(name)
service_target_path =\
'src/main/java/{}/Service{}.java'.format(
args.package.replace(".", "/"),
name.capitalize()
)

if not bound:
service_template_path = 'Service.tmpl.java'
else:
service_template_path = 'BoundService.tmpl.java'

service_target_path = 'src/main/java/{}/Service{}.java'.format(
args.package.replace(".", "/"),
name.capitalize()
)

render(
'Service.tmpl.java',
service_template_path,
service_target_path,
name=name,
entrypoint=entrypoint,
Expand All @@ -480,6 +488,24 @@ def make_package(args):
base_service_class=base_service_class,
)

for spec in args.workers:
spec = spec.split(':')
name = spec[0]
entrypoint = spec[1]

worker_target_path = \
'src/main/java/{}/{}Worker.java'.format(
args.package.replace(".", "/"),
name.capitalize()
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: we could make a one-liner helper function/method that does that, so we have a single source of truth.

def get_target_path(package, name):
    return 'src/main/java/{}/Service{}.java'.format(package.replace(".", "/"), name.capitalize())

render(
'Worker.tmpl.java',
worker_target_path,
name=name,
entrypoint=entrypoint,
args=args
)

# Find the SDK directory and target API
with open('project.properties', 'r') as fileh:
target = fileh.read().strip()
Expand Down Expand Up @@ -695,6 +721,9 @@ def parse_args_and_make_package(args=None):
ap.add_argument('--service', dest='services', action='append', default=[],
help='Declare a new service entrypoint: '
'NAME:PATH_TO_PY[:foreground]')
ap.add_argument('--worker', dest='workers', action='append', default=[],
help='Declare a new worker entrypoint: '
'NAME:PATH_TO_PY')
ap.add_argument('--native-service', dest='native_services', action='append', default=[],
help='Declare a new native service: '
'package.name.service')
Expand Down
120 changes: 108 additions & 12 deletions pythonforandroid/bootstraps/common/build/jni/application/src/start.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ int file_exists(const char *filename) {
return 0;
}

/* int main(int argc, char **argv) { */
int main(int argc, char *argv[]) {

int main_(int argc, char *argv[], int call_exit) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to the main?
I've never played with that part, but won't this get linking issues that the main is not exposed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main only gets called from within the JNICALL functions, and my editor complained about the signature. so i renamed it, maybe start_python or so woud better fit.


char *env_argument = NULL;
char *env_entrypoint = NULL;
Expand Down Expand Up @@ -333,12 +333,14 @@ int main(int argc, char *argv[]) {

https://github.com/kivy/kivy/pull/6107#issue-246120816
*/
char terminatecmd[256];
snprintf(
terminatecmd, sizeof(terminatecmd),
"import sys; sys.exit(%d)\n", ret
);
PyRun_SimpleString(terminatecmd);
if (call_exit) {
char terminatecmd[256];
snprintf(
terminatecmd, sizeof(terminatecmd),
"import sys; sys.exit(%d)\n", ret
);
PyRun_SimpleString(terminatecmd);
}

/* This should never actually be reached, but we'll leave the clean-up
* here just to be safe.
Expand All @@ -356,7 +358,100 @@ int main(int argc, char *argv[]) {
return ret;
}

JNIEXPORT void JNICALL Java_org_kivy_android_PythonService_nativeStart(
int main(int argc, char **argv) {
return main_(argc, argv, 0);
}

JNIEXPORT int JNICALL Java_org_kivy_android_PythonService_nativeStart(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only thing that changes between Java_org_kivy_android_PythonService_nativeStart(), Java_org_kivy_android_PythonWorker_nativeStart() and Java_org_kivy_android_PythonBoundService_nativeStart() is the function name.
Maybe we should share the body via a commun function

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure

JNIEnv *env,
jobject thiz,
jstring j_android_private,
jstring j_android_argument,
jstring j_service_entrypoint,
jstring j_python_name,
jstring j_python_home,
jstring j_python_path,
jstring j_arg) {
jboolean iscopy;
const char *android_private =
(*env)->GetStringUTFChars(env, j_android_private, &iscopy);
const char *android_argument =
(*env)->GetStringUTFChars(env, j_android_argument, &iscopy);
const char *service_entrypoint =
(*env)->GetStringUTFChars(env, j_service_entrypoint, &iscopy);
const char *python_name =
(*env)->GetStringUTFChars(env, j_python_name, &iscopy);
const char *python_home =
(*env)->GetStringUTFChars(env, j_python_home, &iscopy);
const char *python_path =
(*env)->GetStringUTFChars(env, j_python_path, &iscopy);
const char *arg = (*env)->GetStringUTFChars(env, j_arg, &iscopy);

setenv("ANDROID_PRIVATE", android_private, 1);
setenv("ANDROID_ARGUMENT", android_argument, 1);
setenv("ANDROID_APP_PATH", android_argument, 1);
setenv("ANDROID_ENTRYPOINT", service_entrypoint, 1);
setenv("PYTHONOPTIMIZE", "2", 1);
setenv("PYTHON_NAME", python_name, 1);
setenv("PYTHONHOME", python_home, 1);
setenv("PYTHONPATH", python_path, 1);
setenv("PYTHON_SERVICE_ARGUMENT", arg, 1);
setenv("P4A_BOOTSTRAP", bootstrap_name, 1);

char *argv[] = {"."};
/* ANDROID_ARGUMENT points to service subdir,
* so main() will run main.py from this dir
*/
return main_(1, argv, 1);
}

#if defined(BOOTSTRAP_NAME_SERVICELIBRARY)

JNIEXPORT int JNICALL Java_org_kivy_android_PythonWorker_nativeStart(
JNIEnv *env,
jobject thiz,
jstring j_android_private,
jstring j_android_argument,
jstring j_service_entrypoint,
jstring j_python_name,
jstring j_python_home,
jstring j_python_path,
jstring j_arg) {
jboolean iscopy;
const char *android_private =
(*env)->GetStringUTFChars(env, j_android_private, &iscopy);
const char *android_argument =
(*env)->GetStringUTFChars(env, j_android_argument, &iscopy);
const char *service_entrypoint =
(*env)->GetStringUTFChars(env, j_service_entrypoint, &iscopy);
const char *python_name =
(*env)->GetStringUTFChars(env, j_python_name, &iscopy);
const char *python_home =
(*env)->GetStringUTFChars(env, j_python_home, &iscopy);
const char *python_path =
(*env)->GetStringUTFChars(env, j_python_path, &iscopy);
const char *arg = (*env)->GetStringUTFChars(env, j_arg, &iscopy);

setenv("ANDROID_PRIVATE", android_private, 1);
setenv("ANDROID_ARGUMENT", android_argument, 1);
setenv("ANDROID_APP_PATH", android_argument, 1);
setenv("ANDROID_ENTRYPOINT", service_entrypoint, 1);
setenv("PYTHONOPTIMIZE", "2", 1);
setenv("PYTHON_NAME", python_name, 1);
setenv("PYTHONHOME", python_home, 1);
setenv("PYTHONPATH", python_path, 1);
setenv("PYTHON_SERVICE_ARGUMENT", arg, 1);
setenv("P4A_BOOTSTRAP", bootstrap_name, 1);

char *argv[] = {"."};
/* ANDROID_ARGUMENT points to service subdir,
* so main() will run main.py from this dir
*/
// main_(1, argv, 1);
return main_(1, argv, 0);
}

JNIEXPORT int JNICALL Java_org_kivy_android_PythonBoundService_nativeStart(
JNIEnv *env,
jobject thiz,
jstring j_android_private,
Expand Down Expand Up @@ -396,8 +491,9 @@ JNIEXPORT void JNICALL Java_org_kivy_android_PythonService_nativeStart(
/* ANDROID_ARGUMENT points to service subdir,
* so main() will run main.py from this dir
*/
main(1, argv);
return main_(1, argv, 1);
}
#endif

#if defined(BOOTSTRAP_NAME_WEBVIEW) || defined(BOOTSTRAP_NAME_SERVICEONLY)
// Webview and service_only uses some more functions:
Expand All @@ -419,7 +515,7 @@ void Java_org_kivy_android_PythonActivity_nativeSetenv(
}


void Java_org_kivy_android_PythonActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj)
int Java_org_kivy_android_PythonActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj)
{
/* This nativeInit follows SDL2 */

Expand All @@ -435,7 +531,7 @@ void Java_org_kivy_android_PythonActivity_nativeInit(JNIEnv* env, jclass cls, jo
argv[1] = NULL;
/* status = SDL_main(1, argv); */

main(1, argv);
return main_(1, argv, 1);

/* Do not issue an exit or the whole application will terminate instead of just the SDL thread */
/* exit(status); */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

#define BOOTSTRAP_NAME_LIBRARY
#define BOOTSTRAP_NAME_SERVICELIBRARY
#define BOOTSTRAP_USES_NO_SDL_HEADERS

const char bootstrap_name[] = "service_library";
Expand Down
Loading
0