TransactionTooLargeException from Samsung's SmartClip service crashing my app - can it be intercepted? - c#

Android Samsung phones have a SmartClip service that is invoked when a screenshot is taken. It launches an interface to immediately allow the screenshot to be edited.
My app will often crash when this action is performed, specifically when a large number of objects are drawn on the screen. This is a Xamarin.Forms app.
When the crash occurs, two threads are reported as responsible, with the following stack traces:
android.os.BinderProxy.transactNative BinderProxy.java
android.os.BinderProxy.transact BinderProxy.java:605
com.samsung.android.content.smartclip.ISpenGestureService$Stub$Proxy.sendSmartClipRemoteRequestResult ISpenGestureService.java:910
com.samsung.android.content.smartclip.SpenGestureManager.sendSmartClipRemoteRequestResult SpenGestureManager.java:77
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.sendResult SmartClipRemoteRequestDispatcher.java:654
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.dispatchScrollableAreaInfo SmartClipRemoteRequestDispatcher.java:313
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.access$100 SmartClipRemoteRequestDispatcher.java:59
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher$2.run SmartClipRemoteRequestDispatcher.java:154
android.os.Handler.handleCallback Handler.java:938
android.os.Handler.dispatchMessage Handler.java:99
android.os.Looper.loop Looper.java:246
android.app.ActivityThread.main ActivityThread.java:8512
java.lang.reflect.Method.invoke Method.java
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run RuntimeInit.java:602
com.android.internal.os.ZygoteInit.main ZygoteInit.java:1130
com.samsung.android.content.smartclip.SpenGestureManager.sendSmartClipRemoteRequestResult SpenGestureManager.java:81
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.sendResult SmartClipRemoteRequestDispatcher.java:654
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.dispatchScrollableAreaInfo SmartClipRemoteRequestDispatcher.java:313
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher.access$100 SmartClipRemoteRequestDispatcher.java:59
com.samsung.android.content.smartclip.SmartClipRemoteRequestDispatcher$2.run SmartClipRemoteRequestDispatcher.java:154
android.os.Handler.handleCallback Handler.java:938
android.os.Handler.dispatchMessage Handler.java:99
android.os.Looper.loop Looper.java:246
android.app.ActivityThread.main ActivityThread.java:8512
java.lang.reflect.Method.invoke Method.java
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run RuntimeInit.java:602
com.android.internal.os.ZygoteInit.main ZygoteInit.java:1130
So... what do I do? This is a crash originating in third party code that I'm not including myself. Is there a hook somewhere that I can prevent this action from executing, or to handle the exception without crashing my app?
The only other solution would be to reduce the number of objects displayed so it comes under the 1 Mb limit, but I'd like to avoid that.
EDIT to add: Unfortunately, it looks like UnhandledException handling is not going to suffice, it was only meant for logging information about the crash.

