app_main.cpp revision 71f2cf116aab893e224056c38ab146bd1538dd3e
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
20namespace android {
21
22void app_usage()
23{
24    fprintf(stderr,
25        "Usage: app_process [java-options] cmd-dir start-class-name [options]\n");
26}
27
28class AppRuntime : public AndroidRuntime
29{
30public:
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        ALOGV("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        ALOGV("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
121using namespace android;
122
123/*
124 * sets argv0 to as much of newArgv0 as will fit
125 */
126static void setArgv0(const char *argv0, const char *newArgv0)
127{
128    strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
129}
130
131int 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