23

I'm developing an android application and hit the problem with determining system first boot up time. I mean i need to measure how much time already passed from device first boot up.

I know about solution with listening for ACTION_BOOT_COMPLETED and save anything in SharedPreferences, but i need another solution, because this one does not work for some cases. Maybe there is any system property?

Use case (excerpt from discussion)

  1. The filename of each file I receive from server includes a timestamp taken from System.currentMillis()
  2. I compare those timestamps in order to determine, which file the most current one is.
  3. Now, the user changes system time a few months ahead.
  4. I am still able to determine the most current file downloaded after user changed system time.
  5. Now, the user changes time back to original setting.
  6. The file downloaded on step 4 always wins when comparing timestamps.

The silver bullet to solve this problem would be a timestamp that counts seconds since first boot (after factory reset). Just like SystemClock.elapsedRealtime() but without reset after each boot. Unfortunately, the answers so far tell us, that this silver bullet doesn't exist.

However, many answers show a great variety of options how to tackle that problem. OneWorld123 commented each answer, how that suited his needs.

Community
  • 1
  • 1
user2857033
  • 339
  • 4
  • 6
  • so, why old answer does not satisfey you? – hasan Jan 30 '16 at 14:33
  • 2
    @hasan83 ozbeks answer does not cover the fact "first boot". See description of my bounty. – OneWorld Feb 01 '16 at 13:40
  • The System clock (`System.currentMillis()`) which behaves like a wall clock can't be a solution as well as file timestamps which are created with that very system clock. I need a timestamp that never gets changed. Almost like the `SystemClock.elapsedRealtime() `, just since the first time the device came alive. – OneWorld Feb 02 '16 at 07:28
  • 2
    @OneWorld, I'm afraid that I don't have a more specific solution for this, but something you could investigate is looking at timestamps of files / directories on the external SD card - For example the directory `/sdcard/Android/` is created by the Android system (On first boot I guess ?), so you could look at the timestamp on it or on the files in it or in other system-created directories to determine the time the date / time the device was first booted (as long as the clock was correct during the first boot). Unfortunately I have no idea if this works. – JonasCz Feb 02 '16 at 16:39
  • 1
    @JonasCz _"...on the external SD card..."_ What if a device doesn't have one on its first boot? What if an external SD card would be firstly inserted some years after the first boot? – Onik Feb 02 '16 at 23:25
  • That's why I said that I have no idea if it works. However, most devices also have built in, non-removeable storage, on which these directories are created, and which could be used similarly. (That's actually what I meant, the internal shared storage, not the external SD card, that was a typo). (@Onik). – JonasCz Feb 03 '16 at 09:50
  • 1
    @OneWorld why have you updated initial question with use case ? The answer is good, but that was not my use case. – user2857033 Feb 04 '16 at 01:09
  • Initially I thought that the answer to your question solves my problem. That's why I started the bounty rather than asking my own question since I did not want to duplicate it. Meanwhile it turned out that our requirements could differ which is still hard to detect since you do not remember your actual requirements as you posted on your comment. So, now I'm sorry for hijacking your question. I still decided to update the question, because this is the normal flow the SO reader expects. You get answers to questions. Maybe you just add your use case as well? That would keep the "flow" also – OneWorld Feb 04 '16 at 06:09

5 Answers5

13

Maybe there is any system property?

Not sure about system property, but there is SystemClock class which provides API's to get system uptime:

SystemClock.uptimeMillis() which

Returns milliseconds since boot, not counting time spent in deep sleep.

You may also use SystemClock.elapsedRealtime() which

Returns milliseconds since boot, including time spent in sleep.

Hope this helps.

ozbek
  • 20,085
  • 5
  • 54
  • 79
  • Thank you for your response, but maybe i didn't get it, does SystemClock.uptimeMillis() or SystemClock.elapsedRealtime() provide a time from the only first boot, or from last boot ? What I need, it is the time when, for example, the phone is new, you boot up it first time and run through setup. (another case is to do Factory Reset and it will bring the phone to initial state) – user2857033 Apr 25 '14 at 16:44
  • 4
    These provide time since last boot. – ozbek Apr 28 '14 at 01:10
9

In case one needs to know when was the first time an Android device was booted,

