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 <cutils/trace.h>
17#include <android_runtime/AndroidRuntime.h>
18#include <sys/personality.h>
19
20#include <stdlib.h>
21#include <stdio.h>
22#include <unistd.h>
23
24namespace android {
25
26void app_usage()
27{
28    fprintf(stderr,
29        "Usage: app_process [java-options] cmd-dir start-class-name [options]\n");
30}
31
32class AppRuntime : public AndroidRuntime
33{
34public:
35    AppRuntime()
36        : mParentDir(NULL)
37        , mClassName(NULL)
38        , mClass(NULL)
39        , mArgC(0)
40        , mArgV(NULL)
41    {
42    }
43
44#if 0
45    // this appears to be unused
46    const char* getParentDir() const
47    {
48        return mParentDir;
49    }
50#endif
51
52    const char* getClassName() const
53    {
54        return mClassName;
55    }
56
57    virtual void onVmCreated(JNIEnv* env)
58    {
59        if (mClassName == NULL) {
60            return; // Zygote. Nothing to do here.
61        }
62
63        /*
64         * This is a little awkward because the JNI FindClass call uses the
65         * class loader associated with the native method we're executing in.
66         * If called in onStarted (from RuntimeInit.finishInit because we're
67         * launching "am", for example), FindClass would see that we're calling
68         * from a boot class' native method, and so wouldn't look for the class
69         * we're trying to look up in CLASSPATH. Unfortunately it needs to,
70         * because the "am" classes are not boot classes.
71         *
72         * The easiest fix is to call FindClass here, early on before we start
73         * executing boot class Java code and thereby deny ourselves access to
74         * non-boot classes.
75         */
76        char* slashClassName = toSlashClassName(mClassName);
77        mClass = env->FindClass(slashClassName);
78        if (mClass == NULL) {
79            ALOGE("ERROR: could not find class '%s'\n", mClassName);
80        }
81        free(slashClassName);
82
83        mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
84    }
85
86    virtual void onStarted()
87    {
88        sp<ProcessState> proc = ProcessState::self();
89        ALOGV("App process: starting thread pool.\n");
90        proc->startThreadPool();
91
92        AndroidRuntime* ar = AndroidRuntime::getRuntime();
93        ar->callMain(mClassName, mClass, mArgC, mArgV);
94
95        IPCThreadState::self()->stopProcess();
96    }
97
98    virtual void onZygoteInit()
99    {
100        // Re-enable tracing now that we're no longer in Zygote.
101        atrace_set_tracing_enabled(true);
102
103        sp<ProcessState> proc = ProcessState::self();
104        ALOGV("App process: starting thread pool.\n");
105        proc->startThreadPool();
106    }
107
108    virtual void onExit(int code)
109    {
110        if (mClassName == NULL) {
111            // if zygote
112            IPCThreadState::self()->stopProcess();
113        }
114
115        AndroidRuntime::onExit(code);
116    }
117
118
119    const char* mParentDir;
120    const char* mClassName;
121    jclass mClass;
122    int mArgC;
123    const char* const* mArgV;
124};
125
126}
127
128using namespace android;
129
130/*
131 * sets argv0 to as much of newArgv0 as will fit
132 */
133static void setArgv0(const char *argv0, const char *newArgv0)
134{
135    strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
136}
137
138int main(int argc, char* const argv[])
139{
140#ifdef __arm__
141    /*
142     * b/7188322 - Temporarily revert to the compat memory layout
143     * to avoid breaking third party apps.
144     *
145     * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.
146     *
147     * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466
148     * changes the kernel mapping from bottom up to top-down.
149     * This breaks some programs which improperly embed
150     * an out of date copy of Android's linker.
151     */
152    char value[PROPERTY_VALUE_MAX];
153    property_get("ro.kernel.qemu", value, "");
154    bool is_qemu = (strcmp(value, "1") == 0);
155    if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) {
156        int current = personality(0xFFFFFFFF);
157        if ((current & ADDR_COMPAT_LAYOUT) == 0) {
158            personality(current | ADDR_COMPAT_LAYOUT);
159            setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);
160            execv("/system/bin/app_process", argv);
161            return -1;
162        }
163    }
164    unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");
165#endif
166
167    // These are global variables in ProcessState.cpp
168    mArgC = argc;
169    mArgV = argv;
170
171    mArgLen = 0;
172    for (int i=0; i<argc; i++) {
173        mArgLen += strlen(argv[i]) + 1;
174    }
175    mArgLen--;
176
177    AppRuntime runtime;
178    const char* argv0 = argv[0];
179
180    // Process command line arguments
181    // ignore argv[0]
182    argc--;
183    argv++;
184
185    // Everything up to '--' or first non '-' arg goes to the vm
186
187    int i = runtime.addVmArguments(argc, argv);
188
189    // Parse runtime arguments.  Stop at first unrecognized option.
190    bool zygote = false;
191    bool startSystemServer = false;
192    bool application = false;
193    const char* parentDir = NULL;
194    const char* niceName = NULL;
195    const char* className = NULL;
196    while (i < argc) {
197        const char* arg = argv[i++];
198        if (!parentDir) {
199            parentDir = arg;
200        } else if (strcmp(arg, "--zygote") == 0) {
201            zygote = true;
202            niceName = "zygote";
203        } else if (strcmp(arg, "--start-system-server") == 0) {
204            startSystemServer = true;
205        } else if (strcmp(arg, "--application") == 0) {
206            application = true;
207        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
208            niceName = arg + 12;
209        } else {
210            className = arg;
211            break;
212        }
213    }
214
215    if (niceName && *niceName) {
216        setArgv0(argv0, niceName);
217        set_process_name(niceName);
218    }
219
220    runtime.mParentDir = parentDir;
221
222    if (zygote) {
223        runtime.start("com.android.internal.os.ZygoteInit",
224                startSystemServer ? "start-system-server" : "");
225    } else if (className) {
226        // Remainder of args get passed to startup class main()
227        runtime.mClassName = className;
228        runtime.mArgC = argc - i;
229        runtime.mArgV = argv + i;
230        runtime.start("com.android.internal.os.RuntimeInit",
231                application ? "application" : "tool");
232    } else {
233        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
234        app_usage();
235        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
236        return 10;
237    }
238}
239