[Thinkpad Tablet General] KreAch3R:
Lenovo Tab 4 8 - Fix facelock crash (Related gist: https://gist.github.com/KreAch3R/734b1086c928ab8ceeafaf3e4dbd8c33)

I noticed that a Lenovo tab 4 8 (tb-8504x) on the latest stock image as of today didn't have a working face unlock ("facelock"). When it was time to add a new face, it crashed with the following log:

08-16 17:39:34.379 6600 6600 D AndroidRuntime: Shutting down VM
08-16 17:39:34.380 6600 6600 E AndroidRuntime: FATAL EXCEPTION: main
08-16 17:39:34.380 6600 6600 E AndroidRuntime: Process: com.android.facelock, PID: 6600
08-16 17:39:34.380 6600 6600 E AndroidRuntime: java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "_ZN6google8protobuf5Arena15AllocateAlignedEPKSt9type_infom" referenced by "/system/lib64/libfacenet.so"...
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at java.lang.Runtime.loadLibrary0(Runtime.java:989)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at java.lang.System.loadLibrary(System.java:1530)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at com.google.android.libraries.vision.facenet.FaceNet.<clinit>(FaceNet.java:67)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at com.google.android.libraries.vision.facenet.FaceNet.createFromAssets(FaceNet.java:118)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at com.android.facelock.FaceLockUtil.initialize(FaceLockUtil.java:148)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at com.android.facelock.SetupEnrollmentScreen.onCreate(SetupEnrollmentScreen.java:517)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:6720)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at android.app.ActivityThread.-wrap12(ActivityThread.java)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at android.os.Looper.loop(Looper.java:154)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6119)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
08-16 17:39:34.380 6600 6600 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
08-16 17:39:34.383 1428 2305 W ActivityManager: Force finishing activity com.android.facelock/.SetupEnrollmentScreen

The FIX

1. Download libfacenet.so from Open-GApps [Direct link to the binary I used].

2. Follow the instructions from here and download [MENTION=6612046]dywersant[/MENTION] 's magisk-remount.zip module from here.

3. Boot into Android with a RW /system using the module. You can confirm with:

su
cd /system
touch testfile.txt

If the command succeeds, you have a writable /system.

4. Go into the lib64 folder (/system/lib64)

5. Make a backup of the original libfacenet.so file:

cp /system/lib64/libfacenet.so /sdcard/libfacenet.so.orig

BE CAREFUL: Don't make the backup inside the /system partition, as it can be lost after reboot!

6. Mount the specific file as RW

I don't know how or why, but Lenovo seems to have made every lib file a different ro mount point/partition. So:

mount -o rw,remount /system/lib64/libfacenet.so

is needed, otherwise you end up with "read only file system" error (even when the whole /system is RW!)

7. Push to /sdcard and replace the file

cp /sdcard/libfacenet.so /system/lib64/libfacenet.so

Now, try to add a new face again. It should work!

--------------------------------------------------------------

Debugging

If anyone is interested to know how. You always start from the log. Let's disect this line:

java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "_ZN6google8protobuf5Arena15AllocateAlignedEPKSt9type_infom" referenced by "/system/lib64/libfacenet.so"

This tells us that the app com.android.facelock launched and called the library libfacenet.so which referenced a method/symbol/whatever named _ZN6google8protobuf5Arena15AllocateAlignedEPKSt9type_infom but that method doesn't exist inside whatever should include it, so "dlopen" failed and we got ourselves the "java.lang.UnsatisfiedLinkError" error. Let's sum up:

1. The app that crashes is com.android.facelock

2. One related .so lib is libfacenet.so

3. There is another one, unnamed, that should contain _ZN6google8protobuf5Arena15AllocateAlignedEPKSt9type_infom but it doesn't.

Googling about "_ZN6google8protobuf5Arena15AllocateAlignedEPKSt9type_infom" brings up some libprotobuf related results. This is good enough. Grepping through /system/lib64 shows up that there are two .so there:

libprotobuf-cpp-full.so
libprotobuf-cpp-lite.so

Doing the same in a working pixel image produces the same files. But obviously Facelock works on the Pixel but not on this tablet. We need a way to differentiate them (remember, pixel is on a Oreo base while this is Nougat).

Reading this StackExchange post, we find out about the "readelf -a -W elffile" command. Give this a try and you should see that a lot comes up. Next step, grepping through this file dump.

Lenovo libprotobuf-cpp-lite.so:

$ readelf -a -W libprotobuf-cpp-lite.so | grep _ZN6google8protobuf5Arena15AllocateAlignedEPKSt9type_infom
$

Pixel libprotobuf-cpp-lite.so:

$ readelf -a -W libprotobuf-cpp-lite.so | grep _ZN6google8protobuf5Arena15AllocateAlignedEPKSt9type_infom
000000000004fb10 0000005700000402 R_AARCH64_JUMP_SLOT 0000000000022254 _ZN6google8protobuf5Arena15AllocateAlignedEPKSt9type_infom + 0
87: 0000000000022254 216 FUNC GLOBAL DEFAULT 12 _ZN6google8protobuf5Arena15AllocateAlignedEPKSt9type_infom

Bingo! So we confirm that the libfacenet.so is trying to call an upstream method (probably), one that isn't bundled inside the libprotobuf-cpp-lite.so of the Lenovo stock image.

So now we know, it's a problem of version incompatibility. There are two things to try:

1. Replace libprotobuf-cpp-lite.so with a version that contains _ZN6google8protobuf5Arena15AllocateAlignedEPKSt9type_infom

2. Replaced libfacenet.so with a version that doesn't contain _ZN6google8protobuf5Arena15AllocateAlignedEPKSt9type_infom

Method No. 1 didn't work, while it got rid of the "java.lang.UnsatisfiedLinkError" error (confirming the diagnosis), it produced more .so related crashes, so I assume there were a lot more code that was incompatible. But Method No.2 worked as a charm!