Skip to content

Commit

Permalink
Add workarounds for Honor devices
Browse files Browse the repository at this point in the history
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
Application must be initialized.

These workarounds must not be applied for all devices, because they
might cause other issues.

Fixes #4015 <#4015>
Refs #3085 <#3805>

Co-authored-by: Simon Chan <1330321+yume-chan@users.noreply.github.com>
  • Loading branch information
rom1v and yume-chan committed Jun 19, 2023
1 parent 8bf2764 commit 1c2d4b1
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 14 deletions.
4 changes: 2 additions & 2 deletions server/src/main/java/com/genymobile/scrcpy/FakeContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
61 changes: 49 additions & 12 deletions server/src/main/java/com/genymobile/scrcpy/Workarounds.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,22 +31,45 @@ private Workarounds() {
public static void apply(boolean audio) {
Workarounds.prepareMainLooper();

// Workarounds must be applied for Meizu phones:
// - <https://github.com/Genymobile/scrcpy/issues/240>
// - <https://github.com/Genymobile/scrcpy/issues/365>
// - <https://github.com/Genymobile/scrcpy/issues/2656>
//
// But only apply when strictly necessary, since workarounds can cause other issues:
// - <https://github.com/Genymobile/scrcpy/issues/940>
// - <https://github.com/Genymobile/scrcpy/issues/994>
boolean mustFillAppInfo = false;
boolean mustFillBaseContext = false;
boolean mustFillAppContext = false;


if (Build.BRAND.equalsIgnoreCase("meizu")) {
Workarounds.fillAppInfo();
// Workarounds must be applied for Meizu phones:
// - <https://github.com/Genymobile/scrcpy/issues/240>
// - <https://github.com/Genymobile/scrcpy/issues/365>
// - <https://github.com/Genymobile/scrcpy/issues/2656>
//
// But only apply when strictly necessary, since workarounds can cause other issues:
// - <https://github.com/Genymobile/scrcpy/issues/940>
// - <https://github.com/Genymobile/scrcpy/issues/994>
mustFillAppInfo = true;
} else if (Build.BRAND.equalsIgnoreCase("honor")) {
// Honor devices require in addition a system context as a base context of FakeContext:
// - <https://github.com/Genymobile/scrcpy/issues/4015>
// The system context must not be set for all devices, because it would cause other problems:
// - <https://github.com/Genymobile/scrcpy/issues/4015#issuecomment-1595382142>
// - <https://github.com/Genymobile/scrcpy/issues/3805#issuecomment-1596148031>
mustFillBaseContext = true;
mustFillAppContext = true;
}

// Before Android 11, audio is not supported.
// Since Android 12, we can properly set a context on the AudioRecord.
// Only on Android 11 we must fill the application context for the AudioRecord to work.
if (audio && Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
// Before Android 11, audio is not supported.
// Since Android 12, we can properly set a context on the AudioRecord.
// Only on Android 11 we must fill the application context for the AudioRecord to work.
mustFillAppContext = true;
}

if (mustFillAppInfo) {
Workarounds.fillAppInfo();
}
if (mustFillBaseContext) {
Workarounds.fillBaseContext();
}
if (mustFillAppContext) {
Workarounds.fillAppContext();
}
}
Expand Down Expand Up @@ -128,6 +152,19 @@ private 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) {
Expand Down

0 comments on commit 1c2d4b1

Please sign in to comment.