19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Main entry of app process.
3d195e5ab401432ddac659791640a2927fc668699Elliott Hughes *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Starts the interpreted runtime, then starts up the application.
5d195e5ab401432ddac659791640a2927fc668699Elliott Hughes *
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "appproc"
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10fc737fb76cc889d0c19bd8bf74d2b5f1fc4fbe6eMark Salyzyn#include <stdio.h>
11fc737fb76cc889d0c19bd8bf74d2b5f1fc4fbe6eMark Salyzyn#include <stdlib.h>
12fc737fb76cc889d0c19bd8bf74d2b5f1fc4fbe6eMark Salyzyn#include <sys/prctl.h>
13fc737fb76cc889d0c19bd8bf74d2b5f1fc4fbe6eMark Salyzyn#include <sys/stat.h>
14fc737fb76cc889d0c19bd8bf74d2b5f1fc4fbe6eMark Salyzyn#include <unistd.h>
15fc737fb76cc889d0c19bd8bf74d2b5f1fc4fbe6eMark Salyzyn
160795272aa226f4e965968a03daddc53ce30b7cdaMathias Agopian#include <binder/IPCThreadState.h>
17b69ffdb2078e2272fa5637a8c8f2b58020946e20Martijn Coenen#include <hwbinder/IPCThreadState.h>
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h>
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <cutils/memory.h>
20c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath#include <cutils/properties.h>
216ad0452e6301c0650f58f3991f7c523f6f279ddbJamie Gennis#include <cutils/trace.h>
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android_runtime/AndroidRuntime.h>
23d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath#include <private/android_filesystem_config.h>  // for AID_SYSTEM
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampestatic void app_usage()
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    fprintf(stderr,
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Usage: app_process [java-options] cmd-dir start-class-name [options]\n");
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass AppRuntime : public AndroidRuntime
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic:
36a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    AppRuntime(char* argBlockStart, const size_t argBlockLength)
37a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath        : AndroidRuntime(argBlockStart, argBlockLength)
38d195e5ab401432ddac659791640a2927fc668699Elliott Hughes        , mClass(NULL)
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4222ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    void setClassNameAndArgs(const String8& className, int argc, char * const *argv) {
4322ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        mClassName = className;
4422ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        for (int i = 0; i < argc; ++i) {
4522ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath             mArgs.add(String8(argv[i]));
4622ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        }
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
49d195e5ab401432ddac659791640a2927fc668699Elliott Hughes    virtual void onVmCreated(JNIEnv* env)
50d195e5ab401432ddac659791640a2927fc668699Elliott Hughes    {
5122ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        if (mClassName.isEmpty()) {
52d195e5ab401432ddac659791640a2927fc668699Elliott Hughes            return; // Zygote. Nothing to do here.
53d195e5ab401432ddac659791640a2927fc668699Elliott Hughes        }
54d195e5ab401432ddac659791640a2927fc668699Elliott Hughes
55d195e5ab401432ddac659791640a2927fc668699Elliott Hughes        /*
56d195e5ab401432ddac659791640a2927fc668699Elliott Hughes         * This is a little awkward because the JNI FindClass call uses the
57d195e5ab401432ddac659791640a2927fc668699Elliott Hughes         * class loader associated with the native method we're executing in.
58d195e5ab401432ddac659791640a2927fc668699Elliott Hughes         * If called in onStarted (from RuntimeInit.finishInit because we're
59d195e5ab401432ddac659791640a2927fc668699Elliott Hughes         * launching "am", for example), FindClass would see that we're calling
60d195e5ab401432ddac659791640a2927fc668699Elliott Hughes         * from a boot class' native method, and so wouldn't look for the class
61d195e5ab401432ddac659791640a2927fc668699Elliott Hughes         * we're trying to look up in CLASSPATH. Unfortunately it needs to,
62d195e5ab401432ddac659791640a2927fc668699Elliott Hughes         * because the "am" classes are not boot classes.
63d195e5ab401432ddac659791640a2927fc668699Elliott Hughes         *
64d195e5ab401432ddac659791640a2927fc668699Elliott Hughes         * The easiest fix is to call FindClass here, early on before we start
65d195e5ab401432ddac659791640a2927fc668699Elliott Hughes         * executing boot class Java code and thereby deny ourselves access to
66d195e5ab401432ddac659791640a2927fc668699Elliott Hughes         * non-boot classes.
67d195e5ab401432ddac659791640a2927fc668699Elliott Hughes         */
6822ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        char* slashClassName = toSlashClassName(mClassName.string());
69d195e5ab401432ddac659791640a2927fc668699Elliott Hughes        mClass = env->FindClass(slashClassName);
70d195e5ab401432ddac659791640a2927fc668699Elliott Hughes        if (mClass == NULL) {
7122ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath            ALOGE("ERROR: could not find class '%s'\n", mClassName.string());
72d195e5ab401432ddac659791640a2927fc668699Elliott Hughes        }
73d195e5ab401432ddac659791640a2927fc668699Elliott Hughes        free(slashClassName);
74d195e5ab401432ddac659791640a2927fc668699Elliott Hughes
75d195e5ab401432ddac659791640a2927fc668699Elliott Hughes        mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
76d195e5ab401432ddac659791640a2927fc668699Elliott Hughes    }
77d195e5ab401432ddac659791640a2927fc668699Elliott Hughes
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    virtual void onStarted()
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sp<ProcessState> proc = ProcessState::self();
8171f2cf116aab893e224056c38ab146bd1538dd3eSteve Block        ALOGV("App process: starting thread pool.\n");
8210e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown        proc->startThreadPool();
83d195e5ab401432ddac659791640a2927fc668699Elliott Hughes
84d195e5ab401432ddac659791640a2927fc668699Elliott Hughes        AndroidRuntime* ar = AndroidRuntime::getRuntime();
8522ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        ar->callMain(mClassName, mClass, mArgs);
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8710e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown        IPCThreadState::self()->stopProcess();
88b69ffdb2078e2272fa5637a8c8f2b58020946e20Martijn Coenen        hardware::IPCThreadState::self()->stopProcess();
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    virtual void onZygoteInit()
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sp<ProcessState> proc = ProcessState::self();
9471f2cf116aab893e224056c38ab146bd1538dd3eSteve Block        ALOGV("App process: starting thread pool.\n");
9510e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown        proc->startThreadPool();
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    virtual void onExit(int code)
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {
10090c75cf02e8e36be8679273f4ea15fd145001033Narayan Kamath        if (mClassName.isEmpty()) {
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // if zygote
10210e89712863f5b91a2982dc1783fbdfe39c1485dJeff Brown            IPCThreadState::self()->stopProcess();
103b69ffdb2078e2272fa5637a8c8f2b58020946e20Martijn Coenen            hardware::IPCThreadState::self()->stopProcess();
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AndroidRuntime::onExit(code);
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
109d195e5ab401432ddac659791640a2927fc668699Elliott Hughes
11022ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    String8 mClassName;
11122ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    Vector<String8> mArgs;
112d195e5ab401432ddac659791640a2927fc668699Elliott Hughes    jclass mClass;
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectusing namespace android;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
119a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamathstatic size_t computeArgBlockSize(int argc, char* const argv[]) {
120a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    // TODO: This assumes that all arguments are allocated in
121a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    // contiguous memory. There isn't any documented guarantee
122a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    // that this is the case, but this is how the kernel does it
123a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    // (see fs/exec.c).
124a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    //
125a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    // Also note that this is a constant for "normal" android apps.
126a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    // Since they're forked from zygote, the size of their command line
127a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    // is the size of the zygote command line.
128a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    //
129a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    // We change the process name of the process by over-writing
130a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    // the start of the argument block (argv[0]) with the new name of
131a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    // the process, so we'd mysteriously start getting truncated process
132a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    // names if the zygote command line decreases in size.
133a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
134a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
13500c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown    end += strlen(argv[argc - 1]) + 1;
136a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    return (end - start);
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
139d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamathstatic void maybeCreateDalvikCache() {
140d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath#if defined(__aarch64__)
141d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    static const char kInstructionSet[] = "arm64";
142d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath#elif defined(__x86_64__)
143d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    static const char kInstructionSet[] = "x86_64";
144d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath#elif defined(__arm__)
145d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    static const char kInstructionSet[] = "arm";
1466eb1b2611cd2db7f2c2063f8be219d4ef19d11d0Narayan Kamath#elif defined(__i386__)
147d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    static const char kInstructionSet[] = "x86";
1487e7c6031821e2aa55c756a9c85f97a22f4875552Douglas Leung#elif defined (__mips__) && !defined(__LP64__)
149d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    static const char kInstructionSet[] = "mips";
1507e7c6031821e2aa55c756a9c85f97a22f4875552Douglas Leung#elif defined (__mips__) && defined(__LP64__)
1517e7c6031821e2aa55c756a9c85f97a22f4875552Douglas Leung    static const char kInstructionSet[] = "mips64";
152d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath#else
153d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath#error "Unknown instruction set"
154d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath#endif
155d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    const char* androidRoot = getenv("ANDROID_DATA");
156d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    LOG_ALWAYS_FATAL_IF(androidRoot == NULL, "ANDROID_DATA environment variable unset");
157d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath
158d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    char dalvikCacheDir[PATH_MAX];
159d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    const int numChars = snprintf(dalvikCacheDir, PATH_MAX,
160d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath            "%s/dalvik-cache/%s", androidRoot, kInstructionSet);
161d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    LOG_ALWAYS_FATAL_IF((numChars >= PATH_MAX || numChars < 0),
162d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath            "Error constructing dalvik cache : %s", strerror(errno));
163d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath
16455471dcd0f843e79d8665c63165720eca6a9c980Alex Light    int result = mkdir(dalvikCacheDir, 0711);
165d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    LOG_ALWAYS_FATAL_IF((result < 0 && errno != EEXIST),
166d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath            "Error creating cache dir %s : %s", dalvikCacheDir, strerror(errno));
167d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath
168d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    // We always perform these steps because the directory might
169d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    // already exist, with wider permissions and a different owner
170d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    // than we'd like.
17155471dcd0f843e79d8665c63165720eca6a9c980Alex Light    result = chown(dalvikCacheDir, AID_ROOT, AID_ROOT);
172d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    LOG_ALWAYS_FATAL_IF((result < 0), "Error changing dalvik-cache ownership : %s", strerror(errno));
173d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath
17455471dcd0f843e79d8665c63165720eca6a9c980Alex Light    result = chmod(dalvikCacheDir, 0711);
175d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath    LOG_ALWAYS_FATAL_IF((result < 0),
176d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath            "Error changing dalvik-cache permissions : %s", strerror(errno));
177d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath}
178d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath
179c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath#if defined(__LP64__)
180c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamathstatic const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
181d35d3e5d391b8daf20f9af2c5f01d5ff1985c1eeNarayan Kamathstatic const char ZYGOTE_NICE_NAME[] = "zygote64";
182c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath#else
183c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamathstatic const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
184d35d3e5d391b8daf20f9af2c5f01d5ff1985c1eeNarayan Kamathstatic const char ZYGOTE_NICE_NAME[] = "zygote";
185c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath#endif
186c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath
1878a0a929422682ba3eb6a205dc6c0638e68b909deNick Kralevichint main(int argc, char* const argv[])
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
1894f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin    if (!LOG_NDEBUG) {
1904f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin      String8 argv_String;
1914f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin      for (int i = 0; i < argc; ++i) {
1924f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin        argv_String.append("\"");
1934f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin        argv_String.append(argv[i]);
1944f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin        argv_String.append("\" ");
1954f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin      }
1964f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin      ALOGV("app_process main with argv: %s", argv_String.string());
1974f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin    }
1984f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin
199a23fcd7be8e40078a913b1a99222cdd89229e67bNarayan Kamath    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Process command line arguments
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // ignore argv[0]
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    argc--;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    argv++;
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20522ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // Everything up to '--' or first non '-' arg goes to the vm.
20622ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    //
20722ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // The first argument after the VM args is the "parent dir", which
20822ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // is currently unused.
20922ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    //
21022ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // After the parent dir, we expect one or more the following internal
21122ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // arguments :
21222ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    //
21322ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // --zygote : Start in zygote mode
21422ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // --start-system-server : Start the system server.
21522ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // --application : Start in application (stand alone, non zygote) mode.
21622ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // --nice-name : The nice name for this process.
21722ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    //
21822ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // For non zygote starts, these arguments will be followed by
21922ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // the main class name. All remaining arguments are passed to
22022ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // the main method of this class.
22122ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    //
22222ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // For zygote starts, all remaining arguments are passed to the zygote.
22322ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    // main function.
22400c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown    //
22500c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown    // Note that we must copy argument string values since we will rewrite the
22600c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown    // entire argument block when we apply the nice name to argv0.
2274f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin    //
2284f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin    // As an exception to the above rule, anything in "spaced commands"
2294f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin    // goes to the vm even though it has a space in it.
2304f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin    const char* spaced_commands[] = { "-cp", "-classpath" };
2314f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
2324f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin    bool known_command = false;
23322ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath
23400c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown    int i;
23500c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown    for (i = 0; i < argc; i++) {
2364f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin        if (known_command == true) {
2374f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin          runtime.addOption(strdup(argv[i]));
2384f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin          ALOGV("app_process main add known option '%s'", argv[i]);
2394f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin          known_command = false;
2404f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin          continue;
2414f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin        }
2424f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin
2434f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin        for (int j = 0;
2444f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin             j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
2454f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin             ++j) {
2464f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin          if (strcmp(argv[i], spaced_commands[j]) == 0) {
2474f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin            known_command = true;
2484f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin            ALOGV("app_process main found known command '%s'", argv[i]);
2494f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin          }
2504f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin        }
2514f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin
25200c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown        if (argv[i][0] != '-') {
25300c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown            break;
25400c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown        }
25500c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown        if (argv[i][1] == '-' && argv[i][2] == 0) {
25600c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown            ++i; // Skip --.
25700c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown            break;
25800c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown        }
2594f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin
26000c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown        runtime.addOption(strdup(argv[i]));
2614f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin        ALOGV("app_process main add option '%s'", argv[i]);
26200c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown    }
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
264ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    // Parse runtime arguments.  Stop at first unrecognized option.
265ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    bool zygote = false;
266ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    bool startSystemServer = false;
267ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    bool application = false;
26800c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown    String8 niceName;
26922ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    String8 className;
27022ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath
27122ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    ++i;  // Skip unused "parent dir" argument.
272ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    while (i < argc) {
273ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        const char* arg = argv[i++];
27422ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        if (strcmp(arg, "--zygote") == 0) {
275ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            zygote = true;
276d35d3e5d391b8daf20f9af2c5f01d5ff1985c1eeNarayan Kamath            niceName = ZYGOTE_NICE_NAME;
277ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        } else if (strcmp(arg, "--start-system-server") == 0) {
278ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            startSystemServer = true;
279ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        } else if (strcmp(arg, "--application") == 0) {
280ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            application = true;
281ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
28200c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown            niceName.setTo(arg + 12);
283d35d3e5d391b8daf20f9af2c5f01d5ff1985c1eeNarayan Kamath        } else if (strncmp(arg, "--", 2) != 0) {
28422ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath            className.setTo(arg);
285ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown            break;
286d35d3e5d391b8daf20f9af2c5f01d5ff1985c1eeNarayan Kamath        } else {
287d35d3e5d391b8daf20f9af2c5f01d5ff1985c1eeNarayan Kamath            --i;
288d35d3e5d391b8daf20f9af2c5f01d5ff1985c1eeNarayan Kamath            break;
289ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown        }
290ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    }
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29222ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    Vector<String8> args;
29322ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    if (!className.isEmpty()) {
29422ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        // We're not in zygote mode, the only argument we need to pass
29522ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        // to RuntimeInit is the application argument.
29622ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        //
29722ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        // The Remainder of args get passed to startup class main(). Make
29822ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        // copies of them before we overwrite them with the process name.
29922ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        args.add(application ? String8("application") : String8("tool"));
30022ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        runtime.setClassNameAndArgs(className, argc - i, argv + i);
3014f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin
3024f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin        if (!LOG_NDEBUG) {
3034f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin          String8 restOfArgs;
3044f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin          char* const* argv_new = argv + i;
3054f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin          int argc_new = argc - i;
3064f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin          for (int k = 0; k < argc_new; ++k) {
3074f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin            restOfArgs.append("\"");
3084f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin            restOfArgs.append(argv_new[k]);
3094f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin            restOfArgs.append("\" ");
3104f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin          }
3114f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin          ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
3124f66cb3f534eafff335ec803caff0572d08e8aa5Igor Murashkin        }
31322ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    } else {
314d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath        // We're in zygote mode.
315d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath        maybeCreateDalvikCache();
316d1e127e141a8080477f3b3becb792f138ca9ab65Narayan Kamath
31722ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        if (startSystemServer) {
31822ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath            args.add(String8("start-system-server"));
31922ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        }
32022ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath
321c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath        char prop[PROP_VALUE_MAX];
322c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
3236bd762289b911e8876759ebbfd9e8960ba825844Elliott Hughes            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
324c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath                ABI_LIST_PROPERTY);
325c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath            return 11;
326c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath        }
327c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath
328c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath        String8 abiFlag("--abi-list=");
329c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath        abiFlag.append(prop);
330c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath        args.add(abiFlag);
331c41638cb759ce569630ffae4c5c4cdee1b0f3b82Narayan Kamath
33222ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        // In zygote mode, pass all remaining arguments to the zygote
33322ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        // main() method.
33422ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        for (; i < argc; ++i) {
33522ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath            args.add(String8(argv[i]));
33622ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath        }
33722ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath    }
33822ec1eefa4dc8e12f7da8e8750d4770144941526Narayan Kamath
33900c0cd4a24bd0f040055f9e786e2df1fa3b7d2d3Jeff Brown    if (!niceName.isEmpty()) {
340f5b6e5590e0a2c1be10bc0bd0a3b141256fdf7fdDmitriy Filchenko        runtime.setArgv0(niceName.string(), true /* setProcName */);
341ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    }
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
343ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    if (zygote) {
3447a09b8322cab26d6e3da1362d3c74964ae66b5d4Sebastien Hertz        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
345ebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3Jeff Brown    } else if (className) {
3467a09b8322cab26d6e3da1362d3c74964ae66b5d4Sebastien Hertz        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        app_usage();
350de6d1d889ebf15250c04a8ffc204b91af1e447e3Brian Carlstrom        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
353