2

I'm trying to detect if an Android device has rebooted since the last time a preference value is set. Ideally, I'd like to do it without the android.permission.RECEIVE_BOOT_COMPLETED permission.

One way I'm thinking about doing this is storing another preference value that contains some sort of session ID. When I update the preference value in question, I'd update the session value as well. When I check the value in the preference for the session value, if it equals the current session value then there has not been a reboot. If the current session value is different than what's saved, then there's been a reboot. Unfortunately, I've been digging through the docs for quite some time now trying to find a session value, and I can't find anything.

I'd like help with one of two things. If you can provide where I could find a value of something similar to a session ID or a boot ID, then I'll use my algorithm. Alternatively, I'd be open to another algorithm to solve the problem. Thank you so much!

Michael Marvick
  • 521
  • 4
  • 15
  • 3
    Did you try `SystemClock.elapsedRealtime();`? – Raptor Dec 19 '14 at 08:29
  • 1
    Why don't you want to listen for boot completed? – psyren89 Dec 19 '14 at 08:31
  • Unfortunately, I don't think `SystemClock.elapsedRealtime()` will give me what I want. It gives the time since last boot. If I get a time of 3000000 millis since the last time boot, and the value I saved before was at 1000000 millis, I don't know if 2000000 millis have gone by, or if the phone has been rebooted and another 3000000 millis have gone by. – Michael Marvick Dec 19 '14 at 08:32
  • 1
    @Raptor, elapsedRealtime will return the time since the system was booted, but how can we use that to find whether the device was rebooted or not. Can you shed some light there, i cant think of a way using the elapsedRealtime – Shiv Dec 19 '14 at 08:33
  • @psyren89, I'm just trying to cut down on permissions where I can. In my opinion, the fewer permissions a user has to entrust to an app the better, especially if there's a way to do things without the permission. Right now I am using the boot permission and just resetting the preference value on boot, but I think there must be a better way. – Michael Marvick Dec 19 '14 at 08:35
  • 1
    @Shiv As mentioned in the question, the App will set a preference value (a date?). By comparing the date and current date, as well as the up time, we can determine the phone has been rebooted or not. – Raptor Dec 19 '14 at 08:38
  • 2
    @Raptor If the system clock changes for some reason (e.g. it was out of sync with the network time and gets updated by the carrier), this could cause an issue. It's probably not something that would be an issue often, but I'd rather not risk it unless I have to. – Michael Marvick Dec 19 '14 at 08:41
  • 1
    Then in this case, you can save another preference value, which is the difference between device's clock versus world clock (via NTP) – Raptor Dec 19 '14 at 08:48
  • Can you explain how that would help? I want to believe you, but I'm not following. – Michael Marvick Dec 19 '14 at 09:09
  • Going by time is a terrible way to determine whether the phone has been rebooted. User changes time? False positive. Daylight savings changes? False positive. Phone syncs time with carrier/time server? False positive. Rather than trying to hack in a shaky solution, just go with the easiest and simplest solution, and explain it to the user. – psyren89 Jan 05 '15 at 01:41
  • One could avoid the false positives by listening to ACTION_TIME_CHANGED perhaps. – Alexander Pruss Sep 15 '19 at 13:20

2 Answers2

4

This is mad old, but I think I have a good solution that doesn't require any services to run or any special background process.

Simply save the times to persistent memory such as shared preferences. This can be performed at any reference time you need. For me, it's when starting a chronometer so that it can persist even after a reboot. Chronometers relate only to SystemClock.elapsedRealtime(), which is the time since last boot, so you can't use System.currentTimeMillis(), which is the total time since the Unix Epoch (00:00:00 UTC on 1 January 1970).

If you wanted to check if the phone was rebooted only at application start, then add this to your onCreate.

    //Create a SharedPreferences
    SharedPreferences savedKeys = getApplicationContext().getSharedPreferences("MyPref", 0);
    SharedPreferences.Editor editor = savedKeys.edit();
    
    if (((System.currentTimeMillis() - SystemClock.elapsedRealtime())-(savedKeys.getLong("key_oldDelta", 0)))>100) {
    
    //Run code here or set a boolean to true for system reboot.
    
    }
    
    //Save the new values.
    
    editor.putLong("key_oldDelta", (System.currentTimeMillis() - SystemClock.elapsedRealtime()));
    editor.commit();

The following part of the code will get the delta (difference) of the current Unix time and system time since last boot: (System.currentTimeMillis() - SystemClock.elapsedRealtime())

If the system rebooted, those numbers will be larger and smaller respectively compared to what they were before rebooting.

Example: you save times at system time = 100 and Unix time = 1000. You reboot after 450 and restart the app after another 50. 500 has now passed since you recorded the values. They are now 10 and 1500.

New delta: 1500-10=1490

Old delta: 1000-100=900

Delta of deltas: 1490-900=590

The last number will always be higher after a reboot. It doesn't matter how long it's been since the reboot. The difference can only get higher because one number (Unix time) is constantly moving forward and the other is constantly being reset to zero at reboot. My example uses very small numbers to make it easy to understand, but remember the real numbers are in milliseconds, and a fair amount of those have passed since 1970. That's why my code says <100 at the end of the if statement. That gives the app 100 milliseconds to run the math. In reality, it takes more like 1 millisecond, but there's no way a phone will reboot in less than 100, so it's a safe value.

swordguy8
  • 167
  • 1
  • 10
1

Yes you can do that using Application class and the Non-Static broadcast Receiver ACTION_SHUTDOWN. The Application class got started in two cases

  1. Android Device Boot
  2. Your Application Starts after it was "Force-Close" it.

When ACTION_SHUTDOWN received use your application Shared-preferences or database to save a boolean shutdown = true when application class starts check this boolean. If it is true then the device is booting , else the user forced your app to stop.

To get more info you can read the following post that I wrote and try the code example in which, I added

  1. Application Class
  2. Boot Broadcast Receiver (To Show the difference and that both starts)
  3. Shutdown broadcast receiver that is register in the Application calss
ahmedibrahim085
  • 365
  • 5
  • 11
  • One scenario this doesn't cover is if the phone dies and is then turned back on again. For example, the user drops it or takes the battery out, which causes it to power off instantly. Once the phone is turned back on, your app won't know that it happened. – Sam Oct 07 '17 at 03:31
  • @ahmedibrahim085 unfortunately link is dead( – Acuna Jun 19 '19 at 18:03
  • @Acuna the link is active now – ahmedibrahim085 Jul 31 '19 at 16:29
  • Do you have a reference where it says that the Application class gets started on "Android Device Boot"? Are you saying that when Android boots up it starts every application that is installed on the device? That sounds very suspicious. – frezq Jun 14 '22 at 10:15