public static void Set(SensusServiceHelper sensusServiceHelper)
        {
            SENSUS_SERVICE_HELPER = sensusServiceHelper;

            // the helper is set to null, e.g., when the app is stopped.
            if (SENSUS_SERVICE_HELPER == null)
                SENSUS_SERVICE_HELPER_WAIT.Reset();
            else
                SENSUS_SERVICE_HELPER_WAIT.Set();
        }
Beispiel #2
0
        /// <summary>
        /// Initializes the sensus service helper. Must be called when app first starts, from the main / UI thread.
        /// </summary>
        /// <param name="createNew">Function for creating a new service helper, if one is needed.</param>
        public static void Initialize(Func<SensusServiceHelper> createNew)
        {
            if (SINGLETON != null)
            {
                SINGLETON.Logger.Log("Serivce helper already initialized. Nothing to do.", LoggingLevel.Normal, SINGLETON.GetType());
                return;
            }
            
            try
            {
                SINGLETON = JsonConvert.DeserializeObject<SensusServiceHelper>(Decrypt(ReadAllBytes(SERIALIZATION_PATH)), JSON_SERIALIZER_SETTINGS);
                SINGLETON.Logger.Log("Deserialized service helper with " + SINGLETON.RegisteredProtocols.Count + " protocols.", LoggingLevel.Normal, SINGLETON.GetType());
            }
            catch (Exception deserializeException)
            {
                Console.Error.WriteLine("Failed to deserialize Sensus service helper:  " + deserializeException.Message);

                try
                {
                    Console.Error.WriteLine("Creating new Sensus service helper.");
                    SINGLETON = createNew();
                }
                catch (Exception singletonCreationException)
                {
                    #region crash app and report to insights
                    string error = "Failed to construct service helper:  " + singletonCreationException.Message + System.Environment.NewLine + singletonCreationException.StackTrace;
                    Console.Error.WriteLine(error);
                    Exception exceptionToReport = new Exception(error);

                    try
                    {
                        Insights.Report(exceptionToReport, Xamarin.Insights.Severity.Error);
                    }
                    catch (Exception insightsReportException)
                    {
                        Console.Error.WriteLine("Failed to report exception to Xamarin Insights:  " + insightsReportException.Message);
                    }

                    throw exceptionToReport;
                    #endregion
                }

                #region save newly created helper
                try
                {
                    SINGLETON.SaveAsync();
                }
                catch (Exception singletonSaveException)
                {
                    Console.Error.WriteLine("Failed to save new Sensus service helper:  " + singletonSaveException.Message);
                }
                #endregion
            }  
        }
