staticvoid VMDebug_dumpLowOverheadTraceImpl(JNIEnv* env, jclass, jstring javaProfileFileName) {
ScopedUtfChars profileFileName(env, javaProfileFileName); if (profileFileName.c_str() == nullptr) {
LOG(ERROR) << "Filename not provided, ignoring the request to dump low-overhead trace"; return;
}
TraceProfiler::Dump(profileFileName.c_str());
}
staticvoid VMDebug_dumpLowOverheadTraceFdImpl(JNIEnv*, jclass, jint originalFd) { if (originalFd < 0) {
LOG(ERROR) << "Invalid file descriptor, ignoring the request to dump low-overhead trace"; return;
}
// Set the O_CLOEXEC flag atomically here, so the file gets closed when a new process is forked. int fd = DupCloexec(originalFd); if (fd < 0) {
LOG(ERROR)
<< "Unable to dup the file descriptor, ignoring the request to dump low-overhead trace"; return;
}
static jboolean VMDebug_isDebuggerConnected(JNIEnv*, jclass) { // This function will be replaced by the debugger when it's connected. See // external/oj-libjdwp/src/share/vmDebug.c for implementation when debugger is connected. returnfalse;
}
static jlong VMDebug_lastDebuggerActivity(JNIEnv*, jclass) { // This function will be replaced by the debugger when it's connected. See // external/oj-libjdwp/src/share/vmDebug.c for implementation when debugger is connected. return -1;
}
staticvoid VMDebug_suspendAllAndSendVmStart(JNIEnv*, jclass)
REQUIRES_SHARED(Locks::mutator_lock_) { // This function will be replaced by the debugger when it's connected. See // external/oj-libjdwp/src/share/vmDebug.c for implementation when debugger is connected.
ThrowRuntimeException("ART's suspendAllAndSendVmStart is not implemented");
}
staticvoid VMDebug_printLoadedClasses(JNIEnv* env, jclass, jint flags) { class DumpClassVisitor : public ClassVisitor { public: explicit DumpClassVisitor(int dump_flags) : flags_(dump_flags) {}
static jobject VMDebug_getExecutableMethodFileOffsetsNative(JNIEnv* env,
jclass,
jobject javaExecutable) {
ScopedObjectAccess soa(env);
ObjPtr<mirror::Executable> m = soa.Decode<mirror::Executable>(javaExecutable); if (m == nullptr) {
soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "Could not find mirror::Executable for supplied jobject"); return nullptr;
}
ObjPtr<mirror::Class> c = m->GetDeclaringClass(); if (c == nullptr) {
soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "Could not find mirror::Class for supplied jobject"); return nullptr;
}
ArtMethod* art_method = m->GetArtMethod(); if (art_method == nullptr) {
soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "Could not find ArtMethod*. Possibly javaExecutable was a" "serialized constructor"); return nullptr;
} auto oat_method_quick_code = reinterpret_cast<const uint8_t*>(art_method->GetOatMethodQuickCode(kRuntimePointerSize));
// `odex_path` is the path to a given odex file containing precompiled native code.
ScopedLocalRef<jstring> odex_path = CREATE_UTF_OR_RETURN(env, oat_file->GetLocation()); // `odex_offset` is the offset of the odex_path within the program's memory. auto odex_offset = reinterpret_cast64<jlong>(elf_begin); // `method_offset` is the offset of the method *within* the odex. auto method_offset = static_cast<jlong>(adjusted_offset);
/* *ThisistheJITcase,wherethecodeisnotAOTcompiled.Inthiscase,wecompilethe *methodonthefly.Wepass`dynamic_instrumentation=true`tothejitcompilersoit *generatesacalltoastubatthebeginningofthecompiledresult.Theaddressofthestub *willbereturnedtothecaller.Thecallercanattachauprobetothestub,whichhasa *staticaddress,asopposedtotheaddressoftheJITcompiledmethod,whichisdualmappedin *memoryandthusincompatiblewithuprobes.
*/ static jobject GetJitExecutableMethodFileOffsets(JNIEnv* env, ArtMethod* art_method) { if (!com::android::art::rw::flags::dynamic_instrumentation_method_entry_hook()) { return nullptr;
}
jit::Jit* jit = Runtime::Current()->GetJit(); if (jit == nullptr) {
LOG(ERROR) << "JIT compiler is null. JIT compilation may be disabled on device. Thus, cannot " "attach dynamic instrumentation."; return nullptr;
}
ScopedObjectAccess soa(env);
// Invalidate any existing, optimized JIT compiled code for the method, as we cannot know if it // was compiled with the dynamic_instrumentation flag enabled or not.
jit::JitCodeCache* code_cache = jit->GetCodeCache(); constvoid* entry_point = art_method->GetEntryPointFromQuickCompiledCode(); if (code_cache->ContainsPc(entry_point)) { const OatQuickMethodHeader* header = OatQuickMethodHeader::FromEntryPoint(entry_point); if (CodeInfo::IsOptimized(header->GetOptimizedCodeInfoPtr())) {
LOG(INFO) << "Invalidating optimized JIT compiled code for method: "
<< art_method->PrettyMethod();
code_cache->InvalidateCompiledCodeFor(art_method, header);
}
}
// Now go ahead and compile the method. If this returns false, something has gone wrong since // we just invalidated any existing code. Compilation can fail for sufficiently large methods and // methods that have soft verification failures (like we couldn't verify that all the locks have // corresponding unlocks). These cannot be compiled. We accept this limitation among other rare // corner cases. bool jit_compiled = jit->CompileMethod(art_method,
soa.Self(),
CompilationKind::kOptimized, /* prejit= */ false, /* dynamic_instrumentation= */ true); if (!jit_compiled) {
soa.Self()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "JIT compilation failed"); return nullptr;
}
void* stub_addr = (void*)GetNopUprobeMethodEntryHookAddress();
Dl_info info; if (dladdr(stub_addr, &info) != 0) { if (info.dli_fname != NULL && info.dli_fbase != NULL) { // `so_path` is the path to the library containing the stub (e.g. libart.so) auto so_path = CREATE_UTF_OR_RETURN(env, info.dli_fname); auto so_offset = reinterpret_cast64<jlong>(info.dli_fbase); // `method_offset` is the offset of the stub within ART's library. auto method_offset = reinterpret_cast64<jlong>(stub_addr) - so_offset;
// `art_method` is a pointer to the raw ArtMethod object in memory. It can be used by the // client to disambiguate which method is instrumented, since the `so_path` and // `method_offset` will always be the same address (the stub), as opposed to the address // of the JIT compiled method. // It is okay if art_method` is deleted. Then, we wouldn't see any uprobes for this method. // It is also okay if the same address is reused for another ArtMethod. When a uprobe is set // on the new ArtMethod, the mapping for this address will be updated so we don't see stale // information. return CreateExecutableMethodFileOffsetsObject(
env, so_path.get(), reinterpret_cast<jlong>(art_method), method_offset);
}
} else {
LOG(ERROR) << "dladdr failed";
} return nullptr;
}
static jlongArray VMDebug_countInstancesOfClasses(JNIEnv* env,
jclass,
jobjectArray javaClasses,
jboolean countAssignable) {
ScopedObjectAccess soa(env);
gc::Heap* const heap = Runtime::Current()->GetHeap(); // Caller's responsibility to do GC if desired.
ObjPtr<mirror::ObjectArray<mirror::Class>> decoded_classes =
soa.Decode<mirror::ObjectArray<mirror::Class>>(javaClasses); if (decoded_classes == nullptr) { return nullptr;
}
VariableSizedHandleScope hs(soa.Self());
std::vector<Handle<mirror::Class>> classes; for (size_t i = 0, count = decoded_classes->GetLength(); i < count; ++i) {
classes.push_back(hs.NewHandle(decoded_classes->Get(i)));
}
std::vector<uint64_t> counts(classes.size(), 0u); // Heap::CountInstances can handle null and will put 0 for these classes.
heap->CountInstances(classes, countAssignable, &counts[0]);
ObjPtr<mirror::LongArray> long_counts = mirror::LongArray::Alloc(soa.Self(), counts.size()); if (long_counts == nullptr) {
soa.Self()->AssertPendingOOMException(); return nullptr;
} for (size_t i = 0; i < counts.size(); ++i) {
long_counts->Set(i, counts[i]);
} return soa.AddLocalReference<jlongArray>(long_counts);
}
// The runtime stat names for VMDebug.getRuntimeStat(). enumclass VMDebugRuntimeStatId {
kArtGcGcCount = 0,
kArtGcGcTime,
kArtGcBytesAllocated,
kArtGcBytesFreed,
kArtGcBlockingGcCount,
kArtGcBlockingGcTime,
kArtGcGcCountRateHistogram,
kArtGcBlockingGcCountRateHistogram,
kArtGcObjectsAllocated,
kArtGcTotalTimeWaitingForGc,
kArtGcPreOomeGcCount,
kNumRuntimeStats,
};
staticbool SetRuntimeStatValue(Thread* self,
Handle<mirror::ObjectArray<mirror::String>> array,
VMDebugRuntimeStatId id, const std::string& value) REQUIRES_SHARED(Locks::mutator_lock_) {
ObjPtr<mirror::String> ovalue = mirror::String::AllocFromModifiedUtf8(self, value.c_str()); if (ovalue == nullptr) {
DCHECK(self->IsExceptionPending()); returnfalse;
} // We're initializing a newly allocated array object, so we do not need to record that under // a transaction. If the transaction is aborted, the whole object shall be unreachable.
array->SetWithoutChecks</*kTransactionActive=*/ false, /*kCheckTransaction=*/ false>( static_cast<int32_t>(id), ovalue); returntrue;
}
// Android application ID naming convention states: // "The name can contain uppercase or lowercase letters, numbers, and underscores ('_')" // This is fine to convert to std::string constchar* c_process_name = env->GetStringUTFChars(process_name, NULL);
Runtime::Current()->GetRuntimeCallbacks()->SetCurrentProcessName(std::string(c_process_name));
env->ReleaseStringUTFChars(process_name, c_process_name);
}
// Android application ID naming convention states: // "The name can contain uppercase or lowercase letters, numbers, and underscores ('_')" // This is fine to convert to std::string constchar* c_package_name = env->GetStringUTFChars(package_name, NULL);
Runtime::Current()->GetRuntimeCallbacks()->AddApplication(std::string(c_package_name));
env->ReleaseStringUTFChars(package_name, c_package_name);
}
// Android application ID naming convention states: // "The name can contain uppercase or lowercase letters, numbers, and underscores ('_')" // This is fine to convert to std::string constchar* c_package_name = env->GetStringUTFChars(package_name, NULL);
Runtime::Current()->GetRuntimeCallbacks()->RemoveApplication(std::string(c_package_name));
env->ReleaseStringUTFChars(package_name, c_package_name);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.