Skip to content

Bootstrapping Android app - #36233

Merged
getvictor merged 14 commits into
mainfrom
victor/36202-android-bootstrap
Nov 26, 2025
Merged

Bootstrapping Android app#36233
getvictor merged 14 commits into
mainfrom
victor/36202-android-bootstrap

Conversation

@getvictor

@getvictor getvictor commented Nov 24, 2025

Copy link
Copy Markdown
Member

Related issue: Resolves #36202

Updated how Android agent starts. See README updates.

Checklist for submitter

Testing

  • Added/updated automated tests
  • QA'd all new/changed functionality manually

Summary by CodeRabbit

  • New Features

    • Periodic configuration check scheduled every 15 minutes in the Android agent
    • Improved Android management notification handling and app-role support
  • Documentation

    • Updated Android MDM deployment guide with SHA256 fingerprint instructions and build configuration snippets
  • Chores

    • Added WorkManager and AMAPI SDK for Android; updated Android/Go tooling and library versions
  • Tests

    • Added unit test coverage for the periodic config worker

✏️ Tip: You can customize this high-level summary in your review settings.

@codecov

codecov Bot commented Nov 24, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.96%. Comparing base (db2b645) to head (402b2db).
⚠️ Report is 14 commits behind head on main.

Files with missing lines Patch % Lines
server/mdm/android/service/service.go 0.00% 11 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #36233      +/-   ##
==========================================
+ Coverage   65.95%   65.96%   +0.01%     
==========================================
  Files        2132     2133       +1     
  Lines      181575   181682     +107     
  Branches     7427     7451      +24     
==========================================
+ Hits       119755   119850      +95     
- Misses      50861    50866       +5     
- Partials    10959    10966       +7     
Flag Coverage Δ
backend 67.54% <0.00%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@getvictor

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Nov 24, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@coderabbitai

coderabbitai Bot commented Nov 24, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Integrates Android Management API (AMAPI) and WorkManager into the Fleet Android agent: adds periodic config checks, introduces an AMAPI notification service, updates manifest and docs for SHA256 fingerprint handling, adds dependencies/tests, and augments server-side Android policy payload with signing key certs and companion-app role.

Changes

Cohort / File(s) Summary
Android build config & versions
android/gradle/libs.versions.toml, android/app/build.gradle.kts
Added versions for workManager, amapi, robolectric and corresponding libraries; added WorkManager, AMAPI, and Robolectric dependencies and test dependencies.
Android manifest & declarations
android/app/src/main/AndroidManifest.xml
Added <queries> for Device Policy, declared android:name=".FleetApplication", removed RestrictionsReceiver, added exported FleetNotificationReceiverService with metadata, adjusted CertificateService formatting.
Application class & scheduling
android/app/src/main/java/com/fleetdm/agent/FleetApplication.kt
New FleetApplication subclass that logs on create and schedules a 15-minute periodic ConfigCheckWorker via WorkManager.
WorkManager worker & test
android/app/src/main/java/com/fleetdm/agent/ConfigCheckWorker.kt, android/app/src/test/java/com/fleetdm/agent/ConfigCheckWorkerTest.kt
New ConfigCheckWorker that logs and returns success; added Robolectric unit test verifying doWork() returns success.
Notification service & receiver removal
android/app/src/main/java/com/fleetdm/agent/FleetNotificationReceiverService.kt, android/app/src/main/java/com/fleetdm/agent/RestrictionsReceiver.kt
Added FleetNotificationReceiverService extending NotificationReceiverService with AppRolesListener; removed RestrictionsReceiver BroadcastReceiver.
BootReceiver constant refactor
android/app/src/main/java/com/fleetdm/agent/BootReceiver.kt
Moved TAG constant into companion object and updated its value to "fleet-boot"; behavior unchanged.
Android README updates
android/README.md
Added "Getting the SHA256 fingerprint" section, updated MDM deployment flow to require FLEET_DEV_ANDROID_GOOGLE_SERVICE_CREDENTIALS, added FLEET_DEV_ANDROID_AGENT_SHA256 env var and Gradle applicationId snippet.
Server-side Android policy changes
server/mdm/android/service/service.go
AddFleetAgentToAndroidPolicy now includes SigningKeyCerts (fingerprint from FLEET_DEV_ANDROID_AGENT_SHA256) and Roles (with COMPANION_APP) in ApplicationPolicy payload.
Policy mask test update
server/mdm/android/service/androidmgmt/policy_field_mask_test.go
Updated expected policy field mask to include defaultApplicationSettings and swapped assertion argument order.
Go module bumps
go.mod
Bumped multiple indirect dependencies (oauth2, google api/grpc/genproto/protobuf, cloud.google.com/go related packages, golang.org/x/time, enterprise-certificate-proxy) to newer minor/patch versions.

Sequence Diagram(s)

