Запуск сгенерированного машинного кода 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 и значения всех аргументов, которые вы ему передаете, может быть легче найти причину.