Posted by Dom Elliott – Group Product Manager, Google Play and Eric Lynch - Senior Product Manager, Android Security
In the mobile ecosystem, abuse can threaten your revenue, growth, and user trust. To help developers thrive, Google Play offers a resilient threat detection service, Play Integrity API. Play Integrity API helps you verify that interactions and server requests are genuine—coming from your unmodified app on a certified Android device, installed by Google Play.
The impact is significant: apps using Play integrity features see 80% lower unauthorized usage on average compared to other apps. Today, leaders across diverse categories—including Uber, TikTok, Stripe, Kabam, Wooga, Radar.com, Zimperium, Paytm, and Remini—use it to help safeguard their businesses.
We’re continuing to improve the Play Integrity API, making it easier to integrate, more resilient against sophisticated attacks, and better at recovering users who don’t meet integrity standards or encounter errors with new Play in-app remediation prompts.
Detect threats to your business
The Play Integrity API offers verdicts designed to detect specific threats that impact your bottom line during critical interactions.
Unauthorized access: The accountDetails verdict helps you determine whether the user installed or paid for your app or game on Google Play.
Code tampering: The appIntegrity verdict helps you determine whether you're interacting with your unmodified binary that Google Play recognizes.
Risky devices and emulated environments: The deviceIntegrity verdict helps you determine whether your app is running on a genuine Play Protect certified Android device or a genuine instance of Google Play Games for PC.
Unpatched devices: For devices running Android 13 and higher, MEETS_STRONG_INTEGRITY response in the deviceIntegrity verdict helps you determine if a device has applied recent security updates. You can also opt in to deviceAttributes to include the attested Android SDK version in the response.
Risky access by other apps: The appAccessRiskVerdict helps you determine whether apps are running that could be used to capture the screen, display overlays, or control the device (for example, by misusing the accessibility permission). This verdict automatically excludes apps that serve genuine accessibility purposes.
Known malware: The playProtectVerdict helps you determine whether Google Play Protect is turned on and whether it has found risky or dangerous apps installed on the device.
Hyperactivity: The recentDeviceActivity level helps you determine whether a device has made an anomalously high volume of integrity token requests recently, which could indicate automated traffic and could be a sign of attack.
Repeat abuse and reused devices:deviceRecall (beta) helps you determine whether you're interacting with a device that you've previously flagged, even if your app was reinstalled or the device was reset. With device recall, you can customize the repeat actions you want to track.
The API can be used across Android form factors including phones, tablets, foldables, Android Auto, Android TV, Android XR, ChromeOS, Wear OS, and on Google Play Games for PC.
Make the most of Play Integrity API
Apps and games have found success with the Play Integrity API by following the security considerations and taking a phased approach to their anti-abuse strategy.
Step 1: Decide what you want to protect: Decide what actions and server requests in your apps and games are important to verify and protect. For example, you could perform integrity checks when a user is launching the app, signing in, joining a multiplayer game, generating AI content, or transferring money.
Step 2: Collect integrity verdict responses: Perform integrity checks at important moments to start collecting verdict data, without enforcement initially. That way you can analyze the responses for your install base and see how they correlate with your existing abuse signals and historical abuse data.
Step 3: Decide on your enforcement strategy: Decide on your enforcement strategy based on your analysis of the responses and what you are trying to protect. For example, you could change risky traffic at important moments to protect sensitive functionality. The API offers a range of responses so you can implement a tiered enforcement strategy based on the trust level you give to each combination of responses.
Step 4: Gradually rollout enforcement and support your users: Gradually roll out enforcement. Have a retry strategy when verdicts have issues or are unavailable and be prepared to support good users who have issues. The new Play in-app remediation prompts, described below, make it easier than ever to get users with issues back to a good state.
NEW: Let Play recover users with issues automatically
Deciding how to respond to different integrity signals can be complex, you need to handle various integrity responses and API error codes (like network issues or outdated Play services). We’re simplifying this with new Play in-app remediation prompts. You can show a Google Play prompt to your users to automatically fix a wide range of issues directly within your app. This reduces integration complexity, ensures a consistent user interface, and helps get more users back to a good state.
GET_INTEGRITY automatically detects the issue
(in this example, a network error)
and resolves it.
You can trigger theGET_INTEGRITY dialog, available in Play Integrity API library version 1.5.0+, after a range of issues to automatically guide the user through the necessary fixes including:
Unauthorized access: GET_INTEGRITY guides the user back to a Play licensed response in accountDetails.
Code tampering: GET_INTEGRITY guides the user back to a Play recognized response in appIntegrity.
Device integrity issues: GET_INTEGRITY guides the user on how to get back to the MEETS_DEVICE_INTEGRITY state in deviceIntegrity.
Remediable error codes: GET_INTEGRITY resolves remediable API errors, such as prompting the user to fix network connectivity or update Google Play Services.
We also offer specialized dialogs includingGET_STRONG_INTEGRITY (which works like GET_INTEGRITY while also getting the user back to the MEETS_STRONG_INTEGRITY state with no known malware issues in the playProtectVerdict), GET_LICENSED (which gets the user back to a Play licensed and Play recognized state), and CLOSE_UNKNOWN_ACCESS_RISK and CLOSE_ALL_ACCESS_RISK (which prompt the user to close potentially risky apps).
Choose modern integrity solutions
In addition to Play Integrity API, Google offers several other features to consider as part of your overall anti-abuse strategy. Both Play Integrity API and Play’s automatic protection offer user experience and developer benefits for safeguarding app distribution. We encourage existing apps to migrate to these modern integrity solutions instead of using the legacy Play licensing library.
Automatic protection: Prevent unauthorized access with Google Play’s automatic protection and ensure users continue getting your official app updates. Turn it on and Google Play will automatically add an installer check to your app’s code, with no developer integration work required. If your protected app is redistributed or shared through another channel, then the user will be prompted to get your app from Google Play. Eligible Play developers also have access to Play’s advanced anti-tamper protection, which uses obfuscation and runtime checks to make it harder and costlier for attackers to modify and redistribute protected apps.
Android platform key attestation: Play Integrity API is the recommended way to benefit from hardware-backed Android platform key attestation. Play Integrity API takes care of the underlying implementation across the device ecosystem, Play automatically mitigates key-related issues and outages, and you can use the API to detect other threats. Developers who directly implement key attestation instead of relying on Play Integrity API should prepare for the upcoming Android Platform root certificate rotation in February 2026 to avoid disruption (developers using Play Integrity API do not need to take any action).
Firebase App Check: Developers using Firebase can use Firebase App Check to receive an app and device integrity verdict powered by Play Integrity API on certified Android devices, along with responses from other platform attestation providers. To detect all other threats and use other Play features, integrate Play Integrity API directly.
reCAPTCHA Enterprise: Enterprise customers looking for a complete fraud and bot management solution can purchase reCAPTCHA Enterprise for mobile. reCAPTCHA Enterprise uses some of Play Integrity API’s anti-abuse signals, and combines them with reCAPTCHA signals out of the box.
Safeguard your business today
With a strong foundation in hardware-backed security and new automated remediation dialogs simplifying integration, the Play Integrity API is an essential tool for protecting your growth.
Posted by Ben Weiss - Senior Developer Relations Engineer,
Breana Tate - Developer Relations Engineer,
Jossi Wolf - Software Engineer on Compose
Compose
yourselves and let us guide you through more background on performance.
Welcome
to day 3 of Performance Spotlight Week. Today we're continuing to share details and guidance on
important
areas of app performance. We're covering Profile Guided Optimization, Jetpack Compose
performance
improvements and considerations on working behind the scenes. Let's dive right in.
Profile
Guided Optimization
Baseline
Profiles
and Startup
Profiles
are foundational to improve an Android app's startup and runtime performance. They are part of a
group of
performance optimizations called Profile Guided Optimization.
When
an app is packaged, the d8 dexer takes classes and methods and populates your app's classes.dex
files. When a user opens the app, these dex files are loaded, one after the other until the app
can start.
By providing a Startup
Profile
you let d8 know which classes and methods to pack in the first classes.dex
files. This structure allows the app to load fewer files, which in turn improves startup
speed.
Baseline
Profiles effectively move the Just in Time (JIT) compilation steps away from user devices and
onto developer
machines. The generated Ahead Of Time (AOT) compiled code has proven to reduce startup time and
rendering
issues alike.
Trello
and Baseline Profiles
We
asked engineers on the Trello app how Baseline Profiles affected their app's performance. After
applying
Baseline Profiles to their main user journey, Trello saw a significant 25 % reduction in app
startup
time.
Trello
was able to improve their app's startup time by 25 % by using baseline
profiles.
Across
Meta's apps the teams have seen various critical metrics improve by up to 40 % after
applying Baseline
Profiles.
Technical
improvements like these help you improve user satisfaction and business success as well. Sharing
this with
your product owners, CTOs and decision makers can also help speed up your app's
performance.
Get
started with Baseline Profiles
To
generate either a Baseline or Startup Profile, you write a macrobenchmark
test that exercises the app. During the test profile data is collected which will be used during
app
compilation. The tests are written using the new UiAutomator
API,
which we'll cover tomorrow.
Writing
a benchmark like this is straightforward and you can see the full sample on GitHub.
@Test
funprofileGenerator(){
rule.collect(
packageName=TARGET_PACKAGE,
maxIterations=15,
stableIterations=3,
includeInStartupProfile=true
){
uiAutomator{
startApp(TARGET_PACKAGE)
}
}
}
Considerations
Start
by writing a macrobenchmark tests Baseline Profile and a Startup Profile for the path most
traveled by your
users. This means the main entry point that your users take into your app which usually is
after
they logged in.
Then continue to write more test cases to capture a more complete picture only for Baseline
Profiles. You do
not need to cover everything with a Baseline Profile. Stick to the most used paths and measure
performance
in the field. More on that in tomorrow's post.
Get
started with Profile Guided Optimization
To
learn how Baseline Profiles work under the hood, watch this video from the Android Developers
Summit:
And
check out the Android Build Time episode on Profile Guided Optimization for another in-depth
look:
The
UI framework for Android has seen the performance investment of the engineering team pay off.
From version
1.9 of Jetpack Compose, scroll jank has dropped to 0.2 % during an internal long scrolling
benchmark
test.
These
improvements were made possible because of several features packed into the most recent
releases.
Customizable
cache window
By
default, lazy layouts only compose one item ahead of time in the direction of scrolling, and
after something
scrolls off screen it is discarded. You can now customize the amount of items to retain through
a fraction
of the viewport or dp size. This helps your app perform more work upfront, and after enabling
pausable
composition in between frames, using the available time more efficiently.
To
start using customizable cache windows, instantiate a LazyLayoutCacheWindow
and pass it to your lazy list or lazy grid. Measure your app's performance using different cache
window
sizes, for example 50% of the viewport. The optimal value will depend on your content's
structure and item
size.
val
dpCacheWindow = LazyLayoutCacheWindow(ahead = 150.dp,
behind = 100.dp)
val
state = rememberLazyListState(cacheWindow = dpCacheWindow)
LazyColumn(state
= state) {
//
column contents
}
Pausable
composition
This
feature allows compositions to be paused, and their work split up over several frames. The APIs
landed in
1.9 and it is now used by default in 1.10 in lazy layout prefetch. You should see the most
benefit with
complex items with longer composition times.
More
Compose performance optimizations
In
the versions 1.9 and 1.10 of Compose the team also made several optimizations that are a bit
less
obvious.
Several
APIs that use coroutines under the hood have been improved. For example, when using Draggable
and Clickable,
developers should see faster reaction times and improved allocation counts.
Optimizations
in layout rectangle tracking have improved performance of Modifiers like onVisibilityChanged()
and onLayoutRectChanged().
This speeds up the layout phase, even when not explicitly using these APIs.
Another
performance improvement is using cached values when observing positions via onPlaced().
Prefetch
text in the background
Starting
with version 1.9, Compose adds the ability to prefetch text on a background thread. This enables
you to
pre-warm caches to enable faster text layout and is relevant for app rendering performance.
During layout,
text has to be passed into the Android framework where a word cache is populated. By default
this runs on
the Ui thread. Offloading prefetching and populating the word cache onto a background thread can
speed up
layout, especially for longer texts. To prefetch on a background thread you can pass a custom
executor to
any composable that's using BasicText
under the hood by passing a LocalBackgroundTextMeasurementExecutor
to a CompositionLocalProvider
like so.
BasicText("Some text that should be measured on a background thread!")
}
Depending
on the text, this can provide a performance boost to your text rendering. To make sure that it
improves your
app's rendering performance, benchmark and compare the results.
Background
work performance considerations
Background
Work is an essential part of many apps. You may be using libraries like WorkManager or
JobScheduler to
perform tasks like:
Periodically
uploading analytical events
Syncing
data between a backend service and a database
Processing
media (i.e. resizing or compressing images)
A
key challenge while executing these tasks is balancing performance and power efficiency.
WorkManager allows
you to achieve this balance. It's designed to be power-efficient, and allow work to be deferred
to an
optimal execution window influenced by a number of factors, including constraints you specify or
constraints
imposed by the system.
WorkManager
is not a one-size-fits-all solution, though. Android also has a number of power-optimized APIs
that are
designed specifically with certain common Core User Journeys (CUJs) in
mind.
Reference
the Background
Work landing page
for a list of just a few of these, including updating a widget and getting location in the
background.
Local
Debugging tools for Background Work: Common Scenarios
To
debug Background Work and understand why a task may have been delayed or failed, you need
visibility into
how the system has scheduled your tasks.
To
help with this, WorkManager has several related
tools to help you debug locally
and optimize performance (some of these work for JobScheduler as well)! Here are some common
scenarios you
might encounter when using WorkManager, and an explanation of tools you can use to debug
them.
Debugging
why scheduled work is not executing
Scheduled
work being delayed or not executing at all can be due to a number of factors, including
specified
constraints not being met or constraints having been imposed
by the system.
The
first step in investigating why scheduled work is not running is to confirm
the work was successfully scheduled.
After confirming the scheduling status, determine whether there are any unmet constraints or
preconditions
preventing the work from executing.
There
are several tools for debugging this scenario.
Background
Task Inspector
The
Background Task Inspector is a powerful tool integrated directly into Android Studio. It
provides a visual
representation of all WorkManager tasks and their associated states (Running, Enqueued, Failed,
Succeeded).
To
debug why scheduled work is not executing with the Background Task Inspector, consult the listed
Work
status(es). An ‘Enqueued' status indicates your Work was scheduled, but is still waiting to
run.
Benefits:
Aside from providing an easy way to view all tasks, this tool is especially useful if you have
chained work.
The Background Task inspector offers a graph view that can visualize if a previous task failing
may have
impacted the execution of the following task.
Background
Task Inspector list view
Background
Task Inspector graph view
adb
shell dumpsys jobscheduler
This
command
returns a list of all active JobScheduler jobs (which includes WorkManager Workers) along with
specified
constraints, and system-imposed constraints. It also returns job
history.
Use
this if you want a different way to view your scheduled work and associated constraints. For
WorkManager
versions earlier than WorkManager 2.10.0, adb
shell dumpsys jobscheduler
will return a list of Workers with this name:
Benefits:
This
command is useful for understanding if there were any system-imposed
constraints, which
you cannot determine with the Background Task Inspector. For example, this will return your
app's
standby bucket,
which can affect the window in which scheduled work completes.
Enable
Debug logging
You
can enable custom
logging
to see verbose WorkManager logs, which will have WM—
attached.
Benefits:
This allows you to gain visibility into when work is scheduled, constraints are fulfilled, and
lifecycle
events, and you can consult these logs while developing your app.
WorkInfo.StopReason
If
you notice unpredictable performance with a specific worker, you can programmatically observe
the reason
your worker was stopped on the previous run attempt with WorkInfo.getStopReason.
It's
a good practice to configure your app to observe WorkInfo using getWorkInfoByIdFlow to identify
if your work
is being affected by background restrictions, constraints, frequent timeouts, or even stopped by
the
user.
Benefits:
You can use WorkInfo.StopReason to collect field data about your workers'
performance.
Debugging
WorkManager-attributed high wake lock duration flagged by Android vitals
Android
vitals features an excessive partial wake locks metric, which highlights wake locks contributing
to battery
drain. You may be surprised to know that WorkManager
acquires wake locks to execute tasks,
and if the wake locks exceed the threshold set by Google Play, can have impacts to your app's
visibility.
How can you debug why there is so much wake lock duration attributed to your work? You can use
the following
tools.
Perfetto
is a tool for analyzing system traces. When using it for debugging WorkManager specifically, you
can view
the “Device State” section to see when your work started, how long it ran, and how it
contributes to power
consumption.
Under
“Device State: Jobs” track, you can see any workers that have been executed and their
associated wake
locks.
Device
State section in Perfetto, showing CleanupWorker and BlurWorker execution.
Resources
Consult
the Debug
WorkManager page
for an overview of the available debugging methods for other scenarios you might
encounter.
And
to try some of these methods hands on and learn more about debugging WorkManager, check out
the
Advanced WorkManager and Testing
codelab.
Next
steps
Today
we moved beyond code shrinking and explored how the Android Runtime and Jetpack Compose actually
render your
app. Whether it’s pre-compiling critical paths with Baseline Profiles or smoothing out scroll
states with
the new Compose 1.9 and 1.10 features, these tools focus on the feel
of your app. And we dove deep into best practices on debugging background work.
Ask
Android
On
Friday we're hosting a live AMA on performance. Ask your questions now using #AskAndroid and get
them
answered by the experts.
The
challenge
We
challenged you on Monday to enable R8. Today, we are asking you to generate
one Baseline Profile
for your app.
With
Android
Studio Otter,
the Baseline Profile Generator module wizard makes this easier than ever. Pick your most
critical user
journey—even if it’s just your app startup and login—and generate a profile.
Once
you have it, run a Macrobenchmark to compare CompilationMode.None
vs. CompilationMode.Partial.
Share
your startup time improvements on social media using #optimizationEnabled.
Tune
in tomorrow
You
have shrunk your app with R8 and optimized your runtime with Profile Guided Optimization. But
how do you
prove
these wins to your stakeholders? And how do you catch regressions before they hit
production?
Join
us tomorrow for Day
4: The Performance Leveling Guide,
where we will map out exactly how to measure your success, from field data in Play Vitals to
deep local
tracing with Perfetto.
Posted by Ben Weiss - Senior Developer Relations Engineer,
Breana Tate - Developer Relations Engineer,
Jossi Wolf - Software Engineer on Compose
Compose
yourselves and let us guide you through more background on performance.
Welcome
to day 3 of Performance Spotlight Week. Today we're continuing to share details and guidance on
important
areas of app performance. We're covering Profile Guided Optimization, Jetpack Compose
performance
improvements and considerations on working behind the scenes. Let's dive right in.
Profile
Guided Optimization
Baseline
Profiles
and Startup
Profiles
are foundational to improve an Android app's startup and runtime performance. They are part of a
group of
performance optimizations called Profile Guided Optimization.
When
an app is packaged, the d8 dexer takes classes and methods and populates your app's classes.dex
files. When a user opens the app, these dex files are loaded, one after the other until the app
can start.
By providing a Startup
Profile
you let d8 know which classes and methods to pack in the first classes.dex
files. This structure allows the app to load fewer files, which in turn improves startup
speed.
Baseline
Profiles effectively move the Just in Time (JIT) compilation steps away from user devices and
onto developer
machines. The generated Ahead Of Time (AOT) compiled code has proven to reduce startup time and
rendering
issues alike.
Trello
and Baseline Profiles
We
asked engineers on the Trello app how Baseline Profiles affected their app's performance. After
applying
Baseline Profiles to their main user journey, Trello saw a significant 25 % reduction in app
startup
time.
Trello
was able to improve their app's startup time by 25 % by using baseline
profiles.
Across
Meta's apps the teams have seen various critical metrics improve by up to 40 % after
applying Baseline
Profiles.
Technical
improvements like these help you improve user satisfaction and business success as well. Sharing
this with
your product owners, CTOs and decision makers can also help speed up your app's
performance.
Get
started with Baseline Profiles
To
generate either a Baseline or Startup Profile, you write a macrobenchmark
test that exercises the app. During the test profile data is collected which will be used during
app
compilation. The tests are written using the new UiAutomator
API,
which we'll cover tomorrow.
Writing
a benchmark like this is straightforward and you can see the full sample on GitHub.
@Test
funprofileGenerator(){
rule.collect(
packageName=TARGET_PACKAGE,
maxIterations=15,
stableIterations=3,
includeInStartupProfile=true
){
uiAutomator{
startApp(TARGET_PACKAGE)
}
}
}
Considerations
Start
by writing a macrobenchmark tests Baseline Profile and a Startup Profile for the path most
traveled by your
users. This means the main entry point that your users take into your app which usually is
after
they logged in.
Then continue to write more test cases to capture a more complete picture only for Baseline
Profiles. You do
not need to cover everything with a Baseline Profile. Stick to the most used paths and measure
performance
in the field. More on that in tomorrow's post.
Get
started with Profile Guided Optimization
To
learn how Baseline Profiles work under the hood, watch this video from the Android Developers
Summit:
And
check out the Android Build Time episode on Profile Guided Optimization for another in-depth
look:
The
UI framework for Android has seen the performance investment of the engineering team pay off.
From version
1.9 of Jetpack Compose, scroll jank has dropped to 0.2 % during an internal long scrolling
benchmark
test.
These
improvements were made possible because of several features packed into the most recent
releases.
Customizable
cache window
By
default, lazy layouts only compose one item ahead of time in the direction of scrolling, and
after something
scrolls off screen it is discarded. You can now customize the amount of items to retain through
a fraction
of the viewport or dp size. This helps your app perform more work upfront, and after enabling
pausable
composition in between frames, using the available time more efficiently.
To
start using customizable cache windows, instantiate a LazyLayoutCacheWindow
and pass it to your lazy list or lazy grid. Measure your app's performance using different cache
window
sizes, for example 50% of the viewport. The optimal value will depend on your content's
structure and item
size.
val
dpCacheWindow = LazyLayoutCacheWindow(ahead = 150.dp,
behind = 100.dp)
val
state = rememberLazyListState(cacheWindow = dpCacheWindow)
LazyColumn(state
= state) {
//
column contents
}
Pausable
composition
This
feature allows compositions to be paused, and their work split up over several frames. The APIs
landed in
1.9 and it is now used by default in 1.10 in lazy layout prefetch. You should see the most
benefit with
complex items with longer composition times.
More
Compose performance optimizations
In
the versions 1.9 and 1.10 of Compose the team also made several optimizations that are a bit
less
obvious.
Several
APIs that use coroutines under the hood have been improved. For example, when using Draggable
and Clickable,
developers should see faster reaction times and improved allocation counts.
Optimizations
in layout rectangle tracking have improved performance of Modifiers like onVisibilityChanged()
and onLayoutRectChanged().
This speeds up the layout phase, even when not explicitly using these APIs.
Another
performance improvement is using cached values when observing positions via onPlaced().
Prefetch
text in the background
Starting
with version 1.9, Compose adds the ability to prefetch text on a background thread. This enables
you to
pre-warm caches to enable faster text layout and is relevant for app rendering performance.
During layout,
text has to be passed into the Android framework where a word cache is populated. By default
this runs on
the Ui thread. Offloading prefetching and populating the word cache onto a background thread can
speed up
layout, especially for longer texts. To prefetch on a background thread you can pass a custom
executor to
any composable that's using BasicText
under the hood by passing a LocalBackgroundTextMeasurementExecutor
to a CompositionLocalProvider
like so.
BasicText("Some text that should be measured on a background thread!")
}
Depending
on the text, this can provide a performance boost to your text rendering. To make sure that it
improves your
app's rendering performance, benchmark and compare the results.
Background
work performance considerations
Background
Work is an essential part of many apps. You may be using libraries like WorkManager or
JobScheduler to
perform tasks like:
Periodically
uploading analytical events
Syncing
data between a backend service and a database
Processing
media (i.e. resizing or compressing images)
A
key challenge while executing these tasks is balancing performance and power efficiency.
WorkManager allows
you to achieve this balance. It's designed to be power-efficient, and allow work to be deferred
to an
optimal execution window influenced by a number of factors, including constraints you specify or
constraints
imposed by the system.
WorkManager
is not a one-size-fits-all solution, though. Android also has a number of power-optimized APIs
that are
designed specifically with certain common Core User Journeys (CUJs) in
mind.
Reference
the Background
Work landing page
for a list of just a few of these, including updating a widget and getting location in the
background.
Local
Debugging tools for Background Work: Common Scenarios
To
debug Background Work and understand why a task may have been delayed or failed, you need
visibility into
how the system has scheduled your tasks.
To
help with this, WorkManager has several related
tools to help you debug locally
and optimize performance (some of these work for JobScheduler as well)! Here are some common
scenarios you
might encounter when using WorkManager, and an explanation of tools you can use to debug
them.
Debugging
why scheduled work is not executing
Scheduled
work being delayed or not executing at all can be due to a number of factors, including
specified
constraints not being met or constraints having been imposed
by the system.
The
first step in investigating why scheduled work is not running is to confirm
the work was successfully scheduled.
After confirming the scheduling status, determine whether there are any unmet constraints or
preconditions
preventing the work from executing.
There
are several tools for debugging this scenario.
Background
Task Inspector
The
Background Task Inspector is a powerful tool integrated directly into Android Studio. It
provides a visual
representation of all WorkManager tasks and their associated states (Running, Enqueued, Failed,
Succeeded).
To
debug why scheduled work is not executing with the Background Task Inspector, consult the listed
Work
status(es). An ‘Enqueued' status indicates your Work was scheduled, but is still waiting to
run.
Benefits:
Aside from providing an easy way to view all tasks, this tool is especially useful if you have
chained work.
The Background Task inspector offers a graph view that can visualize if a previous task failing
may have
impacted the execution of the following task.
Background
Task Inspector list view
Background
Task Inspector graph view
adb
shell dumpsys jobscheduler
This
command
returns a list of all active JobScheduler jobs (which includes WorkManager Workers) along with
specified
constraints, and system-imposed constraints. It also returns job
history.
Use
this if you want a different way to view your scheduled work and associated constraints. For
WorkManager
versions earlier than WorkManager 2.10.0, adb
shell dumpsys jobscheduler
will return a list of Workers with this name:
Benefits:
This
command is useful for understanding if there were any system-imposed
constraints, which
you cannot determine with the Background Task Inspector. For example, this will return your
app's
standby bucket,
which can affect the window in which scheduled work completes.
Enable
Debug logging
You
can enable custom
logging
to see verbose WorkManager logs, which will have WM—
attached.
Benefits:
This allows you to gain visibility into when work is scheduled, constraints are fulfilled, and
lifecycle
events, and you can consult these logs while developing your app.
WorkInfo.StopReason
If
you notice unpredictable performance with a specific worker, you can programmatically observe
the reason
your worker was stopped on the previous run attempt with WorkInfo.getStopReason.
It's
a good practice to configure your app to observe WorkInfo using getWorkInfoByIdFlow to identify
if your work
is being affected by background restrictions, constraints, frequent timeouts, or even stopped by
the
user.
Benefits:
You can use WorkInfo.StopReason to collect field data about your workers'
performance.
Debugging
WorkManager-attributed high wake lock duration flagged by Android vitals
Android
vitals features an excessive partial wake locks metric, which highlights wake locks contributing
to battery
drain. You may be surprised to know that WorkManager
acquires wake locks to execute tasks,
and if the wake locks exceed the threshold set by Google Play, can have impacts to your app's
visibility.
How can you debug why there is so much wake lock duration attributed to your work? You can use
the following
tools.
Perfetto
is a tool for analyzing system traces. When using it for debugging WorkManager specifically, you
can view
the “Device State” section to see when your work started, how long it ran, and how it
contributes to power
consumption.
Under
“Device State: Jobs” track, you can see any workers that have been executed and their
associated wake
locks.
Device
State section in Perfetto, showing CleanupWorker and BlurWorker execution.
Resources
Consult
the Debug
WorkManager page
for an overview of the available debugging methods for other scenarios you might
encounter.
And
to try some of these methods hands on and learn more about debugging WorkManager, check out
the
Advanced WorkManager and Testing
codelab.
Next
steps
Today
we moved beyond code shrinking and explored how the Android Runtime and Jetpack Compose actually
render your
app. Whether it’s pre-compiling critical paths with Baseline Profiles or smoothing out scroll
states with
the new Compose 1.9 and 1.10 features, these tools focus on the feel
of your app. And we dove deep into best practices on debugging background work.
Ask
Android
On
Friday we're hosting a live AMA on performance. Ask your questions now using #AskAndroid and get
them
answered by the experts.
The
challenge
We
challenged you on Monday to enable R8. Today, we are asking you to generate
one Baseline Profile
for your app.
With
Android
Studio Otter,
the Baseline Profile Generator module wizard makes this easier than ever. Pick your most
critical user
journey—even if it’s just your app startup and login—and generate a profile.
Once
you have it, run a Macrobenchmark to compare CompilationMode.None
vs. CompilationMode.Partial.
Share
your startup time improvements on social media using #optimizationEnabled.
Tune
in tomorrow
You
have shrunk your app with R8 and optimized your runtime with Profile Guided Optimization. But
how do you
prove
these wins to your stakeholders? And how do you catch regressions before they hit
production?
Join
us tomorrow for Day
4: The Performance Leveling Guide,
where we will map out exactly how to measure your success, from field data in Play Vitals to
deep local
tracing with Perfetto.
Today, we're extending our partnership with the McLaren Formula 1 Team, placing Gemini—now with Gemini 3, our most intelligent model that brings any idea to life—at the …
Earlier this year, we launched Gemini in Google Classroom to help educators save time on planning and create more engaging lessons. In the coming weeks, we’re expanding Gemini in Classroom to students in higher education who are 18 years of age and older to help them study and learn.
From a central destination in Google Classroom, students will be able to access learning tools available with Gemini for Education, a no-cost version of the Gemini app built for educational institutions where you get expanded access to our most capable AI model and data isn’t reviewed by humans or used to train AI models.
Students will be able to
Learn about a topic: Get on-demand support and explanations of challenging concepts or step-by-step guidance with Guided Learning.
Take a quiz: test your knowledge with personalized practice quizzes based on specific topics or class materials to help prepare for exams.
Practice with flashcards: Easily transform notes and class materials into custom digital flashcards for quick review.
Create a study guide: Make a study guide about a certain topic, or upload class notes and materials for more personalized resources.
Additional details
Getting started
Gemini in Classroom is only available in English for Google Workspace for Education users over the age of 18. The student experience will be available for users whose role is defined as “Student” in Classroom, are in a higher education organization, and are in a group or OU with both Gemini and Gemini in Classroom set to On.
Navigate to the Gemini tab in the navigation bar in Google Classroom.
When using generated content, you should always review the outputs as AI can make mistakes and refine the output so that it fits your context and local policies.
Visit the Help Center to learn more about Gemini in Classroom and learn more about how to use generative AI for students here.