blob: 92ede6d59a0ba8bc3a88a1082ee5d6c5a8b5963a [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
131int main(int argc, const char* const argv[])
132{
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 Carlstrom27ec9612011-09-19 20:20:38 -0700190 // Everything up to '--' or first non '-' arg goes to the vm
191
192 int i = runtime.addVmArguments(argc, argv);
193
194 // Parse runtime arguments. Stop at first unrecognized option.
195 bool zygote = false;
196 bool startSystemServer = false;
197 bool application = false;
198 const char* parentDir = NULL;
199 const char* niceName = NULL;
200 const char* className = NULL;
201 while (i < argc) {
202 const char* arg = argv[i++];
203 if (!parentDir) {
204 parentDir = arg;
205 } else if (strcmp(arg, "--zygote") == 0) {
206 zygote = true;
207 niceName = "zygote";
208 } else if (strcmp(arg, "--start-system-server") == 0) {
209 startSystemServer = true;
210 } else if (strcmp(arg, "--application") == 0) {
211 application = true;
212 } else if (strncmp(arg, "--nice-name=", 12) == 0) {
213 niceName = arg + 12;
214 } else {
215 className = arg;
216 break;
217 }
218 }
219
220 if (niceName && *niceName) {
221 setArgv0(argv0, niceName);
222 set_process_name(niceName);
223 }
224
225 runtime.mParentDir = parentDir;
226
227 if (zygote) {
228 runtime.start("com.android.internal.os.ZygoteInit",
229 startSystemServer ? "start-system-server" : "");
230 } else if (className) {
231 // Remainder of args get passed to startup class main()
232 runtime.mClassName = className;
233 runtime.mArgC = argc - i;
234 runtime.mArgV = argv + i;
235 runtime.start("com.android.internal.os.RuntimeInit",
236 application ? "application" : "tool");
237 } else {
238 fprintf(stderr, "Error: no class name or --zygote supplied.\n");
239 app_usage();
240 LOG_ALWAYS_FATAL("oat_process: no class name or --zygote supplied.");
241 return 10;
242 }
243}