private async Task PersistLogAsync(Log log, State state) { try { await _storage.PutLog(Name, log).ConfigureAwait(false); } catch (StorageException e) { AppCenterLog.Error(AppCenterLog.LogTag, "Error persisting log", e); return; } try { bool enabled; using (await _mutex.GetLockAsync(state).ConfigureAwait(false)) { _pendingLogCount++; enabled = _enabled; } if (enabled) { CheckPendingLogs(state); return; } AppCenterLog.Warn(AppCenterLog.LogTag, "Channel is temporarily disabled; log was saved to disk"); } catch (StatefulMutexException) { AppCenterLog.Warn(AppCenterLog.LogTag, "The PersistLog operation has been cancelled"); } }
/// <summary> /// Initializes the singleton application object. This is the first line of authored code /// executed, and as such is the logical equivalent of main() or WinMain(). /// </summary> public App() { // Init settings. localSettings = ApplicationData.Current.LocalSettings; TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs args) => { // If you see this message while testing the app and if the stack trace is SDK related, we might have a bug in the SDK as we don't want to leak any exception from the SDK. AppCenterLog.Error("AppCenterPuppet", "Unobserved exception observed=" + args.Observed, args.Exception); }; CoreApplication.EnablePrelaunch(true); InitializeComponent(); AppCenter.LogLevel = LogLevel.Verbose; AppCenter.SetLogUrl("https://in-integration.dev.avalanch.es"); // Set data from local storage. var countryCode = localSettings.Values[Constants.KeyCountryCode] as string; if (!string.IsNullOrEmpty(countryCode)) { AppCenter.SetCountryCode(countryCode); } var storageSize = localSettings.Values[Constants.KeyStorageMaxSize] as long?; if (storageSize != null && storageSize > 0) { AppCenter.SetMaxStorageSizeAsync((long)storageSize); } // User callbacks. Crashes.ShouldProcessErrorReport = (report) => { Log($"Determining whether to process error report with an ID: {report.Id}"); return(true); }; Crashes.GetErrorAttachments = GetErrorAttachmentsHandler; // Event handlers. Crashes.SendingErrorReport += (_, args) => Log($"Sending error report for an error ID: {args.Report.Id}"); Crashes.SentErrorReport += (_, args) => Log($"Sent error report for an error ID: {args.Report.Id}"); Crashes.FailedToSendErrorReport += (_, args) => Log($"Failed to send error report for an error ID: {args.Report.Id}"); // Start App Center. AppCenter.Start("2daf2955-b4e4-4206-b38a-fedcdc6f4f84", typeof(Analytics), typeof(Crashes)); // Set userId. var userId = localSettings.Values[Constants.KeyUserId] as string; if (!string.IsNullOrEmpty(userId)) { AppCenter.SetUserId(userId); } Crashes.HasCrashedInLastSessionAsync().ContinueWith(hasCrashed => { Log("Crashes.HasCrashedInLastSession=" + hasCrashed.Result); }); Crashes.GetLastSessionCrashReportAsync().ContinueWith(task => { Log("Crashes.LastSessionCrashReport.StackTrace=" + task.Result?.StackTrace); }); }
private async Task <string[]> LoadDeliveryTimeList() { try { var timeList = await restActions.GetDeliveryTime(); string[] time = new string[timeList.Count]; int i = 0; foreach (var deliveryTimeObj in timeList) { time[i] = deliveryTimeObj.DELIVERY_TIME; i++; } return(time); } catch (Exception e) { AppCenterLog.Error("ERROR", e.Message, e); } return(null); }
private List <object[]> ExecuteSelectionSqlQuery(string query, IList <object> args = null) { var db = _db ?? throw new StorageException("The database wasn't initialized."); var result = raw.sqlite3_prepare_v2(db, query, out var stmt); if (result != raw.SQLITE_OK) { throw ToStorageException(result, "Failed to prepare SQL query"); } try { var entries = new List <object[]>(); BindParameters(stmt, args); while (raw.sqlite3_step(stmt) == raw.SQLITE_ROW) { var count = raw.sqlite3_column_count(stmt); entries.Add(Enumerable.Range(0, count).Select(i => GetColumnValue(stmt, i)).ToArray()); } return(entries); } finally { result = raw.sqlite3_finalize(stmt); if (result != raw.SQLITE_OK) { AppCenterLog.Error(AppCenterLog.LogTag, $"Failed to finalize statement, result={result}"); } } }
private void HandleSendingFailure(State state, string batchId, IngestionException e) { var isRecoverable = e?.IsRecoverable ?? false; AppCenterLog.Error(AppCenterLog.LogTag, $"Sending logs for channel '{Name}', batch '{batchId}' failed: {e?.Message}"); List <Log> removedLogs; using (_mutex.GetLock(state)) { removedLogs = _sendingBatches[batchId]; _sendingBatches.Remove(batchId); if (isRecoverable) { _pendingLogCount += removedLogs.Count; } } if (!isRecoverable && FailedToSendLog != null) { foreach (var log in removedLogs) { FailedToSendLog?.Invoke(this, new FailedToSendLogEventArgs(log, e)); } } Suspend(state, !isRecoverable, e); }
private void ExecuteNonSelectionSqlQuery(string query, IList <object> args = null) { var db = _db ?? throw new StorageException("The database wasn't initialized."); var result = raw.sqlite3_prepare_v2(db, query, out var stmt); if (result != raw.SQLITE_OK) { throw ToStorageException(result, "Failed to prepare SQL query"); } try { BindParameters(stmt, args); result = raw.sqlite3_step(stmt); if (result != raw.SQLITE_DONE) { throw ToStorageException(result, "Failed to run query"); } } finally { result = raw.sqlite3_finalize(stmt); if (result != raw.SQLITE_OK) { AppCenterLog.Error(AppCenterLog.LogTag, $"Failed to finalize statement, result={result}"); } } }
/// <summary> /// Saves an error log on disk. /// </summary> /// <param name="exception">The exception that caused the crash.</param> /// <param name="errorLog">The error log.</param> public virtual void InstanceSaveErrorLogFiles(System.Exception exception, ManagedErrorLog errorLog) { try { // Serialize main log file. var errorLogString = LogSerializer.Serialize(errorLog); var errorLogFileName = errorLog.Id + ErrorLogFileExtension; AppCenterLog.Debug(Crashes.LogTag, "Saving uncaught exception."); var directory = InstanceGetErrorStorageDirectory(); directory.CreateFile(errorLogFileName, errorLogString); AppCenterLog.Debug(Crashes.LogTag, $"Saved error log in directory {ErrorStorageDirectoryName} with name {errorLogFileName}."); try { // Serialize exception as raw stack trace. var exceptionFileName = errorLog.Id + ExceptionFileExtension; directory.CreateFile(exceptionFileName, exception.ToString()); AppCenterLog.Debug(Crashes.LogTag, $"Saved exception in directory {ErrorStorageDirectoryName} with name {exceptionFileName}."); } catch (System.Exception ex) { AppCenterLog.Warn(Crashes.LogTag, "Failed to serialize exception for client side inspection.", ex); } } catch (System.Exception ex) { AppCenterLog.Error(Crashes.LogTag, "Failed to save error log.", ex); } }
public void OnChannelGroupReady(IChannelGroup channelGroup, string appSecret) { try { #if REFERENCE #else WatsonRegistrationManager.Start(appSecret); #pragma warning disable CS0612 // Type or member is obsolete AppCenter.CorrelationIdChanged += (s, id) => { WatsonRegistrationManager.SetCorrelationId(id.ToString()); }; // Checking for null and setting id needs to be atomic to avoid // overwriting Guid newId = Guid.NewGuid(); AppCenter.TestAndSetCorrelationId(Guid.Empty, ref newId); #pragma warning restore CS0612 // Type or member is obsolete #endif } catch (Exception e) { AppCenterLog.Error(AppCenterLog.LogTag, "Failed to register crashes with Watson", e); } }
private async Task <Exception> HandleStorageRelatedExceptionAsync(Exception e) { // Check if database is corrupted, we have evidence (https://github.com/microsoft/appcenter-sdk-dotnet/issues/1184) // that it's not always originated by a proper SQLiteException (which would then be converted to StorageException in StorageAdapter). // If it was always the right type then the exception would not have been unobserved in that application before we changed the re-throw logic here. // But the message is definitely "Corrupt" and thus unfortunately that is the only check we seem to be able to do as opposed to type/property checking. if (e.Message == "Corrupt" || e.InnerException?.Message == "Corrupt") { AppCenterLog.Error(AppCenterLog.LogTag, "Database corruption detected, deleting the file and starting fresh...", e); await _storageAdapter.DeleteDatabaseFileAsync().ConfigureAwait(false); await InitializeDatabaseAsync().ConfigureAwait(false); } // Return exception to re-throw. if (e is StorageException) { // This is the expected case, storage adapter already wraps exception as StorageException, so return as is. return(e); } // Tasks should already be throwing only storage exceptions, but in case any are missed, // which has happened (the Corrupt exception mentioned previously), catch them here and wrap in a storage exception. This will prevent // the exception from being unobserved. return(new StorageException(e)); }
async void RunMBaaSAsync(object sender, EventArgs e) { try { userInfo = await Auth.SignInAsync(); if (userInfo.AccountId != null) { Application.Current.Properties[AccountId] = userInfo.AccountId; SignInInformationButton.Text = "User authenticated"; } AppCenterLog.Info(App.LogTag, "Auth.SignInAsync succeeded accountId=" + userInfo.AccountId); } catch (Exception ex) { AppCenterLog.Error(App.LogTag, "Auth scenario failed", ex); Crashes.TrackError(ex); } try { var list = await Data.ListAsync <CustomDocument>(DefaultPartitions.UserDocuments); foreach (var doc in list) { AppCenterLog.Info(App.LogTag, "List result=" + doc.DeserializedValue.id); } var document = list.CurrentPage.Items.First(); AppCenterLog.Info(App.LogTag, "List first result=" + document.DeserializedValue.id); document = await Data.DeleteAsync <CustomDocument>(document.Id, DefaultPartitions.UserDocuments); AppCenterLog.Info(App.LogTag, "Delete result=" + document.DeserializedValue); } catch (Exception ex) { AppCenterLog.Error(App.LogTag, "Data list/delete first scenario failed", ex); Crashes.TrackError(ex); } try { var customDoc = new CustomDocument { id = Guid.NewGuid(), timestamp = DateTime.UtcNow }; var id = customDoc.id.ToString(); var document = await Data.ReplaceAsync(id, customDoc, DefaultPartitions.UserDocuments); AppCenterLog.Info(App.LogTag, "Replace result=" + document.DeserializedValue.id); document = await Data.ReadAsync <CustomDocument>(id, DefaultPartitions.UserDocuments); AppCenterLog.Info(App.LogTag, "Read result=" + document.DeserializedValue.id); } catch (Exception ex) { AppCenterLog.Error(App.LogTag, "Data person scenario failed", ex); Crashes.TrackError(ex); } }
/// <summary> /// Check if userId is valid for App Center. /// </summary> /// <param name="userId"></param> /// <returns>true if valid, false otherwise.</returns> public static bool CheckUserIdValidForAppCenter(String userId) { if (userId != null && userId.Length > UserIdMaxLength) { AppCenterLog.Error(AppCenterLog.LogTag, "userId is limited to " + UserIdMaxLength + " characters."); return(false); } return(true); }
private void CreatePushNotificationChannel(Action <PushNotificationChannel> created) { Task <PushNotificationChannel> CreatePushNotificationChannelForApplicationAsync() { try { return(new WindowsPushNotificationChannelManager() .CreatePushNotificationChannelForApplicationAsync() .AsTask()); } catch (Exception e) { return(Task.FromException <PushNotificationChannel>(e)); } } void OnNetworkStateChange(object sender, EventArgs e) { if (NetworkStateAdapter.IsConnected) { NetworkStateAdapter.NetworkStatusChanged -= OnNetworkStateChange; AppCenterLog.Debug(LogTag, "Second attempt to create notification channel..."); // Second attempt is the last one anyway. CreatePushNotificationChannelForApplicationAsync().ContinueWith(task => { if (task.IsFaulted) { AppCenterLog.Error(LogTag, "Unable to create notification channel.", task.Exception); return; } created?.Invoke(task.Result); }); } } // If this isn't the first time after installation, the notification channel is created successfully even without network. CreatePushNotificationChannelForApplicationAsync().ContinueWith(task => { if (task.IsFaulted && NetworkStateAdapter.IsConnected) { AppCenterLog.Error(LogTag, "Unable to create notification channel.", task.Exception); return; } if (!task.IsFaulted && task.Result != null) { created?.Invoke(task.Result); return; } AppCenterLog.Debug(LogTag, "The network isn't connected, another attempt to crate push notification channel " + "will be made after the network is available."); NetworkStateAdapter.NetworkStatusChanged += OnNetworkStateChange; }); }
static StorageAdapter() { try { Batteries_V2.Init(); } catch (Exception e) { AppCenterLog.Error(AppCenterLog.LogTag, "Failed to initialize sqlite3 provider.", e); } }
/// <summary> /// If enabled, register push channel and send URI to backend. /// Also start intercepting pushes. /// If disabled and previously enabled, stop listening for pushes (they will still be received though). /// </summary> private void ApplyEnabledState(bool enabled) { if (enabled) { // We expect caller of this method to lock on _mutex, we can't do it here as that lock is not recursive AppCenterLog.Debug(LogTag, "Getting push token..."); var state = _mutex.State; CreatePushNotificationChannel(channel => { try { using (_mutex.GetLock(state)) { LatestPushToken = channel?.Uri; if (!string.IsNullOrEmpty(LatestPushToken)) { // Save channel member _channel = channel; // Subscribe to UserId Change. UserIdContext.UserIdUpdated -= OnUserIdUpdated; UserIdContext.UserIdUpdated += OnUserIdUpdated; // Subscribe to push. channel.PushNotificationReceived += OnPushNotificationReceivedHandler; // Send channel URI to backend AppCenterLog.Debug(LogTag, $"Push token '{LatestPushToken}'"); var pushInstallationLog = new PushInstallationLog(null, LatestPushToken, null, Guid.NewGuid(), UserIdContext.Instance.UserId); // Do not await the call to EnqueueAsync or the UI thread can be blocked! #pragma warning disable CS4014 Channel.EnqueueAsync(pushInstallationLog); #pragma warning restore } else { AppCenterLog.Error(LogTag, "Push service registering with App Center backend has failed."); } } } catch (StatefulMutexException) { AppCenterLog.Warn(LogTag, "Push Enabled state changed after creating channel."); } }); } else if (_channel != null) { LatestPushToken = null; UserIdContext.UserIdUpdated -= OnUserIdUpdated; _channel.PushNotificationReceived -= OnPushNotificationReceivedHandler; } }
private async Task InitializeDatabaseAsync() { try { await _storageAdapter.CreateTableAsync <LogEntry>().ConfigureAwait(false); } catch (Exception e) { AppCenterLog.Error(AppCenterLog.LogTag, "An error occurred while initializing storage", e); } }
/// <summary> /// Track a handled error. /// </summary> /// <param name="exception">The .NET exception describing the handled error.</param> /// <param name="properties">Optional properties.</param> #endif public static void TrackError(Exception exception, IDictionary <string, string> properties = null) { if (exception == null) { AppCenterLog.Error(LogTag, "TrackError exception parameter cannot be null."); } else { PlatformTrackError(exception, properties); } }
public long GetMaxStorageSize() { try { return(GetMaxPageCount() * GetPageSize()); } catch (StorageException) { AppCenterLog.Error(AppCenterLog.LogTag, $"Could not get max storage size."); return(-1); } }
/// <summary> /// Reads an exception file from the given file. /// </summary> /// <param name="file">The file that contains exception.</param> /// <returns>An exception stack trace or null if the file cannot be read.</returns> public virtual string InstanceReadExceptionFile(File file) { try { return(file.ReadAllText()); } catch (System.Exception e) { AppCenterLog.Error(Crashes.LogTag, $"Encountered an unexpected error while reading stack trace file: {file.Name}", e); } return(null); }
async void RunMBaaSAsync(object sender, EventArgs e) { try { var userInfo = await Auth.SignInAsync(); AppCenterLog.Info(App.LogTag, "Auth.SignInAsync succeeded accountId=" + userInfo.AccountId); } catch (Exception ex) { AppCenterLog.Error(App.LogTag, "Auth scenario failed", ex); Crashes.TrackError(ex); } try { var list = await Data.ListAsync <CustomDocument>(DefaultPartitions.UserDocuments); foreach (var doc in list) { AppCenterLog.Info(App.LogTag, "List result=" + JsonConvert.SerializeObject(doc)); } var document = list.CurrentPage.Items.First(); AppCenterLog.Info(App.LogTag, "List first result=" + JsonConvert.SerializeObject(document)); document = await Data.DeleteAsync <CustomDocument>(document.Id, DefaultPartitions.UserDocuments); AppCenterLog.Info(App.LogTag, "Delete result=" + JsonConvert.SerializeObject(document)); } catch (Exception ex) { AppCenterLog.Error(App.LogTag, "Data list/delete first scenario failed", ex); Crashes.TrackError(ex); } try { var customDoc = new CustomDocument { Id = Guid.NewGuid(), TimeStamp = DateTime.UtcNow }; var id = customDoc.Id.ToString(); var document = await Data.ReplaceAsync(id, customDoc, DefaultPartitions.UserDocuments); AppCenterLog.Info(App.LogTag, "Replace result=" + JsonConvert.SerializeObject(document)); document = await Data.ReadAsync <CustomDocument>(id, DefaultPartitions.UserDocuments); AppCenterLog.Info(App.LogTag, "Read result=" + JsonConvert.SerializeObject(document)); } catch (Exception ex) { AppCenterLog.Error(App.LogTag, "Data person scenario failed", ex); Crashes.TrackError(ex); } }
static void OnUnhandledException(object sender, RaiseThrowableEventArgs e) { var exception = e.Exception; AppCenterLog.Error(LogTag, "Unhandled Exception:", exception); var javaThrowable = exception as Throwable; var modelException = GenerateModelException(exception, true); byte[] rawException = javaThrowable == null?CrashesUtils.SerializeException(exception) : null; WrapperSdkExceptionManager.SaveWrapperException(Thread.CurrentThread(), javaThrowable, modelException, rawException); }
/// <summary> /// Asynchronously retrieves logs from storage and flags them to avoid duplicate retrievals on subsequent calls /// </summary> /// <param name="channelName">Name of the channel to retrieve logs from</param> /// <param name="limit">The maximum number of logs to retrieve</param> /// <param name="logs">A list to which the retrieved logs will be added</param> /// <returns>A batch ID for the set of returned logs; null if no logs are found</returns> /// <exception cref="StorageException"/> public Task <string> GetLogsAsync(string channelName, int limit, List <Log> logs) { return(AddTaskToQueue(() => { logs?.Clear(); var retrievedLogs = new List <Log>(); AppCenterLog.Debug(AppCenterLog.LogTag, $"Trying to get up to {limit} logs from storage for {channelName}"); var idPairs = new List <Tuple <Guid?, long> >(); var failedToDeserializeALog = false; var objectEntries = _storageAdapter.Select(TableName, ColumnChannelName, channelName, ColumnIdName, _pendingDbIdentifiers.Cast <object>().ToArray(), limit); var retrievedEntries = objectEntries.Select(entries => new LogEntry() { Id = (long)entries[0], Channel = (string)entries[1], Log = (string)entries[2] } ).ToList(); foreach (var entry in retrievedEntries) { try { var log = LogSerializer.DeserializeLog(entry.Log); retrievedLogs.Add(log); idPairs.Add(Tuple.Create(log.Sid, Convert.ToInt64(entry.Id))); } catch (JsonException e) { AppCenterLog.Error(AppCenterLog.LogTag, "Cannot deserialize a log in storage", e); failedToDeserializeALog = true; _storageAdapter.Delete(TableName, ColumnIdName, entry.Id); } } if (failedToDeserializeALog) { AppCenterLog.Warn(AppCenterLog.LogTag, "Deleted logs that could not be deserialized"); } if (idPairs.Count == 0) { AppCenterLog.Debug(AppCenterLog.LogTag, $"No available logs in storage for channel '{channelName}'"); return null; } // Process the results var batchId = Guid.NewGuid().ToString(); ProcessLogIds(channelName, batchId, idPairs); logs?.AddRange(retrievedLogs); return batchId; })); }
/// <summary> /// Initializes the singleton application object. This is the first line of authored code /// executed, and as such is the logical equivalent of main() or WinMain(). /// </summary> public App() { TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs args) => { // If you see this message while testing the app and if the stack trace is SDK related, we might have a bug in the SDK as we don't want to leak any exception from the SDK. AppCenterLog.Error("AppCenterDemo", "Unobserved exception observed=" + args.Observed, args.Exception); }; CoreApplication.EnablePrelaunch(true); InitializeComponent(); Suspending += OnSuspending; AppCenter.LogLevel = LogLevel.Verbose; AppCenter.Start("e8354a9a-001a-4728-be65-a6477e57f2e7", typeof(Analytics), typeof(Crashes)); }
/// <summary> /// Reads an error log file from the given file. /// </summary> /// <param name="file">The file that contains error log.</param> /// <returns>An error log instance or null if the file doesn't contain an error log.</returns> public virtual ManagedErrorLog InstanceReadErrorLogFile(File file) { try { var errorLogString = file.ReadAllText(); return((ManagedErrorLog)LogSerializer.DeserializeLog(errorLogString)); } catch (System.Exception e) { AppCenterLog.Error(Crashes.LogTag, $"Encountered an unexpected error while reading an error log file: {file.Name}", e); } return(null); }
static void OnUnhandledException(Exception exception, string source) { if (_exception == null) { AppCenterLog.Error(LogTag, $"Unhandled Exception from source={source}", exception); var javaThrowable = exception as Throwable; var modelException = GenerateModelException(exception, true); byte[] rawException = javaThrowable == null?CrashesUtils.SerializeException(exception) : null; WrapperSdkExceptionManager.SaveWrapperException(Thread.CurrentThread(), javaThrowable, modelException, rawException); _exception = exception; } }
/// <summary> /// Asynchronously retrieves logs from storage and flags them to avoid duplicate retrievals on subsequent calls /// </summary> /// <param name="channelName">Name of the channel to retrieve logs from</param> /// <param name="limit">The maximum number of logs to retrieve</param> /// <param name="logs">A list to which the retrieved logs will be added</param> /// <returns>A batch ID for the set of returned logs; null if no logs are found</returns> /// <exception cref="StorageException"/> public Task <string> GetLogsAsync(string channelName, int limit, List <Log> logs) { return(AddTaskToQueue(() => { logs?.Clear(); var retrievedLogs = new List <Log>(); AppCenterLog.Debug(AppCenterLog.LogTag, $"Trying to get up to {limit} logs from storage for {channelName}"); var idPairs = new List <Tuple <Guid?, long> >(); var failedToDeserializeALog = false; var retrievedEntries = _storageAdapter.GetAsync <LogEntry>(entry => entry.Channel == channelName, limit) .GetAwaiter().GetResult(); foreach (var entry in retrievedEntries) { if (_pendingDbIdentifiers.Contains(entry.Id)) { continue; } try { var log = LogSerializer.DeserializeLog(entry.Log); retrievedLogs.Add(log); idPairs.Add(Tuple.Create(log.Sid, Convert.ToInt64(entry.Id))); } catch (JsonException e) { AppCenterLog.Error(AppCenterLog.LogTag, "Cannot deserialize a log in storage", e); failedToDeserializeALog = true; _storageAdapter.DeleteAsync <LogEntry>(row => row.Id == entry.Id) .GetAwaiter().GetResult(); } } if (failedToDeserializeALog) { AppCenterLog.Warn(AppCenterLog.LogTag, "Deleted logs that could not be deserialized"); } if (idPairs.Count == 0) { AppCenterLog.Debug(AppCenterLog.LogTag, $"No available logs in storage for channel '{channelName}'"); return null; } // Process the results var batchId = Guid.NewGuid().ToString(); ProcessLogIds(channelName, batchId, idPairs); logs?.AddRange(retrievedLogs); return batchId; })); }
public bool SetMaxStorageSize(long sizeInBytes) { var db = _db ?? throw new StorageException("The database wasn't initialized."); // Check the current number of pages in the database to determine whether the requested size will shrink the database. var currentPageCount = GetPageCount(); var pageSize = GetPageSize(); AppCenterLog.Info(AppCenterLog.LogTag, $"Found {currentPageCount} pages in the database."); var requestedMaxPageCount = Convert.ToBoolean(sizeInBytes % pageSize) ? sizeInBytes / pageSize + 1 : sizeInBytes / pageSize; if (currentPageCount > requestedMaxPageCount) { AppCenterLog.Warn(AppCenterLog.LogTag, $"Cannot change database size to {sizeInBytes} bytes as it would cause a loss of data. " + "Maximum database size will not be changed."); return(false); } else { // Attempt to set the limit and check the page count to make sure the given limit works. var result = raw.sqlite3_exec(db, $"PRAGMA max_page_count = {requestedMaxPageCount};"); if (result != raw.SQLITE_OK) { AppCenterLog.Error(AppCenterLog.LogTag, $"Could not change maximum database size to {sizeInBytes} bytes. SQLite error code: {result}."); return(false); } else { var currentMaxPageCount = GetMaxPageCount(); var actualMaxSize = currentMaxPageCount * pageSize; if (requestedMaxPageCount != currentMaxPageCount) { AppCenterLog.Error(AppCenterLog.LogTag, $"Could not change maximum database size to {sizeInBytes} bytes, current maximum size is {actualMaxSize} bytes."); return(false); } else { if (sizeInBytes == actualMaxSize) { AppCenterLog.Info(AppCenterLog.LogTag, $"Changed maximum database size to {actualMaxSize} bytes."); } else { AppCenterLog.Info(AppCenterLog.LogTag, $"Changed maximum database size to {actualMaxSize} bytes (next multiple of 4KiB)."); } return(true); } } } }
private async Task <PushNotificationChannel> CreatePushNotificationChannelAsync() { PushNotificationChannel channel = null; try { // If this isn't the first time after installation, the notification channel is created successfully even without network. channel = await new WindowsPushNotificationChannelManager().CreatePushNotificationChannelForApplicationAsync() .AsTask().ConfigureAwait(false); } catch (Exception exception) { if (NetworkStateAdapter.IsConnected) { AppCenterLog.Error(LogTag, "Unable to create notification channel.", exception); return(null); } } if (channel != null) { return(channel); } AppCenterLog.Debug(LogTag, "The network isn't connected, another attempt will be made after the network is available."); var networkSemaphore = new SemaphoreSlim(0); void NetworkStateChangeHandler(object sender, EventArgs e) { if (NetworkStateAdapter.IsConnected) { networkSemaphore.Release(); } } NetworkStateAdapter.NetworkStatusChanged += NetworkStateChangeHandler; await networkSemaphore.WaitAsync().ConfigureAwait(false); NetworkStateAdapter.NetworkStatusChanged -= NetworkStateChangeHandler; AppCenterLog.Debug(LogTag, "Second attempt to create notification channel..."); try { // Second attempt is the last one anyway. return(await new WindowsPushNotificationChannelManager().CreatePushNotificationChannelForApplicationAsync() .AsTask().ConfigureAwait(false)); } catch (Exception exception) { AppCenterLog.Error(LogTag, "Unable to create notification channel.", exception); return(null); } }
private static void DeleteAndroid() { try { var dbFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "../databases"); Directory.Delete(dbFolder, true); } catch (DirectoryNotFoundException e) { AppCenterLog.Error(LogTag, $"Android DB not found {e.ToString()}."); } catch (IOException e) { AppCenterLog.Error(LogTag, $"Encountered IOException when tried to delete Android DB: {e.ToString()}."); } }
partial void SaveStorageSize(NSObject sender) { var inputText = StorageSizeText.Text; if (int.TryParse(inputText, out var size)) { AppCenter.SetMaxStorageSizeAsync(size); var plist = NSUserDefaults.StandardUserDefaults; plist.SetInt(size, Constants.StorageSizeKey); } else { AppCenterLog.Error(LogTag, "Wrong number value for the max storage size."); } }
private void InitializeDatabase() { EnsureDatabaseDirectoryExists(); try { _storageAdapter.Initialize(_databasePath); _storageAdapter.CreateTable(TableName, new[] { ColumnIdName, ColumnChannelName, ColumnLogName }, new[] { "INTEGER PRIMARY KEY AUTOINCREMENT", "TEXT NOT NULL", "TEXT NOT NULL" }); } catch (Exception e) { AppCenterLog.Error(AppCenterLog.LogTag, "An error occurred while initializing storage", e); } }