blob: e769907585e5412df8c413906bb278dc0494bd37 [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;");
Brian Carlstrom2ae4f902011-09-26 16:48:59 -0700102 jclass BaseDexClassLoader = env->FindClass("dalvik/system/BaseDexClassLoader");
103 jfieldID originalPath = env->GetFieldID(BaseDexClassLoader, "originalPath", "Ljava/lang/String;");
104 jfieldID pathList = env->GetFieldID(BaseDexClassLoader, "pathList", "Ldalvik/system/DexPathList;");
105 jclass DexPathList = env->FindClass("dalvik/system/DexPathList");
106 jmethodID init = env->GetMethodID(DexPathList,
107 "<init>",
108 "(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V");
Brian Carlstrome10b6972011-09-26 13:49:03 -0700109
Brian Carlstrom2ae4f902011-09-26 16:48:59 -0700110 // Set the parent of our pre-existing ClassLoader to the non-null BootClassLoader.getInstance()
Brian Carlstrome10b6972011-09-26 13:49:03 -0700111 const art::ClassLoader* class_loader_object = art::Thread::Current()->GetClassLoaderOverride();
112 jobject class_loader = art::AddLocalReference<jobject>(env, class_loader_object);
Brian Carlstrom2ae4f902011-09-26 16:48:59 -0700113 jobject boot_class_loader = env->CallStaticObjectMethod(BootClassLoader, getInstance);
Brian Carlstrome10b6972011-09-26 13:49:03 -0700114 env->SetObjectField(class_loader, parent, boot_class_loader);
Brian Carlstrom2ae4f902011-09-26 16:48:59 -0700115
116 // Create a DexPathList
117 jstring dex_path = env->NewStringUTF("/system/app/Calculator.apk");
118 jstring library_path = env->NewStringUTF("/data/data/com.android.calculator2/lib");
119 jobject dex_path_list = env->NewObject(DexPathList, init,
120 boot_class_loader, dex_path, library_path, NULL);
121
122 // Set DexPathList into our pre-existing ClassLoader
123 env->SetObjectField(class_loader, pathList, dex_path_list);
124 env->SetObjectField(class_loader, originalPath, dex_path);
125
126 // Stash our pre-existing ClassLoader into ApplicationLoaders.getDefault().mLoaders
127 // under the expected name.
128 jobject application_loaders = env->CallStaticObjectMethod(ApplicationLoaders, getDefault);
129 jobject loaders = env->GetObjectField(application_loaders, mLoaders);
130 env->CallObjectMethod(loaders, put, dex_path, class_loader);
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700131 }
132
133 virtual void onStarted()
134 {
135 sp<ProcessState> proc = ProcessState::self();
136 LOGV("App process: starting thread pool.\n");
137 proc->startThreadPool();
138
139 AndroidRuntime* ar = AndroidRuntime::getRuntime();
140 ar->callMain(mClassName, mClass, mArgC, mArgV);
141
142 IPCThreadState::self()->stopProcess();
143 }
144
145 virtual void onZygoteInit()
146 {
147 sp<ProcessState> proc = ProcessState::self();
148 LOGV("App process: starting thread pool.\n");
149 proc->startThreadPool();
150 }
151
152 virtual void onExit(int code)
153 {
154 if (mClassName == NULL) {
155 // if zygote
156 IPCThreadState::self()->stopProcess();
157 }
158
159 AndroidRuntime::onExit(code);
160 }
161
162
163 const char* mParentDir;
164 const char* mClassName;
165 jclass mClass;
166 int mArgC;
167 const char* const* mArgV;
168};
169
170}
171
172using namespace android;
173
174/*
175 * sets argv0 to as much of newArgv0 as will fit
176 */
177static void setArgv0(const char *argv0, const char *newArgv0)
178{
179 strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
180}
181
Brian Carlstrom395520e2011-09-25 19:35:00 -0700182int main(int argc, const char* argv[])
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700183{
184 // These are global variables in ProcessState.cpp
185 mArgC = argc;
186 mArgV = argv;
187
188 mArgLen = 0;
189 for (int i=0; i<argc; i++) {
190 mArgLen += strlen(argv[i]) + 1;
191 }
192 mArgLen--;
193
194 AppRuntime runtime;
195 const char* argv0 = argv[0];
196
197 // Process command line arguments
198 // ignore argv[0]
199 argc--;
200 argv++;
201
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700202 // ignore /system/bin/app_process when invoked via WrapperInit
203 if (strcmp(argv[0], "/system/bin/app_process") == 0) {
Brian Carlstrome10b6972011-09-26 13:49:03 -0700204 LOG(INFO) << "Removing /system/bin/app_process argument";
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700205 argc--;
206 argv++;
207 for (int i = 0; i < argc; i++) {
Brian Carlstrome10b6972011-09-26 13:49:03 -0700208 LOG(INFO) << StringPrintf("argv[%d]=%s", i, argv[i]);
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700209 }
210 }
211
212 // TODO: remove Calculator special case
213 int oatArgc = argc + 2;
214 const char* oatArgv[oatArgc];
Brian Carlstrom4377a7e2011-10-04 13:19:49 -0700215 if (strcmp(argv[0], "-Ximage:/system/framework/boot.art") != 0) {
Brian Carlstrome10b6972011-09-26 13:49:03 -0700216 LOG(INFO) << "Adding oat arguments";
Brian Carlstrom4377a7e2011-10-04 13:19:49 -0700217 oatArgv[0] = "-Ximage:/system/framework/boot.art";
218 oatArgv[1] = "-Ximage:/system/app/Calculator.art";
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700219 setenv("CLASSPATH", "/system/app/Calculator.apk", 1);
220 memcpy(oatArgv + (oatArgc - argc), argv, argc * sizeof(*argv));
221 argv = oatArgv;
222 argc = oatArgc;
223 for (int i = 0; i < argc; i++) {
Brian Carlstrome10b6972011-09-26 13:49:03 -0700224 LOG(INFO) << StringPrintf("argv[%d]=%s", i, argv[i]);
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700225 }
226 }
227
228 // TODO: remove the heap arguments when implicit garbage collection enabled
Brian Carlstrome10b6972011-09-26 13:49:03 -0700229 LOG(INFO) << "Adding heap arguments";
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700230 int heapArgc = argc + 2;
231 const char* heapArgv[heapArgc];
232 heapArgv[0] = "-Xms64m";
233 heapArgv[1] = "-Xmx64m";
234 memcpy(heapArgv + (heapArgc - argc), argv, argc * sizeof(*argv));
235 argv = heapArgv;
236 argc = heapArgc;
237 for (int i = 0; i < argc; i++) {
Brian Carlstrome10b6972011-09-26 13:49:03 -0700238 LOG(INFO) << StringPrintf("argv[%d]=%s", i, argv[i]);
Brian Carlstrombc2f3e32011-09-22 17:16:54 -0700239 }
240
Brian Carlstrom395520e2011-09-25 19:35:00 -0700241 // TODO: change the system default to not perform preloading
Brian Carlstrome10b6972011-09-26 13:49:03 -0700242 LOG(INFO) << "Disabling preloading";
Brian Carlstrom395520e2011-09-25 19:35:00 -0700243 for (int i = 0; i < argc; i++) {
244 if (strcmp(argv[i], "preload") == 0) {
245 argv[i] = "nopreload";
246 break;
247 }
248 }
249 for (int i = 0; i < argc; i++) {
Brian Carlstrome10b6972011-09-26 13:49:03 -0700250 LOG(INFO) << StringPrintf("argv[%d]=%s", i, argv[i]);
Brian Carlstrom395520e2011-09-25 19:35:00 -0700251 }
252
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700253 // Everything up to '--' or first non '-' arg goes to the vm
254
255 int i = runtime.addVmArguments(argc, argv);
256
257 // Parse runtime arguments. Stop at first unrecognized option.
258 bool zygote = false;
259 bool startSystemServer = false;
260 bool application = false;
261 const char* parentDir = NULL;
262 const char* niceName = NULL;
263 const char* className = NULL;
264 while (i < argc) {
265 const char* arg = argv[i++];
266 if (!parentDir) {
267 parentDir = arg;
268 } else if (strcmp(arg, "--zygote") == 0) {
269 zygote = true;
270 niceName = "zygote";
271 } else if (strcmp(arg, "--start-system-server") == 0) {
272 startSystemServer = true;
273 } else if (strcmp(arg, "--application") == 0) {
274 application = true;
275 } else if (strncmp(arg, "--nice-name=", 12) == 0) {
276 niceName = arg + 12;
277 } else {
278 className = arg;
279 break;
280 }
281 }
282
283 if (niceName && *niceName) {
284 setArgv0(argv0, niceName);
285 set_process_name(niceName);
286 }
287
288 runtime.mParentDir = parentDir;
289
290 if (zygote) {
291 runtime.start("com.android.internal.os.ZygoteInit",
292 startSystemServer ? "start-system-server" : "");
293 } else if (className) {
294 // Remainder of args get passed to startup class main()
295 runtime.mClassName = className;
296 runtime.mArgC = argc - i;
297 runtime.mArgV = argv + i;
298 runtime.start("com.android.internal.os.RuntimeInit",
299 application ? "application" : "tool");
300 } else {
301 fprintf(stderr, "Error: no class name or --zygote supplied.\n");
302 app_usage();
Brian Carlstrome10b6972011-09-26 13:49:03 -0700303 LOG(FATAL) << "oat_process: no class name or --zygote supplied.";
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700304 return 10;
305 }
306}