Compare commits

..

1 Commits

Author SHA1 Message Date
Romain Vimont
95e455faca Fix possible division by zero
On sway (a window manager), SDL_WINDOWEVENT_EXPOSED and
SDL_WINDOWEVENT_SIZE_CHANGED might not be called before a mouse event is
triggered. As a consequence, the "content rectangle" might not be
initialized when the mouse event is processed, causing a division by
zero.

To avoid the problem, initialize the content rect immediately when the
window is shown.

Fixes #4115 <https://github.com/Genymobile/scrcpy/issues/4115>
2023-06-27 18:38:10 +02:00
19 changed files with 194 additions and 206 deletions

1
.gitignore vendored
View File

@@ -7,4 +7,3 @@ build/
.gradle/ .gradle/
/x/ /x/
local.properties local.properties
/scrcpy-server

View File

@@ -1,11 +1,11 @@
# scrcpy (v2.1.1) # scrcpy (v2.1)
<img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" /> <img src="app/data/icon.svg" width="128" height="128" alt="scrcpy" align="right" />
_pronounced "**scr**een **c**o**py**"_ _pronounced "**scr**een **c**o**py**"_
This application mirrors Android devices (video and audio) connected via This application mirrors Android devices (video and audio) connected via
USB or [over TCP/IP](doc/connection.md#tcpip-wireless), and allows to control the USB or [over TCP/IP](doc/device.md#tcpip-wireless), and allows to control the
device with the keyboard and the mouse of the computer. It does not require any device with the keyboard and the mouse of the computer. It does not require any
_root_ access. It works on _Linux_, _Windows_ and _macOS_. _root_ access. It works on _Linux_, _Windows_ and _macOS_.
@@ -68,11 +68,10 @@ mode](doc/hid-otg.md#otg).
The application provides a lot of features and configuration options. They are The application provides a lot of features and configuration options. They are
documented in the following pages: documented in the following pages:
- [Connection](doc/connection.md) - [Device](doc/device.md)
- [Video](doc/video.md) - [Video](doc/video.md)
- [Audio](doc/audio.md) - [Audio](doc/audio.md)
- [Control](doc/control.md) - [Control](doc/control.md)
- [Device](doc/device.md)
- [Window](doc/window.md) - [Window](doc/window.md)
- [Recording](doc/recording.md) - [Recording](doc/recording.md)
- [Tunnels](doc/tunnels.md) - [Tunnels](doc/tunnels.md)
@@ -118,10 +117,7 @@ For general questions or discussions, you can also use:
I'm [@rom1v](https://github.com/rom1v), the author and maintainer of _scrcpy_. I'm [@rom1v](https://github.com/rom1v), the author and maintainer of _scrcpy_.
If you appreciate this application, you can [support my open source If you appreciate this application, you can [support my open source
work][donate]: work][donate].
- [GitHub Sponsors](https://github.com/sponsors/rom1v)
- [Liberapay](https://liberapay.com/rom1v/)
- [PayPal](https://paypal.me/rom2v)
[donate]: https://blog.rom1v.com/about/#support-my-open-source-work [donate]: https://blog.rom1v.com/about/#support-my-open-source-work

View File

@@ -13,7 +13,7 @@ BEGIN
VALUE "LegalCopyright", "Romain Vimont, Genymobile" VALUE "LegalCopyright", "Romain Vimont, Genymobile"
VALUE "OriginalFilename", "scrcpy.exe" VALUE "OriginalFilename", "scrcpy.exe"
VALUE "ProductName", "scrcpy" VALUE "ProductName", "scrcpy"
VALUE "ProductVersion", "2.1.1" VALUE "ProductVersion", "2.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@@ -628,8 +628,8 @@ sc_adb_select_device(struct sc_intr *intr,
return false; return false;
} }
LOGI("ADB device found:"); LOGD("ADB device found:");
sc_adb_devices_log(SC_LOG_LEVEL_INFO, vec.data, vec.size); sc_adb_devices_log(SC_LOG_LEVEL_DEBUG, vec.data, vec.size);
// Move devics into out_device (do not destroy device) // Move devics into out_device (do not destroy device)
sc_adb_device_move(out_device, device); sc_adb_device_move(out_device, device);

View File

@@ -105,6 +105,10 @@ scrcpy_otg(struct scrcpy_options *options) {
usb_device_initialized = true; usb_device_initialized = true;
LOGI("USB device: %s (%04x:%04x) %s %s", usb_device.serial,
(unsigned) usb_device.vid, (unsigned) usb_device.pid,
usb_device.manufacturer, usb_device.product);
ok = sc_usb_connect(&s->usb, usb_device.device, &cbs, NULL); ok = sc_usb_connect(&s->usb, usb_device.device, &cbs, NULL);
if (!ok) { if (!ok) {
goto end; goto end;

View File

@@ -213,8 +213,8 @@ sc_usb_select_device(struct sc_usb *usb, const char *serial,
assert(sel_count == 1); // sel_idx is valid only if sel_count == 1 assert(sel_count == 1); // sel_idx is valid only if sel_count == 1
struct sc_usb_device *device = &vec.data[sel_idx]; struct sc_usb_device *device = &vec.data[sel_idx];
LOGI("USB device found:"); LOGD("USB device found:");
sc_usb_devices_log(SC_LOG_LEVEL_INFO, vec.data, vec.size); sc_usb_devices_log(SC_LOG_LEVEL_DEBUG, vec.data, vec.size);
// Move device into out_device (do not destroy device) // Move device into out_device (do not destroy device)
sc_usb_device_move(out_device, device); sc_usb_device_move(out_device, device);

View File

@@ -77,13 +77,6 @@ In particular, if you get the following error:
then your device has no Opus encoder: try `scrcpy --audio-codec=aac`. then your device has no Opus encoder: try `scrcpy --audio-codec=aac`.
For advanced usage, to pass arbitrary parameters to the [`MediaFormat`],
check `--audio-codec-options` in the manpage or in `scrcpy --help`.
[`MediaFormat`]: https://developer.android.com/reference/android/media/MediaFormat
## Encoder
Several encoders may be available on the device. They can be listed by: Several encoders may be available on the device. They can be listed by:
@@ -93,10 +86,15 @@ scrcpy --list-encoders
To select a specific encoder: To select a specific encoder:
```bash ```
scrcpy --audio-codec=opus --audio-encoder='c2.android.opus.encoder' scrcpy --audio-codec=opus --audio-encoder='c2.android.opus.encoder'
``` ```
For advanced usage, to pass arbitrary parameters to the [`MediaFormat`],
check `--audio-codec-options` in the manpage or in `scrcpy --help`.
[`MediaFormat`]: https://developer.android.com/reference/android/media/MediaFormat
## Bit rate ## Bit rate

View File

@@ -77,7 +77,7 @@ pip3 install meson
sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
# client build dependencies # client build dependencies
sudo dnf install SDL2-devel ffms2-devel libusb1-devel meson gcc make sudo dnf install SDL2-devel ffms2-devel libusb-devel meson gcc make
# server build dependencies # server build dependencies
sudo dnf install java-devel sudo dnf install java-devel
@@ -233,10 +233,10 @@ install` must be run as root)._
#### Option 2: Use prebuilt server #### Option 2: Use prebuilt server
- [`scrcpy-server-v2.1.1`][direct-scrcpy-server] - [`scrcpy-server-v2.1`][direct-scrcpy-server]
<sub>SHA-256: `9558db6c56743a1dc03b38f59801fb40e91cc891f8fc0c89e5b0b067761f148e`</sub> <sub>SHA-256: `5b8bf1940264b930c71a1c614c57da2247f52b2d4240bca865cc6d366dff6688`</sub>
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v2.1.1/scrcpy-server-v2.1.1 [direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v2.1/scrcpy-server-v2.1
Download the prebuilt server somewhere, and specify its path during the Meson Download the prebuilt server somewhere, and specify its path during the Meson
configuration: configuration:

View File

@@ -1,125 +0,0 @@
# Connection
## Selection
If exactly one device is connected (i.e. listed by `adb devices`), then it is
automatically selected.
However, if there are multiple devices connected, you must specify the one to
use in one of 4 ways:
- by its serial:
```bash
scrcpy --serial=0123456789abcdef
scrcpy -s 0123456789abcdef # short version
# the serial is the ip:port if connected over TCP/IP (same behavior as adb)
scrcpy --serial=192.168.1.1:5555
```
- the one connected over USB (if there is exactly one):
```bash
scrcpy --select-usb
scrcpy -d # short version
```
- the one connected over TCP/IP (if there is exactly one):
```bash
scrcpy --select-tcpip
scrcpy -e # short version
```
- a device already listening on TCP/IP (see [below](#tcpip-wireless)):
```bash
scrcpy --tcpip=192.168.1.1:5555
scrcpy --tcpip=192.168.1.1 # default port is 5555
```
The serial may also be provided via the environment variable `ANDROID_SERIAL`
(also used by `adb`):
```bash
# in bash
export ANDROID_SERIAL=0123456789abcdef
scrcpy
```
```cmd
:: in cmd
set ANDROID_SERIAL=0123456789abcdef
scrcpy
```
```powershell
# in PowerShell
$env:ANDROID_SERIAL = '0123456789abcdef'
scrcpy
```
## TCP/IP (wireless)
_Scrcpy_ uses `adb` to communicate with the device, and `adb` can [connect] to a
device over TCP/IP. The device must be connected on the same network as the
computer.
[connect]: https://developer.android.com/studio/command-line/adb.html#wireless
### Automatic
An option `--tcpip` allows to configure the connection automatically. There are
two variants.
If the device (accessible at 192.168.1.1 in this example) already listens on a
port (typically 5555) for incoming _adb_ connections, then run:
```bash
scrcpy --tcpip=192.168.1.1 # default port is 5555
scrcpy --tcpip=192.168.1.1:5555
```
If _adb_ TCP/IP mode is disabled on the device (or if you don't know the IP
address), connect the device over USB, then run:
```bash
scrcpy --tcpip # without arguments
```
It will automatically find the device IP address and adb port, enable TCP/IP
mode if necessary, then connect to the device before starting.
### Manual
Alternatively, it is possible to enable the TCP/IP connection manually using
`adb`:
1. Plug the device into a USB port on your computer.
2. Connect the device to the same Wi-Fi network as your computer.
3. Get your device IP address, in Settings → About phone → Status, or by
executing this command:
```bash
adb shell ip route | awk '{print $9}'
```
4. Enable `adb` over TCP/IP on your device: `adb tcpip 5555`.
5. Unplug your device.
6. Connect to your device: `adb connect DEVICE_IP:5555` _(replace `DEVICE_IP`
with the device IP address you found)_.
7. Run `scrcpy` as usual.
8. Run `adb disconnect` once you're done.
Since Android 11, a [wireless debugging option][adb-wireless] allows to bypass
having to physically connect your device directly to your computer.
[adb-wireless]: https://developer.android.com/studio/command-line/adb#wireless-android11-command-line
## Autostart
A small tool (by the scrcpy author) allows to run arbitrary commands whenever a
new Android device is connected: [AutoAdb]. It can be used to start scrcpy:
```bash
autoadb scrcpy -s '{}'
```
[AutoAdb]: https://github.com/rom1v/autoadb

View File

@@ -1,9 +1,156 @@
# Device # Device
## Selection
If exactly one device is connected (i.e. listed by `adb devices`), then it is
automatically selected.
However, if there are multiple devices connected, you must specify the one to
use in one of 4 ways:
- by its serial:
```bash
scrcpy --serial=0123456789abcdef
scrcpy -s 0123456789abcdef # short version
# the serial is the ip:port if connected over TCP/IP (same behavior as adb)
scrcpy --serial=192.168.1.1:5555
```
- the one connected over USB (if there is exactly one):
```bash
scrcpy --select-usb
scrcpy -d # short version
```
- the one connected over TCP/IP (if there is exactly one):
```bash
scrcpy --select-tcpip
scrcpy -e # short version
```
- a device already listening on TCP/IP (see [below](#tcpip-wireless)):
```bash
scrcpy --tcpip=192.168.1.1:5555
scrcpy --tcpip=192.168.1.1 # default port is 5555
```
The serial may also be provided via the environment variable `ANDROID_SERIAL`
(also used by `adb`):
```bash
# in bash
export ANDROID_SERIAL=0123456789abcdef
scrcpy
```
```cmd
:: in cmd
set ANDROID_SERIAL=0123456789abcdef
scrcpy
```
```powershell
# in PowerShell
$env:ANDROID_SERIAL = '0123456789abcdef'
scrcpy
```
## TCP/IP (wireless)
_Scrcpy_ uses `adb` to communicate with the device, and `adb` can [connect] to a
device over TCP/IP. The device must be connected on the same network as the
computer.
[connect]: https://developer.android.com/studio/command-line/adb.html#wireless
### Automatic
An option `--tcpip` allows to configure the connection automatically. There are
two variants.
If the device (accessible at 192.168.1.1 in this example) already listens on a
port (typically 5555) for incoming _adb_ connections, then run:
```bash
scrcpy --tcpip=192.168.1.1 # default port is 5555
scrcpy --tcpip=192.168.1.1:5555
```
If _adb_ TCP/IP mode is disabled on the device (or if you don't know the IP
address), connect the device over USB, then run:
```bash
scrcpy --tcpip # without arguments
```
It will automatically find the device IP address and adb port, enable TCP/IP
mode if necessary, then connect to the device before starting.
### Manual
Alternatively, it is possible to enable the TCP/IP connection manually using
`adb`:
1. Plug the device into a USB port on your computer.
2. Connect the device to the same Wi-Fi network as your computer.
3. Get your device IP address, in Settings → About phone → Status, or by
executing this command:
```bash
adb shell ip route | awk '{print $9}'
```
4. Enable `adb` over TCP/IP on your device: `adb tcpip 5555`.
5. Unplug your device.
6. Connect to your device: `adb connect DEVICE_IP:5555` _(replace `DEVICE_IP`
with the device IP address you found)_.
7. Run `scrcpy` as usual.
8. Run `adb disconnect` once you're done.
Since Android 11, a [wireless debugging option][adb-wireless] allows to bypass
having to physically connect your device directly to your computer.
[adb-wireless]: https://developer.android.com/studio/command-line/adb#wireless-android11-command-line
## Autostart
A small tool (by the scrcpy author) allows to run arbitrary commands whenever a
new Android device is connected: [AutoAdb]. It can be used to start scrcpy:
```bash
autoadb scrcpy -s '{}'
```
[AutoAdb]: https://github.com/rom1v/autoadb
## Display
If several displays are available on the Android device, it is possible to
select the display to mirror:
```bash
scrcpy --display=1
```
The list of display ids can be retrieved by:
```bash
scrcpy --list-displays
```
A secondary display may only be controlled if the device runs at least Android
10 (otherwise it is mirrored as read-only).
## Actions
Some command line arguments perform actions on the device itself while scrcpy is Some command line arguments perform actions on the device itself while scrcpy is
running. running.
## Stay awake
### Stay awake
To prevent the device from sleeping after a delay **when the device is plugged To prevent the device from sleeping after a delay **when the device is plugged
in**: in**:
@@ -19,7 +166,7 @@ If the device is not plugged in (i.e. only connected over TCP/IP),
`--stay-awake` has no effect (this is the Android behavior). `--stay-awake` has no effect (this is the Android behavior).
## Turn screen off ### Turn screen off
It is possible to turn the device screen off while mirroring on start with a It is possible to turn the device screen off while mirroring on start with a
command-line option: command-line option:
@@ -47,7 +194,7 @@ scrcpy -Sw # short version
``` ```
## Show touches ### Show touches
For presentations, it may be useful to show physical touches (on the physical For presentations, it may be useful to show physical touches (on the physical
device). Android exposes this feature in _Developers options_. device). Android exposes this feature in _Developers options_.
@@ -63,7 +210,7 @@ scrcpy -t # short version
Note that it only shows _physical_ touches (by a finger on the device). Note that it only shows _physical_ touches (by a finger on the device).
## Power off on close ### Power off on close
To turn the device screen off when closing _scrcpy_: To turn the device screen off when closing _scrcpy_:
@@ -71,10 +218,11 @@ To turn the device screen off when closing _scrcpy_:
scrcpy --power-off-on-close scrcpy --power-off-on-close
``` ```
## Power on on start ### Power on on start
By default, on start, the device is powered on. To prevent this behavior: By default, on start, the device is powered on. To prevent this behavior:
```bash ```bash
scrcpy --no-power-on scrcpy --no-power-on
``` ```

View File

@@ -66,14 +66,6 @@ scrcpy --video-codec=av1
H265 may provide better quality, but H264 should provide lower latency. H265 may provide better quality, but H264 should provide lower latency.
AV1 encoders are not common on current Android devices. AV1 encoders are not common on current Android devices.
For advanced usage, to pass arbitrary parameters to the [`MediaFormat`],
check `--video-codec-options` in the manpage or in `scrcpy --help`.
[`MediaFormat`]: https://developer.android.com/reference/android/media/MediaFormat
## Encoder
Several encoders may be available on the device. They can be listed by: Several encoders may be available on the device. They can be listed by:
```bash ```bash
@@ -87,6 +79,11 @@ try another one:
scrcpy --video-codec=h264 --video-encoder='OMX.qcom.video.encoder.avc' scrcpy --video-codec=h264 --video-encoder='OMX.qcom.video.encoder.avc'
``` ```
For advanced usage, to pass arbitrary parameters to the [`MediaFormat`],
check `--video-codec-options` in the manpage or in `scrcpy --help`.
[`MediaFormat`]: https://developer.android.com/reference/android/media/MediaFormat
## Rotation ## Rotation
@@ -137,25 +134,6 @@ phone, landscape for a tablet).
If `--max-size` is also specified, resizing is applied after cropping. If `--max-size` is also specified, resizing is applied after cropping.
## Display
If several displays are available on the Android device, it is possible to
select the display to mirror:
```bash
scrcpy --display=1
```
The list of display ids can be retrieved by:
```bash
scrcpy --list-displays
```
A secondary display may only be controlled if the device runs at least Android
10 (otherwise it is mirrored as read-only).
## Buffering ## Buffering
By default, there is no video buffering, to get the lowest possible latency. By default, there is no video buffering, to get the lowest possible latency.

View File

@@ -4,14 +4,14 @@
Download the [latest release]: Download the [latest release]:
- [`scrcpy-win64-v2.1.1.zip`][direct-win64] (64-bit) - [`scrcpy-win64-v2.1.zip`][direct-win64] (64-bit)
<sub>SHA-256: `f77281e1bce2f9934617699c581f063d5b327f012eff602ee98fb2ef550c25c2`</sub> <sub>SHA-256: `57b98813322c8b5b560ada68714a2cd7b7efe64086fa61d03e389c23212c803d`</sub>
- [`scrcpy-win32-v2.1.1.zip`][direct-win32] (32-bit) - [`scrcpy-win32-v2.1.zip`][direct-win32] (32-bit)
<sub>SHA-256: `ef7ae7fbe9449f2643febdc2244fb186d1a746a3c736394150cfd14f06d3c943`</sub> <sub>SHA-256: `4d261d391a60ea975440d83cdc22f8250b3c8985f2ece8c7e53d6fb26c0d74ed`</sub>
[latest release]: https://github.com/Genymobile/scrcpy/releases/latest [latest release]: https://github.com/Genymobile/scrcpy/releases/latest
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v2.1.1/scrcpy-win64-v2.1.1.zip [direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v2.1/scrcpy-win64-v2.1.zip
[direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v2.1.1/scrcpy-win32-v2.1.1.zip [direct-win32]: https://github.com/Genymobile/scrcpy/releases/download/v2.1/scrcpy-win32-v2.1.zip
and extract it. and extract it.

View File

@@ -2,8 +2,8 @@
set -e set -e
BUILDDIR=build-auto BUILDDIR=build-auto
PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v2.1.1/scrcpy-server-v2.1.1 PREBUILT_SERVER_URL=https://github.com/Genymobile/scrcpy/releases/download/v2.1/scrcpy-server-v2.1
PREBUILT_SERVER_SHA256=9558db6c56743a1dc03b38f59801fb40e91cc891f8fc0c89e5b0b067761f148e PREBUILT_SERVER_SHA256=5b8bf1940264b930c71a1c614c57da2247f52b2d4240bca865cc6d366dff6688
echo "[scrcpy] Downloading prebuilt server..." echo "[scrcpy] Downloading prebuilt server..."
wget "$PREBUILT_SERVER_URL" -O scrcpy-server wget "$PREBUILT_SERVER_URL" -O scrcpy-server

View File

@@ -1,5 +1,5 @@
project('scrcpy', 'c', project('scrcpy', 'c',
version: '2.1.1', version: '2.1',
meson_version: '>= 0.48', meson_version: '>= 0.48',
default_options: [ default_options: [
'c_std=c11', 'c_std=c11',

View File

@@ -7,8 +7,8 @@ android {
applicationId "com.genymobile.scrcpy" applicationId "com.genymobile.scrcpy"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 33 targetSdkVersion 33
versionCode 20101 versionCode 20100
versionName "2.1.1" versionName "2.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {

View File

@@ -12,7 +12,7 @@
set -e set -e
SCRCPY_DEBUG=false SCRCPY_DEBUG=false
SCRCPY_VERSION_NAME=2.1.1 SCRCPY_VERSION_NAME=2.1
PLATFORM=${ANDROID_PLATFORM:-33} PLATFORM=${ANDROID_PLATFORM:-33}
BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-33.0.0} BUILD_TOOLS=${ANDROID_BUILD_TOOLS:-33.0.0}

View File

@@ -118,7 +118,7 @@ public final class AudioCapture {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
startWorkaroundAndroid11(); startWorkaroundAndroid11();
try { try {
tryStartRecording(5, 100); tryStartRecording(3, 100);
} finally { } finally {
stopWorkaroundAndroid11(); stopWorkaroundAndroid11();
} }

View File

@@ -103,11 +103,6 @@ public final class Device {
ServiceManager.getWindowManager().registerDisplayFoldListener(new IDisplayFoldListener.Stub() { ServiceManager.getWindowManager().registerDisplayFoldListener(new IDisplayFoldListener.Stub() {
@Override @Override
public void onDisplayFoldChanged(int displayId, boolean folded) { public void onDisplayFoldChanged(int displayId, boolean folded) {
if (Device.this.displayId != displayId) {
// Ignore events related to other display ids
return;
}
synchronized (Device.this) { synchronized (Device.this) {
DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(displayId); DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(displayId);
if (displayInfo == null) { if (displayInfo == null) {

View File

@@ -8,7 +8,6 @@ import android.media.MediaCodecInfo;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.os.Build; import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock; import android.os.SystemClock;
import android.view.Surface; import android.view.Surface;
@@ -286,10 +285,6 @@ public class ScreenEncoder implements Device.RotationListener, Device.FoldListen
@Override @Override
public void start(TerminationListener listener) { public void start(TerminationListener listener) {
thread = new Thread(() -> { thread = new Thread(() -> {
// Some devices (Meizu) deadlock if the video encoding thread has no Looper
// <https://github.com/Genymobile/scrcpy/issues/4143>
Looper.prepare();
try { try {
streamScreen(); streamScreen();
} catch (ConfigurationException e) { } catch (ConfigurationException e) {