Gains and Reflections on Adapting Android System for Xiaomi Mi Pad 2

Gains and Reflections on Adapting Android System for Xiaomi Mi Pad 2

I have a wish: to run a 64-bit Android 9.0 on the Xiaomi Mi Pad 2. The compatibility of 64-bit Android 9.0’s houdini is excellent. I once tried to implant houdini 9 into Android_x86-9.0 r2 and then installed it on the Xiaomi Mi Pad 2. I found that the apps ran very stably, and the common app crash issues on Xiaomi Mi Pad 2’s Android system were almost nonexistent. However, due to the graphics card limitations, Android_x86-9.0 r2 can only run in nomodeset mode on the Xiaomi Mi Pad 2, leading to severe system lag due to CPU video decoding.

The goal is beautiful, but for a novice in Android adaptation, achieving this goal must be done step by step.

I have the lineage13.0 for latte (the codename for Xiaomi Mi Pad 2) source code that can be compiled successfully. Lineage13.0 is based on Android 6. To narrow the gap and reduce difficulty, I decided to start with adapting lineage14.1 for the Xiaomi Mi Pad 2, as lineage14.1 is based on Android 7, which has smaller changes compared to Android 6 than Android 9.

Although the adaptation work is not yet complete, I have gained a lot from the process. Here are some summaries.

1. Downloading Source Code

The main source code for lineage14.1 can be downloaded according to the instructions on the LineageOS Wiki, while the vendor, device, and kernel for latte come from Github (LineageOS Resources for Xiaomi Mi Pad 2). However, when configuring local_mainifest.xml, be careful: do not use the vendor, device, and kernel from the cm-14.1 branch, as it has too many bugs, and adapting based on it will be a huge workload with many incomprehensible issues. It is recommended to use the cm-13.0 branch because it has been successfully adapted on lineage13.0 for latte and has no inherent problems; what needs to be done is to debug lineage14.1.

2. Getting Logs

The lineage14.1 ROM compiled initially often fails to run on the Xiaomi Mi Pad 2, and logs need to be checked to analyze the reason. However, if the system has not reached the appropriate stage, logs cannot be obtained through ADB. What to do? A group friend, ygjsz, provided a method.

Add the following code to init.rc:

# Take logs even when adb is not working.
# Thanks: markakash
# Add these lines to your init.rc file:

service boot_lc_main /system/bin/logcat -f /cache/boot_lc_main.txt
    class main
    user root
    group root system
    oneshot

service boot_dmesg /system/bin/sh -c "dmesg > /cache/boot_dmesg.txt"
    class main
    user root
    group root system
    oneshot

on property:sys.boot_completed=1
    start boot_lc_main
    start boot_dmesg

This code will automatically log to the cache folder after booting. When the system fails to start, press and hold the power button + volume up button to enter Recovery mode, and you can copy out the logs for analysis.

3. Handling dlopen failed Error

The logs often show a dlopen failed error in the form of cannot locate symbol “_ZNxxxx” referenced by “xxxxx.so”, for example:

dlopen failed: cannot locate symbol "_ZN7android13GraphicBufferC1Ejjij" referenced by "/system/vendor/lib/hw/hwcomposer.gmin.so"

It is important to understand what the symbol “_ZN7androidxxxxxx” is. In simple terms, it is an alias for a function that is automatically generated during the compilation of the so file. This function originally has an easily understandable name in the source code, but during compilation, the compiler generates a symbol for it. This symbol has uniqueness, and the generation rules are related to the function name, number of parameters, and parameter types. The system can locate the specific function in the dynamic library based on it during runtime.

The first step to solve this error is to locate this function. However, since the generation rules are unknown, it is impossible to directly decode the symbol to locate the function source code. But I found a method.

The xxxxx.so mentioned in the error is generally located in system/vendor/lib. Since we are using the lineage13.0 for latte’s vendor, the symbol that cannot be found in lineage14.1 must be found in lineage13.0. Therefore, you can first look in lineage13.0 to determine which source file the function is located in, and then check why this file is missing in lineage14.1.

For example, for the error dlopen failed: cannot locate symbol “_ZN7android13GraphicBufferC1Ejjij” referenced by “/system/vendor/lib/hw/hwcomposer.gmin.so”:

First, check which dynamic link library in lineage13.0 contains “_ZN7android13GraphicBufferC1Ejjij”:

butterfly@Amazon:~/lineage/13.0/out/target/product/latte/system/lib$ find -type f -name '*.so' | xargs grep "_ZN7android13GraphicBufferC1Ejjij"

The following results appear:

