Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 #include <string.h>
     26 #include <stdlib.h>
     27 
     28 #include "jni.h"
     29 #include "jni_util.h"
     30 #include "jvm.h"
     31 #include "io_util.h"
     32 
     33 
     34 #include "openssl/opensslv.h"
     35 #include "zlib.h"
     36 #include "JNIHelp.h"
     37 #include "cutils/log.h"
     38 #if defined(__ANDROID__)
     39 void android_get_LD_LIBRARY_PATH(char*, size_t);
     40 #endif
     41 
     42 #define NATIVE_METHOD(className, functionName, signature) \
     43 { #functionName, signature, (void*)(className ## _ ## functionName) }
     44 
     45 #define PUTPROP(props, key, val) \
     46     if (1) { \
     47         jstring jkey = (*env)->NewStringUTF(env, key); \
     48         jstring jval = (*env)->NewStringUTF(env, val); \
     49         jobject r = (*env)->CallObjectMethod(env, props, putID, jkey, jval); \
     50         if ((*env)->ExceptionOccurred(env)) return NULL; \
     51         (*env)->DeleteLocalRef(env, jkey); \
     52         (*env)->DeleteLocalRef(env, jval); \
     53         (*env)->DeleteLocalRef(env, r); \
     54     } else ((void) 0)
     55 
     56 /*  "key" is a char type string with only ASCII character in it.
     57     "val" is a nchar (typedefed in java_props.h) type string  */
     58 
     59 #define PUTPROP_ForPlatformNString(props, key, val) \
     60     if (1) { \
     61         jstring jkey = (*env)->NewStringUTF(env, key);  \
     62         jstring jval = GetStringPlatform(env, val); \
     63         jobject r = (*env)->CallObjectMethod(env, props, putID, jkey, jval); \
     64         if ((*env)->ExceptionOccurred(env)) return NULL; \
     65         (*env)->DeleteLocalRef(env, jkey); \
     66         (*env)->DeleteLocalRef(env, jval); \
     67         (*env)->DeleteLocalRef(env, r); \
     68     } else ((void) 0)
     69 #define REMOVEPROP(props, key) \
     70     if (1) { \
     71         jstring jkey = JNU_NewStringPlatform(env, key); \
     72         jobject r = (*env)->CallObjectMethod(env, props, removeID, jkey); \
     73         if ((*env)->ExceptionOccurred(env)) return NULL; \
     74         (*env)->DeleteLocalRef(env, jkey); \
     75         (*env)->DeleteLocalRef(env, r); \
     76     } else ((void) 0)
     77 #define GETPROP(props, key, jret) \
     78     if (1) { \
     79         jstring jkey = JNU_NewStringPlatform(env, key); \
     80         jret = (*env)->CallObjectMethod(env, props, getPropID, jkey); \
     81         if ((*env)->ExceptionOccurred(env)) return NULL; \
     82         (*env)->DeleteLocalRef(env, jkey); \
     83     } else ((void) 0)
     84 
     85 #ifndef VENDOR /* Third party may overwrite this. */
     86 #define VENDOR "Oracle Corporation"
     87 #define VENDOR_URL "http://java.oracle.com/"
     88 #define VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/"
     89 #endif
     90 
     91 #define JAVA_MAX_SUPPORTED_VERSION 51
     92 #define JAVA_MAX_SUPPORTED_MINOR_VERSION 0
     93 
     94 #ifdef JAVA_SPECIFICATION_VENDOR /* Third party may NOT overwrite this. */
     95   #error "ERROR: No override of JAVA_SPECIFICATION_VENDOR is allowed"
     96 #else
     97   #define JAVA_SPECIFICATION_VENDOR "Oracle Corporation"
     98 #endif
     99 
    100 /*
    101  * The following three functions implement setter methods for
    102  * java.lang.System.{in, out, err}. They are natively implemented
    103  * because they violate the semantics of the language (i.e. set final
    104  * variable).
    105  */
    106 JNIEXPORT void JNICALL
    107 System_setIn0(JNIEnv *env, jclass cla, jobject stream)
    108 {
    109     jfieldID fid =
    110         (*env)->GetStaticFieldID(env,cla,"in","Ljava/io/InputStream;");
    111     if (fid == 0)
    112         return;
    113     (*env)->SetStaticObjectField(env,cla,fid,stream);
    114 }
    115 
    116 JNIEXPORT void JNICALL
    117 System_setOut0(JNIEnv *env, jclass cla, jobject stream)
    118 {
    119     jfieldID fid =
    120         (*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;");
    121     if (fid == 0)
    122         return;
    123     (*env)->SetStaticObjectField(env,cla,fid,stream);
    124 }
    125 
    126 JNIEXPORT void JNICALL
    127 System_setErr0(JNIEnv *env, jclass cla, jobject stream)
    128 {
    129     jfieldID fid =
    130         (*env)->GetStaticFieldID(env,cla,"err","Ljava/io/PrintStream;");
    131     if (fid == 0)
    132         return;
    133     (*env)->SetStaticObjectField(env,cla,fid,stream);
    134 }
    135 
    136 static void cpchars(jchar *dst, char *src, int n)
    137 {
    138     int i;
    139     for (i = 0; i < n; i++) {
    140         dst[i] = src[i];
    141     }
    142 }
    143 
    144 JNIEXPORT jstring JNICALL
    145 System_mapLibraryName(JNIEnv *env, jclass ign, jstring libname)
    146 {
    147     int len;
    148     int prefix_len = (int) strlen(JNI_LIB_PREFIX);
    149     int suffix_len = (int) strlen(JNI_LIB_SUFFIX);
    150 
    151     jchar chars[256];
    152     if (libname == NULL) {
    153         JNU_ThrowNullPointerException(env, 0);
    154         return NULL;
    155     }
    156     len = (*env)->GetStringLength(env, libname);
    157     if (len > 240) {
    158         JNU_ThrowIllegalArgumentException(env, "name too long");
    159         return NULL;
    160     }
    161     cpchars(chars, JNI_LIB_PREFIX, prefix_len);
    162     (*env)->GetStringRegion(env, libname, 0, len, chars + prefix_len);
    163     len += prefix_len;
    164     cpchars(chars + len, JNI_LIB_SUFFIX, suffix_len);
    165     len += suffix_len;
    166 
    167     return (*env)->NewString(env, chars, len);
    168 }
    169 
    170 static jobjectArray System_specialProperties(JNIEnv* env, jclass ignored) {
    171     jclass stringClass = (*env)->FindClass(env, "java/lang/String");
    172     jobjectArray result = (*env)->NewObjectArray(env, 4, stringClass, NULL);
    173 
    174     char path[PATH_MAX];
    175     char* process_path = getcwd(path, sizeof(path));
    176     char user_dir[PATH_MAX + 10] = "user.dir=";
    177     strncat(user_dir, process_path, PATH_MAX);
    178     jstring user_dir_str = (*env)->NewStringUTF(env, user_dir);
    179     if ((*env)->ExceptionCheck(env)) {
    180         return NULL;
    181     }
    182     (*env)->SetObjectArrayElement(env, result, 0, user_dir_str);
    183     if ((*env)->ExceptionCheck(env)) {
    184         return NULL;
    185     }
    186     jstring zlib_str = (*env)->NewStringUTF(env, "android.zlib.version=" ZLIB_VERSION);
    187     if ((*env)->ExceptionCheck(env)) {
    188         return NULL;
    189     }
    190     (*env)->SetObjectArrayElement(env, result, 1, zlib_str);
    191     if ((*env)->ExceptionCheck(env)) {
    192         return NULL;
    193     }
    194     jstring ssl_str = (*env)->NewStringUTF(env, "android.openssl.version=" OPENSSL_VERSION_TEXT);
    195     if ((*env)->ExceptionCheck(env)) {
    196         return NULL;
    197     }
    198     (*env)->SetObjectArrayElement(env, result, 2, ssl_str);
    199     if ((*env)->ExceptionCheck(env)) {
    200         return NULL;
    201     }
    202 
    203 
    204     const char* library_path = getenv("LD_LIBRARY_PATH");
    205 #if defined(__ANDROID__)
    206     if (library_path == NULL) {
    207         android_get_LD_LIBRARY_PATH(path, sizeof(path));
    208         library_path = path;
    209     }
    210 #endif
    211     if (library_path == NULL) {
    212         library_path = "";
    213     }
    214     char* java_path = malloc(strlen("java.library.path=") + strlen(library_path) + 1);
    215     strcpy(java_path, "java.library.path=");
    216     strcat(java_path, library_path);
    217     jstring java_path_str = (*env)->NewStringUTF(env, java_path);
    218     free((void*)java_path);
    219     if ((*env)->ExceptionCheck(env)) {
    220         return NULL;
    221     }
    222     (*env)->SetObjectArrayElement(env, result, 3, java_path_str);
    223     if ((*env)->ExceptionCheck(env)) {
    224         return NULL;
    225     }
    226 
    227     return result;
    228 }
    229 
    230 static void System_log(JNIEnv* env, jclass ignored, jchar type, jstring javaMessage, jthrowable exception) {
    231     int priority;
    232     switch (type) {
    233     case 'D': case 'd': priority = ANDROID_LOG_DEBUG;   break;
    234     case 'E': case 'e': priority = ANDROID_LOG_ERROR;   break;
    235     case 'F': case 'f': priority = ANDROID_LOG_FATAL;   break;
    236     case 'I': case 'i': priority = ANDROID_LOG_INFO;    break;
    237     case 'S': case 's': priority = ANDROID_LOG_SILENT;  break;
    238     case 'V': case 'v': priority = ANDROID_LOG_VERBOSE; break;
    239     case 'W': case 'w': priority = ANDROID_LOG_WARN;    break;
    240     default:            priority = ANDROID_LOG_DEFAULT; break;
    241     }
    242 
    243     WITH_PLATFORM_STRING(env, javaMessage, message) {
    244       if (message == NULL) {
    245           // Since this function is used for last-gasp debugging output, be noisy on failure.
    246           return;
    247       }
    248       LOG_PRI(priority, "System", "%s", message);
    249     } END_PLATFORM_STRING(env, message);
    250 
    251     if (exception != NULL) {
    252         jniLogException(env, priority, "System", exception);
    253     }
    254 }
    255 
    256 static jlong System_nanoTime(JNIEnv* env, jclass unused) {
    257   struct timespec now;
    258   clock_gettime(CLOCK_MONOTONIC, &now);
    259   return now.tv_sec * 1000000000LL + now.tv_nsec;
    260 }
    261 
    262 static jlong System_currentTimeMillis(JNIEnv* env, jclass unused) {
    263   return JVM_CurrentTimeMillis(NULL, NULL);
    264 }
    265 
    266 static JNINativeMethod gMethods[] = {
    267   NATIVE_METHOD(System, mapLibraryName, "(Ljava/lang/String;)Ljava/lang/String;"),
    268   NATIVE_METHOD(System, setErr0, "(Ljava/io/PrintStream;)V"),
    269   NATIVE_METHOD(System, setOut0, "(Ljava/io/PrintStream;)V"),
    270   NATIVE_METHOD(System, setIn0, "(Ljava/io/InputStream;)V"),
    271   NATIVE_METHOD(System, specialProperties, "()[Ljava/lang/String;"),
    272   NATIVE_METHOD(System, log, "(CLjava/lang/String;Ljava/lang/Throwable;)V"),
    273   NATIVE_METHOD(System, currentTimeMillis, "()J"),
    274   NATIVE_METHOD(System, nanoTime, "()J"),
    275 };
    276 
    277 void register_java_lang_System(JNIEnv* env) {
    278   jniRegisterNativeMethods(env, "java/lang/System", gMethods, NELEM(gMethods));
    279 }
    280