Skip to content

Commit

Permalink
[Core, Android] Fix to address the elusive 'Sharing violation on path…
Browse files Browse the repository at this point in the history
… PropertyStore.forms.tmp' (xamarin#1075)

* use a semaphor for actual saving piece
make reading serialized propertystore readonly to help with collisions.

* change over to async Task and await OnStateChanged() method to try and mitigate what might be the race condition causing the ' Sharing violation on path PropertyStore.forms.tmp' error

* update Semaphore name

* remove private specifier per the style guide

* Update docs and add warning suppression for broken mono warning

* ... and adding the warning suppression to Release mode, as well.

* -add try...finally block so we can guarantee that the semaphore is released if there's an exception while saving the properties.
-remove the legacy code that the semaphore replaces

* Update docs

* Attempting to fix docs

* Trying again to get docs to pass
  • Loading branch information
dgeller-OUHSC authored and rmarinho committed Oct 3, 2017
1 parent 6877d63 commit afa0fb7
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 39 deletions.
24 changes: 12 additions & 12 deletions Xamarin.Forms.Core/Application.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading;
using System.ComponentModel;
using System.Threading.Tasks;
using Xamarin.Forms.Internals;
Expand All @@ -15,14 +16,13 @@ public class Application : Element, IResourcesProvider, IApplicationController,
readonly Lazy<PlatformConfigurationRegistry<Application>> _platformConfigurationRegistry;

IAppIndexingProvider _appIndexProvider;
bool _isSaving;

ReadOnlyCollection<Element> _logicalChildren;

Page _mainPage;

ResourceDictionary _resources;
bool _saveAgain;
static SemaphoreSlim SaveSemaphore = new SemaphoreSlim(1, 1);

protected Application()
{
Expand Down Expand Up @@ -309,16 +309,16 @@ void OnPopCanceled()

async Task SetPropertiesAsync()
{
if (_isSaving)
{
_saveAgain = true;
return;
}
_isSaving = true;
await DependencyService.Get<IDeserializer>().SerializePropertiesAsync(Properties);
if (_saveAgain)
await DependencyService.Get<IDeserializer>().SerializePropertiesAsync(Properties);
_isSaving = _saveAgain = false;
await SaveSemaphore.WaitAsync();
try
{
await DependencyService.Get<IDeserializer>().SerializePropertiesAsync(Properties);
}
finally
{
SaveSemaphore.Release();
}

}

class NavigationImpl : NavigationProxy
Expand Down
27 changes: 14 additions & 13 deletions Xamarin.Forms.Platform.Android/AppCompat/FormsAppCompatActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using AlertDialog = Android.Support.V7.App.AlertDialog;
using ARelativeLayout = Android.Widget.RelativeLayout;
using Xamarin.Forms.Internals;
using System.Threading.Tasks;

#endregion

Expand Down Expand Up @@ -162,7 +163,7 @@ protected override void OnActivityResult(int requestCode, Result resultCode, Int
callback(resultCode, data);
}

protected override void OnCreate(Bundle savedInstanceState)
protected override async void OnCreate(Bundle savedInstanceState)
{
if (!AllowFragmentRestore)
{
Expand Down Expand Up @@ -194,7 +195,7 @@ protected override void OnCreate(Bundle savedInstanceState)
_previousState = _currentState;
_currentState = AndroidApplicationLifecycleState.OnCreate;

OnStateChanged();
await OnStateChanged();

if (Forms.IsLollipopOrNewer)
{
Expand All @@ -221,7 +222,7 @@ protected override void OnNewIntent(Intent intent)
CheckForAppLink(intent);
}

protected override void OnPause()
protected override async void OnPause()
{
_layout.HideKeyboard(true);

Expand All @@ -234,20 +235,20 @@ protected override void OnPause()
_previousState = _currentState;
_currentState = AndroidApplicationLifecycleState.OnPause;

OnStateChanged();
await OnStateChanged();
}

protected override void OnRestart()
protected override async void OnRestart()
{
base.OnRestart();

_previousState = _currentState;
_currentState = AndroidApplicationLifecycleState.OnRestart;

OnStateChanged();
await OnStateChanged();
}

protected override void OnResume()
protected override async void OnResume()
{
// counterpart to OnPause
base.OnResume();
Expand All @@ -263,24 +264,24 @@ protected override void OnResume()
_previousState = _currentState;
_currentState = AndroidApplicationLifecycleState.OnResume;

OnStateChanged();
await OnStateChanged();
}

protected override void OnStart()
protected override async void OnStart()
{
base.OnStart();

_previousState = _currentState;
_currentState = AndroidApplicationLifecycleState.OnStart;

OnStateChanged();
await OnStateChanged();
}

// Scenarios that stop and restart your app
// -- Switches from your app to another app, activity restarts when clicking on the app again.
// -- Action in your app that starts a new Activity, the current activity is stopped and the second is created, pressing back restarts the activity
// -- The user receives a phone call while using your app on his or her phone
protected override void OnStop()
protected override async void OnStop()
{
// writing to storage happens here!
// full UI obstruction
Expand All @@ -293,7 +294,7 @@ protected override void OnStop()
_previousState = _currentState;
_currentState = AndroidApplicationLifecycleState.OnStop;

OnStateChanged();
await OnStateChanged();
}

void AppOnPropertyChanged(object sender, PropertyChangedEventArgs args)
Expand Down Expand Up @@ -380,7 +381,7 @@ void OnPageBusy(Page sender, bool enabled)
UpdateProgressBarVisibility(_busyCount > 0);
}

async void OnStateChanged()
async Task OnStateChanged()
{
if (_application == null)
return;
Expand Down
28 changes: 17 additions & 11 deletions Xamarin.Forms.Platform.Android/Deserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,28 @@ public Task<IDictionary<string, object>> DeserializePropertiesAsync()
return Task.Run(() =>
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
using (IsolatedStorageFileStream stream = store.OpenFile(PropertyStoreFile, System.IO.FileMode.OpenOrCreate))
using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max))
{
if (stream.Length == 0)
if (!store.FileExists(PropertyStoreFile))
return null;

try
using (IsolatedStorageFileStream stream = store.OpenFile(PropertyStoreFile, System.IO.FileMode.Open, System.IO.FileAccess.Read))
using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max))
{
var dcs = new DataContractSerializer(typeof(Dictionary<string, object>));
return (IDictionary<string, object>)dcs.ReadObject(reader);
}
catch (Exception e)
{
Debug.WriteLine("Could not deserialize properties: " + e.Message);
Log.Warning("Xamarin.Forms PropertyStore", $"Exception while reading Application properties: {e}");
if (stream.Length == 0)
return null;

try
{
var dcs = new DataContractSerializer(typeof(Dictionary<string, object>));
return (IDictionary<string, object>)dcs.ReadObject(reader);
}
catch (Exception e)
{
Debug.WriteLine("Could not deserialize properties: " + e.Message);
Log.Warning("Xamarin.Forms PropertyStore", $"Exception while reading Application properties: {e}");
}
}

}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>
</NoWarn>
<NoWarn>CS0109</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Turkey|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
Expand Down
2 changes: 1 addition & 1 deletion docs/Xamarin.Forms.Core/Xamarin.Forms/Application.xml
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@
<AttributeName>System.Diagnostics.DebuggerStepThrough</AttributeName>
</Attribute>
<Attribute>
<AttributeName>System.Runtime.CompilerServices.AsyncStateMachine(typeof(Xamarin.Forms.Application/&lt;SavePropertiesAsync&gt;d__53))</AttributeName>
<AttributeName>System.Runtime.CompilerServices.AsyncStateMachine(typeof(Xamarin.Forms.Application/&lt;SavePropertiesAsync&gt;d__52))</AttributeName>
</Attribute>
</Attributes>
<ReturnValue>
Expand Down

0 comments on commit afa0fb7

Please sign in to comment.