sequenceDiagram
    participant Android as Android System
    participant App as Fleet Agent App
    participant WM as WorkManager
    participant Worker as ConfigCheckWorker
    participant AMAPI as Android Management API
    participant Notif as FleetNotificationReceiverService

    Android->>App: App process start
    App->>App: FleetApplication.onCreate()
    App->>WM: enqueueUniquePeriodicWork("config_check_periodic", 15m)
    App->>App: Log "Periodic config check scheduled"

    Note over WM: Periodic trigger (~15m)
    WM->>Worker: trigger doWork()
    Worker->>Worker: Log "Periodic config check triggered"
    Worker-->>WM: Result.success()

    AMAPI->>Notif: Notification: App roles change
    Notif->>Notif: onAppRolesSet(request)
    Notif->>AMAPI: AppRolesSetResponse (default)
    Notif->>Notif: Log "App roles set by Android Device Policy"
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas to focus review on:
    • Correct scheduling and uniqueness semantics in FleetApplication WorkManager usage.
    • AMAPI listener implementation contract in FleetNotificationReceiverService and manifest/service metadata.
    • Proper sourcing and formatting of SHA256 fingerprint into SigningKeyCerts in server/mdm/android/service/service.go.
    • Ensure removal of RestrictionsReceiver does not break certificate provisioning flow.
    • Unit test setup with Robolectric for reliability.

Possibly related PRs

Suggested reviewers

  • dantecatalfamo
  • ksykulev
  • mostlikelee

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ⚠️ Warning The PR description is minimal and incomplete. It lacks most required checklist items and provides insufficient detail about the changes. Complete the description with checked/unchecked checklist items, add a changes file entry, verify all database and configuration considerations, and provide more detail about the bootstrap implementation.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Bootstrapping Android app' directly relates to the main objective of implementing a bootstrap mechanism for the Android agent.
Linked Issues check ✅ Passed The PR implements the bootstrap mechanism through new Android app components (FleetApplication, ConfigCheckWorker, FleetNotificationReceiverService) and supporting infrastructure to enable automatic agent launch after enrollment.
Out of Scope Changes check ✅ Passed All changes directly support the bootstrap objective: Android app classes and manifest configuration enable auto-launch; go.mod updates are transitive dependency bumps; server-side policy changes support signing cert integration for the Android agent.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch victor/36202-android-bootstrap

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@getvictor

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Nov 24, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
android/app/src/test/java/com/fleetdm/agent/ConfigCheckWorkerTest.kt (1)

22-31: Test coverage is minimal but appropriate for the current stub implementation.

The test only verifies that doWork() returns success without checking any actual config-checking behavior. When the worker implementation is expanded to perform real configuration checks, add tests to verify:

  • Actual config retrieval and processing
  • Error handling scenarios
  • Logging behavior
  • Any side effects of the config check
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 817773d and 1ce911d.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (13)
  • android/README.md (1 hunks)
  • android/app/build.gradle.kts (1 hunks)
  • android/app/src/main/AndroidManifest.xml (2 hunks)
  • android/app/src/main/java/com/fleetdm/agent/BootReceiver.kt (1 hunks)
  • android/app/src/main/java/com/fleetdm/agent/ConfigCheckWorker.kt (1 hunks)
  • android/app/src/main/java/com/fleetdm/agent/FleetApplication.kt (1 hunks)
  • android/app/src/main/java/com/fleetdm/agent/FleetNotificationReceiverService.kt (1 hunks)
  • android/app/src/main/java/com/fleetdm/agent/RestrictionsReceiver.kt (0 hunks)
  • android/app/src/test/java/com/fleetdm/agent/ConfigCheckWorkerTest.kt (1 hunks)
  • android/gradle/libs.versions.toml (2 hunks)
  • go.mod (4 hunks)
  • server/mdm/android/service/androidmgmt/policy_field_mask_test.go (1 hunks)
  • server/mdm/android/service/service.go (1 hunks)
💤 Files with no reviewable changes (1)
  • android/app/src/main/java/com/fleetdm/agent/RestrictionsReceiver.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

⚙️ CodeRabbit configuration file

When reviewing SQL queries that are added or modified, ensure that appropriate filtering criteria are applied—especially when a query is intended to return data for a specific entity (e.g., a single host). Check for missing WHERE clauses or incorrect filtering that could lead to incorrect or non-deterministic results (e.g., returning the first row instead of the correct one). Flag any queries that may return unintended results due to lack of precise scoping.

Files:

  • server/mdm/android/service/androidmgmt/policy_field_mask_test.go
  • server/mdm/android/service/service.go
🧠 Learnings (1)
📚 Learning: 2025-08-08T08:32:31.529Z
Learnt from: getvictor
Repo: fleetdm/fleet PR: 31695
File: server/datastore/mysql/apple_mdm_test.go:132-132
Timestamp: 2025-08-08T08:32:31.529Z
Learning: Datastore.NewMDMWindowsConfigProfile signature is: NewMDMWindowsConfigProfile(ctx context.Context, cp fleet.MDMWindowsConfigProfile, usesFleetVars []string) (*fleet.MDMWindowsConfigProfile, error). Passing nil for usesFleetVars in tests denotes “no Fleet variables referenced” and is used consistently across the repo.

