Compare commits

...

3 Commits

Author SHA1 Message Date
9bff8ccadb Apply workaround on "honor" devices
This makes audio work on those devices.

Fixes #4015 <https://github.com/Genymobile/scrcpy/issues/4015>
2023-06-17 00:25:10 +02:00
0d4157357a Use system context as base context
DONOTMERGE: it causes #994 on Xiaomi devices

This allows to make Context.getPackageManager() work.

Fixes #4015 <https://github.com/Genymobile/scrcpy/issues/4015>
Refs <https://github.com/Genymobile/scrcpy/issues/4015#issuecomment-1594262721>

Co-authored-by: Simon Chan <1330321+yume-chan@users.noreply.github.com>
2023-06-17 00:25:10 +02:00
95e61e2a0b Move ActivityThread instance
An ActivityThread instance will be needed from several classes.
2023-06-17 00:25:10 +02:00
4 changed files with 66 additions and 10 deletions

View File

@ -1,11 +1,16 @@
package com.genymobile.scrcpy; package com.genymobile.scrcpy;
import com.genymobile.scrcpy.wrappers.ActivityThread;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.AttributionSource; import android.content.AttributionSource;
import android.content.Context;
import android.content.ContextWrapper; import android.content.ContextWrapper;
import android.os.Build; import android.os.Build;
import android.os.Process; import android.os.Process;
import java.lang.reflect.Method;
public final class FakeContext extends ContextWrapper { public final class FakeContext extends ContextWrapper {
public static final String PACKAGE_NAME = "com.android.shell"; public static final String PACKAGE_NAME = "com.android.shell";
@ -13,12 +18,25 @@ public final class FakeContext extends ContextWrapper {
private static final FakeContext INSTANCE = new FakeContext(); private static final FakeContext INSTANCE = new FakeContext();
private static Context retrieveSystemContext() {
try {
Class<?> activityThreadClass = ActivityThread.getActivityThreadClass();
Object activityThread = ActivityThread.getActivityThread();
Method getSystemContextMethod = activityThreadClass.getDeclaredMethod("getSystemContext");
return (Context) getSystemContextMethod.invoke(activityThread);
} catch (Exception e) {
Ln.e("Cannot retrieve system context", e);
return null;
}
}
public static FakeContext get() { public static FakeContext get() {
return INSTANCE; return INSTANCE;
} }
private FakeContext() { private FakeContext() {
super(null); super(retrieveSystemContext());
} }
@Override @Override

View File

@ -109,7 +109,7 @@ public final class Server {
// But only apply when strictly necessary, since workarounds can cause other issues: // 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/940>
// - <https://github.com/Genymobile/scrcpy/issues/994> // - <https://github.com/Genymobile/scrcpy/issues/994>
if (Build.BRAND.equalsIgnoreCase("meizu")) { if (Build.BRAND.equalsIgnoreCase("meizu") || Build.BRAND.equalsIgnoreCase("honor")) {
Workarounds.fillAppInfo(); Workarounds.fillAppInfo();
} }

View File

@ -1,5 +1,7 @@
package com.genymobile.scrcpy; package com.genymobile.scrcpy;
import com.genymobile.scrcpy.wrappers.ActivityThread;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.Application; import android.app.Application;
@ -20,8 +22,7 @@ import java.lang.reflect.Method;
public final class Workarounds { public final class Workarounds {
private static Class<?> activityThreadClass; private static boolean activityThreadFilled;
private static Object activityThread;
private Workarounds() { private Workarounds() {
// not instantiable // not instantiable
@ -42,17 +43,16 @@ public final class Workarounds {
@SuppressLint("PrivateApi,DiscouragedPrivateApi") @SuppressLint("PrivateApi,DiscouragedPrivateApi")
private static void fillActivityThread() throws Exception { private static void fillActivityThread() throws Exception {
if (activityThread == null) { if (!activityThreadFilled) {
// ActivityThread activityThread = new ActivityThread(); Class<?> activityThreadClass = ActivityThread.getActivityThreadClass();
activityThreadClass = Class.forName("android.app.ActivityThread"); Object activityThread = ActivityThread.getActivityThread();
Constructor<?> activityThreadConstructor = activityThreadClass.getDeclaredConstructor();
activityThreadConstructor.setAccessible(true);
activityThread = activityThreadConstructor.newInstance();
// ActivityThread.sCurrentActivityThread = activityThread; // ActivityThread.sCurrentActivityThread = activityThread;
Field sCurrentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread"); Field sCurrentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
sCurrentActivityThreadField.setAccessible(true); sCurrentActivityThreadField.setAccessible(true);
sCurrentActivityThreadField.set(null, activityThread); sCurrentActivityThreadField.set(null, activityThread);
activityThreadFilled = true;
} }
} }
@ -75,6 +75,9 @@ public final class Workarounds {
appInfoField.setAccessible(true); appInfoField.setAccessible(true);
appInfoField.set(appBindData, applicationInfo); appInfoField.set(appBindData, applicationInfo);
Class<?> activityThreadClass = ActivityThread.getActivityThreadClass();
Object activityThread = ActivityThread.getActivityThread();
// activityThread.mBoundApplication = appBindData; // activityThread.mBoundApplication = appBindData;
Field mBoundApplicationField = activityThreadClass.getDeclaredField("mBoundApplication"); Field mBoundApplicationField = activityThreadClass.getDeclaredField("mBoundApplication");
mBoundApplicationField.setAccessible(true); mBoundApplicationField.setAccessible(true);
@ -95,6 +98,9 @@ public final class Workarounds {
baseField.setAccessible(true); baseField.setAccessible(true);
baseField.set(app, FakeContext.get()); baseField.set(app, FakeContext.get());
Class<?> activityThreadClass = ActivityThread.getActivityThreadClass();
Object activityThread = ActivityThread.getActivityThread();
// activityThread.mInitialApplication = app; // activityThread.mInitialApplication = app;
Field mInitialApplicationField = activityThreadClass.getDeclaredField("mInitialApplication"); Field mInitialApplicationField = activityThreadClass.getDeclaredField("mInitialApplication");
mInitialApplicationField.setAccessible(true); mInitialApplicationField.setAccessible(true);

View File

@ -0,0 +1,32 @@
package com.genymobile.scrcpy.wrappers;
import java.lang.reflect.Constructor;
public class ActivityThread {
private static final Class<?> activityThreadClass;
private static final Object activityThread;
static {
try {
activityThreadClass = Class.forName("android.app.ActivityThread");
Constructor<?> activityThreadConstructor = activityThreadClass.getDeclaredConstructor();
activityThreadConstructor.setAccessible(true);
activityThread = activityThreadConstructor.newInstance();
} catch (Exception e) {
throw new AssertionError(e);
}
}
private ActivityThread() {
// only static methods
}
public static Object getActivityThread() {
return activityThread;
}
public static Class<?> getActivityThreadClass() {
return activityThreadClass;
}
}