summaryrefslogtreecommitdiffstats
path: root/runtime/native
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/native')
-rw-r--r--runtime/native/dalvik_system_DexFile.cc310
-rw-r--r--runtime/native/dalvik_system_VMDebug.cc272
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc223
-rw-r--r--runtime/native/dalvik_system_VMStack.cc132
-rw-r--r--runtime/native/dalvik_system_Zygote.cc573
-rw-r--r--runtime/native/java_lang_Class.cc135
-rw-r--r--runtime/native/java_lang_Object.cc70
-rw-r--r--runtime/native/java_lang_Runtime.cc99
-rw-r--r--runtime/native/java_lang_String.cc61
-rw-r--r--runtime/native/java_lang_System.cc334
-rw-r--r--runtime/native/java_lang_Thread.cc186
-rw-r--r--runtime/native/java_lang_Throwable.cc44
-rw-r--r--runtime/native/java_lang_VMClassLoader.cc99
-rw-r--r--runtime/native/java_lang_reflect_Array.cc74
-rw-r--r--runtime/native/java_lang_reflect_Constructor.cc74
-rw-r--r--runtime/native/java_lang_reflect_Field.cc342
-rw-r--r--runtime/native/java_lang_reflect_Method.cc71
-rw-r--r--runtime/native/java_lang_reflect_Proxy.cc51
-rw-r--r--runtime/native/java_util_concurrent_atomic_AtomicLong.cc34
-rw-r--r--runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc40
-rw-r--r--runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc176
-rw-r--r--runtime/native/sun_misc_Unsafe.cc185
22 files changed, 3585 insertions, 0 deletions
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
new file mode 100644
index 0000000..b9838f8
--- /dev/null
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "class_linker.h"
+#include "common_throws.h"
+#include "dex_file-inl.h"
+#include "gc/space/image_space.h"
+#include "gc/space/space-inl.h"
+#include "image.h"
+#include "jni_internal.h"
+#include "mirror/class_loader.h"
+#include "mirror/object-inl.h"
+#include "mirror/string.h"
+#include "oat.h"
+#include "os.h"
+#include "runtime.h"
+#include "scoped_thread_state_change.h"
+#include "ScopedLocalRef.h"
+#include "ScopedUtfChars.h"
+#include "toStringArray.h"
+#include "zip_archive.h"
+
+namespace art {
+
+// A smart pointer that provides read-only access to a Java string's UTF chars.
+// Unlike libcore's NullableScopedUtfChars, this will *not* throw NullPointerException if
+// passed a null jstring. The correct idiom is:
+//
+// NullableScopedUtfChars name(env, javaName);
+// if (env->ExceptionCheck()) {
+// return NULL;
+// }
+// // ... use name.c_str()
+//
+// TODO: rewrite to get rid of this, or change ScopedUtfChars to offer this option.
+class NullableScopedUtfChars {
+ public:
+ NullableScopedUtfChars(JNIEnv* env, jstring s) : mEnv(env), mString(s) {
+ mUtfChars = (s != NULL) ? env->GetStringUTFChars(s, NULL) : NULL;
+ }
+
+ ~NullableScopedUtfChars() {
+ if (mUtfChars) {
+ mEnv->ReleaseStringUTFChars(mString, mUtfChars);
+ }
+ }
+
+ const char* c_str() const {
+ return mUtfChars;
+ }
+
+ size_t size() const {
+ return strlen(mUtfChars);
+ }
+
+ // Element access.
+ const char& operator[](size_t n) const {
+ return mUtfChars[n];
+ }
+
+ private:
+ JNIEnv* mEnv;
+ jstring mString;
+ const char* mUtfChars;
+
+ // Disallow copy and assignment.
+ NullableScopedUtfChars(const NullableScopedUtfChars&);
+ void operator=(const NullableScopedUtfChars&);
+};
+
+static jint DexFile_openDexFile(JNIEnv* env, jclass, jstring javaSourceName, jstring javaOutputName, jint) {
+ ScopedUtfChars sourceName(env, javaSourceName);
+ if (sourceName.c_str() == NULL) {
+ return 0;
+ }
+ std::string source(sourceName.c_str());
+ NullableScopedUtfChars outputName(env, javaOutputName);
+ if (env->ExceptionCheck()) {
+ return 0;
+ }
+ ScopedObjectAccess soa(env);
+ const DexFile* dex_file;
+ if (outputName.c_str() == NULL) {
+ dex_file = Runtime::Current()->GetClassLinker()->FindDexFileInOatFileFromDexLocation(source);
+ } else {
+ std::string output(outputName.c_str());
+ dex_file =
+ Runtime::Current()->GetClassLinker()->FindOrCreateOatFileForDexLocation(source, output);
+ }
+ if (dex_file == NULL) {
+ LOG(WARNING) << "Failed to open dex file: " << source;
+ ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+ soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/io/IOException;",
+ "Unable to open dex file: %s", source.c_str());
+ return 0;
+ }
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(dex_file));
+}
+
+static const DexFile* toDexFile(int dex_file_address) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ const DexFile* dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(dex_file_address));
+ if (dex_file == NULL) {
+ ThrowNullPointerException(NULL, "dex_file == null");
+ }
+ return dex_file;
+}
+
+static void DexFile_closeDexFile(JNIEnv* env, jclass, jint cookie) {
+ const DexFile* dex_file;
+ {
+ ScopedObjectAccess soa(env);
+ dex_file = toDexFile(cookie);
+ }
+ if (dex_file == NULL) {
+ return;
+ }
+ if (Runtime::Current()->GetClassLinker()->IsDexFileRegistered(*dex_file)) {
+ return;
+ }
+ delete dex_file;
+}
+
+static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, jobject javaLoader,
+ jint cookie) {
+ ScopedObjectAccess soa(env);
+ const DexFile* dex_file = toDexFile(cookie);
+ if (dex_file == NULL) {
+ return NULL;
+ }
+ ScopedUtfChars class_name(env, javaName);
+ if (class_name.c_str() == NULL) {
+ return NULL;
+ }
+ const std::string descriptor(DotToDescriptor(class_name.c_str()));
+ const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
+ if (dex_class_def == NULL) {
+ return NULL;
+ }
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ class_linker->RegisterDexFile(*dex_file);
+ mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
+ mirror::Class* result = class_linker->DefineClass(descriptor, class_loader, *dex_file, *dex_class_def);
+ return soa.AddLocalReference<jclass>(result);
+}
+
+static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jint cookie) {
+ const DexFile* dex_file;
+ {
+ ScopedObjectAccess soa(env);
+ dex_file = toDexFile(cookie);
+ }
+ if (dex_file == NULL) {
+ return NULL;
+ }
+
+ std::vector<std::string> class_names;
+ for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
+ const char* descriptor = dex_file->GetClassDescriptor(class_def);
+ class_names.push_back(DescriptorToDot(descriptor));
+ }
+ return toStringArray(env, class_names);
+}
+
+static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename) {
+ bool debug_logging = false;
+
+ ScopedUtfChars filename(env, javaFilename);
+ if (filename.c_str() == NULL) {
+ LOG(ERROR) << "DexFile_isDexOptNeeded null filename";
+ return JNI_TRUE;
+ }
+
+ if (!OS::FileExists(filename.c_str())) {
+ LOG(ERROR) << "DexFile_isDexOptNeeded file '" << filename.c_str() << "' does not exist";
+ ScopedObjectAccess soa(env);
+ ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+ soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/io/FileNotFoundException;",
+ "%s", filename.c_str());
+ return JNI_TRUE;
+ }
+
+ // Always treat elements of the bootclasspath as up-to-date. The
+ // fact that code is running at all means that this should be true.
+ Runtime* runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ const std::vector<const DexFile*>& boot_class_path = class_linker->GetBootClassPath();
+ for (size_t i = 0; i < boot_class_path.size(); i++) {
+ if (boot_class_path[i]->GetLocation() == filename.c_str()) {
+ if (debug_logging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded ignoring boot class path file: " << filename.c_str();
+ }
+ return JNI_FALSE;
+ }
+ }
+
+ // Check if we have an odex file next to the dex file.
+ std::string odex_filename(OatFile::DexFilenameToOdexFilename(filename.c_str()));
+ UniquePtr<const OatFile> oat_file(OatFile::Open(odex_filename, odex_filename, NULL));
+ if (oat_file.get() != NULL) {
+ ScopedObjectAccess soa(env);
+ const art::OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename.c_str());
+ if (oat_dex_file == NULL) {
+ if (debug_logging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded GetOatDexFile failed";
+ }
+ } else {
+ uint32_t location_checksum;
+ // If we have no classes.dex checksum such as in a user build, assume up-to-date.
+ if (!DexFile::GetChecksum(filename.c_str(), location_checksum)) {
+ if (debug_logging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded ignoring precompiled stripped file: "
+ << filename.c_str();
+ }
+ return JNI_FALSE;
+ }
+ if (ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum)) {
+ if (debug_logging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded precompiled file " << odex_filename
+ << " is up-to-date checksum compared to " << filename.c_str();
+ }
+ return JNI_FALSE;
+ }
+ }
+ }
+
+ // Check if we have an oat file in the cache
+ std::string cache_location(GetDalvikCacheFilenameOrDie(filename.c_str()));
+ oat_file.reset(OatFile::Open(cache_location, filename.c_str(), NULL));
+ if (oat_file.get() == NULL) {
+ LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
+ << " does not exist for " << filename.c_str();
+ return JNI_TRUE;
+ }
+
+ gc::Heap* heap = runtime->GetHeap();
+ const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
+ // TODO: C++0x auto
+ typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+ for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+ if ((*it)->IsImageSpace()) {
+ // TODO: Ensure this works with multiple image spaces.
+ const ImageHeader& image_header = (*it)->AsImageSpace()->GetImageHeader();
+ if (oat_file->GetOatHeader().GetImageFileLocationOatChecksum() != image_header.GetOatChecksum()) {
+ ScopedObjectAccess soa(env);
+ LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
+ << " has out-of-date oat checksum compared to "
+ << image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8();
+ return JNI_TRUE;
+ }
+ if (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin()
+ != reinterpret_cast<uint32_t>(image_header.GetOatDataBegin())) {
+ ScopedObjectAccess soa(env);
+ LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
+ << " has out-of-date oat begin compared to "
+ << image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8();
+ return JNI_TRUE;
+ }
+ }
+ }
+
+ ScopedObjectAccess soa(env);
+ uint32_t location_checksum;
+ if (!DexFile::GetChecksum(filename.c_str(), location_checksum)) {
+ LOG(ERROR) << "DexFile_isDexOptNeeded failed to compute checksum of " << filename.c_str();
+ return JNI_TRUE;
+ }
+
+ if (!ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum)) {
+ LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
+ << " has out-of-date checksum compared to " << filename.c_str();
+ return JNI_TRUE;
+ }
+
+ if (debug_logging) {
+ LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
+ << " is up-to-date for " << filename.c_str();
+ }
+ return JNI_FALSE;
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(DexFile, closeDexFile, "(I)V"),
+ NATIVE_METHOD(DexFile, defineClassNative, "(Ljava/lang/String;Ljava/lang/ClassLoader;I)Ljava/lang/Class;"),
+ NATIVE_METHOD(DexFile, getClassNameList, "(I)[Ljava/lang/String;"),
+ NATIVE_METHOD(DexFile, isDexOptNeeded, "(Ljava/lang/String;)Z"),
+ NATIVE_METHOD(DexFile, openDexFile, "(Ljava/lang/String;Ljava/lang/String;I)I"),
+};
+
+void register_dalvik_system_DexFile(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("dalvik/system/DexFile");
+}
+
+} // namespace art
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
new file mode 100644
index 0000000..992998e
--- /dev/null
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include <unistd.h>
+
+#include "class_linker.h"
+#include "common_throws.h"
+#include "debugger.h"
+#include "hprof/hprof.h"
+#include "jni_internal.h"
+#include "mirror/class.h"
+#include "ScopedUtfChars.h"
+#include "scoped_thread_state_change.h"
+#include "toStringArray.h"
+#include "trace.h"
+
+namespace art {
+
+static jobjectArray VMDebug_getVmFeatureList(JNIEnv* env, jclass) {
+ std::vector<std::string> features;
+ features.push_back("method-trace-profiling");
+ features.push_back("method-trace-profiling-streaming");
+ features.push_back("hprof-heap-dump");
+ features.push_back("hprof-heap-dump-streaming");
+ return toStringArray(env, features);
+}
+
+static void VMDebug_startAllocCounting(JNIEnv*, jclass) {
+ Runtime::Current()->SetStatsEnabled(true);
+}
+
+static void VMDebug_stopAllocCounting(JNIEnv*, jclass) {
+ Runtime::Current()->SetStatsEnabled(false);
+}
+
+static jint VMDebug_getAllocCount(JNIEnv*, jclass, jint kind) {
+ return Runtime::Current()->GetStat(kind);
+}
+
+static void VMDebug_resetAllocCount(JNIEnv*, jclass, jint kinds) {
+ Runtime::Current()->ResetStats(kinds);
+}
+
+static void VMDebug_startMethodTracingDdmsImpl(JNIEnv*, jclass, jint bufferSize, jint flags) {
+ Trace::Start("[DDMS]", -1, bufferSize, flags, true);
+}
+
+static void VMDebug_startMethodTracingFd(JNIEnv* env, jclass, jstring javaTraceFilename,
+ jobject javaFd, jint bufferSize, jint flags) {
+ int originalFd = jniGetFDFromFileDescriptor(env, javaFd);
+ if (originalFd < 0) {
+ return;
+ }
+
+ int fd = dup(originalFd);
+ if (fd < 0) {
+ ScopedObjectAccess soa(env);
+ ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+ soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/RuntimeException;",
+ "dup(%d) failed: %s", originalFd, strerror(errno));
+ return;
+ }
+
+ ScopedUtfChars traceFilename(env, javaTraceFilename);
+ if (traceFilename.c_str() == NULL) {
+ return;
+ }
+ Trace::Start(traceFilename.c_str(), fd, bufferSize, flags, false);
+}
+
+static void VMDebug_startMethodTracingFilename(JNIEnv* env, jclass, jstring javaTraceFilename,
+ jint bufferSize, jint flags) {
+ ScopedUtfChars traceFilename(env, javaTraceFilename);
+ if (traceFilename.c_str() == NULL) {
+ return;
+ }
+ Trace::Start(traceFilename.c_str(), -1, bufferSize, flags, false);
+}
+
+static jboolean VMDebug_isMethodTracingActive(JNIEnv*, jclass) {
+ return Trace::IsMethodTracingActive();
+}
+
+static void VMDebug_stopMethodTracing(JNIEnv*, jclass) {
+ Trace::Stop();
+}
+
+static void VMDebug_startEmulatorTracing(JNIEnv*, jclass) {
+ UNIMPLEMENTED(WARNING);
+ //dvmEmulatorTraceStart();
+}
+
+static void VMDebug_stopEmulatorTracing(JNIEnv*, jclass) {
+ UNIMPLEMENTED(WARNING);
+ //dvmEmulatorTraceStop();
+}
+
+static jboolean VMDebug_isDebuggerConnected(JNIEnv*, jclass) {
+ return Dbg::IsDebuggerActive();
+}
+
+static jboolean VMDebug_isDebuggingEnabled(JNIEnv*, jclass) {
+ return Dbg::IsJdwpConfigured();
+}
+
+static jlong VMDebug_lastDebuggerActivity(JNIEnv*, jclass) {
+ return Dbg::LastDebuggerActivity();
+}
+
+static void ThrowUnsupportedOperationException(JNIEnv* env) {
+ ScopedObjectAccess soa(env);
+ ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+ soa.Self()->ThrowNewException(throw_location, "Ljava/lang/UnsupportedOperationException;", NULL);
+}
+
+static void VMDebug_startInstructionCounting(JNIEnv* env, jclass) {
+ ThrowUnsupportedOperationException(env);
+}
+
+static void VMDebug_stopInstructionCounting(JNIEnv* env, jclass) {
+ ThrowUnsupportedOperationException(env);
+}
+
+static void VMDebug_getInstructionCount(JNIEnv* env, jclass, jintArray /*javaCounts*/) {
+ ThrowUnsupportedOperationException(env);
+}
+
+static void VMDebug_resetInstructionCount(JNIEnv* env, jclass) {
+ ThrowUnsupportedOperationException(env);
+}
+
+static void VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) {
+ ScopedObjectAccess soa(env);
+ return Runtime::Current()->GetClassLinker()->DumpAllClasses(flags);
+}
+
+static jint VMDebug_getLoadedClassCount(JNIEnv*, jclass) {
+ return Runtime::Current()->GetClassLinker()->NumLoadedClasses();
+}
+
+/*
+ * Returns the thread-specific CPU-time clock value for the current thread,
+ * or -1 if the feature isn't supported.
+ */
+static jlong VMDebug_threadCpuTimeNanos(JNIEnv*, jclass) {
+ return ThreadCpuNanoTime();
+}
+
+/*
+ * static void dumpHprofData(String fileName, FileDescriptor fd)
+ *
+ * Cause "hprof" data to be dumped. We can throw an IOException if an
+ * error occurs during file handling.
+ */
+static void VMDebug_dumpHprofData(JNIEnv* env, jclass, jstring javaFilename, jobject javaFd) {
+ // Only one of these may be NULL.
+ if (javaFilename == NULL && javaFd == NULL) {
+ ScopedObjectAccess soa(env);
+ ThrowNullPointerException(NULL, "fileName == null && fd == null");
+ return;
+ }
+
+ std::string filename;
+ if (javaFilename != NULL) {
+ ScopedUtfChars chars(env, javaFilename);
+ if (env->ExceptionCheck()) {
+ return;
+ }
+ filename = chars.c_str();
+ } else {
+ filename = "[fd]";
+ }
+
+ int fd = -1;
+ if (javaFd != NULL) {
+ fd = jniGetFDFromFileDescriptor(env, javaFd);
+ if (fd < 0) {
+ ScopedObjectAccess soa(env);
+ ThrowRuntimeException("Invalid file descriptor");
+ return;
+ }
+ }
+
+ hprof::DumpHeap(filename.c_str(), fd, false);
+}
+
+static void VMDebug_dumpHprofDataDdms(JNIEnv*, jclass) {
+ hprof::DumpHeap("[DDMS]", -1, true);
+}
+
+static void VMDebug_dumpReferenceTables(JNIEnv* env, jclass) {
+ ScopedObjectAccess soa(env);
+ LOG(INFO) << "--- reference table dump ---";
+
+ soa.Env()->DumpReferenceTables(LOG(INFO));
+ soa.Vm()->DumpReferenceTables(LOG(INFO));
+
+ LOG(INFO) << "---";
+}
+
+static void VMDebug_crash(JNIEnv*, jclass) {
+ LOG(FATAL) << "Crashing runtime on request";
+}
+
+static void VMDebug_infopoint(JNIEnv*, jclass, jint id) {
+ LOG(INFO) << "VMDebug infopoint " << id << " hit";
+}
+
+static jlong VMDebug_countInstancesOfClass(JNIEnv* env, jclass, jclass javaClass,
+ jboolean countAssignable) {
+ ScopedObjectAccess soa(env);
+ mirror::Class* c = soa.Decode<mirror::Class*>(javaClass);
+ if (c == NULL) {
+ return 0;
+ }
+ std::vector<mirror::Class*> classes;
+ classes.push_back(c);
+ uint64_t count = 0;
+ Runtime::Current()->GetHeap()->CountInstances(classes, countAssignable, &count);
+ return count;
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"),
+ NATIVE_METHOD(VMDebug, crash, "()V"),
+ NATIVE_METHOD(VMDebug, dumpHprofData, "(Ljava/lang/String;Ljava/io/FileDescriptor;)V"),
+ NATIVE_METHOD(VMDebug, dumpHprofDataDdms, "()V"),
+ NATIVE_METHOD(VMDebug, dumpReferenceTables, "()V"),
+ NATIVE_METHOD(VMDebug, getAllocCount, "(I)I"),
+ NATIVE_METHOD(VMDebug, getInstructionCount, "([I)V"),
+ NATIVE_METHOD(VMDebug, getLoadedClassCount, "()I"),
+ NATIVE_METHOD(VMDebug, getVmFeatureList, "()[Ljava/lang/String;"),
+ NATIVE_METHOD(VMDebug, infopoint, "(I)V"),
+ NATIVE_METHOD(VMDebug, isDebuggerConnected, "()Z"),
+ NATIVE_METHOD(VMDebug, isDebuggingEnabled, "()Z"),
+ NATIVE_METHOD(VMDebug, isMethodTracingActive, "()Z"),
+ NATIVE_METHOD(VMDebug, lastDebuggerActivity, "()J"),
+ NATIVE_METHOD(VMDebug, printLoadedClasses, "(I)V"),
+ NATIVE_METHOD(VMDebug, resetAllocCount, "(I)V"),
+ NATIVE_METHOD(VMDebug, resetInstructionCount, "()V"),
+ NATIVE_METHOD(VMDebug, startAllocCounting, "()V"),
+ NATIVE_METHOD(VMDebug, startEmulatorTracing, "()V"),
+ NATIVE_METHOD(VMDebug, startInstructionCounting, "()V"),
+ NATIVE_METHOD(VMDebug, startMethodTracingDdmsImpl, "(II)V"),
+ NATIVE_METHOD(VMDebug, startMethodTracingFd, "(Ljava/lang/String;Ljava/io/FileDescriptor;II)V"),
+ NATIVE_METHOD(VMDebug, startMethodTracingFilename, "(Ljava/lang/String;II)V"),
+ NATIVE_METHOD(VMDebug, stopAllocCounting, "()V"),
+ NATIVE_METHOD(VMDebug, stopEmulatorTracing, "()V"),
+ NATIVE_METHOD(VMDebug, stopInstructionCounting, "()V"),
+ NATIVE_METHOD(VMDebug, stopMethodTracing, "()V"),
+ NATIVE_METHOD(VMDebug, threadCpuTimeNanos, "()J"),
+};
+
+void register_dalvik_system_VMDebug(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("dalvik/system/VMDebug");
+}
+
+} // namespace art
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
new file mode 100644
index 0000000..ce3cc93
--- /dev/null
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <limits.h>
+
+#include "class_linker.h"
+#include "common_throws.h"
+#include "debugger.h"
+#include "dex_file-inl.h"
+#include "gc/allocator/dlmalloc.h"
+#include "gc/space/dlmalloc_space.h"
+#include "jni_internal.h"
+#include "mirror/class-inl.h"
+#include "mirror/object.h"
+#include "mirror/object-inl.h"
+#include "object_utils.h"
+#include "scoped_thread_state_change.h"
+#include "thread.h"
+#include "thread_list.h"
+#include "toStringArray.h"
+
+namespace art {
+
+static jfloat VMRuntime_getTargetHeapUtilization(JNIEnv*, jobject) {
+ return Runtime::Current()->GetHeap()->GetTargetHeapUtilization();
+}
+
+static void VMRuntime_nativeSetTargetHeapUtilization(JNIEnv*, jobject, jfloat target) {
+ Runtime::Current()->GetHeap()->SetTargetHeapUtilization(target);
+}
+
+static void VMRuntime_startJitCompilation(JNIEnv*, jobject) {
+}
+
+static void VMRuntime_disableJitCompilation(JNIEnv*, jobject) {
+}
+
+static jobject VMRuntime_newNonMovableArray(JNIEnv* env, jobject, jclass javaElementClass, jint length) {
+ ScopedObjectAccess soa(env);
+#ifdef MOVING_GARBAGE_COLLECTOR
+ // TODO: right now, we don't have a copying collector, so there's no need
+ // to do anything special here, but we ought to pass the non-movability
+ // through to the allocator.
+ UNIMPLEMENTED(FATAL);
+#endif
+
+ mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+ if (element_class == NULL) {
+ ThrowNullPointerException(NULL, "element class == null");
+ return NULL;
+ }
+ if (length < 0) {
+ ThrowNegativeArraySizeException(length);
+ return NULL;
+ }
+
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ std::string descriptor;
+ descriptor += "[";
+ descriptor += ClassHelper(element_class).GetDescriptor();
+ mirror::Class* array_class = class_linker->FindClass(descriptor.c_str(), NULL);
+ mirror::Array* result = mirror::Array::Alloc(soa.Self(), array_class, length);
+ if (result == NULL) {
+ return NULL;
+ }
+ return soa.AddLocalReference<jobject>(result);
+}
+
+static jlong VMRuntime_addressOf(JNIEnv* env, jobject, jobject javaArray) {
+ if (javaArray == NULL) { // Most likely allocation failed
+ return 0;
+ }
+ ScopedObjectAccess soa(env);
+ mirror::Array* array = soa.Decode<mirror::Array*>(javaArray);
+ if (!array->IsArrayInstance()) {
+ ThrowIllegalArgumentException(NULL, "not an array");
+ return 0;
+ }
+ // TODO: we should also check that this is a non-movable array.
+ return reinterpret_cast<uintptr_t>(array->GetRawData(array->GetClass()->GetComponentSize()));
+}
+
+static void VMRuntime_clearGrowthLimit(JNIEnv*, jobject) {
+ Runtime::Current()->GetHeap()->ClearGrowthLimit();
+}
+
+static jboolean VMRuntime_isDebuggerActive(JNIEnv*, jobject) {
+ return Dbg::IsDebuggerActive();
+}
+
+static jobjectArray VMRuntime_properties(JNIEnv* env, jobject) {
+ return toStringArray(env, Runtime::Current()->GetProperties());
+}
+
+// This is for backward compatibility with dalvik which returned the
+// meaningless "." when no boot classpath or classpath was
+// specified. Unfortunately, some tests were using java.class.path to
+// lookup relative file locations, so they are counting on this to be
+// ".", presumably some applications or libraries could have as well.
+static const char* DefaultToDot(const std::string& class_path) {
+ return class_path.empty() ? "." : class_path.c_str();
+}
+
+static jstring VMRuntime_bootClassPath(JNIEnv* env, jobject) {
+ return env->NewStringUTF(DefaultToDot(Runtime::Current()->GetBootClassPathString()));
+}
+
+static jstring VMRuntime_classPath(JNIEnv* env, jobject) {
+ return env->NewStringUTF(DefaultToDot(Runtime::Current()->GetClassPathString()));
+}
+
+static jstring VMRuntime_vmVersion(JNIEnv* env, jobject) {
+ return env->NewStringUTF(Runtime::Current()->GetVersion());
+}
+
+static jstring VMRuntime_vmLibrary(JNIEnv* env, jobject) {
+ return env->NewStringUTF(kIsDebugBuild ? "libartd.so" : "libart.so");
+}
+
+#if !defined(ART_USE_PORTABLE_COMPILER)
+static void DisableCheckJniCallback(Thread* t, void*) {
+ t->GetJniEnv()->SetCheckJniEnabled(false);
+}
+#endif
+
+static void VMRuntime_setTargetSdkVersion(JNIEnv* env, jobject, jint targetSdkVersion) {
+ // This is the target SDK version of the app we're about to run.
+ // Note that targetSdkVersion may be CUR_DEVELOPMENT (10000).
+ // Note that targetSdkVersion may be 0, meaning "current".
+ if (targetSdkVersion > 0 && targetSdkVersion <= 13 /* honeycomb-mr2 */) {
+ Runtime* runtime = Runtime::Current();
+ JavaVMExt* vm = runtime->GetJavaVM();
+
+#if !defined(ART_USE_PORTABLE_COMPILER)
+ if (vm->check_jni) {
+ LOG(WARNING) << "Turning off CheckJNI so we can turn on JNI app bug workarounds...";
+ Thread* self = static_cast<JNIEnvExt*>(env)->self;
+ MutexLock mu(self, *Locks::thread_list_lock_);
+ vm->SetCheckJniEnabled(false);
+ runtime->GetThreadList()->ForEach(DisableCheckJniCallback, NULL);
+ }
+
+ LOG(INFO) << "Turning on JNI app bug workarounds for target SDK version "
+ << targetSdkVersion << "...";
+
+ vm->work_around_app_jni_bugs = true;
+#else
+ UNUSED(env);
+ LOG(WARNING) << "LLVM does not work-around app jni bugs.";
+ vm->work_around_app_jni_bugs = false;
+#endif
+ }
+}
+
+static void VMRuntime_trimHeap(JNIEnv*, jobject) {
+ uint64_t start_ns = NanoTime();
+
+ // Trim the managed heap.
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ gc::space::DlMallocSpace* alloc_space = heap->GetAllocSpace();
+ size_t alloc_space_size = alloc_space->Size();
+ float managed_utilization =
+ static_cast<float>(alloc_space->GetBytesAllocated()) / alloc_space_size;
+ size_t managed_reclaimed = heap->Trim();
+
+ uint64_t gc_heap_end_ns = NanoTime();
+
+ // Trim the native heap.
+ dlmalloc_trim(0);
+ size_t native_reclaimed = 0;
+ dlmalloc_inspect_all(DlmallocMadviseCallback, &native_reclaimed);
+
+ uint64_t end_ns = NanoTime();
+
+ LOG(INFO) << "Heap trim of managed (duration=" << PrettyDuration(gc_heap_end_ns - start_ns)
+ << ", advised=" << PrettySize(managed_reclaimed) << ") and native (duration="
+ << PrettyDuration(end_ns - gc_heap_end_ns) << ", advised=" << PrettySize(native_reclaimed)
+ << ") heaps. Managed heap utilization of " << static_cast<int>(100 * managed_utilization)
+ << "%.";
+}
+
+static void VMRuntime_concurrentGC(JNIEnv* env, jobject) {
+ Thread* self = static_cast<JNIEnvExt*>(env)->self;
+ Runtime::Current()->GetHeap()->ConcurrentGC(self);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(VMRuntime, addressOf, "(Ljava/lang/Object;)J"),
+ NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
+ NATIVE_METHOD(VMRuntime, classPath, "()Ljava/lang/String;"),
+ NATIVE_METHOD(VMRuntime, clearGrowthLimit, "()V"),
+ NATIVE_METHOD(VMRuntime, concurrentGC, "()V"),
+ NATIVE_METHOD(VMRuntime, disableJitCompilation, "()V"),
+ NATIVE_METHOD(VMRuntime, getTargetHeapUtilization, "()F"),
+ NATIVE_METHOD(VMRuntime, isDebuggerActive, "()Z"),
+ NATIVE_METHOD(VMRuntime, nativeSetTargetHeapUtilization, "(F)V"),
+ NATIVE_METHOD(VMRuntime, newNonMovableArray, "(Ljava/lang/Class;I)Ljava/lang/Object;"),
+ NATIVE_METHOD(VMRuntime, properties, "()[Ljava/lang/String;"),
+ NATIVE_METHOD(VMRuntime, setTargetSdkVersion, "(I)V"),
+ NATIVE_METHOD(VMRuntime, startJitCompilation, "()V"),
+ NATIVE_METHOD(VMRuntime, trimHeap, "()V"),
+ NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"),
+ NATIVE_METHOD(VMRuntime, vmLibrary, "()Ljava/lang/String;"),
+};
+
+void register_dalvik_system_VMRuntime(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("dalvik/system/VMRuntime");
+}
+
+} // namespace art
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
new file mode 100644
index 0000000..1a80d62
--- /dev/null
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni_internal.h"
+#include "nth_caller_visitor.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
+#include "mirror/object-inl.h"
+#include "scoped_thread_state_change.h"
+#include "thread_list.h"
+
+namespace art {
+
+static jobject GetThreadStack(JNIEnv* env, jobject peer) {
+ {
+ ScopedObjectAccess soa(env);
+ if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
+ return soa.Self()->CreateInternalStackTrace(soa);
+ }
+ }
+ // Suspend thread to build stack trace.
+ bool timed_out;
+ Thread* thread = Thread::SuspendForDebugger(peer, true, &timed_out);
+ if (thread != NULL) {
+ jobject trace;
+ {
+ ScopedObjectAccess soa(env);
+ trace = thread->CreateInternalStackTrace(soa);
+ }
+ // Restart suspended thread.
+ Runtime::Current()->GetThreadList()->Resume(thread, true);
+ return trace;
+ } else {
+ if (timed_out) {
+ LOG(ERROR) << "Trying to get thread's stack failed as the thread failed to suspend within a "
+ "generous timeout.";
+ }
+ return NULL;
+ }
+}
+
+static jint VMStack_fillStackTraceElements(JNIEnv* env, jclass, jobject javaThread,
+ jobjectArray javaSteArray) {
+ jobject trace = GetThreadStack(env, javaThread);
+ if (trace == NULL) {
+ return 0;
+ }
+ int32_t depth;
+ Thread::InternalStackTraceToStackTraceElementArray(env, trace, javaSteArray, &depth);
+ return depth;
+}
+
+// Returns the defining class loader of the caller's caller.
+static jobject VMStack_getCallingClassLoader(JNIEnv* env, jclass) {
+ ScopedObjectAccess soa(env);
+ NthCallerVisitor visitor(soa.Self(), 2);
+ visitor.WalkStack();
+ return soa.AddLocalReference<jobject>(visitor.caller->GetDeclaringClass()->GetClassLoader());
+}
+
+static jobject VMStack_getClosestUserClassLoader(JNIEnv* env, jclass, jobject javaBootstrap,
+ jobject javaSystem) {
+ struct ClosestUserClassLoaderVisitor : public StackVisitor {
+ ClosestUserClassLoaderVisitor(Thread* thread, mirror::Object* bootstrap, mirror::Object* system)
+ : StackVisitor(thread, NULL), bootstrap(bootstrap), system(system), class_loader(NULL) {}
+
+ bool VisitFrame() {
+ DCHECK(class_loader == NULL);
+ mirror::Class* c = GetMethod()->GetDeclaringClass();
+ mirror::Object* cl = c->GetClassLoader();
+ if (cl != NULL && cl != bootstrap && cl != system) {
+ class_loader = cl;
+ return false;
+ }
+ return true;
+ }
+
+ mirror::Object* bootstrap;
+ mirror::Object* system;
+ mirror::Object* class_loader;
+ };
+ ScopedObjectAccess soa(env);
+ mirror::Object* bootstrap = soa.Decode<mirror::Object*>(javaBootstrap);
+ mirror::Object* system = soa.Decode<mirror::Object*>(javaSystem);
+ ClosestUserClassLoaderVisitor visitor(soa.Self(), bootstrap, system);
+ visitor.WalkStack();
+ return soa.AddLocalReference<jobject>(visitor.class_loader);
+}
+
+// Returns the class of the caller's caller's caller.
+static jclass VMStack_getStackClass2(JNIEnv* env, jclass) {
+ ScopedObjectAccess soa(env);
+ NthCallerVisitor visitor(soa.Self(), 3);
+ visitor.WalkStack();
+ return soa.AddLocalReference<jclass>(visitor.caller->GetDeclaringClass());
+}
+
+static jobjectArray VMStack_getThreadStackTrace(JNIEnv* env, jclass, jobject javaThread) {
+ jobject trace = GetThreadStack(env, javaThread);
+ if (trace == NULL) {
+ return NULL;
+ }
+ return Thread::InternalStackTraceToStackTraceElementArray(env, trace);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(VMStack, fillStackTraceElements, "(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I"),
+ NATIVE_METHOD(VMStack, getCallingClassLoader, "()Ljava/lang/ClassLoader;"),
+ NATIVE_METHOD(VMStack, getClosestUserClassLoader, "(Ljava/lang/ClassLoader;Ljava/lang/ClassLoader;)Ljava/lang/ClassLoader;"),
+ NATIVE_METHOD(VMStack, getStackClass2, "()Ljava/lang/Class;"),
+ NATIVE_METHOD(VMStack, getThreadStackTrace, "(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;"),
+};
+
+void register_dalvik_system_VMStack(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("dalvik/system/VMStack");
+}
+
+} // namespace art
diff --git a/runtime/native/dalvik_system_Zygote.cc b/runtime/native/dalvik_system_Zygote.cc
new file mode 100644
index 0000000..9b995f4
--- /dev/null
+++ b/runtime/native/dalvik_system_Zygote.cc
@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
+#include <sys/mount.h>
+#include <linux/fs.h>
+
+#include <grp.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "cutils/fs.h"
+#include "cutils/multiuser.h"
+#include "cutils/sched_policy.h"
+#include "debugger.h"
+#include "jni_internal.h"
+#include "JNIHelp.h"
+#include "ScopedLocalRef.h"
+#include "ScopedPrimitiveArray.h"
+#include "ScopedUtfChars.h"
+#include "thread.h"
+
+#if defined(HAVE_PRCTL)
+#include <sys/prctl.h>
+#endif
+
+#include <selinux/android.h>
+
+#if defined(__linux__)
+#include <sys/personality.h>
+#include <sys/utsname.h>
+#include <sys/capability.h>
+#endif
+
+namespace art {
+
+static pid_t gSystemServerPid = 0;
+
+// Must match values in dalvik.system.Zygote.
+enum MountExternalKind {
+ MOUNT_EXTERNAL_NONE = 0,
+ MOUNT_EXTERNAL_SINGLEUSER = 1,
+ MOUNT_EXTERNAL_MULTIUSER = 2,
+ MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
+};
+
+// This signal handler is for zygote mode, since the zygote must reap its children
+static void SigChldHandler(int /*signal_number*/) {
+ pid_t pid;
+ int status;
+
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ // Log process-death status that we care about. In general it is
+ // not safe to call LOG(...) from a signal handler because of
+ // possible reentrancy. However, we know a priori that the
+ // current implementation of LOG() is safe to call from a SIGCHLD
+ // handler in the zygote process. If the LOG() implementation
+ // changes its locking strategy or its use of syscalls within the
+ // lazy-init critical section, its use here may become unsafe.
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status)) {
+ LOG(INFO) << "Process " << pid << " exited cleanly (" << WEXITSTATUS(status) << ")";
+ } else if (false) {
+ LOG(INFO) << "Process " << pid << " exited cleanly (" << WEXITSTATUS(status) << ")";
+ }
+ } else if (WIFSIGNALED(status)) {
+ if (WTERMSIG(status) != SIGKILL) {
+ LOG(INFO) << "Process " << pid << " terminated by signal (" << WTERMSIG(status) << ")";
+ } else if (false) {
+ LOG(INFO) << "Process " << pid << " terminated by signal (" << WTERMSIG(status) << ")";
+ }
+#ifdef WCOREDUMP
+ if (WCOREDUMP(status)) {
+ LOG(INFO) << "Process " << pid << " dumped core";
+ }
+#endif /* ifdef WCOREDUMP */
+ }
+
+ // If the just-crashed process is the system_server, bring down zygote
+ // so that it is restarted by init and system server will be restarted
+ // from there.
+ if (pid == gSystemServerPid) {
+ LOG(ERROR) << "Exit zygote because system server (" << pid << ") has terminated";
+ kill(getpid(), SIGKILL);
+ }
+ }
+
+ if (pid < 0) {
+ PLOG(WARNING) << "Zygote SIGCHLD error in waitpid";
+ }
+}
+
+// Configures the SIGCHLD handler for the zygote process. This is configured
+// very late, because earlier in the runtime we may fork() and exec()
+// other processes, and we want to waitpid() for those rather than
+// have them be harvested immediately.
+//
+// This ends up being called repeatedly before each fork(), but there's
+// no real harm in that.
+static void SetSigChldHandler() {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SigChldHandler;
+
+ int err = sigaction(SIGCHLD, &sa, NULL);
+ if (err < 0) {
+ PLOG(WARNING) << "Error setting SIGCHLD handler";
+ }
+}
+
+// Sets the SIGCHLD handler back to default behavior in zygote children.
+static void UnsetSigChldHandler() {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+
+ int err = sigaction(SIGCHLD, &sa, NULL);
+ if (err < 0) {
+ PLOG(WARNING) << "Error unsetting SIGCHLD handler";
+ }
+}
+
+// Calls POSIX setgroups() using the int[] object as an argument.
+// A NULL argument is tolerated.
+static void SetGids(JNIEnv* env, jintArray javaGids) {
+ if (javaGids == NULL) {
+ return;
+ }
+
+ COMPILE_ASSERT(sizeof(gid_t) == sizeof(jint), sizeof_gid_and_jint_are_differerent);
+ ScopedIntArrayRO gids(env, javaGids);
+ CHECK(gids.get() != NULL);
+ int rc = setgroups(gids.size(), reinterpret_cast<const gid_t*>(&gids[0]));
+ if (rc == -1) {
+ PLOG(FATAL) << "setgroups failed";
+ }
+}
+
+// Sets the resource limits via setrlimit(2) for the values in the
+// two-dimensional array of integers that's passed in. The second dimension
+// contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
+// treated as an empty array.
+static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) {
+ if (javaRlimits == NULL) {
+ return;
+ }
+
+ rlimit rlim;
+ memset(&rlim, 0, sizeof(rlim));
+
+ for (int i = 0; i < env->GetArrayLength(javaRlimits); ++i) {
+ ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i));
+ ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get()));
+ if (javaRlimit.size() != 3) {
+ LOG(FATAL) << "rlimits array must have a second dimension of size 3";
+ }
+
+ rlim.rlim_cur = javaRlimit[1];
+ rlim.rlim_max = javaRlimit[2];
+
+ int rc = setrlimit(javaRlimit[0], &rlim);
+ if (rc == -1) {
+ PLOG(FATAL) << "setrlimit(" << javaRlimit[0] << ", "
+ << "{" << rlim.rlim_cur << ", " << rlim.rlim_max << "}) failed";
+ }
+ }
+}
+
+#if defined(HAVE_ANDROID_OS)
+
+// The debug malloc library needs to know whether it's the zygote or a child.
+extern "C" int gMallocLeakZygoteChild;
+
+static void EnableDebugger() {
+ // To let a non-privileged gdbserver attach to this
+ // process, we must set our dumpable flag.
+ if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
+ PLOG(ERROR) << "prctl(PR_SET_DUMPABLE) failed for pid " << getpid();
+ }
+ // We don't want core dumps, though, so set the core dump size to 0.
+ rlimit rl;
+ rl.rlim_cur = 0;
+ rl.rlim_max = RLIM_INFINITY;
+ if (setrlimit(RLIMIT_CORE, &rl) == -1) {
+ PLOG(ERROR) << "setrlimit(RLIMIT_CORE) failed for pid " << getpid();
+ }
+}
+
+static void EnableKeepCapabilities() {
+ int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+ if (rc == -1) {
+ PLOG(FATAL) << "prctl(PR_SET_KEEPCAPS) failed";
+ }
+}
+
+static void DropCapabilitiesBoundingSet() {
+ for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
+ if (i == CAP_NET_RAW) {
+ // Don't break /system/bin/ping
+ continue;
+ }
+ int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+ if (rc == -1) {
+ if (errno == EINVAL) {
+ PLOG(ERROR) << "prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
+ << "your kernel is compiled with file capabilities support";
+ } else {
+ PLOG(FATAL) << "prctl(PR_CAPBSET_DROP) failed";
+ }
+ }
+ }
+}
+
+static void SetCapabilities(int64_t permitted, int64_t effective) {
+ __user_cap_header_struct capheader;
+ __user_cap_data_struct capdata;
+
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+
+ capheader.version = _LINUX_CAPABILITY_VERSION;
+ capheader.pid = 0;
+
+ capdata.effective = effective;
+ capdata.permitted = permitted;
+
+ if (capset(&capheader, &capdata) != 0) {
+ PLOG(FATAL) << "capset(" << permitted << ", " << effective << ") failed";
+ }
+}
+
+static void SetSchedulerPolicy() {
+ errno = -set_sched_policy(0, SP_DEFAULT);
+ if (errno != 0) {
+ PLOG(FATAL) << "set_sched_policy(0, SP_DEFAULT) failed";
+ }
+}
+
+#else
+
+static int gMallocLeakZygoteChild = 0;
+
+static void EnableDebugger() {}
+static void EnableKeepCapabilities() {}
+static void DropCapabilitiesBoundingSet() {};
+static void SetCapabilities(int64_t, int64_t) {}
+static void SetSchedulerPolicy() {}
+
+#endif
+
+static void EnableDebugFeatures(uint32_t debug_flags) {
+ // Must match values in dalvik.system.Zygote.
+ enum {
+ DEBUG_ENABLE_DEBUGGER = 1,
+ DEBUG_ENABLE_CHECKJNI = 1 << 1,
+ DEBUG_ENABLE_ASSERT = 1 << 2,
+ DEBUG_ENABLE_SAFEMODE = 1 << 3,
+ DEBUG_ENABLE_JNI_LOGGING = 1 << 4,
+ };
+
+ if ((debug_flags & DEBUG_ENABLE_CHECKJNI) != 0) {
+ Runtime* runtime = Runtime::Current();
+ JavaVMExt* vm = runtime->GetJavaVM();
+ if (!vm->check_jni) {
+ LOG(DEBUG) << "Late-enabling -Xcheck:jni";
+ vm->SetCheckJniEnabled(true);
+ // There's only one thread running at this point, so only one JNIEnv to fix up.
+ Thread::Current()->GetJniEnv()->SetCheckJniEnabled(true);
+ } else {
+ LOG(DEBUG) << "Not late-enabling -Xcheck:jni (already on)";
+ }
+ debug_flags &= ~DEBUG_ENABLE_CHECKJNI;
+ }
+
+ if ((debug_flags & DEBUG_ENABLE_JNI_LOGGING) != 0) {
+ gLogVerbosity.third_party_jni = true;
+ debug_flags &= ~DEBUG_ENABLE_JNI_LOGGING;
+ }
+
+ Dbg::SetJdwpAllowed((debug_flags & DEBUG_ENABLE_DEBUGGER) != 0);
+ if ((debug_flags & DEBUG_ENABLE_DEBUGGER) != 0) {
+ EnableDebugger();
+ }
+ debug_flags &= ~DEBUG_ENABLE_DEBUGGER;
+
+ // These two are for backwards compatibility with Dalvik.
+ debug_flags &= ~DEBUG_ENABLE_ASSERT;
+ debug_flags &= ~DEBUG_ENABLE_SAFEMODE;
+
+ if (debug_flags != 0) {
+ LOG(ERROR) << StringPrintf("Unknown bits set in debug_flags: %#x", debug_flags);
+ }
+}
+
+// Create a private mount namespace and bind mount appropriate emulated
+// storage for the given user.
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode) {
+ if (mount_mode == MOUNT_EXTERNAL_NONE) {
+ return true;
+ }
+
+ // See storage config details at http://source.android.com/tech/storage/
+ userid_t user_id = multiuser_get_user_id(uid);
+
+ // Create a second private mount namespace for our process
+ if (unshare(CLONE_NEWNS) == -1) {
+ PLOG(WARNING) << "Failed to unshare()";
+ return false;
+ }
+
+ // Create bind mounts to expose external storage
+ if (mount_mode == MOUNT_EXTERNAL_MULTIUSER || mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+ // These paths must already be created by init.rc
+ const char* source = getenv("EMULATED_STORAGE_SOURCE");
+ const char* target = getenv("EMULATED_STORAGE_TARGET");
+ const char* legacy = getenv("EXTERNAL_STORAGE");
+ if (source == NULL || target == NULL || legacy == NULL) {
+ LOG(WARNING) << "Storage environment undefined; unable to provide external storage";
+ return false;
+ }
+
+ // Prepare source paths
+
+ // /mnt/shell/emulated/0
+ std::string source_user(StringPrintf("%s/%d", source, user_id));
+ // /mnt/shell/emulated/obb
+ std::string source_obb(StringPrintf("%s/obb", source));
+ // /storage/emulated/0
+ std::string target_user(StringPrintf("%s/%d", target, user_id));
+
+ if (fs_prepare_dir(source_user.c_str(), 0000, 0, 0) == -1
+ || fs_prepare_dir(source_obb.c_str(), 0000, 0, 0) == -1
+ || fs_prepare_dir(target_user.c_str(), 0000, 0, 0) == -1) {
+ return false;
+ }
+
+ if (mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+ // Mount entire external storage tree for all users
+ if (mount(source, target, NULL, MS_BIND, NULL) == -1) {
+ PLOG(WARNING) << "Failed to mount " << source << " to " << target;
+ return false;
+ }
+ } else {
+ // Only mount user-specific external storage
+ if (mount(source_user.c_str(), target_user.c_str(), NULL, MS_BIND, NULL) == -1) {
+ PLOG(WARNING) << "Failed to mount " << source_user << " to " << target_user;
+ return false;
+ }
+ }
+
+ // Now that user is mounted, prepare and mount OBB storage
+ // into place for current user
+
+ // /storage/emulated/0/Android
+ std::string target_android(StringPrintf("%s/%d/Android", target, user_id));
+ // /storage/emulated/0/Android/obb
+ std::string target_obb(StringPrintf("%s/%d/Android/obb", target, user_id));
+
+ if (fs_prepare_dir(target_android.c_str(), 0000, 0, 0) == -1
+ || fs_prepare_dir(target_obb.c_str(), 0000, 0, 0) == -1
+ || fs_prepare_dir(legacy, 0000, 0, 0) == -1) {
+ return false;
+ }
+ if (mount(source_obb.c_str(), target_obb.c_str(), NULL, MS_BIND, NULL) == -1) {
+ PLOG(WARNING) << "Failed to mount " << source_obb << " to " << target_obb;
+ return false;
+ }
+
+ // Finally, mount user-specific path into place for legacy users
+ if (mount(target_user.c_str(), legacy, NULL, MS_BIND | MS_REC, NULL) == -1) {
+ PLOG(WARNING) << "Failed to mount " << target_user << " to " << legacy;
+ return false;
+ }
+ } else {
+ LOG(WARNING) << "Mount mode " << mount_mode << " unsupported";
+ return false;
+ }
+
+ return true;
+}
+
+#if defined(__linux__)
+static bool NeedsNoRandomizeWorkaround() {
+#if !defined(__arm__)
+ return false;
+#else
+ int major;
+ int minor;
+ struct utsname uts;
+ if (uname(&uts) == -1) {
+ return false;
+ }
+
+ if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
+ return false;
+ }
+
+ // Kernels before 3.4.* need the workaround.
+ return (major < 3) || ((major == 3) && (minor < 4));
+#endif
+}
+#endif
+
+// Utility routine to fork zygote and specialize the child process.
+static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
+ jint debug_flags, jobjectArray javaRlimits,
+ jlong permittedCapabilities, jlong effectiveCapabilities,
+ jint mount_external,
+ jstring java_se_info, jstring java_se_name, bool is_system_server) {
+ Runtime* runtime = Runtime::Current();
+ CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote";
+ if (!runtime->PreZygoteFork()) {
+ LOG(FATAL) << "pre-fork heap failed";
+ }
+
+ SetSigChldHandler();
+
+ // Grab thread before fork potentially makes Thread::pthread_key_self_ unusable.
+ Thread* self = Thread::Current();
+
+ // dvmDumpLoaderStats("zygote"); // TODO: ?
+ pid_t pid = fork();
+
+ if (pid == 0) {
+ // The child process.
+ gMallocLeakZygoteChild = 1;
+
+ // Keep capabilities across UID change, unless we're staying root.
+ if (uid != 0) {
+ EnableKeepCapabilities();
+ }
+
+ DropCapabilitiesBoundingSet();
+
+ if (!MountEmulatedStorage(uid, mount_external)) {
+ PLOG(WARNING) << "Failed to mount emulated storage";
+ if (errno == ENOTCONN || errno == EROFS) {
+ // When device is actively encrypting, we get ENOTCONN here
+ // since FUSE was mounted before the framework restarted.
+ // When encrypted device is booting, we get EROFS since
+ // FUSE hasn't been created yet by init.
+ // In either case, continue without external storage.
+ } else {
+ LOG(FATAL) << "Cannot continue without emulated storage";
+ }
+ }
+
+ SetGids(env, javaGids);
+
+ SetRLimits(env, javaRlimits);
+
+ int rc = setresgid(gid, gid, gid);
+ if (rc == -1) {
+ PLOG(FATAL) << "setresgid(" << gid << ") failed";
+ }
+
+ rc = setresuid(uid, uid, uid);
+ if (rc == -1) {
+ PLOG(FATAL) << "setresuid(" << uid << ") failed";
+ }
+
+#if defined(__linux__)
+ if (NeedsNoRandomizeWorkaround()) {
+ // Work around ARM kernel ASLR lossage (http://b/5817320).
+ int old_personality = personality(0xffffffff);
+ int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
+ if (new_personality == -1) {
+ PLOG(WARNING) << "personality(" << new_personality << ") failed";
+ }
+ }
+#endif
+
+ SetCapabilities(permittedCapabilities, effectiveCapabilities);
+
+ SetSchedulerPolicy();
+
+#if defined(HAVE_ANDROID_OS)
+ {
+ const char* se_info_c_str = NULL;
+ UniquePtr<ScopedUtfChars> se_info;
+ if (java_se_info != NULL) {
+ se_info.reset(new ScopedUtfChars(env, java_se_info));
+ se_info_c_str = se_info->c_str();
+ CHECK(se_info_c_str != NULL);
+ }
+ const char* se_name_c_str = NULL;
+ UniquePtr<ScopedUtfChars> se_name;
+ if (java_se_name != NULL) {
+ se_name.reset(new ScopedUtfChars(env, java_se_name));
+ se_name_c_str = se_name->c_str();
+ CHECK(se_name_c_str != NULL);
+ }
+ rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
+ if (rc == -1) {
+ PLOG(FATAL) << "selinux_android_setcontext(" << uid << ", "
+ << (is_system_server ? "true" : "false") << ", "
+ << "\"" << se_info_c_str << "\", \"" << se_name_c_str << "\") failed";
+ }
+ }
+#else
+ UNUSED(is_system_server);
+ UNUSED(java_se_info);
+ UNUSED(java_se_name);
+#endif
+
+ // Our system thread ID, etc, has changed so reset Thread state.
+ self->InitAfterFork();
+
+ EnableDebugFeatures(debug_flags);
+
+ UnsetSigChldHandler();
+ runtime->DidForkFromZygote();
+ } else if (pid > 0) {
+ // the parent process
+ }
+ return pid;
+}
+
+static jint Zygote_nativeForkAndSpecialize(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
+ jint debug_flags, jobjectArray rlimits, jint mount_external,
+ jstring se_info, jstring se_name) {
+ return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, 0, 0, mount_external, se_info, se_name, false);
+}
+
+static jint Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
+ jint debug_flags, jobjectArray rlimits,
+ jlong permittedCapabilities, jlong effectiveCapabilities) {
+ pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
+ debug_flags, rlimits,
+ permittedCapabilities, effectiveCapabilities,
+ MOUNT_EXTERNAL_NONE, NULL, NULL, true);
+ if (pid > 0) {
+ // The zygote process checks whether the child process has died or not.
+ LOG(INFO) << "System server process " << pid << " has been created";
+ gSystemServerPid = pid;
+ // There is a slight window that the system server process has crashed
+ // but it went unnoticed because we haven't published its pid yet. So
+ // we recheck here just to make sure that all is well.
+ int status;
+ if (waitpid(pid, &status, WNOHANG) == pid) {
+ LOG(FATAL) << "System server process " << pid << " has died. Restarting Zygote!";
+ }
+ }
+ return pid;
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Zygote, nativeForkAndSpecialize, "(II[II[[IILjava/lang/String;Ljava/lang/String;)I"),
+ NATIVE_METHOD(Zygote, nativeForkSystemServer, "(II[II[[IJJ)I"),
+};
+
+void register_dalvik_system_Zygote(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("dalvik/system/Zygote");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
new file mode 100644
index 0000000..a729699
--- /dev/null
+++ b/runtime/native/java_lang_Class.cc
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "class_linker.h"
+#include "dex_file-inl.h"
+#include "jni_internal.h"
+#include "nth_caller_visitor.h"
+#include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
+#include "mirror/object-inl.h"
+#include "mirror/proxy.h"
+#include "object_utils.h"
+#include "scoped_thread_state_change.h"
+#include "ScopedLocalRef.h"
+#include "ScopedUtfChars.h"
+#include "well_known_classes.h"
+
+namespace art {
+
+static mirror::Class* DecodeClass(const ScopedObjectAccess& soa, jobject java_class)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+ DCHECK(c != NULL);
+ DCHECK(c->IsClass());
+ // TODO: we could EnsureInitialized here, rather than on every reflective get/set or invoke .
+ // For now, we conservatively preserve the old dalvik behavior. A quick "IsInitialized" check
+ // every time probably doesn't make much difference to reflection performance anyway.
+ return c;
+}
+
+// "name" is in "binary name" format, e.g. "dalvik.system.Debug$1".
+static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize, jobject javaLoader) {
+ ScopedObjectAccess soa(env);
+ ScopedUtfChars name(env, javaName);
+ if (name.c_str() == NULL) {
+ return NULL;
+ }
+
+ // We need to validate and convert the name (from x.y.z to x/y/z). This
+ // is especially handy for array types, since we want to avoid
+ // auto-generating bogus array classes.
+ if (!IsValidBinaryClassName(name.c_str())) {
+ ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+ soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ClassNotFoundException;",
+ "Invalid name: %s", name.c_str());
+ return NULL;
+ }
+
+ std::string descriptor(DotToDescriptor(name.c_str()));
+ mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ mirror::Class* c = class_linker->FindClass(descriptor.c_str(), class_loader);
+ if (c == NULL) {
+ ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
+ env->ExceptionClear();
+ jthrowable cnfe = reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
+ WellKnownClasses::java_lang_ClassNotFoundException_init,
+ javaName, cause.get()));
+ env->Throw(cnfe);
+ return NULL;
+ }
+ if (initialize) {
+ class_linker->EnsureInitialized(c, true, true);
+ }
+ return soa.AddLocalReference<jclass>(c);
+}
+
+static jint Class_getAnnotationDirectoryOffset(JNIEnv* env, jclass javaClass) {
+ ScopedObjectAccess soa(env);
+ mirror::Class* c = DecodeClass(soa, javaClass);
+ if (c->IsPrimitive() || c->IsArrayClass() || c->IsProxyClass()) {
+ return 0; // primitive, array and proxy classes don't have class definitions
+ }
+ const DexFile::ClassDef* class_def = ClassHelper(c).GetClassDef();
+ if (class_def == NULL) {
+ return 0; // not found
+ } else {
+ return class_def->annotations_off_;
+ }
+}
+
+static jobject Class_getDex(JNIEnv* env, jobject javaClass) {
+ ScopedObjectAccess soa(env);
+ mirror::Class* c = DecodeClass(soa, javaClass);
+
+ mirror::DexCache* dex_cache = c->GetDexCache();
+ if (dex_cache == NULL) {
+ return NULL;
+ }
+ const DexFile* dex_file = dex_cache->GetDexFile();
+ if (dex_file == NULL) {
+ return NULL;
+ }
+ return dex_file->GetDexObject(env);
+}
+
+static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
+ ScopedObjectAccess soa(env);
+ mirror::Class* c = DecodeClass(soa, javaThis);
+ return soa.AddLocalReference<jstring>(c->ComputeName());
+}
+
+static jobjectArray Class_getProxyInterfaces(JNIEnv* env, jobject javaThis) {
+ ScopedObjectAccess soa(env);
+ mirror::SynthesizedProxyClass* c =
+ down_cast<mirror::SynthesizedProxyClass*>(DecodeClass(soa, javaThis));
+ return soa.AddLocalReference<jobjectArray>(c->GetInterfaces()->Clone(soa.Self()));
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
+ NATIVE_METHOD(Class, getAnnotationDirectoryOffset, "()I"),
+ NATIVE_METHOD(Class, getDex, "()Lcom/android/dex/Dex;"),
+ NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"),
+ NATIVE_METHOD(Class, getProxyInterfaces, "()[Ljava/lang/Class;"),
+};
+
+void register_java_lang_Class(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/Class");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc
new file mode 100644
index 0000000..5db7a33
--- /dev/null
+++ b/runtime/native/java_lang_Object.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni_internal.h"
+#include "mirror/object-inl.h"
+#include "scoped_thread_state_change.h"
+
+// TODO: better support for overloading.
+#undef NATIVE_METHOD
+#define NATIVE_METHOD(className, functionName, signature, identifier) \
+ { #functionName, signature, reinterpret_cast<void*>(className ## _ ## identifier) }
+
+namespace art {
+
+static jobject Object_internalClone(JNIEnv* env, jobject java_this) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
+ return soa.AddLocalReference<jobject>(o->Clone(soa.Self()));
+}
+
+static void Object_notify(JNIEnv* env, jobject java_this) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
+ o->Notify(soa.Self());
+}
+
+static void Object_notifyAll(JNIEnv* env, jobject java_this) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
+ o->NotifyAll(soa.Self());
+}
+
+static void Object_wait(JNIEnv* env, jobject java_this) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
+ o->Wait(soa.Self());
+}
+
+static void Object_waitJI(JNIEnv* env, jobject java_this, jlong ms, jint ns) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
+ o->Wait(soa.Self(), ms, ns);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Object, internalClone, "()Ljava/lang/Object;", internalClone),
+ NATIVE_METHOD(Object, notify, "()V", notify),
+ NATIVE_METHOD(Object, notifyAll, "()V", notifyAll),
+ NATIVE_METHOD(Object, wait, "()V", wait),
+ NATIVE_METHOD(Object, wait, "(JI)V", waitJI),
+};
+
+void register_java_lang_Object(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/Object");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_Runtime.cc b/runtime/native/java_lang_Runtime.cc
new file mode 100644
index 0000000..e380c17
--- /dev/null
+++ b/runtime/native/java_lang_Runtime.cc
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dlfcn.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include "gc/heap.h"
+#include "jni_internal.h"
+#include "mirror/class_loader.h"
+#include "runtime.h"
+#include "scoped_thread_state_change.h"
+#include "ScopedUtfChars.h"
+
+namespace art {
+
+static void Runtime_gc(JNIEnv*, jclass) {
+ Runtime::Current()->GetHeap()->CollectGarbage(false);
+}
+
+static void Runtime_nativeExit(JNIEnv*, jclass, jint status) {
+ Runtime::Current()->CallExitHook(status);
+ exit(status);
+}
+
+static jstring Runtime_nativeLoad(JNIEnv* env, jclass, jstring javaFilename, jobject javaLoader, jstring javaLdLibraryPath) {
+ ScopedObjectAccess soa(env);
+ ScopedUtfChars filename(env, javaFilename);
+ if (filename.c_str() == NULL) {
+ return NULL;
+ }
+
+ if (javaLdLibraryPath != NULL) {
+ ScopedUtfChars ldLibraryPath(env, javaLdLibraryPath);
+ if (ldLibraryPath.c_str() == NULL) {
+ return NULL;
+ }
+ void* sym = dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH");
+ if (sym != NULL) {
+ typedef void (*Fn)(const char*);
+ Fn android_update_LD_LIBRARY_PATH = reinterpret_cast<Fn>(sym);
+ (*android_update_LD_LIBRARY_PATH)(ldLibraryPath.c_str());
+ } else {
+ LOG(ERROR) << "android_update_LD_LIBRARY_PATH not found; .so dependencies will not work!";
+ }
+ }
+
+ mirror::ClassLoader* classLoader = soa.Decode<mirror::ClassLoader*>(javaLoader);
+ std::string detail;
+ JavaVMExt* vm = Runtime::Current()->GetJavaVM();
+ bool success = vm->LoadNativeLibrary(filename.c_str(), classLoader, detail);
+ if (success) {
+ return NULL;
+ }
+
+ // Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF.
+ env->ExceptionClear();
+ return env->NewStringUTF(detail.c_str());
+}
+
+static jlong Runtime_maxMemory(JNIEnv*, jclass) {
+ return Runtime::Current()->GetHeap()->GetMaxMemory();
+}
+
+static jlong Runtime_totalMemory(JNIEnv*, jclass) {
+ return Runtime::Current()->GetHeap()->GetTotalMemory();
+}
+
+static jlong Runtime_freeMemory(JNIEnv*, jclass) {
+ return Runtime::Current()->GetHeap()->GetFreeMemory();
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Runtime, freeMemory, "()J"),
+ NATIVE_METHOD(Runtime, gc, "()V"),
+ NATIVE_METHOD(Runtime, maxMemory, "()J"),
+ NATIVE_METHOD(Runtime, nativeExit, "(I)V"),
+ NATIVE_METHOD(Runtime, nativeLoad, "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/String;"),
+ NATIVE_METHOD(Runtime, totalMemory, "()J"),
+};
+
+void register_java_lang_Runtime(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/Runtime");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc
new file mode 100644
index 0000000..3e9c3f3
--- /dev/null
+++ b/runtime/native/java_lang_String.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_throws.h"
+#include "jni_internal.h"
+#include "mirror/string.h"
+#include "scoped_thread_state_change.h"
+#include "ScopedLocalRef.h"
+
+namespace art {
+
+static jint String_compareTo(JNIEnv* env, jobject javaThis, jobject javaRhs) {
+ ScopedObjectAccess soa(env);
+ if (UNLIKELY(javaRhs == NULL)) {
+ ThrowNullPointerException(NULL, "rhs == null");
+ return -1;
+ } else {
+ return soa.Decode<mirror::String*>(javaThis)->CompareTo(soa.Decode<mirror::String*>(javaRhs));
+ }
+}
+
+static jint String_fastIndexOf(JNIEnv* env, jobject java_this, jint ch, jint start) {
+ ScopedObjectAccess soa(env);
+ // This method does not handle supplementary characters. They're dealt with in managed code.
+ DCHECK_LE(ch, 0xffff);
+
+ mirror::String* s = soa.Decode<mirror::String*>(java_this);
+ return s->FastIndexOf(ch, start);
+}
+
+static jstring String_intern(JNIEnv* env, jobject javaThis) {
+ ScopedObjectAccess soa(env);
+ mirror::String* s = soa.Decode<mirror::String*>(javaThis);
+ mirror::String* result = s->Intern();
+ return soa.AddLocalReference<jstring>(result);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(String, compareTo, "(Ljava/lang/String;)I"),
+ NATIVE_METHOD(String, fastIndexOf, "(II)I"),
+ NATIVE_METHOD(String, intern, "()Ljava/lang/String;"),
+};
+
+void register_java_lang_String(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/String");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
new file mode 100644
index 0000000..2462f2f
--- /dev/null
+++ b/runtime/native/java_lang_System.cc
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_throws.h"
+#include "gc/accounting/card_table-inl.h"
+#include "jni_internal.h"
+#include "mirror/array.h"
+#include "mirror/class.h"
+#include "mirror/class-inl.h"
+#include "mirror/object-inl.h"
+#include "mirror/object_array-inl.h"
+#include "scoped_thread_state_change.h"
+
+/*
+ * We make guarantees about the atomicity of accesses to primitive
+ * variables. These guarantees also apply to elements of arrays.
+ * In particular, 8-bit, 16-bit, and 32-bit accesses must be atomic and
+ * must not cause "word tearing". Accesses to 64-bit array elements must
+ * either be atomic or treated as two 32-bit operations. References are
+ * always read and written atomically, regardless of the number of bits
+ * used to represent them.
+ *
+ * We can't rely on standard libc functions like memcpy(3) and memmove(3)
+ * in our implementation of System.arraycopy, because they may copy
+ * byte-by-byte (either for the full run or for "unaligned" parts at the
+ * start or end). We need to use functions that guarantee 16-bit or 32-bit
+ * atomicity as appropriate.
+ *
+ * System.arraycopy() is heavily used, so having an efficient implementation
+ * is important. The bionic libc provides a platform-optimized memory move
+ * function that should be used when possible. If it's not available,
+ * the trivial "reference implementation" versions below can be used until
+ * a proper version can be written.
+ *
+ * For these functions, The caller must guarantee that dst/src are aligned
+ * appropriately for the element type, and that n is a multiple of the
+ * element size.
+ */
+
+/*
+ * Works like memmove(), except:
+ * - if all arguments are at least 32-bit aligned, we guarantee that we
+ * will use operations that preserve atomicity of 32-bit values
+ * - if not, we guarantee atomicity of 16-bit values
+ *
+ * If all three arguments are not at least 16-bit aligned, the behavior
+ * of this function is undefined. (We could remove this restriction by
+ * testing for unaligned values and punting to memmove(), but that's
+ * not currently useful.)
+ *
+ * TODO: add loop for 64-bit alignment
+ * TODO: use __builtin_prefetch
+ * TODO: write ARM/MIPS/x86 optimized versions
+ */
+void MemmoveWords(void* dst, const void* src, size_t n) {
+ DCHECK_EQ((((uintptr_t) dst | (uintptr_t) src | n) & 0x01), 0U);
+
+ char* d = reinterpret_cast<char*>(dst);
+ const char* s = reinterpret_cast<const char*>(src);
+ size_t copyCount;
+
+ // If the source and destination pointers are the same, this is
+ // an expensive no-op. Testing for an empty move now allows us
+ // to skip a check later.
+ if (n == 0 || d == s) {
+ return;
+ }
+
+ // Determine if the source and destination buffers will overlap if
+ // we copy data forward (i.e. *dst++ = *src++).
+ //
+ // It's okay if the destination buffer starts before the source and
+ // there is some overlap, because the reader is always ahead of the
+ // writer.
+ if (LIKELY((d < s) || ((size_t)(d - s) >= n))) {
+ // Copy forward. We prefer 32-bit loads and stores even for 16-bit
+ // data, so sort that out.
+ if (((reinterpret_cast<uintptr_t>(d) | reinterpret_cast<uintptr_t>(s)) & 0x03) != 0) {
+ // Not 32-bit aligned. Two possibilities:
+ // (1) Congruent, we can align to 32-bit by copying one 16-bit val
+ // (2) Non-congruent, we can do one of:
+ // a. copy whole buffer as a series of 16-bit values
+ // b. load/store 32 bits, using shifts to ensure alignment
+ // c. just copy the as 32-bit values and assume the CPU
+ // will do a reasonable job
+ //
+ // We're currently using (a), which is suboptimal.
+ if (((reinterpret_cast<uintptr_t>(d) ^ reinterpret_cast<uintptr_t>(s)) & 0x03) != 0) {
+ copyCount = n;
+ } else {
+ copyCount = 2;
+ }
+ n -= copyCount;
+ copyCount /= sizeof(uint16_t);
+
+ while (copyCount--) {
+ *reinterpret_cast<uint16_t*>(d) = *reinterpret_cast<const uint16_t*>(s);
+ d += sizeof(uint16_t);
+ s += sizeof(uint16_t);
+ }
+ }
+
+ // Copy 32-bit aligned words.
+ copyCount = n / sizeof(uint32_t);
+ while (copyCount--) {
+ *reinterpret_cast<uint32_t*>(d) = *reinterpret_cast<const uint32_t*>(s);
+ d += sizeof(uint32_t);
+ s += sizeof(uint32_t);
+ }
+
+ // Check for leftovers. Either we finished exactly, or we have one remaining 16-bit chunk.
+ if ((n & 0x02) != 0) {
+ *(uint16_t*)d = *(uint16_t*)s;
+ }
+ } else {
+ // Copy backward, starting at the end.
+ d += n;
+ s += n;
+
+ if (((reinterpret_cast<uintptr_t>(d) | reinterpret_cast<uintptr_t>(s)) & 0x03) != 0) {
+ // try for 32-bit alignment.
+ if (((reinterpret_cast<uintptr_t>(d) ^ reinterpret_cast<uintptr_t>(s)) & 0x03) != 0) {
+ copyCount = n;
+ } else {
+ copyCount = 2;
+ }
+ n -= copyCount;
+ copyCount /= sizeof(uint16_t);
+
+ while (copyCount--) {
+ d -= sizeof(uint16_t);
+ s -= sizeof(uint16_t);
+ *reinterpret_cast<uint16_t*>(d) = *reinterpret_cast<const uint16_t*>(s);
+ }
+ }
+
+ // Copy 32-bit aligned words.
+ copyCount = n / sizeof(uint32_t);
+ while (copyCount--) {
+ d -= sizeof(uint32_t);
+ s -= sizeof(uint32_t);
+ *reinterpret_cast<uint32_t*>(d) = *reinterpret_cast<const uint32_t*>(s);
+ }
+
+ // Copy leftovers.
+ if ((n & 0x02) != 0) {
+ d -= sizeof(uint16_t);
+ s -= sizeof(uint16_t);
+ *reinterpret_cast<uint16_t*>(d) = *reinterpret_cast<const uint16_t*>(s);
+ }
+ }
+}
+
+#define move16 MemmoveWords
+#define move32 MemmoveWords
+
+namespace art {
+
+static void ThrowArrayStoreException_NotAnArray(const char* identifier, mirror::Object* array)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ std::string actualType(PrettyTypeOf(array));
+ Thread* self = Thread::Current();
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ self->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;",
+ "%s of type %s is not an array", identifier, actualType.c_str());
+}
+
+static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst, jint dstPos, jint length) {
+ ScopedObjectAccess soa(env);
+
+ // Null pointer checks.
+ if (UNLIKELY(javaSrc == NULL)) {
+ ThrowNullPointerException(NULL, "src == null");
+ return;
+ }
+ if (UNLIKELY(javaDst == NULL)) {
+ ThrowNullPointerException(NULL, "dst == null");
+ return;
+ }
+
+ // Make sure source and destination are both arrays.
+ mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
+ mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
+ if (UNLIKELY(!srcObject->IsArrayInstance())) {
+ ThrowArrayStoreException_NotAnArray("source", srcObject);
+ return;
+ }
+ if (UNLIKELY(!dstObject->IsArrayInstance())) {
+ ThrowArrayStoreException_NotAnArray("destination", dstObject);
+ return;
+ }
+ mirror::Array* srcArray = srcObject->AsArray();
+ mirror::Array* dstArray = dstObject->AsArray();
+ mirror::Class* srcComponentType = srcArray->GetClass()->GetComponentType();
+ mirror::Class* dstComponentType = dstArray->GetClass()->GetComponentType();
+
+ // Bounds checking.
+ if (UNLIKELY(srcPos < 0 || dstPos < 0 || length < 0 || srcPos > srcArray->GetLength() - length || dstPos > dstArray->GetLength() - length)) {
+ ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+ soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayIndexOutOfBoundsException;",
+ "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
+ srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos, length);
+ return;
+ }
+
+ // Handle primitive arrays.
+ if (srcComponentType->IsPrimitive() || dstComponentType->IsPrimitive()) {
+ // If one of the arrays holds a primitive type the other array must hold the exact same type.
+ if (UNLIKELY(srcComponentType != dstComponentType)) {
+ std::string srcType(PrettyTypeOf(srcArray));
+ std::string dstType(PrettyTypeOf(dstArray));
+ ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+ soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;",
+ "Incompatible types: src=%s, dst=%s",
+ srcType.c_str(), dstType.c_str());
+ return;
+ }
+
+ size_t width = srcArray->GetClass()->GetComponentSize();
+ uint8_t* dstBytes = reinterpret_cast<uint8_t*>(dstArray->GetRawData(width));
+ const uint8_t* srcBytes = reinterpret_cast<const uint8_t*>(srcArray->GetRawData(width));
+
+ switch (width) {
+ case 1:
+ memmove(dstBytes + dstPos, srcBytes + srcPos, length);
+ break;
+ case 2:
+ move16(dstBytes + dstPos * 2, srcBytes + srcPos * 2, length * 2);
+ break;
+ case 4:
+ move32(dstBytes + dstPos * 4, srcBytes + srcPos * 4, length * 4);
+ break;
+ case 8:
+ // We don't need to guarantee atomicity of the entire 64-bit word.
+ move32(dstBytes + dstPos * 8, srcBytes + srcPos * 8, length * 8);
+ break;
+ default:
+ LOG(FATAL) << "Unknown primitive array type: " << PrettyTypeOf(srcArray);
+ }
+
+ return;
+ }
+
+ // Neither class is primitive. Are the types trivially compatible?
+ const size_t width = sizeof(mirror::Object*);
+ uint8_t* dstBytes = reinterpret_cast<uint8_t*>(dstArray->GetRawData(width));
+ const uint8_t* srcBytes = reinterpret_cast<const uint8_t*>(srcArray->GetRawData(width));
+ if (dstArray == srcArray || dstComponentType->IsAssignableFrom(srcComponentType)) {
+ // Yes. Bulk copy.
+ COMPILE_ASSERT(sizeof(width) == sizeof(uint32_t), move32_assumes_Object_references_are_32_bit);
+ move32(dstBytes + dstPos * width, srcBytes + srcPos * width, length * width);
+ Runtime::Current()->GetHeap()->WriteBarrierArray(dstArray, dstPos, length);
+ return;
+ }
+
+ // The arrays are not trivially compatible. However, we may still be able to copy some or all of
+ // the elements if the source objects are compatible (for example, copying an Object[] to
+ // String[], the Objects being copied might actually be Strings).
+ // We can't do a bulk move because that would introduce a check-use race condition, so we copy
+ // elements one by one.
+
+ // We already dealt with overlapping copies, so we don't need to cope with that case below.
+ CHECK_NE(dstArray, srcArray);
+
+ mirror::Object* const * srcObjects =
+ reinterpret_cast<mirror::Object* const *>(srcBytes + srcPos * width);
+ mirror::Object** dstObjects = reinterpret_cast<mirror::Object**>(dstBytes + dstPos * width);
+ mirror::Class* dstClass = dstArray->GetClass()->GetComponentType();
+
+ // We want to avoid redundant IsAssignableFrom checks where possible, so we cache a class that
+ // we know is assignable to the destination array's component type.
+ mirror::Class* lastAssignableElementClass = dstClass;
+
+ mirror::Object* o = NULL;
+ int i = 0;
+ for (; i < length; ++i) {
+ o = srcObjects[i];
+ if (o != NULL) {
+ mirror::Class* oClass = o->GetClass();
+ if (lastAssignableElementClass == oClass) {
+ dstObjects[i] = o;
+ } else if (dstClass->IsAssignableFrom(oClass)) {
+ lastAssignableElementClass = oClass;
+ dstObjects[i] = o;
+ } else {
+ // Can't put this element into the array.
+ break;
+ }
+ } else {
+ dstObjects[i] = NULL;
+ }
+ }
+
+ Runtime::Current()->GetHeap()->WriteBarrierArray(dstArray, dstPos, length);
+ if (UNLIKELY(i != length)) {
+ std::string actualSrcType(PrettyTypeOf(o));
+ std::string dstType(PrettyTypeOf(dstArray));
+ ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+ soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;",
+ "source[%d] of type %s cannot be stored in destination array of type %s",
+ srcPos + i, actualSrcType.c_str(), dstType.c_str());
+ return;
+ }
+}
+
+static jint System_identityHashCode(JNIEnv* env, jclass, jobject javaObject) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* o = soa.Decode<mirror::Object*>(javaObject);
+ return static_cast<jint>(o->IdentityHashCode());
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(System, arraycopy, "(Ljava/lang/Object;ILjava/lang/Object;II)V"),
+ NATIVE_METHOD(System, identityHashCode, "(Ljava/lang/Object;)I"),
+};
+
+void register_java_lang_System(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/System");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
new file mode 100644
index 0000000..8ef190a
--- /dev/null
+++ b/runtime/native/java_lang_Thread.cc
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_throws.h"
+#include "debugger.h"
+#include "jni_internal.h"
+#include "monitor.h"
+#include "mirror/object.h"
+#include "scoped_thread_state_change.h"
+#include "ScopedUtfChars.h"
+#include "thread.h"
+#include "thread_list.h"
+
+namespace art {
+
+static jobject Thread_currentThread(JNIEnv* env, jclass) {
+ ScopedObjectAccess soa(env);
+ return soa.AddLocalReference<jobject>(soa.Self()->GetPeer());
+}
+
+static jboolean Thread_interrupted(JNIEnv* env, jclass) {
+ return static_cast<JNIEnvExt*>(env)->self->Interrupted() ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean Thread_isInterrupted(JNIEnv* env, jobject java_thread) {
+ ScopedObjectAccess soa(env);
+ MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+ Thread* thread = Thread::FromManagedThread(soa, java_thread);
+ return (thread != NULL) ? thread->IsInterrupted() : JNI_FALSE;
+}
+
+static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread, jlong stack_size,
+ jboolean daemon) {
+ Thread::CreateNativeThread(env, java_thread, stack_size, daemon == JNI_TRUE);
+}
+
+static jint Thread_nativeGetStatus(JNIEnv* env, jobject java_thread, jboolean has_been_started) {
+ // Ordinals from Java's Thread.State.
+ const jint kJavaNew = 0;
+ const jint kJavaRunnable = 1;
+ const jint kJavaBlocked = 2;
+ const jint kJavaWaiting = 3;
+ const jint kJavaTimedWaiting = 4;
+ const jint kJavaTerminated = 5;
+
+ ScopedObjectAccess soa(env);
+ ThreadState internal_thread_state = (has_been_started ? kTerminated : kStarting);
+ MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+ Thread* thread = Thread::FromManagedThread(soa, java_thread);
+ if (thread != NULL) {
+ internal_thread_state = thread->GetState();
+ }
+ switch (internal_thread_state) {
+ case kTerminated: return kJavaTerminated;
+ case kRunnable: return kJavaRunnable;
+ case kTimedWaiting: return kJavaTimedWaiting;
+ case kSleeping: return kJavaTimedWaiting;
+ case kBlocked: return kJavaBlocked;
+ case kWaiting: return kJavaWaiting;
+ case kStarting: return kJavaNew;
+ case kNative: return kJavaRunnable;
+ case kWaitingForGcToComplete: return kJavaWaiting;
+ case kWaitingPerformingGc: return kJavaWaiting;
+ case kWaitingForCheckPointsToRun: return kJavaWaiting;
+ case kWaitingForDebuggerSend: return kJavaWaiting;
+ case kWaitingForDebuggerToAttach: return kJavaWaiting;
+ case kWaitingInMainDebuggerLoop: return kJavaWaiting;
+ case kWaitingForDebuggerSuspension: return kJavaWaiting;
+ case kWaitingForJniOnLoad: return kJavaWaiting;
+ case kWaitingForSignalCatcherOutput: return kJavaWaiting;
+ case kWaitingInMainSignalCatcherLoop: return kJavaWaiting;
+ case kSuspended: return kJavaRunnable;
+ // Don't add a 'default' here so the compiler can spot incompatible enum changes.
+ }
+ return -1; // Unreachable.
+}
+
+static jboolean Thread_nativeHoldsLock(JNIEnv* env, jobject java_thread, jobject java_object) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* object = soa.Decode<mirror::Object*>(java_object);
+ if (object == NULL) {
+ ThrowNullPointerException(NULL, "object == null");
+ return JNI_FALSE;
+ }
+ MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+ Thread* thread = Thread::FromManagedThread(soa, java_thread);
+ return thread->HoldsLock(object);
+}
+
+static void Thread_nativeInterrupt(JNIEnv* env, jobject java_thread) {
+ ScopedObjectAccess soa(env);
+ MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+ Thread* thread = Thread::FromManagedThread(soa, java_thread);
+ if (thread != NULL) {
+ thread->Interrupt();
+ }
+}
+
+static void Thread_nativeSetName(JNIEnv* env, jobject peer, jstring java_name) {
+ ScopedUtfChars name(env, java_name);
+ {
+ ScopedObjectAccess soa(env);
+ if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
+ soa.Self()->SetThreadName(name.c_str());
+ return;
+ }
+ }
+ // Suspend thread to avoid it from killing itself while we set its name. We don't just hold the
+ // thread list lock to avoid this, as setting the thread name causes mutator to lock/unlock
+ // in the DDMS send code.
+ bool timed_out;
+ Thread* thread = Thread::SuspendForDebugger(peer, true, &timed_out);
+ if (thread != NULL) {
+ {
+ ScopedObjectAccess soa(env);
+ thread->SetThreadName(name.c_str());
+ }
+ Runtime::Current()->GetThreadList()->Resume(thread, true);
+ } else if (timed_out) {
+ LOG(ERROR) << "Trying to set thread name to '" << name.c_str() << "' failed as the thread "
+ "failed to suspend within a generous timeout.";
+ }
+}
+
+/*
+ * Alter the priority of the specified thread. "new_priority" will range
+ * from Thread.MIN_PRIORITY to Thread.MAX_PRIORITY (1-10), with "normal"
+ * threads at Thread.NORM_PRIORITY (5).
+ */
+static void Thread_nativeSetPriority(JNIEnv* env, jobject java_thread, jint new_priority) {
+ ScopedObjectAccess soa(env);
+ MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+ Thread* thread = Thread::FromManagedThread(soa, java_thread);
+ if (thread != NULL) {
+ thread->SetNativePriority(new_priority);
+ }
+}
+
+static void Thread_sleep(JNIEnv* env, jclass, jobject java_lock, jlong ms, jint ns) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* lock = soa.Decode<mirror::Object*>(java_lock);
+ Monitor::Wait(Thread::Current(), lock, ms, ns, true, kSleeping);
+}
+
+/*
+ * Causes the thread to temporarily pause and allow other threads to execute.
+ *
+ * The exact behavior is poorly defined. Some discussion here:
+ * http://www.cs.umd.edu/~pugh/java/memoryModel/archive/0944.html
+ */
+static void Thread_yield(JNIEnv*, jobject) {
+ sched_yield();
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Thread, currentThread, "()Ljava/lang/Thread;"),
+ NATIVE_METHOD(Thread, interrupted, "()Z"),
+ NATIVE_METHOD(Thread, isInterrupted, "()Z"),
+ NATIVE_METHOD(Thread, nativeCreate, "(Ljava/lang/Thread;JZ)V"),
+ NATIVE_METHOD(Thread, nativeGetStatus, "(Z)I"),
+ NATIVE_METHOD(Thread, nativeHoldsLock, "(Ljava/lang/Object;)Z"),
+ NATIVE_METHOD(Thread, nativeInterrupt, "()V"),
+ NATIVE_METHOD(Thread, nativeSetName, "(Ljava/lang/String;)V"),
+ NATIVE_METHOD(Thread, nativeSetPriority, "(I)V"),
+ NATIVE_METHOD(Thread, sleep, "(Ljava/lang/Object;JI)V"),
+ NATIVE_METHOD(Thread, yield, "()V"),
+};
+
+void register_java_lang_Thread(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/Thread");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_Throwable.cc b/runtime/native/java_lang_Throwable.cc
new file mode 100644
index 0000000..332a130
--- /dev/null
+++ b/runtime/native/java_lang_Throwable.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni_internal.h"
+#include "scoped_thread_state_change.h"
+#include "thread.h"
+
+namespace art {
+
+static jobject Throwable_nativeFillInStackTrace(JNIEnv* env, jclass) {
+ ScopedObjectAccess soa(env);
+ return soa.Self()->CreateInternalStackTrace(soa);
+}
+
+static jobjectArray Throwable_nativeGetStackTrace(JNIEnv* env, jclass, jobject javaStackState) {
+ if (javaStackState == NULL) {
+ return NULL;
+ }
+ return Thread::InternalStackTraceToStackTraceElementArray(env, javaStackState);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Throwable, nativeFillInStackTrace, "()Ljava/lang/Object;"),
+ NATIVE_METHOD(Throwable, nativeGetStackTrace, "(Ljava/lang/Object;)[Ljava/lang/StackTraceElement;"),
+};
+
+void register_java_lang_Throwable(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/Throwable");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
new file mode 100644
index 0000000..c23b08c
--- /dev/null
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "class_linker.h"
+#include "jni_internal.h"
+#include "mirror/class_loader.h"
+#include "mirror/object-inl.h"
+#include "scoped_thread_state_change.h"
+#include "ScopedUtfChars.h"
+#include "zip_archive.h"
+
+namespace art {
+
+static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoader, jstring javaName) {
+ ScopedObjectAccess soa(env);
+ mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
+ ScopedUtfChars name(env, javaName);
+ if (name.c_str() == NULL) {
+ return NULL;
+ }
+
+ std::string descriptor(DotToDescriptor(name.c_str()));
+ mirror::Class* c = Runtime::Current()->GetClassLinker()->LookupClass(descriptor.c_str(), loader);
+ if (c != NULL && c->IsResolved()) {
+ return soa.AddLocalReference<jclass>(c);
+ } else {
+ // Class wasn't resolved so it may be erroneous or not yet ready, force the caller to go into
+ // the regular loadClass code.
+ return NULL;
+ }
+}
+
+static jint VMClassLoader_getBootClassPathSize(JNIEnv*, jclass) {
+ return Runtime::Current()->GetClassLinker()->GetBootClassPath().size();
+}
+
+/*
+ * Returns a string URL for a resource with the specified 'javaName' in
+ * entry 'index' of the boot class path.
+ *
+ * We return a newly-allocated String in the following form:
+ *
+ * jar:file://path!/name
+ *
+ * Where "path" is the bootstrap class path entry and "name" is the string
+ * passed into this method. "path" needs to be an absolute path (starting
+ * with '/'); if it's not we'd need to make it absolute as part of forming
+ * the URL string.
+ */
+static jstring VMClassLoader_getBootClassPathResource(JNIEnv* env, jclass, jstring javaName, jint index) {
+ ScopedUtfChars name(env, javaName);
+ if (name.c_str() == NULL) {
+ return NULL;
+ }
+
+ const std::vector<const DexFile*>& path = Runtime::Current()->GetClassLinker()->GetBootClassPath();
+ if (index < 0 || size_t(index) >= path.size()) {
+ return NULL;
+ }
+ const DexFile* dex_file = path[index];
+ const std::string& location(dex_file->GetLocation());
+ UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(location));
+ if (zip_archive.get() == NULL) {
+ return NULL;
+ }
+ UniquePtr<ZipEntry> zip_entry(zip_archive->Find(name.c_str()));
+ if (zip_entry.get() == NULL) {
+ return NULL;
+ }
+
+ std::string url;
+ StringAppendF(&url, "jar:file://%s!/%s", location.c_str(), name.c_str());
+ return env->NewStringUTF(url.c_str());
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(VMClassLoader, findLoadedClass, "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;"),
+ NATIVE_METHOD(VMClassLoader, getBootClassPathResource, "(Ljava/lang/String;I)Ljava/lang/String;"),
+ NATIVE_METHOD(VMClassLoader, getBootClassPathSize, "()I"),
+};
+
+void register_java_lang_VMClassLoader(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/VMClassLoader");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
new file mode 100644
index 0000000..45ec0ad
--- /dev/null
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "class_linker.h"
+#include "common_throws.h"
+#include "dex_file-inl.h"
+#include "jni_internal.h"
+#include "mirror/class-inl.h"
+#include "mirror/object-inl.h"
+#include "object_utils.h"
+#include "scoped_thread_state_change.h"
+#include "sirt_ref.h"
+
+namespace art {
+
+static jobject Array_createMultiArray(JNIEnv* env, jclass, jclass javaElementClass, jobject javaDimArray) {
+ ScopedObjectAccess soa(env);
+ DCHECK(javaElementClass != NULL);
+ mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+ DCHECK(element_class->IsClass());
+ DCHECK(javaDimArray != NULL);
+ mirror::Object* dimensions_obj = soa.Decode<mirror::Object*>(javaDimArray);
+ DCHECK(dimensions_obj->IsArrayInstance());
+ DCHECK_STREQ(ClassHelper(dimensions_obj->GetClass()).GetDescriptor(), "[I");
+ mirror::IntArray* dimensions_array = down_cast<mirror::IntArray*>(dimensions_obj);
+ mirror::Array* new_array = mirror::Array::CreateMultiArray(soa.Self(), element_class, dimensions_array);
+ return soa.AddLocalReference<jobject>(new_array);
+}
+
+static jobject Array_createObjectArray(JNIEnv* env, jclass, jclass javaElementClass, jint length) {
+ ScopedObjectAccess soa(env);
+ DCHECK(javaElementClass != NULL);
+ mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+ if (UNLIKELY(length < 0)) {
+ ThrowNegativeArraySizeException(length);
+ return NULL;
+ }
+ std::string descriptor("[");
+ descriptor += ClassHelper(element_class).GetDescriptor();
+
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ mirror::Class* array_class = class_linker->FindClass(descriptor.c_str(), element_class->GetClassLoader());
+ if (UNLIKELY(array_class == NULL)) {
+ CHECK(soa.Self()->IsExceptionPending());
+ return NULL;
+ }
+ DCHECK(array_class->IsArrayClass());
+ mirror::Array* new_array = mirror::Array::Alloc(soa.Self(), array_class, length);
+ return soa.AddLocalReference<jobject>(new_array);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Array, createMultiArray, "(Ljava/lang/Class;[I)Ljava/lang/Object;"),
+ NATIVE_METHOD(Array, createObjectArray, "(Ljava/lang/Class;I)Ljava/lang/Object;"),
+};
+
+void register_java_lang_reflect_Array(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/reflect/Array");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
new file mode 100644
index 0000000..9180217
--- /dev/null
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "class_linker.h"
+#include "jni_internal.h"
+#include "mirror/class-inl.h"
+#include "mirror/abstract_method.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+#include "object_utils.h"
+#include "reflection.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+
+/*
+ * We get here through Constructor.newInstance(). The Constructor object
+ * would not be available if the constructor weren't public (per the
+ * definition of Class.getConstructor), so we can skip the method access
+ * check. We can also safely assume the constructor isn't associated
+ * with an interface, array, or primitive class.
+ */
+static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) {
+ ScopedObjectAccess soa(env);
+ mirror::AbstractMethod* m = soa.Decode<mirror::Object*>(javaMethod)->AsMethod();
+ mirror::Class* c = m->GetDeclaringClass();
+ if (UNLIKELY(c->IsAbstract())) {
+ ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+ soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/InstantiationException;",
+ "Can't instantiate %s %s",
+ c->IsInterface() ? "interface" : "abstract class",
+ PrettyDescriptor(c).c_str());
+ return NULL;
+ }
+
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return NULL;
+ }
+
+ mirror::Object* receiver = c->AllocObject(soa.Self());
+ if (receiver == NULL) {
+ return NULL;
+ }
+
+ jobject javaReceiver = soa.AddLocalReference<jobject>(receiver);
+ InvokeMethod(soa, javaMethod, javaReceiver, javaArgs);
+
+ // Constructors are ()V methods, so we shouldn't touch the result of InvokeMethod.
+ return javaReceiver;
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Constructor, newInstance, "([Ljava/lang/Object;)Ljava/lang/Object;"),
+};
+
+void register_java_lang_reflect_Constructor(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/reflect/Constructor");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
new file mode 100644
index 0000000..b0daa91
--- /dev/null
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "class_linker.h"
+#include "class_linker-inl.h"
+#include "common_throws.h"
+#include "dex_file-inl.h"
+#include "jni_internal.h"
+#include "mirror/class-inl.h"
+#include "mirror/field.h"
+#include "mirror/field-inl.h"
+#include "object_utils.h"
+#include "reflection.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+
+static bool GetFieldValue(const ScopedObjectAccess& soa, mirror::Object* o, mirror::Field* f,
+ JValue& value, bool allow_references)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK_EQ(value.GetJ(), 0LL);
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(),
+ true, true)) {
+ return false;
+ }
+ switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
+ case Primitive::kPrimBoolean:
+ value.SetZ(f->GetBoolean(o));
+ return true;
+ case Primitive::kPrimByte:
+ value.SetB(f->GetByte(o));
+ return true;
+ case Primitive::kPrimChar:
+ value.SetC(f->GetChar(o));
+ return true;
+ case Primitive::kPrimDouble:
+ value.SetD(f->GetDouble(o));
+ return true;
+ case Primitive::kPrimFloat:
+ value.SetF(f->GetFloat(o));
+ return true;
+ case Primitive::kPrimInt:
+ value.SetI(f->GetInt(o));
+ return true;
+ case Primitive::kPrimLong:
+ value.SetJ(f->GetLong(o));
+ return true;
+ case Primitive::kPrimShort:
+ value.SetS(f->GetShort(o));
+ return true;
+ case Primitive::kPrimNot:
+ if (allow_references) {
+ value.SetL(f->GetObject(o));
+ return true;
+ }
+ // Else break to report an error.
+ break;
+ case Primitive::kPrimVoid:
+ // Never okay.
+ break;
+ }
+ ThrowIllegalArgumentException(NULL,
+ StringPrintf("Not a primitive field: %s",
+ PrettyField(f).c_str()).c_str());
+ return false;
+}
+
+static bool CheckReceiver(const ScopedObjectAccess& soa, jobject j_rcvr, mirror::Field* f,
+ mirror::Object*& class_or_rcvr)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (f->IsStatic()) {
+ class_or_rcvr = f->GetDeclaringClass();
+ return true;
+ }
+
+ class_or_rcvr = soa.Decode<mirror::Object*>(j_rcvr);
+ mirror::Class* declaringClass = f->GetDeclaringClass();
+ if (!VerifyObjectInClass(class_or_rcvr, declaringClass)) {
+ return false;
+ }
+ return true;
+}
+
+static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) {
+ ScopedObjectAccess soa(env);
+ mirror::Field* f = soa.DecodeField(env->FromReflectedField(javaField));
+ mirror::Object* o = NULL;
+ if (!CheckReceiver(soa, javaObj, f, o)) {
+ return NULL;
+ }
+
+ // Get the field's value, boxing if necessary.
+ JValue value;
+ if (!GetFieldValue(soa, o, f, value, true)) {
+ return NULL;
+ }
+ return
+ soa.AddLocalReference<jobject>(BoxPrimitive(FieldHelper(f).GetTypeAsPrimitiveType(), value));
+}
+
+static JValue GetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, char dst_descriptor) {
+ ScopedObjectAccess soa(env);
+ mirror::Field* f = soa.DecodeField(env->FromReflectedField(javaField));
+ mirror::Object* o = NULL;
+ if (!CheckReceiver(soa, javaObj, f, o)) {
+ return JValue();
+ }
+
+ // Read the value.
+ JValue field_value;
+ if (!GetFieldValue(soa, o, f, field_value, false)) {
+ return JValue();
+ }
+
+ // Widen it if necessary (and possible).
+ JValue wide_value;
+ mirror::Class* dst_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass(dst_descriptor);
+ if (!ConvertPrimitiveValue(NULL, false, FieldHelper(f).GetTypeAsPrimitiveType(),
+ dst_type->GetPrimitiveType(), field_value, wide_value)) {
+ return JValue();
+ }
+ return wide_value;
+}
+
+static jboolean Field_getBoolean(JNIEnv* env, jobject javaField, jobject javaObj) {
+ return GetPrimitiveField(env, javaField, javaObj, 'Z').GetZ();
+}
+
+static jbyte Field_getByte(JNIEnv* env, jobject javaField, jobject javaObj) {
+ return GetPrimitiveField(env, javaField, javaObj, 'B').GetB();
+}
+
+static jchar Field_getChar(JNIEnv* env, jobject javaField, jobject javaObj) {
+ return GetPrimitiveField(env, javaField, javaObj, 'C').GetC();
+}
+
+static jdouble Field_getDouble(JNIEnv* env, jobject javaField, jobject javaObj) {
+ return GetPrimitiveField(env, javaField, javaObj, 'D').GetD();
+}
+
+static jfloat Field_getFloat(JNIEnv* env, jobject javaField, jobject javaObj) {
+ return GetPrimitiveField(env, javaField, javaObj, 'F').GetF();
+}
+
+static jint Field_getInt(JNIEnv* env, jobject javaField, jobject javaObj) {
+ return GetPrimitiveField(env, javaField, javaObj, 'I').GetI();
+}
+
+static jlong Field_getLong(JNIEnv* env, jobject javaField, jobject javaObj) {
+ return GetPrimitiveField(env, javaField, javaObj, 'J').GetJ();
+}
+
+static jshort Field_getShort(JNIEnv* env, jobject javaField, jobject javaObj) {
+ return GetPrimitiveField(env, javaField, javaObj, 'S').GetS();
+}
+
+static void SetFieldValue(mirror::Object* o, mirror::Field* f, const JValue& new_value,
+ bool allow_references)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(),
+ true, true)) {
+ return;
+ }
+ switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
+ case Primitive::kPrimBoolean:
+ f->SetBoolean(o, new_value.GetZ());
+ break;
+ case Primitive::kPrimByte:
+ f->SetByte(o, new_value.GetB());
+ break;
+ case Primitive::kPrimChar:
+ f->SetChar(o, new_value.GetC());
+ break;
+ case Primitive::kPrimDouble:
+ f->SetDouble(o, new_value.GetD());
+ break;
+ case Primitive::kPrimFloat:
+ f->SetFloat(o, new_value.GetF());
+ break;
+ case Primitive::kPrimInt:
+ f->SetInt(o, new_value.GetI());
+ break;
+ case Primitive::kPrimLong:
+ f->SetLong(o, new_value.GetJ());
+ break;
+ case Primitive::kPrimShort:
+ f->SetShort(o, new_value.GetS());
+ break;
+ case Primitive::kPrimNot:
+ if (allow_references) {
+ f->SetObject(o, new_value.GetL());
+ break;
+ }
+ // Else fall through to report an error.
+ case Primitive::kPrimVoid:
+ // Never okay.
+ ThrowIllegalArgumentException(NULL, StringPrintf("Not a primitive field: %s",
+ PrettyField(f).c_str()).c_str());
+ return;
+ }
+
+ // Special handling for final fields on SMP systems.
+ // We need a store/store barrier here (JMM requirement).
+ if (f->IsFinal()) {
+ ANDROID_MEMBAR_STORE();
+ }
+}
+
+static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Field* f = soa.DecodeField(env->FromReflectedField(javaField));
+
+ // Unbox the value, if necessary.
+ mirror::Object* boxed_value = soa.Decode<mirror::Object*>(javaValue);
+ JValue unboxed_value;
+ if (!UnboxPrimitiveForField(boxed_value, FieldHelper(f).GetType(), unboxed_value, f)) {
+ return;
+ }
+
+ // Check that the receiver is non-null and an instance of the field's declaring class.
+ mirror::Object* o = NULL;
+ if (!CheckReceiver(soa, javaObj, f, o)) {
+ return;
+ }
+
+ SetFieldValue(o, f, unboxed_value, true);
+}
+
+static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, char src_descriptor,
+ const JValue& new_value) {
+ ScopedObjectAccess soa(env);
+ mirror::Field* f = soa.DecodeField(env->FromReflectedField(javaField));
+ mirror::Object* o = NULL;
+ if (!CheckReceiver(soa, javaObj, f, o)) {
+ return;
+ }
+ FieldHelper fh(f);
+ if (!fh.IsPrimitiveType()) {
+ ThrowIllegalArgumentException(NULL, StringPrintf("Not a primitive field: %s",
+ PrettyField(f).c_str()).c_str());
+ return;
+ }
+
+ // Widen the value if necessary (and possible).
+ JValue wide_value;
+ mirror::Class* src_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass(src_descriptor);
+ if (!ConvertPrimitiveValue(NULL, false, src_type->GetPrimitiveType(), fh.GetTypeAsPrimitiveType(),
+ new_value, wide_value)) {
+ return;
+ }
+
+ // Write the value.
+ SetFieldValue(o, f, wide_value, false);
+}
+
+static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z) {
+ JValue value;
+ value.SetZ(z);
+ SetPrimitiveField(env, javaField, javaObj, 'Z', value);
+}
+
+static void Field_setByte(JNIEnv* env, jobject javaField, jobject javaObj, jbyte b) {
+ JValue value;
+ value.SetB(b);
+ SetPrimitiveField(env, javaField, javaObj, 'B', value);
+}
+
+static void Field_setChar(JNIEnv* env, jobject javaField, jobject javaObj, jchar c) {
+ JValue value;
+ value.SetC(c);
+ SetPrimitiveField(env, javaField, javaObj, 'C', value);
+}
+
+static void Field_setDouble(JNIEnv* env, jobject javaField, jobject javaObj, jdouble d) {
+ JValue value;
+ value.SetD(d);
+ SetPrimitiveField(env, javaField, javaObj, 'D', value);
+}
+
+static void Field_setFloat(JNIEnv* env, jobject javaField, jobject javaObj, jfloat f) {
+ JValue value;
+ value.SetF(f);
+ SetPrimitiveField(env, javaField, javaObj, 'F', value);
+}
+
+static void Field_setInt(JNIEnv* env, jobject javaField, jobject javaObj, jint i) {
+ JValue value;
+ value.SetI(i);
+ SetPrimitiveField(env, javaField, javaObj, 'I', value);
+}
+
+static void Field_setLong(JNIEnv* env, jobject javaField, jobject javaObj, jlong j) {
+ JValue value;
+ value.SetJ(j);
+ SetPrimitiveField(env, javaField, javaObj, 'J', value);
+}
+
+static void Field_setShort(JNIEnv* env, jobject javaField, jobject javaObj, jshort s) {
+ JValue value;
+ value.SetS(s);
+ SetPrimitiveField(env, javaField, javaObj, 'S', value);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Field, get, "(Ljava/lang/Object;)Ljava/lang/Object;"),
+ NATIVE_METHOD(Field, getBoolean, "(Ljava/lang/Object;)Z"),
+ NATIVE_METHOD(Field, getByte, "(Ljava/lang/Object;)B"),
+ NATIVE_METHOD(Field, getChar, "(Ljava/lang/Object;)C"),
+ NATIVE_METHOD(Field, getDouble, "(Ljava/lang/Object;)D"),
+ NATIVE_METHOD(Field, getFloat, "(Ljava/lang/Object;)F"),
+ NATIVE_METHOD(Field, getInt, "(Ljava/lang/Object;)I"),
+ NATIVE_METHOD(Field, getLong, "(Ljava/lang/Object;)J"),
+ NATIVE_METHOD(Field, getShort, "(Ljava/lang/Object;)S"),
+ NATIVE_METHOD(Field, set, "(Ljava/lang/Object;Ljava/lang/Object;)V"),
+ NATIVE_METHOD(Field, setBoolean, "(Ljava/lang/Object;Z)V"),
+ NATIVE_METHOD(Field, setByte, "(Ljava/lang/Object;B)V"),
+ NATIVE_METHOD(Field, setChar, "(Ljava/lang/Object;C)V"),
+ NATIVE_METHOD(Field, setDouble, "(Ljava/lang/Object;D)V"),
+ NATIVE_METHOD(Field, setFloat, "(Ljava/lang/Object;F)V"),
+ NATIVE_METHOD(Field, setInt, "(Ljava/lang/Object;I)V"),
+ NATIVE_METHOD(Field, setLong, "(Ljava/lang/Object;J)V"),
+ NATIVE_METHOD(Field, setShort, "(Ljava/lang/Object;S)V"),
+};
+
+void register_java_lang_reflect_Field(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/reflect/Field");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
new file mode 100644
index 0000000..14dc6a4
--- /dev/null
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "class_linker.h"
+#include "jni_internal.h"
+#include "mirror/class-inl.h"
+#include "mirror/abstract_method.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+#include "mirror/object_array-inl.h"
+#include "mirror/proxy.h"
+#include "object_utils.h"
+#include "reflection.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+
+static jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobject javaArgs) {
+ ScopedObjectAccess soa(env);
+ return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs);
+}
+
+static jobject Method_getExceptionTypesNative(JNIEnv* env, jobject javaMethod) {
+ ScopedObjectAccess soa(env);
+ mirror::AbstractMethod* proxy_method = soa.Decode<mirror::Object*>(javaMethod)->AsMethod();
+ CHECK(proxy_method->GetDeclaringClass()->IsProxyClass());
+ mirror::SynthesizedProxyClass* proxy_class =
+ down_cast<mirror::SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
+ int throws_index = -1;
+ size_t num_virt_methods = proxy_class->NumVirtualMethods();
+ for (size_t i = 0; i < num_virt_methods; i++) {
+ if (proxy_class->GetVirtualMethod(i) == proxy_method) {
+ throws_index = i;
+ break;
+ }
+ }
+ CHECK_NE(throws_index, -1);
+ mirror::ObjectArray<mirror::Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
+ return soa.AddLocalReference<jobject>(declared_exceptions->Clone(soa.Self()));
+}
+
+static jobject Method_findOverriddenMethodNative(JNIEnv* env, jobject javaMethod) {
+ ScopedObjectAccess soa(env);
+ mirror::AbstractMethod* method = soa.Decode<mirror::Object*>(javaMethod)->AsMethod();
+ return soa.AddLocalReference<jobject>(method->FindOverriddenMethod());
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Method, invoke, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
+ NATIVE_METHOD(Method, getExceptionTypesNative, "()[Ljava/lang/Class;"),
+ NATIVE_METHOD(Method, findOverriddenMethodNative, "()Ljava/lang/reflect/Method;"),
+};
+
+void register_java_lang_reflect_Method(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/reflect/Method");
+}
+
+} // namespace art
diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
new file mode 100644
index 0000000..547ce7b
--- /dev/null
+++ b/runtime/native/java_lang_reflect_Proxy.cc
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "class_linker.h"
+#include "jni_internal.h"
+#include "mirror/class_loader.h"
+#include "mirror/object_array.h"
+#include "mirror/string.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+
+static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring javaName,
+ jobjectArray javaInterfaces, jobject javaLoader,
+ jobjectArray javaMethods, jobjectArray javaThrows) {
+ ScopedObjectAccess soa(env);
+ mirror::String* name = soa.Decode<mirror::String*>(javaName);
+ mirror::ObjectArray<mirror::Class>* interfaces =
+ soa.Decode<mirror::ObjectArray<mirror::Class>*>(javaInterfaces);
+ mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
+ mirror::ObjectArray<mirror::AbstractMethod>* methods =
+ soa.Decode<mirror::ObjectArray<mirror::AbstractMethod>*>(javaMethods);
+ mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >* throws =
+ soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(javaThrows);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ mirror::Class* result = class_linker->CreateProxyClass(name, interfaces, loader, methods, throws);
+ return soa.AddLocalReference<jclass>(result);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Proxy, generateProxy, "(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/Method;[[Ljava/lang/Class;)Ljava/lang/Class;"),
+};
+
+void register_java_lang_reflect_Proxy(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/reflect/Proxy");
+}
+
+} // namespace art
diff --git a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
new file mode 100644
index 0000000..bf92e12
--- /dev/null
+++ b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "atomic.h"
+#include "jni_internal.h"
+
+namespace art {
+
+static jboolean AtomicLong_VMSupportsCS8(JNIEnv*, jclass) {
+ return QuasiAtomic::LongAtomicsUseMutexes() ? JNI_FALSE : JNI_TRUE;
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(AtomicLong, VMSupportsCS8, "()Z"),
+};
+
+void register_java_util_concurrent_atomic_AtomicLong(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/util/concurrent/atomic/AtomicLong");
+}
+
+} // namespace art
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
new file mode 100644
index 0000000..d7cd18d
--- /dev/null
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "base/logging.h"
+#include "debugger.h"
+#include "scoped_thread_state_change.h"
+#include "ScopedPrimitiveArray.h"
+
+namespace art {
+
+static void DdmServer_nativeSendChunk(JNIEnv* env, jclass, jint type,
+ jbyteArray javaData, jint offset, jint length) {
+ ScopedObjectAccess soa(env);
+ ScopedByteArrayRO data(env, javaData);
+ DCHECK_LE(offset + length, static_cast<int32_t>(data.size()));
+ Dbg::DdmSendChunk(type, length, reinterpret_cast<const uint8_t*>(&data[offset]));
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(DdmServer, nativeSendChunk, "(I[BII)V"),
+};
+
+void register_org_apache_harmony_dalvik_ddmc_DdmServer(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("org/apache/harmony/dalvik/ddmc/DdmServer");
+}
+
+} // namespace art
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
new file mode 100644
index 0000000..5ba2994
--- /dev/null
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "base/logging.h"
+#include "base/mutex.h"
+#include "debugger.h"
+#include "jni_internal.h"
+#include "scoped_thread_state_change.h"
+#include "ScopedLocalRef.h"
+#include "ScopedPrimitiveArray.h"
+#include "stack.h"
+#include "thread_list.h"
+
+namespace art {
+
+static void DdmVmInternal_enableRecentAllocations(JNIEnv*, jclass, jboolean enable) {
+ Dbg::SetAllocTrackingEnabled(enable);
+}
+
+static jbyteArray DdmVmInternal_getRecentAllocations(JNIEnv* env, jclass) {
+ ScopedObjectAccess soa(env);
+ return Dbg::GetRecentAllocations();
+}
+
+static jboolean DdmVmInternal_getRecentAllocationStatus(JNIEnv*, jclass) {
+ return Dbg::IsAllocTrackingEnabled();
+}
+
+/*
+ * Get a stack trace as an array of StackTraceElement objects. Returns
+ * NULL on failure, e.g. if the threadId couldn't be found.
+ */
+static jobjectArray DdmVmInternal_getStackTraceById(JNIEnv* env, jclass, jint thin_lock_id) {
+ ScopedLocalRef<jobject> peer(env, NULL);
+ {
+ Thread* t = Runtime::Current()->GetThreadList()->FindThreadByThinLockId(thin_lock_id);
+ if (t == NULL) {
+ return NULL;
+ }
+ ScopedObjectAccess soa(env);
+ peer.reset(soa.AddLocalReference<jobject>(t->GetPeer()));
+ }
+ if (peer.get() == NULL) {
+ return NULL;
+ }
+
+ // Suspend thread to build stack trace.
+ bool timed_out;
+ Thread* thread = Thread::SuspendForDebugger(peer.get(), true, &timed_out);
+ if (thread != NULL) {
+ jobject trace;
+ {
+ ScopedObjectAccess soa(env);
+ trace = thread->CreateInternalStackTrace(soa);
+ }
+ // Restart suspended thread.
+ Runtime::Current()->GetThreadList()->Resume(thread, true);
+ return Thread::InternalStackTraceToStackTraceElementArray(env, trace);
+ } else {
+ if (timed_out) {
+ LOG(ERROR) << "Trying to get thread's stack by id failed as the thread failed to suspend "
+ "within a generous timeout.";
+ }
+ return NULL;
+ }
+}
+
+static void ThreadCountCallback(Thread*, void* context) {
+ uint16_t& count = *reinterpret_cast<uint16_t*>(context);
+ ++count;
+}
+
+static const int kThstBytesPerEntry = 18;
+static const int kThstHeaderLen = 4;
+
+static void ThreadStatsGetterCallback(Thread* t, void* context) {
+ /*
+ * Generate the contents of a THST chunk. The data encompasses all known
+ * threads.
+ *
+ * Response has:
+ * (1b) header len
+ * (1b) bytes per entry
+ * (2b) thread count
+ * Then, for each thread:
+ * (4b) thread id
+ * (1b) thread status
+ * (4b) tid
+ * (4b) utime
+ * (4b) stime
+ * (1b) is daemon?
+ *
+ * The length fields exist in anticipation of adding additional fields
+ * without wanting to break ddms or bump the full protocol version. I don't
+ * think it warrants full versioning. They might be extraneous and could
+ * be removed from a future version.
+ */
+ char native_thread_state;
+ int utime, stime, task_cpu;
+ GetTaskStats(t->GetTid(), native_thread_state, utime, stime, task_cpu);
+
+ std::vector<uint8_t>& bytes = *reinterpret_cast<std::vector<uint8_t>*>(context);
+ JDWP::Append4BE(bytes, t->GetThinLockId());
+ JDWP::Append1BE(bytes, t->GetState());
+ JDWP::Append4BE(bytes, t->GetTid());
+ JDWP::Append4BE(bytes, utime);
+ JDWP::Append4BE(bytes, stime);
+ JDWP::Append1BE(bytes, t->IsDaemon());
+}
+
+static jbyteArray DdmVmInternal_getThreadStats(JNIEnv* env, jclass) {
+ std::vector<uint8_t> bytes;
+ Thread* self = static_cast<JNIEnvExt*>(env)->self;
+ {
+ MutexLock mu(self, *Locks::thread_list_lock_);
+ ThreadList* thread_list = Runtime::Current()->GetThreadList();
+
+ uint16_t thread_count = 0;
+ thread_list->ForEach(ThreadCountCallback, &thread_count);
+
+ JDWP::Append1BE(bytes, kThstHeaderLen);
+ JDWP::Append1BE(bytes, kThstBytesPerEntry);
+ JDWP::Append2BE(bytes, thread_count);
+
+ thread_list->ForEach(ThreadStatsGetterCallback, &bytes);
+ }
+
+ jbyteArray result = env->NewByteArray(bytes.size());
+ if (result != NULL) {
+ env->SetByteArrayRegion(result, 0, bytes.size(), reinterpret_cast<const jbyte*>(&bytes[0]));
+ }
+ return result;
+}
+
+static jint DdmVmInternal_heapInfoNotify(JNIEnv* env, jclass, jint when) {
+ ScopedObjectAccess soa(env);
+ return Dbg::DdmHandleHpifChunk(static_cast<Dbg::HpifWhen>(when));
+}
+
+static jboolean DdmVmInternal_heapSegmentNotify(JNIEnv*, jclass, jint when, jint what, jboolean native) {
+ return Dbg::DdmHandleHpsgNhsgChunk(static_cast<Dbg::HpsgWhen>(when), static_cast<Dbg::HpsgWhat>(what), native);
+}
+
+static void DdmVmInternal_threadNotify(JNIEnv*, jclass, jboolean enable) {
+ Dbg::DdmSetThreadNotification(enable);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(DdmVmInternal, enableRecentAllocations, "(Z)V"),
+ NATIVE_METHOD(DdmVmInternal, getRecentAllocations, "()[B"),
+ NATIVE_METHOD(DdmVmInternal, getRecentAllocationStatus, "()Z"),
+ NATIVE_METHOD(DdmVmInternal, getStackTraceById, "(I)[Ljava/lang/StackTraceElement;"),
+ NATIVE_METHOD(DdmVmInternal, getThreadStats, "()[B"),
+ NATIVE_METHOD(DdmVmInternal, heapInfoNotify, "(I)Z"),
+ NATIVE_METHOD(DdmVmInternal, heapSegmentNotify, "(IIZ)Z"),
+ NATIVE_METHOD(DdmVmInternal, threadNotify, "(Z)V"),
+};
+
+void register_org_apache_harmony_dalvik_ddmc_DdmVmInternal(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("org/apache/harmony/dalvik/ddmc/DdmVmInternal");
+}
+
+} // namespace art
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
new file mode 100644
index 0000000..eece81a
--- /dev/null
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "atomic.h"
+#include "gc/accounting/card_table-inl.h"
+#include "jni_internal.h"
+#include "mirror/object.h"
+#include "mirror/object-inl.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+
+static jboolean Unsafe_compareAndSwapInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint expectedValue, jint newValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ byte* raw_addr = reinterpret_cast<byte*>(obj) + offset;
+ volatile int32_t* address = reinterpret_cast<volatile int32_t*>(raw_addr);
+ // Note: android_atomic_release_cas() returns 0 on success, not failure.
+ int result = android_atomic_release_cas(expectedValue, newValue, address);
+ return (result == 0) ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean Unsafe_compareAndSwapLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong expectedValue, jlong newValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ byte* raw_addr = reinterpret_cast<byte*>(obj) + offset;
+ volatile int64_t* address = reinterpret_cast<volatile int64_t*>(raw_addr);
+ // Note: android_atomic_cmpxchg() returns 0 on success, not failure.
+ bool success = QuasiAtomic::Cas64(expectedValue, newValue, address);
+ return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean Unsafe_compareAndSwapObject(JNIEnv* env, jobject, jobject javaObj, jlong offset, jobject javaExpectedValue, jobject javaNewValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ mirror::Object* expectedValue = soa.Decode<mirror::Object*>(javaExpectedValue);
+ mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+ byte* raw_addr = reinterpret_cast<byte*>(obj) + offset;
+ int32_t* address = reinterpret_cast<int32_t*>(raw_addr);
+ // Note: android_atomic_cmpxchg() returns 0 on success, not failure.
+ int result = android_atomic_release_cas(reinterpret_cast<int32_t>(expectedValue),
+ reinterpret_cast<int32_t>(newValue), address);
+ if (result == 0) {
+ Runtime::Current()->GetHeap()->WriteBarrierField(obj, MemberOffset(offset), newValue);
+ }
+ return (result == 0) ? JNI_TRUE : JNI_FALSE;
+}
+
+static jint Unsafe_getInt(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ return obj->GetField32(MemberOffset(offset), false);
+}
+
+static jint Unsafe_getIntVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ return obj->GetField32(MemberOffset(offset), true);
+}
+
+static void Unsafe_putInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint newValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ obj->SetField32(MemberOffset(offset), newValue, false);
+}
+
+static void Unsafe_putIntVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint newValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ obj->SetField32(MemberOffset(offset), newValue, true);
+}
+
+static void Unsafe_putOrderedInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint newValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ANDROID_MEMBAR_STORE();
+ obj->SetField32(MemberOffset(offset), newValue, false);
+}
+
+static jlong Unsafe_getLong(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ return obj->GetField64(MemberOffset(offset), false);
+}
+
+static jlong Unsafe_getLongVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ return obj->GetField64(MemberOffset(offset), true);
+}
+
+static void Unsafe_putLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong newValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ obj->SetField64(MemberOffset(offset), newValue, false);
+}
+
+static void Unsafe_putLongVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong newValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ obj->SetField64(MemberOffset(offset), newValue, true);
+}
+
+static void Unsafe_putOrderedLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong newValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ANDROID_MEMBAR_STORE();
+ obj->SetField64(MemberOffset(offset), newValue, false);
+}
+
+static jobject Unsafe_getObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ mirror::Object* value = obj->GetFieldObject<mirror::Object*>(MemberOffset(offset), true);
+ return soa.AddLocalReference<jobject>(value);
+}
+
+static jobject Unsafe_getObject(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ mirror::Object* value = obj->GetFieldObject<mirror::Object*>(MemberOffset(offset), false);
+ return soa.AddLocalReference<jobject>(value);
+}
+
+static void Unsafe_putObject(JNIEnv* env, jobject, jobject javaObj, jlong offset, jobject javaNewValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+ obj->SetFieldObject(MemberOffset(offset), newValue, false);
+}
+
+static void Unsafe_putObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset, jobject javaNewValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+ obj->SetFieldObject(MemberOffset(offset), newValue, true);
+}
+
+static void Unsafe_putOrderedObject(JNIEnv* env, jobject, jobject javaObj, jlong offset, jobject javaNewValue) {
+ ScopedObjectAccess soa(env);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+ ANDROID_MEMBAR_STORE();
+ obj->SetFieldObject(MemberOffset(offset), newValue, false);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Unsafe, compareAndSwapInt, "(Ljava/lang/Object;JII)Z"),
+ NATIVE_METHOD(Unsafe, compareAndSwapLong, "(Ljava/lang/Object;JJJ)Z"),
+ NATIVE_METHOD(Unsafe, compareAndSwapObject, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z"),
+ NATIVE_METHOD(Unsafe, getIntVolatile, "(Ljava/lang/Object;J)I"),
+ NATIVE_METHOD(Unsafe, putIntVolatile, "(Ljava/lang/Object;JI)V"),
+ NATIVE_METHOD(Unsafe, getLongVolatile, "(Ljava/lang/Object;J)J"),
+ NATIVE_METHOD(Unsafe, putLongVolatile, "(Ljava/lang/Object;JJ)V"),
+ NATIVE_METHOD(Unsafe, getObjectVolatile, "(Ljava/lang/Object;J)Ljava/lang/Object;"),
+ NATIVE_METHOD(Unsafe, putObjectVolatile, "(Ljava/lang/Object;JLjava/lang/Object;)V"),
+ NATIVE_METHOD(Unsafe, getInt, "(Ljava/lang/Object;J)I"),
+ NATIVE_METHOD(Unsafe, putInt, "(Ljava/lang/Object;JI)V"),
+ NATIVE_METHOD(Unsafe, putOrderedInt, "(Ljava/lang/Object;JI)V"),
+ NATIVE_METHOD(Unsafe, getLong, "(Ljava/lang/Object;J)J"),
+ NATIVE_METHOD(Unsafe, putLong, "(Ljava/lang/Object;JJ)V"),
+ NATIVE_METHOD(Unsafe, putOrderedLong, "(Ljava/lang/Object;JJ)V"),
+ NATIVE_METHOD(Unsafe, getObject, "(Ljava/lang/Object;J)Ljava/lang/Object;"),
+ NATIVE_METHOD(Unsafe, putObject, "(Ljava/lang/Object;JLjava/lang/Object;)V"),
+ NATIVE_METHOD(Unsafe, putOrderedObject, "(Ljava/lang/Object;JLjava/lang/Object;)V"),
+};
+
+void register_sun_misc_Unsafe(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("sun/misc/Unsafe");
+}
+
+} // namespace art