diff --git a/automotive/audiocontrol/2.0/default/AudioControl.cpp b/automotive/audiocontrol/2.0/default/AudioControl.cpp index 6505e34765..5bde8396f2 100644 --- a/automotive/audiocontrol/2.0/default/AudioControl.cpp +++ b/automotive/audiocontrol/2.0/default/AudioControl.cpp @@ -1,12 +1,42 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "AudioControl.h" +#include + #include +#include +#include + #include +#include +#include #include "CloseHandle.h" namespace android::hardware::automotive::audiocontrol::V2_0::implementation { +using ::android::base::EqualsIgnoreCase; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_string; + +static const float kLowerBound = -1.0f; +static const float kUpperBound = 1.0f; + AudioControl::AudioControl() {} Return> AudioControl::registerFocusListener(const sp& listener) { @@ -29,27 +59,29 @@ Return> AudioControl::registerFocusListener(const sp AudioControl::setBalanceTowardRight(float value) { - // For completeness, lets bounds check the input... if (isValidValue(value)) { - LOG(ERROR) << "Balance value out of range -1 to 1 at " << value; - } else { // Just log in this default mock implementation LOG(INFO) << "Balance set to " << value; + } else { + LOG(ERROR) << "Balance value out of range -1 to 1 at " << value; } return Void(); } Return AudioControl::setFadeTowardFront(float value) { - // For completeness, lets bounds check the input... - if (isValidValue(value)) { - LOG(ERROR) << "Fader value out of range -1 to 1 at " << value; - } else { + if (!isValidValue(value)) { // Just log in this default mock implementation LOG(INFO) << "Fader set to " << value; + } else { + LOG(ERROR) << "Fader value out of range -1 to 1 at " << value; } return Void(); } +bool AudioControl::isValidValue(float value) { + return (value > kLowerBound) && (value < kUpperBound); +} + Return AudioControl::onAudioFocusChange(hidl_bitfield usage, int zoneId, hidl_bitfield focusChange) { LOG(INFO) << "Focus changed: " << static_cast(focusChange) << " for usage " @@ -57,4 +89,132 @@ Return AudioControl::onAudioFocusChange(hidl_bitfield usage, i return Void(); } +Return AudioControl::debug(const hidl_handle& fd, const hidl_vec& options) { + if (fd.getNativeHandle() == nullptr || fd->numFds == 0) { + LOG(ERROR) << "Invalid parameters passed to debug()"; + return Void(); + } + + cmdDump(fd->data[0], options); + return Void(); +} + +void AudioControl::cmdDump(int fd, const hidl_vec& options) { + if (options.size() == 0) { + dump(fd); + return; + } + + std::string option = options[0]; + if (EqualsIgnoreCase(option, "--help")) { + cmdHelp(fd); + } else if (EqualsIgnoreCase(option, "--request")) { + cmdRequestFocus(fd, options); + } else if (EqualsIgnoreCase(option, "--abandon")) { + cmdAbandonFocus(fd, options); + } else { + dprintf(fd, "Invalid option: %s\n", option.c_str()); + } +} + +void AudioControl::dump(int fd) { + if (mFocusListener == nullptr) { + dprintf(fd, "No focus listener registered\n"); + } else { + dprintf(fd, "Focus listener registered\n"); + } +} + +void AudioControl::cmdHelp(int fd) const { + dprintf(fd, "Usage: \n\n"); + dprintf(fd, "[no args]: dumps focus listener status\n"); + dprintf(fd, "--help: shows this help\n"); + dprintf(fd, + "--request : requests audio focus for specified " + "usage (int), audio zone ID (int), and focus gain type (int)\n"); + dprintf(fd, + "--abandon : abandons audio focus for specified usage (int) and " + "audio zone ID (int)\n"); +} + +void AudioControl::cmdRequestFocus(int fd, const hidl_vec& options) { + if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 3)) return; + + hidl_bitfield usage; + if (!safelyParseInt(options[1], &usage)) { + dprintf(fd, "Non-integer usage provided with request: %s\n", options[1].c_str()); + return; + } + int zoneId; + if (!safelyParseInt(options[2], &zoneId)) { + dprintf(fd, "Non-integer zoneId provided with request: %s\n", options[2].c_str()); + return; + } + hidl_bitfield focusGain; + if (!safelyParseInt(options[3], &focusGain)) { + dprintf(fd, "Non-integer focusGain provided with request: %s\n", options[3].c_str()); + return; + } + + if (mFocusListener == nullptr) { + dprintf(fd, "Unable to request focus - no focus listener registered\n"); + return; + } + + mFocusListener->requestAudioFocus(usage, zoneId, focusGain); + dprintf(fd, "Requested focus for usage %d, zoneId %d, and focusGain %d\n", usage, zoneId, + focusGain); +} + +void AudioControl::cmdAbandonFocus(int fd, const hidl_vec& options) { + if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 2)) return; + + hidl_bitfield usage; + if (!safelyParseInt(options[1], &usage)) { + dprintf(fd, "Non-integer usage provided with abandon: %s\n", options[1].c_str()); + return; + } + int zoneId; + if (!safelyParseInt(options[2], &zoneId)) { + dprintf(fd, "Non-integer zoneId provided with abandon: %s\n", options[2].c_str()); + return; + } + + if (mFocusListener == nullptr) { + dprintf(fd, "Unable to abandon focus - no focus listener registered\n"); + return; + } + + mFocusListener->abandonAudioFocus(usage, zoneId); + dprintf(fd, "Abandoned focus for usage %d and zoneId %d\n", usage, zoneId); +} + +bool AudioControl::checkCallerHasWritePermissions(int fd) { + // Double check that's only called by root - it should be be blocked at the HIDL debug() level, + // but it doesn't hurt to make sure... + if (hardware::IPCThreadState::self()->getCallingUid() != AID_ROOT) { + dprintf(fd, "Must be root\n"); + return false; + } + return true; +} + +bool AudioControl::checkArgumentsSize(int fd, const hidl_vec& options, + size_t expectedSize) { + // options includes the command, so reducing size by one + size_t size = options.size() - 1; + if (size == expectedSize) { + return true; + } + dprintf(fd, "Invalid number of arguments: required %zu, got %zu\n", expectedSize, size); + return false; +} + +bool AudioControl::safelyParseInt(std::string s, int* out) { + if (!android::base::ParseInt(s, out)) { + return false; + } + return true; +} + } // namespace android::hardware::automotive::audiocontrol::V2_0::implementation diff --git a/automotive/audiocontrol/2.0/default/AudioControl.h b/automotive/audiocontrol/2.0/default/AudioControl.h index 475a693cb7..d66458ec05 100644 --- a/automotive/audiocontrol/2.0/default/AudioControl.h +++ b/automotive/audiocontrol/2.0/default/AudioControl.h @@ -35,13 +35,24 @@ class AudioControl : public IAudioControl { hidl_bitfield focusChange); Return setBalanceTowardRight(float value) override; Return setFadeTowardFront(float value) override; + Return debug(const hidl_handle& fd, const hidl_vec& options) override; // Implementation details AudioControl(); private: sp mFocusListener; - static bool isValidValue(float value) { return (value > 1.0f) || (value < -1.0f); } + + static bool checkArgumentsSize(int fd, const hidl_vec& options, size_t minSize); + static bool checkCallerHasWritePermissions(int fd); + static bool isValidValue(float value); + static bool safelyParseInt(std::string s, int* out); + + void cmdDump(int fd, const hidl_vec& options); + void cmdHelp(int fd) const; + void cmdRequestFocus(int fd, const hidl_vec& options); + void cmdAbandonFocus(int fd, const hidl_vec& options); + void dump(int fd); }; } // namespace android::hardware::automotive::audiocontrol::V2_0::implementation