Beispiel #3
0
        public virtual void Dispose()
        {
            try
            {
                Stop();
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine("Failed to stop service helper:  " + ex.Message);
            }

            SINGLETON = null;
        }
        /// <summary>
        /// Initializes the sensus service helper. Must be called when app first starts, from the main / UI thread.
        /// </summary>
        /// <param name="createNew">Function for creating a new service helper, if one is needed.</param>
        public static void Initialize(Func<SensusServiceHelper> createNew)
        {
            if (SINGLETON == null)
            {                
                Exception deserializeException;
                if (!TryDeserializeSingleton(out deserializeException))
                {
                    // we failed to deserialize. wait a bit and try again. but don't wait too long since we're holding up the 
                    // app-load sequence, which is not allowed to take too much time.
                    Thread.Sleep(5000);

                    if (!TryDeserializeSingleton(out deserializeException))
                    {
                        // we really couldn't deserialize the service helper! try to create a new service helper...
                        try
                        {
                            SINGLETON = createNew();
                        }
                        catch (Exception singletonCreationException)
                        {
                            #region crash app and report to insights
                            string error = "Failed to construct service helper:  " + singletonCreationException.Message + System.Environment.NewLine + singletonCreationException.StackTrace;
                            Console.Error.WriteLine(error);
                            Exception exceptionToReport = new Exception(error);

                            try
                            {
                                Insights.Report(exceptionToReport, Xamarin.Insights.Severity.Error);
                            }
                            catch (Exception insightsReportException)
                            {
                                Console.Error.WriteLine("Failed to report exception to Xamarin Insights:  " + insightsReportException.Message);
                            }

                            throw exceptionToReport;
                            #endregion
                        }

                        SINGLETON.Logger.Log("Repeatedly failed to deserialize service helper. Most recent exception:  " + deserializeException.Message, LoggingLevel.Normal, SINGLETON.GetType());
                        SINGLETON.Logger.Log("Created new service helper after failing to deserialize the old one.", LoggingLevel.Normal, SINGLETON.GetType());
                    }
                }
            }
            else
                SINGLETON.Logger.Log("Serivce helper already initialized. Nothing to do.", LoggingLevel.Normal, SINGLETON.GetType());
        }
        private static bool TryDeserializeSingleton(out Exception ex)
        {
            ex = null;
            string errorMessage = null;

            // read bytes
            byte[] encryptedJsonBytes = null;
            try
            {
                encryptedJsonBytes = ReadAllBytes(SERIALIZATION_PATH);
            }
            catch (Exception exception)
            {
                errorMessage = "Failed to read service helper file into byte array:  " + exception.Message;
                Console.Error.WriteLine(errorMessage);
            }

            if (encryptedJsonBytes != null)
            {
                // decrypt JSON
                string decryptedJSON = null;
                try
                {
                    decryptedJSON = Decrypt(encryptedJsonBytes);
                }
                catch (Exception exception)
                {
                    errorMessage = "Failed to decrypt service helper byte array (length=" + encryptedJsonBytes.Length + ") into JSON:  " + exception.Message;
                    Console.Error.WriteLine(errorMessage);
                }
                 
                if (decryptedJSON != null)
                {
                    // deserialize service helper
                    try
                    {
                        SINGLETON = JsonConvert.DeserializeObject<SensusServiceHelper>(decryptedJSON, JSON_SERIALIZER_SETTINGS);
                    }
                    catch (Exception exception)
                    {
                        errorMessage = "Failed to deserialize service helper JSON (length=" + decryptedJSON + ") into service helper:  " + exception.Message;
                        Console.Error.WriteLine(errorMessage);
                    }
                }
            }

            if (errorMessage != null)
                ex = new Exception(errorMessage);

            if (SINGLETON != null)
                SINGLETON.Logger.Log("Deserialized service helper with " + SINGLETON.RegisteredProtocols.Count + " protocols.", LoggingLevel.Normal, SINGLETON.GetType());

            return SINGLETON != null;
        }
        public virtual void Stop()
        {
            // stop all protocols
            lock (_registeredProtocols)
            {
                _logger.Log("Stopping protocols.", LoggingLevel.Normal, GetType());

                foreach (Protocol protocol in _registeredProtocols)
                {
                    try
                    {
                        protocol.Stop();
                    }
                    catch (Exception ex)
                    {
                        _logger.Log("Failed to stop protocol \"" + protocol.Name + "\":  " + ex.Message, LoggingLevel.Normal, GetType());
                    }
                }
            }

            // make sure all logged messages get into the file.
            _logger.CommitMessageBuffer();

            SINGLETON = null;
        }
Beispiel #7
0
        public void Stop()
        {
            lock (_locker)
            {
                if (_running)
                {
                    _running = false;
                }
                else
                {
                    return;
                }

                if (ProtocolRunningChanged != null)
                {
                    ProtocolRunningChanged(this, _running);
                }

                SensusServiceHelper.Get().RemoveRunningProtocolId(_id);

                SensusServiceHelper.Get().Logger.Log("Stopping protocol \"" + _name + "\".", LoggingLevel.Normal, GetType());

                foreach (Probe probe in _probes)
                {
                    if (probe.Running)
                    {
                        try
                        {
                            probe.Stop();
                        }
                        catch (Exception ex)
                        {
                            SensusServiceHelper.Get().Logger.Log("Failed to stop " + probe.GetType().FullName + ":  " + ex.Message, LoggingLevel.Normal, GetType());
                        }
                    }
                }

                if (_localDataStore != null && _localDataStore.Running)
                {
                    try
                    {
                        _localDataStore.Stop();
                    }
                    catch (Exception ex)
                    {
                        SensusServiceHelper.Get().Logger.Log("Failed to stop local data store:  " + ex.Message, LoggingLevel.Normal, GetType());
                    }
                }

                if (_remoteDataStore != null && _remoteDataStore.Running)
                {
                    try
                    {
                        _remoteDataStore.Stop();
                    }
                    catch (Exception ex)
                    {
                        SensusServiceHelper.Get().Logger.Log("Failed to stop remote data store:  " + ex.Message, LoggingLevel.Normal, GetType());
                    }
                }

                SensusServiceHelper.Get().Logger.Log("Stopped protocol \"" + _name + "\".", LoggingLevel.Normal, GetType());
            }
        }
Beispiel #8
0
        public void TestHealth(bool userInitiated)
        {
            lock (_locker)
            {
                if (!userInitiated)
                {
                    lock (_healthTestTimes)
                    {
                        _healthTestTimes.Add(DateTime.Now);

                        // remove health test times prior to the participation horizon
                        int cutoff = _healthTestTimes.FindIndex(healthTestTime => healthTestTime >= DateTime.Now.AddDays(-_participationHorizonDays));
                        if (cutoff > 0)
                        {
                            _healthTestTimes.RemoveRange(0, cutoff);
                        }
                    }
                }

                string error   = null;
                string warning = null;
                string misc    = null;

                if (!_running)
                {
                    error += "Restarting protocol \"" + _name + "\"...";
                    try
                    {
                        Stop();
                        Start();
                    }
                    catch (Exception ex)
                    {
                        error += ex.Message + "...";
                    }

                    if (_running)
                    {
                        error += "restarted protocol." + Environment.NewLine;
                    }
                    else
                    {
                        error += "failed to restart protocol." + Environment.NewLine;
                    }
                }

                if (_running)
                {
                    if (_localDataStore == null)
                    {
                        error += "No local data store present on protocol." + Environment.NewLine;
                    }
                    else if (_localDataStore.TestHealth(ref error, ref warning, ref misc))
                    {
                        error += "Restarting local data store...";

                        try
                        {
                            _localDataStore.Restart();
                        }
                        catch (Exception ex)
                        {
                            error += ex.Message + "...";
                        }

                        if (!_localDataStore.Running)
                        {
                            error += "failed to restart local data store." + Environment.NewLine;
                        }
                    }

                    if (_remoteDataStore == null)
                    {
                        error += "No remote data store present on protocol." + Environment.NewLine;
                    }
                    else if (_remoteDataStore.TestHealth(ref error, ref warning, ref misc))
                    {
                        error += "Restarting remote data store...";

                        try
                        {
                            _remoteDataStore.Restart();
                        }
                        catch (Exception ex)
                        {
                            error += ex.Message + "...";
                        }

                        if (!_remoteDataStore.Running)
                        {
                            error += "failed to restart remote data store." + Environment.NewLine;
                        }
                    }

                    foreach (Probe probe in _probes)
                    {
                        if (probe.Enabled && probe.TestHealth(ref error, ref warning, ref misc))
                        {
                            error += "Restarting probe \"" + probe.GetType().FullName + "\"...";

                            try
                            {
                                probe.Restart();
                            }
                            catch (Exception ex)
                            {
                                error += ex.Message + "...";
                            }

                            if (!probe.Running)
                            {
                                error += "failed to restart probe \"" + probe.GetType().FullName + "\"." + Environment.NewLine;
                            }
                        }
                    }
                }

                _mostRecentReport = new ProtocolReport(DateTimeOffset.UtcNow, error, warning, misc);
                SensusServiceHelper.Get().Logger.Log("Protocol report:" + Environment.NewLine + _mostRecentReport, LoggingLevel.Normal, GetType());

                SensusServiceHelper.Get().Logger.Log("Storing protocol report locally.", LoggingLevel.Normal, GetType());
                _localDataStore.AddNonProbeDatum(_mostRecentReport);

                if (!_localDataStore.UploadToRemoteDataStore && _forceProtocolReportsToRemoteDataStore)
                {
                    SensusServiceHelper.Get().Logger.Log("Local data aren't pushed to remote, so we're copying the report datum directly to the remote cache.", LoggingLevel.Normal, GetType());
                    _remoteDataStore.AddNonProbeDatum(_mostRecentReport);
                }

                int runningProtocols = SensusServiceHelper.Get().RunningProtocolIds.Count;
                SensusServiceHelper.Get().UpdateApplicationStatus(runningProtocols + " protocol" + (runningProtocols == 1 ? " is " : "s are") + " running");
            }
        }
