Refactor clean up configuration to simplify
All options were configured dynamically by sending a single byte to an output stream. But in practice, only the power mode must be changed dynamically, the others are configured once on start. For simplicity, pass the value of static options as command line arguments, and handle dynamic options in a loop only from a separate thread once the clean up process is started. This will allow to easily add cleanup options with values which do not fit in 1 byte. Also handle the clean up thread (and the loading of initial settings values) from the CleanUp class, to expose a simpler clean up API. Refs 9efa162949c2a3e3e42564862ff390700270394d PR #5447 <https://github.com/Genymobile/scrcpy/pull/5447>
This commit is contained in:
parent
5936167ff7
commit
d3db9c4065
@ -5,6 +5,8 @@ import com.genymobile.scrcpy.util.Ln;
|
||||
import com.genymobile.scrcpy.util.Settings;
|
||||
import com.genymobile.scrcpy.util.SettingsException;
|
||||
|
||||
import android.os.BatteryManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
@ -16,59 +18,110 @@ import java.io.OutputStream;
|
||||
*/
|
||||
public final class CleanUp {
|
||||
|
||||
private static final int MSG_TYPE_MASK = 0b11;
|
||||
private static final int MSG_TYPE_RESTORE_STAY_ON = 0;
|
||||
private static final int MSG_TYPE_DISABLE_SHOW_TOUCHES = 1;
|
||||
private static final int MSG_TYPE_RESTORE_DISPLAY_POWER = 2;
|
||||
private static final int MSG_TYPE_POWER_OFF_SCREEN = 3;
|
||||
// Dynamic options
|
||||
private static final int PENDING_CHANGE_DISPLAY_POWER = 1 << 0;
|
||||
private int pendingChanges;
|
||||
private boolean pendingRestoreDisplayPower;
|
||||
|
||||
private static final int MSG_PARAM_SHIFT = 2;
|
||||
private Thread thread;
|
||||
|
||||
private final OutputStream out;
|
||||
|
||||
public CleanUp(OutputStream out) {
|
||||
this.out = out;
|
||||
private CleanUp(int displayId, Options options) {
|
||||
thread = new Thread(() -> runCleanUp(displayId, options), "cleanup");
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public static CleanUp configure(int displayId) throws IOException {
|
||||
String[] cmd = {"app_process", "/", CleanUp.class.getName(), String.valueOf(displayId)};
|
||||
public static CleanUp start(int displayId, Options options) {
|
||||
return new CleanUp(displayId, options);
|
||||
}
|
||||
|
||||
public void interrupt() {
|
||||
thread.interrupt();
|
||||
}
|
||||
|
||||
public void join() throws InterruptedException {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
private void runCleanUp(int displayId, Options options) {
|
||||
boolean disableShowTouches = false;
|
||||
if (options.getShowTouches()) {
|
||||
try {
|
||||
String oldValue = Settings.getAndPutValue(Settings.TABLE_SYSTEM, "show_touches", "1");
|
||||
// If "show touches" was disabled, it must be disabled back on clean up
|
||||
disableShowTouches = !"1".equals(oldValue);
|
||||
} catch (SettingsException e) {
|
||||
Ln.e("Could not change \"show_touches\"", e);
|
||||
}
|
||||
}
|
||||
|
||||
int restoreStayOn = -1;
|
||||
if (options.getStayAwake()) {
|
||||
int stayOn = BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB | BatteryManager.BATTERY_PLUGGED_WIRELESS;
|
||||
try {
|
||||
String oldValue = Settings.getAndPutValue(Settings.TABLE_GLOBAL, "stay_on_while_plugged_in", String.valueOf(stayOn));
|
||||
try {
|
||||
int currentStayOn = Integer.parseInt(oldValue);
|
||||
// Restore only if the current value is different
|
||||
if (currentStayOn != stayOn) {
|
||||
restoreStayOn = currentStayOn;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// ignore
|
||||
}
|
||||
} catch (SettingsException e) {
|
||||
Ln.e("Could not change \"stay_on_while_plugged_in\"", e);
|
||||
}
|
||||
}
|
||||
|
||||
boolean powerOffScreen = options.getPowerOffScreenOnClose();
|
||||
|
||||
try {
|
||||
run(displayId, restoreStayOn, disableShowTouches, powerOffScreen);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
} catch (IOException e) {
|
||||
Ln.e("Clean up I/O exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void run(int displayId, int restoreStayOn, boolean disableShowTouches, boolean powerOffScreen) throws IOException, InterruptedException {
|
||||
String[] cmd = {
|
||||
"app_process",
|
||||
"/",
|
||||
CleanUp.class.getName(),
|
||||
String.valueOf(displayId),
|
||||
String.valueOf(restoreStayOn),
|
||||
String.valueOf(disableShowTouches),
|
||||
String.valueOf(powerOffScreen),
|
||||
};
|
||||
|
||||
ProcessBuilder builder = new ProcessBuilder(cmd);
|
||||
builder.environment().put("CLASSPATH", Server.SERVER_PATH);
|
||||
Process process = builder.start();
|
||||
return new CleanUp(process.getOutputStream());
|
||||
}
|
||||
OutputStream out = process.getOutputStream();
|
||||
|
||||
private boolean sendMessage(int type, int param) {
|
||||
assert (type & ~MSG_TYPE_MASK) == 0;
|
||||
int msg = type | param << MSG_PARAM_SHIFT;
|
||||
try {
|
||||
out.write(msg);
|
||||
out.flush();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
Ln.w("Could not configure cleanup (type=" + type + ", param=" + param + ")", e);
|
||||
return false;
|
||||
while (true) {
|
||||
int localPendingChanges;
|
||||
boolean localPendingRestoreDisplayPower;
|
||||
synchronized (this) {
|
||||
while (pendingChanges == 0) {
|
||||
wait();
|
||||
}
|
||||
localPendingChanges = pendingChanges;
|
||||
localPendingRestoreDisplayPower = pendingRestoreDisplayPower;
|
||||
pendingChanges = 0;
|
||||
}
|
||||
if ((localPendingChanges & PENDING_CHANGE_DISPLAY_POWER) != 0) {
|
||||
out.write(localPendingRestoreDisplayPower ? 1 : 0);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setRestoreStayOn(int restoreValue) {
|
||||
// Restore the value (between 0 and 7), -1 to not restore
|
||||
// <https://developer.android.com/reference/android/provider/Settings.Global#STAY_ON_WHILE_PLUGGED_IN>
|
||||
assert restoreValue >= -1 && restoreValue <= 7;
|
||||
return sendMessage(MSG_TYPE_RESTORE_STAY_ON, restoreValue & 0b1111);
|
||||
}
|
||||
|
||||
public boolean setDisableShowTouches(boolean disableOnExit) {
|
||||
return sendMessage(MSG_TYPE_DISABLE_SHOW_TOUCHES, disableOnExit ? 1 : 0);
|
||||
}
|
||||
|
||||
public boolean setRestoreDisplayPower(boolean restoreOnExit) {
|
||||
return sendMessage(MSG_TYPE_RESTORE_DISPLAY_POWER, restoreOnExit ? 1 : 0);
|
||||
}
|
||||
|
||||
public boolean setPowerOffScreen(boolean powerOffScreenOnExit) {
|
||||
return sendMessage(MSG_TYPE_POWER_OFF_SCREEN, powerOffScreenOnExit ? 1 : 0);
|
||||
public synchronized void setRestoreDisplayPower(boolean restoreDisplayPower) {
|
||||
pendingRestoreDisplayPower = restoreDisplayPower;
|
||||
pendingChanges |= PENDING_CHANGE_DISPLAY_POWER;
|
||||
notify();
|
||||
}
|
||||
|
||||
public static void unlinkSelf() {
|
||||
@ -83,35 +136,20 @@ public final class CleanUp {
|
||||
unlinkSelf();
|
||||
|
||||
int displayId = Integer.parseInt(args[0]);
|
||||
int restoreStayOn = Integer.parseInt(args[1]);
|
||||
boolean disableShowTouches = Boolean.parseBoolean(args[2]);
|
||||
boolean powerOffScreen = Boolean.parseBoolean(args[3]);
|
||||
|
||||
int restoreStayOn = -1;
|
||||
boolean disableShowTouches = false;
|
||||
// Dynamic option
|
||||
boolean restoreDisplayPower = false;
|
||||
boolean powerOffScreen = false;
|
||||
|
||||
try {
|
||||
// Wait for the server to die
|
||||
int msg;
|
||||
while ((msg = System.in.read()) != -1) {
|
||||
int type = msg & MSG_TYPE_MASK;
|
||||
int param = msg >> MSG_PARAM_SHIFT;
|
||||
switch (type) {
|
||||
case MSG_TYPE_RESTORE_STAY_ON:
|
||||
restoreStayOn = param > 7 ? -1 : param;
|
||||
break;
|
||||
case MSG_TYPE_DISABLE_SHOW_TOUCHES:
|
||||
disableShowTouches = param != 0;
|
||||
break;
|
||||
case MSG_TYPE_RESTORE_DISPLAY_POWER:
|
||||
restoreDisplayPower = param != 0;
|
||||
break;
|
||||
case MSG_TYPE_POWER_OFF_SCREEN:
|
||||
powerOffScreen = param != 0;
|
||||
break;
|
||||
default:
|
||||
Ln.w("Unexpected msg type: " + type);
|
||||
break;
|
||||
}
|
||||
// Only restore display power
|
||||
assert msg == 0 || msg == 1;
|
||||
restoreDisplayPower = msg != 0;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Expected when the server is dead
|
||||
|
@ -16,8 +16,6 @@ import com.genymobile.scrcpy.device.NewDisplay;
|
||||
import com.genymobile.scrcpy.device.Streamer;
|
||||
import com.genymobile.scrcpy.util.Ln;
|
||||
import com.genymobile.scrcpy.util.LogUtils;
|
||||
import com.genymobile.scrcpy.util.Settings;
|
||||
import com.genymobile.scrcpy.util.SettingsException;
|
||||
import com.genymobile.scrcpy.video.CameraCapture;
|
||||
import com.genymobile.scrcpy.video.NewDisplayCapture;
|
||||
import com.genymobile.scrcpy.video.ScreenCapture;
|
||||
@ -25,7 +23,6 @@ import com.genymobile.scrcpy.video.SurfaceCapture;
|
||||
import com.genymobile.scrcpy.video.SurfaceEncoder;
|
||||
import com.genymobile.scrcpy.video.VideoSource;
|
||||
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Build;
|
||||
|
||||
import java.io.File;
|
||||
@ -76,51 +73,6 @@ public final class Server {
|
||||
// not instantiable
|
||||
}
|
||||
|
||||
private static void initAndCleanUp(Options options, CleanUp cleanUp) {
|
||||
// This method is called from its own thread, so it may only configure cleanup actions which are NOT dynamic (i.e. they are configured once
|
||||
// and for all, they cannot be changed from another thread)
|
||||
|
||||
if (options.getShowTouches()) {
|
||||
try {
|
||||
String oldValue = Settings.getAndPutValue(Settings.TABLE_SYSTEM, "show_touches", "1");
|
||||
// If "show touches" was disabled, it must be disabled back on clean up
|
||||
if (!"1".equals(oldValue)) {
|
||||
if (!cleanUp.setDisableShowTouches(true)) {
|
||||
Ln.e("Could not disable show touch on exit");
|
||||
}
|
||||
}
|
||||
} catch (SettingsException e) {
|
||||
Ln.e("Could not change \"show_touches\"", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.getStayAwake()) {
|
||||
int stayOn = BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB | BatteryManager.BATTERY_PLUGGED_WIRELESS;
|
||||
try {
|
||||
String oldValue = Settings.getAndPutValue(Settings.TABLE_GLOBAL, "stay_on_while_plugged_in", String.valueOf(stayOn));
|
||||
try {
|
||||
int restoreStayOn = Integer.parseInt(oldValue);
|
||||
if (restoreStayOn != stayOn) {
|
||||
// Restore only if the current value is different
|
||||
if (!cleanUp.setRestoreStayOn(restoreStayOn)) {
|
||||
Ln.e("Could not restore stay on on exit");
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// ignore
|
||||
}
|
||||
} catch (SettingsException e) {
|
||||
Ln.e("Could not change \"stay_on_while_plugged_in\"", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.getPowerOffScreenOnClose()) {
|
||||
if (!cleanUp.setPowerOffScreen(true)) {
|
||||
Ln.e("Could not power off screen on exit");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void scrcpy(Options options) throws IOException, ConfigurationException {
|
||||
if (Build.VERSION.SDK_INT < AndroidVersions.API_31_ANDROID_12 && options.getVideoSource() == VideoSource.CAMERA) {
|
||||
Ln.e("Camera mirroring is not supported before Android 12");
|
||||
@ -150,14 +102,12 @@ public final class Server {
|
||||
}
|
||||
|
||||
CleanUp cleanUp = null;
|
||||
Thread initThread = null;
|
||||
|
||||
NewDisplay newDisplay = options.getNewDisplay();
|
||||
int displayId = newDisplay == null ? options.getDisplayId() : Device.DISPLAY_ID_NONE;
|
||||
|
||||
if (options.getCleanup()) {
|
||||
cleanUp = CleanUp.configure(displayId);
|
||||
initThread = startInitThread(options, cleanUp);
|
||||
cleanUp = CleanUp.start(displayId, options);
|
||||
}
|
||||
|
||||
int scid = options.getScid();
|
||||
@ -240,8 +190,8 @@ public final class Server {
|
||||
|
||||
completion.await();
|
||||
} finally {
|
||||
if (initThread != null) {
|
||||
initThread.interrupt();
|
||||
if (cleanUp != null) {
|
||||
cleanUp.interrupt();
|
||||
}
|
||||
for (AsyncProcessor asyncProcessor : asyncProcessors) {
|
||||
asyncProcessor.stop();
|
||||
@ -250,8 +200,8 @@ public final class Server {
|
||||
connection.shutdown();
|
||||
|
||||
try {
|
||||
if (initThread != null) {
|
||||
initThread.join();
|
||||
if (cleanUp != null) {
|
||||
cleanUp.join();
|
||||
}
|
||||
for (AsyncProcessor asyncProcessor : asyncProcessors) {
|
||||
asyncProcessor.join();
|
||||
@ -264,12 +214,6 @@ public final class Server {
|
||||
}
|
||||
}
|
||||
|
||||
private static Thread startInitThread(final Options options, final CleanUp cleanUp) {
|
||||
Thread thread = new Thread(() -> initAndCleanUp(options, cleanUp), "init-cleanup");
|
||||
thread.start();
|
||||
return thread;
|
||||
}
|
||||
|
||||
public static void main(String... args) {
|
||||
int status = 0;
|
||||
try {
|
||||
|
Loading…
x
Reference in New Issue
Block a user