Compare commits
3 Commits
ga
...
activity_t
Author | SHA1 | Date | |
---|---|---|---|
9bff8ccadb | |||
0d4157357a | |||
95e61e2a0b |
@ -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
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user