Hi,

> On 16/09/16 18:43, "Jonathan Pryor" <jonpr...@vt.edu> wrote:
> 
> Kumpera: Please see Option #5, at end.
> 
> On Sep 16, 2016, at 10:59 AM, Sebastien Pouliot via android-devel 
> <android-de...@lists.dot.net> wrote:
> > The current sequence of events is this:
> >  
> > a) The app launches, and Xamarin.iOS initializes the Mono runtime.
> 
> Which raises Plausible Solution #0: structure things such that the 3rd party 
> lib sets the default signal handler *before* mono is initialized.
> 
> This could be done by e.g. using a C++ global object in an archive linked 
> into the main binary: the constructor will be executed before `main()` 
> executes, so by the time mono has initialized it will see the 3rd party 
> SIGSEGV handler, not the system handler.
> 
> There are problems with this:
> 
> 1. Before `main()`, execution order of global constructors is undefined. This 
> solution is “scalable”, in that any number of libraries can participate, but 
> the order between those libraries can’t be controlled.

Most native crash reporting libraries I've seen on iOS asks the app developer 
to initialize the library in the [UIApplicationDelegate 
application:didFinishLaunchingWithOptions:] method, which is late in the app 
startup sequence. At this point Xamarin apps are running managed code (in fact 
the managed equivalent: UIApplicationDelegate.FinishedLaunching), so requiring 
3rd party libraries to initialize earlier when used with Xamarin.iOS is not a 
general/good solution.

> 
> 2. It requires that the 3rd party library be create-able in this fashion. For 
> example, if it uses a license key which is only available in managed code, 
> this can’t work.

Typically, on iOS there's a native library (where the actual crash detection / 
data collection code resides), and managed bindings for Xamarin.iOS. The app 
developer initializes the library using managed code, which is another reason 
this won't work.

> 
> 3. It only works for *app* projects. This can thus work for Xamarin.iOS, but 
> it *can’t* work for Xamarin.Android, which uses shared libraries.
> 
> However, we can apply similar Judo to make things work in Xamarin.Android. 
> Mono is initialized on Android through a ContentProvider with a high 
> //provider/@android:initOrder value; the `initOrder` value controls the order 
> of loading ContentProviders. You could thus set things up so that the 3rd 
> party lib uses a Java ContentProvider with a *higher* `initOrder` value, thus 
> ensuring that the 3rd party lib is initialized *before* Xamarin.Android. Mono 
> will thus see the 3rd party’s SIGSEGV handler, not the system one.
> 
> The immediate problem here is that Xamarin.Android sets the initOrder value 
> to int.MaxValue, but we can certainly lower the value we use to allow code to 
> execute before the Xamarin.Android bootstrap code…
> 
> Pro: works/can be made to work *now*, with minimal/no changes to mono and 
> Xamarin.
> 
> Con: Requires modifying process state before Mono starts executing, which 
> isn’t always easy or straightforward (requires native code).
> 
> > b) Managed code starts running, and the actual app initializes any 
> > third-party libraries. At this point third-party libraries typically do 
> > something like this:
> 
> This is assuming/requiring that the 3rd party code is managed code. When it 
> comes to signal handlers, I don’t think that’s valid; any reasonably sane 
> SIGSEGV-handling code *must* be native. Thus, we don’t necessarily need to 
> support initializing it *during* execution of managed code.

Yes, we do.

There is always a native 3rd party library  (usable for all types of iOS apps, 
not just Xamarin ones), and then Xamarin-specific managed bindings on top of 
the native library.

So the app developer writes something like this (in managed code):

    public override bool FinishedLaunching(UIApplication application, 
NSDictionary launchOptions)
    {
        var HockeyAppManager = BITHockeyManager.SharedHockeyManager;
        HockeyAppManager.Configure("app-specific-value");
        HockeyAppManager.StartManager();
        return true;
    }

