blob: a49998cd5aa453f1a8058218568b0401b0b54cb6 [file] [log] [blame]
// 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));
}