Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b592f4e authored by Brett Chabot's avatar Brett Chabot Committed by Jerome Gaillard
Browse files

Fix ICU-related failures in Robolectric.

A recent change to HostRuntime modified it to read the ICU data
file location from an android.os.SystemProperties using a native call instead of a java.lang.System property.

This breaks Robolectric tests which specify icu.data.path as a
java.lang.System property.

It appears layoutlib makes this work by calling back to Bridge.setSystemProperties from JNI *after* the native SystemProperties methods have been bound. It feels circular to add a JNI to java call just to avoid a JNI to java.lang.System.getProperty call.

This commit fixes the issue by falling back to read ICU data path from a java property if the android system property is not set.

This also refactors out a common getJavaProperty method.

Flag: NONE host-only change
Test: atest android.database.SQLiteDatabaseTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:990cc8ae811d581edfea8b540459f40e55e26ac9)
Merged-In: I728594fa3408d60fa4f199a72605f52db75dc205
Change-Id: I728594fa3408d60fa4f199a72605f52db75dc205
parent d6a86e84
Loading
Loading
Loading
Loading
+36 −32
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/AndroidRuntime.h>
#include <jni_wrappers.h>
#include <jni_wrappers.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <nativehelper/jni_macros.h>
#include <nativehelper/jni_macros.h>
#include <unicode/putil.h>
#include <unicode/putil.h>
#include <unicode/udata.h>
#include <unicode/udata.h>
@@ -259,11 +260,21 @@ static void* mmapFile(const char* dataFilePath) {
#endif
#endif
}
}


// Loads the ICU data file from the location specified in the system property ro.icu.data.path
// returns result from java.lang.System.getProperty
static void loadIcuData() {
static string getJavaProperty(JNIEnv* env, const char* property_name) {
    string icuPath = base::GetProperty("ro.icu.data.path", "");
    jclass system = FindClassOrDie(env, "java/lang/System");
    if (!icuPath.empty()) {
    jmethodID getPropertyMethod =
        // Set the location of ICU data
            GetStaticMethodIDOrDie(env, system, "getProperty",
                                   "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");

    auto jString = (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
                                                        env->NewStringUTF(property_name),
                                                        env->NewStringUTF(""));
    ScopedUtfChars chars(env, jString);
    return string(chars.c_str());
}

static void loadIcuData(string icuPath) {
    void* addr = mmapFile(icuPath.c_str());
    void* addr = mmapFile(icuPath.c_str());
    UErrorCode err = U_ZERO_ERROR;
    UErrorCode err = U_ZERO_ERROR;
    udata_setCommonData(addr, &err);
    udata_setCommonData(addr, &err);
@@ -271,23 +282,27 @@ static void loadIcuData() {
        ALOGE("Unable to load ICU data\n");
        ALOGE("Unable to load ICU data\n");
    }
    }
}
}

// Loads the ICU data file from the location specified in properties.
// First try specified in the system property ro.icu.data.path,
// then fallback to java property icu.data.path
static void loadIcuData() {
    string icuPath = base::GetProperty("ro.icu.data.path", "");
    if (!icuPath.empty()) {
        loadIcuData(icuPath);
    } else {
        // fallback to read from java.lang.System.getProperty
        JNIEnv* env = AndroidRuntime::getJNIEnv();
        string icuPathFromJava = getJavaProperty(env, "icu.data.path");
        if (!icuPathFromJava.empty()) {
            loadIcuData(icuPathFromJava);
        }
    }
}
}


static int register_android_core_classes(JNIEnv* env) {
static int register_android_core_classes(JNIEnv* env) {
    jclass system = FindClassOrDie(env, "java/lang/System");
    string nativesClassesString = getJavaProperty(env, "core_native_classes");
    jmethodID getPropertyMethod =
            GetStaticMethodIDOrDie(env, system, "getProperty",
                                   "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");

    // 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);
    vector<string> classesToRegister = parseCsv(nativesClassesString);
    env->ReleaseStringUTFChars(nativesClassesJString, nativesClassesArray);


    if (register_jni_procs(gRegJNIMap, classesToRegister, env) < 0) {
    if (register_jni_procs(gRegJNIMap, classesToRegister, env) < 0) {
        return JNI_ERR;
        return JNI_ERR;
@@ -360,18 +375,7 @@ void AndroidRuntime::onStarted() {
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    JNIEnv* env = AndroidRuntime::getJNIEnv();


    jclass system = FindClassOrDie(env, "java/lang/System");
    auto method_binding_format = getJavaProperty(env, "method_binding_format");
    jmethodID getPropertyMethod =
            GetStaticMethodIDOrDie(env, system, "getProperty",
                                   "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");

    auto methodBindingJString =
            (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
                                                 env->NewStringUTF("method_binding_format"),
                                                 env->NewStringUTF(""));
    const char* methodBindingChars = env->GetStringUTFChars(methodBindingJString, 0);
    auto method_binding_format = string(methodBindingChars);
    env->ReleaseStringUTFChars(methodBindingJString, methodBindingChars);


    setJniMethodFormat(method_binding_format);
    setJniMethodFormat(method_binding_format);