Beispiel #9
0
        public void Start()
        {
            lock (_locker)
            {
                if (_running)
                {
                    return;
                }
                else
                {
                    _running = true;
                }

                if (ProtocolRunningChanged != null)
                {
                    ProtocolRunningChanged(this, _running);
                }

                // let the service helper know that the current protocol is running (saves helper)
                SensusServiceHelper.Get().RegisterProtocol(this);
                SensusServiceHelper.Get().AddRunningProtocolId(_id);

                bool stopProtocol = false;

                // start local data store
                try
                {
                    if (_localDataStore == null)
                    {
                        throw new Exception("Local data store not defined.");
                    }

                    _localDataStore.Start();

                    // start remote data store
                    try
                    {
                        if (_remoteDataStore == null)
                        {
                            throw new Exception("Remote data store not defined.");
                        }

                        _remoteDataStore.Start();

                        // start probes
                        try
                        {
                            SensusServiceHelper.Get().Logger.Log("Starting probes for protocol " + _name + ".", LoggingLevel.Normal, GetType());
                            int probesEnabled = 0;
                            int probesStarted = 0;
                            foreach (Probe probe in _probes)
                            {
                                if (probe.Enabled)
                                {
                                    ++probesEnabled;

                                    try
                                    {
                                        probe.Start();
                                        probesStarted++;
                                    }
                                    catch (Exception ex)
                                    {
                                        // stop probe to clean up any inconsistent state information
                                        try
                                        {
                                            probe.Stop();
                                        }
                                        catch (Exception ex2)
                                        {
                                            SensusServiceHelper.Get().Logger.Log("Failed to stop probe after failing to start it:  " + ex2.Message, LoggingLevel.Normal, GetType());
                                        }

                                        string message = "Failed to start probe \"" + probe.GetType().FullName + "\":  " + ex.Message;
                                        SensusServiceHelper.Get().Logger.Log(message, LoggingLevel.Normal, GetType());
                                        SensusServiceHelper.Get().FlashNotificationAsync(message);

                                        // disable probe if it is not supported on the device
                                        if (ex is NotSupportedException)
                                        {
                                            probe.Enabled = false;
                                        }
                                    }
                                }
                            }

                            if (probesEnabled == 0)
                            {
                                throw new Exception("No probes were enabled.");
                            }
                            else if (probesStarted == 0)
                            {
                                throw new Exception("No probes started.");
                            }
                        }
                        catch (Exception ex)
                        {
                            string message = "Failure while starting probes:  " + ex.Message;
                            SensusServiceHelper.Get().Logger.Log(message, LoggingLevel.Normal, GetType());
                            SensusServiceHelper.Get().FlashNotificationAsync(message);
                            stopProtocol = true;
                        }
                    }
                    catch (Exception ex)
                    {
                        string message = "Remote data store failed to start:  " + ex.Message;
                        SensusServiceHelper.Get().Logger.Log(message, LoggingLevel.Normal, GetType());
                        SensusServiceHelper.Get().FlashNotificationAsync(message);
                        stopProtocol = true;
                    }
                }
                catch (Exception ex)
                {
                    string message = "Local data store failed to start:  " + ex.Message;
                    SensusServiceHelper.Get().Logger.Log(message, LoggingLevel.Normal, GetType());
                    SensusServiceHelper.Get().FlashNotificationAsync(message);
                    stopProtocol = true;
                }

                if (stopProtocol)
                {
                    Stop();
                }
            }
        }
