Home | History | Annotate | Download | only in Launcher
      1 // Copyright 2017 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "launcher_internal.h"
     16 
     17 #include <Python.h>
     18 #include <android-base/file.h>
     19 #include <osdefs.h>
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <string>
     23 
     24 int main(int argc, char *argv[]) {
     25   int result = 0 /* Used to mark if current program runs with success/failure. */;
     26 
     27   // Clear PYTHONPATH and PYTHONHOME so Python doesn't attempt to check the local
     28   // disk for Python modules to load. The value of PYTHONHOME will replace "prefix"
     29   // and "exe_prefix" based on the description in getpath.c.
     30   // Please don't use PYTHONPATH and PYTHONHOME within user program.
     31   // TODO(nanzhang): figure out if unsetenv("PYTHONPATH") is better.
     32   unsetenv(const_cast<char *>("PYTHONPATH"));
     33   // TODO(nanzhang): figure out if Py_SetPythonHome() is better.
     34   unsetenv(const_cast<char *>("PYTHONHOME"));
     35   // PYTHONEXECUTABLE is only used on MacOs X, when the Python interpreter
     36   // embedded in an application bundle. It is not sure that we have this use case
     37   // for Android hermetic Python. So override this environment variable to empty
     38   // for now to make our self-contained environment more strict.
     39   // For user (.py) program, it can access hermetic .par file path through
     40   // sys.argv[0].
     41   unsetenv(const_cast<char *>("PYTHONEXECUTABLE"));
     42 
     43   // Resolving absolute path based on argv[0] is not reliable since it may
     44   // include something unusable, too bad.
     45   // android::base::GetExecutablePath() also handles for Darwin/Windows.
     46   std::string executable_path = android::base::GetExecutablePath();
     47 
     48   argv[0] = strdup(executable_path.c_str());
     49   // argv[0] is used for setting internal path, and Python sys.argv[0]. It
     50   // should not exceed MAXPATHLEN defined for CPython.
     51   if (!argv[0] || strlen(argv[0]) > MAXPATHLEN) {
     52     fprintf(stderr, "The executable path %s is NULL or of invalid length.\n", argv[0]);
     53     return 1;
     54   }
     55 
     56   // For debugging/logging purpose, set stdin/stdout/stderr unbuffered through
     57   // environment variable.
     58   // TODO(nanzhang): Set Py_VerboseFlag if more debugging requests needed.
     59   const char *unbuffered_env = getenv("PYTHONUNBUFFERED");
     60   if (unbuffered_env && unbuffered_env[0]) {
     61     #if defined(MS_WINDOWS) || defined(__CYGWIN__)
     62       _setmode(fileno(stdin), O_BINARY);
     63       _setmode(fileno(stdout), O_BINARY);
     64     #endif
     65     #ifdef HAVE_SETVBUF
     66       setvbuf(stdin,  (char *)NULL, _IONBF, BUFSIZ);
     67       setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
     68       setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ);
     69     #else /* !HAVE_SETVBUF */
     70       setbuf(stdin,  (char *)NULL);
     71       setbuf(stdout, (char *)NULL);
     72       setbuf(stderr, (char *)NULL);
     73     #endif /* !HAVE_SETVBUF */
     74   }
     75   //For debugging/logging purpose, Warning control.
     76   //Pythons warning machinery by default prints warning messages to sys.stderr.
     77   //The full form of argument is:action:message:category:module:line
     78   char *warnings_env = getenv("PYTHONWARNINGS");
     79   if (warnings_env && warnings_env[0]) {
     80       char *warnings_buf, *warning;
     81 
     82       // Note: "new" operation; we need free this chuck of data after use.
     83       warnings_buf = new char[strlen(warnings_env) + 1];
     84       if (warnings_buf == NULL)
     85           Py_FatalError(
     86              "not enough memory to copy PYTHONWARNINGS");
     87       strcpy(warnings_buf, warnings_env);
     88       for (warning = strtok(warnings_buf, ",");
     89            warning != NULL;
     90            warning = strtok(NULL, ","))
     91           PySys_AddWarnOption(warning);
     92       delete[] warnings_buf;
     93   }
     94 
     95   // Always enable Python "-s" option. We don't need user-site directories,
     96   // everything's supposed to be hermetic.
     97   Py_NoUserSiteDirectory = 1;
     98 
     99   Py_SetProgramName(argv[0]);
    100   Py_Initialize();
    101   PySys_SetArgvEx(argc, argv, 0);
    102 
    103   // Set sys.executable to None. The real executable is available as
    104   // sys.argv[0], and too many things assume sys.executable is a regular Python
    105   // binary, which isn't available. By setting it to None we get clear errors
    106   // when people try to use it.
    107   if (PySys_SetObject(const_cast<char *>("executable"), Py_None) < 0) {
    108     PyErr_Print();
    109     result = 1;
    110     goto error;
    111   }
    112 
    113   result = android::cpython2::python_launcher::RunEntryPointOrMainModule(argv[0]);
    114   if (result < 0) {
    115     PyErr_Print();
    116     goto error;
    117   }
    118 
    119 error:
    120   Py_Finalize();
    121 
    122   free(argv[0]);
    123   exit(abs(result));
    124 }
    125