Android横竖屏切换卡顿问题

Android横竖屏切换卡顿问题,第1张

概述今天遇到一个android系统在切换横竖屏时一直卡着不动,大概3秒以后才能转过来的问题。最后定位到是由于ScreenRotationAnimation类的构造函数调用了SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(SurfaceControl.BUILT_IN_DISPLAY_I

今天遇到一个androID系统在切换横竖屏时一直卡着不动,大概3秒以后才能转过来的问题。最后定位到是由于ScreenRotationAnimation类的构造函数调用了

SurfaceControl.screenshot(SurfaceControl.getBuiltIndisplay(                        SurfaceControl.BUILT_IN_disPLAY_ID_MAIN), sur);

进行截屏导致的。
截屏函数最终是由SurfaceFlinger完成的。在surfaceflinger中加入日志调试。

nsecs_t st = systemTime();result = flinger->captureScreenImplLocked(hw,        producer, reqWIDth, reqHeight, minLayerZ, maxLayerZ);nsecs_t et = systemTime();ALOGI("surfaceflinger captureScreenImplLocked use time:%dms", (int)ns2ms(et - st));

得到以下输出:

03-11 14:12:44.550 2259-2797/? W/ScreenRotationAnimation: SurfaceControl.screenshot use 3142ms03-11 14:13:01.950 2259-2669/? W/ScreenRotationAnimation: SurfaceControl.screenshot use 3282ms03-11 14:23:26.250 2259-2669/? W/ScreenRotationAnimation: SurfaceControl.screenshot use 3176ms03-11 14:23:36.790 2259-2668/? W/ScreenRotationAnimation: SurfaceControl.screenshot use 3239ms

为什么需要这么长时间?
最后研究发现这个时间跟SurfaceVIEw的数量还有关系,每多一个SurfaceVIEw截屏时间就多个500到600毫秒,我的界面总共添加了3个SurfaceVIEw,所以截屏时间花了3秒。
如果一个SurfaceVIEw都不添加,截屏只需要花费大概600毫秒的时间。
看了一眼captureScreenImplLocked这个函数的实现,发现这个函数很神奇,只调用了几个GL函数,截屏就完成了。

status_t SurfaceFlinger::captureScreenImplLocked(        const sp<const displayDevice>& hw,        const sp<IGraphicBufferProducer>& producer,        uint32_t reqWIDth, uint32_t reqHeight,        uint32_t minLayerZ, uint32_t maxLayerZ){    ATRACE_CALL();    // get screen geometry    const uint32_t hw_w = hw->getWIDth();    const uint32_t hw_h = hw->getHeight();    // if we have secure windows on this display, never allow the screen capture    if (hw->getSecureLayerVisible()) {        ALOGW("FB is protected: PERMISSION_DENIED");        return PERMISSION_DENIED;    }    if ((reqWIDth > hw_w) || (reqHeight > hw_h)) {        ALOGE("size mismatch (%d, %d) > (%d, %d)",                reqWIDth, reqHeight, hw_w, hw_h);        return BAD_VALUE;    }    reqWIDth = (!reqWIDth) ? hw_w : reqWIDth;    reqHeight = (!reqHeight) ? hw_h : reqHeight;    // Create a surface to render into    sp<Surface> surface = new Surface(producer);    ANativeWindow* const window = surface.get();    // set the buffer size to what the user requested    native_window_set_buffers_user_dimensions(window, reqWIDth, reqHeight);    // and create the corresponding EGLSurface    EGLSurface eglSurface = eglCreatewindowsurface(            mEGLdisplay, mEGLConfig, window, NulL);    if (eglSurface == EGL_NO_SURFACE) {        ALOGE("captureScreenImplLocked: eglCreatewindowsurface() Failed 0x%4x",                eglGetError());        return BAD_VALUE;    }    if (!eglMakeCurrent(mEGLdisplay, eglSurface, eglSurface, mEGLContext)) {        ALOGE("captureScreenImplLocked: eglMakeCurrent() Failed 0x%4x",                eglGetError());        eglDestroySurface(mEGLdisplay, eglSurface);        return BAD_VALUE;    }    renderScreenImplLocked(hw, reqWIDth, reqHeight, minLayerZ, maxLayerZ, false);    // and finishing things up...    if (eglSwapBuffers(mEGLdisplay, eglSurface) != EGL_TRUE) {        ALOGE("captureScreenImplLocked: eglSwapBuffers() Failed 0x%4x",                eglGetError());        eglDestroySurface(mEGLdisplay, eglSurface);        getDefaultdisplayDevice()->makeCurrent(mEGLdisplay, mEGLContext);        return BAD_VALUE;    }    eglDestroySurface(mEGLdisplay, eglSurface);    getDefaultdisplayDevice()->makeCurrent(mEGLdisplay, mEGLContext);    return NO_ERROR;}

不明觉厉,这个函数我是改不了了,不过还好我们这个设备是墨水屏,刷新特别慢,在旋转时不需要动画,可以想办法去掉动画,这样就不用调用截屏函数了。
首先打印一下调用堆栈,看看谁调用的截屏函数。

 	try {		throw new Exception();     } catch(Exception e) {		e.printstacktrace();     }	long st = System.currentTimeMillis();    SurfaceControl.screenshot(SurfaceControl.getBuiltIndisplay(             SurfaceControl.BUILT_IN_disPLAY_ID_MAIN), sur);					long et = System.currentTimeMillis();	Slog.w(TAG, "SurfaceControl.screenshot use " + (et - st) + "ms");

得到以下输出:

03-11 14:27:39.840 2259-2439/? W/System.err: java.lang.Exception03-11 14:27:39.840 2259-2439/? W/System.err:     at com.androID.server.wm.ScreenRotationAnimation.<init>(ScreenRotationAnimation.java:260)03-11 14:27:39.840 2259-2439/? W/System.err:     at com.androID.server.wm.WindowManagerService.startFreezingdisplayLocked(WindowManagerService.java:9945)03-11 14:27:39.840 2259-2439/? W/System.err:     at com.androID.server.wm.WindowManagerService.updateRotationUncheckedLocked(WindowManagerService.java:5960)03-11 14:27:39.840 2259-2439/? W/System.err:     at com.androID.server.wm.WindowManagerService.updateOrIEntationFromAppTokensLocked(WindowManagerService.java:3708)03-11 14:27:39.840 2259-2439/? W/System.err:     at com.androID.server.wm.WindowManagerService.updateOrIEntationFromAppTokensLocked(WindowManagerService.java:3645)03-11 14:27:39.840 2259-2439/? W/System.err:     at com.androID.server.wm.WindowManagerService.updateOrIEntationFromAppTokens(WindowManagerService.java:3633)03-11 14:27:39.840 2259-2439/? W/System.err:     at com.androID.server.am.ActivityManagerService.setRequestedOrIEntation(ActivityManagerService.java:3596)03-11 14:27:39.840 2259-2439/? W/System.err:     at androID.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:955)03-11 14:27:39.840 2259-2439/? W/System.err:     at com.androID.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2084)03-11 14:27:39.840 2259-2439/? W/System.err:     at androID.os.Binder.execTransact(Binder.java:404)03-11 14:27:39.850 2259-2439/? W/System.err:     at dalvik.system.NativeStart.run(Native Method)

