/*
* 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));
}