1

I am trying to call a java method from with android/SDL c++ code to popup or update a Toast. but I am getting

W/dalvikvm( 4026): Invalid indirect reference 0x41e6b710 in decodeIndirectRef

The Toast appears to work when updated from Java side (eg. from a regularly called Handler) and my message string will Log() OK, but as soon as a set anything (even a "Hello World") in the setText() I get the crash.

my main.cc (with reference to https://wiki.libsdl.org/SDL_AndroidGetJNIEnv)

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#include "SDL.h"

#include <android/log.h>
#include <jni.h>

#define log(...) __android_log_print(ANDROID_LOG_INFO, "SDL/c", __VA_ARGS__);

void progressMessage(const char *message)
{
    log("0) '%s'", message);
    JNIEnv *jni_env = (JNIEnv*)SDL_AndroidGetJNIEnv();
    log("1) env %08x", (unsigned int)jni_env);
    jobject jni_activity = (jobject)SDL_AndroidGetActivity();
    log("2) act %08x", (unsigned int)jni_activity);

    jclass jni_class(jni_env->GetObjectClass(jni_activity));
    log("3) cls %08x", (unsigned int)jni_class);
    jstring jstr = jni_env->NewStringUTF(message);
    log("4) str %08x", (unsigned int)jstr);
    jmethodID method = jni_env->GetMethodID(jni_class,
    "progressMessage", "(Ljava/lang/String;)V    ");
    log("5) met %08x", (unsigned int)method);

    jni_env->CallVoidMethod(jni_activity, method, jstr);
    log("6) done");
    jni_env->DeleteLocalRef(jni_activity);
    jni_env->DeleteLocalRef(jni_class);
}

int main(int argc, char *argv[])
{
    SDL_Window *window;
    SDL_Renderer *renderer;

    if(SDL_CreateWindowAndRenderer(0, 0, 0, &window, &renderer) < 0)
        exit(2);

    Uint8 done = 0;
    SDL_Event event;

    int loop = 0;
    while(!done)
    {
        if (loop % 100 == 0)
        {
            char message[256];
            sprintf(message, "Log %d", loop);
            progressMessage(message);
        }

        while(SDL_PollEvent(&event))
        {
            if(event.type == SDL_QUIT || event.type == SDL_KEYDOWN || event.type == SDL_FINGERDOWN)
            {
                done = 1;
            }
        }

        int col = loop % 512;
        if (col > 255)
            col = 256-col;
        SDL_SetRenderDrawColor(renderer, col,col,col, 0xFF);
        SDL_RenderClear(renderer);
        SDL_RenderPresent(renderer);
        SDL_Delay(10);

        loop++;
    }

    exit(0);
}

My class

package com.example.test;

import android.util.Log;
import android.widget.Toast;
import android.os.Bundle;

import org.libsdl.app.SDLActivity; 

public class SDLTest extends SDLActivity {

    public static Toast toast = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        toast = Toast.makeText(this, "", Toast.LENGTH_SHORT);

        this.progressMessage("Starting");
    }

    public void progressMessage(String message) {
        Log.i("SDL/java", message);
        toast.setText(message);
        toast.setDuration(Toast.LENGTH_SHORT);
        toast.show();
    }
}

and here's the logcat output

I/SDL     ( 4561): SDL_Android_Init()
I/SDL     ( 4561): SDL_Android_Init() finished!
I/SDL/c   ( 4561): 0) 'Log 0'
I/SDL/c   ( 4561): 1) env 76160ec8
I/SDL/c   ( 4561): 2) act 2d900009
I/SDL/c   ( 4561): 3) cls 1dd00011
I/SDL/c   ( 4561): 4) str 1d200015
I/SDL/c   ( 4561): 5) met 6d788688
I/SDL/java( 4561): Log 0
I/SDL/c   ( 4561): 6) done
I/ActivityManager(  594): Displayed com.example.test/.SDLTest: +218ms
V/SDL     ( 4561): onWindowFocusChanged(): true
I/SDL/c   ( 4561): 0) 'Log 100'
I/SDL/c   ( 4561): 1) env 76160ec8
I/SDL/c   ( 4561): 2) act 1de00011
I/SDL/c   ( 4561): 3) cls 2da00009
I/SDL/c   ( 4561): 4) str 1dc00019
I/SDL/c   ( 4561): 5) met 6d788688
I/SDL/java( 4561): Log 100
I/SDL/c   ( 4561): 6) done
I/SDL/c   ( 4561): 0) 'Log 200'
I/SDL/c   ( 4561): 1) env 76160ec8
I/SDL/c   ( 4561): 2) act 41e64a80
W/dalvikvm( 4561): Invalid indirect reference 0x41e64a80 in decodeIndirectRef
I/dalvikvm( 4561): "SDLThread" prio=5 tid=11 RUNNABLE
I/dalvikvm( 4561):   | group="main" sCount=0 dsCount=0 obj=0x41e75fd0 self=0x761607a0
I/dalvikvm( 4561):   | sysTid=4579 nice=0 sched=0/0 cgrp=apps handle=1981156344
I/dalvikvm( 4561):   | state=R schedstat=( 0 0 0 ) utm=3 stm=11 core=1
I/dalvikvm( 4561):   at org.libsdl.app.SDLActivity.nativeInit(Native Method)
I/dalvikvm( 4561):   at org.libsdl.app.SDLMain.run(SDLActivity.java:915)
I/dalvikvm( 4561):   at java.lang.Thread.run(Thread.java:841)
I/dalvikvm( 4561): 
E/dalvikvm( 4561): VM aborting

It appears that the 'activity' pointer has become corrupted.

(I'm also hoping that env, activity, class and method can all be cached)

What have I missed?

2
  • I see the function main(). I'm not familiar with SDL, but usually the function main() is not called, instead, native functions are called from Java. At second, all UI stuff must be accessed from the main thread (this includes the toast). If you try to access the activity from another thread, well... there may be problems. Commented Dec 11, 2014 at 14:20
  • Hi, SDL provides SDLActivity which handles all the jni startup and then calls your main(). My framework was based on dinomage.com/2013/01/howto-sdl-on-android Commented Dec 11, 2014 at 14:57

1 Answer 1

1

This is a threading problem.

SDL starts SDLMain() in a separate thread so calling those Java methods is problematic!

Ideal solution would be to run SDL in some unthreaded mode as mentioned here http://theorangeduck.com/page/issues-sdl-ios-and-android

but I have solved my immediate problem by exposing sendCommand in SDLActivity

public boolean sendCommand(int command, Object data)

and implementing a message system which can be processed by

public void progressMessage(String message) {
    toast.setText(message);
    toast.setDuration(Toast.LENGTH_LONG);
    toast.show();
}

public static boolean sendCommand(int command, String string) {
    return SDLActivity.mSingleton.sendCommand(command, string);
}

@Override
protected boolean onUnhandledMessage(int command, Object param) {
    boolean ok = true;
    switch (command) {
    case COMMAND_USER_PROGRESS:
        progressMessage((String)param);
        break;
    default:
        ok = false;
        break;
    }
    return ok;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.