Today, we’ll explore the TrustedTime API, a new API introduced to ensure accurate and secure timekeeping in Android apps. It helps apps prevent time tampering, ensuring that system time remains reliable for critical operations.
Why TrustedTime API?
Time manipulation can lead to security vulnerabilities, affecting authentication mechanisms, digital signatures, and event logging. The TrustedTime API provides apps with a tamper-resistant time source that remains consistent even if the system clock is changed by the user.
How It Works
The TrustedTime API sources time from secure sources such as GPS, NTP (Network Time Protocol), and carrier networks. It provides a monotonic and verifiable timestamp that apps can use instead of relying solely on System.currentTimeMillis()
.
Add the Dependency
First, include the TrustedTime API dependency in your build.gradle
file:
implementation("com.google.android.gms:play-services-time:16.0.1")
This ensures your app can access the API via Google Play services.
Initialize TrustedTime Early
The TrustedTimeClient should be initialized early in your app’s lifecycle, preferably in the Application
class.
class MyApp : Application() {
private var trustedTimeClient: TrustedTimeClient? = null
override fun onCreate() {
super.onCreate()
TrustedTime.createClient(this)
.addOnSuccessListener { client -> trustedTimeClient = client }
.addOnFailureListener { exception ->
Log.e("TrustedTime", "Failed to create client", exception)
}
}
fun getTrustedTimeClient(): TrustedTimeClient? = trustedTimeClient
}
This initializes the TrustedTimeClient once and makes it available throughout the app.
Retrieve a Trusted Timestamp
Once initialized, you can fetch the current trusted time anywhere in your app. The API provides a secure timestamp that falls back to the system clock if no verified time is available.
val trustedTimeClient = (applicationContext as MyApp).getTrustedTimeClient()
val currentTimeMillis = trustedTimeClient?.computeCurrentUnixEpochMillis()
?: System.currentTimeMillis()
Log.d("TrustedTime", "Current Trusted Time: $currentTimeMillis")
Using TrustedTime in Activities
If you’re working within an Activity
or Fragment
, you can create a new TrustedTimeClient instance when needed:
class MainActivity : AppCompatActivity() {
private var trustedTimeClient: TrustedTimeClient? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
TrustedTime.createClient(this)
.addOnSuccessListener { client -> trustedTimeClient = client }
.addOnFailureListener { exception ->
Log.e("TrustedTime", "Failed to create client", exception)
}
}
private fun getCurrentTrustedTime(): Long? {
return trustedTimeClient?.computeCurrentUnixEpochMillis()
}
}
Using TrustedTime in Compose
If you need to access TrustedTimeClient in a Composable, you can use LaunchedEffect to fetch it in the background without blocking the UI.
@Composable
fun TrustedTimeScreen() {
val context = LocalContext.current.applicationContext as MyApp
var trustedTime by remember { mutableStateOf<Long?>(null) }
LaunchedEffect(Unit) {
trustedTime = context.getTrustedTimeClient()?.computeCurrentUnixEpochMillis()
}
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
text = trustedTime?.toString() ?: "Fetching trusted time...",
style = MaterialTheme.typography.bodyLarge
)
}
}
Handling Trusted Time Availability
Since TrustedTime requires an internet connection after device startup, it’s important to handle cases where a trusted timestamp isn’t available:
if (trustedTimeClient?.hasReliableTime() == true) {
val trustedTime = trustedTimeClient?.computeCurrentUnixEpochMillis()
Log.d("TrustedTime", "Using trusted time: $trustedTime")
} else {
Log.w("TrustedTime", "Trusted time unavailable, falling back to system time")
}
Limitations
The TrustedTime API ensures reliable timekeeping on Android devices running Google Play services (Android 5.0 and above), but it comes with certain limitations. Since it requires an internet connection after a device boots up, timestamps won’t be available if the device hasn’t connected online. Additionally, while TrustedTime helps prevent manual time manipulation, it does not eliminate clock drift, which can still occur due to environmental factors like temperature, battery level, or doze mode.
To mitigate this, the API provides error estimates that developers can use to assess the reliability of timestamps. Though it enhances security, TrustedTime is not foolproof—sophisticated tampering methods can still manipulate time-dependent operations, so apps requiring absolute accuracy should implement additional safeguards.
While the API requires an internet connection after boot to retrieve timestamps, it does cache the last known trusted time when the device goes offline. This means apps can still access a recently verified timestamp, but its accuracy depends on when the last sync occurred.
I hope you enjoyed this article, feel free to contact me if you need anything. See you next time.
Photo by Aron Visuals on Unsplash