GoogleAnalyticsForXamarinForms icon indicating copy to clipboard operation
GoogleAnalyticsForXamarinForms copied to clipboard

Crashes when distributing for Xamarin.Mac

Open KeithBoynton opened this issue 6 years ago • 20 comments

Implemented very well into Windows, Xamarin.iOS and Xamarin.Mac and everything is working really well in Debug within Visual Studio.

However when I come to package up and distribute, it crashes on the distributed version with the following stack trace:

Crashed Thread:        0  tid_307  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Segmentation fault: 11
Termination Reason:    Namespace SIGNAL, Code 0xb
Terminating Process:   exc handler [497]

Thread 0 Crashed:: tid_307  Dispatch queue: com.apple.main-thread
0   com.xxxxx.xxxxxxxxxxx         	0x000000010d7b005d eglib_log_adapter + 13 (mono-logger.c:404)
1   com.xxxxx.xxxxxxxxxxx         	0x000000010d7ca26e monoeg_g_logv_nofree + 190 (goutput.c:150)
2   com.xxxxx.xxxxxxxxxxx         	0x000000010d7ca3ef monoeg_assertion_message + 143 (goutput.c:184)
3   com.xxxxx.xxxxxxxxxxx         	0x000000010d5a8a69 mono_jit_thread_attach + 169
4   com.xxxxx.xxxxxxxxxxx         	0x000000010d4bd5a0 xamarin_switch_gchandle + 144 (runtime.m:1853)
5   com.xxxxx.xxxxxxxxxxx         	0x000000010d4c0217 xamarin_release_trampoline + 103 (trampolines.m:474)
6   libobjc.A.dylib               	0x0000000119a3711a (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 710
7   com.xxxxx.xxxxxxxxxxx         	0x000000010d4c79c2 xamarin_main + 1234 (launcher.m:674)
8   com.xxxxx.xxxxxxxxxxx         	0x000000010d4c8834 main + 36 (launcher.m:679)
9   libdyld.dylib                 	0x000000011a4ec3d5 start + 1

I understand you have listed Xamarin.Mac as "partial" support but I assumed as I've gotten everything running nicely within Visual Studio in Xamarin.Mac I wasn't touching any of the unsupported elements.

I've wrapped it in a static class...

using Plugin.GoogleAnalytics;

namespace Core.Analytics
{
 public static class AppClient
    {
        public static void Initialise()
        {
            GoogleAnalytics.Current.Config.TrackingId = "XXX";
            GoogleAnalytics.Current.Config.AppId = "XXX";
            GoogleAnalytics.Current.Config.AppName = "XXX";
            GoogleAnalytics.Current.Config.AppVersion = "XXX";
            GoogleAnalytics.Current.Config.AppInstallerId = "XXX";
            GoogleAnalytics.Current.Config.StartMessage = "Startup";
            GoogleAnalytics.Current.Tracker.DataSource = "app";

#if __MACOS__
            GoogleAnalytics.Current.Tracker.UserAgentOverride = $"Mozilla/5.0 (Mac OS {Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor}; Trident/7.0; rv:11.0) like Geko";
#endif

            GoogleAnalytics.Current.InitTracker();
        }
    }
}

And I call it from my app logic....


// Set up analytics
LogWriter.Info ("Setting up analytics");
Analytics.AppClient.Initialise();
LogWriter.Info ("Done");

The Analytics.AppClient.Initialise(); line is where it crashes. The "Setting up analytics" logging gets written but not the "Done" line.

I'm guessing this isn't expected, is there anything special needed to distribute or does that crash indicate anything to you?

KeithBoynton avatar Jul 05 '19 14:07 KeithBoynton

Thanks for your feedback, I'm currently working on the .net standard version. I think I can fix it.

KSemenenko avatar Jul 05 '19 21:07 KSemenenko

Thanks for your response, it's strange because it's working just fine in the distributed iOS and Windows versions. Is there anything you can suggest as a workaround?

KeithBoynton avatar Jul 06 '19 13:07 KeithBoynton

If I can help progress it in any way then I'd like to help. This has the next release of my app blocked as both the Mac Distribution and Mac App Store versions crash. If you could point me in a direction to look I will be more than happy to try and help out.

KeithBoynton avatar Jul 07 '19 09:07 KeithBoynton

@KeithBoynton Hi, can you test it please? https://www.nuget.org/packages/ksemenenko.GoogleAnalytics/1.0.4-pre

KSemenenko avatar Jul 10 '19 08:07 KSemenenko

Hi, been away for a few days.. just back.. will test asap

KeithBoynton avatar Jul 16 '19 16:07 KeithBoynton

@KSemenenko Hi again, unfortunately 1.0.4-pre is still crashing for on the distributed xamarin.mac version.

It gives the following trace..

Crashed Thread:        0  tid_307  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Segmentation fault: 11
Termination Reason:    Namespace SIGNAL, Code 0xb
Terminating Process:   exc handler [499]

VM Regions Near 0:
--> 
    __TEXT                 0000000101bbb000-0000000101fc8000 [ 4148K] r-x/rwx SM=COW  /Applications/xxxxxxxxxxx.app/Contents/MacOS/xxxxxxxxxxx

Thread 0 Crashed:: tid_307  Dispatch queue: com.apple.main-thread
0   com.xxxxx.xxxxxxxxxxx         	0x0000000101edd05d eglib_log_adapter + 13 (mono-logger.c:404)
1   com.xxxxx.xxxxxxxxxxx         	0x0000000101ef726e monoeg_g_logv_nofree + 190 (goutput.c:150)
2   com.xxxxx.xxxxxxxxxxx         	0x0000000101ef73ef monoeg_assertion_message + 143 (goutput.c:184)
3   com.xxxxx.xxxxxxxxxxx         	0x0000000101cd5a69 mono_jit_thread_attach + 169
4   com.xxxxx.xxxxxxxxxxx         	0x0000000101bea5a0 xamarin_switch_gchandle + 144 (runtime.m:1853)
5   com.xxxxx.xxxxxxxxxxx         	0x0000000101bed217 xamarin_release_trampoline + 103 (trampolines.m:474)
6   libobjc.A.dylib               	0x000000010e1a111a (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 710
7   com.xxxxx.xxxxxxxxxxx         	0x0000000101bf49c2 xamarin_main + 1234 (launcher.m:674)
8   com.xxxxx.xxxxxxxxxxx         	0x0000000101bf5834 main + 36 (launcher.m:679)
9   libdyld.dylib                 	0x000000010ec363d5 start + 1

No code changes since last time and the app logs show me it crashing on the same line.

If there is anything I can do to help please do let me know... any ideas for something for me to investigate?

KeithBoynton avatar Jul 17 '19 05:07 KeithBoynton

Hi @KSemenenko would it be possible for you to give me a steer on what to look at to get this Xamarin.Mac crashing resolved. I'd like to contribute to try and progress this issue as my release path is blocked at the moment because of it.

KeithBoynton avatar Jul 21 '19 12:07 KeithBoynton

@KeithBoynton You can try to add the project source code to your project and see what went wrong in the debugger.

KSemenenko avatar Jul 21 '19 21:07 KSemenenko

Maybe there are some problems with disk access?

KSemenenko avatar Jul 21 '19 21:07 KSemenenko

Hi @KSemenenko. I'm working with Keith on this issue a bit. I ended up pulling down the repo and tracing through to see what was happening. In a nutshell the Mac implementation is trying to write directly into the app bundle contents. The read and write methods in the DeviceInfo implementation for Mac are here: https://github.com/KSemenenko/GoogleAnalyticsForXamarinForms/blob/master/Plugin.GoogleAnalytics/Plugin.GoogleAnalytics.Mac/DeviceInfo.cs#L117

For these methods, GoogleAnalyticsFolder = "ga-store" and path = "ga-anonymous-id.guid" therefore File.Exists(Path.Combine(GoogleAnalyticsFolder, path)) evaluates to "[AppBundleFolder]/AppPackage/Contents/Resources/ga-store/ga-anonymous-id.guid". While Debug builds can get away with this, Distributed builds cannot write back into the app package to create folders/files.

I modified the methods to do the following, adding a method that uses the SpecialFolders to construct a path to the user's Library folder where application data can be stored. This seemed to work, perhaps something like this could be done instead:

       static string GetFullGaFolder()
        {
            var docsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            var gaFolder = Path.Combine(docsPath, "Library", GoogleAnalyticsFolder);
            return gaFolder;
        }
        public string ReadFile(string path)
        {
            var gaFolder = GetFullGaFolder();

            if (!File.Exists(Path.Combine(gaFolder, path)))
            {
                return string.Empty;
            }

            return File.ReadAllText(Path.Combine(gaFolder, path));
        }

        public void WriteFile(string path, string content)
        {
            var gaFolder = GetFullGaFolder();

            if (!Directory.Exists(gaFolder))
            {
                Directory.CreateDirectory(gaFolder);
            }
            File.WriteAllText(Path.Combine(gaFolder, path), content);
        }

Hopefully that helps! I'm sure @KeithBoynton would be interested in a fix for this ASAP. :)

DennisWelu avatar Jul 25 '19 05:07 DennisWelu

Just thinking about this a little more...you might consider another segment in that Library path so that multiple applications using the library don't end up writing to the same ga-store folder. Perhaps something with the application name/id in there like Path.Combine(docsPath, "Library", ApplicationNameOrId, GoogleAnalyticsFolder)

DennisWelu avatar Jul 25 '19 05:07 DennisWelu

@DennisWelu I don't really understand macOS, but is this not an isolated storage?

KSemenenko avatar Jul 25 '19 08:07 KSemenenko

I'm no Mac expert, but I believe writing back to the app bundle, which is just a zip file essentially, messes up the digital signature (https://stackoverflow.com/a/23803875/1735721) that is applied for any kind of distribution build.

There are various options for storing data depending on what type of data you are storing...user data vs app data, backed up to iCloud vs not, whether the app is sandboxed or not (https://apple.stackexchange.com/a/28930).

Sandboxed apps on Mac have a lot of rules and things to do to get them set up (https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW6).

In fact I just thought to check and the app in question here is actually writing other similarly cached and internal use files to ".../Library/Containers/[InternalAppId]/Data/Caches/[Subfolder]". So it would be really nice to be able to configure it to use that Caches folder and maybe the "ga-store" folder is created under there... Not sure the best way to make that happen with the library you have. I see there are various pieces of config that you can configure like the app name and id, so maybe something from the config could be substituted into that path construction to get the appropriate container folder location?

DennisWelu avatar Jul 25 '19 12:07 DennisWelu

Thank you so much for your help @DennisWelu @KSemenenko I'm going to do some testing based on Dennis' findings then when I understand it a little more and am confident it's writing into a place that is going to be workable for the AppStore version I'll submit it to the Mac AppStore for review and let you know the outcome.

Did you have any thoughts on how you want to handle the location of where it writes it's internal files in the Mac version?

KeithBoynton avatar Jul 26 '19 13:07 KeithBoynton

@KSemenenko I can confirm this is now working in both the Xamarin.Mac Distribution and AppStore versions.

KeithBoynton avatar Jul 31 '19 06:07 KeithBoynton

@KSemenenko do you want the fix merging into your codebase or do you have things you'd like to change first?

KeithBoynton avatar Aug 07 '19 13:08 KeithBoynton

@KeithBoynton I will be very grateful if you create PR. then I will release a new version with .net standard

KSemenenko avatar Aug 07 '19 14:08 KSemenenko

Happy to do that, I had created a branch to make the change but can't push it remotely before making a PR, do I need some other permissions?

KeithBoynton avatar Aug 25 '19 15:08 KeithBoynton

@KeithBoynton There are two ways, the first via github:

  1. do you fork
  2. create a branch in your fork, commit changes there
  3. open the country of my repository
  4. you have the option to create a PR

or just archive the project and attach the archive here

KSemenenko avatar Aug 25 '19 18:08 KSemenenko

@KSemenenko It's a really simple change.. probably much easier to just attach the updated file here...

Plugin.GoogleAnalytics/Plugin.GoogleAnalytics.Mac/DeviceInfo.cs DeviceInfo.zip

KeithBoynton avatar Aug 26 '19 07:08 KeithBoynton