小鱼塘--自说自话的地方

  • 小玩意
  • 小想法
记录自己技术和想法地方
  1. 首页
  2. 工具
  3. 正文

scrcpy屏幕关闭逻辑分析

17 9 月, 2024 1036点热度 0人点赞 0条评论
内容目录

背景

以前直接用scrcpy代码进行屏幕关闭,但后来手机系统升级版本没有效果了,我也没有更新代码,就一直没有管他,一直没有弄清楚的他的原理,他这个最神器地方,屏幕关闭应用还是正常跑。

思考

如果要用弄清楚关闭屏幕代码就从原来的调用函数分析代码引用

过程

一、它使用的SurfaceControl.setDisplayPowerMode 调用从而关闭屏幕
二、找他们有关的介绍

这个就说明屏幕灭屏的有关系,那么基本推测,scrcpy根据分析android 灭屏流程分析得出来调用这个函数

三、通过源代码搜索setDisplayPowerMode的引用,找到有关系的代码
Search (androidxref.com)
找到发现在LocalDisplayAdapter.java 中调用,分析这个文件可以找到几个关键函数

//这个函数可以到通过displayid 互殴displaytoken,这个就是函数关键
   private void tryConnectDisplayLocked(int builtInDisplayId) {
       IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
       if (displayToken != null) {
           SurfaceControl.PhysicalDisplayInfo[] configs =
                   SurfaceControl.getDisplayConfigs(displayToken);
           if (configs == null) {
               // There are no valid configs for this device, so we can't use it
               Slog.w(TAG, "No valid configs found for display device " +
                       builtInDisplayId);
               return;
            }
            int activeConfig = SurfaceControl.getActiveConfig(displayToken);
            if (activeConfig < 0) {
                // There is no active config, and for now we don't have the
                // policy to set one.
                Slog.w(TAG, "No active config found for display device " +
                        builtInDisplayId);
                return;
            }
            int activeColorMode = SurfaceControl.getActiveColorMode(displayToken);
            if (activeColorMode < 0) {
                // We failed to get the active color mode. We don't bail out here since on the next
                // configuration pass we'll go ahead and set it to whatever it was set to last (or
                // COLOR_MODE_NATIVE if this is the first configuration).
                Slog.w(TAG, "Unable to get active color mode for display device " +
                        builtInDisplayId);
                activeColorMode = Display.COLOR_MODE_INVALID;
            }
            int[] colorModes = SurfaceControl.getDisplayColorModes(displayToken);
            LocalDisplayDevice device = mDevices.get(builtInDisplayId);
            if (device == null) {
                // Display was added.
                device = new LocalDisplayDevice(displayToken, builtInDisplayId,
                        configs, activeConfig, colorModes, activeColorMode);
                mDevices.put(builtInDisplayId, device);
                sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
            } else if (device.updatePhysicalDisplayInfoLocked(configs, activeConfig,
                        colorModes, activeColorMode)) {
                // Display properties changed.
                sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
            }
        } else {
            // The display is no longer available. Ignore the attempt to add it.
            // If it was connected but has already been disconnected, we'll get a
            // disconnect event that will remove it from mDevices.
        }
    }
//这个设置屏幕状态
  public Runnable requestDisplayStateLocked(final int state, final int brightness) {
           // Assume that the brightness is off if the display is being turned off.
           assert state != Display.STATE_OFF || brightness == PowerManager.BRIGHTNESS_OFF;

           final boolean stateChanged = (mState != state);
           final boolean brightnessChanged = (mBrightness != brightness) && mBacklight != null;
           if (stateChanged || brightnessChanged) {
               final int displayId = mBuiltInDisplayId;
               final IBinder token = getDisplayTokenLocked();
               final int oldState = mState;

               if (stateChanged) {
                   mState = state;
                   updateDeviceInfoLocked();
               }

               if (brightnessChanged) {
                   mBrightness = brightness;
               }

               // Defer actually setting the display state until after we have exited
               // the critical section since it can take hundreds of milliseconds
               // to complete.
               return new Runnable() {
                   @Override
                   public void run() {
                       // Exit a suspended state before making any changes.
                       int currentState = oldState;
                       if (Display.isSuspendedState(oldState)
                               || oldState == Display.STATE_UNKNOWN) {
                           if (!Display.isSuspendedState(state)) {
                               setDisplayState(state);
                               currentState = state;
                           } else if (state == Display.STATE_DOZE_SUSPEND
                                   || oldState == Display.STATE_DOZE_SUSPEND) {
                               setDisplayState(Display.STATE_DOZE);
                               currentState = Display.STATE_DOZE;
                           } else if (state == Display.STATE_ON_SUSPEND
                                   || oldState == Display.STATE_ON_SUSPEND) {
                               setDisplayState(Display.STATE_ON);
                               currentState = Display.STATE_ON;
                           } else {
                               return; // old state and new state is off
                           }
                       }

                       // If the state change was from or to VR, then we need to tell the light
                       // so that it can apply appropriate VR brightness settings. Also, update the
                       // brightness so the state is propogated to light.
                       boolean vrModeChange = false;
                       if ((state == Display.STATE_VR || currentState == Display.STATE_VR) &&
                               currentState != state) {
                           setVrMode(state == Display.STATE_VR);
                           vrModeChange = true;
                       }

                       // Apply brightness changes given that we are in a non-suspended state.
                       if (brightnessChanged || vrModeChange) {
                           setDisplayBrightness(brightness);
                       }

                       // Enter the final desired state, possibly suspended.
                       if (state != currentState) {
                           setDisplayState(state);
                       }
                   }

                   private void setVrMode(boolean isVrEnabled) {
                       if (DEBUG) {
                           Slog.d(TAG, "setVrMode("
                                   + "id=" + displayId
                                   + ", state=" + Display.stateToString(state) + ")");
                       }
                       mBacklight.setVrMode(isVrEnabled);
                   }

                   private void setDisplayState(int state) {
                       if (DEBUG) {
                           Slog.d(TAG, "setDisplayState("
                                   + "id=" + displayId
                                   + ", state=" + Display.stateToString(state) + ")");
                       }

                       // We must tell sidekick to stop controlling the display before we
                       // can change its power mode, so do that first.
                       if (mSidekickActive) {
                           Trace.traceBegin(Trace.TRACE_TAG_POWER,
                                   "SidekickInternal#endDisplayControl");
                           try {
                               mSidekickInternal.endDisplayControl();
                           } finally {
                               Trace.traceEnd(Trace.TRACE_TAG_POWER);
                           }
                           mSidekickActive = false;
                       }
                       final int mode = getPowerModeForState(state);
                       Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayState("
                               + "id=" + displayId
                               + ", state=" + Display.stateToString(state) + ")");
                       try {
                           SurfaceControl.setDisplayPowerMode(token, mode);
                           Trace.traceCounter(Trace.TRACE_TAG_POWER, "DisplayPowerMode", mode);
                       } finally {
                           Trace.traceEnd(Trace.TRACE_TAG_POWER);
                       }
                       // If we're entering a suspended (but not OFF) power state and we
                       // have a sidekick available, tell it now that it can take control.
                       if (Display.isSuspendedState(state) && state != Display.STATE_OFF
                               && mSidekickInternal != null && !mSidekickActive) {
                           Trace.traceBegin(Trace.TRACE_TAG_POWER,
                                   "SidekickInternal#startDisplayControl");
                           try {
                               mSidekickActive = mSidekickInternal.startDisplayControl(state);
                           } finally {
                               Trace.traceEnd(Trace.TRACE_TAG_POWER);
                           }
                       }
                   }

                   private void setDisplayBrightness(int brightness) {
                       if (DEBUG) {
                           Slog.d(TAG, "setDisplayBrightness("
                                   + "id=" + displayId + ", brightness=" + brightness + ")");
                       }

                       Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
                               + "id=" + displayId + ", brightness=" + brightness + ")");
                       try {
                           mBacklight.setBrightness(brightness);
                           Trace.traceCounter(Trace.TRACE_TAG_POWER,
                                   "ScreenBrightness", brightness);
                       } finally {
                           Trace.traceEnd(Trace.TRACE_TAG_POWER);
                       }
                   }
               };
           }
           return null;
       }

所以scrcpy反射用到获取displaytoken 代码是上面第一个函数得出来的,你可以分析不同版本android代码,你就知道怎么适配对应版本的代码

你去搜搜LocalDisplayAdapter就有很多分析,找到很多资料,这个也是侧面验证分析逻辑是通过代码分析得到的

总结

android实现一些特别的功能基本通过分析源代码流程得出来的,这个挺有意思的,我之前看scrcpy实现点击等等,也是通过类似方法找到源代码cmd实现逻辑,我后面就全面自己做适配,高版本cmd命令完全是通用的,可以简单构建就可以快速调用。

todo

准备自己适配android 14屏幕关闭

标签: scrcpy
最后更新:17 9 月, 2024

小鱼儿

爱研究技术,爱玩LOL

点赞
< 上一篇
下一篇 >

COPYRIGHT © 2022 小鱼塘. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

湘ICP备18005349号