The easiest method would be to have an application

  • that is installed in the factory image
  • that is configured to run during boot
  • that logs the current date & time into a sharedPreference on its first run

Subsequently any other apps that need to determine the first boot time of the Android device can lookup the appropriate sharedPreference during the lifetime of the device. (or until the device is factory-reset; at which point the pre-installed app would write the new date&time into the shared preference after a reboot.)


However if it is not possible to an pre-install an application on the Android device, then a couple of potential workarounds would be:

1. As a root/superuser

one would lookup the time-stamp of a directory/file that is known to get created on the Android device during first-boot.

2. As a regular app,

a simple workaround method using standard Android APIs would be to check for the installation-time of an appropriate system package that is known to get installed during first-boot.

/* This returns the last time a package was installed */
PackageManager pm = context.getPackageManager();
PackageInfo pInfo = pm.getPackageInfo(<app-package-name>, 0);
return pInfo.firstInstallTime;

3. Alternately as a regular app,

if we can rely on a specific package being updated one-time during first-boot (and never again) we can check its update-time as follows:

/* This returns the last time a package was updated */
PackageManager pm = context.getPackageManager();
ApplicationInfo appInfo = pm.getApplicationInfo(<app-package-name>, 0);
String appFile = appInfo.sourceDir;
long installed = new File(appFile).lastModified();
TheCodeArtist
  • 19,131
  • 3
  • 60
  • 123
  • Rooting is no option. As for checking the install time: Sounded promising. However this uses the "wall clock time" which is changeable by the user. I have to compare it with System.currentMillis() - the method I don't want to use anymore. – OneWorld Feb 02 '16 at 07:23
  • @OneWorld Are you trying to implement some sort of DRM / secure-monitor / time-bound license that expires? A question here on SO explaining your actual use-case is likely to come-up with potential alternate designs rather than hack around with the first boot-time. – TheCodeArtist Feb 02 '16 at 11:54
  • See the discussion about my use case in this chat http://chat.stackoverflow.com/rooms/102325/discussion-between-ankitagrawal-and-oneworld – OneWorld Feb 02 '16 at 16:20
  • 1
    @oneworld right. The above chat discussion emphasises a need for monotonic counter. This you can implement by tagging a sequence-id to each instance of ur data. Have a single class/module that returns unique increasing integer every time you call it. This is separate from the wall-clock/timestamp. Every time your app is launched remember to initialise the counter to the "last largest sequence-id + 1" before you start returning ids. Any other reason you still need to know the time of first boot?... – TheCodeArtist Feb 02 '16 at 16:33
  • The "monotonic" counter would have been the cleanest approach to solve that problem. I am gonna implement that in future projects. – OneWorld Feb 03 '16 at 22:06
1

There are 3 methods in ANDROID SDK for these:-

public static long  elapsedRealtime ()

Added in API level 1

Returns milliseconds since boot, including time spent in sleep. Returns

elapsed milliseconds since boot.

public static long elapsedRealtimeNanos ()

Added in API level 17

Returns nanoseconds since boot, including time spent in sleep. Returns

elapsed nanoseconds since boot.

For @oneWorld Case:

You can use 2 approach:-

1) While writing check if some data has date above the current date then change the date of previous data to something less than current data and time, so it will return correct latest data.

2) You can store the time on server and retrieve time from there and set it.

JAAD
  • 12,171
  • 6
  • 34
  • 56
  • Pls read the description of my bounty. I discussed the methods you posted in your answer as not appropriate to solve the problem. – OneWorld Feb 02 '16 at 07:20
  • i answered for user2857033 and not your particular case, anyways i do have a solution for u – JAAD Feb 02 '16 at 07:23
  • do u need the time since user first booted and now?? – JAAD Feb 02 '16 at 07:24
  • For Time Since First Boot:- Whenever user switch off the phone store SystemClock.elapsedRealtime() and current date and time in a sharePreference and when is switch on check the current date and time and from sharedPreference to get the time when the phone was switch off and also u have first boot in SystemClock.elapsedRealtime(), so u can use this approach to get elasped time – JAAD Feb 02 '16 at 07:29
  • Storing the current elapsedRealtime when user switches off the phone would solve the problem. However, that is not a robust method. How to detect, the device is shutting down? What, if my app crashed before shut down? Also see my newest comment to the question. – OneWorld Feb 02 '16 at 07:33
  • You need to listen for the following intent action in your receiver: To make it compatible with some HTC (or other) devices which offer quick power-off feature, you need to include the following action too with in the same intent-filter: – JAAD Feb 02 '16 at 07:36
  • see it is a robust solution ,save it in shared preference in onREcieve of this event – JAAD Feb 02 '16 at 07:36
  • http://stackoverflow.com/questions/14133077/android-action-shutdown-broadcast-not-working/14133824#14133824 says, ACTION_SHUTDOWN can be only implemented using JAVA code not the manifest. Meaning that my app won't detect the shutdown if it crashed before. – OneWorld Feb 02 '16 at 07:47
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/102325/discussion-between-ankitagrawal-and-oneworld). – JAAD Feb 02 '16 at 07:47
  • Thanks for the discussion which determined my real requirements. I chose the 1st approach you offered (renaming files with future timestamp), because that was the fastest fix for my existing app. On future apps I would go with a monotonic counter for comparing (TheCodeArtist) and an additional timestamp with time taken from server (your 2nd approach) to show the time to the user. – OneWorld Feb 03 '16 at 22:14
1

If we stick to the SDK, I don't know of a method providing this information directly; but there might be a way to derive this information from other resources. Again, if we stick to SDK, one "rather reliable" option is to use application usage statistics which Android OS saves during device lifetime. That is - the timestamp for a first "usage stats" ever saved.

This, though, clearly does not provide an exact "first boot time" timestamp, so it depends on whether some approximation is OK in your case. Generally, the problem with usage statistics is that Andriod aggregates it for periods distant in time - so, the older device is - the less accurate the date is. For example, for my current phone, first booted on Dec. 3 2014, aggregated usage statistics is first recorded on Dec. 21 2014 currently (for the record - it is Feb. 2016 by the time of this writing). (I have to admit though that I don't know how Android OS schedules the aggregation, and if it is just scheduled on Dec. 21 every year, or if it is indeed somewhat close to the first device usage - I guess it is easy to check with any other device.)

Following is some sample code showing UsageStatsManager usage, but it certainly would need more adjustments in order to address the fact of having more precision for more recent periods:

UsageStatsManager usageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
Calendar year2013 = Calendar.getInstance(); year2013.set(2013, 0, 1);
List<UsageStats> stats = usageStatsManager.queryUsageStats(
    UsageStatsManager.INTERVAL_YEARLY, // or adjust for "younger" devices to get more precision - so, you'll probably need several queries
    year2013.getTimeMillis(),
    Calendar.getInstance().getTimeInMillis());
// now, first element in stats (if it is present at all) will point to the "earliest" statistics saved *for this interval* (yearly in this case)
// use UsageStats.getFirstTimeStamp() to get first known/saved usage

Note also that, as documented in the SDK, UsageStatsManager requires PACKAGE_USAGE_STATS system-level permission, so you'll need to make user accept it in Settings first:

Intent settingsIntent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(settingsIntent);

Hope it helps!

Timur
  • 10,392
  • 7
  • 44
  • 62
1

According to your discussion on: https://chat.stackoverflow.com/rooms/102325/discussion-between-ankitagrawal-and-oneworld , you need a monotonic counter to uniquely identify a dataset.

For that you can easily set a SharedPreference and increment this value every time you need a new identifier. When you require to know which is the newest file, just compare the identifiers. If it is an issue that this counter gets reset once the app is uninstalled, please refer to: In android is there any way to preserve SharedPreferences after an uninstall

A different approach that could be used, is to request a timestamp from an outside server.

Hope it helps ;-)

Community
  • 1
  • 1
lucianohgo
  • 319
  • 1
  • 9
  • that discussion is about different problem. I was asking about timestamp after full reset, so in that case non of the shared preferences from any app in user space would be saved. – user2857033 Feb 03 '16 at 10:28
  • Okay, but you can save this preferences in the cloud, you can get them back through a back up. Or you require the app to be completely offline? – lucianohgo Feb 03 '16 at 11:59
  • Just to mention, I'm not on that project anymore :) I don't remember exactly what were the requirements, sorry. But i agree that this is one of the possible solutions. And I think we were planning to reduce app network communication to the minimum. – user2857033 Feb 03 '16 at 17:51