Bug触发前提和操作:
-
设置为滑动解锁
-
支持双击power按键跳转相机功能
-
反复亮灭屏,并通过双击power按键唤醒相机就有几率触发此问题
Bug具体表现如下图:
keyguard壁纸图层消失,显示出了底下的camera预览界面,且当前keyguard时序错乱,解锁流程异常
分析流程:
因为是静态壁纸,所以最早的考虑可能和Systemui的LockscreenWallpaper.java 和NotificationMediaManager.java这两部分壁纸处理部可能有些问题,但通过调试验证后发现LockscreenWallpaper 默认的情况使用的是系统wallpaper图层,具体看下面loadBitmap方法注释;根据上述分析,尝试锁屏壁纸为null直接去取launcher的壁纸后测试,这个时候可以发现壁纸确实不会异常消失了,但是问题依然存在,解锁流程异常,上划解锁的时候会卡顿,有时候还要解锁两遍才行,所以这个问题并没有解决,还要继续分析,
//system/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
public LoaderResult loadBitmap(int currentUserId, UserHandle selectedUser) {
final int lockWallpaperUserId =
selectedUser != null ? selectedUser.getIdentifier() : currentUserId;
ParcelFileDescriptor fd = mWallpaperManager.getWallpaperFile(
WallpaperManager.FLAG_LOCK, lockWallpaperUserId);
//未单独设置锁屏壁纸时,锁屏壁纸为null,这里默认取的是桌面壁纸,这样NotificationMediaManager那边一直可以通过getBitmap正常取到壁纸
if(fd == null){
fd = mWallpaperManager.getWallpaperFile(WallpaperManager.FLAG_SYSTEM,lockWallpaperUserId);
}
if (fd != null) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.HARDWARE;
return LoaderResult.success(BitmapFactory.decodeFileDescriptor(
fd.getFileDescriptor(), null, options));
} else {
if (selectedUser != null) {
// Show the selected user's static wallpaper.
return LoaderResult.success(mWallpaperManager.getBitmapAsUser(
selectedUser.getIdentifier(), true /* hardware */));
} else {
//默认会走到这里,使用系统默认wallpaper图层,此时getBitmap一直为null
// When there is no selected user, show the system wallpaper
return LoaderResult.success(null);
}
}
}
初步来看不是systemui 壁纸部分的逻辑问题,可以看看是否为壁纸图层问题,重新复现此问题后通过dump SurfaceFlinger读取图层,对比正常逻辑来看,异常的时候壁纸图层消失了,然后从抓取的log分析,systemui时序也有些问题,对比正常和异常的时序log如下,keyguardGoingAway 之后没有正常去执行handleStartKeyguardExitAnimation的退出动画流程,目前来看就是没有正常退出keyguard动画导致后续时序错乱,
正常流程:
36636: 01-14 17:57:04.877845 1450 1450 D KeyguardViewMediator: handleKeyguardDone
36637: 01-14 17:57:04.877935 1450 1450 D KeyguardViewMediator: handleHide
36638: 01-14 17:57:04.877965 1450 1450 D KeyguardViewMediator: keyguardGoingAway
37048: 01-14 17:57:04.998568 1450 1450 D KeyguardViewMediator: handleStartKeyguardExitAnimation, the startTime=0 fadeoutDuration=0
37053: 01-14 17:57:04.999293 1450 1450 D KeyguardViewMediator: set mKeyguardDoneOnGoing = false
39240: 01-14 17:57:05.306755 1450 1450 D KeyguardViewMediator: onKeyguardExitRemoteAnimationFinished
39398: 01-14 17:57:05.315843 1450 1450 D KeyguardViewMediator: onKeyguardExitFinished()
39405: 01-14 17:57:05.316766 1450 1450 D KeyguardViewMediator: adjustStatusBarLocked: mShowing=false mOccluded=false isSecure=false force=false mPowerGestureIntercepted=false --> flags=0x0
39407: 01-14 17:57:05.317367 1450 1450 D KeyguardViewMediator: onKeyguardExitRemoteAnimationFinished#hideKeyguardViewAfterRemoteAnimation
39523: 01-14 17:57:05.348362 1450 1450 D KeyguardViewMediator: keyguardGone
40071: 01-14 17:57:05.393523 1450 1804 D KeyguardViewMediator: updateActivityLockScreenState(false, false)
42114: 01-14 17:57:05.705789 1450 7484 D KeyguardViewMediator: setOccluded(false)
42115: 01-14 17:57:05.705812 1450 7484 D KeyguardViewMediator: setOccluded false
异常流程:
49189: 01-14 17:57:07.474846 1450 1450 D KeyguardViewMediator: handleKeyguardDone
49190: 01-14 17:57:07.474904 1450 1450 D KeyguardViewMediator: handleHide
49191: 01-14 17:57:07.474943 1450 1450 D KeyguardViewMediator: keyguardGoingAway
53185: 01-14 17:57:08.217943 1450 6811 D KeyguardViewMediator: setOccluded(false)
53186: 01-14 17:57:08.217971 1450 6811 D KeyguardViewMediator: setOccluded false
53187: 01-14 17:57:08.218512 1450 1450 D KeyguardViewMediator: handleSetOccluded(false)
53188: 01-14 17:57:08.218645 1450 1450 D KeyguardViewMediator: isOccluded=false,mPowerGestureIntercepted=false
57112: 01-14 17:57:09.654649 1450 1450 D KeyguardViewMediator: received DELAYED_KEYGUARD_ACTION with seq = 14, mDelayedShowingSequence = 16
继续加了一些log调试,通过对比正常和异常时候日志,可以发现正常过渡动画的流程,最终是会执行TRANSIT_TO_BACK的过渡动画的,异常的时候这个操作被丢失掉了,会卡在 TRANSIT_WAKE的动画,一直到TRANSIT_WAKE被abort;而TRANSIT_TO_BACK这个过渡动画就是KeyguardController的requestTransitionIfNeeded调用产生的,并且会让壁纸可见(和异常时候表现一致,大致确定是这个动画没有正常执行的问题了)
// system/frameworks/base/services/core/java/com/android/server/wm/KeyguardController.java
void keyguardGoingAway(int displayId, int flags) {
...
final int transitFlags = convertTransitFlags(flags);
final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
dc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, transitFlags);
// We are deprecating TRANSIT_KEYGUARD_GOING_AWAY for Shell transition and use
// TRANSIT_FLAG_KEYGUARD_GOING_AWAY to indicate that it should animate keyguard going
// away.
dc.mAtmService.getTransitionController().requestTransitionIfNeeded(
TRANSIT_TO_BACK, transitFlags, null /* trigger */, dc);
updateKeyguardSleepToken();
// Make the home wallpaper visible
dc.mWallpaperController.showWallpaperInTransition(true /* showHome */);
// Some stack visibility might change (e.g. docked stack)
mRootWindowContainer.resumeFocusedTasksTopActivities();
mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
mRootWindowContainer.addStartingWindowsForVisibleActivities();
mWindowManager.executeAppTransition();
} finally {
mService.continueWindowLayout();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
继续调试,可以知道是isCollecting为true导致无法被正常创建导致;最开始尝试过滤TRANSIT_TO_BACK来调试,但后续的createTransition的有做mTransitionPlayer和mCollectingTransition 的是否为null做判断,修改对逻辑影响太大,遂放弃;继续看Transition的操作逻辑和调试的log, mCollectingTransition的collectting有超时机制,而Transition最终会去执行TransitionController.onAbort中断当前的Transition,
// system/frameworks/base/services/core/java/com/android/server/wm/TransitionController.java
Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
... ) {
if (mTransitionPlayer == null) {
return null;
}
Transition newTransition = null;
if (isCollecting()) {
...
} else {
newTransition = requestStartTransition(createTransition(type, flags),
trigger != null ? trigger.asTask() : null, remoteTransition, displayChange);
if (newTransition != null && displayChange != null && trigger != null
&& trigger.asDisplayContent() != null) {
setDisplaySyncMethod(displayChange, newTransition, trigger.asDisplayContent());
}
}
...
return newTransition;
}
/**
* @return {@code true} if transition is actively collecting changes. This is {@code false}
* once a transition is playing
*/
boolean isCollecting() {
return mCollectingTransition != null;
}
/** Called when a transition is aborted. This should only be called by {@link Transition} */
void onAbort(Transition transition) {
if (transition != mCollectingTransition) {
int waitingIdx = mWaitingTransitions.indexOf(transition);
if (waitingIdx < 0) {
throw new IllegalStateException("Too late for abort.");
}
mWaitingTransitions.remove(waitingIdx);
} else {
mCollectingTransition = null;
if (!mWaitingTransitions.isEmpty()) {
mCollectingTransition = mWaitingTransitions.remove(0);
}
if (mCollectingTransition == null) {
// nothing collecting anymore, so clear order records.
mLatestOnTopTasksReported.clear();
}
}
// This is called during Transition.abort whose codepath will eventually check the queue
// via sync-engine idle.
}
有了上述两点分析,而且TRANSIT_TO_BACK 是正常解锁后最终Transition动画,所以可以尝试针对TRANSIT_TO_BACK创建失败时候做保存操作,在上个Transition被Abort了之后重新去走TRANSIT_TO_BACK的创建流程,具体修改如下代码,然后再次测试验证ok,算是暂时修复了此问题
// system/frameworks/base/services/core/java/com/android/server/wm/TransitionController.java
+ private int waitType;
+ private int waitFlag;
+ private WindowContainer waitTrigger;
+ private WindowContainer waitReadyGroupRef
@Nullable
Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
@WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger,
@NonNull WindowContainer readyGroupRef) {
- return requestTransitionIfNeeded(type, flags, trigger, readyGroupRef,
+ // BEGIN <When the TRANSIT_TO_BACK animation fails to be added, it will be re-executed after the collection is completed.>
+ Transition mTransition = requestTransitionIfNeeded(type, flags, trigger, readyGroupRef,
null /* remoteTransition */, null /* displayChange */);
+ if (mTransition == null && type == TRANSIT_TO_BACK) {
+ waitType = type;
+ waitFlag = flags;
+ waitTrigger = trigger;
+ waitReadyGroupRef = readyGroupRef;
+ Log.e(TAG,"Add TRANSIT_TO_BACK transition until collecting finish");
+ }
+ return mTransition;
+ // END <When the TRANSIT_TO_BACK animation fails to be added, it will be re-executed after the collection is completed.>
}
/** Called when a transition is aborted. This should only be called by {@link Transition} */
void onAbort(Transition transition) {
if (transition != mCollectingTransition) {
int waitingIdx = mWaitingTransitions.indexOf(transition);
if (waitingIdx < 0) {
throw new IllegalStateException("Too late for abort.");
}
mWaitingTransitions.remove(waitingIdx);
} else {
mCollectingTransition = null;
if (!mWaitingTransitions.isEmpty()) {
mCollectingTransition = mWaitingTransitions.remove(0);
}
if (mCollectingTransition == null) {
// nothing collecting anymore, so clear order records.
mLatestOnTopTasksReported.clear();
}
+ // BEGIN <When the TRANSIT_TO_BACK animation fails to be added, it will be re-executed after the collection is completed.>
+ if (waitType == TRANSIT_TO_BACK && mCollectingTransition == null) {
+ Log.e(TAG,"come to here continue play animation");
+ waitType = -1;
+ requestTransitionIfNeeded(waitType,waitFlag,waitTrigger,waitReadyGroupRef);
+ }
+ // END <When the TRANSIT_TO_BACK animation fails to be added, it will be re-executed after the collection is completed.>
}
// This is called during Transition.abort whose codepath will eventually check the queue
// via sync-engine idle.
}
总结:
最后总结一下,这个Keyguard壁纸图层消失的问题,主要还是亮灭屏太快,framework的动画流程出现问题,前面一个Transition还没有collecting执行完毕,就执行到了TRANSIT_TO_BACK的过渡,导致过渡动画被废弃无法正常执行,目前的方案是把前面废弃的动画TRANSIT_TO_BACK重新执行,暂时解决了这个问题,另外附上调试捋出来的keyguard退出动画完整的创建过渡动画和调用的流程
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)
文章来源:https://www.toymoban.com/news/detail-836572.html
PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题
文章来源地址https://www.toymoban.com/news/detail-836572.html
到了这里,关于MTK Android 14 锁屏通知栏与相机预览界面重叠的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!