Home | History | Annotate | Download | only in openjdkjvm
      1 /* Copyright (C) 2014 The Android Open Source Project
      2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      3  *
      4  * This file implements interfaces from the file jvm.h. This implementation
      5  * is licensed under the same terms as the file jvm.h.  The
      6  * copyright and license information for the file jvm.h follows.
      7  *
      8  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
      9  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     10  *
     11  * This code is free software; you can redistribute it and/or modify it
     12  * under the terms of the GNU General Public License version 2 only, as
     13  * published by the Free Software Foundation.  Oracle designates this
     14  * particular file as subject to the "Classpath" exception as provided
     15  * by Oracle in the LICENSE file that accompanied this code.
     16  *
     17  * This code is distributed in the hope that it will be useful, but WITHOUT
     18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     20  * version 2 for more details (a copy is included in the LICENSE file that
     21  * accompanied this code).
     22  *
     23  * You should have received a copy of the GNU General Public License version
     24  * 2 along with this work; if not, write to the Free Software Foundation,
     25  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     26  *
     27  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     28  * or visit www.oracle.com if you need additional information or have any
     29  * questions.
     30  */
     31 
     32 /*
     33  * Services that OpenJDK expects the VM to provide.
     34  */
     35 #include <dlfcn.h>
     36 #include <limits.h>
     37 #include <stdio.h>
     38 #include <sys/ioctl.h>
     39 #include <sys/socket.h>
     40 #include <sys/time.h>
     41 #include <unistd.h>
     42 
     43 #include <android-base/logging.h>
     44 
     45 #include "../../libcore/ojluni/src/main/native/jvm.h"  // TODO(narayan): fix it
     46 
     47 #include "base/macros.h"
     48 #include "common_throws.h"
     49 #include "gc/heap.h"
     50 #include "handle_scope-inl.h"
     51 #include "jni/java_vm_ext.h"
     52 #include "jni/jni_internal.h"
     53 #include "mirror/class_loader.h"
     54 #include "mirror/string-inl.h"
     55 #include "monitor.h"
     56 #include "native/scoped_fast_native_object_access-inl.h"
     57 #include "nativehelper/scoped_local_ref.h"
     58 #include "nativehelper/scoped_utf_chars.h"
     59 #include "runtime.h"
     60 #include "scoped_thread_state_change-inl.h"
     61 #include "thread.h"
     62 #include "thread_list.h"
     63 #include "verify_object.h"
     64 
     65 #undef LOG_TAG
     66 #define LOG_TAG "artopenjdk"
     67 
     68 /* posix open() with extensions; used by e.g. ZipFile */
     69 JNIEXPORT jint JVM_Open(const char* fname, jint flags, jint mode) {
     70     /*
     71      * Some code seems to want the special return value JVM_EEXIST if the
     72      * file open fails due to O_EXCL.
     73      */
     74     // Don't use JVM_O_DELETE, it's problematic with FUSE, see b/28901232.
     75     if (flags & JVM_O_DELETE) {
     76         LOG(FATAL) << "JVM_O_DELETE option is not supported (while opening: '"
     77                    << fname << "')";
     78     }
     79 
     80     flags |= O_CLOEXEC;
     81     int fd = TEMP_FAILURE_RETRY(open(fname, flags & ~JVM_O_DELETE, mode));
     82     if (fd < 0) {
     83         int err = errno;
     84         if (err == EEXIST) {
     85             return JVM_EEXIST;
     86         } else {
     87             return -1;
     88         }
     89     }
     90 
     91     return fd;
     92 }
     93 
     94 /* posix close() */
     95 JNIEXPORT jint JVM_Close(jint fd) {
     96     // don't want TEMP_FAILURE_RETRY here -- file is closed even if EINTR
     97     return close(fd);
     98 }
     99 
    100 /* posix read() */
    101 JNIEXPORT jint JVM_Read(jint fd, char* buf, jint nbytes) {
    102     return TEMP_FAILURE_RETRY(read(fd, buf, nbytes));
    103 }
    104 
    105 /* posix write(); is used to write messages to stderr */
    106 JNIEXPORT jint JVM_Write(jint fd, char* buf, jint nbytes) {
    107     return TEMP_FAILURE_RETRY(write(fd, buf, nbytes));
    108 }
    109 
    110 /* posix lseek() */
    111 JNIEXPORT jlong JVM_Lseek(jint fd, jlong offset, jint whence) {
    112 #if !defined(__APPLE__)
    113     // NOTE: Using TEMP_FAILURE_RETRY here is busted for LP32 on glibc - the return
    114     // value will be coerced into an int32_t.
    115     //
    116     // lseek64 isn't specified to return EINTR so it shouldn't be necessary
    117     // anyway.
    118     return lseek64(fd, offset, whence);
    119 #else
    120     // NOTE: This code is compiled for Mac OS but isn't ever run on that
    121     // platform.
    122     return lseek(fd, offset, whence);
    123 #endif
    124 }
    125 
    126 /*
    127  * "raw monitors" seem to be expected to behave like non-recursive pthread
    128  * mutexes.  They're used by ZipFile.
    129  */
    130 JNIEXPORT void* JVM_RawMonitorCreate(void) {
    131     pthread_mutex_t* mutex =
    132         reinterpret_cast<pthread_mutex_t*>(malloc(sizeof(pthread_mutex_t)));
    133     CHECK(mutex != nullptr);
    134     CHECK_PTHREAD_CALL(pthread_mutex_init, (mutex, nullptr), "JVM_RawMonitorCreate");
    135     return mutex;
    136 }
    137 
    138 JNIEXPORT void JVM_RawMonitorDestroy(void* mon) {
    139     CHECK_PTHREAD_CALL(pthread_mutex_destroy,
    140                        (reinterpret_cast<pthread_mutex_t*>(mon)),
    141                        "JVM_RawMonitorDestroy");
    142     free(mon);
    143 }
    144 
    145 JNIEXPORT jint JVM_RawMonitorEnter(void* mon) {
    146     return pthread_mutex_lock(reinterpret_cast<pthread_mutex_t*>(mon));
    147 }
    148 
    149 JNIEXPORT void JVM_RawMonitorExit(void* mon) {
    150     CHECK_PTHREAD_CALL(pthread_mutex_unlock,
    151                        (reinterpret_cast<pthread_mutex_t*>(mon)),
    152                        "JVM_RawMonitorExit");
    153 }
    154 
    155 JNIEXPORT char* JVM_NativePath(char* path) {
    156     return path;
    157 }
    158 
    159 JNIEXPORT jint JVM_GetLastErrorString(char* buf, int len) {
    160 #if defined(__GLIBC__) || defined(__BIONIC__)
    161   if (len == 0) {
    162     return 0;
    163   }
    164 
    165   const int err = errno;
    166   char* result = strerror_r(err, buf, len);
    167   if (result != buf) {
    168     strncpy(buf, result, len);
    169     buf[len - 1] = '\0';
    170   }
    171 
    172   return strlen(buf);
    173 #else
    174   UNUSED(buf);
    175   UNUSED(len);
    176   return -1;
    177 #endif
    178 }
    179 
    180 JNIEXPORT int jio_fprintf(FILE* fp, const char* fmt, ...) {
    181     va_list args;
    182 
    183     va_start(args, fmt);
    184     int len = jio_vfprintf(fp, fmt, args);
    185     va_end(args);
    186 
    187     return len;
    188 }
    189 
    190 JNIEXPORT int jio_vfprintf(FILE* fp, const char* fmt, va_list args) {
    191     assert(fp != nullptr);
    192     return vfprintf(fp, fmt, args);
    193 }
    194 
    195 /* posix fsync() */
    196 JNIEXPORT jint JVM_Sync(jint fd) {
    197     return TEMP_FAILURE_RETRY(fsync(fd));
    198 }
    199 
    200 JNIEXPORT void* JVM_FindLibraryEntry(void* handle, const char* name) {
    201     return dlsym(handle, name);
    202 }
    203 
    204 JNIEXPORT jlong JVM_CurrentTimeMillis(JNIEnv* env ATTRIBUTE_UNUSED,
    205                                       jclass clazz ATTRIBUTE_UNUSED) {
    206     struct timeval tv;
    207     gettimeofday(&tv, (struct timezone *) nullptr);
    208     jlong when = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
    209     return when;
    210 }
    211 
    212 JNIEXPORT jint JVM_Socket(jint domain, jint type, jint protocol) {
    213     return TEMP_FAILURE_RETRY(socket(domain, type, protocol));
    214 }
    215 
    216 JNIEXPORT jint JVM_InitializeSocketLibrary() {
    217   return 0;
    218 }
    219 
    220 int jio_vsnprintf(char *str, size_t count, const char *fmt, va_list args) {
    221   if ((intptr_t)count <= 0) return -1;
    222   return vsnprintf(str, count, fmt, args);
    223 }
    224 
    225 int jio_snprintf(char *str, size_t count, const char *fmt, ...) {
    226   va_list args;
    227   int len;
    228   va_start(args, fmt);
    229   len = jio_vsnprintf(str, count, fmt, args);
    230   va_end(args);
    231   return len;
    232 }
    233 
    234 JNIEXPORT jint JVM_SetSockOpt(jint fd, int level, int optname,
    235     const char* optval, int optlen) {
    236   return TEMP_FAILURE_RETRY(setsockopt(fd, level, optname, optval, optlen));
    237 }
    238 
    239 JNIEXPORT jint JVM_SocketShutdown(jint fd, jint howto) {
    240   return TEMP_FAILURE_RETRY(shutdown(fd, howto));
    241 }
    242 
    243 JNIEXPORT jint JVM_GetSockOpt(jint fd, int level, int optname, char* optval,
    244   int* optlen) {
    245   socklen_t len = *optlen;
    246   int cc = TEMP_FAILURE_RETRY(getsockopt(fd, level, optname, optval, &len));
    247   *optlen = len;
    248   return cc;
    249 }
    250 
    251 JNIEXPORT jint JVM_GetSockName(jint fd, struct sockaddr* addr, int* addrlen) {
    252   socklen_t len = *addrlen;
    253   int cc = TEMP_FAILURE_RETRY(getsockname(fd, addr, &len));
    254   *addrlen = len;
    255   return cc;
    256 }
    257 
    258 JNIEXPORT jint JVM_SocketAvailable(jint fd, jint* result) {
    259   if (TEMP_FAILURE_RETRY(ioctl(fd, FIONREAD, result)) < 0) {
    260       return JNI_FALSE;
    261   }
    262 
    263   return JNI_TRUE;
    264 }
    265 
    266 JNIEXPORT jint JVM_Send(jint fd, char* buf, jint nBytes, jint flags) {
    267   return TEMP_FAILURE_RETRY(send(fd, buf, nBytes, flags));
    268 }
    269 
    270 JNIEXPORT jint JVM_SocketClose(jint fd) {
    271   // Don't want TEMP_FAILURE_RETRY here -- file is closed even if EINTR.
    272   return close(fd);
    273 }
    274 
    275 JNIEXPORT jint JVM_Listen(jint fd, jint count) {
    276   return TEMP_FAILURE_RETRY(listen(fd, count));
    277 }
    278 
    279 JNIEXPORT jint JVM_Connect(jint fd, struct sockaddr* addr, jint addrlen) {
    280   return TEMP_FAILURE_RETRY(connect(fd, addr, addrlen));
    281 }
    282 
    283 JNIEXPORT int JVM_GetHostName(char* name, int namelen) {
    284   return TEMP_FAILURE_RETRY(gethostname(name, namelen));
    285 }
    286 
    287 JNIEXPORT jstring JVM_InternString(JNIEnv* env, jstring jstr) {
    288   art::ScopedFastNativeObjectAccess soa(env);
    289   art::ObjPtr<art::mirror::String> s = soa.Decode<art::mirror::String>(jstr);
    290   return soa.AddLocalReference<jstring>(s->Intern());
    291 }
    292 
    293 JNIEXPORT jlong JVM_FreeMemory(void) {
    294   return art::Runtime::Current()->GetHeap()->GetFreeMemory();
    295 }
    296 
    297 JNIEXPORT jlong JVM_TotalMemory(void) {
    298   return art::Runtime::Current()->GetHeap()->GetTotalMemory();
    299 }
    300 
    301 JNIEXPORT jlong JVM_MaxMemory(void) {
    302   return art::Runtime::Current()->GetHeap()->GetMaxMemory();
    303 }
    304 
    305 JNIEXPORT void JVM_GC(void) {
    306   if (art::Runtime::Current()->IsExplicitGcDisabled()) {
    307       LOG(INFO) << "Explicit GC skipped.";
    308       return;
    309   }
    310   art::Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references */ false);
    311 }
    312 
    313 JNIEXPORT __attribute__((noreturn)) void JVM_Exit(jint status) {
    314   LOG(INFO) << "System.exit called, status: " << status;
    315   art::Runtime::Current()->CallExitHook(status);
    316   exit(status);
    317 }
    318 
    319 JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env,
    320                                  jstring javaFilename,
    321                                  jobject javaLoader,
    322                                  jclass caller) {
    323   ScopedUtfChars filename(env, javaFilename);
    324   if (filename.c_str() == nullptr) {
    325     return nullptr;
    326   }
    327 
    328   std::string error_msg;
    329   {
    330     art::JavaVMExt* vm = art::Runtime::Current()->GetJavaVM();
    331     bool success = vm->LoadNativeLibrary(env,
    332                                          filename.c_str(),
    333                                          javaLoader,
    334                                          caller,
    335                                          &error_msg);
    336     if (success) {
    337       return nullptr;
    338     }
    339   }
    340 
    341   // Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF.
    342   env->ExceptionClear();
    343   return env->NewStringUTF(error_msg.c_str());
    344 }
    345 
    346 JNIEXPORT void JVM_StartThread(JNIEnv* env, jobject jthread, jlong stack_size, jboolean daemon) {
    347   art::Thread::CreateNativeThread(env, jthread, stack_size, daemon == JNI_TRUE);
    348 }
    349 
    350 JNIEXPORT void JVM_SetThreadPriority(JNIEnv* env, jobject jthread, jint prio) {
    351   art::ScopedObjectAccess soa(env);
    352   art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
    353   art::Thread* thread = art::Thread::FromManagedThread(soa, jthread);
    354   if (thread != nullptr) {
    355     thread->SetNativePriority(prio);
    356   }
    357 }
    358 
    359 JNIEXPORT void JVM_Yield(JNIEnv* env ATTRIBUTE_UNUSED, jclass threadClass ATTRIBUTE_UNUSED) {
    360   sched_yield();
    361 }
    362 
    363 JNIEXPORT void JVM_Sleep(JNIEnv* env, jclass threadClass ATTRIBUTE_UNUSED,
    364                          jobject java_lock, jlong millis) {
    365   art::ScopedFastNativeObjectAccess soa(env);
    366   art::ObjPtr<art::mirror::Object> lock = soa.Decode<art::mirror::Object>(java_lock);
    367   art::Monitor::Wait(art::Thread::Current(), lock.Ptr(), millis, 0, true, art::kSleeping);
    368 }
    369 
    370 JNIEXPORT jobject JVM_CurrentThread(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED) {
    371   art::ScopedFastNativeObjectAccess soa(env);
    372   return soa.AddLocalReference<jobject>(soa.Self()->GetPeer());
    373 }
    374 
    375 JNIEXPORT void JVM_Interrupt(JNIEnv* env, jobject jthread) {
    376   art::ScopedFastNativeObjectAccess soa(env);
    377   art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
    378   art::Thread* thread = art::Thread::FromManagedThread(soa, jthread);
    379   if (thread != nullptr) {
    380     thread->Interrupt(soa.Self());
    381   }
    382 }
    383 
    384 JNIEXPORT jboolean JVM_IsInterrupted(JNIEnv* env, jobject jthread, jboolean clearInterrupted) {
    385   if (clearInterrupted) {
    386     return static_cast<art::JNIEnvExt*>(env)->GetSelf()->Interrupted() ? JNI_TRUE : JNI_FALSE;
    387   } else {
    388     art::ScopedFastNativeObjectAccess soa(env);
    389     art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
    390     art::Thread* thread = art::Thread::FromManagedThread(soa, jthread);
    391     return (thread != nullptr) ? thread->IsInterrupted() : JNI_FALSE;
    392   }
    393 }
    394 
    395 JNIEXPORT jboolean JVM_HoldsLock(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED, jobject jobj) {
    396   art::ScopedObjectAccess soa(env);
    397   art::ObjPtr<art::mirror::Object> object = soa.Decode<art::mirror::Object>(jobj);
    398   if (object == nullptr) {
    399     art::ThrowNullPointerException("object == null");
    400     return JNI_FALSE;
    401   }
    402   return soa.Self()->HoldsLock(object);
    403 }
    404 
    405 JNIEXPORT void JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring java_name) {
    406   ScopedUtfChars name(env, java_name);
    407   {
    408     art::ScopedObjectAccess soa(env);
    409     if (soa.Decode<art::mirror::Object>(jthread) == soa.Self()->GetPeer()) {
    410       soa.Self()->SetThreadName(name.c_str());
    411       return;
    412     }
    413   }
    414   // Suspend thread to avoid it from killing itself while we set its name. We don't just hold the
    415   // thread list lock to avoid this, as setting the thread name causes mutator to lock/unlock
    416   // in the DDMS send code.
    417   art::ThreadList* thread_list = art::Runtime::Current()->GetThreadList();
    418   bool timed_out;
    419   // Take suspend thread lock to avoid races with threads trying to suspend this one.
    420   art::Thread* thread;
    421   {
    422     thread = thread_list->SuspendThreadByPeer(jthread,
    423                                               true,
    424                                               art::SuspendReason::kInternal,
    425                                               &timed_out);
    426   }
    427   if (thread != nullptr) {
    428     {
    429       art::ScopedObjectAccess soa(env);
    430       thread->SetThreadName(name.c_str());
    431     }
    432     bool resumed = thread_list->Resume(thread, art::SuspendReason::kInternal);
    433     DCHECK(resumed);
    434   } else if (timed_out) {
    435     LOG(ERROR) << "Trying to set thread name to '" << name.c_str() << "' failed as the thread "
    436         "failed to suspend within a generous timeout.";
    437   }
    438 }
    439 
    440 JNIEXPORT __attribute__((noreturn)) jint JVM_IHashCode(JNIEnv* env ATTRIBUTE_UNUSED,
    441                              jobject javaObject ATTRIBUTE_UNUSED) {
    442   UNIMPLEMENTED(FATAL) << "JVM_IHashCode is not implemented";
    443   UNREACHABLE();
    444 }
    445 
    446 JNIEXPORT __attribute__((noreturn)) jlong JVM_NanoTime(JNIEnv* env ATTRIBUTE_UNUSED, jclass unused ATTRIBUTE_UNUSED) {
    447   UNIMPLEMENTED(FATAL) << "JVM_NanoTime is not implemented";
    448   UNREACHABLE();
    449 }
    450 
    451 JNIEXPORT __attribute__((noreturn)) void JVM_ArrayCopy(JNIEnv* /* env */, jclass /* unused */, jobject /* javaSrc */,
    452                              jint /* srcPos */, jobject /* javaDst */, jint /* dstPos */,
    453                              jint /* length */) {
    454   UNIMPLEMENTED(FATAL) << "JVM_ArrayCopy is not implemented";
    455   UNREACHABLE();
    456 }
    457 
    458 JNIEXPORT __attribute__((noreturn)) jint JVM_FindSignal(const char* name ATTRIBUTE_UNUSED) {
    459   LOG(FATAL) << "JVM_FindSignal is not implemented";
    460   UNREACHABLE();
    461 }
    462 
    463 JNIEXPORT __attribute__((noreturn)) void* JVM_RegisterSignal(jint signum ATTRIBUTE_UNUSED, void* handler ATTRIBUTE_UNUSED) {
    464   LOG(FATAL) << "JVM_RegisterSignal is not implemented";
    465   UNREACHABLE();
    466 }
    467 
    468 JNIEXPORT __attribute__((noreturn)) jboolean JVM_RaiseSignal(jint signum ATTRIBUTE_UNUSED) {
    469   LOG(FATAL) << "JVM_RaiseSignal is not implemented";
    470   UNREACHABLE();
    471 }
    472 
    473 JNIEXPORT __attribute__((noreturn))  void JVM_Halt(jint code) {
    474   exit(code);
    475 }
    476 
    477 JNIEXPORT jboolean JVM_IsNaN(jdouble d) {
    478   return isnan(d);
    479 }
    480