/* * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #include <string.h> #include <stdlib.h> #include "jni.h" #include "jni_util.h" #include "jvm.h" #include "io_util.h" #include "openssl/opensslv.h" #include "zlib.h" #include "JNIHelp.h" #include "cutils/log.h" #if defined(__ANDROID__) void android_get_LD_LIBRARY_PATH(char*, size_t); #endif #define NATIVE_METHOD(className, functionName, signature) \ { #functionName, signature, (void*)(className ## _ ## functionName) } #define PUTPROP(props, key, val) \ if (1) { \ jstring jkey = (*env)->NewStringUTF(env, key); \ jstring jval = (*env)->NewStringUTF(env, val); \ jobject r = (*env)->CallObjectMethod(env, props, putID, jkey, jval); \ if ((*env)->ExceptionOccurred(env)) return NULL; \ (*env)->DeleteLocalRef(env, jkey); \ (*env)->DeleteLocalRef(env, jval); \ (*env)->DeleteLocalRef(env, r); \ } else ((void) 0) /* "key" is a char type string with only ASCII character in it. "val" is a nchar (typedefed in java_props.h) type string */ #define PUTPROP_ForPlatformNString(props, key, val) \ if (1) { \ jstring jkey = (*env)->NewStringUTF(env, key); \ jstring jval = GetStringPlatform(env, val); \ jobject r = (*env)->CallObjectMethod(env, props, putID, jkey, jval); \ if ((*env)->ExceptionOccurred(env)) return NULL; \ (*env)->DeleteLocalRef(env, jkey); \ (*env)->DeleteLocalRef(env, jval); \ (*env)->DeleteLocalRef(env, r); \ } else ((void) 0) #define REMOVEPROP(props, key) \ if (1) { \ jstring jkey = JNU_NewStringPlatform(env, key); \ jobject r = (*env)->CallObjectMethod(env, props, removeID, jkey); \ if ((*env)->ExceptionOccurred(env)) return NULL; \ (*env)->DeleteLocalRef(env, jkey); \ (*env)->DeleteLocalRef(env, r); \ } else ((void) 0) #define GETPROP(props, key, jret) \ if (1) { \ jstring jkey = JNU_NewStringPlatform(env, key); \ jret = (*env)->CallObjectMethod(env, props, getPropID, jkey); \ if ((*env)->ExceptionOccurred(env)) return NULL; \ (*env)->DeleteLocalRef(env, jkey); \ } else ((void) 0) #ifndef VENDOR /* Third party may overwrite this. */ #define VENDOR "Oracle Corporation" #define VENDOR_URL "http://java.oracle.com/" #define VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/" #endif #define JAVA_MAX_SUPPORTED_VERSION 51 #define JAVA_MAX_SUPPORTED_MINOR_VERSION 0 #ifdef JAVA_SPECIFICATION_VENDOR /* Third party may NOT overwrite this. */ #error "ERROR: No override of JAVA_SPECIFICATION_VENDOR is allowed" #else #define JAVA_SPECIFICATION_VENDOR "Oracle Corporation" #endif /* * The following three functions implement setter methods for * java.lang.System.{in, out, err}. They are natively implemented * because they violate the semantics of the language (i.e. set final * variable). */ JNIEXPORT void JNICALL System_setIn0(JNIEnv *env, jclass cla, jobject stream) { jfieldID fid = (*env)->GetStaticFieldID(env,cla,"in","Ljava/io/InputStream;"); if (fid == 0) return; (*env)->SetStaticObjectField(env,cla,fid,stream); } JNIEXPORT void JNICALL System_setOut0(JNIEnv *env, jclass cla, jobject stream) { jfieldID fid = (*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;"); if (fid == 0) return; (*env)->SetStaticObjectField(env,cla,fid,stream); } JNIEXPORT void JNICALL System_setErr0(JNIEnv *env, jclass cla, jobject stream) { jfieldID fid = (*env)->GetStaticFieldID(env,cla,"err","Ljava/io/PrintStream;"); if (fid == 0) return; (*env)->SetStaticObjectField(env,cla,fid,stream); } static void cpchars(jchar *dst, char *src, int n) { int i; for (i = 0; i < n; i++) { dst[i] = src[i]; } } JNIEXPORT jstring JNICALL System_mapLibraryName(JNIEnv *env, jclass ign, jstring libname) { int len; int prefix_len = (int) strlen(JNI_LIB_PREFIX); int suffix_len = (int) strlen(JNI_LIB_SUFFIX); jchar chars[256]; if (libname == NULL) { JNU_ThrowNullPointerException(env, 0); return NULL; } len = (*env)->GetStringLength(env, libname); if (len > 240) { JNU_ThrowIllegalArgumentException(env, "name too long"); return NULL; } cpchars(chars, JNI_LIB_PREFIX, prefix_len); (*env)->GetStringRegion(env, libname, 0, len, chars + prefix_len); len += prefix_len; cpchars(chars + len, JNI_LIB_SUFFIX, suffix_len); len += suffix_len; return (*env)->NewString(env, chars, len); } static jobjectArray System_specialProperties(JNIEnv* env, jclass ignored) { jclass stringClass = (*env)->FindClass(env, "java/lang/String"); jobjectArray result = (*env)->NewObjectArray(env, 4, stringClass, NULL); char path[PATH_MAX]; char* process_path = getcwd(path, sizeof(path)); char user_dir[PATH_MAX + 10] = "user.dir="; strncat(user_dir, process_path, PATH_MAX); jstring user_dir_str = (*env)->NewStringUTF(env, user_dir); if ((*env)->ExceptionCheck(env)) { return NULL; } (*env)->SetObjectArrayElement(env, result, 0, user_dir_str); if ((*env)->ExceptionCheck(env)) { return NULL; } jstring zlib_str = (*env)->NewStringUTF(env, "android.zlib.version=" ZLIB_VERSION); if ((*env)->ExceptionCheck(env)) { return NULL; } (*env)->SetObjectArrayElement(env, result, 1, zlib_str); if ((*env)->ExceptionCheck(env)) { return NULL; } jstring ssl_str = (*env)->NewStringUTF(env, "android.openssl.version=" OPENSSL_VERSION_TEXT); if ((*env)->ExceptionCheck(env)) { return NULL; } (*env)->SetObjectArrayElement(env, result, 2, ssl_str); if ((*env)->ExceptionCheck(env)) { return NULL; } const char* library_path = getenv("LD_LIBRARY_PATH"); #if defined(__ANDROID__) if (library_path == NULL) { android_get_LD_LIBRARY_PATH(path, sizeof(path)); library_path = path; } #endif if (library_path == NULL) { library_path = ""; } char* java_path = malloc(strlen("java.library.path=") + strlen(library_path) + 1); strcpy(java_path, "java.library.path="); strcat(java_path, library_path); jstring java_path_str = (*env)->NewStringUTF(env, java_path); free((void*)java_path); if ((*env)->ExceptionCheck(env)) { return NULL; } (*env)->SetObjectArrayElement(env, result, 3, java_path_str); if ((*env)->ExceptionCheck(env)) { return NULL; } return result; } static void System_log(JNIEnv* env, jclass ignored, jchar type, jstring javaMessage, jthrowable exception) { int priority; switch (type) { case 'D': case 'd': priority = ANDROID_LOG_DEBUG; break; case 'E': case 'e': priority = ANDROID_LOG_ERROR; break; case 'F': case 'f': priority = ANDROID_LOG_FATAL; break; case 'I': case 'i': priority = ANDROID_LOG_INFO; break; case 'S': case 's': priority = ANDROID_LOG_SILENT; break; case 'V': case 'v': priority = ANDROID_LOG_VERBOSE; break; case 'W': case 'w': priority = ANDROID_LOG_WARN; break; default: priority = ANDROID_LOG_DEFAULT; break; } WITH_PLATFORM_STRING(env, javaMessage, message) { if (message == NULL) { // Since this function is used for last-gasp debugging output, be noisy on failure. return; } LOG_PRI(priority, "System", "%s", message); } END_PLATFORM_STRING(env, message); if (exception != NULL) { jniLogException(env, priority, "System", exception); } } static jlong System_nanoTime(JNIEnv* env, jclass unused) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); return now.tv_sec * 1000000000LL + now.tv_nsec; } static jlong System_currentTimeMillis(JNIEnv* env, jclass unused) { return JVM_CurrentTimeMillis(NULL, NULL); } static JNINativeMethod gMethods[] = { NATIVE_METHOD(System, mapLibraryName, "(Ljava/lang/String;)Ljava/lang/String;"), NATIVE_METHOD(System, setErr0, "(Ljava/io/PrintStream;)V"), NATIVE_METHOD(System, setOut0, "(Ljava/io/PrintStream;)V"), NATIVE_METHOD(System, setIn0, "(Ljava/io/InputStream;)V"), NATIVE_METHOD(System, specialProperties, "()[Ljava/lang/String;"), NATIVE_METHOD(System, log, "(CLjava/lang/String;Ljava/lang/Throwable;)V"), NATIVE_METHOD(System, currentTimeMillis, "()J"), NATIVE_METHOD(System, nanoTime, "()J"), }; void register_java_lang_System(JNIEnv* env) { jniRegisterNativeMethods(env, "java/lang/System", gMethods, NELEM(gMethods)); }