code running from alarm manager dying after 1 minute - c#

I have some code that should take (roughly) 5 minutes to run. This code should run periodically, so I'm calling it using the built in AlarmManager.
Like this:
public void setAlarm(Context context)
{
AlarmManager am = (AlarmManager)context.GetSystemService(Context.AlarmService);
Intent i = new Intent(context, typeof(keyboardservice.alarmreciever));
PendingIntent pi = PendingIntent.GetBroadcast(context, 0, i, PendingIntentFlags.CancelCurrent);
am.SetRepeating(AlarmType.ElapsedRealtimeWakeup, 0, 1000 * 60 * 30, pi); // Millisec * Second * Minute
}
As you can see the code should run every 30 minutes.
AlarmService looks something like this :
[BroadcastReceiver(Enabled = true)]
public class alarmreciever : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Task.Delay(1000 * 300).Wait();
}
}
I've simplified the code above, but the result is the same the code dies after 1 minute (exactly), like there's some limit.
It doesn't matter if the screen is on or off.
What am I missing?

AlarmService looks something like this
That is not a Service. That is a BroadcastReceiver.
What am I missing?
First, your BroadcastReceiver is attempting to tie up the main application thread for five minutes. Even if that were possible, it would be a profoundly bad idea, as that means that your UI would be frozen during those five minutes. But, it is not possible, as a watchdog should terminate your work in the ANR timeout period (10-15 seconds for background work IIRC).
Second, in general, you cannot do anything in the background for more than a minute on Android 8.0+. There are exceptions, notably if you use JobScheduler, where you have ~10 minutes.
If you are sure that your work will be completed in less than 10 minutes, then if your minSdkVersion is 21 or higher, switch to JobScheduler. If your minSdkVersion is below 21, at least on those older devices, have your BroadcastReceiver start a JobIntentService, were you do your five minutes of work in onHandleWork().
Note that I do not know what of this has been Xamarin-ified, as I do not use Xamarin.

Solved with :
new Task(() =>
{
DoAction(context);
}).Start();

Related

Incorrect job interval when using HangFire

I have 2 simple jobers GetMenuJober and GetOrdersJober. All they do is printing message in console, RunJob method is similar in both classes:
public async Task RunJob()
{
Console.WriteLine($"{this.GetType().Name} has been started.");
}
I planned to start these workers in 5 seconds:
RecurringJob.AddOrUpdate<GetOrdersJober>(x => x.RunJob(), "0/5 * * * * *");
RecurringJob.AddOrUpdate<GetMenuJober>(x => x.RunJob(), "0/5 * * * * *");
And expected to see something like this in the console:
GetOrdersJober has been started.
GetMenuJober has been started.
GetOrdersJober has been started.
GetMenuJober has been started.
GetOrdersJober has been started.
GetMenuJober has been started.
The intervals between the launches of both are different, while they are not equal to 5 seconds, sometimes 30, sometimes more than a minute. Jobs run completely different. What did I miss ?
Moreover, even if I set cron expression as Cron.Minutely both jobs will run in absolutely random interval.

How to run functionality only sometimes in an Azure function

I have an Azure function with a trigger to make it run once every 15 minutes:
TimerTrigger("0 */15 * * * *", RunOnStartup =false)
Within this function, there is some functionality that I only want to run once per hour. I am currently checking the minute of the current time to see whether it should run or not. But as I understand it, Azure function triggers are not always precise (this is running on a consumption-based app service), so instead I am checking for a range of minutes.
int currentMinute = DateTime.Now.Minute;
bool extraFunctionality = (currentMinute >= 58 && currentMinute <= 2);
This seems like it will work; only running this functionality during the ":00" runs, once per hour. However, it looks like bad code to me, for a couple reasons:
The up to 2 minutes early and 2 minutes late number was chosen pretty much arbitrarily; I don't have a good idea of what sort of time span to use there.
It relies on using DateTime.Now which will return different results depending on server settings, even though I don't care about anything other than the current minute.
The code simply doesn't read like the intent is to get it to run once per hour.
Is there a better / more proper way to do this within Azure functions? Can I either get information from the TimerInfo parameter or the ExecutionContext parameter about which 15-minute trigger caused the function to run? Or can I have a separate TimerTrigger which runs once per hour, and then have different functionality based on which of the 2 timers caused the function to trigger? Or is there some way to have the TimerTrigger itself pass in a parameter telling me which 15-minute window it is in?
Or, is my code fine as-is; perhaps with some adjustment to the number of minutes I allow it to be off?
You could create two Azure Functions, one which runs at 15, 30, 45 minutes past the hour and another which runs on the hour. Then in each of these functions set a variable for if it's runnin on the hour.
[FunctionName("HourlyFunction")]
public static void RunHourly([TimerTrigger("0 0 15,30,45 * * *")]TimerInfo myTimer, ILogger log)
{
_myService.Run(true);
}
[FunctionName("FifteenMinuteFunction")]
public static void RunEveryFifteen([TimerTrigger("0 0 * * * *")]TimerInfo myTimer, ILogger log)
{
_myService.Run(false);
}
Then have a separate service which can be called by those functions:
public class MyService : IMyService
{
public async Task Run(bool isHourlyRun)
{
// Do work here
}
}
* I'm not sure those cron expressions are correct

