DeviceMonitor failure
ningma97 opened this issue · 7 comments
Hi,
I have been using SharpAdbClient with great pleasure. However, recently I notice that occasionally DeviceMonitor
would throw an exception and failed to detect new adb devices
07:34 E/AdbSocket: Got reply 'FAIL', diag='device offline'
Exception thrown: 'SharpAdbClient.Exceptions.AdbException' in SharpAdbClient.dll
Exception thrown: 'SharpAdbClient.Exceptions.AdbException' in SharpAdbClient.dll
Exception thrown: 'System.AggregateException' in mscorlib.dll
Exception thrown: 'SharpAdbClient.Exceptions.AdbException' in SharpAdbClient.dll
Exception thrown: 'SharpAdbClient.Exceptions.AdbException' in SharpAdbClient.dll
When this happens, I can see the device via adb
command line. I guess I can try to catch this exception and restart the monitor, but thought it might be better to understand what has caused the problem.
My code is simply below.
var result = AdbServer.Instance.StartServer(@"adb.exe", true);
adbMonitor = new DeviceMonitor(new AdbSocket(AdbServer.Instance.EndPoint));
adbMonitor.DeviceConnected += this.OnDeviceConnected;
adbMonitor.DeviceDisconnected += this.OnDeviceDisconnected;
adbMonitor.Start();
Did I do anything wrong?
Many thanks.
Ning
Hi Ning,
No, I don't think you did anything wrong, and I'm assuming it's a bug in our codebase that we'd better fix :)
It would help if you can share more information about the exceptions that are being thrown.
Is the exception being caught by your application code? If so, can you share the stack trace and the error message of the exceptions?
Thanks!
Thanks for your prompt reply!
The exception was thrown when a new device was connected and I was accessing the DeviceData
in the OnDeviceConnected
handler with AdbClient.Instance.ExecuteRemoteCommand()
.
As I said this exception does not occur all the time but I almost always get it if I plug/unplug my device for a few times (I waited a few seconds before plugging the device back in). When the exception occurs, I am able to execute the same command in the command line using adb shell
.
Some more information about the exception below. Let me know if you need any further information.
SharpAdbClient.Exceptions.AdbException occurred
AdbError=device offline
ConnectionReset=false
HResult=-2146233088
Message=An error occurred while reading a response from ADB: device offline
Source=SharpAdbClient
StackTrace:
at SharpAdbClient.AdbSocket.ReadAdbResponse()
InnerException:
The Call Stack before the exception is
SharpAdbClient.dll!SharpAdbClient.AdbSocket.ReadAdbResponse() Unknown
SharpAdbClient.dll!SharpAdbClient.AdbClient.SetDevice(SharpAdbClient.IAdbSocket socket, SharpAdbClient.DeviceData device) Unknown
SharpAdbClient.dll!SharpAdbClient.AdbClient.ExecuteRemoteCommandAsync(string command, SharpAdbClient.DeviceData device, SharpAdbClient.IShellOutputReceiver receiver, System.Threading.CancellationToken cancellationToken, int maxTimeToOutputResponse) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start<SharpAdbClient.AdbClient.<ExecuteRemoteCommandAsync>d__25>(ref SharpAdbClient.AdbClient.<ExecuteRemoteCommandAsync>d__25 stateMachine) Unknown
SharpAdbClient.dll!SharpAdbClient.AdbClient.ExecuteRemoteCommandAsync(string command, SharpAdbClient.DeviceData device, SharpAdbClient.IShellOutputReceiver receiver, System.Threading.CancellationToken cancellationToken, int maxTimeToOutputResponse) Unknown
SharpAdbClient.dll!SharpAdbClient.AdbClientExtensions.ExecuteRemoteCommand(SharpAdbClient.IAdbClient client, string command, SharpAdbClient.DeviceData device, SharpAdbClient.IShellOutputReceiver rcvr) Unknown
> TheiaCamera.exe!TheiaCamera.Form1.DeviceFileExists(SharpAdbClient.DeviceData device, string remotePath) Line 48 C#
TheiaCamera.exe!TheiaCamera.Form1.IsValidDevice(SharpAdbClient.DeviceData device) Line 41 C#
TheiaCamera.exe!TheiaCamera.Form1.OnDeviceConnected(object sender, SharpAdbClient.DeviceDataEventArgs e) Line 130 C#
SharpAdbClient.dll!SharpAdbClient.DeviceMonitor.OnDeviceConnected(SharpAdbClient.DeviceDataEventArgs e) Unknown
SharpAdbClient.dll!SharpAdbClient.DeviceMonitor.UpdateDevices(System.Collections.Generic.List<SharpAdbClient.DeviceData> devices) Unknown
SharpAdbClient.dll!SharpAdbClient.DeviceMonitor.ProcessIncomingDeviceData(string result) Unknown
SharpAdbClient.dll!SharpAdbClient.DeviceMonitor.DeviceMonitorLoopAsync(System.Threading.CancellationToken cancellationToken) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine) Unknown
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run() Unknown
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask) Unknown
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations() Unknown
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree() Unknown
mscorlib.dll!System.Threading.Tasks.Task<System.__Canon>.TrySetResult(System.__Canon result) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<string>.SetResult(string result) Unknown
SharpAdbClient.dll!SharpAdbClient.AdbSocket.ReadStringAsync(System.Threading.CancellationToken cancellationToken) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine) Unknown
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run() Unknown
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask) Unknown
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations() Unknown
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree() Unknown
mscorlib.dll!System.Threading.Tasks.Task<int>.TrySetResult(int result) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.SetResult(int result) Unknown
SharpAdbClient.dll!SharpAdbClient.AdbSocket.ReadAsync(byte[] data, int length, System.Threading.CancellationToken cancellationToken) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine) Unknown
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run() Unknown
mscorlib.dll!System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action action, bool allowInlining, ref System.Threading.Tasks.Task currentTask) Unknown
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations() Unknown
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree() Unknown
mscorlib.dll!System.Threading.Tasks.Task<int>.TrySetResult(int result) Unknown
mscorlib.dll!System.Threading.Tasks.TaskCompletionSource<int>.TrySetResult(int result) Unknown
SharpAdbClient.dll!SharpAdbClient.SocketExtensions.ReceiveAsync.AnonymousMethod__1(System.IAsyncResult iar) Unknown
System.dll!System.Net.LazyAsyncResult.Complete(System.IntPtr userToken) Unknown
System.dll!System.Net.ContextAwareResult.CompleteCallback(object state) Unknown
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Unknown
System.dll!System.Net.ContextAwareResult.Complete(System.IntPtr userToken) Unknown
System.dll!System.Net.LazyAsyncResult.ProtectedInvokeCallback(object result, System.IntPtr userToken) Unknown
System.dll!System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* nativeOverlapped) Unknown
mscorlib.dll!System.Threading._IOCompletionCallback.PerformIOCompletionCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* pOVERLAP) Unknown
Forgot to say that I am using the prerelease version 2.1.0-beta338...
Ok – this starts to make sense. Are you plugging & unplugging hour device really fast? It looks like your IsValidDevice method is still executing when you’ve disconnected the device, hence the exception.
It bubbles up because the DeviceMonitor raises the event, so if your code has an unhandled exception, the device monitor stops.
Could you wrap OnDeviceConnected in a try/catch block? That should fix it. On our side, we should make the device monitor more defensive – exceptions in event handlers should not cause the device monitor to stop.
I was playing with detection of device insertion using DeviceMonitor
, and was not plugging/unplugging the device really fast.
My IsValidDevice
method is used to detect if the newly inserted device is a specific type that I am interested in, and thus it was executed in OnDeviceConnected
which was triggered when I connected the device, ie. the exception was thrown when I've just connected the device.
I could catch it, but want to understand if I am doing something wrong.
- Is it possible to access the device in
OnDeviceConnected
? I notice if I set a break point inOnDeviceConnected
, therefore paused a bit before callingExecuteRemoteCommand
, I don't get the exception. It almost feels like occasionally the device was not ready before I calledExecuteRemoteCommand
inOnDeviceConnected
- In case of an exception, is there a proper way to reset things and try again? I ask because when the exception is thrown, and my program breaks, I can execute the same command using
adb shell
Thanks for the clarification! If I understand it correctly, what you're saying is that the device remains connected, and your assumption is that the event is raised before ExecuteRemoteCommand
can reliable execute?
That may make sense, you should be able to test it by just adding a Thread.Sleep
in your event handler and see if the issue goes away.
If it does, we have a timing issue - the event is fired too soon. The problem is, the DeviceMonitor
doesn't really do much, and it receives all its events from adb
. The same with ExecuteRemoteCommand
-- all it does is to invoke the same adb
command as adb shell
.
W.r.t. the exception, SharpAdbClient
doesn't keep much state to start with, so except for restarting the DeviceMonitor
there's not much you need to do to try again.
Yes the device remained plugged in when the exception was thrown. It certainly seems so... however the problem doesn't occur every time I plug in the device but comes after a few times.
I will try to pause the thread a little bit and see if it goes away.
Thanks for your help.