Android overdraw automation

Android over-drawing refers to the fact that a certain pixel on the screen is drawn multiple times (more than once) within the same frame time. Serious over-drawing will waste cpu and gpu resources and cause performance problems. Google Editors' Choice requires overdrawing of app pages, so all pages need to be overdrawn. In the daily version testing process, we rely entirely on manual testing to test whether the page has overdrawing problems. However, there are nearly 80 different pages in the App, and all manual testing is time-consuming and labor-intensive. Therefore, in the daily version test takeover strategy, only overdraw manual tests are performed for newly added pages. Therefore, how to efficiently perform all page overdrawing tests and actually incorporate them into the version testing process, so as to ensure that all pages of the app do not have serious overdrawing problems.

influence

  • Does not meet Editors' Choice requirements for an app 's impeccable quality
  • On low-end machines, for example, in the case of listView sliding up and down and over-drawing, drawing multiple times within the same frame time may cause frame loss, which may lead to stuttering, or obvious jumping.

How to find

manual testing

During the daily test, follow the steps below to turn on the option of Show GPU Overrdraw to test whether the current page is overdrawn:

设置 -> 开发者选项 -> 调试GPU过度绘制 -> 显示GPU过度绘制

Since there are many different pages in the App, all manual testing is time-consuming and labor-intensive, so it is necessary to consider whether it can be automated.

Automate overdraw testing

Implementation plan research

Get the overdraw overdrawCounter value in real time

By reading the Android source code and looking at the over-drawing implementation code /frameworks/base/libs/hwui/OpenGLRenderer.cpp, I understand its implementation principle:


void OpenGLRenderer::renderOverdraw() {
        ......

        // 1x overdraw
        mCaches.stencil.enableDebugTest(2);
        drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);

        // 2x overdraw
        mCaches.stencil.enableDebugTest(3);
        drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);

        // 3x overdraw
        mCaches.stencil.enableDebugTest(4);
        drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);

        // 4x overdraw and higher
        mCaches.stencil.enableDebugTest(4, true);
        drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);

        mCaches.stencil.disable();
    }
}

void OpenGLRenderer::countOverdraw() {
    size_t count = mWidth * mHeight;
    uint32_t* buffer = new uint32_t[count];
    glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);

    size_t total = 0;
    for (size_t i = 0; i < count; i++) {
        total += buffer[i] & 0xff;
    }

    mOverdraw = total / float(count);

    delete[] buffer;
}

After each view of Android is drawn through the drawColor function, according to the number of pixel redraws, different colors are redrawn on the interface to identify the overdrawing of the pixel. At the same time, there is a countOverdraw value here, and we can use this indicator to measure the degree of Overdraw.
Since the code here belongs to the code of c, the value cannot be obtained. Continue to check the call and find that the value is used in Framework/base/core/Java/android/view/HardwareRender.java.

private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
            final String text = String.format(\"%.2fx\", overdraw);
            final Paint paint = setupPaint(density);
            // HSBtoColor will clamp the values in the 0..1 range
            paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
            canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
}

Based on the above source code analysis, we can get OverdrawCounter through hook to measure the degree of Overdraw.

Toggle debugGPUoverdraw mode

This function can be executed only when debugGPUoverdraw switches the Show Overdraw Counter mode in the Setting of the device. The code for switching debugGPUoverdraw in the Android source code is as follows:

private void writeDebugHwOverdrawOptions(Object newValue) {
   SystemProperties.set(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY,
           newValue == null ? "" : newValue.toString());
   pokeSystemProperties();
   updateDebugHwOverdrawOptions();
}

Since there are APIs hidden by the Android system in the above code, it cannot be called directly, but this function can be implemented through reflection. The specific implementation code is as follows:

public void writeDebugHwOverdrawOptions() {

        Class clz = null;
        try {
            clz = Class.forName("android.os.ServiceManager");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Method method = null;
        Method methodcheckService = null;
        try {
            method = clz.getMethod("listServices");
            methodcheckService = clz.getMethod("checkService", String.class);

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        String[] services = null;
        try {
            services = (String[]) method.invoke(clz);
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        Parcel data = null;
        for (String service : services) {
            IBinder obj = null;
            try {
                obj = (IBinder) methodcheckService.invoke(clz, service);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            if (obj != null) {
                data = Parcel.obtain();
                try {
                    obj.transact(SYSPROPS_TRANSACTION, data, null, 0);
                } catch (RemoteException e) {
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            data.recycle();
        }
    }

Referring to the execution process of the debugGPUoverdraw switching option in Setting in the Android source code, by modifying the system property debug.hwui.overdraw to be empty/count/show, the function that notifies all services in the system is executed to realize the switching option. At the same time, it can avoid turning on over-drawing all the time, which will cause the phone to freeze.

However, the drawOverdrawCounter function is only implemented in the source code of Android 4.4.4, and was removed after Android 5.0. This solution can only be implemented on Android 4.4.4. Through the actual comparison, it is found that over-drawing is consistent on different operating system versions, so the solution is still feasible.

Implementation

Get the current page overdraw OverdrawCounter value in real time
  • Create a new Android 4.4.4 emulator and install the Xposed framework
  • Get the overdrawing Counter value through the method drawOverdrawCounter of the inner class android.view.HardwareRenderer$GlRenderer of the hook system function android.view.HardwareCanvas
  • The value is saved in /sdcard/overDraw.txt in real time, which can be obtained through adb -s deviceid shell cat /sdcard/overDraw.txt
Overdraw UI Automation

Combined with appium's android ui automation, when each case enters the specified page, it collects over-drawn values ​​and screenshots, and finally displays the data. When entering the specified page, open the Count mode of debugGPUoverdraw, and get the OverdrawCounter. If the OverdrawCounter is greater than 3, it is considered to be overdraw, switch to the show mode, and take a screenshot and save it in the out/ directory. Then turn off debugGPUoverdraw to avoid performance problems affecting the case success rate when it is turned on all the time. After executing the last case, generate an html report, click the corresponding histogram to jump to the corresponding screenshot

  • UI executes to the specified page
  • Switch to count mode and get the OverdrawCounter value
  • If the OverdrawCounter value is greater than 3, switch show mode, screenshot
  • Close debugGPUoverdraw, the use case is over

bug workaround

In res/layout/shipping_package_header.xml, remove the extra background color of android:background=”@color/white”.

     android:id="@+id/ll_shipping_package"
     android:layout_width="match_parent"
     android:layout_height="match_parent" 
-    android:background="@color/white"
     android:orientation="vertical">
     <LinearLayout

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326541448&siteId=291194637