Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d195e5ab authored by Elliott Hughes's avatar Elliott Hughes
Browse files

Replace a custom AndroidRuntime::findClass with a more targeted fix.

This seems simpler and more contained, and I think the comment explaining
why hoop-jumping is necessary is a bit clearer now.

Change-Id: Ief4afd7cbb42188ed835fce23e497520bdb753a8
parent 966f9e55
Loading
Loading
Loading
Loading
+41 −20
Original line number Original line Diff line number Diff line
@@ -25,23 +25,13 @@ void app_usage()
        "Usage: app_process [java-options] cmd-dir start-class-name [options]\n");
        "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
class AppRuntime : public AndroidRuntime
{
{
public:
public:
    AppRuntime()
    AppRuntime()
        : mParentDir(NULL)
        : mParentDir(NULL)
        , mClassName(NULL)
        , mClassName(NULL)
        , mClass(NULL)
        , mArgC(0)
        , mArgC(0)
        , mArgV(NULL)
        , mArgV(NULL)
    {
    {
@@ -60,6 +50,35 @@ public:
        return mClassName;
        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()
    virtual void onStarted()
    {
    {
        sp<ProcessState> proc = ProcessState::self();
        sp<ProcessState> proc = ProcessState::self();
@@ -68,7 +87,8 @@ public:
            proc->startThreadPool();
            proc->startThreadPool();
        }
        }


        app_init(mClassName, mArgC, mArgV);
        AndroidRuntime* ar = AndroidRuntime::getRuntime();
        ar->callMain(mClassName, mClass, mArgC, mArgV);


        if (ProcessState::self()->supportsProcesses()) {
        if (ProcessState::self()->supportsProcesses()) {
            IPCThreadState::self()->stopProcess();
            IPCThreadState::self()->stopProcess();
@@ -99,6 +119,7 @@ public:


    const char* mParentDir;
    const char* mParentDir;
    const char* mClassName;
    const char* mClassName;
    jclass mClass;
    int mArgC;
    int mArgC;
    const char* const* mArgV;
    const char* const* mArgV;
};
};
+19 −20
Original line number Original line Diff line number Diff line
@@ -68,7 +68,6 @@ extern Condition gEventQCondition;


namespace android {
namespace android {


extern status_t app_init(const char* className);
extern void set_finish_init_func(void (*func)());
extern void set_finish_init_func(void (*func)());




+19 −9
Original line number Original line Diff line number Diff line
@@ -97,11 +97,22 @@ extern "C" status_t system_init()
    // the beginning of their processes's main(), before calling
    // the beginning of their processes's main(), before calling
    // the init function.
    // the init function.
    LOGI("System server: starting Android runtime.\n");
    LOGI("System server: starting Android runtime.\n");
    
    AndroidRuntime* runtime = AndroidRuntime::getRuntime();
    AndroidRuntime* runtime = AndroidRuntime::getRuntime();


    LOGI("System server: starting Android services.\n");
    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
    // If running in our own process, just go into the thread
    // pool.  Otherwise, call the initialization finished
    // pool.  Otherwise, call the initialization finished
@@ -114,4 +125,3 @@ extern "C" status_t system_init()
    }
    }
    return NO_ERROR;
    return NO_ERROR;
}
}
+54 −148
Original line number Original line Diff line number Diff line
/* //device/libs/android_runtime/AndroidRuntime.cpp
/*
**
 * Copyright (C) 2006 The Android Open Source Project
** Copyright 2006, The Android Open Source Project
 *
**
 * Licensed under the Apache License, Version 2.0 (the "License");
** Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License.
** you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at
** You may obtain a copy of the License at 
 *
**
 *      http://www.apache.org/licenses/LICENSE-2.0
**     http://www.apache.org/licenses/LICENSE-2.0 
 *
**
 * Unless required by applicable law or agreed to in writing, software
** Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS,
** distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and
** See the License for the specific language governing permissions and 
 * limitations under the License.
** limitations under the License.
 */
 */


#define LOG_TAG "AndroidRuntime"
#define LOG_TAG "AndroidRuntime"
@@ -278,51 +277,16 @@ AndroidRuntime::~AndroidRuntime()
    return jniRegisterNativeMethods(env, className, gMethods, numMethods);
    return jniRegisterNativeMethods(env, className, gMethods, numMethods);
}
}


/*
status_t AndroidRuntime::callMain(const char* className,
 * Call a static Java Programming Language function that takes no arguments and returns void.
    jclass clazz, int argc, const char* const argv[])
 */
