blob: ca80fc2edc26748b152e8ced7ae296a378b1b169 [file] [log] [blame]
Brian Carlstrom27ec9612011-09-19 20:20:38 -07001/*
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
17#include <stdio.h>
18#include <unistd.h>
19
20namespace android {
21
22void app_usage()
23{
24 fprintf(stderr,
25 "Usage: oat_process [java-options] cmd-dir start-class-name [options]\n");
26}
27
28class AppRuntime : public AndroidRuntime
29{
30public:
31 AppRuntime()
32 : mParentDir(NULL)
33 , mClassName(NULL)
34 , mClass(NULL)
35 , mArgC(0)
36 , mArgV(NULL)
37 {
38 }
39
40#if 0
41 // this appears to be unused
42 const char* getParentDir() const
43 {
44 return mParentDir;
45 }
46#endif
47
48 const char* getClassName() const
49 {
50 return mClassName;
51 }
52
53 virtual void onVmCreated(JNIEnv* env)
54 {
55 if (mClassName == NULL) {
56 return; // Zygote. Nothing to do here.
57 }
58
59 /*
60 * This is a little awkward because the JNI FindClass call uses the
61 * class loader associated with the native method we're executing in.
62 * If called in onStarted (from RuntimeInit.finishInit because we're
63 * launching "am", for example), FindClass would see that we're calling
64 * from a boot class' native method, and so wouldn't look for the class
65 * we're trying to look up in CLASSPATH. Unfortunately it needs to,
66 * because the "am" classes are not boot classes.
67 *
68 * The easiest fix is to call FindClass here, early on before we start
69 * executing boot class Java code and thereby deny ourselves access to
70 * non-boot classes.
71 */
72 char* slashClassName = toSlashClassName(mClassName);
73 mClass = env->FindClass(slashClassName);
74 if (mClass == NULL) {
75 LOGE("ERROR: could not find class '%s'\n", mClassName);
76 }
77 free(slashClassName);
78
79 mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
80 }
81
82 virtual void onStarted()
83 {
84 sp<ProcessState> proc = ProcessState::self();
85 LOGV("App process: starting thread pool.\n");
86 proc->startThreadPool();
87
88 AndroidRuntime* ar = AndroidRuntime::getRuntime();
89 ar->callMain(mClassName, mClass, mArgC, mArgV);
90
91 IPCThreadState::self()->stopProcess();
92 }
93
94 virtual void onZygoteInit()
95 {
96 sp<ProcessState> proc = ProcessState::self();
97 LOGV("App process: starting thread pool.\n");
98 proc->startThreadPool();
99 }
100
101 virtual void onExit(int code)
102 {
103 if (mClassName == NULL) {
104 // if zygote
105 IPCThreadState::self()->stopProcess();
106 }
107
108 AndroidRuntime::onExit(code);
109 }
110
111
112 const char* mParentDir;
113 const char* mClassName;
114 jclass mClass;
115 int mArgC;
116 const char* const* mArgV;
117};
118
119}
120
121using namespace android;
122
123/*
124 * sets argv0 to as much of newArgv0 as will fit
125 */
126static void setArgv0(const char *argv0, const char *newArgv0)
127{
128 strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
129}
130
Brian Carlstrom395520e2011-09-25 19:35:00 -0700131int main(int argc, const char* argv[])
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700132{
133 // These are global variables in ProcessState.cpp
134 mArgC = argc;
135 mArgV = argv;
136
137 mArgLen = 0;
138 for (int i=0; i<argc; i++) {
139 mArgLen += strlen(argv[i]) + 1;
140 }
141 mArgLen--;
142
143 AppRuntime runtime;
144 const char* argv0 = argv[0];
145
146 // Process command line arguments
147 // ignore argv[0]
148 argc--;
149 argv++;
150
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700151 // ignore /system/bin/app_process when invoked via WrapperInit
152 if (strcmp(argv[0], "/system/bin/app_process") == 0) {
153 LOGI("Removing /system/bin/app_process argument");
154 argc--;
155 argv++;
156 for (int i = 0; i < argc; i++) {
157 LOGI("argv[%d]=%s", i, argv[i]);
158 }
159 }
160
161 // TODO: remove Calculator special case
162 int oatArgc = argc + 2;
163 const char* oatArgv[oatArgc];
164 if (strcmp(argv[0], "-Xbootimage:/system/framework/boot.oat") != 0) {
165 LOGI("Adding oat arguments");
166 oatArgv[0] = "-Xbootimage:/system/framework/boot.oat";
167 oatArgv[1] = "-Ximage:/system/app/Calculator.oat";
168 setenv("CLASSPATH", "/system/app/Calculator.apk", 1);
169 memcpy(oatArgv + (oatArgc - argc), argv, argc * sizeof(*argv));
170 argv = oatArgv;
171 argc = oatArgc;
172 for (int i = 0; i < argc; i++) {
173 LOGI("argv[%d]=%s", i, argv[i]);
174 }
175 }
176
177 // TODO: remove the heap arguments when implicit garbage collection enabled
178 LOGI("Adding heap arguments");
179 int heapArgc = argc + 2;
180 const char* heapArgv[heapArgc];
181 heapArgv[0] = "-Xms64m";
182 heapArgv[1] = "-Xmx64m";
183 memcpy(heapArgv + (heapArgc - argc), argv, argc * sizeof(*argv));
184 argv = heapArgv;
185 argc = heapArgc;
186 for (int i = 0; i < argc; i++) {
187 LOGI("argv[%d]=%s", i, argv[i]);
188 }
189
Brian Carlstrom395520e2011-09-25 19:35:00 -0700190 // TODO: change the system default to not perform preloading
191 LOGI("Disabling preloading");
192 for (int i = 0; i < argc; i++) {
193 if (strcmp(argv[i], "preload") == 0) {
194 argv[i] = "nopreload";
195 break;
196 }
197 }
198 for (int i = 0; i < argc; i++) {
199 LOGI("argv[%d]=%s", i, argv[i]);
200 }
201
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700202 // Everything up to '--' or first non '-' arg goes to the vm
203
204 int i = runtime.addVmArguments(argc, argv);
205
206 // Parse runtime arguments. Stop at first unrecognized option.
207 bool zygote = false;
208 bool startSystemServer = false;
209 bool application = false;
210 const char* parentDir = NULL;
211 const char* niceName = NULL;
212 const char* className = NULL;
213 while (i < argc) {
214 const char* arg = argv[i++];
215 if (!parentDir) {
216 parentDir = arg;
217 } else if (strcmp(arg, "--zygote") == 0) {
218 zygote = true;
219 niceName = "zygote";
220 } else if (strcmp(arg, "--start-system-server") == 0) {
221 startSystemServer = true;
222 } else if (strcmp(arg, "--application") == 0) {
223 application = true;
224 } else if (strncmp(arg, "--nice-name=", 12) == 0) {
225 niceName = arg + 12;
226 } else {
227 className = arg;
228 break;
229 }
230 }
231
232 if (niceName && *niceName) {
233 setArgv0(argv0, niceName);
234 set_process_name(niceName);
235 }
236
237 runtime.mParentDir = parentDir;
238
239 if (zygote) {
240 runtime.start("com.android.internal.os.ZygoteInit",
241 startSystemServer ? "start-system-server" : "");
242 } else if (className) {
243 // Remainder of args get passed to startup class main()
244 runtime.mClassName = className;
245 runtime.mArgC = argc - i;
246 runtime.mArgV = argv + i;
247 runtime.start("com.android.internal.os.RuntimeInit",
248 application ? "application" : "tool");
249 } else {
250 fprintf(stderr, "Error: no class name or --zygote supplied.\n");
251 app_usage();
252 LOG_ALWAYS_FATAL("oat_process: no class name or --zygote supplied.");
253 return 10;
254 }
255}