Commit b4644a8f authored by Matt Reynolds's avatar Matt Reynolds Committed by Commit Bot

[gamepad] Fix Joy-Con Charging Grip disconnection crash

This CL avoids a crash when disconnecting a Joy-Con Charging
Grip gamepad. The Joy-Con Charging Grip is a USB-C device that
docks with two Nintendo Switch Joy-Cons and allows them to
behave like a single USB gamepad.

When disconnecting, NintendoDataFetcher::RemoveDevice decomposes
the gamepad representing the charging grip into its Joy-Con
subcomponents (composite_left_ and composite_right_). The parent
device is then shut down, which may trigger a "stop vibration"
command. This causes a null dereference when it tries to forward
the vibration command to the subcomponent.

To fix, the vibration command is sent before the subcomponents
have been removed from the parent device and additional checks
are added to ensure the subcomponents are not dereferenced after
the parent is decomposed.

BUG=995548

Change-Id: I1d82e423b134ab3c99dd1e98a6615555cfadd47e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1758980Reviewed-by: default avatarOvidio de Jesús Ruiz-Henríquez <odejesush@chromium.org>
Commit-Queue: Matt Reynolds <mattreynolds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#691885}
parent a363daa2
...@@ -886,6 +886,9 @@ bool NintendoController::IsNintendoController(uint16_t vendor_id, ...@@ -886,6 +886,9 @@ bool NintendoController::IsNintendoController(uint16_t vendor_id,
std::vector<std::unique_ptr<NintendoController>> std::vector<std::unique_ptr<NintendoController>>
NintendoController::Decompose() { NintendoController::Decompose() {
// Stop any ongoing vibration effects before decomposing the device.
SetZeroVibration();
std::vector<std::unique_ptr<NintendoController>> decomposed_devices; std::vector<std::unique_ptr<NintendoController>> decomposed_devices;
if (composite_left_) if (composite_left_)
decomposed_devices.push_back(std::move(composite_left_)); decomposed_devices.push_back(std::move(composite_left_));
...@@ -951,7 +954,7 @@ bool NintendoController::IsUsable() const { ...@@ -951,7 +954,7 @@ bool NintendoController::IsUsable() const {
if (state_ != kInitialized) if (state_ != kInitialized)
return false; return false;
if (is_composite_) if (is_composite_)
return true; return composite_left_ && composite_right_;
switch (gamepad_id_) { switch (gamepad_id_) {
case GamepadId::kNintendoProduct2009: case GamepadId::kNintendoProduct2009:
case GamepadId::kNintendoProduct2006: case GamepadId::kNintendoProduct2006:
...@@ -968,10 +971,12 @@ bool NintendoController::IsUsable() const { ...@@ -968,10 +971,12 @@ bool NintendoController::IsUsable() const {
} }
bool NintendoController::HasGuid(const std::string& guid) const { bool NintendoController::HasGuid(const std::string& guid) const {
if (is_composite_) if (is_composite_) {
DCHECK(composite_left_);
DCHECK(composite_right_);
return composite_left_->HasGuid(guid) || composite_right_->HasGuid(guid); return composite_left_->HasGuid(guid) || composite_right_->HasGuid(guid);
else }
return device_info_->guid == guid; return device_info_->guid == guid;
} }
GamepadStandardMappingFunction NintendoController::GetMappingFunction() const { GamepadStandardMappingFunction NintendoController::GetMappingFunction() const {
...@@ -1027,6 +1032,8 @@ void NintendoController::UpdatePadConnected() { ...@@ -1027,6 +1032,8 @@ void NintendoController::UpdatePadConnected() {
void NintendoController::UpdateGamepadState(Gamepad& pad) const { void NintendoController::UpdateGamepadState(Gamepad& pad) const {
if (is_composite_) { if (is_composite_) {
DCHECK(composite_left_);
DCHECK(composite_right_);
// If this is a composite device, update the gamepad state using the state // If this is a composite device, update the gamepad state using the state
// of the subcomponents. // of the subcomponents.
pad.connected = true; pad.connected = true;
...@@ -1709,8 +1716,10 @@ void NintendoController::SetVibration(double strong_magnitude, ...@@ -1709,8 +1716,10 @@ void NintendoController::SetVibration(double strong_magnitude,
double weak_magnitude) { double weak_magnitude) {
if (is_composite_) { if (is_composite_) {
// Split the vibration effect between the left and right subdevices. // Split the vibration effect between the left and right subdevices.
composite_left_->SetVibration(strong_magnitude, 0); if (composite_left_ && composite_right_) {
composite_right_->SetVibration(0, weak_magnitude); composite_left_->SetVibration(strong_magnitude, 0);
composite_right_->SetVibration(0, weak_magnitude);
}
} else { } else {
RequestVibration(kVibrationFrequencyStrongRumble, RequestVibration(kVibrationFrequencyStrongRumble,
kVibrationAmplitudeStrongRumbleMax * strong_magnitude, kVibrationAmplitudeStrongRumbleMax * strong_magnitude,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment