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#define LOG_TAG "libcore"
26
27#include <stdlib.h>
28#include <string.h>
29#include <time.h>
30
31#include <log/log.h>
32
33#include "io_util.h"
34#include "jni.h"
35#include "jni_util.h"
36#include "jvm.h"
37
38#include "openssl/opensslv.h"
39#include "zlib.h"
40#include <nativehelper/JNIHelp.h>
41#if defined(__ANDROID__)
42void android_get_LD_LIBRARY_PATH(char*, size_t);
43#endif
44
45#define NATIVE_METHOD(className, functionName, signature) \
46{ #functionName, signature, (void*)(className ## _ ## functionName) }
47
48#define PUTPROP(props, key, val) \
49    if (1) { \
50        jstring jkey = (*env)->NewStringUTF(env, key); \
51        jstring jval = (*env)->NewStringUTF(env, val); \
52        jobject r = (*env)->CallObjectMethod(env, props, putID, jkey, jval); \
53        if ((*env)->ExceptionOccurred(env)) return NULL; \
54        (*env)->DeleteLocalRef(env, jkey); \
55        (*env)->DeleteLocalRef(env, jval); \
56        (*env)->DeleteLocalRef(env, r); \
57    } else ((void) 0)
58
59/*  "key" is a char type string with only ASCII character in it.
60    "val" is a nchar (typedefed in java_props.h) type string  */
61
62#define PUTPROP_ForPlatformNString(props, key, val) \
63    if (1) { \
64        jstring jkey = (*env)->NewStringUTF(env, key);  \
65        jstring jval = GetStringPlatform(env, val); \
66        jobject r = (*env)->CallObjectMethod(env, props, putID, jkey, jval); \
67        if ((*env)->ExceptionOccurred(env)) return NULL; \
68        (*env)->DeleteLocalRef(env, jkey); \
69        (*env)->DeleteLocalRef(env, jval); \
70        (*env)->DeleteLocalRef(env, r); \
71    } else ((void) 0)
72#define REMOVEPROP(props, key) \
73    if (1) { \
74        jstring jkey = JNU_NewStringPlatform(env, key); \
75        jobject r = (*env)->CallObjectMethod(env, props, removeID, jkey); \
76        if ((*env)->ExceptionOccurred(env)) return NULL; \
77        (*env)->DeleteLocalRef(env, jkey); \
78        (*env)->DeleteLocalRef(env, r); \
79    } else ((void) 0)
80#define GETPROP(props, key, jret) \
81    if (1) { \
82        jstring jkey = JNU_NewStringPlatform(env, key); \
83        (jret) = (*env)->CallObjectMethod(env, props, getPropID, jkey); \
84        if ((*env)->ExceptionOccurred(env)) return NULL; \
85        (*env)->DeleteLocalRef(env, jkey); \
86    } else ((void) 0)
87
88#ifndef VENDOR /* Third party may overwrite this. */
89#define VENDOR "Oracle Corporation"
90#define VENDOR_URL "http://java.oracle.com/"
91#define VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/"
92#endif
93
94#define JAVA_MAX_SUPPORTED_VERSION 51
95#define JAVA_MAX_SUPPORTED_MINOR_VERSION 0
96
97#ifdef JAVA_SPECIFICATION_VENDOR /* Third party may NOT overwrite this. */
98  #error "ERROR: No override of JAVA_SPECIFICATION_VENDOR is allowed"
99#else
100  #define JAVA_SPECIFICATION_VENDOR "Oracle Corporation"
101#endif
102
103/*
104 * The following three functions implement setter methods for
105 * java.lang.System.{in, out, err}. They are natively implemented
106 * because they violate the semantics of the language (i.e. set final
107 * variable).
108 */
109JNIEXPORT void JNICALL
110System_setIn0(JNIEnv *env, jclass cla, jobject stream)
111{
112    jfieldID fid =
113        (*env)->GetStaticFieldID(env,cla,"in","Ljava/io/InputStream;");
114    if (fid == 0)
115        return;
116    (*env)->SetStaticObjectField(env,cla,fid,stream);
117}
118
119JNIEXPORT void JNICALL
120System_setOut0(JNIEnv *env, jclass cla, jobject stream)
121{
122    jfieldID fid =
123        (*env)->GetStaticFieldID(env,cla,"out","Ljava/io/PrintStream;");
124    if (fid == 0)
125        return;
126    (*env)->SetStaticObjectField(env,cla,fid,stream);
127}
128
129JNIEXPORT void JNICALL
130System_setErr0(JNIEnv *env, jclass cla, jobject stream)
131{
132    jfieldID fid =
133        (*env)->GetStaticFieldID(env,cla,"err","Ljava/io/PrintStream;");
134    if (fid == 0)
135        return;
136    (*env)->SetStaticObjectField(env,cla,fid,stream);
137}
138
139static void cpchars(jchar *dst, char *src, int n)
140{
141    int i;
142    for (i = 0; i < n; i++) {
143        dst[i] = src[i];
144    }
145}
146
147JNIEXPORT jstring JNICALL
148System_mapLibraryName(JNIEnv *env, jclass ign, jstring libname)
149{
150    int len;
151    int prefix_len = (int) strlen(JNI_LIB_PREFIX);
152    int suffix_len = (int) strlen(JNI_LIB_SUFFIX);
153
154    jchar chars[256];
155    if (libname == NULL) {
156        JNU_ThrowNullPointerException(env, 0);
157        return NULL;
158    }
159    len = (*env)->GetStringLength(env, libname);
160    if (len > 240) {
161        JNU_ThrowIllegalArgumentException(env, "name too long");
162        return NULL;
163    }
164    cpchars(chars, JNI_LIB_PREFIX, prefix_len);
165    (*env)->GetStringRegion(env, libname, 0, len, chars + prefix_len);
166    len += prefix_len;
167    cpchars(chars + len, JNI_LIB_SUFFIX, suffix_len);
168    len += suffix_len;
169
170    return (*env)->NewString(env, chars, len);
171}
172
173static jobjectArray System_specialProperties(JNIEnv* env, jclass ignored) {
174    jclass stringClass = (*env)->FindClass(env, "java/lang/String");
175    jobjectArray result = (*env)->NewObjectArray(env, 4, stringClass, NULL);
176
177    char path[PATH_MAX];
178    char* process_path = getcwd(path, sizeof(path));
179    char user_dir[PATH_MAX + 10] = "user.dir=";
180    strncat(user_dir, process_path, PATH_MAX);
181    jstring user_dir_str = (*env)->NewStringUTF(env, user_dir);
182    if ((*env)->ExceptionCheck(env)) {
183        return NULL;
184    }
185    (*env)->SetObjectArrayElement(env, result, 0, user_dir_str);
186    if ((*env)->ExceptionCheck(env)) {
187        return NULL;
188    }
189    jstring zlib_str = (*env)->NewStringUTF(env, "android.zlib.version=" ZLIB_VERSION);
190    if ((*env)->ExceptionCheck(env)) {
191        return NULL;
192    }
193    (*env)->SetObjectArrayElement(env, result, 1, zlib_str);
194    if ((*env)->ExceptionCheck(env)) {
195        return NULL;
196    }
197    jstring ssl_str = (*env)->NewStringUTF(env, "android.openssl.version=" OPENSSL_VERSION_TEXT);
198    if ((*env)->ExceptionCheck(env)) {
199        return NULL;
200    }
201    (*env)->SetObjectArrayElement(env, result, 2, ssl_str);
202    if ((*env)->ExceptionCheck(env)) {
203        return NULL;
204    }
205
206
207    const char* library_path = getenv("LD_LIBRARY_PATH");
208#if defined(__ANDROID__)
209    if (library_path == NULL) {
210        android_get_LD_LIBRARY_PATH(path, sizeof(path));
211        library_path = path;
212    }
213#endif
214    if (library_path == NULL) {
215        library_path = "";
216    }
217    char* java_path = malloc(strlen("java.library.path=") + strlen(library_path) + 1);
218    strcpy(java_path, "java.library.path=");
219    strcat(java_path, library_path);
220    jstring java_path_str = (*env)->NewStringUTF(env, java_path);
221    free((void*)java_path);
222    if ((*env)->ExceptionCheck(env)) {
223        return NULL;
224    }
225    (*env)->SetObjectArrayElement(env, result, 3, java_path_str);
226    if ((*env)->ExceptionCheck(env)) {
227        return NULL;
228    }
229
230    return result;
231}
232
233static void System_log(JNIEnv* env, jclass ignored, jchar type, jstring javaMessage, jthrowable exception) {
234    int priority;
235    switch (type) {
236    case 'D': case 'd': priority = ANDROID_LOG_DEBUG;   break;
237    case 'E': case 'e': priority = ANDROID_LOG_ERROR;   break;
238    case 'F': case 'f': priority = ANDROID_LOG_FATAL;   break;
239    case 'I': case 'i': priority = ANDROID_LOG_INFO;    break;
240    case 'S': case 's': priority = ANDROID_LOG_SILENT;  break;
241    case 'V': case 'v': priority = ANDROID_LOG_VERBOSE; break;
242    case 'W': case 'w': priority = ANDROID_LOG_WARN;    break;
243    default:            priority = ANDROID_LOG_DEFAULT; break;
244    }
245
246    WITH_PLATFORM_STRING(env, javaMessage, message) {
247      LOG_PRI(priority, "System", "%s", message);
248    } END_PLATFORM_STRING(env, message);
249
250    if (exception != NULL) {
251        jniLogException(env, priority, "System", exception);
252    }
253}
254
255static jlong System_nanoTime(JNIEnv* env, jclass unused) {
256  struct timespec now;
257  clock_gettime(CLOCK_MONOTONIC, &now);
258  return now.tv_sec * 1000000000LL + now.tv_nsec;
259}
260
261static jlong System_currentTimeMillis(JNIEnv* env, jclass unused) {
262  return JVM_CurrentTimeMillis(NULL, NULL);
263}
264
265static JNINativeMethod gMethods[] = {
266  NATIVE_METHOD(System, mapLibraryName, "(Ljava/lang/String;)Ljava/lang/String;"),
267  NATIVE_METHOD(System, setErr0, "(Ljava/io/PrintStream;)V"),
268  NATIVE_METHOD(System, setOut0, "(Ljava/io/PrintStream;)V"),
269  NATIVE_METHOD(System, setIn0, "(Ljava/io/InputStream;)V"),
270  NATIVE_METHOD(System, specialProperties, "()[Ljava/lang/String;"),
271  NATIVE_METHOD(System, log, "(CLjava/lang/String;Ljava/lang/Throwable;)V"),
272  NATIVE_METHOD(System, currentTimeMillis, "()J"),
273  NATIVE_METHOD(System, nanoTime, "()J"),
274};
275
276void register_java_lang_System(JNIEnv* env) {
277  jniRegisterNativeMethods(env, "java/lang/System", gMethods, NELEM(gMethods));
278}
279