Matched in binary file ./libstagefright_wfd.so
Matched in binary file ./libshim_camera.so
Matched in binary file ./libgui.so
Matched in binary file ./hw/camera.gmin.so
Matched in binary file ./arm/libgui.so
Matched in binary file ./arm/libui.so
Matched in binary file ./arm/nb/libgui.so
Matched in binary file ./arm/nb/libui.so
Matched in binary file ./libui.so
Matched in binary file ./libwebviewchromium_plat_support.so

This indicates that these so dynamic link files all contain “_ZN7android13GraphicBufferC1Ejjij”. However, having it does not mean that this function is in this file; it may just be that this file calls this function. So which one is the called file?

Execute the following command on each of these files:

butterfly@Amazon:~/lineage/13.0$ ~/Android/Sdk/ndk/16.1.4479499/toolchains/x86_64-4.9/prebuilt/linux-x86_64/bin/x86_64-linux-android-gcc-nm -D ~/lineage/13.0/out/target/product/latte/system/lib/libui.so | grep GraphicBuffer | sort

In the command, “GraphicBuffer” is a segment of literal meaning in the symbol; it is generally a part of the function name.

The following results appear:

00007930 T _ZN7android13GraphicBufferC1Ev
00007930 T _ZN7android13GraphicBufferC2Ev
00007a20 T _ZN7android13GraphicBufferC1Ejjij
00007a20 T _ZN7android13GraphicBufferC2Ejjij
00007b30 T _ZN7android13GraphicBuffer8initSizeEjjij
00007c00 T _ZN7android13GraphicBufferC1EjjijjP13native_handleb
......

You can see that the third line is the symbol we are looking for, and it has a hexadecimal string 00007a20 in front of it, indicating that this symbol corresponds to an actual function in this so file. If the symbol does not have a hexadecimal string in front of it, it indicates that this symbol appears in this file only because this file calls this function from another library. By this method, we can find the so file that contains this function. In this example, it is system/lib/libui.so (actually, there is a way to reduce the workload without checking each so file: use the Cutter tool to open hwcomposer.gmin.so and check its dependent libraries, only analyze the so files that are its dependencies).

In the previous command, the path of x86_64-linux-android-gcc-nm is its installation location on the computer, which is installed at ~/Android/Sdk/ndk/16.1.4479499/toolchains/x86_64-4.9/prebuilt/linux-x86_64/bin/.

Next, check the exact function name and parameters of this so file. Execute the following command on system/lib/libui.so (which is similar to the previous command but adds a “-C”):

butterfly@Amazon:~/lineage/13.0$ ~/Android/Sdk/ndk/16.1.4479499/toolchains/x86_64-4.9/prebuilt/linux-x86_64/bin/x86_64-linux-android-gcc-nm -C -D ~/lineage/13.0/out/target/product/latte/system/lib/libui.so | grep GraphicBuffer | sort

The following results appear:

00007930 T android::GraphicBuffer::GraphicBuffer()
00007930 T android::GraphicBuffer::GraphicBuffer()
00007a20 T android::GraphicBuffer::GraphicBuffer(unsigned int, unsigned int, int, unsigned int)
00007a20 T android::GraphicBuffer::GraphicBuffer(unsigned int, unsigned int, int, unsigned int)
00007b30 T android::GraphicBuffer::initSize(unsigned int, unsigned int, int, unsigned int)
00007c00 T android::GraphicBuffer::GraphicBuffer(unsigned int, unsigned int, int, unsigned int, unsigned int, native_handle*, bool)
00007c00 T android::GraphicBuffer::GraphicBuffer(unsigned int, unsigned int, int, unsigned int, unsigned int, native_handle*, bool)
00007d00 T android::GraphicBuffer::GraphicBuffer(ANativeWindowBuffer*, bool)
00007d00 T android::GraphicBuffer::GraphicBuffer(ANativeWindowBuffer*, bool)
00007e10 T android::GraphicBuffer::~GraphicBuffer()
00007e10 T android::GraphicBuffer::~GraphicBuffer()
......

We find that the line 00007a20 corresponds to GraphicBuffer::GraphicBuffer(unsigned int, unsigned int, int, unsigned int), which is the name and parameters of that function.

Then search for the function source code. Execute the following command:

butterfly@Amazon:~/lineage/13.0$ find -type f -name '*.mk' | xargs grep "LOCAL_MODULE := libui"

The result appears:

./frameworks/native/libs/ui/Android.mk:LOCAL_MODULE := libui

This indicates that the source code for libui is in frameworks/native/libs/ui/. Enter this folder and run:

butterfly@Amazon:~/lineage/13.0/frameworks/native/libs/ui$ find -type f -name '*.cpp' | xargs grep "GraphicBuffer::GraphicBuffer("

The result appears:

./GraphicBuffer.cpp:GraphicBuffer::GraphicBuffer()
./GraphicBuffer.cpp:GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
./GraphicBuffer.cpp:GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
./GraphicBuffer.cpp:GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership)