Thanks to #ToolmakerSteve I have a workaround.
I used the information in the links to detect this exception and restart the activity:
# in MainApplication.cs
private void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if ((e.ExceptionObject as RuntimeException)?.InnerException is TransactionTooLargeException)
{
Intent intent = new Intent(ApplicationContext, typeof(MainActivity));
intent.AddFlags(ActivityFlags.NewTask);
StartActivity(intent);
}
}
}
Trying to do any state-saving action in this method fails. You have to rely on state that's saved prior to the crash. Luckily I already had such a mechanism.
So I just needed to detect a crash on startup (I used AppCenter's Crashes.HasCrashedInLastSessionAsync() and run my state-restoring method. Though for some reason I could only run this check after populating MainPage. Doing it before risked a blank screen.
In addition to this, I implemented limits on the number of objects drawn on the screen, so that the crash happens less frequently.
This isn't the best answer because it would be better to stop the third party code from crashing apps, but I hope it helps someone else.

Related

IGeolocator's PositionChanged firing twice?

Context
I'm developing a traffic management app using C# (Xamarin Forms) which requires a constant feed of the user's location.
Plugin
I'm using the Geolocator plugin by James Montemagno and the PositionChanged event on the IGeolocator interface seems to be triggering twice when a position change occurs.
Device
I'm currently debugging on an Android Emulator on Visual Studio Enterprise v15.5.3
Steps to reproduce the behaviour
1) After instantiating the locator object:
IGeolocator locator = CrossGeolocator.Current
2) Some code for when the locator's PositionChanged is triggered:
locator.PositionChanged += (sender,e) => {
// Testing its frequency
System.Diagnostics.Debug.WriteLine("Position Changed Triggered.");
}
3) Start listening in an async Task function
locator.DesiredAccuracy = 100;
if(!locator.isListening)
await locator.StartListeningAsync(TimeSpan.FromMilliseconds(500), 1, true);
4) Send coordinates via the emulator
Expected Results
The output window should display one message saying "Position Changed Triggered".
Actual Results
The output window has two identical messages printed, saying: "Position Changed Triggered".
Why is this happening? and how can I make it so that the event is ONLY triggered/handled ONCE for every time the position is actually changed.
What I've tried so far
Googled the issue, not many identical situations found.
Saw an explanation here which makes me believe it's the emulator has something to do with it, although I found the solution a bit ambiguous and am not sure what they're referring to with "Live/Pin Mode"
Created a separate function and assigned the event to it, then removed it after calling my code. This does cause it to execute once, but it never executes again unless I reassign in. And if I do, sure enough the code will run for the second time, resulting in the same initial problem.
Tried setting a boolean to check if it has already run once, but realised not long after how that's illogical.
Tried to set a DateTime object to make sure no more than 1 event occurs in a given time frame; this was also no good.
Help would be appreciated. Thanks.
Please note that the location service might deliver a location event more than one time (more here).
Even if the location service is not delivering the location event more than one time, usage and/or implementation of the API (Geolocator plugin) might cause reception of the location event more than one time from the API.
In the app you might check the location event properties (accuracy, location timestamp, order of event received, etc.). Use the "best" location event with "best" meaning preferred accuracy, most recent timestamp, or the first received location event if timestamp and accuracy are equal.

UWP - DataPackage.OperationCompleted is EMPTY & gets called by nobody

I'm writing a UWP file manager and I've come to a problem with drag&drop. I'm probably just beating my head against the wall since this is obviously another bug in the platform, but this time I can't find any workaround.
When dragging files and dropping them into File Explorer everything is fine. I fill up the DataPackage and listen to the OperationCompleted event, which happens when the files finished moving to another folder. When I drop them into another view within my app, I can call DataPackageView.ReportOperationCompleted, which does work (sort of). The problem is, it's also called AUTOMATICALLY at the same time the drop happens, even though the operation is not finished yet - and I can't do anything about it. The call stack is completely empty when I hit a breakpoint in the event handler.
On top of that, when I actually look into the arguments of OperationCompleted, the Operation in OperationCompletedEventArgs is ALWAYS None! It's None when File Explorer does the job, it's None when it gets called automatically, it's None when I call it manually, NO MATTER WHAT argument I pass in. Any explanation for this, Microsoft? I'm tired of fixing your bugs, especially when I can't actually do it since the platform is so limited.
one other "curiosity" with drag&dropping files in UWP is that if you get files dropped in your app and a requested operation set to move - you can't actually move them - the files are read-only. Try explaining that to the user.
Not sure how you to move files. In general, you should use StorageFile.CopyAsync method. You could use try/catch block to wrap this operation like the follwing:
try
{
var operation = appFile.File.CopyAsync(ApplicationData.Current.LocalFolder, appFile.File.DisplayName, NameCollisionOption.GenerateUniqueName);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("exception msg: "+ex.Message);
}
Then if the file is readonly, you will get exception message, you should use this message to notify user.
I wanted a notification for when the operation is actually done.
You should implemente AsyncOperationWithProgressCompletedHandler for your async operation, then you will get notification when it's completed.
operation.Completed = (tresult,tprogress) => { System.Diagnostics.Debug.WriteLine("progress msg: "+tprogress); };

Making file picker asynchronous - Windows Phone 8.1

I tried to make File open picker asynchronous using TaskComplectionSource however sometimes I get my application closed with -1 return value, sometimes I get exception like:
[System.Runtime.InteropServices.COMException] = {System.Runtime.InteropServices.COMException (0x80004005): Unspecified error
Unspecified error
at Windows.Storage.Pickers.FileOpenPicker.PickSingleFileAndContinue()
at PhotosGraphos.Mobile.Common.StorageFileExtensions.<PickSingleFileAsyncMobile..
Code:
public static class StorageFileExtensions
{
private static TaskCompletionSource<StorageFile> PickFileTaskCompletionSource;
private static bool isPickingFileInProgress;
public static async Task<StorageFile> PickSingleFileAsyncMobile(this FileOpenPicker openPicker)
{
if (isPickingFileInProgress)
return null;
isPickingFileInProgress = true;
PickFileTaskCompletionSource = new TaskCompletionSource<StorageFile>();
var currentView = CoreApplication.GetCurrentView();
currentView.Activated += OnActivated;
openPicker.PickSingleFileAndContinue();
StorageFile pickedFile;
try
{
pickedFile = await PickFileTaskCompletionSource.Task;
}
catch (TaskCanceledException)
{
pickedFile = null;
}
finally
{
PickFileTaskCompletionSource = null;
isPickingFileInProgress = false;
}
return pickedFile;
}
private static void OnActivated(CoreApplicationView sender, IActivatedEventArgs args)
{
var continuationArgs = args as FileOpenPickerContinuationEventArgs;
sender.Activated -= OnActivated;
if (continuationArgs != null && continuationArgs.Files.Any())
{
StorageFile pickedFile = continuationArgs.Files.First();
PickFileTaskCompletionSource.SetResult(pickedFile);
}
else
{
PickFileTaskCompletionSource.SetCanceled();
}
}
}
What's weird - this bug is hardly reproduced while debugging. Does anyone have any idea what could be reason of that?
Don't do that (don't try to turn Continuation behaviour into async). Why?
Normally when your app is put into the background (for example when you call file picker), it's being suspended, and here is one small pitfall - when you have a debugger attached, your app will work without being suspended. Surely that can cause some troubles.
Note also that when you normally run your app and you fire a picker, then in some cases your app can be terminated (low resources, user closes it ...). So you need here two things which are added by VS as a template: ContinuationManager and SuspensionManager. More you will find at MSDN. At the same link you will find a good procedure to debug your app:
Follow these steps to test the case in which your app is terminated after calling the AndContinue method. These steps ensure that the debugger reattaches to your app after completing the operation and continuing.
In Visual Studio, right-click on your project and select Properties.
In Project Designer, on the Debug tab under Start action, enable Do not launch, but debug my code when it starts.
Run your app with debugging. This deploys the app, but does not run it.
Start your app manually. The debugger attaches to the app. If you have breakpoints in your code, the debugger stops at the breakpoints. When your app calls the AndContinue method, the debugger continues to run.
If your app calls a file picker, wait until you have opened the file provider (for example, Phone, Photos, or OneDrive). If your app calls an online identity provider, wait until the authentication page opens.
On the Debug Location toolbar, in the Process dropdown list, select the process for your app. In the Lifecycle Events dropdown list, select Suspend and Shutdown to terminate your app but leave the emulator running.
After the AndContinue operation completes, the debugger reattaches to your app automatically when the app continues.
I've changed file picker to standard way provided by #Romasz - it still was crashing. I've been debugging it for hours and I get same COMException but sometimes with information provided:
"GetNavigationState doesn't support serialization of a parameter type which was passed to Frame.Navigate"
It seems that code with TaskCompletionSource works and there is nothing wrong with that. I found out in msdn documentation for Frame
Note: The serialization format used by these methods is for internal use only. Your app should not form any dependencies on it. Additionally, this format supports serialization only for basic types like string, char, numeric and GUID types.
And I was passing my model-class object in navigation parameter - so it was kept in navigation stack therefore it couldn't be serialized. The lesson is: do not use non-primitive types for navigation parameter - Frame.Navigate should disallow such navigation and throw exception - but it doesn't..
EDIT:
Another bug - if you bind tapped (let say button tapped) or event like that to command which launch FileOpenPicker you need to check if picker.PickFile.. was called before - otherwise when you tap fast on that button you'll get few calls to picker.PickFile.. and UnauthorizedAccessException will be thrown.

ObjectDisposedException: Safe handle has been closed

So this is a rather small question with a big explanation. As is noted by the title I am getting an unhandled exception telling me my Safe handle has been closed. What I'll probably have to do is edit this post a few times with more and more code to help me diagnose what the problem is.
I'm using POS for .NET to make a Service Object for my RFID and MSR device. Although my devices are the same, I have 2 different Virtual COM Port chips that communicate to those devices. One by Silicon labs, the other by FTDI. I wanted to use the plug and play features with POS for .NET so I gave it both my Hardware ID's. Because it is plug and play I have the full hardware path available to me which I can then create a SafeFileHandle using a call to PInvoke and using that SafeFileHandle I create a FileStream. The FTDI chip doesn't let me talk to the devices directly like that so I have to get the friendly name of the device then use mutex to pull out the COM port then create a SerialPort instance. That step works fine and great. As a FYI I have tried to use the Friendly name of both chips to get the COM port and the Silicon Labs one (for some strange reason) doesn't get listed using SetupAPI.GetDeviceDetails using the Ports GUID. I'm not sure on that one since in Device Manager the Silicon labs Device Class Guid is the Ports GUID.
Well since both the SerialPort and the FileStream have a Stream object I decided to use that to read and write to that port. The problem with that is if I send a RFID command to the MSR device the MSR device doesn't respond back with anything. So if I use this code int fromReader = ReaderStream.ReadByte(); my thread is blocked. It's a blocking call and requires a minimum of 1 byte to proceed. So I looked around and it appears the only solution is to use a separate thread and set a timeout. If the timeout happens then abort the thread.
Thread t = new Thread(new ThreadStart(ReadFromStream));
t.Start();
if (!t.Join(timeout))
{
t.Abort();
}
(t.Abort has been surrounded with a try/catch to no avail, since it didn't fix the problem I removed it)
ReadFromStream is Abstract method in RFID Device. Here is one of the implementations
protected override void ReadFromStream()
{
var commandLength = USN3170Constants.MIN_RESPONSE_LENGTH;
var response = new System.Collections.Generic.List<byte>(USN3170Constants.MIN_RESPONSE_LENGTH);
for (int i = 0; i <= commandLength; i++)
{
int fromReader = ReaderStream.ReadByte();
if (fromReader == -1) break; //at end of stream
response.Add((byte)fromReader);
if (response.Count > USN3170Constants.DATA_LENGTH_INDEX && response[USN3170Constants.DATA_LENGTH_INDEX] > 0)
{
commandLength = response[USN3170Constants.DATA_LENGTH_INDEX] + 3;
}
}
streamBuffer = response.ToArray();
}
(int fromReader = ReaderStream.ReadByte(); was surrounded with a try/catch. Only thing it caught was the aborted thread exception, so I took it out)
The above code is where I suspect the problem lies. The strange thing is, though, is that I have a unit test which I feel mimics rather well the Microsoft Test App.
(FYI QUADPORT is the FTDI chipset)
PosExplorer posExplorer;
DeviceCollection smartCardRWs;
[Test]
public void TestQuadPortOpen()
{
posExplorer = new PosExplorer();
smartCardRWs = posExplorer.GetDevices(DeviceType.SmartCardRW, DeviceCompatibilities.CompatibilityLevel1);
//if using quadport one item is the MSR and the other is the RFID
//because of that one of them will fail. Currently the first Device in the collection is the the RFID, and the second is MSR
Assert.GreaterOrEqual(smartCardRWs.Count, 2);
//Hardware Id: QUADPORT\QUAD_SERIAL_INTERFACE
foreach(DeviceInfo item in smartCardRWs)
{
Assert.AreEqual("QUADPORT\\QUAD_SERIAL_INTERFACE", item.HardwareId);
}
SmartCardRW rfidDevice = (SmartCardRW)posExplorer.CreateInstance(smartCardRWs[0]);
SmartCardRW msrDevice = (SmartCardRW)posExplorer.CreateInstance(smartCardRWs[1]);
rfidDevice.Open();
Assert.AreNotEqual(ControlState.Closed, rfidDevice.State);
rfidDevice.Close();
try
{
msrDevice.Open();
Assert.Fail("MSR Device is not a RFID Device");
}
catch
{
Assert.AreEqual(ControlState.Closed, msrDevice.State);
}
rfidDevice = null;
msrDevice = null;
}
When I run that test I do not get the SafeFileHandle exception. In fact the test passes.
So I am at a loss as to how to track down this bug. Since I'll be using this Service Object in a different program that I am also creating I'll probably end up using this code from this test in that program. However I feel that the Microsoft Test App is more or less the "Golden Standard". Is it really... probably not. But it does work good for my purposes, SO I feel it is a problem with my code and not theirs.
Any tricks on how I can narrow this down? FYI I've tried using the debugger but walking the Open Code the error does not occur. I also walked the Update Status Timer and it also does not throw the error. Once I hit continue then I'll get the exception. I turned of Just My Code and Loaded Symbols and it tells me "Source Information is missing from teh debug information for this module"
This problem (and in particular the reference to a SerialPort instance) sounds suspiciously like the problem documented at http://connect.microsoft.com/VisualStudio/feedback/details/140018/serialport-crashes-after-disconnect-of-usb-com-port.
As I understand it, in the case of a non-permanent SerialPort (like one associated with a USB device, for example) when the port "goes away" unexpectedly the underlying Stream associated with it gets disposed. If there is an active read or write operation on the port at the time a subsequent call to SerialPort.Close can lead to the exception you mention, however the exception is occurring in Microsoft's code running on a different thread and cannot be caught from within your code. (It will still be seen by any "last chance" exception handler you have bound to the UnhandledException event on the AppDomain.)
There seem to be two basic workaround styles in the linked document. In both instances, after opening the port you store a reference to the BaseStream instance for the open port. One workaround then suppresses garbage collection on that base stream. The other explicitly calls Close on the base stream, capturing any exceptions thrown during that operation, before calling Close on the SerialPort.
EDIT: For what it's worth, under the .NET framework V4.5, it appears that none of the documented workarounds on the Microsoft Connect site fully resolve the problem although they may be reducing the frequency with which it occurs. :-(
I had the same error when I used a thread to read from a SerialPort. Calling Interrupt on the thread occasionally caused the uncatchable ObjectDisposedException. After hours of debugging and carefully reading this:
https://blogs.msdn.microsoft.com/bclteam/2006/10/10/top-5-serialport-tips-kim-hamilton/
I realized that the problem is just this:
NET 2.0 (and above) isn’t letting you get away with some things, such as attempting to cancel a SerialPort read by interrupting the thread accessing the SerialPort.
So before you call Thread.Interrupt() you have to close the COM... This will cause a catchable exception on the ReadByte operation.
Or you may use the ReadTimeout property on the SerialPort to avoid using a thread just to have a timeout.
I would like to post my case in which I had a similar issue trying to read from a serial port (virtual com driven by a Moxa RS232 to ethernet).
Since I did have no chance to catch the ObjectDisposedException, the only solution was to increase the ReadTimeout property which was originally set to -1 (continuous reading).
Setting the ReadTimeout to 100 millis solved this issue in my case.
EDIT
It is not the definitive solution: it can happen that if you close the application during a read attempt you can get the same uncatchable exception.
My final solution is to kill the process of the application directly in the FormClosing event :
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
Process p = Process.GetCurrentProcess();
p.Kill();
}
Please take a look at this:
https://github.com/jcurl/SerialPortStream
I replaced System.IO.Ports with RJPC.IO.Ports, fixed up a couple parameter differences in the initialization, and all the problems went away with this issue.

