| // Copyright 2017 Google Inc. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "launcher_internal.h" |
| |
| #include <Python.h> |
| #include <android-base/file.h> |
| #include <osdefs.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string> |
| |
| int main(int argc, char *argv[]) { |
| int result = 0 /* Used to mark if current program runs with success/failure. */; |
| |
| // Clear PYTHONPATH and PYTHONHOME so Python doesn't attempt to check the local |
| // disk for Python modules to load. The value of PYTHONHOME will replace "prefix" |
| // and "exe_prefix" based on the description in getpath.c. |
| // Please don't use PYTHONPATH and PYTHONHOME within user program. |
| // TODO(nanzhang): figure out if unsetenv("PYTHONPATH") is better. |
| unsetenv(const_cast<char *>("PYTHONPATH")); |
| // TODO(nanzhang): figure out if Py_SetPythonHome() is better. |
| unsetenv(const_cast<char *>("PYTHONHOME")); |
| // PYTHONEXECUTABLE is only used on MacOs X, when the Python interpreter |
| // embedded in an application bundle. It is not sure that we have this use case |
| // for Android hermetic Python. So override this environment variable to empty |
| // for now to make our self-contained environment more strict. |
| // For user (.py) program, it can access hermetic .par file path through |
| // sys.argv[0]. |
| unsetenv(const_cast<char *>("PYTHONEXECUTABLE")); |
| |
| // Resolving absolute path based on argv[0] is not reliable since it may |
| // include something unusable, too bad. |
| // android::base::GetExecutablePath() also handles for Darwin/Windows. |
| std::string executable_path = android::base::GetExecutablePath(); |
| |
| argv[0] = strdup(executable_path.c_str()); |
| // argv[0] is used for setting internal path, and Python sys.argv[0]. It |
| // should not exceed MAXPATHLEN defined for CPython. |
| if (!argv[0] || strlen(argv[0]) > MAXPATHLEN) { |
| fprintf(stderr, "The executable path %s is NULL or of invalid length.\n", argv[0]); |
| return 1; |
| } |
| |
| // For debugging/logging purpose, set stdin/stdout/stderr unbuffered through |
| // environment variable. |
| // TODO(nanzhang): Set Py_VerboseFlag if more debugging requests needed. |
| const char *unbuffered_env = getenv("PYTHONUNBUFFERED"); |
| if (unbuffered_env && unbuffered_env[0]) { |
| #if defined(MS_WINDOWS) || defined(__CYGWIN__) |
| _setmode(fileno(stdin), O_BINARY); |
| _setmode(fileno(stdout), O_BINARY); |
| #endif |
| #ifdef HAVE_SETVBUF |
| setvbuf(stdin, (char *)NULL, _IONBF, BUFSIZ); |
| setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ); |
| setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ); |
| #else /* !HAVE_SETVBUF */ |
| setbuf(stdin, (char *)NULL); |
| setbuf(stdout, (char *)NULL); |
| setbuf(stderr, (char *)NULL); |
| #endif /* !HAVE_SETVBUF */ |
| } |
| //For debugging/logging purpose, Warning control. |
| //Python’s warning machinery by default prints warning messages to sys.stderr. |
| //The full form of argument is:action:message:category:module:line |
| char *warnings_env = getenv("PYTHONWARNINGS"); |
| if (warnings_env && warnings_env[0]) { |
| char *warnings_buf, *warning; |
| |
| // Note: "new" operation; we need free this chuck of data after use. |
| warnings_buf = new char[strlen(warnings_env) + 1]; |
| if (warnings_buf == NULL) |
| Py_FatalError( |
| "not enough memory to copy PYTHONWARNINGS"); |
| strcpy(warnings_buf, warnings_env); |
| for (warning = strtok(warnings_buf, ","); |
| warning != NULL; |
| warning = strtok(NULL, ",")) |
| PySys_AddWarnOption(warning); |
| delete[] warnings_buf; |
| } |
| |
| // Always enable Python "-s" option. We don't need user-site directories, |
| // everything's supposed to be hermetic. |
| Py_NoUserSiteDirectory = 1; |
| |
| Py_SetProgramName(argv[0]); |
| Py_Initialize(); |
| PySys_SetArgvEx(argc, argv, 0); |
| |
| // Set sys.executable to None. The real executable is available as |
| // sys.argv[0], and too many things assume sys.executable is a regular Python |
| // binary, which isn't available. By setting it to None we get clear errors |
| // when people try to use it. |
| if (PySys_SetObject(const_cast<char *>("executable"), Py_None) < 0) { |
| PyErr_Print(); |
| result = 1; |
| goto error; |
| } |
| |
| result = android::cpython2::python_launcher::RunEntryPointOrMainModule(argv[0]); |
| if (result < 0) { |
| PyErr_Print(); |
| goto error; |
| } |
| |
| error: |
| Py_Finalize(); |
| |
| free(argv[0]); |
| exit(abs(result)); |
| } |