HockeyAppManager.StartManager is a managed binding for a native method (with 
some magic to make it not override Mono's signals): 
https://github.com/bitstadium/HockeySDK-Xamarin/blob/master/source/HockeySDK.iOSBindings/Additions.cs#L24-L54

> 
> That might still be a good idea… I’m not sure, myself.
> 
> > A couple of ideas:
> >  
> > 1) Add an API to select/set the signal handler Mono chains to:
> >  
> > namespace ObjCRuntime {
> >       public class Runtime {
> >             public struct SigAction
> >             {
> >                   public IntPtr Handler; //
> >                   public uint Mask; // sa_mask => sigset_t => 
> > __darwin_sigset_t => uint32_t
> >                   public int Flags; // sa_flags => int
> >             }
> >  
> >             public static bool InstallSignalHandler (int signal, SigAction 
> > handler, out SigAction previous_handler);
> >       }
> > }
> 
> I would prefer to *not* expose a managed binding of `struct sigaction`, in 
> part to reduce portability issues. On Android, `sigset_t` is `unsigned long`, 
> so on 64-bit platforms this will be a 64-bit value, not a 32-bit value, so 
> this wouldn’t be compatible.
> 
> Granted, we could have “parallel” definitions for Android vs. iOS, but if 
> we’re doing to define a new API, we should try to minimize such things. :-)

We could just expose an IntPtr:

> public static bool InstallSignalHandler (int signal, byte[] /* or IntPtr */ 
> handler);

But not sure that makes it nicer.

> 
> > 2) Add an attribute that gives the name of the signal handler, and then 
> > Xamarin.iOS generates the required code to make sure these signal handlers 
> > are called for signals Mono doesn't handle:
> 
> Such an attribute would need to be iOS/Mac-specific; there’s no Android 
> equivalent. It would also require that `third_party_signal_handler` be a 
> public symbol that the linker can find, in addition to the “use before 
> initialized” issue that Rolf notes.
> 
> I think Solution #0 (global C++ objects) overlaps with this general idea, and 
> is cleaner to boot.
> 
> > 3) A mix of both of the above:
> >  
> >       ObjCRuntime.Runtime.EnableCustomSignalHandler (Signals.SIGSEGV, 
> > "third_party_signal_handler");
> >  
> >    The problem here is that we'd have to use dlsym to lookup the function 
> > pointer for third_party_signal_handler, which can be problematic sometimes 
> > (#1 just gets the function pointer from the signal handler the native 
> > third-party library installed, and for #2 generate native code that 
> > references the function instead).
> 
> Another issue: the signals that are specified are signals that Mono needs to 
> handle *first*. I’m not sure that this list of signals is/should be set in 
> stone; what if Mono needs to be first for processing SIGILL in the future? 
> Then this code will be out-of-date, possibly resulting on obscure errors.

If Mono needs to process new signals, then every single crash reporting library 
for Xamarin.iOS has a problem.

Also I don't see any solution that won't require updates to the crash reporting 
library anyway.
 
> 
> This doesn’t feel “safe” to me
> 
> >  4) A mix of all of the above:
> ..
> > Any other ideas? Suggestions for better naming for the API?
> 
> Option 5: a “new" Mono function.
> 
> The fundamental problem is that Mono *must* be the first signal handler for 
> e.g. SIGSEGV, but ~anybody else can replace the SIGSEGV handler at any time.
> 
> What if the Mono team made one of the following function public:
> 
>       // in: https://github.com/mono/mono/blob/master/mono/mini/mini-posix.c
>       void mono_runtime_install_handlers (void);
>       void mono_runtime_posix_install_handlers (void);
> 
> My quick reading of `mono_runtime_posix_install_handlers()` (line ~470) 
> suggests that it registers those signals. It’s currently “internal”, i.e. you 
> can’t `dlsym()` that function from `libmonosgen-2.0.dylib`, but if it were 
> public, you could then register all your third party library code, then call 
> `mono_runtime_install_handlers()`, and the app would be fine.

So mono would install its signal handlers twice?

i.e. something like this:

a) Mono initializes, calls mono_runtime_install_handlers.
b) App starts up, installs the crash reporting signal handlers.
c) App calls mono_runtime_install_handlers, which will make mono chain to the 
crash reporting signal handlers.

Which will probably confuse mono if the crash reporting signal handlers chain 
to the first mono signal handlers (which I believe PLCrashReporting does). It 
will probably chain again to the crash reporting signal handler, ending up with 
either an infinite loop or stack overflow.

I think one major point is that I don't think we can/should impose restrictions 
on when the crash reporting signal handlers are installed. There are a number 
of 3rd party libraries that provide crash reporting services, and they already 
work well with Xcode projects, and we need to figure out how we can make those 
libraries work well with us, without any changes.

Rolf


_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.dot.net
http://lists.dot.net/mailman/listinfo/mono-devel-list

Reply via email to