Skip to content
This repository has been archived by the owner on May 26, 2022. It is now read-only.

JNI crash #24

Closed
zhaohuaxishi opened this issue Aug 23, 2017 · 9 comments
Closed

JNI crash #24

zhaohuaxishi opened this issue Aug 23, 2017 · 9 comments

Comments

@zhaohuaxishi
Copy link

I got two kind of jni crash when use this lib, and here is the crash stack

1 #00 pc 000051de /data/app/com.cvte.androidrender-1/lib/arm/libjdns_sd.so (Java_com_apple_dnssd_AppleService_BlockForData+97) [armeabi-v7a]
--
2 #01 pc 0025ba37 /data/dalvik-cache/arm/data@[email protected]@[email protected] (oatdata+2468407) [armeabi]
3 java:
4 com.apple.dnssd.AppleService.void run()(DNSSD.java:688)
5 java.lang.Thread.run(Thread.java:818)
1 #00 pc 00021fc0 /system/lib/libc.so (tgkill+12) [armeabi-v7a]
--
2 #01 pc 0001307d /system/lib/libc.so (pthread_kill+48) [armeabi-v7a]
3 #02 pc 00013291 /system/lib/libc.so (raise+10) [armeabi-v7a]
4 #03 pc 00011fa9 /system/lib/libc.so [armeabi-v7a]
5 #04 pc 00021874 /system/lib/libc.so (abort+4) [armeabi-v7a]
6 #05 pc 00045bdb /system/lib/libdvm.so (dvmAbort+78) [armeabi-v7a]
7 #06 pc 00049381 /system/lib/libdvm.so [armeabi-v7a]
8 #07 pc 0004b24f /system/lib/libdvm.so [armeabi-v7a]
9 #08 pc 0000638d /data/app-lib/com.cvte.androidrender-2/libjdns_sd.so [armeabi-v7a]
10 #09 pc 000039c1 /data/app-lib/com.cvte.androidrender-2/libjdns_sd.so [armeabi-v7a]
11 #10 pc 00002b8b /data/app-lib/com.cvte.androidrender-2/libjdns_sd.so (DNSServiceProcessResult+602) [armeabi-v7a]
12 #11 pc 000052bd /data/app-lib/com.cvte.androidrender-2/libjdns_sd.so (Java_com_apple_dnssd_AppleService_ProcessResults+140) [armeabi-v7a]
13 #12 pc 0001db8c /system/lib/libdvm.so (dvmPlatformInvoke+112) [armeabi-v7a]
14 #13 pc 0004e033 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+398) [armeabi-v7a]
15 #14 pc 00026fa0 /system/lib/libdvm.so [armeabi-v7a]
16 #15 pc 0002df2c /system/lib/libdvm.so (dvmMterpStd(Thread*)+76) [armeabi-v7a]
17 #16 pc 0002b5d8 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184) [armeabi-v7a]
18 #17 pc 0006045f /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+338) [armeabi-v7a]
19 #18 pc 00060483 /system/lib/libdvm.so (dvmCallMethod(Thread*, Method const*, Object*, JValue*, ...)+20) [armeabi-v7a]
20 #19 pc 00055173 /system/lib/libdvm.so [armeabi-v7a]
21 #20 pc 0000d208 /system/lib/libc.so (__thread_entry+72) [armeabi-v7a]
22 #21 pc 0000d3a4 /system/lib/libc.so (pthread_create+240) [armeabi-v7a]
23 java:
24 com.apple.dnssd.AppleService.int ProcessResults()(Native Method)
25 com.apple.dnssd.AppleService.void run()(DNSSD.java:693)
26 java.lang.Thread.run(Thread.java:841)
@zhaohuaxishi
Copy link
Author

The version i use is 0.8.4

@andriydruk
Copy link
Owner

Could you share code snippet that starts browsing?

@zhaohuaxishi
Copy link
Author

public class RxDnssdServiceBrowser implements IServiceBrowser {
    private final static String LOCAL_DOMAIN = "local.";
    private String serviceType;
    private Subscription subscription;
    private List<BonjourService> mServices;

    public RxDnssdServiceBrowser(String serviceType) {
        this.serviceType = serviceType;
        this.mServices = new ArrayList<>();
    }

    @Override
    public void startDiscover() {
        RxDnssd rxDnssd = WirelessChannelApplication.getContext().getRxDnssd();
        subscription = rxDnssd.browse(serviceType, LOCAL_DOMAIN)
                .compose(rxDnssd.resolve())
                .compose(rxDnssd.queryRecords())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<BonjourService>() {
                    @Override
                    public void call(BonjourService bonjourService) {
                        if (bonjourService.isLost()) {
                            mServices.remove(bonjourService);
                        } else {
                            mServices.remove(bonjourService);
                            mServices.add(bonjourService);
                        }
                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        KLog.e(throwable);
                    }
                });
    }

    @Override
    public void stopDiscover() {
        if (subscription != null) {
            subscription.unsubscribe();
        }

        mServices.clear();
    }

    @Override
    public List<BonjourService> listServices() {
        return mServices;
    }
}
public class WirelessChannelApplication extends MultiDexApplication {
    private static WirelessChannelApplication sContext;

    private RxDnssd rxDnssd;

    public static WirelessChannelApplication getContext() {
        return sContext;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sContext = this;

        rxDnssd = new RxDnssdBindable(this);
    }

    public RxDnssd getRxDnssd() {
        return rxDnssd;
    }
}

@zhaohuaxishi
Copy link
Author

I also got java.lang.OutOfMemoryError with reason Could not allocate JNI Env