Beispiel #10
0
        /// <summary>
        /// Converts JSON to a Protocol object. Private because Protocols should always be serialized as encrypted binary codes, and this function works with unencrypted strings (it's called in service of the former).
        /// </summary>
        /// <param name="json">JSON to deserialize.</param>
        private static void DisplayFromJsonAsync(string json)
        {
            new Thread(() =>
            {
                try
                {
                    #region allow protocols to be opened across platforms by manually editing the namespaces in the JSON
                    string newJSON;
                    switch (SensusServiceHelper.Get().GetType().Name)
                    {
                    case "AndroidSensusServiceHelper":
                        newJSON = json.Replace(".iOS", ".Android").Replace(".WinPhone", ".Android");
                        break;

                    case "iOSSensusServiceHelper":
                        newJSON = json.Replace(".Android", ".iOS").Replace(".WinPhone", ".iOS");
                        break;

                    case "WinPhone":
                        newJSON = json.Replace(".Android", ".WinPhone").Replace(".iOS", ".WinPhone");
                        break;

                    default:
                        throw new SensusException("Attempted to deserialize JSON into unknown service helper type:  " + SensusServiceHelper.Get().GetType().FullName);
                    }

                    if (newJSON == json)
                    {
                        SensusServiceHelper.Get().Logger.Log("No cross-platform conversion required for service helper JSON.", LoggingLevel.Normal, typeof(Protocol));
                    }
                    else
                    {
                        SensusServiceHelper.Get().Logger.Log("Performed cross-platform conversion of service helper JSON.", LoggingLevel.Normal, typeof(Protocol));
                        json = newJSON;
                    }
                    #endregion

                    Protocol protocol             = null;
                    ManualResetEvent protocolWait = new ManualResetEvent(false);

                    // always deserialize protocols on the main thread (e.g., since a looper might be required for android)
                    Device.BeginInvokeOnMainThread(() =>
                    {
                        try
                        {
                            protocol = JsonConvert.DeserializeObject <Protocol>(json, SensusServiceHelper.JSON_SERIALIZER_SETTINGS);
                        }
                        catch (Exception ex)
                        {
                            SensusServiceHelper.Get().Logger.Log("Error while deserializing protocol:  " + ex.Message, LoggingLevel.Normal, typeof(Protocol));
                        }
                        finally
                        {
                            protocolWait.Set();
                        }
                    });

                    protocolWait.WaitOne();

                    if (protocol == null)
                    {
                        SensusServiceHelper.Get().Logger.Log("Failed to deserialize protocol.", LoggingLevel.Normal, typeof(Protocol));
                        SensusServiceHelper.Get().FlashNotificationAsync("Failed to deserialize protocol.");
                        return;
                    }
                    else
                    {
                        Action <Protocol> StartProtocol = p =>
                        {
                            Device.BeginInvokeOnMainThread(async() =>
                            {
                                if (!(App.Current.MainPage.Navigation.NavigationStack.Last() is ProtocolsPage))
                                {
                                    await App.Current.MainPage.Navigation.PushAsync(new ProtocolsPage());
                                }

                                p.StartWithUserAgreement("You just opened a protocol named \"" + p.Name + "\" within Sensus." + (string.IsNullOrWhiteSpace(p.StartupAgreement) ? "" : " Please read the following terms and conditions."));
                            });
                        };

                        Protocol existingProtocol = SensusServiceHelper.Get().RegisteredProtocols.FirstOrDefault(p => p.Id == protocol.Id);

                        if (existingProtocol == null)
                        {
                            Probe.GetAllAsync(probes =>
                            {
                                // add any probes for the current platform that didn't come through when deserializing. for example, android has a listening WLAN probe, but iOS has a polling WLAN probe. neither will come through on the other platform when deserializing, since the types are not defined.
                                List <Type> deserializedProbeTypes = protocol.Probes.Select(p => p.GetType()).ToList();

                                foreach (Probe probe in probes)
                                {
                                    if (!deserializedProbeTypes.Contains(probe.GetType()))
                                    {
                                        SensusServiceHelper.Get().Logger.Log("Adding missing probe to protocol:  " + probe.GetType().FullName, LoggingLevel.Normal, typeof(Protocol));
                                        protocol.AddProbe(probe);
                                    }
                                }

                                // reset the random time anchor -- we shouldn't use the same one that someone else used
                                protocol.ResetRandomTimeAnchor();

                                // reset the storage directory
                                protocol.StorageDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), protocol.Id);
                                if (!Directory.Exists(protocol.StorageDirectory))
                                {
                                    Directory.CreateDirectory(protocol.StorageDirectory);
                                }

                                SensusServiceHelper.Get().RegisterProtocol(protocol);

                                StartProtocol(protocol);
                            });
                        }
                        else if (existingProtocol.Running)
                        {
                            SensusServiceHelper.Get().FlashNotificationAsync("Protocol \"" + existingProtocol.Name + "\" is already running.");
                        }
                        else
                        {
                            StartProtocol(existingProtocol);
                        }
                    }
                }
                catch (Exception ex)
                {
                    SensusServiceHelper.Get().Logger.Log("Failed to deserialize/display protocol from JSON:  " + ex.Message, LoggingLevel.Normal, typeof(Protocol));
                    SensusServiceHelper.Get().FlashNotificationAsync("Failed to deserialize and/or display protocol.");
                }
            }).Start();
        }