简体   繁体   English

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

[英]Using method parameters in anonymous class causes SIGSEGV

I'm writing Android application that has Java and native part. 我正在编写具有Java和本机部分的Android应用程序。 Java part sends messages to native part and receives answers back. Java部分将消息发送到本机部分并接收返回的答案。 Native part does all work on separate thread and when it returns answer I want to handle answers on main thread. 本机部分在单独的线程上完成所有工作,当它返回答案时,我想处理主线程上的答案。 Here is part of my extended Application class: 这是我扩展的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
        }
    });
}

Native code calls OnMessage method on it's thread and trying to pass it to UI thread through Handler. 本机代码在其线程上调用OnMessage方法,并尝试通过Handler将其传递给UI线程。 And when I try to use any method of msg inside UI thread my program fails with SEGSEGV. 当我尝试在UI线程中使用msg的任何方法时,我的程序因SEGSEGV失败。

Significant fact is that Message class is the wrapper for C++ Message class. 重要的事实是Message类是C ++ Message类的包装器。 Wrapper was generated by SWIG . 包装是由SWIG生成的。

I tried to debug it in GDB, and GDB even shows me stack trace, which ends in native Message.toStr method. 我试图在GDB中调试它,GDB甚至向我显示了堆栈跟踪,该跟踪以本机Message.toStr方法结尾。 But gdb refuses to print variables, saying "No symbol " * " in current context". 但是gdb拒绝打印变量,说“在当前上下文中没有符号“ * ”。

Please, help me to resolve this issue. 请帮我解决这个问题。

I don't think you are using Handler properly for what you are trying to do (copy object across threads). 我认为您没有为要执行的操作正确使用Handler(跨线程复制对象)。 Check out the blog post here: 在此处查看博客文章:

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

Specifically the sending of messages to handlers like this: 具体来说,是将消息发送到处理程序,如下所示:

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

I don't think the way you are doing this performs the Handler magic of data copy between threads because it's just running a Runnable. 我不认为您执行此操作的方式会在线程之间执行Handler复制数据的魔力,因为它只是运行Runnable。

EDIT: I am curious to see if this was the issue, so even if it wasn't could you respond in a comment and let me know the outcome? 编辑:我很好奇,看看这是否是问题,所以即使不是,您也不能在评论中回复让我知道结果吗?

EDIT 2: So it looks like your object is probably being stored as a local ref in the JNI Layer. 编辑2:所以看起来您的对象可能被存储为JNI层中的本地引用。 Unfortunately, that's not good enough for your purposes, you may need to make it a global ref. 不幸的是,这还不足以满足您的目的,您可能需要使其成为全局引用。 Just be wary of the fact that if you do make it a global ref, you have to delete it yourself in native code when you are done with it. 只是要警惕这样一个事实,如果您将其设置为全局引用,则必须在完成处理后以本机代码自己将其删除。

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

Finally I solved problem by myself. 最后我自己解决了问题。 The problem was, that when we make call from C++ to Java, SWIG proxy method passed pointer to it's argument to Java side. 问题是,当我们从C ++到Java进行调用时,SWIG代理方法将指向其参数的指针传递给了Java端。 Something like: 就像是:

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

On Java side another proxy method recieved pointer, wrapped it with Java representation of Message class and passed it to Java method OnMessage: 在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.
  }

After OnMessage finished, native Message object was destructed in SwigDirector_NativeLayerDelegate::OnMessage and Java Message object kept pointer to destructed native object. OnMessage完成后,本机Message对象在SwigDirector_NativeLayerDelegate::OnMessage被破坏,而Java Message对象保留了指向被破坏本机对象的指针。

Solution

I've wrote custom typemaps for my Message object: 我已经为Message对象编写了自定义类型映射:

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

Now SwigDirector_NativeLayerDelegate::OnMessage creates copy of msg and Java object owns it: 现在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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM