Bug 15528 - Crash using Multipeer Connectivity MCSession.SendResource
Summary: Crash using Multipeer Connectivity MCSession.SendResource
Status: VERIFIED FIXED
Alias: None
Product: iOS
Classification: Xamarin
Component: Xamarin.iOS.dll ()
Version: 7.0.2.x
Hardware: PC Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Sebastien Pouliot
URL:
Depends on:
Blocks:
 
Reported: 2013-10-20 19:32 UTC by Bob Reck
Modified: 2014-11-28 10:49 UTC (History)
3 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Crash info from console of resource receiving device. (6.53 KB, text/plain)
2013-10-20 19:34 UTC, Bob Reck
Details
App Crash File (29.79 KB, application/octet-stream)
2013-10-21 09:04 UTC, Bob Reck
Details
App Crash File (New) (32.72 KB, application/octet-stream)
2013-10-21 09:30 UTC, Bob Reck
Details
Sample project that crashes like my app. (83 bytes, text/plain)
2013-10-21 10:54 UTC, Bob Reck
Details
Screen shot showing resource successfully transferred. (196.10 KB, image/png)
2013-10-21 10:57 UTC, Bob Reck
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
VERIFIED FIXED

Description Bob Reck 2013-10-20 19:32:40 UTC
Dear Xamarin,

I have posted about this on the Xamarin.IOS forums but have not received any responses. I am started to believe this is a bug and figured I'd post it here for you to check.

I have an app using the new iOS 7 Multipeer Connectivity API's. I am sending pictures from one device to another connected peer device. My process first uses many MCSession.SendData calls with no issue. Then, I try to send my images using MCSession.SendResource. The receiving device receives the incoming resource (a .PNG file) without issue and I can see them, via xcode organizer, stored in the temp folder inside the app. Once the resource completes, the code should then call DidFinishReceivingResource. But before anything executes inside that method, the app crashes.

I have put try/catch blocks around all my code to catch any errors, but none are displayed. I have also removed ALL of the code from the method (except the required output error assignment) and tried to run the app with the same result. So, my code does not appear to be the problem.

I'd really appreciate it if you could create your own app using the MCSession.SendResource method and let me know if you get a crash. This problem has been plaguing me for over a week. I've tried completely rewriting this more than once. I've used custom Browsers and Advertisers, same problem. I'm currently using the built in MCBrowserView and MCAdvertiserAssistant and I'm at my wits end.

Below is a sample of my code. Thanks.
Bob


Sending the resource: 

mySession.SendResource (NSUrl.FromFilename (fileurl), fileName, peers [0], (myError) => { 
    if (myError != null) { 
        InvokeOnMainThread (() => _utils.ShowError (myError.ToString ())); 
    } else { 
        InvokeOnMainThread (() => Console.WriteLine ("Sent file: " + fileName)); 
    } 
});

MCSessionDelegate used by the advertiser and receiver of the resource: 

class ImportSessionDelegate : MCSessionDelegate 
{ 
    ImportData parent;
    public ImportSessionDelegate(ImportData parent)
    {
        this.parent = parent;
    }

    public override void DidChangeState (MCSession session, MCPeerID peerID, MCSessionState state)
    {
        if (state == MCSessionState.Connected) {
            InvokeOnMainThread (() => {
                Console.WriteLine ("Connected to " + peerID.DisplayName + ".");
            });
        } else if (state == MCSessionState.NotConnected) {
            InvokeOnMainThread (() => {
                Console.WriteLine.SetStatusLabel("Disconnected from " + peerID.DisplayName + ".");
            });
        }
    }

    public override void DidReceiveData (MCSession session, NSData data, MCPeerID peerID)
    {
        InvokeOnMainThread(() => {
            parent.HideStartExportLabel (true);
            parent.LoadIncomingData (data, peerID);
        });
    }

    public override void DidStartReceivingResource (MCSession session, string resourceName, MCPeerID fromPeer, NSProgress progress)
    {
        Console.WriteLine ("Start of Did Start Receiving Resource");
        while (progress.FractionCompleted < 1) {
            InvokeOnMainThread(() => parent.UpdateProgressBar (progress));
        }
        Console.WriteLine ("End of Did Start Receiving Resource");
    }

    public override void DidFinishReceivingResource (MCSession session, string resourceName, MCPeerID formPeer, NSUrl localUrl, out NSError error)
    {
        Console.WriteLine ("Start of Did Finish Receiving Resource");
        //The following line is where I handle the received image and save it. But I never get past the previous line.
        //InvokeOnMainThread (() => parent.LoadIncomingResource (resourceName, localUrl, formPeer));
        Console.WriteLine ("Start of Did Finish Receiving Resource");
        error = null;
    }

    public override void DidReceiveStream (MCSession session, NSInputStream stream, string streamName, MCPeerID peerID)
    {
    }
}
Comment 1 Bob Reck 2013-10-20 19:34:43 UTC
Created attachment 5187 [details]
Crash info from console of resource receiving device.

This is my console output on my target iPad. I cleared the console, ran my app using the Multipeer Connectivity and saved the log right after the crash occurred.
Comment 2 Sebastien Pouliot 2013-10-21 08:36:41 UTC
> Oct 20 15:47:42 Bobs-iPad ReportCrash[8064] <Notice>: ReportCrash acting against PID 8058
> Oct 20 15:47:42 Bobs-iPad ReportCrash[8064] <Notice>: Formulating crash report for process FirearmSafe[8058]

Can you attach the symbolicated crash report ? that will tell us a bit more about what could be the issue.

Also please attach a self-contained test case so we're able to reproduce the crash easily (same code and same build options).

note: have you looked at / compared with:
http://blog.xamarin.com/send-the-monkey-a-message-with-multipeer-connectivity/ ?
Comment 3 Bob Reck 2013-10-21 08:56:36 UTC
Sebastien, 
I have looked at the Send The Monkey A Message example. The problem is, that example is only doing an MCSession.SendData. As stated above, SendData is working perfectly for me. I am calling SendData numerous times and then I am calling SendResource. I moved the call for SendResource to the beginning of the process as well and it did the same thing.

I will attach a crash report from the device. I do not know how to make it Symbolicated. If you can give me some direction on how to do that, I'll give it a shot.

I will try to throw together another example because my code has a lot of references to other classes in the project. Stay tuned...

Bob
Comment 4 Sebastien Pouliot 2013-10-21 09:01:03 UTC
Open Xcode organizer, select your device, then device logs, then the crash report (look at app name and time). In general you'll get the symbols automagically* (you'll see some app specific names in the stack) and you can export and attach the crash report to this bug report.

* It might already be symbolicated (it really depend on Spotlight which will, at some point, index the symbols of your application).
Comment 5 Bob Reck 2013-10-21 09:02:11 UTC
Gotcha. I see that now. Thanks. Exporting one now.
Comment 6 Bob Reck 2013-10-21 09:04:01 UTC
Created attachment 5188 [details]
App Crash File

Here is the requested crash file.
Comment 7 Sebastien Pouliot 2013-10-21 09:10:10 UTC
That's not symbolicated.

Thread 6 Crashed:
0   libsystem_kernel.dylib        	0x3913d1fc __pthread_kill + 8
1   libsystem_pthread.dylib       	0x391a6a2e pthread_kill + 54
2   libsystem_c.dylib             	0x390edff8 abort + 72
3   FirearmSafe                   	0x005df3f8 0xdd000 + 5252088
4   FirearmSafe                   	0x005e8198 0xdd000 + 5288344
5   libsystem_platform.dylib      	0x391a1060 _sigtramp + 40
6   FirearmSafe                   	0x003d5994 0xdd000 + 3115412
7   MultipeerConnectivity         	0x2fbe8f3c __58-[MCSession syncHandleNetworkEvent:pid:freeEventWhenDone:]_block_invoke733 + 168
8   libdispatch.dylib             	0x39061d78 _dispatch_call_block_and_release + 8
9   libdispatch.dylib             	0x39068292 _dispatch_queue_drain$VARIANT$mp + 370
10  libdispatch.dylib             	0x39068096 _dispatch_queue_invoke$VARIANT$mp + 38
11  libdispatch.dylib             	0x39068d12 _dispatch_root_queue_drain + 74
12  libdispatch.dylib             	0x39068f88 _dispatch_worker_thread2 + 52
13  libsystem_pthread.dylib       	0x391a3dbc _pthread_wqthread + 296
14  libsystem_pthread.dylib       	0x391a3c80 start_wqthread + 4

Lines #3, 4 and 6 those should have names, not just addresses, that would tell us what was being executed. Still it gives some clues (better than nothing).
Comment 8 Sebastien Pouliot 2013-10-21 09:11:44 UTC
Since the crash report looks to be from yesterday it could be the symbols where removed (a new build created) so it's now impossible to symbolicate it (unless you archived a copy of them).

In this case just rebuild your app (new symbols), run and crash. Then try again Xcode (you'll have the symbols and the crash that match them),
Comment 9 Bob Reck 2013-10-21 09:29:40 UTC
Ok, sorry. I am attaching a new one now.
Comment 10 Bob Reck 2013-10-21 09:30:37 UTC
Created attachment 5189 [details]
App Crash File (New)

Here's the new version that appears to be symbolicated this time.
Comment 11 Sebastien Pouliot 2013-10-21 10:51:44 UTC
Yes, its symbolicated :-)

