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