当前位置: 首页 > news >正文

【WorkManager】无法在 Direct Boot 模式下初始化

【WorkManager】无法在 Direct Boot 模式下初始化

  • 一、问题描述
  • 二、问题分析
    • 2.1 关于 Direct Boot 模式
    • 2.2 支持 Direct Boot 模式
    • 2.3 手动初始化 WorkManager 组件
    • 2.4 WorkManager 不支持 Direct Boot 的官方修改
  • 三、解决方案

一、问题描述

在使用 WorkManager 库来实现开机上报设备信息和定时上报设备信息时,当 Android 设备设置屏幕锁定密码并未解锁时,此时 WorkManager 会无法初始化导致异常无法执行任务。

09-08 09:44:41.744  1827  1827 E AndroidRuntime: FATAL EXCEPTION: main
09-08 09:44:41.744  1827  1827 E AndroidRuntime: Process: com.xxx.devicereport, PID: 1827
09-08 09:44:41.744  1827  1827 E AndroidRuntime: java.lang.RuntimeException: Unable to get provider androidx.startup.InitializationProvider: androidx.startup.StartupException: java.lang.IllegalStateException: Cannot initialize WorkManager in direct boot mode
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at android.app.ActivityThread.installProvider(ActivityThread.java:7940)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at android.app.ActivityThread.installContentProviders(ActivityThread.java:7444)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7148)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2328)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:106)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at android.os.Looper.loopOnce(Looper.java:205)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at android.os.Looper.loop(Looper.java:294)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:8408)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:640)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:982)
09-08 09:44:41.744  1827  1827 E AndroidRuntime: Caused by: androidx.startup.StartupException: java.lang.IllegalStateException: Cannot initialize WorkManager in direct boot mode
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.startup.AppInitializer.doInitialize(AppInitializer.java:187)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.startup.AppInitializer.discoverAndInitialize(AppInitializer.java:239)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.startup.AppInitializer.discoverAndInitialize(AppInitializer.java:207)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.startup.InitializationProvider.onCreate(InitializationProvider.java:49)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at android.content.ContentProvider.attachInfo(ContentProvider.java:2621)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at android.content.ContentProvider.attachInfo(ContentProvider.java:2590)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at android.app.ActivityThread.installProvider(ActivityThread.java:7935)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        ... 11 more
09-08 09:44:41.744  1827  1827 E AndroidRuntime: Caused by: java.lang.IllegalStateException: Cannot initialize WorkManager in direct boot mode
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.work.impl.WorkManagerImpl.<init>(WorkManagerImpl.java:237)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.work.impl.WorkManagerImplExtKt.createWorkManager(WorkManagerImplExt.kt:48)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.work.impl.WorkManagerImplExtKt.createWorkManager$default(WorkManagerImplExt.kt:29)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.work.impl.WorkManagerImplExtKt.createWorkManager(WorkManagerImplExt.kt:0)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.work.impl.WorkManagerImpl.initialize(WorkManagerImpl.java:206)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.work.WorkManager.initialize(WorkManager.java:212)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.work.WorkManagerInitializer.create(WorkManagerInitializer.java:39)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.work.WorkManagerInitializer.create(WorkManagerInitializer.java:30)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        at androidx.startup.AppInitializer.doInitialize(AppInitializer.java:180)
09-08 09:44:41.744  1827  1827 E AndroidRuntime:        ... 17 more

二、问题分析

2.1 关于 Direct Boot 模式

Android中的 Direct Boot 模式(直接启动模式)是Android 7.它允许设备在启动后、用户解锁前的锁定状态下运行特定的应用组件,确保关键功能(如闹钟、紧急通知和无障碍服务)在设备重启后仍能正常工作。

核心设计目标

Direct Boot模式解决了全盘加密(FDE)设备重启后需用户解锁才能运行应用的问题。通过文件级加密(FBE)和两个独立的存储分区,系统在未解锁状态下仍能有限运行:

  • 设备加密存储(DE):使用设备硬件绑定的密钥加密,在Direct Boot模式和用户解锁后均可访问。
  • 凭据加密存储(CE):使用用户凭据(如密码、PIN)加密,仅在用户解锁后可用。

加密路径
/data/user_de/0/com.xxx.aidevicereport
非加密
/data/user/0/com.xxx.devicereport

实现方式

组件标记 在AndroidManifest.xml中将组件(Application、Activity、Service、BroadcastReceiver等)设置为android:directBootAware="true"

2.2 支持 Direct Boot 模式

关于设备开启重启后的几个广播

// 无论直接启动支持如何,在启动时立即发送
public static final String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";// 目标用户解锁凭据加密的专用存储时发送
public static final String ACTION_USER_UNLOCKED = "android.intent.action.USER_UNLOCKED";// 设备解锁后发送
public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";

查询用户是否已解锁设备的方法

UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
if (userManager != null) {boolean isUserUnlocked = userManager.isUserUnlocked();Log.d(TAG, "Application isUserUnlocked:" + isUserUnlocked);
}

访问设备加密存储空间的方法,通过此上下文 createDeviceProtectedStorageContext() 发出的所有存储 API 调用均访问设备加密存储空间,包括文件数据库SharedPreferences

Context directBootContext = appContext.createDeviceProtectedStorageContext();
// Access appDataFilename that lives in device encrypted storage
FileInputStream inStream = directBootContext.openFileInput(appDataFilename);
// Use inStream to read content...

官方文档:https://developer.android.com/privacy-and-security/direct-boot?hl=zh-cn

2.3 手动初始化 WorkManager 组件

网上很多解决方案是手动完成 WorkManager 组件的初始化,对于大多数的应用是在设备解锁后使用的是可以解决的,但是在需要在设备未解锁的状态下仍需要执行任务的情况就不适用了。

停用 WorkManager 组件自动初始化

 <providerandroid:name="androidx.startup.InitializationProvider"android:authorities="${applicationId}.androidx-startup"tools:node="remove"></provider>

让你的 Application 类实现 Configuration.Provider接口,并提供您自己的 Configuration.Provider.getWorkManagerConfiguration。 当您需要使用 WorkManager 时,请务必调用 WorkManager.getInstance(Context)。 WorkManager 会调用应用的自定义 getWorkManagerConfiguration() 方法来发现其 Configuration。(无需自行调用 WorkManager.initialize。)

class MyApplication extends Application implements Configuration.Provider {@Overridepublic Configuration getWorkManagerConfiguration() {return new Configuration.Builder().setMinimumLoggingLevel(android.util.Log.INFO).build();}
}

官方文档:
https://developer.android.com/topic/libraries/app-startup?hl=zh-cn#manual
https://developer.android.com/develop/background-work/background-tasks/persistent/configuration/custom-configuration?hl=zh-cn

2.4 WorkManager 不支持 Direct Boot 的官方修改

Gerrit Commit:https://android-review.googlesource.com/c/platform/frameworks/support/+/1196948

Throw an exception when trying to initialize WorkManager in direct boot mode.* WorkManager does not support direct boot mode. Therefore when an app tries toinitialize WorkManager in direct boot mode, we now throw an IllegalStateException.Test: Added unit tests.
Change-Id: I549cca9aae0e8d5136a59719226c647dd3b1bb8b
/*** Initializes an instance of {@link WorkManagerImpl}.** @param context The application {@link Context}* @param configuration The {@link Configuration} configuration* @param workDatabase The {@link WorkDatabase} instance* @param schedulers The {@link List} of {@link Scheduler}s to use* @param processor The {@link Processor} instance*/
private void internalInit(@NonNull Context context,@NonNull Configuration configuration,@NonNull TaskExecutor workTaskExecutor,@NonNull WorkDatabase workDatabase,@NonNull List<Scheduler> schedulers,@NonNull Processor processor) {context = context.getApplicationContext();mContext = context;mConfiguration = configuration;mWorkTaskExecutor = workTaskExecutor;mWorkDatabase = workDatabase;mSchedulers = schedulers;mProcessor = processor;mPreferenceUtils = new PreferenceUtils(workDatabase);mForceStopRunnableCompleted = false;// Check for direct boot modeif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && context.isDeviceProtectedStorage()) {throw new IllegalStateException("Cannot initialize WorkManager in direct boot mode");}// Checks for app force stops.mWorkTaskExecutor.executeOnBackgroundThread(new ForceStopRunnable(context, this));
}

三、解决方案

当应用会在 Direct Boot 模式下启动并完成初始化,还需要执行相关的任务,这里需要解决 2 个问题,其一是 WorkManager 的初始化,其二是访问设备加密存储,操作文件、数据库或 SharedPreferences,否则可能会出现如下报错:

09-05 16:17:43.361  1976  2111 E AndroidRuntime: Caused by: android.database.sqlite.SQLiteCantOpenDatabaseException: Cannot open database '/data/user/0/com.xxx.devicereport/no_backup/androidx.work.workdb' with flags 0x30000000: Directory /data/user/0/com.revomovil.devicereport/no_backup doesn't exist
09-04 14:47:40.445  5355  5355 E AndroidRuntime: Caused by: java.lang.IllegalStateException: SharedPreferences in credent
ial encrypted storage are not available until after user (id 0) is unlocked

因为应用是支持 Direct Boot 模式是,所以你的应用需要声明 directBootAware

<applicationandroid:name=".DeviceReportApplication"android:directBootAware="true"android:label="@string/app_name"android:persistent="true"android:usesCleartextTraffic="true" />

规避 WorkManager 的初始化时的 IllegalStateException: Cannot initialize WorkManager in direct boot mode,根据源码处的判断将 isDeviceProtectedStorage() 返回 false 即可

