• User 10 must be unlocked for widgets to be available


    参考文章:

    https://blog.csdn.net/weixin_31786973/article/details/117552325
    https://blog.csdn.net/w1070216393/article/details/72722759

    问题背景:

    Android 12客户项目中,切换访客时,launcher概率性发生crash。

    问题分析

    crash log:

    E AndroidRuntime: FATAL EXCEPTION: main
    E AndroidRuntime: Process: com.tblenovo.launcher, PID: 13963
    E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tblenovo.launcher/com.android.searchlauncher.SearchLauncher}: java.lang.RuntimeException: java.lang.IllegalStateException: User 10 must be unlocked for widgets to be available
    E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3678)
    E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3835)
    E AndroidRuntime: at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5780)
    E AndroidRuntime: at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:5672)
    E AndroidRuntime: at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:71)
    E AndroidRuntime: at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
    E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2248)
    E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106)
    E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:201)
    E AndroidRuntime: at android.os.Looper.loop(Looper.java:288)
    E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7883)
    E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
    E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
    E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)
    E AndroidRuntime: Caused by: java.lang.RuntimeException: java.lang.IllegalStateException: User 10 must be unlocked for widgets to be available
    E AndroidRuntime: at com.android.launcher3.widget.LauncherAppWidgetHost.startListening(LauncherAppWidgetHost.java:115)
    E AndroidRuntime: at com.android.launcher3.Launcher.onCreate(Launcher.java:790)
    E AndroidRuntime: at com.android.launcher3.BaseQuickstepLauncher.onCreate(BaseQuickstepLauncher.java:124)
    E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8334)
    E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8314)
    E AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
    E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3649)
    E AndroidRuntime: ... 15 more
    E AndroidRuntime: Caused by: java.lang.IllegalStateException: User 10 must be unlocked for widgets to be available
    E AndroidRuntime: at android.os.Parcel.createExceptionOrNull(Parcel.java:2463)
    E AndroidRuntime: at android.os.Parcel.createException(Parcel.java:2439)
    E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:2422)
    E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:2364)
    E AndroidRuntime: at com.android.internal.appwidget.IAppWidgetService$Stub$Proxy.startListening(IAppWidgetService.java:784)
    E AndroidRuntime: at android.appwidget.AppWidgetHost.startListening(AppWidgetHost.java:222)
    E AndroidRuntime: at com.android.launcher3.widget.LauncherAppWidgetHost.startListening(LauncherAppWidgetHost.java:112)
    E AndroidRuntime: ... 21 more
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    很明显crash是Launcher onCreate的时候调用LauncherAppWidgetHost.startListening,底层发生crash。

    User 10 must be unlocked for widgets to be available

    此log在framework/base下面AppWidgetServiceImpl.java中

    private void ensureGroupStateLoadedLocked(int userId, boolean enforceUserUnlockingOrUnlocked) {
            if (enforceUserUnlockingOrUnlocked && !isUserRunningAndUnlocked(userId)) {
                throw new IllegalStateException(
                        "User " + userId + " must be unlocked for widgets to be available");
            }
            if (enforceUserUnlockingOrUnlocked && isProfileWithLockedParent(userId)) {
                throw new IllegalStateException(
                        "Profile " + userId + " must have unlocked parent");
            }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Log提示信息是因为没有解锁设备,去刷新widget导致此问题。

    Android 7.0引入了Direct Boot模式,当手机已经通电开机但是用户并有解锁锁屏的时候,Android N运行于一个安全的模式,也就是Dierect Boot模式。
    也就是这个时候不能去更新widget。如果launcher提前加载,需要特殊处理这个地方。

    解决方案

    在LauncherAppWidgetHost.startListening添加判断,如果没有解锁,则不进行相关处理,等解锁后再执行。

    private static final int FLAG_UNLOCK_DELAY_LISTENING = 1 << 4;
    ...
    //添加解锁监听,解锁后判断是否要执行相应的逻辑startListening
    screenListener = new ScreenListener(mContext);
    screenListener.begin(new ScreenListener.ScreenStateListener() {
        @Override
        public void onUserPresent() {
            if (isUnlockDelayListening()){
    			startListening();
            }
            mFlags &= ~FLAG_UNLOCK_DELAY_LISTENING;
        }
    });
    ...
    	@Override
        public void startListening() {
            if (WidgetsModel.GO_DISABLE_WIDGETS) {
                return;
            }
            final int userId = UserHandle.myUserId();
            //判断是否解锁,如果没有解锁,更新标志位,解锁后再执行。
            Log.d(TAG,"startListening# userId: "+userId);
            if(!StorageManager.isUserKeyUnlocked(userId)){
                mFlags |= FLAG_UNLOCK_DELAY_LISTENING;
                return;
            }else{
                mFlags &= ~FLAG_UNLOCK_DELAY_LISTENING;
            }
            mFlags |= FLAG_LISTENING;
            try {
                super.startListening();
            } catch (Exception e) {
                if (!Utilities.isBinderSizeError(e)) {
                    throw new RuntimeException(e);
                }
                // We're willing to let this slide. The exception is being caused by the list of
                // RemoteViews which is being passed back. The startListening relationship will
                // have been established by this point, and we will end up populating the
                // widgets upon bind anyway. See issue 14255011 for more context.
            }
            // We go in reverse order and inflate any deferred widget
            for (int i = mViews.size() - 1; i >= 0; i--) {
                LauncherAppWidgetHostView view = mViews.valueAt(i);
                if (view instanceof DeferredAppWidgetHostView) {
                    view.reInflate();
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    crash log 2

    解决上述问题后,再次测试,又有其它地方的crash问题。报错依然是User 10 must be unlocked for widgets to be available。

    E AndroidRuntime: FATAL EXCEPTION: main
    E AndroidRuntime: Process: com.tblenovo.launcher, PID: 15694
    E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tblenovo.launcher/com.android.searchlauncher.SearchLauncher}: java.lang.IllegalStateException: User 10 must be unlocked for widgets to be available
    E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3678)
    E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3835)
    E AndroidRuntime: at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5780)
    E AndroidRuntime: at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:5672)
    E AndroidRuntime: at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:71)
    E AndroidRuntime: at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
    E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2248)
    E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106)
    E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:201)
    E AndroidRuntime: at android.os.Looper.loop(Looper.java:288)
    E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7883)
    E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
    E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
    E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)
    E AndroidRuntime: Caused by: java.lang.IllegalStateException: User 10 must be unlocked for widgets to be available
    E AndroidRuntime: at android.os.Parcel.createExceptionOrNull(Parcel.java:2463)
    E AndroidRuntime: at android.os.Parcel.createException(Parcel.java:2439)
    E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:2422)
    E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:2364)
    E AndroidRuntime: at com.android.internal.appwidget.IAppWidgetService$Stub$Proxy.getAppWidgetInfo(IAppWidgetService.java:1240)
    E AndroidRuntime: at android.appwidget.AppWidgetManager.getAppWidgetInfo(AppWidgetManager.java:909)
    E AndroidRuntime: at com.android.launcher3.widget.WidgetManagerHelper.getLauncherAppWidgetInfo(WidgetManagerHelper.java:64)
    E AndroidRuntime: at com.android.launcher3.Launcher.inflateAppWidget(Launcher.java:3184)
    E AndroidRuntime: at com.android.launcher3.Launcher.bindItems(Launcher.java:3048)
    E AndroidRuntime: at com.android.launcher3.Launcher.bindItems(Launcher.java:2999)
    E AndroidRuntime: at com.android.launcher3.model.BaseLoaderResults$WorkspaceBinder.lambda$bindAppWidgets$8(BaseLoaderResults.java:258)
    E AndroidRuntime: at com.android.launcher3.model.BaseLoaderResults$WorkspaceBinder$$ExternalSyntheticLambda4.execute(Unknown Source:2)
    E AndroidRuntime: at com.android.launcher3.model.BaseLoaderResults$WorkspaceBinder.lambda$executeCallbacksTask$9$com-android-launcher3-model-BaseLoaderResults$WorkspaceBinder(BaseLoaderResults.java:268)
    E AndroidRuntime: at com.android.launcher3.model.BaseLoaderResults$WorkspaceBinder$$ExternalSyntheticLambda8.run(Unknown Source:4)
    E AndroidRuntime: at com.android.launcher3.util.LooperExecutor.execute(LooperExecutor.java:45)
    E AndroidRuntime: at com.android.launcher3.model.BaseLoaderResults$WorkspaceBinder.executeCallbacksTask(BaseLoaderResults.java:263)
    E AndroidRuntime: at com.android.launcher3.model.BaseLoaderResults$WorkspaceBinder.bindAppWidgets(BaseLoaderResults.java:257)
    E AndroidRuntime: at com.android.launcher3.model.BaseLoaderResults$WorkspaceBinder.bind(BaseLoaderResults.java:205)
    E AndroidRuntime: at com.android.launcher3.model.BaseLoaderResults$WorkspaceBinder.access$000(BaseLoaderResults.java:128)
    E AndroidRuntime: at com.android.launcher3.model.BaseLoaderResults.bindWorkspace(BaseLoaderResults.java:92)
    E AndroidRuntime: at com.android.launcher3.LauncherModel.startLoader(LauncherModel.java:391)
    E AndroidRuntime: at com.android.launcher3.LauncherModel.addCallbacksAndLoad(LauncherModel.java:352)
    E AndroidRuntime: at com.android.launcher3.Launcher.onCreate(Launcher.java:817)
    E AndroidRuntime: at com.android.launcher3.BaseQuickstepLauncher.onCreate(BaseQuickstepLauncher.java:124)
    E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8334)
    E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8314)
    E AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    log分析:
    Launcher.inflateAppWidget填充widget信息时,调用底层方法报错。
    解决思路同上。
    在LauncherModel.startLoader中,bindWorkspace前进行判断。

    	public boolean startLoader() {
            // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
            ItemInstallQueue.INSTANCE.get(mApp.getContext())
                    .pauseModelPush(ItemInstallQueue.FLAG_LOADER_RUNNING);
            synchronized (mLock) {
                // Don't bother to start the thread if we know it's not going to do anything
                final Callbacks[] callbacksList = getCallbacks();
                if (callbacksList.length > 0) {
                    // Clear any pending bind-runnables from the synchronized load process.
                    for (Callbacks cb : callbacksList) {
                        MAIN_EXECUTOR.execute(cb::clearPendingBinds);
                    }
    
                    // If there is already one running, tell it to stop.
                    stopLoader();
                    LoaderResults loaderResults = new LoaderResults(
                            mApp, mBgDataModel, mBgAllAppsList, callbacksList);
                    final int userId = UserHandle.myUserId();
                    isUserRunningAndUnlocked = UserCache.INSTANCE.get(mApp.getContext()).isUserRunningAndUnlocked(userId);
                    Log.d(TAG,"startLoader# userId: "+userId + " isUserRunningAndUnlocked: "+isUserRunningAndUnlocked);
                    if (isUserRunningAndUnlocked){//添加判断,如果没有解锁,则不做处理,不开始bind桌面图标和widget
                        if (mModelLoaded && !mIsLoaderTaskRunning) {
                            // Divide the set of loaded items into those that we are binding synchronously,
                            // and everything else that is to be bound normally (asynchronously).
                            loaderResults.bindWorkspace();
                            // For now, continue posting the binding of AllApps as there are other
                            // issues that arise from that.
                            loaderResults.bindAllApps();
                            loaderResults.bindDeepShortcuts();
                            loaderResults.bindWidgets();
                            return true;
                        } else {
                            startLoaderForResults(loaderResults);
                        }
                    }
                }
            }
            return false;
        }
    
        public void validateModelDataOnResume() {
            MODEL_EXECUTOR.getHandler().removeCallbacks(mDataValidationCheck);
            MODEL_EXECUTOR.post(mDataValidationCheck);
    
            final int userId = UserHandle.myUserId();
            boolean isUserRunningAndUnlocked = UserCache.INSTANCE.get(mApp.getContext()).isUserRunningAndUnlocked(userId);
            Log.d(TAG,"validateModelDataOnResume# userId: "+userId + " isUserRunningAndUnlocked: "+isUserRunningAndUnlocked + " this.isUserRunningAndUnlocked: "+this.isUserRunningAndUnlocked+" mLoaderTask "+mLoaderTask);
            if (!this.isUserRunningAndUnlocked && isUserRunningAndUnlocked){//onResume的时候,判断标志位,rebind
            Log.d(TAG,"validateModelDataOnResume isUserRunningAndUnlocked# widget not bind,need reload ");
                rebindCallbacks();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    致此,目前自测没有发现其它crash。如果有其它地方也有类似报错,同样处理就好了。

    后续总结

    此问题是因为launcher加载过早,让launcher在Direct Boot模式运行,提前调用widget相关方法导致。
    需要launcher自己处理widget相关的逻辑。

  • 相关阅读:
    链表合并(暑假每日一题 3)
    AndroidStudio连接真机测试运行
    “2024杭州智慧城市及安防展会”将于4月在杭州博览中心盛大召开
    前后缀分解
    Simple-BEV: What Really Matters for Multi-Sensor BEV Perception? 论文笔记
    C++ Reference: Standard C++ Library reference: C Library: cwchar: wcstod
    ROS总结理解
    SPA项目开发之CRUD+表单验证
    达之云BI平台助力中国融通集团陕西军民服务社有限公司实现数字化运营
    《第一行代码》读书笔记(1)—系统架构
  • 原文地址:https://blog.csdn.net/a396604593/article/details/124967835