Home | History | Annotate | Download | only in app_process
      1 /*
      2  * Main entry of app process.
      3  *
      4  * Starts the interpreted runtime, then starts up the application.
      5  *
      6  */
      7 
      8 #define LOG_TAG "appproc"
      9 
     10 #include <binder/IPCThreadState.h>
     11 #include <binder/ProcessState.h>
     12 #include <utils/Log.h>
     13 #include <cutils/process_name.h>
     14 #include <cutils/memory.h>
     15 #include <android_runtime/AndroidRuntime.h>
     16 
     17 #include <stdio.h>
     18 #include <unistd.h>
     19 
     20 namespace android {
     21 
     22 void app_usage()
     23 {
     24     fprintf(stderr,
     25         "Usage: app_process [java-options] cmd-dir start-class-name [options]\n");
     26 }
     27 
     28 class AppRuntime : public AndroidRuntime
     29 {
     30 public:
     31     AppRuntime()
     32         : mParentDir(NULL)
     33         , mClassName(NULL)
     34         , mClass(NULL)
     35         , mArgC(0)
     36         , mArgV(NULL)
     37     {
     38     }
     39 
     40 #if 0
     41     // this appears to be unused
     42     const char* getParentDir() const
     43     {
     44         return mParentDir;
     45     }
     46 #endif
     47 
     48     const char* getClassName() const
     49     {
     50         return mClassName;
     51     }
     52 
     53     virtual void onVmCreated(JNIEnv* env)
     54     {
     55         if (mClassName == NULL) {
     56             return; // Zygote. Nothing to do here.
     57         }
     58 
     59         /*
     60          * This is a little awkward because the JNI FindClass call uses the
     61          * class loader associated with the native method we're executing in.
     62          * If called in onStarted (from RuntimeInit.finishInit because we're
     63          * launching "am", for example), FindClass would see that we're calling
     64          * from a boot class' native method, and so wouldn't look for the class
     65          * we're trying to look up in CLASSPATH. Unfortunately it needs to,
     66          * because the "am" classes are not boot classes.
     67          *
     68          * The easiest fix is to call FindClass here, early on before we start
     69          * executing boot class Java code and thereby deny ourselves access to
     70          * non-boot classes.
     71          */
     72         char* slashClassName = toSlashClassName(mClassName);
     73         mClass = env->FindClass(slashClassName);
     74         if (mClass == NULL) {
     75             LOGE("ERROR: could not find class '%s'\n", mClassName);
     76         }
     77         free(slashClassName);
     78 
     79         mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
     80     }
     81 
     82     virtual void onStarted()
     83     {
     84         sp<ProcessState> proc = ProcessState::self();
     85         LOGV("App process: starting thread pool.\n");
     86         proc->startThreadPool();
     87 
     88         AndroidRuntime* ar = AndroidRuntime::getRuntime();
     89         ar->callMain(mClassName, mClass, mArgC, mArgV);
     90 
     91         IPCThreadState::self()->stopProcess();
     92     }
     93 
     94     virtual void onZygoteInit()
     95     {
     96         sp<ProcessState> proc = ProcessState::self();
     97         LOGV("App process: starting thread pool.\n");
     98         proc->startThreadPool();
     99     }
    100 
    101     virtual void onExit(int code)
    102     {
    103         if (mClassName == NULL) {
    104             // if zygote
    105             IPCThreadState::self()->stopProcess();
    106         }
    107 
    108         AndroidRuntime::onExit(code);
    109     }
    110 
    111 
    112     const char* mParentDir;
    113     const char* mClassName;
    114     jclass mClass;
    115     int mArgC;
    116     const char* const* mArgV;
    117 };
    118 
    119 }
    120 
    121 using namespace android;
    122 
    123 /*
    124  * sets argv0 to as much of newArgv0 as will fit
    125  */
    126 static void setArgv0(const char *argv0, const char *newArgv0)
    127 {
    128     strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
    129 }
    130 
    131 int main(int argc, const char* const argv[])
    132 {
    133     // These are global variables in ProcessState.cpp
    134     mArgC = argc;
    135     mArgV = argv;
    136 
    137     mArgLen = 0;
    138     for (int i=0; i<argc; i++) {
    139         mArgLen += strlen(argv[i]) + 1;
    140     }
    141     mArgLen--;
    142 
    143     AppRuntime runtime;
    144     const char* argv0 = argv[0];
    145 
    146     // Process command line arguments
    147     // ignore argv[0]
    148     argc--;
    149     argv++;
    150 
    151     // Everything up to '--' or first non '-' arg goes to the vm
    152 
    153     int i = runtime.addVmArguments(argc, argv);
    154 
    155     // Parse runtime arguments.  Stop at first unrecognized option.
    156     bool zygote = false;
    157     bool startSystemServer = false;
    158     bool application = false;
    159     const char* parentDir = NULL;
    160     const char* niceName = NULL;
    161     const char* className = NULL;
    162     while (i < argc) {
    163         const char* arg = argv[i++];
    164         if (!parentDir) {
    165             parentDir = arg;
    166         } else if (strcmp(arg, "--zygote") == 0) {
    167             zygote = true;
    168             niceName = "zygote";
    169         } else if (strcmp(arg, "--start-system-server") == 0) {
    170             startSystemServer = true;
    171         } else if (strcmp(arg, "--application") == 0) {
    172             application = true;
    173         } else if (strncmp(arg, "--nice-name=", 12) == 0) {
    174             niceName = arg + 12;
    175         } else {
    176             className = arg;
    177             break;
    178         }
    179     }
    180 
    181     if (niceName && *niceName) {
    182         setArgv0(argv0, niceName);
    183         set_process_name(niceName);
    184     }
    185 
    186     runtime.mParentDir = parentDir;
    187 
    188     if (zygote) {
    189         runtime.start("com.android.internal.os.ZygoteInit",
    190                 startSystemServer ? "start-system-server" : "");
    191     } else if (className) {
    192         // Remainder of args get passed to startup class main()
    193         runtime.mClassName = className;
    194         runtime.mArgC = argc - i;
    195         runtime.mArgV = argv + i;
    196         runtime.start("com.android.internal.os.RuntimeInit",
    197                 application ? "application" : "tool");
    198     } else {
    199         fprintf(stderr, "Error: no class name or --zygote supplied.\n");
    200         app_usage();
    201         LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    202         return 10;
    203     }
    204 }
    205