public class DeviceReportApplication extends Application {private static final String TAG = "DeviceReportApplication";/*** default false to androidx.work.*/@Overridepublic boolean isDeviceProtectedStorage() {return false;}
}

因为 WokrManager 内部实现的数据库访问无法修改,所以需要全局访问设备加密存储,有 2 种方式。

可以直接在 Application 标签下声明 defaultToDeviceProtectedStorage

<applicationandroid:name=".DeviceReportApplication"android:directBootAware="true"android:defaultToDeviceProtectedStorage="true"android:label="@string/app_name"android:persistent="true"android:usesCleartextTraffic="true" />

或者在 Application 中替换全局 Context,修改 attachBaseContext

public class DeviceReportApplication extends Application {private static final String TAG = "DeviceReportApplication";@Overrideprotected void attachBaseContext(Context base) {super.attachBaseContext(base.createDeviceProtectedStorageContext());}/*** default false to androidx.work.*/@Overridepublic boolean isDeviceProtectedStorage() {return false;}
}

在这里插入图片描述

相关参考

深入了解 Jetpack WorkManager: 高效的后台任务调度

Android DirectBoot模式及其数据存储


文章转载自:

http://EUXdLkR0.snjpj.cn
http://K9DCqcim.snjpj.cn
http://1hG55T5I.snjpj.cn
http://kEHzF5nl.snjpj.cn
http://lbP7UZm0.snjpj.cn
http://B19JWTH5.snjpj.cn
http://0hallABL.snjpj.cn
http://KbJfqdVS.snjpj.cn
http://JyVqG98A.snjpj.cn
http://G3A0kPjX.snjpj.cn
http://sbABEsJK.snjpj.cn
http://OjuWart3.snjpj.cn
http://3rXH7DZX.snjpj.cn
http://Y5DXaiiA.snjpj.cn
http://E88E1mYK.snjpj.cn
http://YijvoqPU.snjpj.cn
http://WnWmsfEv.snjpj.cn
http://xNrolrGY.snjpj.cn
http://MCOp5p02.snjpj.cn
http://q9DEnf7p.snjpj.cn
http://9Y14tCeI.snjpj.cn
http://RvyNeyMq.snjpj.cn
http://OOwEUcao.snjpj.cn
http://BYvywVfL.snjpj.cn
http://fQiOi1Mz.snjpj.cn
http://V65WBeI2.snjpj.cn
http://iISEl7nJ.snjpj.cn
http://z6z7l9iB.snjpj.cn
http://ZvA7FQSX.snjpj.cn
http://gGTpZxVi.snjpj.cn
http://www.dtcms.com/a/373115.html

相关文章:

  • Prompt Engineering to Context Engineering
  • Swift 语法学习指南 - 与 Kotlin 对比
  • Redux和MobX在React Native状态管理中的优缺点对比
  • 新的一天开始2025.9.8
  • LAMPSecurity: CTF6靶场渗透
  • 服务器安装 LDOPE(MODIS 数据处理工具)
  • 动态线程池中修改核心线程数比当前线程数要少,会不会影响正在执行的线程任务
  • Axum文档 ~ 2.路由
  • 【C++】IO库
  • 常见的显示器接口技术
  • 如何在本地机器上使用LLM构建知识图谱(一)
  • 论文阅读:ACL 2023 MPCHAT: Towards Multimodal Persona-Grounded Conversation
  • Java全栈开发工程师的实战面试:从基础到微服务
  • 向量回归策略
  • 【数据库】时序数据库科学选型,以IoTDB构筑大数据时代的时序数据底座
  • MAUI劝退:安卓实体机测试
  • Day8 C++
  • 在线教程 | VibeVoice-1.5B独创双Tokenizer架构实现一次性生成90分钟4人对话语音,重新定义TTS技术边界
  • 《练手:ipv4地址计算和Telnet 远程设备管理配置实验文档》
  • [论文阅读] 人工智能 + 软件工程 | TDD痛点破解:LLM自动生成测试骨架靠谱吗?静态分析+专家评审给出答案
  • 【计算机网络 | 第10篇】信道复用技术
  • Pytest+requests进行接口自动化测试1.0(基础知识 + 测试用例 + request库)
  • 使用 OpenLayers + 高德瓦片源实现旅游足迹地图
  • 2025年体制内职业发展相关资格认证参考指南
  • window显示驱动开发—监视筛选器驱动程序(三)
  • 计算机网络:数据链路层--数据链路层基本功能
  • 第二课、熟悉Cocos Creator 编辑器界面
  • [Wit]CnOCR模型训练全流程简化记录(包括排除BUG)
  • JavaEE 进阶第四期:开启前端入门之旅(四)
  • TFS-2004《Input Selection for Nonlinear Regression Models》