Applied to files:

  • server/mdm/android/service/service.go
🔇 Additional comments (9)
android/app/src/main/java/com/fleetdm/agent/BootReceiver.kt (1)

9-11: LGTM!

Moving TAG to a companion object with const val is idiomatic Kotlin and aligns with the pattern used in other files like FleetApplication.kt.

server/mdm/android/service/androidmgmt/policy_field_mask_test.go (1)

10-14: LGTM!

The addition of defaultApplicationSettings to the expected mask aligns with the new policy fields. The assertion order change to expectedMask, mask follows the correct convention for assert.Equal (expected, actual).

android/app/src/main/java/com/fleetdm/agent/FleetApplication.kt (2)

20-24: LGTM!

The Application class correctly initializes logging and schedules the periodic config check during app startup.


26-42: Verify KEEP policy behavior for frequent process restarts.

The ExistingPeriodicWorkPolicy.KEEP policy ensures that if the app process is restarted multiple times (e.g., due to broadcasts), the existing periodic work will not be rescheduled. This is the correct choice for this use case.

However, verify that this behavior is desired if you ever need to update the work request parameters (e.g., change the interval). With KEEP, you would need to explicitly cancel and re-enqueue the work to apply changes.

android/README.md (1)

112-119: LGTM!

The deployment instructions are clear and include both required environment variables for the Fleet server.

android/app/build.gradle.kts (1)

110-114: LGTM!

All new dependencies are correctly specified in gradle/libs.versions.toml:

  • androidx-work-runtime-ktx (line 32, references workManager version)
  • amapi-sdk (line 34, references amapi v1.7.0)
  • androidx-work-testing (line 33, references workManager version)
  • robolectric (line 35, references robolectric v4.14)

The dependencies appropriately support the WorkManager-based config checking and AMAPI integration introduced in this PR.

android/app/src/main/AndroidManifest.xml (2)

5-9: LGTM!

The package visibility query for com.google.android.apps.work.clouddpc is required for apps targeting Android 11 (API 30) and above to interact with the Android Device Policy app. This is correctly implemented according to the AMAPI SDK integration guide.


18-18: LGTM!

The application class declaration references FleetApplication, which aligns with the PR's objective to implement Android agent bootstrapping using WorkManager for periodic configuration checks.

go.mod (1)

156-156: Dependency updates are compatible with the codebase.

Verification confirms all updated Google Cloud dependencies (oauth2 v0.33.0, grpc v1.76.0, protobuf v1.36.10, and others) are compatible:

  • No breaking changes apply: grpc v1.76.0 requires Go 1.24+, adds optional Balancer.ExitIdle method, and removes a rarely-used experimental env var—none of which affect this codebase (which uses Go 1.25.3, has no custom Balancer implementations, and doesn't use the removed env var).
  • oauth2 and protobuf updates are patch-level with no API breaks.
  • Android Management API integration (18+ files) uses standard googleapis patterns compatible with these versions.
  • go.sum is consistent with go.mod.

Comment thread android/app/src/main/AndroidManifest.xml
Comment on lines +19 to +22
override fun doWork(): Result {
Log.i(TAG, "Periodic config check triggered")
return Result.success()
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Stub implementation needs actual config checking logic.

The doWork() method currently only logs a message and returns success without performing any actual configuration checking. For a complete bootstrap implementation, consider adding:

  • Retrieval of managed configurations via RestrictionsManager or AMAPI
  • Processing of retrieved configuration data
  • Error handling for network failures or invalid configurations
  • Appropriate Result.retry() or Result.failure() returns for error cases

Is this stub intentional for incremental development, or should the implementation be completed in this PR?

Do you want me to generate a sample implementation that retrieves and processes managed configurations?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this will be added later.

Comment thread android/gradle/libs.versions.toml Outdated
Comment thread android/README.md
Comment thread server/mdm/android/service/service.go
@getvictor
getvictor marked this pull request as ready for review November 25, 2025 00:57
* Custom Application class for Fleet Agent.
* Runs when the app process starts (triggered by broadcasts, not by user).
*/
class AgentApplication : Application() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the significance of an Application as opposed to a Service?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a singleton, and it is the first thing that runs. It is typically used for global application state and initialization.

@sharon-fdm sharon-fdm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only reviewed .github/workflows/test-android.yml

LGTM

@getvictor
getvictor merged commit 61c5167 into main Nov 26, 2025
43 checks passed
@getvictor
getvictor deleted the victor/36202-android-bootstrap branch November 26, 2025 17:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android agent: bootstrap app

3 participants