app_main.cpp revision fc17dc2548234461eb43ff83539ede4c9893a825
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 <cutils/properties.h>
11#include <binder/IPCThreadState.h>
12#include <binder/ProcessState.h>
13#include <utils/Log.h>
14#include <cutils/process_name.h>
15#include <cutils/memory.h>
16#include <android_runtime/AndroidRuntime.h>
17#include <sys/personality.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()
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        sp<ProcessState> proc = ProcessState::self();
100        ALOGV("App process: starting thread pool.\n");
101        proc->startThreadPool();
102    }
103
104    virtual void onExit(int code)
105    {
106        if (mClassName == NULL) {
107            // if zygote
108            IPCThreadState::self()->stopProcess();
109        }
110
111        AndroidRuntime::onExit(code);
112    }
113
114
115    const char* mParentDir;
116    const char* mClassName;
117    jclass mClass;
118    int mArgC;
119    const char* const* mArgV;
120};
121
122}
123
124using namespace android;
125
126/*
127 * sets argv0 to as much of newArgv0 as will fit
128 */
129static void setArgv0(const char *argv0, const char *newArgv0)
130{
131    strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
132}
133
134int main(int argc, char* const argv[])
135{
136#ifdef __arm__
137    /*
138     * b/7188322 - Temporarily revert to the compat memory layout
139     * to avoid breaking third party apps.
140     *
141     * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.
142     *
143     * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466
144     * changes the kernel mapping from bottom up to top-down.
145     * This breaks some programs which improperly embed
146     * an out of date copy of Android's linker.
147     */
148    char value[PROPERTY_VALUE_MAX];
149    property_get("ro.kernel.qemu", value, "");
150    bool is_qemu = (strcmp(value, "1") == 0);
151    if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) {
152        int current = personality(0xFFFFFFFF);
153        if ((current & ADDR_COMPAT_LAYOUT) == 0) {
154            personality(current | ADDR_COMPAT_LAYOUT);
155            setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);
156            execv("/system/bin/app_process", argv);
157            return -1;
158        }
159    }
160    unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");
161#endif
162
163    // These are global variables in ProcessState.cpp
164    mArgC = argc;
165    mArgV = argv;
166
167    mArgLen = 0;
168    for (int i=0; i<argc; i++) {
169        mArgLen += strlen(argv[i]) + 1;
170    }
171    mArgLen--;
172
173    AppRuntime runtime;
174    const char* argv0 = argv[0];
175
176    // Process command line arguments
177    // ignore argv[0]
178    argc--;
179    argv++;
180
181    // Everything up to '--' or first non '-' arg goes to the vm
182
183    int i = runtime.addVmArguments(argc, argv);
184
185    // Parse runtime arguments.  Stop at first unrecognized option.
186    bool zygote = false;
187    bool startSystemServer = false;
188    bool application = false;
189    const char* parentDir = NULL;
190    const char* niceName = NULL;
191    const char* className = NULL;
192    while (i < argc) {
193        const char* arg = argv[i++];
194        if (!parentDir) {
195            parentDir = arg;
196        } else if (strcmp(arg, "--zygote") == 0) {
197            zygote = true;
198            niceName = "zygote";
199        } else if (strcmp(arg, "--start-system-server") == 0) {
200            startSystemServer = true;
201        } else if (strcmp(arg, "--application") == 0) {
202            application = true;
203        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
204            niceName = arg + 12;
205        } else {
206            className = arg;
207            break;
208        }
209    }
210
211    if (niceName && *niceName) {
212        setArgv0(argv0, niceName);
213        set_process_name(niceName);
214    }
215
216    runtime.mParentDir = parentDir;
217
218    if (zygote) {
219        runtime.start("com.android.internal.os.ZygoteInit",
220                startSystemServer ? "start-system-server" : "");
221    } else if (className) {
222        // Remainder of args get passed to startup class main()
223        runtime.mClassName = className;
224        runtime.mArgC = argc - i;
225        runtime.mArgV = argv + i;
226        runtime.start("com.android.internal.os.RuntimeInit",
227                application ? "application" : "tool");
228    } else {
229        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
230        app_usage();
231        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
232        return 10;
233    }
234}
235