diff options
-rw-r--r-- | cmds/app_process/app_main.cpp | 61 | ||||
-rw-r--r-- | cmds/runtime/main_runtime.cpp | 39 | ||||
-rw-r--r-- | cmds/system_server/library/system_init.cpp | 28 | ||||
-rw-r--r-- | core/jni/AndroidRuntime.cpp | 202 | ||||
-rw-r--r-- | core/jni/android_util_Process.cpp | 11 | ||||
-rw-r--r-- | include/android_runtime/AndroidRuntime.h | 18 |
6 files changed, 145 insertions, 214 deletions
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp index 0159edd..371268f 100644 --- a/cmds/app_process/app_main.cpp +++ b/cmds/app_process/app_main.cpp @@ -1,8 +1,8 @@ /* * Main entry of app process. - * + * * Starts the interpreted runtime, then starts up the application. - * + * */ #define LOG_TAG "appproc" @@ -25,23 +25,13 @@ void app_usage() "Usage: app_process [java-options] cmd-dir start-class-name [options]\n"); } -status_t app_init(const char* className, int argc, const char* const argv[]) -{ - LOGV("Entered app_init()!\n"); - - AndroidRuntime* jr = AndroidRuntime::getRuntime(); - jr->callMain(className, argc, argv); - - LOGV("Exiting app_init()!\n"); - return NO_ERROR; -} - class AppRuntime : public AndroidRuntime { public: AppRuntime() : mParentDir(NULL) , mClassName(NULL) + , mClass(NULL) , mArgC(0) , mArgV(NULL) { @@ -60,6 +50,35 @@ public: return mClassName; } + virtual void onVmCreated(JNIEnv* env) + { + if (mClassName == NULL) { + return; // Zygote. Nothing to do here. + } + + /* + * This is a little awkward because the JNI FindClass call uses the + * class loader associated with the native method we're executing in. + * If called in onStarted (from RuntimeInit.finishInit because we're + * launching "am", for example), FindClass would see that we're calling + * from a boot class' native method, and so wouldn't look for the class + * we're trying to look up in CLASSPATH. Unfortunately it needs to, + * because the "am" classes are not boot classes. + * + * The easiest fix is to call FindClass here, early on before we start + * executing boot class Java code and thereby deny ourselves access to + * non-boot classes. + */ + char* slashClassName = toSlashClassName(mClassName); + mClass = env->FindClass(slashClassName); + if (mClass == NULL) { + LOGE("ERROR: could not find class '%s'\n", mClassName); + } + free(slashClassName); + + mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass)); + } + virtual void onStarted() { sp<ProcessState> proc = ProcessState::self(); @@ -67,8 +86,9 @@ public: LOGV("App process: starting thread pool.\n"); proc->startThreadPool(); } - - app_init(mClassName, mArgC, mArgV); + + AndroidRuntime* ar = AndroidRuntime::getRuntime(); + ar->callMain(mClassName, mClass, mArgC, mArgV); if (ProcessState::self()->supportsProcesses()) { IPCThreadState::self()->stopProcess(); @@ -81,7 +101,7 @@ public: if (proc->supportsProcesses()) { LOGV("App process: starting thread pool.\n"); proc->startThreadPool(); - } + } } virtual void onExit(int code) @@ -96,9 +116,10 @@ public: AndroidRuntime::onExit(code); } - + const char* mParentDir; const char* mClassName; + jclass mClass; int mArgC; const char* const* mArgV; }; @@ -120,7 +141,7 @@ int main(int argc, const char* const argv[]) // These are global variables in ProcessState.cpp mArgC = argc; mArgV = argv; - + mArgLen = 0; for (int i=0; i<argc; i++) { mArgLen += strlen(argv[i]) + 1; @@ -139,7 +160,7 @@ int main(int argc, const char* const argv[]) argv++; // Everything up to '--' or first non '-' arg goes to the vm - + int i = runtime.addVmArguments(argc, argv); // Next arg is parent directory @@ -151,7 +172,7 @@ int main(int argc, const char* const argv[]) if (i < argc) { arg = argv[i++]; if (0 == strcmp("--zygote", arg)) { - bool startSystemServer = (i < argc) ? + bool startSystemServer = (i < argc) ? strcmp(argv[i], "--start-system-server") == 0 : false; setArgv0(argv0, "zygote"); set_process_name("zygote"); diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp index 83cb533..785e4cc 100644 --- a/cmds/runtime/main_runtime.cpp +++ b/cmds/runtime/main_runtime.cpp @@ -12,7 +12,7 @@ #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> -#include <utils/Log.h> +#include <utils/Log.h> #include <cutils/zygote.h> #include <cutils/properties.h> @@ -41,7 +41,7 @@ #undef LOG_TAG #define LOG_TAG "runtime" -static const char* ZYGOTE_ARGV[] = { +static const char* ZYGOTE_ARGV[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003", @@ -68,7 +68,6 @@ extern Condition gEventQCondition; namespace android { -extern status_t app_init(const char* className); extern void set_finish_init_func(void (*func)()); @@ -76,7 +75,7 @@ extern void set_finish_init_func(void (*func)()); * This class is used to kill this process (runtime) when the system_server dies. */ class GrimReaper : public IBinder::DeathRecipient { -public: +public: GrimReaper() { } virtual void binderDied(const wp<IBinder>& who) @@ -170,7 +169,7 @@ LOGI("run() sending FIRST_CALL_TRANSACTION to activity manager"); /* * Post-system-process initialization. - * + * * This function continues initialization after the system process * has been initialized. It needs to be separate because the system * initialization needs to care of starting the Android runtime if it is not @@ -210,17 +209,17 @@ static bool contextChecker( static void boot_init() { LOGI("Entered boot_init()!\n"); - + sp<ProcessState> proc(ProcessState::self()); LOGD("ProcessState: %p\n", proc.get()); proc->becomeContextManager(contextChecker, NULL); - + if (proc->supportsProcesses()) { LOGI("Binder driver opened. Multiprocess enabled.\n"); } else { LOGI("Binder driver not found. Processes not supported.\n"); } - + sp<BServiceManager> sm = new BServiceManager; proc->setContextObject(sm); } @@ -258,7 +257,7 @@ static void validateTime() int res; time_t min_time = 1167652800; // jan 1 2007, type 'date -ud "1/1 12:00" +%s' to get value for current year struct timespec ts; - + fd = open("/dev/alarm", O_RDWR); if(fd < 0) { LOGW("Unable to open alarm driver: %s\n", strerror(errno)); @@ -346,14 +345,14 @@ int main(int argc, char* const argv[]) int ic; int result = 1; pid_t systemPid; - + sp<ProcessState> proc; #ifndef HAVE_ANDROID_OS /* Set stdout/stderr to unbuffered for MinGW/MSYS. */ //setvbuf(stdout, NULL, _IONBF, 0); //setvbuf(stderr, NULL, _IONBF, 0); - + LOGI("commandline args:\n"); for (int i = 0; i < argc; i++) LOGI(" %2d: '%s'\n", i, argv[i]); @@ -455,7 +454,7 @@ int main(int argc, char* const argv[]) #if 0 // Hack to keep libc from beating the filesystem to death. It's - // hitting /etc/localtime frequently, + // hitting /etc/localtime frequently, // // This statement locks us into Pacific time. We could do better, // but there's not much point until we're sure that the library @@ -467,15 +466,15 @@ int main(int argc, char* const argv[]) /* track our progress through the boot sequence */ const int LOG_BOOT_PROGRESS_START = 3000; - LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, + LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); validateTime(); proc = ProcessState::self(); - + boot_init(); - + /* If we are in multiprocess mode, have zygote spawn the system * server process and call system_init(). If we are running in * single process mode just call system_init() directly. @@ -488,8 +487,8 @@ int main(int argc, char* const argv[]) property_get("log.redirect-stdio", propBuf, ""); logStdio = (strcmp(propBuf, "true") == 0); - zygote_run_oneshot((int)(!logStdio), - sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]), + zygote_run_oneshot((int)(!logStdio), + sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]), ZYGOTE_ARGV); //start_process("/system/bin/mediaserver"); @@ -497,7 +496,7 @@ int main(int argc, char* const argv[]) } else { #ifndef HAVE_ANDROID_OS QuickRuntime* runt = new QuickRuntime(); - runt->start("com/android/server/SystemServer", + runt->start("com/android/server/SystemServer", false /* spontaneously fork system server from zygote */); #endif } @@ -506,11 +505,11 @@ int main(int argc, char* const argv[]) finish_system_init(proc); run(proc); - + bail: if (proc != NULL) { proc->setContextObject(NULL); } - + return 0; } diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp index a29ba73..b615764 100644 --- a/cmds/system_server/library/system_init.cpp +++ b/cmds/system_server/library/system_init.cpp @@ -37,7 +37,7 @@ namespace android { * This class is used to kill this process when the runtime dies. */ class GrimReaper : public IBinder::DeathRecipient { -public: +public: GrimReaper() { } virtual void binderDied(const wp<IBinder>& who) @@ -54,15 +54,15 @@ public: extern "C" status_t system_init() { LOGI("Entered system_init()"); - + sp<ProcessState> proc(ProcessState::self()); - + sp<IServiceManager> sm = defaultServiceManager(); LOGI("ServiceManager: %p\n", sm.get()); - + sp<GrimReaper> grim = new GrimReaper(); sm->asBinder()->linkToDeath(grim, grim.get(), 0); - + char propBuf[PROPERTY_VALUE_MAX]; property_get("system_init.startsurfaceflinger", propBuf, "1"); if (strcmp(propBuf, "1") == 0) { @@ -97,12 +97,23 @@ extern "C" status_t system_init() // the beginning of their processes's main(), before calling // the init function. LOGI("System server: starting Android runtime.\n"); - AndroidRuntime* runtime = AndroidRuntime::getRuntime(); LOGI("System server: starting Android services.\n"); - runtime->callStatic("com/android/server/SystemServer", "init2"); - + JNIEnv* env = runtime->getJNIEnv(); + if (env == NULL) { + return UNKNOWN_ERROR; + } + jclass clazz = env->FindClass("com/android/server/SystemServer"); + if (clazz == NULL) { + return UNKNOWN_ERROR; + } + jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V"); + if (methodId == NULL) { + return UNKNOWN_ERROR; + } + env->CallStaticVoidMethod(clazz, methodId); + // If running in our own process, just go into the thread // pool. Otherwise, call the initialization finished // func to let this process continue its initilization. @@ -114,4 +125,3 @@ extern "C" status_t system_init() } return NO_ERROR; } - diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index f29d83e..b628b9d 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -1,19 +1,18 @@ -/* //device/libs/android_runtime/AndroidRuntime.cpp -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #define LOG_TAG "AndroidRuntime" //#define LOG_NDEBUG 0 @@ -212,7 +211,7 @@ static jint com_android_internal_os_RuntimeInit_getQwertyKeyboard(JNIEnv* env, j if (value != NULL && strcmp(value, "true") == 0) { return 1; } - + return 0; } @@ -227,7 +226,7 @@ static JNINativeMethod gMethods[] = { { "isComputerOn", "()I", (void*) com_android_internal_os_RuntimeInit_isComputerOn }, { "turnComputerOn", "()V", - (void*) com_android_internal_os_RuntimeInit_turnComputerOn }, + (void*) com_android_internal_os_RuntimeInit_turnComputerOn }, { "getQwertyKeyboard", "()I", (void*) com_android_internal_os_RuntimeInit_getQwertyKeyboard }, }; @@ -278,51 +277,16 @@ AndroidRuntime::~AndroidRuntime() return jniRegisterNativeMethods(env, className, gMethods, numMethods); } -/* - * Call a static Java Programming Language function that takes no arguments and returns void. - */ -status_t AndroidRuntime::callStatic(const char* className, const char* methodName) +status_t AndroidRuntime::callMain(const char* className, + jclass clazz, int argc, const char* const argv[]) { JNIEnv* env; - jclass clazz; - jmethodID methodId; - - env = getJNIEnv(); - if (env == NULL) - return UNKNOWN_ERROR; - - clazz = findClass(env, className); - if (clazz == NULL) { - LOGE("ERROR: could not find class '%s'\n", className); - return UNKNOWN_ERROR; - } - methodId = env->GetStaticMethodID(clazz, methodName, "()V"); - if (methodId == NULL) { - LOGE("ERROR: could not find method %s.%s\n", className, methodName); - return UNKNOWN_ERROR; - } - - env->CallStaticVoidMethod(clazz, methodId); - - return NO_ERROR; -} - -status_t AndroidRuntime::callMain( - const char* className, int argc, const char* const argv[]) -{ - JNIEnv* env; - jclass clazz; jmethodID methodId; LOGD("Calling main entry %s", className); env = getJNIEnv(); - if (env == NULL) - return UNKNOWN_ERROR; - - clazz = findClass(env, className); - if (clazz == NULL) { - LOGE("ERROR: could not find class '%s'\n", className); + if (clazz == NULL || env == NULL) { return UNKNOWN_ERROR; } @@ -352,70 +316,6 @@ status_t AndroidRuntime::callMain( } /* - * Find the named class. - */ -jclass AndroidRuntime::findClass(JNIEnv* env, const char* className) -{ - if (env->ExceptionCheck()) { - LOGE("ERROR: exception pending on entry to findClass()"); - return NULL; - } - - /* - * This is a little awkward because the JNI FindClass call uses the - * class loader associated with the native method we're executing in. - * Because this native method is part of a "boot" class, JNI doesn't - * look for the class in CLASSPATH, which unfortunately is a likely - * location for it. (Had we issued the FindClass call before calling - * into the VM -- at which point there isn't a native method frame on - * the stack -- the VM would have checked CLASSPATH. We have to do - * this because we call into Java Programming Language code and - * bounce back out.) - * - * JNI lacks a "find class in a specific class loader" operation, so we - * have to do things the hard way. - */ - jclass cls = NULL; - - jclass javaLangClassLoader; - jmethodID getSystemClassLoader, loadClass; - jobject systemClassLoader; - jstring strClassName; - - /* find the "system" class loader; none of this is expected to fail */ - javaLangClassLoader = env->FindClass("java/lang/ClassLoader"); - assert(javaLangClassLoader != NULL); - getSystemClassLoader = env->GetStaticMethodID(javaLangClassLoader, - "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); - loadClass = env->GetMethodID(javaLangClassLoader, - "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - assert(getSystemClassLoader != NULL && loadClass != NULL); - systemClassLoader = env->CallStaticObjectMethod(javaLangClassLoader, - getSystemClassLoader); - assert(systemClassLoader != NULL); - - /* create an object for the class name string; alloc could fail */ - strClassName = env->NewStringUTF(className); - if (env->ExceptionCheck()) { - LOGE("ERROR: unable to convert '%s' to string", className); - return NULL; - } - LOGV("system class loader is %p, loading %p (%s)", - systemClassLoader, strClassName, className); - - /* try to find the named class */ - cls = (jclass) env->CallObjectMethod(systemClassLoader, loadClass, - strClassName); - if (env->ExceptionCheck()) { - LOGE("ERROR: unable to load class '%s' from %p", - className, systemClassLoader); - return NULL; - } - - return cls; -} - -/* * The VM calls this through the "exit" hook. */ static void runtime_exit(int code) @@ -457,7 +357,7 @@ static bool runtime_isSensitiveThread() { int AndroidRuntime::addVmArguments(int argc, const char* const argv[]) { int i; - + for (i = 0; i<argc; i++) { if (argv[i][0] != '-') { return i; @@ -890,6 +790,17 @@ bail: return result; } +char* AndroidRuntime::toSlashClassName(const char* className) +{ + char* result = strdup(className); + for (char* cp = result; *cp != '\0'; cp++) { + if (*cp == '.') { + *cp = '/'; + } + } + return result; +} + /* * Start the Android runtime. This involves starting the virtual machine * and calling the "static void main(String[] args)" method in the class @@ -900,20 +811,16 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) LOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n", className != NULL ? className : "(unknown)"); - char* slashClassName = NULL; - char* cp; - JNIEnv* env; - blockSigpipe(); - /* - * 'startSystemServer == true' means runtime is obsolete and not run from + /* + * 'startSystemServer == true' means runtime is obsolete and not run from * init.rc anymore, so we print out the boot start event here. */ if (startSystemServer) { /* track our progress through the boot sequence */ const int LOG_BOOT_PROGRESS_START = 3000; - LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, + LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); } @@ -922,7 +829,7 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) rootDir = "/system"; if (!hasDir("/system")) { LOG_FATAL("No root directory specified, and /android does not exist."); - goto bail; + return; } setenv("ANDROID_ROOT", rootDir, 1); } @@ -931,15 +838,18 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack); /* start the virtual machine */ - if (startVm(&mJavaVM, &env) != 0) - goto bail; + JNIEnv* env; + if (startVm(&mJavaVM, &env) != 0) { + return; + } + onVmCreated(env); /* * Register android functions. */ if (startReg(env) < 0) { LOGE("Unable to register all android natives\n"); - goto bail; + return; } /* @@ -959,7 +869,7 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) classNameStr = env->NewStringUTF(className); assert(classNameStr != NULL); env->SetObjectArrayElement(strArray, 0, classNameStr); - startSystemServerStr = env->NewStringUTF(startSystemServer ? + startSystemServerStr = env->NewStringUTF(startSystemServer ? "true" : "false"); env->SetObjectArrayElement(strArray, 1, startSystemServerStr); @@ -967,20 +877,13 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ - jclass startClass; - jmethodID startMeth; - - slashClassName = strdup(className); - for (cp = slashClassName; *cp != '\0'; cp++) - if (*cp == '.') - *cp = '/'; - - startClass = env->FindClass(slashClassName); + char* slashClassName = toSlashClassName(className); + jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { LOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { - startMeth = env->GetStaticMethodID(startClass, "main", + jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { LOGE("JavaVM unable to find main() in '%s'\n", className); @@ -994,15 +897,13 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer) #endif } } + free(slashClassName); LOGD("Shutting down VM\n"); if (mJavaVM->DetachCurrentThread() != JNI_OK) LOGW("Warning: unable to detach main thread\n"); if (mJavaVM->DestroyJavaVM() != 0) LOGW("Warning: VM did not shut down cleanly\n"); - -bail: - free(slashClassName); } void AndroidRuntime::start() @@ -1017,6 +918,11 @@ void AndroidRuntime::onExit(int code) exit(code); } +void AndroidRuntime::onVmCreated(JNIEnv* env) +{ + // If AndroidRuntime had anything to do here, we'd have done it in 'start'. +} + /* * Get the JNIEnv pointer for this thread. * @@ -1111,7 +1017,7 @@ static int javaDetachThread(void) * into the VM before it really starts executing. */ /*static*/ int AndroidRuntime::javaCreateThreadEtc( - android_thread_func_t entryFunction, + android_thread_func_t entryFunction, void* userData, const char* threadName, int32_t threadPriority, @@ -1299,7 +1205,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_backup_BackupDataOutput), REG_JNI(register_android_backup_FileBackupHelperBase), REG_JNI(register_android_backup_BackupHelperDispatcher), - + REG_JNI(register_android_app_ActivityThread), REG_JNI(register_android_app_NativeActivity), REG_JNI(register_android_view_InputChannel), diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 34f0fdc..e5c2848 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -103,17 +103,6 @@ static void signalExceptionForGroupError(JNIEnv* env, jobject obj, int err) } } - -static void fakeProcessEntry(void* arg) -{ - String8* cls = (String8*)arg; - - AndroidRuntime* jr = AndroidRuntime::getRuntime(); - jr->callMain(cls->string(), 0, NULL); - - delete cls; -} - jint android_os_Process_myPid(JNIEnv* env, jobject clazz) { return getpid(); diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h index de2d50b..b02a057 100644 --- a/include/android_runtime/AndroidRuntime.h +++ b/include/android_runtime/AndroidRuntime.h @@ -46,14 +46,10 @@ public: const char* className, const JNINativeMethod* gMethods, int numMethods); /** - * Call a static Java function that takes no arguments and returns void. - */ - status_t callStatic(const char* className, const char* methodName); - - /** * Call a class's static main method with the given arguments, */ - status_t callMain(const char* className, int argc, const char* const argv[]); + status_t callMain(const char* className, jclass clazz, int argc, + const char* const argv[]); /** * Find a class, with the input either of the form @@ -69,6 +65,13 @@ public: static AndroidRuntime* getRuntime(); /** + * This gets called after the VM has been created, but before we + * run any code. Override it to make any FindClass calls that need + * to use CLASSPATH. + */ + virtual void onVmCreated(JNIEnv* env); + + /** * This gets called after the JavaVM has initialized. Override it * with the system's native entry point. */ @@ -98,6 +101,9 @@ public: /** return a pointer to the JNIEnv pointer for this thread */ static JNIEnv* getJNIEnv(); + /** return a new string corresponding to 'className' with all '.'s replaced by '/'s. */ + static char* toSlashClassName(const char* className); + private: static int startReg(JNIEnv* env); void parseExtraOpts(char* extraOptsBuf); |