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.
dynamic_cleanup
Romain Vimont 3 months ago
parent d25cbc55f2
commit 05b5deacad

@ -26,7 +26,20 @@ public final class ActivityManager {
private Method startActivityAsUserWithFeatureMethod;
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;
}

@ -20,7 +20,18 @@ public final class ClipboardManager {
private int setMethodVersion;
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;
}

@ -5,16 +5,31 @@ import com.genymobile.scrcpy.DisplayInfo;
import com.genymobile.scrcpy.Ln;
import com.genymobile.scrcpy.Size;
import android.annotation.SuppressLint;
import android.view.Display;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@SuppressLint("PrivateApi,DiscouragedPrivateApi")
public final class DisplayManager {
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;
}

@ -2,12 +2,14 @@ package com.genymobile.scrcpy.wrappers;
import com.genymobile.scrcpy.Ln;
import android.annotation.SuppressLint;
import android.view.InputEvent;
import android.view.MotionEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@SuppressLint("PrivateApi,DiscouragedPrivateApi")
public final class InputManager {
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 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;
}

@ -13,7 +13,12 @@ public final class PowerManager {
private final IInterface manager;
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;
}

@ -9,7 +9,6 @@ import android.os.IBinder;
import android.os.IInterface;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@SuppressLint("PrivateApi,DiscouragedPrivateApi")
@ -38,7 +37,7 @@ public final class ServiceManager {
/* not instantiable */
}
private static IInterface getService(String service, String type) {
static IInterface getService(String service, String type) {
try {
IBinder binder = (IBinder) GET_SERVICE_METHOD.invoke(null, service);
Method asInterfaceMethod = Class.forName(type + "$Stub").getMethod("asInterface", IBinder.class);
@ -50,90 +49,51 @@ public final class ServiceManager {
public static WindowManager getWindowManager() {
if (windowManager == null) {
windowManager = new WindowManager(getService("window", "android.view.IWindowManager"));
windowManager = WindowManager.create();
}
return windowManager;
}
public static DisplayManager getDisplayManager() {
if (displayManager == null) {
try {
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);
}
displayManager = DisplayManager.create();
}
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() {
if (inputManager == null) {
try {
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);
}
inputManager = InputManager.create();
}
return inputManager;
}
public static PowerManager getPowerManager() {
if (powerManager == null) {
powerManager = new PowerManager(getService("power", "android.os.IPowerManager"));
powerManager = PowerManager.create();
}
return powerManager;
}
public static StatusBarManager getStatusBarManager() {
if (statusBarManager == null) {
statusBarManager = new StatusBarManager(getService("statusbar", "com.android.internal.statusbar.IStatusBarService"));
statusBarManager = StatusBarManager.create();
}
return statusBarManager;
}
public static ClipboardManager getClipboardManager() {
if (clipboardManager == null) {
IInterface clipboard = 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;
}
clipboardManager = new ClipboardManager(clipboard);
// May be null, some devices have no clipboard manager
clipboardManager = ClipboardManager.create();
}
return clipboardManager;
}
public static ActivityManager getActivityManager() {
if (activityManager == null) {
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);
activityManager = new ActivityManager(am);
} catch (Exception e) {
throw new AssertionError(e);
}
activityManager = ActivityManager.create();
}
return activityManager;
}

@ -16,7 +16,12 @@ public final class StatusBarManager {
private boolean expandSettingsPanelMethodNewVersion = true;
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;
}

@ -17,7 +17,12 @@ public final class WindowManager {
private Method isRotationFrozenMethod;
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;
}

Loading…
Cancel
Save