Merge "Implements a basic version of AndroidRuntime for host" into main
diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp
index 30c926c..7e2a5ac 100644
--- a/core/jni/platform/host/HostRuntime.cpp
+++ b/core/jni/platform/host/HostRuntime.cpp
@@ -17,6 +17,8 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android/graphics/jni_runtime.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <jni_wrappers.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/jni_macros.h>
#include <unicode/putil.h>
@@ -27,9 +29,6 @@
#include <unordered_map>
#include <vector>
-#include "android_view_InputDevice.h"
-#include "core_jni_helpers.h"
-#include "jni.h"
#ifdef _WIN32
#include <windows.h>
#else
@@ -38,8 +37,6 @@
#include <sys/stat.h>
#endif
-#include <iostream>
-
using namespace std;
/*
@@ -49,12 +46,6 @@
* (see AndroidRuntime.cpp).
*/
-static JavaVM* javaVM;
-static jclass bridge;
-static jclass layoutLog;
-static jmethodID getLogId;
-static jmethodID logMethodId;
-
extern int register_android_os_Binder(JNIEnv* env);
extern int register_libcore_util_NativeAllocationRegistry_Delegate(JNIEnv* env);
@@ -168,28 +159,9 @@
}
}
- if (register_android_graphics_classes(env) < 0) {
- return -1;
- }
-
return 0;
}
-int AndroidRuntime::registerNativeMethods(JNIEnv* env, const char* className,
- const JNINativeMethod* gMethods, int numMethods) {
- return jniRegisterNativeMethods(env, className, gMethods, numMethods);
-}
-
-JNIEnv* AndroidRuntime::getJNIEnv() {
- JNIEnv* env;
- if (javaVM->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) return nullptr;
- return env;
-}
-
-JavaVM* AndroidRuntime::getJavaVM() {
- return javaVM;
-}
-
static vector<string> parseCsv(const string& csvString) {
vector<string> result;
istringstream stream(csvString);
@@ -200,29 +172,6 @@
return result;
}
-void LayoutlibLogger(base::LogId, base::LogSeverity severity, const char* tag, const char* file,
- unsigned int line, const char* message) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- jint logPrio = severity;
- jstring tagString = env->NewStringUTF(tag);
- jstring messageString = env->NewStringUTF(message);
-
- jobject bridgeLog = env->CallStaticObjectMethod(bridge, getLogId);
-
- env->CallVoidMethod(bridgeLog, logMethodId, logPrio, tagString, messageString);
-
- env->DeleteLocalRef(tagString);
- env->DeleteLocalRef(messageString);
- env->DeleteLocalRef(bridgeLog);
-}
-
-void LayoutlibAborter(const char* abort_message) {
- // Layoutlib should not call abort() as it would terminate Studio.
- // Throw an exception back to Java instead.
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- jniThrowRuntimeException(env, "The Android framework has encountered a fatal error");
-}
-
// This method has been copied/adapted from system/core/init/property_service.cpp
// If the ro.product.cpu.abilist* properties have not been explicitly
// set, derive them from ro.system.product.cpu.abilist* properties.
@@ -311,62 +260,49 @@
#endif
}
-static bool init_icu(const char* dataPath) {
- void* addr = mmapFile(dataPath);
- UErrorCode err = U_ZERO_ERROR;
- udata_setCommonData(addr, &err);
- if (err != U_ZERO_ERROR) {
- return false;
- }
- return true;
-}
-
-// Creates an array of InputDevice from key character map files
-static void init_keyboard(JNIEnv* env, const vector<string>& keyboardPaths) {
- jclass inputDevice = FindClassOrDie(env, "android/view/InputDevice");
- jobjectArray inputDevicesArray =
- env->NewObjectArray(keyboardPaths.size(), inputDevice, nullptr);
- int keyboardId = 1;
-
- for (const string& path : keyboardPaths) {
- base::Result<std::shared_ptr<KeyCharacterMap>> charMap =
- KeyCharacterMap::load(path, KeyCharacterMap::Format::BASE);
-
- InputDeviceInfo info = InputDeviceInfo();
- info.initialize(keyboardId, 0, 0, InputDeviceIdentifier(),
- "keyboard " + std::to_string(keyboardId), true, false,
- ui::LogicalDisplayId::DEFAULT);
- info.setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- info.setKeyCharacterMap(*charMap);
-
- jobject inputDeviceObj = android_view_InputDevice_create(env, info);
- if (inputDeviceObj) {
- env->SetObjectArrayElement(inputDevicesArray, keyboardId - 1, inputDeviceObj);
- env->DeleteLocalRef(inputDeviceObj);
+// Loads the ICU data file from the location specified in the system property ro.icu.data.path
+static void loadIcuData() {
+ string icuPath = base::GetProperty("ro.icu.data.path", "");
+ if (!icuPath.empty()) {
+ // Set the location of ICU data
+ void* addr = mmapFile(icuPath.c_str());
+ UErrorCode err = U_ZERO_ERROR;
+ udata_setCommonData(addr, &err);
+ if (err != U_ZERO_ERROR) {
+ ALOGE("Unable to load ICU data\n");
}
- keyboardId++;
}
-
- if (bridge == nullptr) {
- bridge = FindClassOrDie(env, "com/android/layoutlib/bridge/Bridge");
- bridge = MakeGlobalRefOrDie(env, bridge);
- }
- jmethodID setInputManager = GetStaticMethodIDOrDie(env, bridge, "setInputManager",
- "([Landroid/view/InputDevice;)V");
- env->CallStaticVoidMethod(bridge, setInputManager, inputDevicesArray);
- env->DeleteLocalRef(inputDevicesArray);
}
-} // namespace android
+static int register_android_core_classes(JNIEnv* env) {
+ jclass system = FindClassOrDie(env, "java/lang/System");
+ jmethodID getPropertyMethod =
+ GetStaticMethodIDOrDie(env, system, "getProperty",
+ "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
-using namespace android;
+ // Get the names of classes that need to register their native methods
+ auto nativesClassesJString =
+ (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
+ env->NewStringUTF("core_native_classes"),
+ env->NewStringUTF(""));
+ const char* nativesClassesArray = env->GetStringUTFChars(nativesClassesJString, nullptr);
+ string nativesClassesString(nativesClassesArray);
+ vector<string> classesToRegister = parseCsv(nativesClassesString);
+ env->ReleaseStringUTFChars(nativesClassesJString, nativesClassesArray);
+
+ if (register_jni_procs(gRegJNIMap, classesToRegister, env) < 0) {
+ return JNI_ERR;
+ }
+
+ return 0;
+}
// Called right before aborting by LOG_ALWAYS_FATAL. Print the pending exception.
void abort_handler(const char* abort_message) {
ALOGE("About to abort the process...");
- JNIEnv* env = NULL;
- if (javaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (env == nullptr) {
ALOGE("vm->GetEnv() failed");
return;
}
@@ -377,107 +313,98 @@
ALOGE("Aborting because: %s", abort_message);
}
+// ------------------ Host implementation of AndroidRuntime ------------------
+
+/*static*/ JavaVM* AndroidRuntime::mJavaVM;
+
+/*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env, const char* className,
+ const JNINativeMethod* gMethods,
+ int numMethods) {
+ return jniRegisterNativeMethods(env, className, gMethods, numMethods);
+}
+
+/*static*/ JNIEnv* AndroidRuntime::getJNIEnv() {
+ JNIEnv* env;
+ JavaVM* vm = AndroidRuntime::getJavaVM();
+ if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) {
+ return nullptr;
+ }
+ return env;
+}
+
+/*static*/ JavaVM* AndroidRuntime::getJavaVM() {
+ return mJavaVM;
+}
+
+/*static*/ int AndroidRuntime::startReg(JNIEnv* env) {
+ if (register_android_core_classes(env) < 0) {
+ return JNI_ERR;
+ }
+ if (register_android_graphics_classes(env) < 0) {
+ return JNI_ERR;
+ }
+ return 0;
+}
+
+void AndroidRuntime::onVmCreated(JNIEnv* env) {
+ env->GetJavaVM(&mJavaVM);
+}
+
+void AndroidRuntime::onStarted() {
+ property_initialize_ro_cpu_abilist();
+ loadIcuData();
+
+ // Use English locale for number format to ensure correct parsing of floats when using strtof
+ setlocale(LC_NUMERIC, "en_US.UTF-8");
+}
+
+void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ // Register native functions.
+ if (startReg(env) < 0) {
+ ALOGE("Unable to register all android native methods\n");
+ }
+ onStarted();
+}
+
+AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength)
+ : mExitWithoutCleanup(false), mArgBlockStart(argBlockStart), mArgBlockLength(argBlockLength) {
+ init_android_graphics();
+}
+
+AndroidRuntime::~AndroidRuntime() {}
+
+// Version of AndroidRuntime to run on host
+class HostRuntime : public AndroidRuntime {
+public:
+ HostRuntime() : AndroidRuntime(nullptr, 0) {}
+
+ void onVmCreated(JNIEnv* env) override {
+ AndroidRuntime::onVmCreated(env);
+ // initialize logging, so ANDROD_LOG_TAGS env variable is respected
+ android::base::InitLogging(nullptr, android::base::StderrLogger, abort_handler);
+ }
+
+ void onStarted() override {
+ AndroidRuntime::onStarted();
+ }
+};
+
+} // namespace android
+
+using namespace android;
+
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
- javaVM = vm;
JNIEnv* env = nullptr;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
- __android_log_set_aborter(abort_handler);
+ Vector<String8> args;
+ HostRuntime runtime;
- init_android_graphics();
-
- // Configuration is stored as java System properties.
- // Get a reference to System.getProperty
- jclass system = FindClassOrDie(env, "java/lang/System");
- jmethodID getPropertyMethod =
- GetStaticMethodIDOrDie(env, system, "getProperty",
- "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
-
- // Java system properties that contain LayoutLib config. The initial values in the map
- // are the default values if the property is not specified.
- std::unordered_map<std::string, std::string> systemProperties =
- {{"core_native_classes", ""},
- {"register_properties_during_load", ""},
- {"icu.data.path", ""},
- {"use_bridge_for_logging", ""},
- {"keyboard_paths", ""}};
-
- for (auto& [name, defaultValue] : systemProperties) {
- jstring propertyString =
- (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
- env->NewStringUTF(name.c_str()),
- env->NewStringUTF(defaultValue.c_str()));
- const char* propertyChars = env->GetStringUTFChars(propertyString, 0);
- systemProperties[name] = string(propertyChars);
- env->ReleaseStringUTFChars(propertyString, propertyChars);
- }
- // Get the names of classes that need to register their native methods
- vector<string> classesToRegister = parseCsv(systemProperties["core_native_classes"]);
-
- if (systemProperties["register_properties_during_load"] == "true") {
- // Set the system properties first as they could be used in the static initialization of
- // other classes
- if (register_android_os_SystemProperties(env) < 0) {
- return JNI_ERR;
- }
- classesToRegister.erase(find(classesToRegister.begin(), classesToRegister.end(),
- "android.os.SystemProperties"));
- bridge = FindClassOrDie(env, "com/android/layoutlib/bridge/Bridge");
- bridge = MakeGlobalRefOrDie(env, bridge);
- jmethodID setSystemPropertiesMethod =
- GetStaticMethodIDOrDie(env, bridge, "setSystemProperties", "()V");
- env->CallStaticVoidMethod(bridge, setSystemPropertiesMethod);
- property_initialize_ro_cpu_abilist();
- }
-
- if (register_jni_procs(gRegJNIMap, classesToRegister, env) < 0) {
- return JNI_ERR;
- }
-
- if (!systemProperties["icu.data.path"].empty()) {
- // Set the location of ICU data
- bool icuInitialized = init_icu(systemProperties["icu.data.path"].c_str());
- if (!icuInitialized) {
- return JNI_ERR;
- }
- }
-
- if (systemProperties["use_bridge_for_logging"] == "true") {
- layoutLog = FindClassOrDie(env, "com/android/ide/common/rendering/api/ILayoutLog");
- layoutLog = MakeGlobalRefOrDie(env, layoutLog);
- logMethodId = GetMethodIDOrDie(env, layoutLog, "logAndroidFramework",
- "(ILjava/lang/String;Ljava/lang/String;)V");
- if (bridge == nullptr) {
- bridge = FindClassOrDie(env, "com/android/layoutlib/bridge/Bridge");
- bridge = MakeGlobalRefOrDie(env, bridge);
- }
- getLogId = GetStaticMethodIDOrDie(env, bridge, "getLog",
- "()Lcom/android/ide/common/rendering/api/ILayoutLog;");
- android::base::SetLogger(LayoutlibLogger);
- android::base::SetAborter(LayoutlibAborter);
- } else {
- // initialize logging, so ANDROD_LOG_TAGS env variable is respected
- android::base::InitLogging(nullptr, android::base::StderrLogger);
- }
-
- // Use English locale for number format to ensure correct parsing of floats when using strtof
- setlocale(LC_NUMERIC, "en_US.UTF-8");
-
- if (!systemProperties["keyboard_paths"].empty()) {
- vector<string> keyboardPaths = parseCsv(systemProperties["keyboard_paths"]);
- init_keyboard(env, keyboardPaths);
- } else {
- fprintf(stderr, "Skip initializing keyboard\n");
- }
+ runtime.onVmCreated(env);
+ runtime.start("HostRuntime", args, false);
return JNI_VERSION_1_6;
}
-
-JNIEXPORT void JNI_OnUnload(JavaVM* vm, void*) {
- JNIEnv* env = nullptr;
- vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
- env->DeleteGlobalRef(bridge);
- env->DeleteGlobalRef(layoutLog);
-}