Do not print stacktraces when unnecessary
User-friendly error messages are printed on specific configuration exceptions. In that case, do not print the stacktrace. Also handle the user-friendly error message directly where the error occurs, and print multiline messages in a single log call, to avoid confusing interleaving.
This commit is contained in:
parent
9f8e96e895
commit
b43938fa66
6 changed files with 44 additions and 77 deletions
|
@ -0,0 +1,7 @@
|
||||||
|
package com.genymobile.scrcpy;
|
||||||
|
|
||||||
|
public class ConfigurationException extends Exception {
|
||||||
|
public ConfigurationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,12 +61,12 @@ public final class Device {
|
||||||
|
|
||||||
private final boolean supportsInputEvents;
|
private final boolean supportsInputEvents;
|
||||||
|
|
||||||
public Device(Options options) {
|
public Device(Options options) throws ConfigurationException {
|
||||||
displayId = options.getDisplayId();
|
displayId = options.getDisplayId();
|
||||||
DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(displayId);
|
DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(displayId);
|
||||||
if (displayInfo == null) {
|
if (displayInfo == null) {
|
||||||
int[] displayIds = ServiceManager.getDisplayManager().getDisplayIds();
|
Ln.e(buildUnknownDisplayIdMessage(displayId));
|
||||||
throw new InvalidDisplayIdException(displayId, displayIds);
|
throw new ConfigurationException("Unknown display id: " + displayId);
|
||||||
}
|
}
|
||||||
|
|
||||||
int displayInfoFlags = displayInfo.getFlags();
|
int displayInfoFlags = displayInfo.getFlags();
|
||||||
|
@ -130,6 +130,18 @@ public final class Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String buildUnknownDisplayIdMessage(int displayId) {
|
||||||
|
StringBuilder msg = new StringBuilder("Display ").append(displayId).append(" not found");
|
||||||
|
int[] displayIds = ServiceManager.getDisplayManager().getDisplayIds();
|
||||||
|
if (displayIds != null && displayIds.length > 0) {
|
||||||
|
msg.append("\nTry to use one of the available display ids:");
|
||||||
|
for (int id : displayIds) {
|
||||||
|
msg.append("\n scrcpy --display=").append(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return msg.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void setMaxSize(int newMaxSize) {
|
public synchronized void setMaxSize(int newMaxSize) {
|
||||||
maxSize = newMaxSize;
|
maxSize = newMaxSize;
|
||||||
screenInfo = ScreenInfo.computeScreenInfo(screenInfo.getReverseVideoRotation(), deviceSize, crop, newMaxSize, lockVideoOrientation);
|
screenInfo = ScreenInfo.computeScreenInfo(screenInfo.getReverseVideoRotation(), deviceSize, crop, newMaxSize, lockVideoOrientation);
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
package com.genymobile.scrcpy;
|
|
||||||
|
|
||||||
public class InvalidDisplayIdException extends RuntimeException {
|
|
||||||
|
|
||||||
private final int displayId;
|
|
||||||
private final int[] availableDisplayIds;
|
|
||||||
|
|
||||||
public InvalidDisplayIdException(int displayId, int[] availableDisplayIds) {
|
|
||||||
super("There is no display having id " + displayId);
|
|
||||||
this.displayId = displayId;
|
|
||||||
this.availableDisplayIds = availableDisplayIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDisplayId() {
|
|
||||||
return displayId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getAvailableDisplayIds() {
|
|
||||||
return availableDisplayIds;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package com.genymobile.scrcpy;
|
|
||||||
|
|
||||||
import android.media.MediaCodecInfo;
|
|
||||||
|
|
||||||
public class InvalidEncoderException extends RuntimeException {
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
private final MediaCodecInfo[] availableEncoders;
|
|
||||||
|
|
||||||
public InvalidEncoderException(String name, MediaCodecInfo[] availableEncoders) {
|
|
||||||
super("There is no encoder having name '" + name + "'");
|
|
||||||
this.name = name;
|
|
||||||
this.availableEncoders = availableEncoders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MediaCodecInfo[] getAvailableEncoders() {
|
|
||||||
return availableEncoders;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -63,7 +63,7 @@ public class ScreenEncoder implements Device.RotationListener {
|
||||||
return rotationChanged.getAndSet(false);
|
return rotationChanged.getAndSet(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void streamScreen(Device device, Callbacks callbacks) throws IOException {
|
public void streamScreen(Device device, Callbacks callbacks) throws IOException, ConfigurationException {
|
||||||
MediaCodec codec = createCodec(videoMimeType, encoderName);
|
MediaCodec codec = createCodec(videoMimeType, encoderName);
|
||||||
MediaFormat format = createFormat(videoMimeType, bitRate, maxFps, codecOptions);
|
MediaFormat format = createFormat(videoMimeType, bitRate, maxFps, codecOptions);
|
||||||
IBinder display = createDisplay();
|
IBinder display = createDisplay();
|
||||||
|
@ -207,14 +207,14 @@ public class ScreenEncoder implements Device.RotationListener {
|
||||||
return result.toArray(new MediaCodecInfo[result.size()]);
|
return result.toArray(new MediaCodecInfo[result.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MediaCodec createCodec(String videoMimeType, String encoderName) throws IOException {
|
private static MediaCodec createCodec(String videoMimeType, String encoderName) throws IOException, ConfigurationException {
|
||||||
if (encoderName != null) {
|
if (encoderName != null) {
|
||||||
Ln.d("Creating encoder by name: '" + encoderName + "'");
|
Ln.d("Creating encoder by name: '" + encoderName + "'");
|
||||||
try {
|
try {
|
||||||
return MediaCodec.createByCodecName(encoderName);
|
return MediaCodec.createByCodecName(encoderName);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
MediaCodecInfo[] encoders = listEncoders(videoMimeType);
|
Ln.e(buildUnknownEncoderMessage(videoMimeType, encoderName));
|
||||||
throw new InvalidEncoderException(encoderName, encoders);
|
throw new ConfigurationException("Unknown encoder: " + encoderName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MediaCodec codec = MediaCodec.createEncoderByType(videoMimeType);
|
MediaCodec codec = MediaCodec.createEncoderByType(videoMimeType);
|
||||||
|
@ -222,6 +222,18 @@ public class ScreenEncoder implements Device.RotationListener {
|
||||||
return codec;
|
return codec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String buildUnknownEncoderMessage(String videoMimeType, String encoderName) {
|
||||||
|
StringBuilder msg = new StringBuilder("Encoder '").append(encoderName).append("' not found");
|
||||||
|
MediaCodecInfo[] encoders = listEncoders(videoMimeType);
|
||||||
|
if (encoders != null && encoders.length > 0) {
|
||||||
|
msg.append("\nTry to use one of the available encoders:");
|
||||||
|
for (MediaCodecInfo encoder : encoders) {
|
||||||
|
msg.append("\n scrcpy --encoder='").append(encoder.getName()).append("'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return msg.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private static void setCodecOption(MediaFormat format, CodecOption codecOption) {
|
private static void setCodecOption(MediaFormat format, CodecOption codecOption) {
|
||||||
String key = codecOption.getKey();
|
String key = codecOption.getKey();
|
||||||
Object value = codecOption.getValue();
|
Object value = codecOption.getValue();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package com.genymobile.scrcpy;
|
package com.genymobile.scrcpy;
|
||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.media.MediaCodecInfo;
|
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
|
@ -59,7 +58,7 @@ public final class Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void scrcpy(Options options) throws IOException {
|
private static void scrcpy(Options options) throws IOException, ConfigurationException {
|
||||||
Ln.i("Device: " + Build.MANUFACTURER + " " + Build.MODEL + " (Android " + Build.VERSION.RELEASE + ")");
|
Ln.i("Device: " + Build.MANUFACTURER + " " + Build.MODEL + " (Android " + Build.VERSION.RELEASE + ")");
|
||||||
final Device device = new Device(options);
|
final Device device = new Device(options);
|
||||||
List<CodecOption> codecOptions = options.getCodecOptions();
|
List<CodecOption> codecOptions = options.getCodecOptions();
|
||||||
|
@ -299,38 +298,19 @@ public final class Server {
|
||||||
return new Rect(x, y, x + width, y + height);
|
return new Rect(x, y, x + width, y + height);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void suggestFix(Throwable e) {
|
|
||||||
if (e instanceof InvalidDisplayIdException) {
|
|
||||||
InvalidDisplayIdException idie = (InvalidDisplayIdException) e;
|
|
||||||
int[] displayIds = idie.getAvailableDisplayIds();
|
|
||||||
if (displayIds != null && displayIds.length > 0) {
|
|
||||||
Ln.e("Try to use one of the available display ids:");
|
|
||||||
for (int id : displayIds) {
|
|
||||||
Ln.e(" scrcpy --display=" + id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (e instanceof InvalidEncoderException) {
|
|
||||||
InvalidEncoderException iee = (InvalidEncoderException) e;
|
|
||||||
MediaCodecInfo[] encoders = iee.getAvailableEncoders();
|
|
||||||
if (encoders != null && encoders.length > 0) {
|
|
||||||
Ln.e("Try to use one of the available encoders:");
|
|
||||||
for (MediaCodecInfo encoder : encoders) {
|
|
||||||
Ln.e(" scrcpy --encoder='" + encoder.getName() + "'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String... args) throws Exception {
|
public static void main(String... args) throws Exception {
|
||||||
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
|
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
|
||||||
Ln.e("Exception on thread " + t, e);
|
Ln.e("Exception on thread " + t, e);
|
||||||
suggestFix(e);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Options options = createOptions(args);
|
Options options = createOptions(args);
|
||||||
|
|
||||||
Ln.initLogLevel(options.getLogLevel());
|
Ln.initLogLevel(options.getLogLevel());
|
||||||
|
|
||||||
|
try {
|
||||||
scrcpy(options);
|
scrcpy(options);
|
||||||
|
} catch (ConfigurationException e) {
|
||||||
|
// Do not print stack trace, a user-friendly error-message has already been logged
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue