Setting system time of ROOTED phone
Asked Answered
S

2

22

I am currently trying to set Android system time in software. Yes, I know that many people tried it - and failed like I do now. :-)

But I also know that it is possible to set Android system time on ROOTED phones. I have testet an app called ClockSync which does exaclty that.

So what I want is find out how to set system time on ROOTED devices. Please do not say it is not possible. :-)

What I tried so far is setting the following permissions:

<uses-permission android:name="android.permission.SET_TIME_ZONE"/>
<uses-permission android:name="android.permission.SET_TIME"/>

And then in my code:

AlarmManager a = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
long current_time_millies = System.currentTimeMillis();
try {
    a.setTime((long)current_time_millies+10000);
} catch (Exception e) {
// Why is this exception thrown?
}

But I always get the following exception:

java.lang.SecurityException: setTime: Neither user 10054 nor current process has android.permission.SET_TIME.

I am testing it on the same device where ClockSync works perfectly. So - what am I doing wrong? Or better: Can you provide tested code that works?

Selfridge answered 5/1, 2012 at 7:33 Comment(0)
T
56

UPDATE: This method no longer works with the recent Android versions. The only other way that I'm aware of is to use the date command to set time. Note that command format may be different depending on the Android version and on the third-party tools installed (BusyBox version of date doesn't support time zones).

  // Android 6 and later default date format is "MMDDhhmm[[CC]YY][.ss]", that's (2 digits each)
  // month, day, hour (0-23), and minute. Optionally century, year, and second.
private static final SimpleDateFormat setDateFormat = new SimpleDateFormat("MMddHHmmyyyy.ss", Locale.US);

  // Standard Android date format: yyyymmdd.[[[hh]mm]ss]
  // https://mcmap.net/q/587073/-set-the-date-from-a-shell-on-android
private static final SimpleDateFormat setDateFormat = new SimpleDateFormat("yyyyMMdd.HHmmss", Locale.US);

  // BusyBox date format:
  // [[[[[YY]YY]MM]DD]hh]mm[.ss]
  // but recent versions also accept MMDDhhmm[[YY]YY][.ss]
private static final SimpleDateFormat bbSetDateFormat = new SimpleDateFormat("yyyyMMddHHmm.ss", Locale.US);

First of all, I'm the developer of ClockSync and I know something about setting time on Android.

I'm afraid the answer provided by Violet Giraffe is not correct. The problem is that normal user application cannot gain access to SET_TIME permission. This permission can be used only by system applications that are installed as a part of the ROM or are signed with the same key as the ROM itself (depends on the vendor). One of the applications that is using this approach is NTPc. It's signed with the AOSP key and can be installed on the AOSP based Android ROMs, such as CyanogenMod. Note that Google has banned AOSP keys from Market recently and the author will never be able to update his application. NTPc cannot be installed on regular ROMs used on most of the phones.

If you need the details, make sure to read the comments for the famous issue 4581: Allow user apps to set the system time. Note that the issue was Declined by Google with the following comment:

Hi, it is by design that applications can not change the time. There are many subtle aspects of security that can rely on the current time, such as certificate expiration, license management, etc. We do not want to allow third party applications to globally disrupt the system in this way.


How to set time on a rooted device:

What ClockSync does to set time is changing the permission of the /dev/alarm device. Essentially, it runs chmod 666 /dev/alarm in the root shell. Once this device has write permissions for all the users, SystemClock.setCurrentTimeMillis(...) call will succeed. Some applications use another approach, they run date command in the root shell with appropriate arguments, however it's error prone and is less accurate because superuser shell and command execution can take several seconds. An example of such application is Sytrant.

By default ClockSync sets 666 permission only if /dev/alarm is not already writable. This saves CPU/battery because su/Superuser.apk execution is relatively expensive. If you worry about security, there is Restore Permission option that will make the alarm device permission 664 after setting time.

For easier root shell access from the application I'm using my own helper class: ShellInterface. Another option is to use the RootTools library.

Here is the sample code based on the ShellInterface class:

  public void setTime(long time) {
    if (ShellInterface.isSuAvailable()) {
      ShellInterface.runCommand("chmod 666 /dev/alarm");
      SystemClock.setCurrentTimeMillis(time);
      ShellInterface.runCommand("chmod 664 /dev/alarm");
    }
  }

Feel free to check other Android issues related to setting time:


If you need precise time in the application without using root and changing system time, you can have your own timers, for example based on Joda Time. You can get the time from NTP servers using NTP client from the Apache commons-net library.

Tyre answered 6/1, 2012 at 1:0 Comment(9)
I've got /dev/alarm set up with 666 and am calling setCurrentTimeMillis, but it always returns falseGinglymus
@Ginglymus it can happen on the latest Samsung firmwares with KNOX (SELinux) enabled. The only way to overcome it is to use the date command line call as suggested by @Karan. date command doesn't support milliseconds, so I suggest that you align the command call with the second start using the timer based on the atomic time.Tyre
I see, right now I'm having the issue on a cubieboard, I'll ask the engineers if they did something to block it. meanwhile I'll follow your suggestion thnxGinglymus
I might suggest using a try/finally pattern here, to ensure that the permission is reverted even if an exception occurs between the two commands actually getting executed within the shell. Furthermore, I'd argue that instead of hard-coding the 664, the original permission should be queried in case the default changes at some point. Finally, it's worth noting that this changes the permission system-wide, allowing other applications to change the time with a race condition - this isn't particularly dangerous, it's just worth knowing about.Dovev
FYI, this approach worked for me up until the new Lollipop permission model. I'm unable to set the date/time this way anymore.Wenger
On Lollipop and Marshmallow I had to switch to making a root call to "date", only the usage included doesn't/didn't support the -s option. So I switched to "date mmddHHmmYYYY.ss". Note that the usage is not the same as what everyone else has reported.Wenger
the setcurrenttimemillis gives java.lang.SecurityException now, even with the chmod command.Waechter
@TomásRodrigues yes, it has changed in 5.0 or 6.0, now the only way to set time is by using the date command.Tyre
@Tyre The ClockSync is an amazing app, I've been using it for so many years! I'd like to integrate the same functionality of ClockSync into my project, any chance you'd open-source ClockSync?Grimbald
W
9

you can set system Date and time on rooted device like this

public void setDate()
    {
        try {
            Process process = Runtime.getRuntime().exec("su");
        DataOutputStream os = new DataOutputStream(process.getOutputStream());
            os.writeBytes("date -s 20120419.024012; \n");
        } catch (Exception e) {
            Log.d(TAG,"error=="+e.toString());
            e.printStackTrace();
        }
    } 
Waterfall answered 17/6, 2012 at 9:29 Comment(2)
It's poor alternative as it will invoke shell every time you need to set the clock, date command will take some time to execute, therefore less precision, also date command on some devices uses different format and will not work.Tyre
it is working for rooted device. Can some help me to make this functionality for system app?Popover

© 2022 - 2024 — McMap. All rights reserved.