app_main.cpp revision d195e5ab401432ddac659791640a2927fc668699
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        if (proc->supportsProcesses()) {
86            LOGV("App process: starting thread pool.\n");
87            proc->startThreadPool();
88        }
89
90        AndroidRuntime* ar = AndroidRuntime::getRuntime();
91        ar->callMain(mClassName, mClass, mArgC, mArgV);
92
93        if (ProcessState::self()->supportsProcesses()) {
94            IPCThreadState::self()->stopProcess();
95        }
96    }
97
98    virtual void onZygoteInit()
99    {
100        sp<ProcessState> proc = ProcessState::self();
101        if (proc->supportsProcesses()) {
102            LOGV("App process: starting thread pool.\n");
103            proc->startThreadPool();
104        }
105    }
106
107    virtual void onExit(int code)
108    {
109        if (mClassName == NULL) {
110            // if zygote
111            if (ProcessState::self()->supportsProcesses()) {
112                IPCThreadState::self()->stopProcess();
113            }
114        }
115
116        AndroidRuntime::onExit(code);
117    }
118
119
120    const char* mParentDir;
121    const char* mClassName;
122    jclass mClass;
123    int mArgC;
124    const char* const* mArgV;
125};
126
127}
128
129using namespace android;
130
131/*
132 * sets argv0 to as much of newArgv0 as will fit
133 */
134static void setArgv0(const char *argv0, const char *newArgv0)
135{
136    strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
137}
138
139int main(int argc, const char* const argv[])
140{
141    // These are global variables in ProcessState.cpp
142    mArgC = argc;
143    mArgV = argv;
144
145    mArgLen = 0;
146    for (int i=0; i<argc; i++) {
147        mArgLen += strlen(argv[i]) + 1;
148    }
149    mArgLen--;
150
151    AppRuntime runtime;
152    const char *arg;
153    const char *argv0;
154
155    argv0 = argv[0];
156
157    // Process command line arguments
158    // ignore argv[0]
159    argc--;
160    argv++;
161
162    // Everything up to '--' or first non '-' arg goes to the vm
163
164    int i = runtime.addVmArguments(argc, argv);
165
166    // Next arg is parent directory
167    if (i < argc) {
168        runtime.mParentDir = argv[i++];
169    }
170
171    // Next arg is startup classname or "--zygote"
172    if (i < argc) {
173        arg = argv[i++];
174        if (0 == strcmp("--zygote", arg)) {
175            bool startSystemServer = (i < argc) ?
176                    strcmp(argv[i], "--start-system-server") == 0 : false;
177            setArgv0(argv0, "zygote");
178            set_process_name("zygote");
179            runtime.start("com.android.internal.os.ZygoteInit",
180                startSystemServer);
181        } else {
182            set_process_name(argv0);
183
184            runtime.mClassName = arg;
185
186            // Remainder of args get passed to startup class main()
187            runtime.mArgC = argc-i;
188            runtime.mArgV = argv+i;
189
190            LOGV("App process is starting with pid=%d, class=%s.\n",
191                 getpid(), runtime.getClassName());
192            runtime.start();
193        }
194    } else {
195        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
196        app_usage();
197        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
198        return 10;
199    }
200
201}
202