Move service managers creation

Create the service managers from each manager wrapper class rather than
from their getter in ServiceManager.

The way a wrapper retrieve the underlying service is an implementation
detail, and it must be consistent with the way it accesses it, so it is
better to write the creation in the wrapper.
pull/4649/head
Romain Vimont 4 months ago
parent d25cbc55f2
commit 05b5deacad

@ -26,7 +26,20 @@ public final class ActivityManager {
private Method startActivityAsUserWithFeatureMethod; private Method startActivityAsUserWithFeatureMethod;
private Method forceStopPackageMethod; private Method forceStopPackageMethod;
public ActivityManager(IInterface manager) { static ActivityManager create() {
try {
// On old Android versions, the ActivityManager is not exposed via AIDL,
// so use ActivityManagerNative.getDefault()
Class<?> cls = Class.forName("android.app.ActivityManagerNative");
Method getDefaultMethod = cls.getDeclaredMethod("getDefault");
IInterface am = (IInterface) getDefaultMethod.invoke(null);
return new ActivityManager(am);
} catch (Exception e) {
throw new AssertionError(e);
}
}
private ActivityManager(IInterface manager) {
this.manager = manager; this.manager = manager;
} }

@ -20,7 +20,18 @@ public final class ClipboardManager {
private int setMethodVersion; private int setMethodVersion;
private int addListenerMethodVersion; private int addListenerMethodVersion;
public ClipboardManager(IInterface manager) { static ClipboardManager create() {
IInterface clipboard = ServiceManager.getService("clipboard", "android.content.IClipboard");
if (clipboard == null) {
// Some devices have no clipboard manager
// <https://github.com/Genymobile/scrcpy/issues/1440>
// <https://github.com/Genymobile/scrcpy/issues/1556>
return null;
}
return new ClipboardManager(clipboard);
}
private ClipboardManager(IInterface manager) {
this.manager = manager; this.manager = manager;
} }

@ -5,16 +5,31 @@ import com.genymobile.scrcpy.DisplayInfo;
import com.genymobile.scrcpy.Ln; import com.genymobile.scrcpy.Ln;
import com.genymobile.scrcpy.Size; import com.genymobile.scrcpy.Size;
import android.annotation.SuppressLint;
import android.view.Display; import android.view.Display;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@SuppressLint("PrivateApi,DiscouragedPrivateApi")
public final class DisplayManager { public final class DisplayManager {
private final Object manager; // instance of hidden class android.hardware.display.DisplayManagerGlobal private final Object manager; // instance of hidden class android.hardware.display.DisplayManagerGlobal
public DisplayManager(Object manager) { static DisplayManager create() {
try {
Class<?> clazz = Class.forName("android.hardware.display.DisplayManagerGlobal");
Method getInstanceMethod = clazz.getDeclaredMethod("getInstance");
Object dmg = getInstanceMethod.invoke(null);
return new DisplayManager(dmg);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
}
private DisplayManager(Object manager) {
this.manager = manager; this.manager = manager;
} }

@ -2,12 +2,14 @@ package com.genymobile.scrcpy.wrappers;
import com.genymobile.scrcpy.Ln; import com.genymobile.scrcpy.Ln;
import android.annotation.SuppressLint;
import android.view.InputEvent; import android.view.InputEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@SuppressLint("PrivateApi,DiscouragedPrivateApi")
public final class InputManager { public final class InputManager {
public static final int INJECT_INPUT_EVENT_MODE_ASYNC = 0; public static final int INJECT_INPUT_EVENT_MODE_ASYNC = 0;
@ -20,7 +22,27 @@ public final class InputManager {
private static Method setDisplayIdMethod; private static Method setDisplayIdMethod;
private static Method setActionButtonMethod; private static Method setActionButtonMethod;
public InputManager(Object manager) { static InputManager create() {
try {
Class<?> inputManagerClass = getInputManagerClass();
Method getInstanceMethod = inputManagerClass.getDeclaredMethod("getInstance");
Object im = getInstanceMethod.invoke(null);
return new InputManager(im);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
}
private static Class<?> getInputManagerClass() {
try {
// Parts of the InputManager class have been moved to a new InputManagerGlobal class in Android 14 preview
return Class.forName("android.hardware.input.InputManagerGlobal");
} catch (ClassNotFoundException e) {
return android.hardware.input.InputManager.class;
}
}
private InputManager(Object manager) {
this.manager = manager; this.manager = manager;
} }

@ -13,7 +13,12 @@ public final class PowerManager {
private final IInterface manager; private final IInterface manager;
private Method isScreenOnMethod; private Method isScreenOnMethod;
public PowerManager(IInterface manager) { static PowerManager create() {
IInterface manager = ServiceManager.getService("power", "android.os.IPowerManager");
return new PowerManager(manager);
}
private PowerManager(IInterface manager) {
this.manager = manager; this.manager = manager;
} }

@ -9,7 +9,6 @@ import android.os.IBinder;
import android.os.IInterface; import android.os.IInterface;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@SuppressLint("PrivateApi,DiscouragedPrivateApi") @SuppressLint("PrivateApi,DiscouragedPrivateApi")
@ -38,7 +37,7 @@ public final class ServiceManager {
/* not instantiable */ /* not instantiable */
} }
private static IInterface getService(String service, String type) { static IInterface getService(String service, String type) {
try { try {
IBinder binder = (IBinder) GET_SERVICE_METHOD.invoke(null, service); IBinder binder = (IBinder) GET_SERVICE_METHOD.invoke(null, service);
Method asInterfaceMethod = Class.forName(type + "$Stub").getMethod("asInterface", IBinder.class); Method asInterfaceMethod = Class.forName(type + "$Stub").getMethod("asInterface", IBinder.class);
@ -50,90 +49,51 @@ public final class ServiceManager {
public static WindowManager getWindowManager() { public static WindowManager getWindowManager() {
if (windowManager == null) { if (windowManager == null) {
windowManager = new WindowManager(getService("window", "android.view.IWindowManager")); windowManager = WindowManager.create();
} }
return windowManager; return windowManager;
} }
public static DisplayManager getDisplayManager() { public static DisplayManager getDisplayManager() {
if (displayManager == null) { if (displayManager == null) {
try { displayManager = DisplayManager.create();
Class<?> clazz = Class.forName("android.hardware.display.DisplayManagerGlobal");
Method getInstanceMethod = clazz.getDeclaredMethod("getInstance");
Object dmg = getInstanceMethod.invoke(null);
displayManager = new DisplayManager(dmg);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
} }
return displayManager; return displayManager;
} }
public static Class<?> getInputManagerClass() {
try {
// Parts of the InputManager class have been moved to a new InputManagerGlobal class in Android 14 preview
return Class.forName("android.hardware.input.InputManagerGlobal");
} catch (ClassNotFoundException e) {
return android.hardware.input.InputManager.class;
}
}
public static InputManager getInputManager() { public static InputManager getInputManager() {
if (inputManager == null) { if (inputManager == null) {
try { inputManager = InputManager.create();
Class<?> inputManagerClass = getInputManagerClass();
Method getInstanceMethod = inputManagerClass.getDeclaredMethod("getInstance");
Object im = getInstanceMethod.invoke(null);
inputManager = new InputManager(im);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
} }
return inputManager; return inputManager;
} }
public static PowerManager getPowerManager() { public static PowerManager getPowerManager() {
if (powerManager == null) { if (powerManager == null) {
powerManager = new PowerManager(getService("power", "android.os.IPowerManager")); powerManager = PowerManager.create();
} }
return powerManager; return powerManager;
} }
public static StatusBarManager getStatusBarManager() { public static StatusBarManager getStatusBarManager() {
if (statusBarManager == null) { if (statusBarManager == null) {
statusBarManager = new StatusBarManager(getService("statusbar", "com.android.internal.statusbar.IStatusBarService")); statusBarManager = StatusBarManager.create();
} }
return statusBarManager; return statusBarManager;
} }
public static ClipboardManager getClipboardManager() { public static ClipboardManager getClipboardManager() {
if (clipboardManager == null) { if (clipboardManager == null) {
IInterface clipboard = getService("clipboard", "android.content.IClipboard"); // May be null, some devices have no clipboard manager
if (clipboard == null) { clipboardManager = ClipboardManager.create();
// Some devices have no clipboard manager
// <https://github.com/Genymobile/scrcpy/issues/1440>
// <https://github.com/Genymobile/scrcpy/issues/1556>
return null;
}
clipboardManager = new ClipboardManager(clipboard);
} }
return clipboardManager; return clipboardManager;
} }
public static ActivityManager getActivityManager() { public static ActivityManager getActivityManager() {
if (activityManager == null) { if (activityManager == null) {
try { activityManager = ActivityManager.create();
// On old Android versions, the ActivityManager is not exposed via AIDL,
// so use ActivityManagerNative.getDefault()
Class<?> cls = Class.forName("android.app.ActivityManagerNative");
Method getDefaultMethod = cls.getDeclaredMethod("getDefault");
IInterface am = (IInterface) getDefaultMethod.invoke(null);
activityManager = new ActivityManager(am);
} catch (Exception e) {
throw new AssertionError(e);
}
} }
return activityManager; return activityManager;
} }

@ -16,7 +16,12 @@ public final class StatusBarManager {
private boolean expandSettingsPanelMethodNewVersion = true; private boolean expandSettingsPanelMethodNewVersion = true;
private Method collapsePanelsMethod; private Method collapsePanelsMethod;
public StatusBarManager(IInterface manager) { static StatusBarManager create() {
IInterface manager = ServiceManager.getService("statusbar", "com.android.internal.statusbar.IStatusBarService");
return new StatusBarManager(manager);
}
private StatusBarManager(IInterface manager) {
this.manager = manager; this.manager = manager;
} }

@ -17,7 +17,12 @@ public final class WindowManager {
private Method isRotationFrozenMethod; private Method isRotationFrozenMethod;
private Method thawRotationMethod; private Method thawRotationMethod;
public WindowManager(IInterface manager) { static WindowManager create() {
IInterface manager = ServiceManager.getService("window", "android.view.IWindowManager");
return new WindowManager(manager);
}
private WindowManager(IInterface manager) {
this.manager = manager; this.manager = manager;
} }

Loading…
Cancel
Save