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 24 namespace android { 25 26 void app_usage() 27 { 28 fprintf(stderr, 29 "Usage: app_process [java-options] cmd-dir start-class-name [options]\n"); 30 } 31 32 class AppRuntime : public AndroidRuntime 33 { 34 public: 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 128 using namespace android; 129 130 /* 131 * sets argv0 to as much of newArgv0 as will fit 132 */ 133 static void setArgv0(const char *argv0, const char *newArgv0) 134 { 135 strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0)); 136 } 137 138 int 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