根据日志查看WindowManagerService.java 9945行附近,有如下代码:

if (CUSTOM_SCREEN_ROTATION) {	mExitAnimID = exitAnim;	mEnteranimID = enteranim;	final displayContent displayContent = getDefaultdisplayContentLocked();	final int displayID = displayContent.getdisplayID();	ScreenRotationAnimation screenRotationAnimation =			mAnimator.getScreenRotationAnimationLocked(displayID);	if (screenRotationAnimation != null) {		screenRotationAnimation.kill();	}	// Todo(multidisplay): rotation on main screen only.	screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,			mFxSession, inTransaction, mPolicy.isDefaultOrIEntationForced());	mAnimator.setScreenRotationAnimationLocked(displayID, screenRotationAnimation);}

重点是if (CUSTOM_SCREEN_ROTATION) {判断条件,再搜索一下CUSTOM_SCREEN_ROTATION变量,发现只有一个初始值,中间没有任何赋值的地方。

    /**     * If true, the window manager will do its own custom freezing and general     * management of the screen during rotation.     */    static final boolean CUSTOM_SCREEN_ROTATION = true;

既然是这样,把CUSTOM_SCREEN_ROTATION 修改为false试试效果看。
哇!果然很快,就是效果有点儿差,能看得见黑屏。

总结

以上是内存溢出为你收集整理的Android横竖屏切换卡顿问题全部内容,希望文章能够帮你解决Android横竖屏切换卡顿问题所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/web/1064358.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-26
下一篇 2022-05-26

发表评论

登录后才能评论

评论列表(0条)

保存