在匿名类中使用方法参数会导致SIGSEGV

时间:2013-08-08 23:36:26

标签: java android java-native-interface swig

我正在编写具有Java和本机部分的Android应用程序。 Java部分将消息发送到本机部分并接收回答。本机部分完全在单独的线程上工作,当它返回答案时,我想处理主线程上的答案。这是我扩展的Application类的一部分:

@Override
public void OnMessage(final Message msg, final long answerTo) {
    Log.i(TAG, msg.ToStr()); // OK
    handler.post(new Runnable() {
        @Override
        public void run() {
            Log.i(TAG, msg.ToStr()); // Fatal signal 11 (SIGSEGV)
                                     // at 0x74616862 (code=1), thread 13255
        }
    });
}

本机代码在其线程上调用OnMessage方法并尝试通过Handler将其传递给UI线程。当我尝试在UI线程中使用任何msg方法时,我的程序会失败并使用SEGSEGV。

重要的事实是Message类是C ++ Message类的包装器。包装器由SWIG生成。

我尝试在GDB中调试它,GDB甚至向我展示了堆栈跟踪,它以本机Message.toStr方法结束。但gdb拒绝打印变量,在当前上下文中说“无符号” * “。

请帮我解决这个问题。

2 个答案:

答案 0 :(得分:0)

我认为你没有正确使用Handler来做你想做的事情(跨线程复制对象)。在这里查看博客文章:

http://techtej.blogspot.com/2011/02/android-passing-data-between-main.html

特别是向处理程序发送消息,如下所示:

Message msg = Message.obtain();
msg.obj =  // Some Arbitrary object
mHandler.sendMessage(msg);

我不认为你这样做的方式会执行线程之间数据复制的Handler魔力,因为它只是运行Runnable。

编辑:我很想知道这是不是问题,所以即使不是,你能否在评论中回复并告诉我结果?

编辑2:所以看起来你的对象可能被存储为JNI层中的本地引用。不幸的是,这对您的目的来说还不够好,您可能需要将其作为全球参考。请注意,如果您确实将其设为全局引用,则必须在完成本机代码时自行删除它。

http://developer.android.com/training/articles/perf-jni.html#local_and_global_references

答案 1 :(得分:0)

最后我自己解决了问题。问题是,当我们从C ++调用Java时,SWIG代理方法将指向它的参数传递给Java端。类似的东西:

void SwigDirector_NativeLayerDelegate::OnMessage(Message msg, Long answer_to) {
  ...
  *((Message **)&jmsg) = &msg;
  ...
  jenv->CallStaticVoidMethod(..., jmsg, ...);
  ...
}

在Java端,另一个代理方法接收指针,用Message类的Java表示包装它并将其传递给Java方法OnMessage:

  public static void SwigDirector_NativeLayerDelegate_OnMessage(
     NativeLayerDelegate self, long msg, long answer_to) {
    self.OnMessage(new Message(msg, false), answer_to);
    // false parameter means that Message object isn't owner of 'msg' pointer, so it
    // shouldn't free it on finalize.
  }

在OnMessage完成之后,在SwigDirector_NativeLayerDelegate::OnMessage中破坏了本机Message对象,并且Java Message对象保留了指向被破坏的本机对象的指针。

<强>解决方案

我为Message对象编写了自定义文字图:

%typemap(directorin,descriptor="L$packagepath/$javaclassname;") Message
  %{*((Message**)&$input) = new Message($1);%}
%typemap(javadirectorin,descriptor="L$packagepath/$javaclassname;") Message
  %{new Message($1, true)%}

现在SwigDirector_NativeLayerDelegate :: OnMessage创建msg的副本,Java对象拥有它:

// Native
void SwigDirector_NativeLayerDelegate::OnMessage(Message msg, Long answer_to) {
  ...
  *((Message**)&jmsg) = new Message(msg);
  ...
  jenv->CallStaticVoidMethod(..., jmsg, ...);
  ...
}

// Java
public static void SwigDirector_NativeLayerDelegate_OnMessage(
     NativeLayerDelegate self, long msg, long answer_to) {
    self.OnMessage(new Message(msg, true), answer_to);
}