Thread 8 Crashed:
0   libsystem_kernel.dylib        	0x3913d1fc __pthread_kill + 8
1   libsystem_pthread.dylib       	0x391a6a2e pthread_kill + 54
2   libsystem_c.dylib             	0x390edff8 abort + 72
3   FirearmSafe                   	0x00635124 mono_handle_native_sigsegv (mini-exceptions.c:2413)
4   FirearmSafe                   	0x0063df74 mono_sigsegv_signal_handler (mini.c:6640)
5   libsystem_platform.dylib      	0x391a1060 _sigtramp + 40
6   FirearmSafe                   	0x00429fbc wrapper_native_to_managed_MonoTouch_ObjCRuntime_Runtime_GetNSObjectWrapped_intptr_intptr + 84
7   MultipeerConnectivity         	0x2fbe8f3c __58-[MCSession syncHandleNetworkEvent:pid:freeEventWhenDone:]_block_invoke733 + 168

Looks like something goes wrong the the completion handler. It could be an object without a reference or a bug in our side. A test case would help.
Comment 12 Bob Reck 2013-10-21 10:54:43 UTC
Created attachment 5190 [details]
Sample project that crashes like my app.

I put together this example which sends 2 messages via MCSession.SendData. It also attempts to send one image via MCSession.SendResource. The code crashes the same way my real app does. The SendResource appears to be successful (see screen shot attachment to follow) as can be seen in Xcode organizer. The resource file is there. If I export the download the app contents, then show the package contents and click on the resource file, the correct image is shown.

So, again, the file is being transferred. But the crash occurs as the DidFinishReceivingResource is called.

Bob
Comment 13 Bob Reck 2013-10-21 10:57:21 UTC
Created attachment 5192 [details]
Screen shot showing resource successfully transferred.

This shows that the file has been transferred from the source device to the target device and placed into the TMP folder by the SendResource process. However, I am never able to manipulate the image (display it, move it to permanent folder, etc) because the app crashes as soon as the resource transfer completes.

Bob
Comment 14 Sebastien Pouliot 2013-10-21 11:27:26 UTC
I can duplicate and we'll start looking into it. Thanks for your sample!
Comment 15 Sebastien Pouliot 2013-10-21 11:41:32 UTC
It's a bug in our code. The method signature is wrong, i.e. there should NOT be a `out` for the NSError parameter in: 

	public override void DidFinishReceivingResource (MCSession session, string resourceName, MCPeerID formPeer, NSUrl localUrl, NSError error)

You can workaround this by using a WeakDelegate and exporting the selectors. Let me know if you need help doing so.
Comment 16 Bob Reck 2013-10-21 11:45:22 UTC
Sebastien, 
So glad to hear this. I have been struggling with it for a while now and it's good to know it's not just me. Thank you very much for the quick response.

When do you expect the change to be in an alpha? If it's going to be sometime in the next day or so, then I can wait. Otherwise, I'm still learning, so if you could give me a quick overview of how to create the weak delegate, I'd appreciate it.

Thank you so much!
Bob
Comment 17 Bob Reck 2013-10-21 11:55:00 UTC
I think I figured out the weakdelegate.
Bob
Comment 18 Sebastien Pouliot 2013-10-21 11:57:55 UTC
Fixed in master 83c01b548ff3e1e038ea4768c1d7175a3bab5452

We just release an alpha - so the next one (with the fix) might take some time to be available.

The key of using weak delegates is:

1. Use the WeakDelegate property, e.g.

				mySession.WeakDelegate = new ExportSessionDelegate (this);

2. Use the assembly browser (from XS) to see the base type, e.g. MCSessionDelegate

3. Copy/paste the [Export] attributes to your methods, e.g.

		[Export ("session:didFinishReceivingResourceWithName:fromPeer:atURL:withError:")]
		public void DidFinishReceivingResource (MCSession session, string resourceName, MCPeerID fromPeer, NSUrl localUrl, NSError error);

4. Stop subclassing the delegate type (e.g. MCSessionDelegate)

	class ExportSessionDelegate { 


Alternatively you can also move the methods inside your `Export` type and set `WeakDeleagte = this;`. That's pretty much like what ObjC apps do most of the time.

Again thanks for your help identifying the issue!
Comment 19 Bob Reck 2013-10-21 12:42:04 UTC
Sebastien, 
Thanks... the weakdelegate works. I successfully transferred and processed my images!!!!

Look forward to the fix being pushed out.
Bob
Comment 20 Mohit Kheterpal 2014-11-28 10:49:38 UTC
As per comment 19, this issue is working fine.

Hence closing this issue by marking it as Verified.