Запуск сгенерированного машинного кода ARM на Android дает исключение UnsupportedOperationException с растровыми объектами Java

Мы ( http://www.mosync.com/) скомпилировали наш компилятор ARM с помощью Android NDK, который берет наш внутренний байт-код и генерирует машинный код ARM. При выполнении перекомпилированного кода мы видим огромное увеличение производительности, за одним небольшим исключением, мы не можем использовать какие-либо операции с битовой картой Java. Нативная система использует функцию, которая заботится обо всех вызовах на стороне Java, которые вызывает перекомпилированный код. На стороне Java (Dalvik) у нас есть привязки к функциям Android. Нет проблем при перекомпиляции кода или при выполнении машинного кода. Точно такой же исходный код работает на Symbian и Windows Mobile 6.x, поэтому, похоже, перекомпилятор генерирует правильный машинный код ARM. Как я уже сказал, проблема в том, что мы не можем использовать объекты Java Bitmap. Мы убедились, что параметры, отправляемые из кода Java, верны, и мы попытались проследить за выполнением в собственных системах JNI Android. Проблема в том, что мы получаем UnsupportedOperationException с "размер должен соответствовать 32 битам". Проблема кажется последовательной на Android 1.5 до 2.3. Мы не пробовали перекомпиляцию на устройствах Android 3.

Является ли это ошибкой, с которой столкнулись другие люди, я думаю, что другие разработчики сделали подобные вещи.

2 ответа

Решение

Мне удалось найти обходной путь. Когда я обертываю все вызовы Bitmap.createBitmap внутри Activity.runOnUiThread(), это работает.

Я нашел сообщение в dalvik_system_VMRuntime.c:

/*
 * public native boolean trackExternalAllocation(long size)
 *
 * Asks the VM if <size> bytes can be allocated in an external heap.
 * This information may be used to limit the amount of memory available
 * to Dalvik threads.  Returns false if the VM would rather that the caller
 * did not allocate that much memory.  If the call returns false, the VM
 * will not update its internal counts.
 */
static void Dalvik_dalvik_system_VMRuntime_trackExternalAllocation(
    const u4* args, JValue* pResult)
{
    s8 longSize = GET_ARG_LONG(args, 1);

    /* Fit in 32 bits. */
    if (longSize < 0) {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "size must be positive");
        RETURN_VOID();
    } else if (longSize > INT_MAX) {
        dvmThrowException("Ljava/lang/UnsupportedOperationException;",
            "size must fit in 32 bits");
        RETURN_VOID();
    }
    RETURN_BOOLEAN(dvmTrackExternalAllocation((size_t)longSize));
}

Этот метод вызывается, например, из GraphicsJNI::setJavaPixelRef:

size_t size = size64.get32();
jlong jsize = size;  // the VM wants longs for the size
if (reportSizeToVM) {
    //    SkDebugf("-------------- inform VM we've allocated %d bytes\n", size);
    bool r = env->CallBooleanMethod(gVMRuntime_singleton,
                                gVMRuntime_trackExternalAllocationMethodID,
                                jsize);

Я бы сказал, что кажется, что код, который вы вызываете, пытается выделить слишком большой размер. Если вы показываете фактический сбой вызова Java и значения всех аргументов, которые вы ему передаете, может быть легче найти причину.

Другие вопросы по тегам