status_t AndroidRuntime::callStatic(const char* className, const char* methodName)
{
{
    JNIEnv* env;
    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;
    jmethodID methodId;


    LOGD("Calling main entry %s", className);
    LOGD("Calling main entry %s", className);


    env = getJNIEnv();
    env = getJNIEnv();
    if (env == NULL)
    if (clazz == NULL || env == NULL) {
        return UNKNOWN_ERROR;

    clazz = findClass(env, className);
    if (clazz == NULL) {
        LOGE("ERROR: could not find class '%s'\n", className);
        return UNKNOWN_ERROR;
        return UNKNOWN_ERROR;
    }
    }


@@ -351,70 +315,6 @@ status_t AndroidRuntime::callMain(
    return NO_ERROR;
    return NO_ERROR;
}
}


/*
 * 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.
 * The VM calls this through the "exit" hook.
 */
 */
@@ -890,6 +790,17 @@ bail:
    return result;
    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
 * Start the Android runtime.  This involves starting the virtual machine
 * and calling the "static void main(String[] args)" method in the class
 * and calling the "static void main(String[] args)" method in the class
@@ -900,10 +811,6 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
    LOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
    LOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
            className != NULL ? className : "(unknown)");
            className != NULL ? className : "(unknown)");


    char* slashClassName = NULL;
    char* cp;
    JNIEnv* env;

    blockSigpipe();
    blockSigpipe();


    /*
    /*
@@ -922,7 +829,7 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
        rootDir = "/system";
        rootDir = "/system";
        if (!hasDir("/system")) {
        if (!hasDir("/system")) {
            LOG_FATAL("No root directory specified, and /android does not exist.");
            LOG_FATAL("No root directory specified, and /android does not exist.");
            goto bail;
            return;
        }
        }
        setenv("ANDROID_ROOT", rootDir, 1);
        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);
    //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);


    /* start the virtual machine */
    /* start the virtual machine */
    if (startVm(&mJavaVM, &env) != 0)
    JNIEnv* env;
        goto bail;
    if (startVm(&mJavaVM, &env) != 0) {
        return;
    }
    onVmCreated(env);


    /*
    /*
     * Register android functions.
     * Register android functions.
     */
     */
    if (startReg(env) < 0) {
    if (startReg(env) < 0) {
        LOGE("Unable to register all android natives\n");
        LOGE("Unable to register all android natives\n");
        goto bail;
        return;
    }
    }


    /*
    /*
@@ -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
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     * not return until the VM exits.
     */
     */
    jclass startClass;
    char* slashClassName = toSlashClassName(className);
    jmethodID startMeth;
    jclass startClass = env->FindClass(slashClassName);

    slashClassName = strdup(className);
    for (cp = slashClassName; *cp != '\0'; cp++)
        if (*cp == '.')
            *cp = '/';

    startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
    if (startClass == NULL) {
        LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
        /* keep going */
    } else {
    } else {
        startMeth = env->GetStaticMethodID(startClass, "main",
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
        if (startMeth == NULL) {
            LOGE("JavaVM unable to find main() in '%s'\n", className);
            LOGE("JavaVM unable to find main() in '%s'\n", className);
@@ -994,15 +897,13 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
#endif
#endif
        }
        }
    }
    }
    free(slashClassName);


    LOGD("Shutting down VM\n");
    LOGD("Shutting down VM\n");
    if (mJavaVM->DetachCurrentThread() != JNI_OK)
    if (mJavaVM->DetachCurrentThread() != JNI_OK)
        LOGW("Warning: unable to detach main thread\n");
        LOGW("Warning: unable to detach main thread\n");
    if (mJavaVM->DestroyJavaVM() != 0)
    if (mJavaVM->DestroyJavaVM() != 0)
        LOGW("Warning: VM did not shut down cleanly\n");
        LOGW("Warning: VM did not shut down cleanly\n");

bail:
    free(slashClassName);
}
}


void AndroidRuntime::start()
void AndroidRuntime::start()
@@ -1017,6 +918,11 @@ void AndroidRuntime::onExit(int code)
    exit(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.
 * Get the JNIEnv pointer for this thread.
 *
 *
+0 −11
Original line number Original line Diff line number Diff line
@@ -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)
jint android_os_Process_myPid(JNIEnv* env, jobject clazz)
{
{
    return getpid();
    return getpid();
Loading