C# Error on Close

When I close my C# application, I am getting the a windows sound that indicates an error. However, when I debug through the close process, I get all the way back up into the Program class...
It gets past Application.Run(..), exits the static void Main() function, and then makes the error noise.
Other than the noise there is nothing indicative of an error. I don't even know where to begin looking! Any ideas?
One thing that you could to in order to maybe get some information is to hook up event listeners for the AppDomain.UnhandledException and Application.ThreadException events. It's a long shot, but may provide some info. You could add the following in the beginning of the Main function to set them up, and have them show any exception info in a message box:
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(delegate(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show(e.ExceptionObject.ToString());
});
Application.ThreadException += new ThreadExceptionEventHandler(delegate(object sender, ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.ToString());
});
// run your app
}
It only happens when you close your app or does it happen when you close any app?
My first thought would be that someone changed your windows sound scheme and set the close program sound to mess with you :).
Something is going wrong in the cleanup, that could be very hard to find. There are two ways to attack this:
Enhance the chances of detecting it while you're still in control (in Main) by wrapping everything in your Main in a try/catch and add some code after the Application.Run to get as much of the cleanup going as possible. A few things I can think of:
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
GC.Collect();
GC.WaitForPendingFinalizers();
Collect at least 2 times, maybe more. In the same spirit, add a few Application.DoEvents() in the OnClosing of the MainForm.
The other approach is more dependent on your code, to take a stab in the dark: look for all static fields/properties you can set to null and Disposable objects you can Dispose deterministically on Exit.
And all this in combination with Fredrik Mörks suggestion for the UnhandledException event.
Do you have any code that raises custom events? Could these processes still be running when the app tries to close in real-time?
Do you have any custom Dispose code that could be running at time of close?

Categories