1 java.lang.Thread.nativeCreate(Native Method)
--
2 java.lang.Thread.start(Thread.java:1063)
3 com.apple.dnssd.AppleQuery.void <init>(int,int,java.lang.String,int,int,com.apple.dnssd.QueryListener)(DNSSD.java:844)
4 com.apple.dnssd.AppleDNSSD.com.apple.dnssd.DNSSDService _queryRecord(int,int,java.lang.String,int,int,com.apple.dnssd.QueryListener)(DNSSD.java:591)
5 com.apple.dnssd.DNSSD.com.apple.dnssd.DNSSDService queryRecord(int,int,java.lang.String,int,int,com.apple.dnssd.QueryListener)(DNSSD.java:321)
6 com.github.druk.rxdnssd.RxDnssdCommon$3$1$2.com.apple.dnssd.DNSSDService getService(rx.Subscriber)(RxDnssdCommon.java:108)
7 com.github.druk.rxdnssd.RxDnssdBindable$DNSSDServiceAction.void call(rx.Subscriber)(RxDnssdBindable.java:65)
8 com.github.druk.rxdnssd.RxDnssdBindable$DNSSDServiceAction.void call(java.lang.Object)(RxDnssdBindable.java:51)
9 rx.internal.operators.OnSubscribeLift.void call(rx.Subscriber)(OnSubscribeLift.java:1048)
10 ##_parent_##1##_parent_##
11 ##_child_## void call(java.lang.Object)##_child_##
12 rx.Observable.rx.Subscription unsafeSubscribe(rx.Subscriber)(Observable.java:10346)
13 rx.internal.operators.OperatorMerge$MergeSubscriber.void onNext(rx.Observable)(OperatorMerge.java:4248)
14 ##_parent_##1##_parent_##
15 ##_child_## void onNext(java.lang.Object)##_child_##
16 rx.internal.operators.OnSubscribeFromArray$FromArrayProducer.void fastPath()(OnSubscribeFromArray.java:76)
17 rx.internal.operators.OnSubscribeFromArray$FromArrayProducer.void request(long)(OnSubscribeFromArray.java:58)
18 rx.Subscriber.void setProducer(rx.Producer)(Subscriber.java:211)
19 rx.internal.operators.OnSubscribeFromArray.void call(rx.Subscriber)(OnSubscribeFromArray.java:1032)
20 ##_parent_##1##_parent_##
21 ##_child_## void call(java.lang.Object)##_child_##
22 rx.internal.operators.OnSubscribeLift.void call(rx.Subscriber)(OnSubscribeLift.java:1048)
23 ##_parent_##1##_parent_##
24 ##_child_## void call(java.lang.Object)##_child_##
25 rx.Observable.rx.Subscription unsafeSubscribe(rx.Subscriber)(Observable.java:10346)
26 rx.internal.operators.OperatorMerge$MergeSubscriber.void onNext(rx.Observable)(OperatorMerge.java:4248)
27 ##_parent_##1##_parent_##
28 ##_child_## void onNext(java.lang.Object)##_child_##
29 rx.internal.operators.OnSubscribeMap$MapSubscriber.void onNext(java.lang.Object)(OnSubscribeMap.java:77)
30 rx.internal.operators.OperatorMerge$MergeSubscriber.void emitLoop()(OperatorMerge.java:726)
31 rx.internal.operators.OperatorMerge$MergeSubscriber.void emitScalar(rx.internal.operators.OperatorMerge$InnerSubscriber,java.lang.Object,long)(OperatorMerge.java:2433)
32 ##_parent_##1##_parent_##
33 ##_child_## void tryEmit(rx.internal.operators.OperatorMerge$InnerSubscriber,java.lang.Object)##_child_##
34 rx.internal.operators.OperatorMerge$InnerSubscriber.void onNext(java.lang.Object)(OperatorMerge.java:846)
35 rx.observers.Subscribers$5.void onNext(java.lang.Object)(Subscribers.java:235)
36 com.github.druk.rxdnssd.RxResolveListener.void serviceResolved(com.apple.dnssd.DNSSDService,int,int,byte[],byte[],int,com.apple.dnssd.TXTRecord)(RxResolveListener.java:46)
37 com.apple.dnssd.AppleService.int ProcessResults()(Native Method)
38 com.apple.dnssd.AppleService.void run()(DNSSD.java:693)
39 java.lang.Thread.run(Thread.java:818)


@onnlucky
Copy link

We ran into the same issue, but it is an API misuse issue. (But also partly a problem in how the library works.)

Ultimately most InternalDNSSD.AppleService objects will start a thread (on most platforms, as hasAutoCallbacks is false). Failure to call #close() on such objects will keep that thread alive forever. Ultimately causing failures to start new ones (the Could not allocate JNI Env error) or the system runs out of memory elsewhere.

A possible solution in the library would be to not give out the AppleService objects to the user, but instead give out proxy objects that point to the AppleServices, while the AppleService object does not strongly point back to that proxy. That way a finalizer queue for these proxy objects can be used to call AppleQuery#stop().

Another solution is to document this frequent error front and center. Developers can also keep an eye on this issue by logging Thread.activeCount() regularly.

@andriydruk
Copy link
Owner

Hi @onnlucky
Thanks for you feedback. Now it's clear why OutOfMemoryError happened.
Look like it's due to #3 and endless resolve operation in Rx chain.

I definitely will separate this 2 APIs and make default operation completable.

@andriydruk
Copy link
Owner

When you make browsing you should have only 1 long-running service - actually browse
All resolve and query services should be stopped immediately after result or error

@andriydruk
Copy link
Owner

Fixed in 0.9.3

@onnlucky
Copy link

Good work! Thanks!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants