app_main.cpp revision a23fcd7be8e40078a913b1a99222cdd89229e67b
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 <cutils/trace.h>
16#include <android_runtime/AndroidRuntime.h>
17
18#include <stdlib.h>
19#include <stdio.h>
20#include <unistd.h>
21
22namespace android {
23
24void app_usage()
25{
26    fprintf(stderr,
27        "Usage: app_process [java-options] cmd-dir start-class-name [options]\n");
28}
29
30class AppRuntime : public AndroidRuntime
31{
32public:
33    AppRuntime(char* argBlockStart, const size_t argBlockLength)
34        : AndroidRuntime(argBlockStart, argBlockLength)
35        , mParentDir(NULL)
36        , mClassName(NULL)
37        , mClass(NULL)
38        , mArgC(0)
39        , mArgV(NULL)
40    {
41    }
42
43#if 0
44    // this appears to be unused
45    const char* getParentDir() const
46    {
47        return mParentDir;
48    }
49#endif
50
51    const char* getClassName() const
52    {
53        return mClassName;
54    }
55
56    virtual void onVmCreated(JNIEnv* env)
57    {
58        if (mClassName == NULL) {
59            return; // Zygote. Nothing to do here.
60        }
61
62        /*
63         * This is a little awkward because the JNI FindClass call uses the
64         * class loader associated with the native method we're executing in.
65         * If called in onStarted (from RuntimeInit.finishInit because we're
66         * launching "am", for example), FindClass would see that we're calling
67         * from a boot class' native method, and so wouldn't look for the class
68         * we're trying to look up in CLASSPATH. Unfortunately it needs to,
69         * because the "am" classes are not boot classes.
70         *
71         * The easiest fix is to call FindClass here, early on before we start
72         * executing boot class Java code and thereby deny ourselves access to
73         * non-boot classes.
74         */
75        char* slashClassName = toSlashClassName(mClassName);
76        mClass = env->FindClass(slashClassName);
77        if (mClass == NULL) {
78            ALOGE("ERROR: could not find class '%s'\n", mClassName);
79        }
80        free(slashClassName);
81
82        mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
83    }
84
85    virtual void onStarted()
86    {
87        sp<ProcessState> proc = ProcessState::self();
88        ALOGV("App process: starting thread pool.\n");
89        proc->startThreadPool();
90
91        AndroidRuntime* ar = AndroidRuntime::getRuntime();
92        ar->callMain(mClassName, mClass, mArgC, mArgV);
93
94        IPCThreadState::self()->stopProcess();
95    }
96
97    virtual void onZygoteInit()
98    {
99        // Re-enable tracing now that we're no longer in Zygote.
100        atrace_set_tracing_enabled(true);
101
102        sp<ProcessState> proc = ProcessState::self();
103        ALOGV("App process: starting thread pool.\n");
104        proc->startThreadPool();
105    }
106
107    virtual void onExit(int code)
108    {
109        if (mClassName == NULL) {
110            // if zygote
111            IPCThreadState::self()->stopProcess();
112        }
113
114        AndroidRuntime::onExit(code);
115    }
116
117
118    const char* mParentDir;
119    const char* mClassName;
120    jclass mClass;
121    int mArgC;
122    const char* const* mArgV;
123};
124
125}
126
127using namespace android;
128
129static size_t computeArgBlockSize(int argc, char* const argv[]) {
130    // TODO: This assumes that all arguments are allocated in
131    // contiguous memory. There isn't any documented guarantee
132    // that this is the case, but this is how the kernel does it
133    // (see fs/exec.c).
134    //
135    // Also note that this is a constant for "normal" android apps.
136    // Since they're forked from zygote, the size of their command line
137    // is the size of the zygote command line.
138    //
139    // We change the process name of the process by over-writing
140    // the start of the argument block (argv[0]) with the new name of
141    // the process, so we'd mysteriously start getting truncated process
142    // names if the zygote command line decreases in size.
143    uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
144    uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
145    end += strlen(argv[argc - 1]);
146
147    return (end - start);
148}
149
150int main(int argc, char* const argv[])
151{
152    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
153    // Process command line arguments
154    // ignore argv[0]
155    argc--;
156    argv++;
157
158    // Everything up to '--' or first non '-' arg goes to the vm
159
160    int i = runtime.addVmArguments(argc, argv);
161
162    // Parse runtime arguments.  Stop at first unrecognized option.
163    bool zygote = false;
164    bool startSystemServer = false;
165    bool application = false;
166    const char* parentDir = NULL;
167    const char* niceName = NULL;
168    const char* className = NULL;
169    while (i < argc) {
170        const char* arg = argv[i++];
171        if (!parentDir) {
172            parentDir = arg;
173        } else if (strcmp(arg, "--zygote") == 0) {
174            zygote = true;
175            niceName = "zygote";
176        } else if (strcmp(arg, "--start-system-server") == 0) {
177            startSystemServer = true;
178        } else if (strcmp(arg, "--application") == 0) {
179            application = true;
180        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
181            niceName = arg + 12;
182        } else {
183            className = arg;
184            break;
185        }
186    }
187
188    if (niceName && *niceName) {
189        runtime.setArgv0(niceName);
190        set_process_name(niceName);
191    }
192
193    runtime.mParentDir = parentDir;
194
195    if (zygote) {
196        runtime.start("com.android.internal.os.ZygoteInit",
197                startSystemServer ? "start-system-server" : "");
198    } else if (className) {
199        // Remainder of args get passed to startup class main()
200        runtime.mClassName = className;
201        runtime.mArgC = argc - i;
202        runtime.mArgV = argv + i;
203        runtime.start("com.android.internal.os.RuntimeInit",
204                application ? "application" : "tool");
205    } else {
206        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
207        app_usage();
208        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
209        return 10;
210    }
211}
212