app_main.cpp revision a23fcd7be8e40078a913b1a99222cdd89229e67b
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 <cutils/trace.h> 16#include <android_runtime/AndroidRuntime.h> 17 18#include <stdlib.h> 19#include <stdio.h> 20#include <unistd.h> 21 22namespace android { 23 24void app_usage() 25{ 26 fprintf(stderr, 27 "Usage: app_process [java-options] cmd-dir start-class-name [options]\n"); 28} 29 30class AppRuntime : public AndroidRuntime 31{ 32public: 33 AppRuntime(char* argBlockStart, const size_t argBlockLength) 34 : AndroidRuntime(argBlockStart, argBlockLength) 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 // Re-enable tracing now that we're no longer in Zygote. 100 atrace_set_tracing_enabled(true); 101 102 sp<ProcessState> proc = ProcessState::self(); 103 ALOGV("App process: starting thread pool.\n"); 104 proc->startThreadPool(); 105 } 106 107 virtual void onExit(int code) 108 { 109 if (mClassName == NULL) { 110 // if zygote 111 IPCThreadState::self()->stopProcess(); 112 } 113 114 AndroidRuntime::onExit(code); 115 } 116 117 118 const char* mParentDir; 119 const char* mClassName; 120 jclass mClass; 121 int mArgC; 122 const char* const* mArgV; 123}; 124 125} 126 127using namespace android; 128 129static size_t computeArgBlockSize(int argc, char* const argv[]) { 130 // TODO: This assumes that all arguments are allocated in 131 // contiguous memory. There isn't any documented guarantee 132 // that this is the case, but this is how the kernel does it 133 // (see fs/exec.c). 134 // 135 // Also note that this is a constant for "normal" android apps. 136 // Since they're forked from zygote, the size of their command line 137 // is the size of the zygote command line. 138 // 139 // We change the process name of the process by over-writing 140 // the start of the argument block (argv[0]) with the new name of 141 // the process, so we'd mysteriously start getting truncated process 142 // names if the zygote command line decreases in size. 143 uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]); 144 uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]); 145 end += strlen(argv[argc - 1]); 146 147 return (end - start); 148} 149 150int main(int argc, char* const argv[]) 151{ 152 AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); 153 // Process command line arguments 154 // ignore argv[0] 155 argc--; 156 argv++; 157 158 // Everything up to '--' or first non '-' arg goes to the vm 159 160 int i = runtime.addVmArguments(argc, argv); 161 162 // Parse runtime arguments. Stop at first unrecognized option. 163 bool zygote = false; 164 bool startSystemServer = false; 165 bool application = false; 166 const char* parentDir = NULL; 167 const char* niceName = NULL; 168 const char* className = NULL; 169 while (i < argc) { 170 const char* arg = argv[i++]; 171 if (!parentDir) { 172 parentDir = arg; 173 } else if (strcmp(arg, "--zygote") == 0) { 174 zygote = true; 175 niceName = "zygote"; 176 } else if (strcmp(arg, "--start-system-server") == 0) { 177 startSystemServer = true; 178 } else if (strcmp(arg, "--application") == 0) { 179 application = true; 180 } else if (strncmp(arg, "--nice-name=", 12) == 0) { 181 niceName = arg + 12; 182 } else { 183 className = arg; 184 break; 185 } 186 } 187 188 if (niceName && *niceName) { 189 runtime.setArgv0(niceName); 190 set_process_name(niceName); 191 } 192 193 runtime.mParentDir = parentDir; 194 195 if (zygote) { 196 runtime.start("com.android.internal.os.ZygoteInit", 197 startSystemServer ? "start-system-server" : ""); 198 } else if (className) { 199 // Remainder of args get passed to startup class main() 200 runtime.mClassName = className; 201 runtime.mArgC = argc - i; 202 runtime.mArgV = argv + i; 203 runtime.start("com.android.internal.os.RuntimeInit", 204 application ? "application" : "tool"); 205 } else { 206 fprintf(stderr, "Error: no class name or --zygote supplied.\n"); 207 app_usage(); 208 LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); 209 return 10; 210 } 211} 212