app_main.cpp revision 6bd762289b911e8876759ebbfd9e8960ba825844
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/memory.h> 14#include <cutils/process_name.h> 15#include <cutils/properties.h> 16#include <cutils/trace.h> 17#include <android_runtime/AndroidRuntime.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(char* argBlockStart, const size_t argBlockLength) 35 : AndroidRuntime(argBlockStart, argBlockLength) 36 , mClass(NULL) 37 { 38 } 39 40 void setClassNameAndArgs(const String8& className, int argc, char * const *argv) { 41 mClassName = className; 42 for (int i = 0; i < argc; ++i) { 43 mArgs.add(String8(argv[i])); 44 } 45 } 46 47 virtual void onVmCreated(JNIEnv* env) 48 { 49 if (mClassName.isEmpty()) { 50 return; // Zygote. Nothing to do here. 51 } 52 53 /* 54 * This is a little awkward because the JNI FindClass call uses the 55 * class loader associated with the native method we're executing in. 56 * If called in onStarted (from RuntimeInit.finishInit because we're 57 * launching "am", for example), FindClass would see that we're calling 58 * from a boot class' native method, and so wouldn't look for the class 59 * we're trying to look up in CLASSPATH. Unfortunately it needs to, 60 * because the "am" classes are not boot classes. 61 * 62 * The easiest fix is to call FindClass here, early on before we start 63 * executing boot class Java code and thereby deny ourselves access to 64 * non-boot classes. 65 */ 66 char* slashClassName = toSlashClassName(mClassName.string()); 67 mClass = env->FindClass(slashClassName); 68 if (mClass == NULL) { 69 ALOGE("ERROR: could not find class '%s'\n", mClassName.string()); 70 } 71 free(slashClassName); 72 73 mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass)); 74 } 75 76 virtual void onStarted() 77 { 78 sp<ProcessState> proc = ProcessState::self(); 79 ALOGV("App process: starting thread pool.\n"); 80 proc->startThreadPool(); 81 82 AndroidRuntime* ar = AndroidRuntime::getRuntime(); 83 ar->callMain(mClassName, mClass, mArgs); 84 85 IPCThreadState::self()->stopProcess(); 86 } 87 88 virtual void onZygoteInit() 89 { 90 // Re-enable tracing now that we're no longer in Zygote. 91 atrace_set_tracing_enabled(true); 92 93 sp<ProcessState> proc = ProcessState::self(); 94 ALOGV("App process: starting thread pool.\n"); 95 proc->startThreadPool(); 96 } 97 98 virtual void onExit(int code) 99 { 100 if (mClassName.isEmpty()) { 101 // if zygote 102 IPCThreadState::self()->stopProcess(); 103 } 104 105 AndroidRuntime::onExit(code); 106 } 107 108 109 String8 mClassName; 110 Vector<String8> mArgs; 111 jclass mClass; 112}; 113 114} 115 116using namespace android; 117 118static size_t computeArgBlockSize(int argc, char* const argv[]) { 119 // TODO: This assumes that all arguments are allocated in 120 // contiguous memory. There isn't any documented guarantee 121 // that this is the case, but this is how the kernel does it 122 // (see fs/exec.c). 123 // 124 // Also note that this is a constant for "normal" android apps. 125 // Since they're forked from zygote, the size of their command line 126 // is the size of the zygote command line. 127 // 128 // We change the process name of the process by over-writing 129 // the start of the argument block (argv[0]) with the new name of 130 // the process, so we'd mysteriously start getting truncated process 131 // names if the zygote command line decreases in size. 132 uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]); 133 uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]); 134 end += strlen(argv[argc - 1]); 135 136 return (end - start); 137} 138 139#if defined(__LP64__) 140static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64"; 141static const char ZYGOTE_NICE_NAME[] = "zygote64"; 142#else 143static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32"; 144static const char ZYGOTE_NICE_NAME[] = "zygote"; 145#endif 146 147int main(int argc, char* const argv[]) 148{ 149 AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); 150 // Process command line arguments 151 // ignore argv[0] 152 argc--; 153 argv++; 154 155 // Everything up to '--' or first non '-' arg goes to the vm. 156 // 157 // The first argument after the VM args is the "parent dir", which 158 // is currently unused. 159 // 160 // After the parent dir, we expect one or more the following internal 161 // arguments : 162 // 163 // --zygote : Start in zygote mode 164 // --start-system-server : Start the system server. 165 // --application : Start in application (stand alone, non zygote) mode. 166 // --nice-name : The nice name for this process. 167 // 168 // For non zygote starts, these arguments will be followed by 169 // the main class name. All remaining arguments are passed to 170 // the main method of this class. 171 // 172 // For zygote starts, all remaining arguments are passed to the zygote. 173 // main function. 174 175 176 int i = runtime.addVmArguments(argc, argv); 177 178 // Parse runtime arguments. Stop at first unrecognized option. 179 bool zygote = false; 180 bool startSystemServer = false; 181 bool application = false; 182 const char* niceName = NULL; 183 String8 className; 184 185 ++i; // Skip unused "parent dir" argument. 186 while (i < argc) { 187 const char* arg = argv[i++]; 188 if (strcmp(arg, "--zygote") == 0) { 189 zygote = true; 190 niceName = ZYGOTE_NICE_NAME; 191 } else if (strcmp(arg, "--start-system-server") == 0) { 192 startSystemServer = true; 193 } else if (strcmp(arg, "--application") == 0) { 194 application = true; 195 } else if (strncmp(arg, "--nice-name=", 12) == 0) { 196 niceName = arg + 12; 197 } else if (strncmp(arg, "--", 2) != 0) { 198 className.setTo(arg); 199 break; 200 } else { 201 --i; 202 break; 203 } 204 } 205 206 Vector<String8> args; 207 if (!className.isEmpty()) { 208 // We're not in zygote mode, the only argument we need to pass 209 // to RuntimeInit is the application argument. 210 // 211 // The Remainder of args get passed to startup class main(). Make 212 // copies of them before we overwrite them with the process name. 213 args.add(application ? String8("application") : String8("tool")); 214 runtime.setClassNameAndArgs(className, argc - i, argv + i); 215 } else { 216 if (startSystemServer) { 217 args.add(String8("start-system-server")); 218 } 219 220 char prop[PROP_VALUE_MAX]; 221 if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) { 222 LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.", 223 ABI_LIST_PROPERTY); 224 return 11; 225 } 226 227 String8 abiFlag("--abi-list="); 228 abiFlag.append(prop); 229 args.add(abiFlag); 230 231 // In zygote mode, pass all remaining arguments to the zygote 232 // main() method. 233 for (; i < argc; ++i) { 234 args.add(String8(argv[i])); 235 } 236 } 237 238 if (niceName && *niceName) { 239 runtime.setArgv0(niceName); 240 set_process_name(niceName); 241 } 242 243 if (zygote) { 244 runtime.start("com.android.internal.os.ZygoteInit", args); 245 } else if (className) { 246 runtime.start("com.android.internal.os.RuntimeInit", args); 247 } else { 248 fprintf(stderr, "Error: no class name or --zygote supplied.\n"); 249 app_usage(); 250 LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); 251 return 10; 252 } 253} 254