Solve the problem of recovery page inversion

1. Preface

In the customized development of Android 10.0 system ROM, the recoverv page in the system is also an important part. Functions such as system recovery TA upgrades require the recoverv function. In some product customization
During the recovery, I found that it was rotated 180 degrees. Next, I analyzed the source code related to the screen display direction of the recovery to modify this function.

2. Core class of the solution to the 180-degree problem of recovery page rotation

 bootable/recovery/minui/include/minui/minui.h
     boottable/recovery/minui/graphics.cpp

3.Core function analysis and implementation of the solution to the 180-degree problem of recovery page rotation

In the implementation of the core function of the solution to the problem of 180-degree rotation of the recovery page, in the relevant system source code in Android 10.0 Recovery, recoverv is based on the minui library under bootablerecovery and uses the method of direct access to the framebuffer. Complete the drawing of various UI required in recovery.
In the source code of recoverv, the general structure of the code related to UI display is:
resources.cpp, graphics.cpp under boottable/recovery/minui
The API provided by resources.cpp is mainly used for reading and loading image resources.
graphics.cpp is responsible for specifically completing the drawing of various types of UI. Since graphics.cpp is responsible for the drawing of various types of UI, the modification of the rotation direction must start here.

 #include "graphics.h"
     
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #include <memory>
     
    #include <android-base/properties.h>
     
    #include "graphics_adf.h"
    #include "graphics_drm.h"
    #include "graphics_fbdev.h"
    #include "minui/minui.h"
    ...
     
    int gr_measure(const GRFont* font, const char* s) {<!-- -->
      if (font == nullptr) {<!-- -->
        return -1;
      }
     
      return font->char_width * strlen(s);
    }
     
    int gr_font_size(const GRFont* font, int* x, int* y) {<!-- -->
      if (font == nullptr) {<!-- -->
        return -1;
      }
     
      *x = font->char_width;
      *y = font->char_height;
      return 0;
    }
     
     
    // Increments pixel pointer right, with current rotation.
    static void incr_x(uint32_t** p, int row_pixels) {<!-- -->
      if (rotation == GRRotation::LEFT) {<!-- -->
        *p = *p - row_pixels;
      } else if (rotation == GRRotation::RIGHT) {<!-- -->
        *p = *p + row_pixels;
      } else if (rotation == GRRotation::DOWN) {<!-- -->
        *p = *p - 1;
      } else {<!-- --> // GRRotation::NONE
        *p = *p + 1;
      }
    }
     
    // Increments pixel pointer down, with current rotation.
    static void incr_y(uint32_t** p, int row_pixels) {<!-- -->
      if (rotation == GRRotation::LEFT) {<!-- -->
        *p = *p + 1;
      } else if (rotation == GRRotation::RIGHT) {<!-- -->
        *p = *p - 1;
      } else if (rotation == GRRotation::DOWN) {<!-- -->
        *p = *p - row_pixels;
      } else {<!-- --> // GRRotation::NONE
        *p = *p + row_pixels;
      }
    }
     
     
    void gr_fill(int x1, int y1, int x2, int y2) {<!-- -->
      x1 + = overscan_offset_x;
      y1 + = overscan_offset_y;
     
      x2 + = overscan_offset_x;
      y2 + = overscan_offset_y;
     
      if (outside(x1, y1) || outside(x2 - 1, y2 - 1)) return;
     
      int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes;
      uint32_t* p = PixelAt(gr_draw, x1, y1, row_pixels);
      uint8_t alpha = static_cast<uint8_t>(((gr_current & amp; alpha_mask) >> 24));
      if (alpha > 0) {<!-- -->
        for (int y = y1; y < y2; + + y) {<!-- -->
          uint32_t* px = p;
          for (int x = x1; x < x2; + + x) {<!-- -->
            *px = pixel_blend(alpha, *px);
            incr_x( & amp;px, row_pixels);
          }
          incr_y( & amp;p, row_pixels);
        }
      }
    }
     
     
    int gr_init_font(const char* name, GRFont** dest) {<!-- -->
      GRFont* font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font)));
      if (font == nullptr) {<!-- -->
        return -1;
      }
     
      int res = res_create_alpha_surface(name, & amp;(font->texture));
      if (res < 0) {<!-- -->
        free(font);
        return res;
      }
     
      // The font image should be a 96x2 array of character images. The
      // columns are the printable ASCII characters 0x20 - 0x7f. The
      // top row is regular text; the bottom row is bold.
      font->char_width = font->texture->width / 96;
      font->char_height = font->texture->height / 2;
     
      *dest = font;
     
      return 0;
    }
    int gr_init() {<!-- -->
      // pixel_format needs to be set before loading any resources or initializing backends.
      std::string format = android::base::GetProperty("ro.minui.pixel_format", "");
      if (format == "ABGR_8888") {<!-- -->
        pixel_format = PixelFormat::ABGR;
      } else if (format == "RGBX_8888") {<!-- -->
        pixel_format = PixelFormat::RGBX;
      } else if (format == "BGRA_8888") {<!-- -->
        pixel_format = PixelFormat::BGRA;
      } else {<!-- -->
        pixel_format = PixelFormat::UNKNOWN;
      }
     
      int ret = gr_init_font("font", & amp;gr_font);
      if (ret != 0) {<!-- -->
        printf("Failed to init font: %d, continuing graphic backend initialization without font file\\
",
               ret);
      }
     
      auto backend = std::unique_ptr<MinuiBackend>{<!-- --> std::make_unique<MinuiBackendAdf>() };
      gr_draw = backend->Init();
     
      if (!gr_draw) {<!-- -->
        backend = std::make_unique<MinuiBackendDrm>();
        gr_draw = backend->Init();
      }
     
      if (!gr_draw) {<!-- -->
        backend = std::make_unique<MinuiBackendFbdev>();
        gr_draw = backend->Init();
      }
     
      if (!gr_draw) {<!-- -->
        return -1;
      }
     
      gr_backend = backend.release();
     
      int overscan_percent = android::base::GetIntProperty("ro.minui.overscan_percent", 0);
      overscan_offset_x = gr_draw->width * overscan_percent / 100;
      overscan_offset_y = gr_draw->height * overscan_percent / 100;
     
      gr_flip();
      gr_flip();
      if (!gr_draw) {<!-- -->
        printf("gr_init: gr_draw becomes nullptr after gr_flip\\
");
        return -1;
      }
     
      std::string rotation_str =
          android::base::GetProperty("ro.minui.default_rotation", "ROTATION_NONE");
      if (rotation_str == "ROTATION_RIGHT") {<!-- -->
        gr_rotate(GRRotation::RIGHT);
      } else if (rotation_str == "ROTATION_DOWN") {<!-- -->
        gr_rotate(GRRotation::DOWN);
      } else if (rotation_str == "ROTATION_LEFT") {<!-- -->
        gr_rotate(GRRotation::LEFT);
      } else {<!-- --> // "ROTATION_NONE" or unknown string
        gr_rotate(GRRotation::NONE);
      }
      rotation = GRRotation::RIGHT;//add code
      if (gr_draw->pixel_bytes != 4) {<!-- -->
        printf("gr_init: Only 4-byte pixel formats supported\\
");
      }
     
      return 0;
    }
     
    void gr_rotate(GRRotation rot) {<!-- -->
      rotation = rot;
    }

In the implementation of the core function of the solution to the recoverv page rotation problem of 180 degrees, from the above source code in graphics.cpp, it can be seen that r get width (const GRSurtace?surface) is to get the width of the screen
gr get height(const GRSurface* surface) Get the height of the screen
gr init font(const char* name.GRFont** dest) gets the font size
gr init() mainly sets the RGB and screen rotation direction. gr cear() clears some drawing screen parameters and redraws the parameters related to the screen display. Next, let’s look at the analysis of the relevant code for setting the direction of recoverv.
gr rotate(DEFAULT ROTATION):
In the gr init() method, gr rotate(DEFAULT ROTATION): sets the direction of the screen to the default direction and defines the relevant parameters of the recoverv direction in minui.h, as follows

enum GRRotation {<!-- -->
 
ROTATION_NONE = 0,
 
ROTATION_RIGHT = 1,//90
 
ROTATION_DOWN = 2,//180
 
ROTATION_LEFT = 3,//270
 
};

In the implementation of the core function of the solution to the problem of recovev page rotation of 180 degrees, according to the relevant parameters of GRRotation, we can know that ROTATION RIGHT means the screen rotates 90 degrees, and ROTATION DOWN means the screen rotates 180 degrees, and ROTATION LEFT means the screen rotates 270 degrees.
Therefore, to set the horizontal screen to flip up and down, you need to change the screen orientation to ROTATION LEFT. The specific changes are as follows:

int gr_init() {<!-- -->
 
....
 
std::string rotation_str =
 
android::base::GetProperty("ro.minui.default_rotation", "ROTATION_NONE");
 
if (rotation_str == "ROTATION_RIGHT") {<!-- -->
 
gr_rotate(GRRotation::RIGHT);
 
} else if (rotation_str == "ROTATION_DOWN") {<!-- -->
 
gr_rotate(GRRotation::DOWN);
 
} else if (rotation_str == "ROTATION_LEFT") {<!-- -->
 
gr_rotate(GRRotation::LEFT);
 
} else {<!-- --> // "ROTATION_NONE" or unknown string
 
gr_rotate(GRRotation::NONE);
 
}
 
 + rotation = GRRotation::LEFT;//add code
 
....
 
}

In the implementation of the core function of the solution to the recover page rotation problem of 180 degrees, analysis of the above source code in the above graphics.cpp shows that in gr init) it mainly sets the RGB and screen rotation direction, so it is based on the returned
The value of rotation is used to determine the rotation direction of the current screen, so through the above modification method, in gr init()
Add rotation = GRRotation:LEFT://add code as the rotation method of the current screen to ensure that the rotation is 180 degrees, which is to achieve the functional requirements.