At this point, we can confirm that the symbol corresponds to a function in frameworks/native/libs/ui/GraphicBuffer.cpp.

Open ~/lineage/13.0/frameworks/native/libs/ui/GraphicBuffer.cpp, and you can find GraphicBuffer::GraphicBuffer(unsigned int, unsigned int, int, unsigned int). Open the same named file in Lineage14.1, and although it also has the GraphicBuffer::GraphicBuffer function, there are no parameters of (unsigned int, unsigned int, int, unsigned int) among all the GraphicBuffer functions.

Now we can solve the dlopen failed error: refer to the function content in lineage13.0 and add the same parameter GraphicBuffer function in lineage14.1. How to write this function needs to be analyzed on a case-by-case basis, that is, it should achieve its intended functionality without breaking the existing functions.

After adding, compile it, let the tablet enter REC mode, copy the newly generated out/target/product/latte/system/lib/libui.so from lineage14.1 to the tablet, and then boot to obtain logs. You can see that the dlopen failed error no longer appears.

Other dlopen failed errors can also be solved using this method.

However, there is a similar error that requires a different approach, with the error form: Can’t locate symbol “ufoInitPlatform” referenced by ……

This issue troubled me for a long time until I discovered that there are two libskuwa.so files in the system, one in system/lib and one in vendor/lib. By default, the one in system/lib is called, but that one does not have the ufoInitPlatform function. The solution is to delete the libskuwa.so in system/lib.

Through these previous handling methods, I successfully achieved the boot animation display on the Xiaomi Mi Pad 2.

4. Current Difficulties Encountered

The adaptation work is still progressing slowly, and I constantly encounter new problems. Currently, there are three main issues that I do not know how to analyze.

1. keymaster

The following repeated error appears in the logs:

3336  3336 I keystore: Found keymaster0 module Keymaster Intel MEI HAL, version 3
3336  3336 I SoftKeymaster: system/keymaster/soft_keymaster_device.cpp, Line 131: Creating device
3336  3336 D SoftKeymaster: system/keymaster/soft_keymaster_device.cpp, Line 132: Device address: 0xf6eb0000
3336  3336 I ITEEKeyMaster: intel_mei_km_open called
3336  3336 I ITEEKeyMaster: Connected to keymasterd successfully
3336  3336 I ITEEKeyMaster: get_supported_classes called
2904  3337 E ITEEKeyMasterD: Could not acquire wake lock ret = -2
3336  3336 E ITEEKeyMaster: Received error -2 on command 0 from FW
3336  3336 E ITEEKeyMaster: CMD_ID_GET_SUPPORTED_CLASSES failed
3336  3336 E keystore: Error opening keystore keymaster0 device.
3336  3336 E keystore: keystore keymaster could not be initialized; exiting

I can trace the error back to keystore.gmin.so, and since I do not have its source code, I cannot analyze it further.

I tried replacing keystore.gmin.so with keystore.default.so, and the error in the logs disappeared, changing to the following content, but I am not sure if it is resolved.

3045  3045 I keystore: Found keymaster0 module Keymaster OpenSSL HAL, version 2
3045  3045 I SoftKeymaster: system/keymaster/soft_keymaster_device.cpp, Line 131: Creating device
3045  3045 D SoftKeymaster: system/keymaster/soft_keymaster_device.cpp, Line 132: Device address: 0xf6eb0000
3045  3045 I keystore: Keymaster0 module is software-only.  Using SoftKeymasterDevice instead.

2. sensorhubd

The error is as follows, and I do not know how to analyze it.

3335  3335 F libc    : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 3335 (sensorhubd)
3338  3338 E         : debuggerd: Unable to connect to activity manager (connect failed: Connection refused)
3338  3338 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
3338  3338 F DEBUG   : LineageOS Version: '14.1-20220120-UNOFFICIAL-latte'
3338  3338 F DEBUG   : Build fingerprint: 'Xiaomi/latte/latte:5.1/LMY47I/V8.2.2.0.LACCNDL:user/release-keys'
3338  3338 F DEBUG   : Revision: '0'
3338  3338 F DEBUG   : ABI: 'x86'
3338  3338 F DEBUG   : pid: 3335, tid: 3335, name: sensorhubd  >>> /system/bin/sensorhubd <<<
3338  3338 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
3338  3338 F DEBUG   :     eax 00000001  ebx f733fdcc  ecx 00000000  edx f7747371
3338  3338 F DEBUG   :     esi f6d1900c  edi f745f010
3338  3338 F DEBUG   :     xcs 00000023  xds 0000002b  xes 0000002b  xfs 00000003  xss 0000002b
3338  3338 F DEBUG   :     eip f6dd92ce  ebp ffb37a18  esp ffb37a18  flags 00010286
3338  3338 F DEBUG   : 
3338  3338 F DEBUG   : backtrace:
3338  3338 F DEBUG   :     #00 pc 000062ce  /system/lib/libcutils.so (android_atomic_inc+14)
3338  3338 F DEBUG   :     #01 pc 00008f6d  /system/lib/libaware_client.so (_ZNK7android12SharedBuffer7acquireEv+29)
3338  3338 F DEBUG   :     #02 pc 00005470  /system/lib/libaware_client.so (_ZN7android7String8C1Ev+32)
3338  3338 F DEBUG   :     #03 pc 000074b1  /system/lib/libEGL.so
3338  3338 F DEBUG   :     #04 pc 0000b91b  /system/bin/linker (__dl__ZN6soinfo13call_functionEPKcPFvvE+139)
3338  3338 F DEBUG   :     #05 pc 0000b803  /system/bin/linker (__dl__ZN6soinfo10call_arrayEPKcPPFvvEjb+323)
3338  3338 F DEBUG   :     #06 pc 00009423  /system/bin/linker (__dl__ZN6soinfo17call_constructorsEv+371)
3338  3338 F DEBUG   :     #07 pc 0000937a  /system/bin/linker (__dl__ZN6soinfo17call_constructorsEv+202)
3338  3338 F DEBUG   :     #08 pc 0000937a  /system/bin/linker (__dl__ZN6soinfo17call_constructorsEv+202)
3338  3338 F DEBUG   :     #09 pc 0000937a  /system/bin/linker (__dl__ZN6soinfo17call_constructorsEv+202)
3338  3338 F DEBUG   :     #10 pc 0000937a  /system/bin/linker (__dl__ZN6soinfo17call_constructorsEv+202)
3338  3338 F DEBUG   :     #11 pc 00010ec2  /system/bin/linker (__dl__ZL29__linker_init_post_relocationR19KernelArgumentBlockj+7746)
3338  3338 F DEBUG   :     #12 pc 0000efb6  /system/bin/linker (__dl___linker_init+630)
579  3338  3338 F DEBUG   :     #14 pc 0001c4f3  /system/bin/linker (__dl__start+35)

After deleting system/bin/sensorhubd, the error disappeared, but the problem is definitely not resolved.

3. Preloading Shared Libraries

After dealing with the previous two errors, the logs stopped at the following line, and I do not know how to analyze it. I need to brush up on some knowledge about Android system startup.

3054  3054 I Zygote  : Preloading shared libraries...

5. Some Insights

I do not know whether I will succeed in the end, but it is necessary to summarize from time to time.

  1. The goal of adapting a higher version of Android for the Xiaomi Mi Pad 2 provides me with a strong motivation to learn. The methods and tools I have explored, as well as many small and miscellaneous gains that are inconvenient to record, are all driven by this motivation. I can confidently say that without this goal, I would not be able to persist in self-learning so many things, which aligns well with the Feynman learning technique.

  2. Without sufficient knowledge reserves, including C++, JAVA, Android system principles, etc., it is very difficult to carry out adaptation work. This means that one cannot be impatient for success; having strong motivation is good, but being overly eager to solve immediate problems and wanting to see results immediately is unrealistic. Haste makes waste, and haste often leads to taking detours. One should stop and review related knowledge.

  3. When doing a difficult task, aiming for the final goal is certainly important, but designing sub-goals in the process is also crucial. Especially for a system adaptation goal where success is uncertain, if the final goal is not achieved and there are no gains in the process, it would be a waste of time. For this project, setting some learning goals as sub-goals is a good choice.

  4. Lineage14.1 for latte is not a good topic for beginners. Choosing it at first was not wrong because it was the most appealing to me, but after encountering so many insurmountable difficulties, I should pause and switch to another goal. The vendor for lineage14.1 for latte does not have source code, and when encountering problems, it often leads to trial and error, which is very inefficient and largely reliant on luck; the changes from Android 7 compared to Android 6 are greater than expected, resulting in insufficient reference for lineage13.0’s code and logs for 14.1; the Xiaomi Mi Pad 2 is a relatively old device, and there are few people adapting it, making it difficult to find valuable information online.

I plan to switch to another system for learning examples, and when my knowledge accumulates to a certain extent, I will return to continue the adaptation of lineage.

I hope that experts who see this article can provide guidance. Your few words may illuminate my path. Thank you!

I also hope that Xiaomi Mi Pad users can help let more people see this article. The more experts see it, the more suggestions there will be, and the greater the hope of successfully adapting the Xiaomi Mi Pad 2.

Gains and Reflections on Adapting Android System for Xiaomi Mi Pad 2

Click the lower left corner “Read the original text” to view the comments

Leave a Comment