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
很明显crash是Launcher onCreate的时候调用LauncherAppWidgetHost.startListening,底层发生crash。
此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");
}
}
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();
}
}
}
解决上述问题后,再次测试,又有其它地方的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)
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();
}
}
致此,目前自测没有发现其它crash。如果有其它地方也有类似报错,同样处理就好了。
此问题是因为launcher加载过早,让launcher在Direct Boot模式运行,提前调用widget相关方法导致。
需要launcher自己处理widget相关的逻辑。