Skip to content

Commit

Permalink
Move service managers creation
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rom1v committed Feb 10, 2024
1 parent d25cbc5 commit 05b5dea
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,31 @@
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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

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;
Expand All @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import android.os.IInterface;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@SuppressLint("PrivateApi,DiscouragedPrivateApi")
Expand Down Expand Up @@ -38,7 +37,7 @@ private 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);
Expand All @@ -50,90 +49,51 @@ private static IInterface getService(String service, String type) {

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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit 05b5dea

Please sign in to comment.