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