Avoid app throttling when Electron is in background - electron

Consider the following example:
setInterval(function()
{
console.log(new Date());
});
If I run it with electron example.js under OS X, it opens up an icon in my dockbar and starts printing out the time on the console. If the app is not focused, however, after a while it starts throttling.
I looked around and found that this is due to OS X power saving strategy. Now, what if I needed it to keep working in background? My app will be a daemon doing a little bit of something every now and then, and I can't have my users blankly staring at my app for ages.
I found out here that I can do
electron.powerSaveBlocker.start('prevent-app-suspension');
Which actually fixes my problem. This however, is quite invasive, since as far as my understanding goes it prevents the system from sleeping at all! I don't need this much, I would just need my app to do something when the computer is active and online without forcing it to stay awake forever.
Isn't there anything in the middle, between having my users keeping the app continuously in the foreground, and making their computer sleepless forever?

As per the current docs:
Note: prevent-display-sleep has higher precedence over
prevent-app-suspension. Only the highest precedence type takes effect.
In other words, prevent-display-sleep always takes precedence over
prevent-app-suspension.
For example, an API calling A requests for prevent-app-suspension, and
another calling B requests for prevent-display-sleep.
prevent-display-sleep will be used until B stops its request. After
that, prevent-app-suspension is used.
What this means is that setting prevent-app-suspension to on, will still allow the system to sleep, and simply does what you desire it to. You can however run the function twice, passing both flags, turning both options on. However, as the docs above say, if both are set to on, then the system will not sleep until that flag has been removed.

Related

setInterval Stops After An Hour With Electron

Hoping someone can point me in the right direction here. My electron app needs to perform an API call every 10 minutes or so. I currently do this using a setInterval loop in the renderer process that fires every 10 minutes.
It generally works fine, for a few hours before it seems to just stop firing. I have several processes that clear and restart the setInterval to try and counteract the problem, but nothing seems to work.
The app opens new browser windows and displays content, which mean the main window may not be in focus all the time, which I suspect may have something to do with it.
I have tried adding
powerSaveBlocker.start("prevent-display-sleep");
powerSaveBlocker.start("prevent-app-suspension");
to my main electron js script, but it doesn't seem to have an effect. The problem is mostly being displayed on Windows machines. I'm not entirely sure if it happens on Mac or Linux.
So my question, is there any reason why this would be happening that intervals just die after a point? The powerSaveBlocker calls made sense to me, but they don't really seem to do anything.
Or is there a better way to have a background process running at intervals that can perform these API calls? I had looked at node-schedule but I'm not sure if it will fix this issue.
Answering my own question here with credit to #snwflk who pointed me in the right direction in a comment on the original post.
Whilst I have not been able to clarify with absolute certainty this solves the problem, I have also not seen the problem since. (It's not always 100% reproducible, and its difficult to test as it requires a machine, left alone for several hours, which may or may not display the problem).
I have however rolled the fix out to a few customers and their machines seem to still be online days later, which is a good sign.
So, the solution was to disable backgroundThrottling on the main BrowserWindow object (interval was running in the renderer processes)
Docs: https://electronjs.org/docs/api/browser-window#new-browserwindowoptions
An example
mainWindow = new BrowserWindow({
webPreferences: {
backgroundThrottling: false,
},
});
FYI be warned there have been a few bugs that prevented this setting from working, ie https://github.com/electron/electron/issues/20974 so be sure to update your electron version.
As far as I know intervals should keep running forever (the MDN page also doesn't mention anything).
If I understood correctly, your Electron app only does that API call? So it would be hard to tell the difference between the interval not triggering, and some other problem causing a freeze?
My guess would be you have an uncaught exception being thrown, or some other similar error or event. https://stackoverflow.com/a/43911292/841830 gives some suggestions of things to catch. https://github.com/sindresorhus/electron-unhandled says it can be used in both main and renderer processes to catch and report all problems.
Or is there a better way to have a background process running at intervals that can perform these API calls?
If you were on Linux, using cron to run a node script (or even just a wget or curl command) would be better than using an Electron app just for this. Task scheduler seems to be the windows equivalent of cron.

In iOS11, how to keep a background task running past 10 min?

My question involves keeping an app that monitors user interactions in the background, for example time spent in one or the app. The issue arises when you can not have a background process run for more than 10 min or violate Apple's sandbox restrictions. Since I am relatively new to the Apple API, and could not find a direct answer that didn't involve location services or VOIP (which are both interesting options, but my application will not be able to use either viably), I come to ask for options in which I can understand when another app opens, when it closes, when it fetches data, and when user holds phone in certain orientation (ie when people hold their phone at certain angles to read text and etc.) for certain amount of time.
The purpose of this analyzation is to predict an attention span for the user, so I need to be able to run in the background, as the user will not be using my app while it predicts attention span.
My thoughts on this are possibly accessing the system log, and somehow parse previous statements (I don't think sandbox will allow), but inevitably the iOS system will suspend my processes after some point unless I put a timer. There is also the option of having the system wake up my app via opportunistic fetching, but that won't be useful if I don't collect the data.
Keep in mind this is within IOS 11, so it is much more restrictive than previous iterations. I understand this may seem like a complex problem, but even a direction in which to head could be useful to me.
This solution might work, (not recommended since it drains the battery quicker).
Just update your current location, every 10 mins. It will reset the background thread timer.

Is it mandatory to call NSUserDefaults synchronize method?

Please, anyone, help me: Is calling NSUserDefaults's synchronize() method mandatory?. If I don't call it, what will happen? My application is working fine without it.
No.
Since iOS12, it isn't mandatory anymore.
Apple says:
This method is unnecessary and shouldn't be used.
You can find more information on iOS12 release note:
UserDefaults
NSUserDefaults has several bug fixes and improvements:
Removed synchronization requirements. It's no longer necessary to use synchronize, CFPreferencesAppSynchronize, or CFPreferencesSynchronize. These methods will be deprecated in a future version of the OS.
Now that you don't need to call these synchronization methods, the performance characteristics of NSUserDefaults and Preferences Utilities are slightly different: The time taken for enqueueing write operations is now paid by the writing thread, rather than by the next thread to call synchronize or do a read operation.
From the docs:
Because this method is automatically invoked at periodic intervals, use this method only if you cannot wait for the automatic synchronization (for example, if your application is about to exit) or if you want to update the user defaults to what is on disk even though you have not made any changes.
Meaning that if you kill the app right after something is written to the defaults without the periodic interval catching it, it will get lost. You probably did not kill the app right after a write event yet which is why your app seems to work fine so far.
Normally it works perfectly fine and you only have to use it in special cases, for example when the app will close directly after writing to NSUserDefaults. So you can simply add the synchronize method to the corresponding AppDelegate-method.
As others have said, you don't normally have to call synchronize at all.
Normally the system calls it for you so your defaults changes get written.
However, when working with Xcode it's pretty common to terminate your app by pressing command period or clicking the stop button. In that case it terminates the app without warning and your user defaults changes will quite likely not be written out, and will be lost.
This can be a good thing or a bad thing, depending on what you want. It's certainly confusing.
You can "fix" it by calling synchronize each time you make a change, or on some time interval. However that does slow your app down and increase it's power requirements (both by very small amounts.) If you are in a loop, writing changes to 10,000 server or Core Data records, and you change user defaults after each pass, then calling synchronize after each one might have a measurable effect on app speed and on battery life. In most cases you're not likely to notice the difference however.

Can I prevent an iOS user from changing the date and time?

I want to deploy managed iOS devices to employees of the company, and the app they will use will timestamp data that will be recorded locally, then forwarded. I need those timestamps to be correct, so I must prevent the user from adjusting the time on the device, recording a value, then resetting the date and time. Date and time will be configured to come from the network automatically, but the device may not have network connectivity at all times (otherwise I would just read network time every time a data value is recorded). I haven't seen an option in Apple Configurator to prevent changing the date and time, so is there some other way to do this?
You won't be able to prevent a user either changing their clock or just hitting your API directly as other commentators have posted. These are two separate issues and can be solved by having a local time that you control on the device and by generating a hashed key of what you send to the server.
Local Time on Device:
To start, make an API call when you start the app which sends back a timestamp from the server; this is your 'actual time'. Now store this on the device and run a timer which uses a phone uptime function (not mach_absolute_time() or CACurrentMediaTime() - these get weird when your phone is in standby mode) and a bit of math to increase that actual time every second. I've written an article on how I did this for one of my apps at (be sure to read the follow up as the original article used CACurrentMediaTime() but that has some bugs). You can periodically make that initial API call (i.e. if the phone goes into the background and comes back again) to make sure that everything is staying accurate but the time should always be correct so long as you don't restart the phone (which should prompt an API call when you next open the app to update the time).
Securing the API:
You now have a guaranteed* accurate time on your device but you still have an issue in that somebody could send the wrong time to your API directly (i.e. not from your device). To counteract this, I would use some form of salt/hash with the data you are sending similar to OAuth. For example, take all of the parameters you are sending, join them together and hash them with a salt only you know and send that generated key as an extra parameter. On your server, you know the hash you are using and the salt so you can rebuild that key and check it with the one that was sent; if they don't match, somebody is trying to play with your timestamp.
*Caveat: A skilled attacked could hi-jack the connection so that any calls to example.com/api/timestamp come from a different machine they have set up which returns the time they want so that the phone is given the wrong time as the starting base. There are ways to prevent this (obfuscation, pairing it with other data, encryption) but that becomes a very open-ended question very quickly so best asked elsewhere. A combination of the above plus a monitor to notice weird times might be the best thing.
There doesn't appear to be any way to accomplish what you're asking for. There doesn't seem to be a way to stop the user from being able to change the time. But beyond that, even if you could prevent them from changing the time, they could let their device battery die, then plug it in and turn it on where they don't have a net connection, and their clock will be wrong until it has a chance to set itself over a network. So even preventing them from changing the time won't guarantee accuracy.
What you could do is require a network connection to record values, so that you can verify the time on a server. If you must allow it to work without a net connection, you could at least always log the current time when the app is brought up and note if the time ever seems to go backwards. You'll know something is up if the timestamp suddenly is earlier than the previous timestamp. You could also do this check perhaps only when they try to record a value. If they record a value that has a timestamp earlier than any previous recorded value, you could reject it, or log the event so that the person can be questioned about it at a later time.
This is also one of those cases where maybe you just have to trust the user not to do this, because there doesn't seem to be a perfect solution to this.
The first thing to note is that the user will always be able to forge messages to your server in order to create incorrect records.
But there are some useful things you can use to at least notice problems. Most of the time the best way to secure this kind of system is to focus on detection, and then publicly discipline anyone who has gone out of their way to circumvent policy. Strong locks are meaningless unless there's a cop who's eventually going to show up and stop you.
Of course you should first assume that any time mistakes are accidental. But just publicly "noticing" that someone's device seems to be "misbehaving" is often enough to make bad behaviors go away.
So what can you do? The first thing is to note the timestamps of things when they show up at the server. Timestamps should always move forward in time. So if you've already seen records from a device for Monday, you should not later receive records for the previous Sunday. The same should be true for your app. You can keep track of when you are terminated in NSUserDefaults (as well as posting this information to the server). You should not generally wake up in the past. If you do, complain to your server.
Watch for UIApplicationSignificantTimeChangeNotification. I believe you'll receive it if the time is manually changed (you'll receive it in several other cases as well, most of them benign). Watch for time moving significantly backwards. Complain to your server.
Pay attention to mach_absolute_time(). This is the time since the device was booted and is not otherwise modifiable by the user without jailbreaking. It's useful for distinguishing between reboots and other events. It's in a weird time unit, but it can be converted to human time as described in QA1398. If the mach time difference is more than an hour greater than the wall clock time, something is weird (DST changes can cause 1 hour). Complain to your sever.
All of these things could be benign. A human will need to investigate and make a decision.
None of these things will ensure that your records are correct if there is a dedicated and skilled attacker involved. As I said, a dedicated and skilled attacker could just send you fake messages. But these things, coupled with monitoring and disciplinary action, make it dangerous for insiders to even experiment with how to beat the system.
You cannot prevent the user from changing time.
Even the time of an Location is adjusted by Apple, and not a real GPS time.
You could look at mach kernel time, which is a relative time.
Compare that to the time when having last network connection.
But this all sounds not reliable.

how to use GANTracker for long running iOS apps, including background audio

My App is typically run overnight as a baby monitor, either as foreground app, or with background audio running.
Goals:
Track total app startups ie. active user count.
Track total usage time in foreground vs background and total session time.
Track various page-views if they navigate the settings screens.
As recommended, I start the tracker in didFinishLaunchingWithOptions, and track my first ViewController as my first 'page-view'. My App might stay on this page then for the next 8 hours...
A couple of issues then appear:
When do I call stopTracker and what does it do? I'm hoping that it terminates the tracking session. But since google kindly hid their code in a static lib, I have no idea what's going on under the covers, and the .h doesn't say much. First instinct is to put stopTracker in applicationWillResignActive however, if the user decides to enable background audio my app is still running...
Next I read that a session can timeout after 30mins with no new pageviews, or at midnight. I could set a repeating timer to send the same page-view every 20mins, that should keep my session alive, at least until midnight, but then my page views are going to be much larger? unless it's smart enough to know I'm on the same page with every call. google analytics blog
[Update: each call seems to be counted as a new pageview, and numbers are thus skewed, so still an issue how to handle this]
If my timer above runs past midnight and the session has expired, I'm going to end up with a new session and double the actual active user count?
If I do call stopTracker in applicationWillResignActive, will the next call to track a page-view restart the tracker? or do I need to call startTrackerWithAccountID again?
If instead I start the tracker in applicationDidBecomeActive, I lose the session that might have been running in the background.
[update: this seems to be the best approach so far, but testing is very slow due to time lag on analytics reports, I will report back soon]
PS EasyTracker doesn't seem to handle this any better.
I got this working by using a pageview called 'Backgrounded', and when the user has selected no background functionality, then instead the app is calling stopTracker. I see multiple hits, with an average session of 20mins, but i can multiple pageview by time to see total time for goal 2. I found two solutions for goal one, events (which were not exposed in easy tracker), and also in my applicationDidBecomeActive (if it's not a restore of backgrounded app) then i track a pageview for AppStarted. I ended up wrapping the whole thing in a utility class and rolled it into a couple of my apps, so will be interesting too see the results. If anyone else tries this, you might want to think about using the custom variables too. I added my app version to this, so I can also monitor how many users are migrating to the latest app releases.

Resources