I called timeBeginPeriod(1), but it didn't work

The Window's default precision for Thread.Sleep() is 15.625 ms (1000 / 64), i.e. if you call Thread.Sleep(1), the time elapsed is 15 ms or 16 ms. I want to improve the accuracy to 1 ms.
There's a function "timeBeginPeriod" which can change the accuracy. But I didn't get what I want. Here's my code:
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
public static extern void TimeBeginPeriod(int t);
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod")]
public static extern void TimeEndPeriod(int t);
TimeBeginPeriod(1);
var t1 = Environment.TickCount;
Thread.Sleep(1);
var t2 = Environment.TickCount;
Console.WriteLn(t2 - t1);
TimeEndPeriod(1);
What I expected is 1 or 2, but I got 15 or 16 actually.
Is there any code I missed?
Based on discussions in various forums, I have the suspicion that this feature was broken on Windows 10 for a while, but it appears to be fixed on my machine running Windows 10 version 2004. Without the call to timeBeginPeriod, the sleep timer has a resolution of ~15ms. After calling timeBeginPeriod(1), the sleep timer resolution goes down to 1..2 ms
Can others confirm this on an up-to-date Windows system?
Addendum 1: I just found https://stackoverflow.com/a/48011619/295690 which indicates that even though the feature might actually be repaired, there are good reasons to avoid it anyway.
Addendum 2: Even more insight from https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/ leads me to assume that it is not just a matter of the OS version. I could well imagine that certain power saving modes or hardware configurations prevent programs from increasing the system-wide tick frequency.
I have some update about this problem.
The accuracy of Environment.TickCount is about 16ms.It's not a high precision method. Actually by using DateTime, we can get more accurate elapse time even without using TimeBeginPeriod/TimeEndPeriod on Windows 10, Version 1903.
long t1 = Environment.TickCount;
DateTime dt1 = DateTime.Now;
Thread.Sleep(1);
DateTime dt2 = DateTime.Now;
long t2 = Environment.TickCount;
Console.WriteLine("DateTime Method: " + (dt2-dt1).TotalMilliseconds);
Console.WriteLine("TickCount Method: " + (t2 - t1));
DateTime Method: 2.0074
TickCount Method: 0

Post Oreo 8.0+ Action_User_Present Workaround?

I want to have my app open up every single time the device is unlocked. Effectively, I need a consistent replacement for ACTION_USER_PRESENT.
(NOTE THIS IS FOR AN INTERDISCIPLINARY, PEER-REVIEWED ACADEMIC STUDY STARTING SOON AND IS VITAL FOR THE STUDY'S SUCCESS)
Before the Oero 8.0 update, ACTION_USER_PRESENT was a perfect way to start up the android app each time the device was unlocked.
Unfortunately the work-arounds I've been trying to use are just not cutting it. Effectively I've assigned a myBroadastReceiver to attempt to run the app and PowerManager to see if the device is on or not. Depending on if the device is being used will impact if in the myBroadcastReceiver code will Initiate an Intent.
Problem 1) The broadcast receiver can only be assigned to run at minimum every 15 minutes. I need it to run every time the device unlocks.
Problem 2) Sometimes the broadcast receiver doesnt even try to run for hours at a time... as if the assigned 15 minute check is more of a loose suggestion and not an explicit command.
SOME CODE:
public class classMyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context contextOfReceive, Intent intentOfReceive) {
////////////////////////////////////////////////////////////////////////////////////////////
//This loads up the user selected settings choosen at the homepage of the application.
final SharedPreferences internalAppInformation = contextOfReceive.getSharedPreferences("userPreferences", Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = internalAppInformation.edit();
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
//Code used to determine 2 things
// 1) if the Device being used or inactive
// 2) if the activity has already been prompted earlier and therefore should be in the foreground of the device
PowerManager pm = (PowerManager) contextOfReceive.getSystemService(Context.POWER_SERVICE);
boolean booleanIsScreenOn = pm.isInteractive();
boolean booleanIsActivityUp = internalAppInformation.getBoolean("booleanIsActivityUp", false);
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
//If Screen is Off (i.e. the device is NOT BEING USED AT THE MOMENT)
//then this code should allow the Activity to Start
if ( (!booleanIsActivityUp)&&(!booleanIsScreenOn) ) {
//Initiates and Starts up the Intent PromptAndClose.class
editor.putBoolean("booleanIsActivityUp", true);
editor.commit();
editor.apply();
//THE REST OF THE CODE BELOW IS JUST CHOOSING AND
// INITIATING THE PROGRAM AND IS NOT PROBLEMATIC.
}
}
More detailed code can be provided if it will be helpful. I am worried that more code will result it too much clutter for the reader.
ADDITIONAL CODE TO DESCRIBE WHEN THE myBroadcastReceiver is Initiated.
public class Settings extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
////////////////////////////////////////////////////////////////////////////////////////////
//Sets up and starts the calendar (with the setAlarm method for re-occuring attempts to
//prompt the app to move to the foreground if the right conditions are met.
Calendar calendar = Calendar.getInstance();
//if(Build.VERSION.SDK_INT >= 23) {
Log.i("Calendar", "Set Calendar >=23");
calendar.set(
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH),
calendar.get(Calendar.HOUR),
calendar.get(Calendar.MINUTE),
30
);
setAlarm(calendar.getTimeInMillis());
int time = (int) calendar.getTimeInMillis();
String timeString = String.valueOf(time);
Log.i("TIME", "time: " + timeString);
}
private void setAlarm(long timeInMillis) {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, classMyBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
assert alarmManager != null;
//RTC-Fires the pending intent at the specified time but does not wake up the device.
//The shortest interval is INTERVAL_FIFTEEN_MINUTES.
alarmManager.setInexactRepeating(AlarmManager.RTC, timeInMillis,
AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent);
}
}
This code is present in the main activity of the application. The concept is that the first time the app is installed and ran, it will run this code and start and continuous loop of checking and displaying the app to the foreground of the device if the device is not being used. Once that intent is interacted with by the user and closed, the loop starts up again.
That is not going to work. Doze mode and app standby will make what you are trying to do very unreliable.
Try this: Create a foreground service. Start that foreground service when you need to start receiving this broadcast. In onCreate() of that service, call registerReceiver() register a receiver for ACTION_USER_PRESENT. So long as your service is running, you will receive the ACTION_USER_PRESENT broadcast as before.

Foreground services and repetitive tasks which need to be executed on time

I'm developing an app which basically performs some tasks on timer tick (in this case - searching for beacons) and sends results to the server. My goal was to create an app which does its job constantly in the background. Fortunately, I'm using logging all over the code, so when we started to test it we found that sometime later the timer's callback wasn't being called on time. There were some pauses which obviously had been caused by standby and doze mode. At that moment I was using a background service and System.Threading.Timer. Then, after some research, I rewrote the services to use Alarm Manager + Wake locks, but the pauses were still there. The next try was to make the service foreground and use it with a Handler to post delayed tasks and everything seemed to be fine while the device was connected to the computer. When the device is not connected to a charger those pauses are here again. The interesting thing is that we cannot actually predict this behavior. Sometimes it works perfectly fine and sometimes not. And this is really strange because the code to schedule it is pretty simple and straightforward:
...
private int scanThreadsCount = 0;
private Android.OS.Handler handler = new Android.OS.Handler();
private bool LocationInProgress
{
get { return Interlocked.CompareExchange(ref scanThreadsCount, 0, 0) != 0; }
}
public void ForceLocation()
{
if (!LocationInProgress) DoLocation();
}
private async void DoLocation()
{
Interlocked.Increment(ref scanThreadsCount);
Logger.Debug("Location is started");
try
{
// Location...
}
catch (Exception e)
{
Logger.Error(e, "Location cannot be performed due to an unexpected error");
}
finally
{
if (LocationInterval > 0)
{
# It's here. The location interval is 60 seconds
# and the service is running in the foreground!
# But in the screenshot we can see the delay which
# sometimes reaches 10 minutes or even more
handler.PostDelayed(ForceLocation, LocationInterval * 1000);
}
Logger.Debug("Location has been finished");
Interlocked.Decrement(ref scanThreadsCount);
}
}
...
Actually it can be ok, but I need that service to do its job strictly on time, but the callback is being called with a few seconds delay or a few minutes and that's not acceptable.
The Android documentation says that foreground services are not restricted by standby and doze mode, but I cannot really find the cause of that strange behavior. Why is the callback not being called on time? Where do these 10 minutes pauses come from? It's pretty frustrating because I cannot move further unless I have the robust basis. Does anybody know the reason of such a strange behavior or any suggestions how I can achieve the callback to be executed on time?
P.S. The current version of the app is here. I know, it's quite boring trying to figure out what is wrong with one's code, but there are only 3 files which have to do with that problem:
~/Services/BeaconService.cs
~/Services/BeaconServiceScanFunctionality.cs
~/Services/BeaconServiceSyncFunctionality.cs
The project was provided for those who would probably want to try it in action and figure it out by themselves.
Any help will be appreciated!
Thanks in advance

Categories

Resources