Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix turn screen off on Android 14 #4456

Merged
merged 1 commit into from
Nov 25, 2023
Merged

Conversation

rom1v
Copy link
Collaborator

@rom1v rom1v commented Nov 23, 2023

A new PR to replace #4446.

On Android 14, the methods to access the display have been moved to DisplayControl, which is not in the core framework. Use a specific ClassLoader to access this class and its native dependencies.

Fixes #3927
Refs #3927 (comment)
Refs #4446 (comment)

cc @yume-chan


Here is a binary for Windows:

On Android 14, the methods to access the display have been moved to
DisplayControl, which is not in the core framework. Use a specific
ClassLoader to access this class and its native dependencies.

Fixes #3927 <#3927>
Refs #3927 comment <#3927 (comment)>
Refs #4446 comment <#4446 (comment)>
PR #4456 <#4456>

Co-authored-by: Simon Chan <1330321+yume-chan@users.noreply.github.com>
Signed-off-by: Romain Vimont <rom@rom1v.com>
@rom1v
Copy link
Collaborator Author

rom1v commented Dec 1, 2023

@yume-chan I noticed by accident that, on Android 14 (Pixel 8), turning the screen on in the cleanup process makes app_process crash:

12-01 11:09:46.193 11994 11994 I scrcpy  : Cleaning up
12-01 11:09:46.196  1726  1964 I DisplayDeviceRepository: Display device removed: DisplayDeviceInfo{"scrcpy": uniqueId="virtual:com.android.shell,2000,scrcpy,0", 1080 x 2400, modeId 22, renderFrameRate 60.0, defaultModeId 22, supportedModes [{id=22, width=1080, height=2400, fps=60.0, alternativeRefreshRates=[], supportedHdrTypes=[]}], colorMode 0, supportedColorModes [0], hdrCapabilities null, allmSupported false, gameContentTypeSupported false, density 1, 1.0 x 1.0 dpi, appVsyncOff 0, presDeadline 16666666, touch NONE, rotation 0, type VIRTUAL, deviceProductInfo null, state ON, committedState UNKNOWN, owner com.android.shell (uid 2000), frameRateOverride , brightnessMinimum 0.0, brightnessMaximum 0.0, brightnessDefault 0.0, hdrSdrRatio NaN, FLAG_PRIVATE, installOrientation 0, displayShape DisplayShape{ spec=-1893857183 displayWidth=1080 displayHeight=2400 physicalPixelDisplaySizeRatio=1.0 rotation=0 offsetX=0 offsetY=0 scale=1.0}}
12-01 11:09:46.196  1474  2638 E mediaserver: unlinkToDeath: removed reference to death recipient but unlink failed: DEAD_OBJECT
12-01 11:09:46.196  1474  2638 E IPCThreadState: attemptIncStrongHandle(7): Not supported
12-01 11:09:46.197  1726  1964 I LogicalDisplayMapper: Removing display: 11
12-01 11:09:46.199  1726  1964 W IPCThreadState: Sending oneway calls to frozen process.
12-01 11:09:46.202 11994 11994 I scrcpy  : Restoring normal power mode
12-01 11:09:46.203  1352 12008 D BufferPoolAccessor2.0: Destruction - bufferpool2 0xb400007039d50658 cached: 0/0M, 0/0% in use; allocs: 0, 0% recycled; transfers: 0, 0% unfetched
12-01 11:09:46.203   621  3521 D hwc-display: setActiveConfigWithConstraints:: PrimaryDisplay config(37) test(0)
12-01 11:09:46.203   621  3521 I hwc-display: [PrimaryDisplay] setActiveConfigWithConstraints: config(37)
12-01 11:09:46.204 11994 11994 W app_process: ClassLoaderContext classpath size mismatch. expected=1, found=0 (PCL[/system/framework/com.android.location.provider.jar*3994156536] | PCL[];PCL[/data/local/tmp/scrcpy-server.jar*3083433313])
12-01 11:09:46.205  1726  1745 I InputManager: Not applying additional properties for display 11 because the pointer is currently targeting display 0.
12-01 11:09:46.206 11994 11994 D nativeloader: InitApexLibraries:
12-01 11:09:46.206 11994 11994 D nativeloader:   com_android_art: libnativehelper.so
12-01 11:09:46.206 11994 11994 D nativeloader:   com_android_i18n: libicui18n.so:libicuuc.so:libicu.so
12-01 11:09:46.206 11994 11994 D nativeloader:   com_android_neuralnetworks: libneuralnetworks.so
12-01 11:09:46.206 11994 11994 D nativeloader: InitDefaultPublicLibraries for_preload=0: libandroid.so:libaaudio.so:libamidi.so:libbinder_ndk.so:libc.so:libcamera2ndk.so:libclang_rt.hwasan-aarch64-android.so:libdl.so:libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libjnigraphics.so:liblog.so:libmediandk.so:libm.so:libnativewindow.so:libOpenMAXAL.so:libOpenSLES.so:libRS.so:libstdc++.so:libsync.so:libvulkan.so:libwebviewchromium_plat_support.so:libz.so
12-01 11:09:46.206 11994 11994 D nativeloader: Configuring clns-shared-1 for other apk /system/framework/services.jar. target_sdk_version=0, uses_libraries=ALL, library_path=, permitted_path=/data:/mnt/expand
12-01 11:09:46.206 11994 11994 D nativeloader: InitExtendedPublicLibraries: libedgetpu_dba.google.so
12-01 11:09:46.206 11994 11994 D nativeloader: Extending system_exposed_libraries: libedgetpu_dba.google.so
12-01 11:09:46.207 11994 11994 D nativeloader: InitVendorPublicLibraries: libOpenCL.so:libOpenCL-pixel.so:libedgetpu_client.google.so:libedgetpu_util.so:lib_aion_buffer.so:lib_jpg_encoder.so:libgxp.so
12-01 11:09:46.207 11994 11994 D nativeloader: InitProductPublicLibraries: 
12-01 11:09:46.213  1352  2626 I ExynosC2H264EncComponent: [release] component is released
12-01 11:09:46.214  1352  2626 D BufferPoolAccessor2.0: Destruction - bufferpool2 0xb400007039d4e5f8 cached: 0/0M, 0/0% in use; allocs: 16, 69% recycled; transfers: 11, 45% unfetched
12-01 11:09:46.258   619   619 D SurfaceFlinger: Setting power mode 2 on display 4619827078044484352
12-01 11:09:46.261 11994 11994 D AndroidRuntime: Shutting down VM
12-01 11:09:46.498  1523  1981 I CHRE    : @ 3245.638: [ip] Peak detected: magnitude = 1.112667 hpa, duration = 319.999992 ms
12-01 11:09:46.498  1325  2195 I suez-nanoapp-clients: Barometric peak detected: magnitude = 1.112667 hPa (bucket: 20), duration = 320.000000 ms (bucket: 27).
12-01 11:09:46.499  1523  1981 I CHRE    : @ 3245.639: [ip] Peak detected: magnitude = 0.178285 hpa, duration = 481.000006 ms
12-01 11:09:46.500  1304  1316 D ContextHubHal: Got message from nanoapp: ID 0x476f6f676c001022
12-01 11:09:46.503  1304  1316 D ContextHubHal: Got message from nanoapp: ID 0x476f6f676c001022
12-01 11:09:46.503  1726  2409 E ContextHubClientManager: Cannot send message to unregistered client (host endpoint ID = -28638)
12-01 11:09:46.504  1325  2195 I suez-nanoapp-clients: Vendor atom [id = 100047] reported.
12-01 11:09:46.505  1325  2195 I suez-nanoapp-clients: Barometric peak detected: magnitude = 0.178285 hPa (bucket: 4), duration = 481.000000 ms (bucket: 39).
12-01 11:09:46.506  1726  2409 E ContextHubClientManager: Cannot send message to unregistered client (host endpoint ID = -28638)
12-01 11:09:46.507  1325  2195 I suez-nanoapp-clients: Vendor atom [id = 100047] reported.
12-01 11:09:46.942   601 11955 I keystore2: system/security/keystore2/src/watchdog.rs:319 - Watchdog thread idle -> terminating. Have a great day.
12-01 11:09:47.104  4233  4584 D ModemODPMPoller: Current Modem ODPM (mw): 43, threshold: 800
--------- beginning of crash
12-01 11:09:47.125 11994 11994 F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x758087c260 in tid 11994 (Shutdown thread), pid 11994 (Shutdown thread)
12-01 11:09:47.164 12053 12053 I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstoneProto
12-01 11:09:47.166   773   773 I tombstoned: received crash request for pid 11994
12-01 11:09:47.167 12053 12053 I crash_dump64: performing dump of process 11994 (target tid = 11994)
12-01 11:09:47.226 12053 12053 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
12-01 11:09:47.226 12053 12053 F DEBUG   : Build fingerprint: 'google/shiba/shiba:14/UD1A.231105.004/11010374:user/release-keys'
12-01 11:09:47.226 12053 12053 F DEBUG   : Revision: 'MP1.0'
12-01 11:09:47.226 12053 12053 F DEBUG   : ABI: 'arm64'
12-01 11:09:47.226 12053 12053 F DEBUG   : Timestamp: 2023-12-01 11:09:47.172442540+0100
12-01 11:09:47.226 12053 12053 F DEBUG   : Process uptime: 4s
12-01 11:09:47.226 12053 12053 F DEBUG   : Cmdline: app_process / com.genymobile.scrcpy.CleanUp AAAAAP////8CAAAA
12-01 11:09:47.226 12053 12053 F DEBUG   : pid: 11994, tid: 11994, name: Shutdown thread  >>> app_process <<<
12-01 11:09:47.226 12053 12053 F DEBUG   : uid: 2000
12-01 11:09:47.226 12053 12053 F DEBUG   : tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
12-01 11:09:47.226 12053 12053 F DEBUG   : pac_enabled_keys: 000000000000000f (PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY)
12-01 11:09:47.226 12053 12053 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x000000758087c260
12-01 11:09:47.226 12053 12053 F DEBUG   :     x0  000000784f2bdb78  x1  0000000000001000  x2  0000000000000001  x3  0000007fc43fee08
12-01 11:09:47.226 12053 12053 F DEBUG   :     x4  0000000000000058  x5  00000076ec80c7bc  x6  0000000000000001  x7  0000007870a6f004
12-01 11:09:47.226 12053 12053 F DEBUG   :     x8  000000758087c264  x9  0000000000000001  x10 0000000000000002  x11 00000078587ad000
12-01 11:09:47.226 12053 12053 F DEBUG   :     x12 000000000000abf1  x13 0000000000001ba2  x14 0000000000000018  x15 0000000000000000
12-01 11:09:47.226 12053 12053 F DEBUG   :     x16 0000007858341c00  x17 0000007858327310  x18 0000007871bfc000  x19 0000000000000000
12-01 11:09:47.226 12053 12053 F DEBUG   :     x20 00000078587ad6e4  x21 000000784f2bdb78  x22 0000000000001000  x23 00000078638a1760
12-01 11:09:47.226 12053 12053 F DEBUG   :     x24 00000078587ad000  x25 00000000000040b0  x26 000000000000068c  x27 00000000000002b2
12-01 11:09:47.226 12053 12053 F DEBUG   :     x28 0000000000004000  x29 0000007fc43fee70
12-01 11:09:47.226 12053 12053 F DEBUG   :     lr  00000078583298f4  sp  0000007fc43fee40  pc  00000078638a1764  pst 0000000080001000
12-01 11:09:47.226 12053 12053 F DEBUG   : 4 total frames
12-01 11:09:47.226 12053 12053 F DEBUG   : backtrace:
12-01 11:09:47.226 12053 12053 F DEBUG   :       #00 pc 0000000000018764  /system/lib64/libutils.so (android::String16::~String16()+4) (BuildId: fa4adad04146b4ad60c9be9226c5d8bb)
12-01 11:09:47.226 12053 12053 F DEBUG   :       #01 pc 00000000000da8f0  /apex/com.android.runtime/lib64/bionic/libc.so (__cxa_finalize+144) (BuildId: a017f07431ff6692304a0cae225962fb)
12-01 11:09:47.226 12053 12053 F DEBUG   :       #02 pc 00000000000cca98  /apex/com.android.runtime/lib64/bionic/libc.so (exit+24) (BuildId: a017f07431ff6692304a0cae225962fb)
12-01 11:09:47.226 12053 12053 F DEBUG   :       #03 pc 00000000000616ec  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108) (BuildId: a017f07431ff6692304a0cae225962fb)
12-01 11:09:47.231  1726  2663 W NativeCrashListener: Couldn't find ProcessRecord for pid 11994

Despite this crash, the screen is turned on correctly.

In fact, it crashes when the process terminates, for example, in this case, it crashes 5 seconds later:

diff --git a/server/src/main/java/com/genymobile/scrcpy/CleanUp.java b/server/src/main/java/com/genymobile/scrcpy/CleanUp.java
index b3a1aac13..006736c1a 100644
--- a/server/src/main/java/com/genymobile/scrcpy/CleanUp.java
+++ b/server/src/main/java/com/genymobile/scrcpy/CleanUp.java
@@ -2,6 +2,7 @@ package com.genymobile.scrcpy;
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.SystemClock;
 import android.util.Base64;
 
 import java.io.File;
@@ -187,5 +188,7 @@ public final class CleanUp {
                 Device.setScreenPowerMode(Device.POWER_MODE_NORMAL);
             }
         }
+
+        SystemClock.sleep(5000);
     }
 }

However, if I don't restore the power mode, then it does not crash:

diff --git a/server/src/main/java/com/genymobile/scrcpy/CleanUp.java b/server/src/main/java/com/genymobile/scrcpy/CleanUp.java
index b3a1aac13..eaf16a3b8 100644
--- a/server/src/main/java/com/genymobile/scrcpy/CleanUp.java
+++ b/server/src/main/java/com/genymobile/scrcpy/CleanUp.java
@@ -184,7 +184,6 @@ public final class CleanUp {
                 Device.powerOffScreen(config.displayId);
             } else if (config.restoreNormalPowerMode) {
                 Ln.i("Restoring normal power mode");
-                Device.setScreenPowerMode(Device.POWER_MODE_NORMAL);
             }
         }
     }

Turning the screen off or on in the main scrcpy process works without crashing.

Any idea why?

@yume-chan
Copy link
Contributor

I have no idea. I tried my POC and it also crashes on exit. Why Scrcpy main process doesn't crash sounds like a bigger question.

I tried to debug the process. By adding LD_DEBUG=1 environment variable I can find which module the invalid address belongs to, and every time they are from /system/lib64/libbatterystats_aidl.so. But I can't find anything special in it.

Searching "SIGSEGV cxa_finalize" shows that if a module has destructors registered using atexit, dlclose it may cause a crash when exiting. In our case, libandroid_server.so and its dependencies are unloaded by ART when it shuts down, which may cause this issue.

Anyway, if this crash causes system instability, we can try to switch to #4446 (comment). The transaction ID might change between versions, but overall I believe this is the best. We can also call setDisplayPowerMode from it, instead of SurfaceControl:

public void setPowerMode(IBinder display, int mode) {
    var data = Parcel.obtain();
    var reply = Parcel.obtain();
    try {
        data.writeInterfaceToken("android.gui.ISurfaceComposer");
        data.writeStrongBinder(display);
        data.writeInt(mode);
        surfaceComposer.transact(IBinder.FIRST_CALL_TRANSACTION + 8, data, reply, 0);
        reply.readException();
    } catch (RemoteException e) {
        throw new RuntimeException(e);
    } finally {
        data.recycle();
        reply.recycle();
    }
}

@rom1v
Copy link
Collaborator Author

rom1v commented Dec 3, 2023

Why Scrcpy main process doesn't crash sounds like a bigger question.

The reason is that the main process calls System.exit() since 41ccb58.

If I do the same for cleanup, it "solves" the problem too:

diff --git a/server/src/main/java/com/genymobile/scrcpy/CleanUp.java b/server/src/main/java/com/genymobile/scrcpy/CleanUp.java
index b3a1aac13..c84e25bb8 100644
--- a/server/src/main/java/com/genymobile/scrcpy/CleanUp.java
+++ b/server/src/main/java/com/genymobile/scrcpy/CleanUp.java
@@ -187,5 +187,7 @@ public final class CleanUp {
                 Device.setScreenPowerMode(Device.POWER_MODE_NORMAL);
             }
         }
+
+        System.exit(0);
     }
 }

In any case, I think restoring the display power mode to normal on exit should only be called when it is not already in that state. But for that, the main process must notify the cleanup process every time MOD+o or MOD+Shift+o is pressed. So CleanUp should not get its parameters from the command line, but receive changes from the main process via stdin/stdout… I'll probably do that in the future.

rom1v added a commit that referenced this pull request Dec 4, 2023
This avoids an internal crash reported in `adb logcat`.

Refs #4456 <#4456 (comment)>
@rom1v
Copy link
Collaborator Author

rom1v commented Feb 1, 2024

Setting the power mode with this mechanism on Android 14 causes issues on some devices (the device reboots after a few minutes): #4624

rom1v added a commit that referenced this pull request Feb 5, 2024
Some actions may be performed when scrcpy exits, currently:
 - disable "show touches"
 - restore "stay on while plugged in"
 - power off screen
 - restore "power mode" (to disable "turn screen off")

They are performed from a separate process so that they can be executed
even when scrcpy-server is killed (e.g. if the device is unplugged).

The clean up actions to perform were configured when scrcpy started.
Given that there is no method to read the current "power mode" in
Android, and that "turn screen off" can be applied at any time using an
scrcpy shortcut, there was no way to determine if "power mode" had to be
restored on exit. Therefore, it was always restored to "normal", even
when not necessary.

However, setting the "power mode" is quite fragile on some devices, and
may cause some issues, so it is preferable to call it only when
necessary (when "turn screen off" has actually been called).

For that purpose, make the scrcpy-server main process and the clean up
process communicate the actions to perform over the stdout/stdin, so
that they can be changed dynamically. In particular, when the power mode
is changed at runtime, notify the clean up process.

Refs 1beec99
Refs #4456 <#4456>
Refs #4624 <#4624>
@rom1v
Copy link
Collaborator Author

rom1v commented Feb 5, 2024

In any case, I think restoring the display power mode to normal on exit should only be called when it is not already in that state. But for that, the main process must notify the cleanup process every time MOD+o or MOD+Shift+o is pressed. So CleanUp should not get its parameters from the command line, but receive changes from the main process via stdin/stdout… I'll probably do that in the future.

I just implemented that this week-end: #4649

rom1v added a commit that referenced this pull request Feb 5, 2024
Some actions may be performed when scrcpy exits, currently:
 - disable "show touches"
 - restore "stay on while plugged in"
 - power off screen
 - restore "power mode" (to disable "turn screen off")

They are performed from a separate process so that they can be executed
even when scrcpy-server is killed (e.g. if the device is unplugged).

The clean up actions to perform were configured when scrcpy started.
Given that there is no method to read the current "power mode" in
Android, and that "turn screen off" can be applied at any time using an
scrcpy shortcut, there was no way to determine if "power mode" had to be
restored on exit. Therefore, it was always restored to "normal", even
when not necessary.

However, setting the "power mode" is quite fragile on some devices, and
may cause some issues, so it is preferable to call it only when
necessary (when "turn screen off" has actually been called).

For that purpose, make the scrcpy-server main process and the clean up
process communicate the actions to perform over the stdout/stdin, so
that they can be changed dynamically. In particular, when the power mode
is changed at runtime, notify the clean up process.

Refs 1beec99
Refs #4456 <#4456>
Refs #4624 <#4624>
PR #4649 <#4649>
rom1v added a commit that referenced this pull request Feb 17, 2024
Some actions may be performed when scrcpy exits, currently:
 - disable "show touches"
 - restore "stay on while plugged in"
 - power off screen
 - restore "power mode" (to disable "turn screen off")

They are performed from a separate process so that they can be executed
even when scrcpy-server is killed (e.g. if the device is unplugged).

The clean up actions to perform were configured when scrcpy started.
Given that there is no method to read the current "power mode" in
Android, and that "turn screen off" can be applied at any time using an
scrcpy shortcut, there was no way to determine if "power mode" had to be
restored on exit. Therefore, it was always restored to "normal", even
when not necessary.

However, setting the "power mode" is quite fragile on some devices, and
may cause some issues, so it is preferable to call it only when
necessary (when "turn screen off" has actually been called).

For that purpose, make the scrcpy-server main process and the clean up
process communicate the actions to perform over a pipe (stdin/stdout),
so that they can be changed dynamically. In particular, when the power
mode is changed at runtime, notify the clean up process.

Refs 1beec99
Refs #4456 <#4456>
Refs #4624 <#4624>
PR #4649 <#4649>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants