From feb247f78266ce68c4d6d81da6b20653d679dba4 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 18 Jun 2023 17:52:43 +0200 Subject: [PATCH] Add workarounds for Honor devices Audio did not work on Honor devices. To make it work, a system context must be set as a base context of FakeContext (so that a PackageManager is available), and a current ActivityThread must be initialized. These workarounds must not be applied for all devices, because they might cause other issues. Fixes #4015 Refs #3085 Co-authored-by: Simon Chan <1330321+yume-chan@users.noreply.github.com> --- .../com/genymobile/scrcpy/FakeContext.java | 4 ++-- .../java/com/genymobile/scrcpy/Server.java | 24 ++++++++++++------- .../com/genymobile/scrcpy/Workarounds.java | 14 +++++++++++ 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/server/src/main/java/com/genymobile/scrcpy/FakeContext.java b/server/src/main/java/com/genymobile/scrcpy/FakeContext.java index 738203dedc..6501d4cf26 100644 --- a/server/src/main/java/com/genymobile/scrcpy/FakeContext.java +++ b/server/src/main/java/com/genymobile/scrcpy/FakeContext.java @@ -2,11 +2,11 @@ import android.annotation.TargetApi; import android.content.AttributionSource; -import android.content.ContextWrapper; +import android.content.MutableContextWrapper; import android.os.Build; import android.os.Process; -public final class FakeContext extends ContextWrapper { +public final class FakeContext extends MutableContextWrapper { public static final String PACKAGE_NAME = "com.android.shell"; public static final int ROOT_UID = 0; // Like android.os.Process.ROOT_UID, but before API 29 diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index 1380227586..3074010276 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -101,16 +101,24 @@ private static void scrcpy(Options options) throws IOException, ConfigurationExc Workarounds.prepareMainLooper(); - // Workarounds must be applied for Meizu phones: - // - - // - - // - - // - // But only apply when strictly necessary, since workarounds can cause other issues: - // - - // - if (Build.BRAND.equalsIgnoreCase("meizu")) { + // Workarounds must be applied for Meizu phones: + // - + // - + // - + // + // But only apply when strictly necessary, since workarounds can cause other issues: + // - + // - Workarounds.fillAppInfo(); + } else if (Build.BRAND.equalsIgnoreCase("honor")) { + // Honor devices require in addition a system context as a base context of FakeContext: + // - + // The system context must not be set for all devices, because it would cause other problems: + // - + // - + Workarounds.fillAppInfo(); + Workarounds.fillBaseContext(); } // Before Android 11, audio is not supported. diff --git a/server/src/main/java/com/genymobile/scrcpy/Workarounds.java b/server/src/main/java/com/genymobile/scrcpy/Workarounds.java index 9ae7983f16..b8e7b68155 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Workarounds.java +++ b/server/src/main/java/com/genymobile/scrcpy/Workarounds.java @@ -4,6 +4,7 @@ import android.annotation.TargetApi; import android.app.Application; import android.content.AttributionSource; +import android.content.Context; import android.content.ContextWrapper; import android.content.pm.ApplicationInfo; import android.media.AudioAttributes; @@ -105,6 +106,19 @@ public static void fillAppContext() { } } + public static void fillBaseContext() { + try { + fillActivityThread(); + + Method getSystemContextMethod = activityThreadClass.getDeclaredMethod("getSystemContext"); + Context context = (Context) getSystemContextMethod.invoke(activityThread); + FakeContext.get().setBaseContext(context); + } catch (Throwable throwable) { + // this is a workaround, so failing is not an error + Ln.d("Could not fill base context: " + throwable.getMessage()); + } + } + @TargetApi(Build.VERSION_CODES.R) @SuppressLint("WrongConstant,MissingPermission,BlockedPrivateApi,SoonBlockedPrivateApi,DiscouragedPrivateApi") public static AudioRecord createAudioRecord(int source, int sampleRate, int channelConfig, int channels, int channelMask, int encoding) {