blob: 45950cdf40c48c39ac29c7268a71021ba28c634b [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
Brian Carlstrome10b6972011-09-26 13:49:03 -070010#include "class_loader.h"
11#include "jni_internal.h"
12#include "stringprintf.h"
13#include "thread.h"
14
Brian Carlstrom27ec9612011-09-19 20:20:38 -070015#include <binder/IPCThreadState.h>
16#include <binder/ProcessState.h>
17#include <utils/Log.h>
18#include <cutils/process_name.h>
19#include <cutils/memory.h>
20#include <android_runtime/AndroidRuntime.h>
21
22#include <stdio.h>
23#include <unistd.h>
24
25namespace android {
26
27void app_usage()
28{
29 fprintf(stderr,
30 "Usage: oat_process [java-options] cmd-dir start-class-name [options]\n");
31}
32
33class AppRuntime : public AndroidRuntime
34{
35public:
36 AppRuntime()
37 : mParentDir(NULL)
38 , mClassName(NULL)
39 , mClass(NULL)
40 , mArgC(0)
41 , mArgV(NULL)
42 {
43 }
44
45#if 0
46 // this appears to be unused
47 const char* getParentDir() const
48 {
49 return mParentDir;
50 }
51#endif
52
53 const char* getClassName() const
54 {
55 return mClassName;
56 }
57
58 virtual void onVmCreated(JNIEnv* env)
59 {
60 if (mClassName == NULL) {
61 return; // Zygote. Nothing to do here.
62 }
63
64 /*
65 * This is a little awkward because the JNI FindClass call uses the
66 * class loader associated with the native method we're executing in.
67 * If called in onStarted (from RuntimeInit.finishInit because we're
68 * launching "am", for example), FindClass would see that we're calling
69 * from a boot class' native method, and so wouldn't look for the class
70 * we're trying to look up in CLASSPATH. Unfortunately it needs to,
71 * because the "am" classes are not boot classes.
72 *
73 * The easiest fix is to call FindClass here, early on before we start
74 * executing boot class Java code and thereby deny ourselves access to
75 * non-boot classes.
76 */
77 char* slashClassName = toSlashClassName(mClassName);
78 mClass = env->FindClass(slashClassName);
79 if (mClass == NULL) {
Brian Carlstrome10b6972011-09-26 13:49:03 -070080 LOG(ERROR) << StringPrintf("ERROR: could not find class '%s'\n", mClassName);
Brian Carlstrom27ec9612011-09-19 20:20:38 -070081 }
82 free(slashClassName);
83
84 mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
Brian Carlstrome10b6972011-09-26 13:49:03 -070085
86 // TODO: remove this ClassLoader code
87 jclass ApplicationLoaders = env->FindClass("android/app/ApplicationLoaders");
88 jmethodID getDefault = env->GetStaticMethodID(ApplicationLoaders,
89 "getDefault",
90 "()Landroid/app/ApplicationLoaders;");
91 jfieldID mLoaders = env->GetFieldID(ApplicationLoaders, "mLoaders", "Ljava/util/Map;");
92 jclass BootClassLoader = env->FindClass("java/lang/BootClassLoader");
93 jmethodID getInstance = env->GetStaticMethodID(BootClassLoader,
94 "getInstance",
95 "()Ljava/lang/BootClassLoader;");
96 jclass ClassLoader = env->FindClass("java/lang/ClassLoader");
97 jfieldID parent = env->GetFieldID(ClassLoader, "parent", "Ljava/lang/ClassLoader;");
98 jclass Map = env->FindClass("java/util/Map");
99 jmethodID put = env->GetMethodID(Map,
100 "put",
101 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
102
103 jobject application_loaders = env->CallStaticObjectMethod(ApplicationLoaders, getDefault);
104 jobject loaders = env->GetObjectField(application_loaders, mLoaders);
105 jobject boot_class_loader = env->CallStaticObjectMethod(BootClassLoader, getInstance);
106 const art::ClassLoader* class_loader_object = art::Thread::Current()->GetClassLoaderOverride();
107 jobject class_loader = art::AddLocalReference<jobject>(env, class_loader_object);
108 env->SetObjectField(class_loader, parent, boot_class_loader);
109 jstring apk = env->NewStringUTF("/system/app/Calculator.apk");
110 env->CallObjectMethod(loaders, put, apk, class_loader);
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700111 }
112
113 virtual void onStarted()
114 {
115 sp<ProcessState> proc = ProcessState::self();
116 LOGV("App process: starting thread pool.\n");
117 proc->startThreadPool();
118
119 AndroidRuntime* ar = AndroidRuntime::getRuntime();
120 ar->callMain(mClassName, mClass, mArgC, mArgV);
121
122 IPCThreadState::self()->stopProcess();
123 }
124
125 virtual void onZygoteInit()
126 {
127 sp<ProcessState> proc = ProcessState::self();
128 LOGV("App process: starting thread pool.\n");
129 proc->startThreadPool();
130 }
131
132 virtual void onExit(int code)
133 {
134 if (mClassName == NULL) {
135 // if zygote
136 IPCThreadState::self()->stopProcess();
137 }
138
139 AndroidRuntime::onExit(code);
140 }
141
142
143 const char* mParentDir;
144 const char* mClassName;
145 jclass mClass;
146 int mArgC;
147 const char* const* mArgV;
148};
149
150}
151
152using namespace android;
153
154/*
155 * sets argv0 to as much of newArgv0 as will fit
156 */
157static void setArgv0(const char *argv0, const char *newArgv0)
158{
159 strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
160}
161
Brian Carlstrom395520e2011-09-25 19:35:00 -0700162int main(int argc, const char* argv[])
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700163{
164 // These are global variables in ProcessState.cpp
165 mArgC = argc;
166 mArgV = argv;
167
168 mArgLen = 0;
169 for (int i=0; i<argc; i++) {
170 mArgLen += strlen(argv[i]) + 1;
171 }
172 mArgLen--;
173
174 AppRuntime runtime;
175 const char* argv0 = argv[0];
176
177 // Process command line arguments
178 // ignore argv[0]
179 argc--;
180 argv++;
181
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700182 // ignore /system/bin/app_process when invoked via WrapperInit
183 if (strcmp(argv[0], "/system/bin/app_process") == 0) {
Brian Carlstrome10b6972011-09-26 13:49:03 -0700184 LOG(INFO) << "Removing /system/bin/app_process argument";
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700185 argc--;
186 argv++;
187 for (int i = 0; i < argc; i++) {
Brian Carlstrome10b6972011-09-26 13:49:03 -0700188 LOG(INFO) << StringPrintf("argv[%d]=%s", i, argv[i]);
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700189 }
190 }
191
192 // TODO: remove Calculator special case
193 int oatArgc = argc + 2;
194 const char* oatArgv[oatArgc];
195 if (strcmp(argv[0], "-Xbootimage:/system/framework/boot.oat") != 0) {
Brian Carlstrome10b6972011-09-26 13:49:03 -0700196 LOG(INFO) << "Adding oat arguments";
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700197 oatArgv[0] = "-Xbootimage:/system/framework/boot.oat";
198 oatArgv[1] = "-Ximage:/system/app/Calculator.oat";
199 setenv("CLASSPATH", "/system/app/Calculator.apk", 1);
200 memcpy(oatArgv + (oatArgc - argc), argv, argc * sizeof(*argv));
201 argv = oatArgv;
202 argc = oatArgc;
203 for (int i = 0; i < argc; i++) {
Brian Carlstrome10b6972011-09-26 13:49:03 -0700204 LOG(INFO) << StringPrintf("argv[%d]=%s", i, argv[i]);
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700205 }
206 }
207
208 // TODO: remove the heap arguments when implicit garbage collection enabled
Brian Carlstrome10b6972011-09-26 13:49:03 -0700209 LOG(INFO) << "Adding heap arguments";
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700210 int heapArgc = argc + 2;
211 const char* heapArgv[heapArgc];
212 heapArgv[0] = "-Xms64m";
213 heapArgv[1] = "-Xmx64m";
214 memcpy(heapArgv + (heapArgc - argc), argv, argc * sizeof(*argv));
215 argv = heapArgv;
216 argc = heapArgc;
217 for (int i = 0; i < argc; i++) {
Brian Carlstrome10b6972011-09-26 13:49:03 -0700218 LOG(INFO) << StringPrintf("argv[%d]=%s", i, argv[i]);
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700219 }
220
Brian Carlstrom395520e2011-09-25 19:35:00 -0700221 // TODO: change the system default to not perform preloading
Brian Carlstrome10b6972011-09-26 13:49:03 -0700222 LOG(INFO) << "Disabling preloading";
Brian Carlstrom395520e2011-09-25 19:35:00 -0700223 for (int i = 0; i < argc; i++) {
224 if (strcmp(argv[i], "preload") == 0) {
225 argv[i] = "nopreload";
226 break;
227 }
228 }
229 for (int i = 0; i < argc; i++) {
Brian Carlstrome10b6972011-09-26 13:49:03 -0700230 LOG(INFO) << StringPrintf("argv[%d]=%s", i, argv[i]);
Brian Carlstrom395520e2011-09-25 19:35:00 -0700231 }
232
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700233 // Everything up to '--' or first non '-' arg goes to the vm
234
235 int i = runtime.addVmArguments(argc, argv);
236
237 // Parse runtime arguments. Stop at first unrecognized option.
238 bool zygote = false;
239 bool startSystemServer = false;
240 bool application = false;
241 const char* parentDir = NULL;
242 const char* niceName = NULL;
243 const char* className = NULL;
244 while (i < argc) {
245 const char* arg = argv[i++];
246 if (!parentDir) {
247 parentDir = arg;
248 } else if (strcmp(arg, "--zygote") == 0) {
249 zygote = true;
250 niceName = "zygote";
251 } else if (strcmp(arg, "--start-system-server") == 0) {
252 startSystemServer = true;
253 } else if (strcmp(arg, "--application") == 0) {
254 application = true;
255 } else if (strncmp(arg, "--nice-name=", 12) == 0) {
256 niceName = arg + 12;
257 } else {
258 className = arg;
259 break;
260 }
261 }
262
263 if (niceName && *niceName) {
264 setArgv0(argv0, niceName);
265 set_process_name(niceName);
266 }
267
268 runtime.mParentDir = parentDir;
269
270 if (zygote) {
271 runtime.start("com.android.internal.os.ZygoteInit",
272 startSystemServer ? "start-system-server" : "");
273 } else if (className) {
274 // Remainder of args get passed to startup class main()
275 runtime.mClassName = className;
276 runtime.mArgC = argc - i;
277 runtime.mArgV = argv + i;
278 runtime.start("com.android.internal.os.RuntimeInit",
279 application ? "application" : "tool");
280 } else {
281 fprintf(stderr, "Error: no class name or --zygote supplied.\n");
282 app_usage();
Brian Carlstrome10b6972011-09-26 13:49:03 -0700283 LOG(FATAL) << "oat_process: no class name or --zygote supplied.";
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700284 return 10;
285 }
286}