Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  Utils.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "Utils.h"
#include "Types.h"

#include <android/log.h>
#include <pthread.h>
#include <sys/prctl.h>

#include "mozilla/Assertions.h"
#include "mozilla/java/GeckoAppShellWrappers.h"
#include "mozilla/java/GeckoThreadWrappers.h"

#include "AndroidBuild.h"
#include "nsAppShell.h"
#include "nsExceptionHandler.h"

namespace mozilla {
namespace jni {

namespace detail {

#define DEFINE_PRIMITIVE_TYPE_ADAPTER(NativeType, JNIType, JNIName, ABIName)   \
                                                                               \
  constexpr JNIType (JNIEnv::*TypeAdapter<NativeType>::Call)(                  \
      jobject, jmethodID, CallArgs::JValueType) MOZ_JNICALL_ABI;               \
  constexpr JNIType (JNIEnv::*TypeAdapter<NativeType>::StaticCall)(            \
      jclass, jmethodID, CallArgs::JValueType) MOZ_JNICALL_ABI;                \
  constexpr JNIType (JNIEnv::*TypeAdapter<NativeType>::Get)(jobject, jfieldID) \
      ABIName;                                                                 \
  constexpr JNIType (JNIEnv::*TypeAdapter<NativeType>::StaticGet)(             \
      jclass, jfieldID) ABIName;                                               \
  constexpr void (JNIEnv::*TypeAdapter<NativeType>::Set)(jobject, jfieldID,    \
                                                         JNIType) ABIName;     \
  constexpr void (JNIEnv::*TypeAdapter<NativeType>::StaticSet)(                \
      jclass, jfieldID, JNIType) ABIName;                                      \
  constexpr void (JNIEnv::*TypeAdapter<NativeType>::GetArray)(                 \
      JNIType##Array, jsize, jsize, JNIType*)

DEFINE_PRIMITIVE_TYPE_ADAPTER(bool, jboolean, Boolean, /*nothing*/);
DEFINE_PRIMITIVE_TYPE_ADAPTER(int8_t, jbyte, Byte, /*nothing*/);
DEFINE_PRIMITIVE_TYPE_ADAPTER(char16_t, jchar, Char/*nothing*/);
DEFINE_PRIMITIVE_TYPE_ADAPTER(int16_t, jshort, Short/*nothing*/);
DEFINE_PRIMITIVE_TYPE_ADAPTER(int32_t, jint, Int/*nothing*/);
DEFINE_PRIMITIVE_TYPE_ADAPTER(int64_t, jlong, Long/*nothing*/);
DEFINE_PRIMITIVE_TYPE_ADAPTER(float, jfloat, Float, MOZ_JNICALL_ABI);
DEFINE_PRIMITIVE_TYPE_ADAPTER(double, jdouble, Double, MOZ_JNICALL_ABI);

#undef DEFINE_PRIMITIVE_TYPE_ADAPTER

}  // namespace detail

template <>
const char ObjectBase<Object, jobject>::name[] = "java/lang/Object";
template <>
const char ObjectBase<TypedObject<jstring>, jstring>::name[] =
    "java/lang/String";
template <>
const char ObjectBase<TypedObject<jclass>, jclass>::name[] = "java/lang/Class";
template <>
const char ObjectBase<TypedObject<jthrowable>, jthrowable>::name[] =
    "java/lang/Throwable";
template <>
const char ObjectBase<BoxedObject<jboolean>, jobject>::name[] =
    "java/lang/Boolean";
template <>
const char ObjectBase<BoxedObject<jbyte>, jobject>::name[] = "java/lang/Byte";
template <>
const char ObjectBase<BoxedObject<jchar>, jobject>::name[] =
    "java/lang/Character";
template <>
const char ObjectBase<BoxedObject<jshort>, jobject>::name[] = "java/lang/Short";
template <>
const char ObjectBase<BoxedObject<jint>, jobject>::name[] = "java/lang/Integer";
template <>
const char ObjectBase<BoxedObject<jlong>, jobject>::name[] = "java/lang/Long";
template <>
const char ObjectBase<BoxedObject<jfloat>, jobject>::name[] = "java/lang/Float";
template <>
const char ObjectBase<BoxedObject<jdouble>, jobject>::name[] =
    "java/lang/Double";
template <>
const char ObjectBase<TypedObject<jbooleanArray>, jbooleanArray>::name[] = "[Z";
template <>
const char ObjectBase<TypedObject<jbyteArray>, jbyteArray>::name[] = "[B";
template <>
const char ObjectBase<TypedObject<jcharArray>, jcharArray>::name[] = "[C";
template <>
const char ObjectBase<TypedObject<jshortArray>, jshortArray>::name[] = "[S";
template <>
const char ObjectBase<TypedObject<jintArray>, jintArray>::name[] = "[I";
template <>
const char ObjectBase<TypedObject<jlongArray>, jlongArray>::name[] = "[J";
template <>
const char ObjectBase<TypedObject<jfloatArray>, jfloatArray>::name[] = "[F";
template <>
const char ObjectBase<TypedObject<jdoubleArray>, jdoubleArray>::name[] = "[D";
template <>
const char ObjectBase<TypedObject<jobjectArray>, jobjectArray>::name[] =
    "[Ljava/lang/Object;";
template <>
const char ObjectBase<ByteBuffer, jobject>::name[] = "java/nio/ByteBuffer";

JavaVM* sJavaVM;
JNIEnv* sGeckoThreadEnv;

namespace {

pthread_key_t sThreadEnvKey;
jclass sOOMErrorClass;
jobject sClassLoader;
jmethodID sClassLoaderLoadClass;

void UnregisterThreadEnv(void* env) {
  if (!env) {
    // We were never attached.
    return;
  }
  // The thread may have already been detached. In that case, it's still
  // okay to call DetachCurrentThread(); it'll simply return an error.
  // However, we must not access | env | because it may be invalid.
  MOZ_ASSERT(sJavaVM);
  sJavaVM->DetachCurrentThread();
}

}  // namespace

void SetGeckoThreadEnv(JNIEnv* aEnv) {
  MOZ_ASSERT(aEnv);
  MOZ_ASSERT(!sGeckoThreadEnv || sGeckoThreadEnv == aEnv);

  if (!sGeckoThreadEnv &&
      pthread_key_create(&sThreadEnvKey, UnregisterThreadEnv)) {
    MOZ_CRASH("Failed to initialize required TLS");
  }

  sGeckoThreadEnv = aEnv;
  MOZ_ALWAYS_TRUE(!pthread_setspecific(sThreadEnvKey, aEnv));

  MOZ_ALWAYS_TRUE(!aEnv->GetJavaVM(&sJavaVM));
  MOZ_ASSERT(sJavaVM);

  sOOMErrorClass =
      Class::GlobalRef(
          Class::LocalRef::Adopt(aEnv->FindClass("java/lang/OutOfMemoryError")))
          .Forget();
  aEnv->ExceptionClear();

  sClassLoader = Object::GlobalRef(java::GeckoThread::ClsLoader()).Forget();
  sClassLoaderLoadClass = aEnv->GetMethodID(
      Class::LocalRef::Adopt(aEnv->GetObjectClass(sClassLoader)).Get(),
      "loadClass""(Ljava/lang/String;)Ljava/lang/Class;");
  MOZ_ASSERT(sClassLoader && sClassLoaderLoadClass);
}

JNIEnv* GetEnvForThread() {
  MOZ_ASSERT(sGeckoThreadEnv);

  JNIEnv* env = static_cast<JNIEnv*>(pthread_getspecific(sThreadEnvKey));
  if (env) {
    return env;
  }

  // By default the VM has a nasty habit of overwriting our lovely
  // thread names with "Thread-<n>" making them hard to identify in a debugger,
  // so we pass the name in AttachArgs below to prevent that from happening.
  // PR_GET_NAME requires a 16 byte buffer: https://linux.die.net/man/2/prctl.
  // JNI_VERSION_1_4 is required for NewDirectByteBuffer.
  char threadName[16] = {'\0'};
  prctl(PR_GET_NAME, threadName);
  JavaVMAttachArgs attachArgs{
      .version = JNI_VERSION_1_4, .name = threadName, .group = nullptr};

  // We don't have a saved JNIEnv, so try to get one.
  // AttachCurrentThread() does the same thing as GetEnv() when a thread is
  // already attached, so we don't have to call GetEnv() at all.
  if (!sJavaVM->AttachCurrentThread(&env, &attachArgs)) {
    MOZ_ASSERT(env);
    MOZ_ALWAYS_TRUE(!pthread_setspecific(sThreadEnvKey, env));
    return env;
  }

  MOZ_CRASH("Failed to get JNIEnv for thread");
  return nullptr;  // unreachable
}

bool ThrowException(JNIEnv* aEnv, const char* aClass, const char* aMessage) {
  MOZ_ASSERT(aEnv, "Invalid thread JNI env");

  Class::LocalRef cls = Class::LocalRef::Adopt(aEnv->FindClass(aClass));
  MOZ_ASSERT(cls, "Cannot find exception class");

  return !aEnv->ThrowNew(cls.Get(), aMessage);
}

bool HandleUncaughtException(JNIEnv* aEnv) {
  MOZ_ASSERT(aEnv, "Invalid thread JNI env");

  if (!aEnv->ExceptionCheck()) {
    return false;
  }

#ifdef MOZ_CHECK_JNI
  aEnv->ExceptionDescribe();
#endif

  Throwable::LocalRef e =
      Throwable::LocalRef::Adopt(aEnv, aEnv->ExceptionOccurred());
  MOZ_ASSERT(e);
  aEnv->ExceptionClear();

  String::LocalRef stack = java::GeckoAppShell::GetExceptionStackTrace(e);
  if (stack && ReportException(aEnv, e.Get(), stack.Get())) {
    return true;
  }

  aEnv->ExceptionClear();
  java::GeckoAppShell::HandleUncaughtException(e);

  if (NS_WARN_IF(aEnv->ExceptionCheck())) {
    aEnv->ExceptionDescribe();
    aEnv->ExceptionClear();
  }

  return true;
}

bool ReportException(JNIEnv* aEnv, jthrowable aExc, jstring aStack) {
  bool result = true;

  result &= NS_SUCCEEDED(CrashReporter::RecordAnnotationNSCString(
      CrashReporter::Annotation::JavaStackTrace,
      String::Ref::From(aStack)->ToCString()));

  auto appNotes = java::GeckoAppShell::GetAppNotes();
  if (NS_WARN_IF(aEnv->ExceptionCheck())) {
    aEnv->ExceptionDescribe();
    aEnv->ExceptionClear();
  } else if (appNotes) {
    CrashReporter::AppendAppNotesToCrashReport("\n"_ns + appNotes->ToCString());
  }

  if (sOOMErrorClass && aEnv->IsInstanceOf(aExc, sOOMErrorClass)) {
    NS_ABORT_OOM(0);  // Unknown OOM size
  }
  return result;
}

namespace {

jclass sJNIObjectClass;
jfieldID sJNIObjectHandleField;

bool EnsureJNIObject(JNIEnv* env, jobject instance) {
  if (!sJNIObjectClass) {
    sJNIObjectClass =
        Class::GlobalRef(Class::LocalRef::Adopt(GetClassRef(
                             env, "org/mozilla/gecko/mozglue/JNIObject")))
            .Forget();

    sJNIObjectHandleField = env->GetFieldID(sJNIObjectClass, "mHandle""J");
  }

  MOZ_ASSERT(env->IsInstanceOf(instance, sJNIObjectClass),
             "Java class is not derived from JNIObject");
  return true;
}

}  // namespace

uintptr_t GetNativeHandle(JNIEnv* env, jobject instance) {
  if (!EnsureJNIObject(env, instance)) {
    return 0;
  }

  return static_cast<uintptr_t>(
      env->GetLongField(instance, sJNIObjectHandleField));
}

void SetNativeHandle(JNIEnv* env, jobject instance, uintptr_t handle) {
  if (!EnsureJNIObject(env, instance)) {
    return;
  }

  env->SetLongField(instance, sJNIObjectHandleField,
                    static_cast<jlong>(handle));
}

jclass GetClassRef(JNIEnv* aEnv, const char* aClassName) {
  // First try the default class loader.
  auto classRef = Class::LocalRef::Adopt(aEnv, aEnv->FindClass(aClassName));

  if ((!classRef || aEnv->ExceptionCheck()) && sClassLoader) {
    // If the default class loader failed but we have an app class loader, try
    // that. Clear the pending exception from failed FindClass call above.
    aEnv->ExceptionClear();
    classRef = Class::LocalRef::Adopt(
        aEnv,
        jclass(aEnv->CallObjectMethod(sClassLoader, sClassLoaderLoadClass,
                                      StringParam(aClassName, aEnv).Get())));
  }

  if (classRef && !aEnv->ExceptionCheck()) {
    return classRef.Forget();
  }

  __android_log_print(
      ANDROID_LOG_ERROR, "Gecko",
      ">>> FATAL JNI ERROR! FindClass(\"%s\") failed. "
      "Does the class require a newer API version? "
      "Or did ProGuard optimize away something it shouldn't have?",
      aClassName);
  aEnv->ExceptionDescribe();
  MOZ_CRASH("Cannot find JNI class");
  return nullptr;
}

void DispatchToGeckoPriorityQueue(already_AddRefed<nsIRunnable> aCall) {
  class RunnableEvent : public nsAppShell::Event {
    nsCOMPtr<nsIRunnable> mCall;

   public:
    explicit RunnableEvent(already_AddRefed<nsIRunnable> aCall)
        : mCall(aCall) {}
    void Run() override { NS_ENSURE_SUCCESS_VOID(mCall->Run()); }
  };

  nsAppShell::PostEvent(MakeUnique<RunnableEvent>(std::move(aCall)));
}

int GetAPIVersion() {
  static int32_t apiVersion = 0;
  if (!apiVersion && IsAvailable()) {
    apiVersion = java::sdk::Build::VERSION::SDK_INT();
  }
  return apiVersion;
}

pid_t GetUIThreadId() {
  static pid_t uiThreadId;
  if (!uiThreadId) {
    uiThreadId = pid_t(java::GeckoThread::UiThreadId());
  }
  return uiThreadId;
}

bool IsOOMException(JNIEnv* aEnv) {
  MOZ_ASSERT(aEnv->ExceptionCheck());
  Throwable::LocalRef e =
      Throwable::LocalRef::Adopt(aEnv, aEnv->ExceptionOccurred());
  return sOOMErrorClass && aEnv->IsInstanceOf(e.Get(), sOOMErrorClass);
}

}  // namespace jni
}  // namespace mozilla

Messung V0.5
C=94 H=100 G=96

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge