Add adb shell command to default AIDL
Add adb shell commands to call methods of tune, seek, step, cancel,
startProgramListUpdates and stopProgramListUpdates in
BroadcastRadio HAL.
Bug: 170336130
Test: m -j
Test: manually test dump options listed in "adb shell dumpsys
android.hardware.broadcastradio.IBroadcastRadio/amfm --help"
Change-Id: I7aac96459f61c36dc9aae2d0a3866272f5bb9aed
diff --git a/broadcastradio/aidl/default/BroadcastRadio.cpp b/broadcastradio/aidl/default/BroadcastRadio.cpp
index 57c5133..0209a0e 100644
--- a/broadcastradio/aidl/default/BroadcastRadio.cpp
+++ b/broadcastradio/aidl/default/BroadcastRadio.cpp
@@ -22,11 +22,15 @@
#include <aidl/android/hardware/broadcastradio/Result.h>
#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+#include <private/android_filesystem_config.h>
namespace aidl::android::hardware::broadcastradio {
using ::aidl::android::hardware::broadcastradio::utils::resultToInt;
using ::aidl::android::hardware::broadcastradio::utils::tunesTo;
+using ::android::base::EqualsIgnoreCase;
using ::ndk::ScopedAStatus;
using ::std::literals::chrono_literals::operator""ms;
using ::std::literals::chrono_literals::operator""s;
@@ -83,6 +87,15 @@
return info;
}
+static bool checkDumpCallerHasWritePermissions(int fd) {
+ uid_t uid = AIBinder_getCallingUid();
+ if (uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM) {
+ return true;
+ }
+ dprintf(fd, "BroadcastRadio HAL dump must be root, shell or system\n");
+ return false;
+}
+
} // namespace
BroadcastRadio::BroadcastRadio(const VirtualRadio& virtualRadio)
@@ -470,4 +483,306 @@
"registering announcementListener is not supported");
}
+binder_status_t BroadcastRadio::dump(int fd, const char** args, uint32_t numArgs) {
+ if (numArgs == 0) {
+ return dumpsys(fd);
+ }
+
+ string option = string(args[0]);
+ if (EqualsIgnoreCase(option, "--help")) {
+ return cmdHelp(fd);
+ } else if (EqualsIgnoreCase(option, "--tune")) {
+ return cmdTune(fd, args, numArgs);
+ } else if (EqualsIgnoreCase(option, "--seek")) {
+ return cmdSeek(fd, args, numArgs);
+ } else if (EqualsIgnoreCase(option, "--step")) {
+ return cmdStep(fd, args, numArgs);
+ } else if (EqualsIgnoreCase(option, "--cancel")) {
+ return cmdCancel(fd, numArgs);
+ } else if (EqualsIgnoreCase(option, "--startProgramListUpdates")) {
+ return cmdStartProgramListUpdates(fd, args, numArgs);
+ } else if (EqualsIgnoreCase(option, "--stopProgramListUpdates")) {
+ return cmdStopProgramListUpdates(fd, numArgs);
+ }
+ dprintf(fd, "Invalid option: %s\n", option.c_str());
+ return STATUS_BAD_VALUE;
+}
+
+binder_status_t BroadcastRadio::dumpsys(int fd) {
+ if (!checkDumpCallerHasWritePermissions(fd)) {
+ return STATUS_PERMISSION_DENIED;
+ }
+ lock_guard<mutex> lk(mMutex);
+ dprintf(fd, "AmFmRegionConfig: %s\n", mAmFmConfig.toString().c_str());
+ dprintf(fd, "Properties: %s \n", mProperties.toString().c_str());
+ if (mIsTuneCompleted) {
+ dprintf(fd, "Tune completed\n");
+ } else {
+ dprintf(fd, "Tune not completed\n");
+ }
+ if (mCallback == nullptr) {
+ dprintf(fd, "No ITunerCallback registered\n");
+ } else {
+ dprintf(fd, "ITunerCallback registered\n");
+ }
+ dprintf(fd, "CurrentProgram: %s \n", mCurrentProgram.toString().c_str());
+ return STATUS_OK;
+}
+
+binder_status_t BroadcastRadio::cmdHelp(int fd) const {
+ dprintf(fd, "Usage: \n\n");
+ dprintf(fd, "[no args]: dumps focus listener / gain callback registered status\n");
+ dprintf(fd, "--help: shows this help\n");
+ dprintf(fd,
+ "--tune amfm <FREQUENCY>: tunes amfm radio to frequency (in Hz) specified: "
+ "frequency (int) \n"
+ "--tune dab <SID> <ENSEMBLE>: tunes dab radio to sid and ensemble specified: "
+ "sidExt (int), ensemble (int) \n");
+ dprintf(fd,
+ "--seek [up|down] <SKIP_SUB_CHANNEL>: seek with direction (up or down) and "
+ "option whether skipping sub channel: "
+ "skipSubChannel (string, should be either \"true\" or \"false\")\n");
+ dprintf(fd, "--step [up|down]: step in direction (up or down) specified\n");
+ dprintf(fd, "--cancel: cancel current pending tune, step, and seek\n");
+ dprintf(fd,
+ "--startProgramListUpdates <IDENTIFIER_TYPES> <IDENTIFIERS> <INCLUDE_CATEGORIES> "
+ "<EXCLUDE_MODIFICATIONS>: start update program list with the filter specified: "
+ "identifier types (string, in format <TYPE>,<TYPE>,...,<TYPE> or \"null\" (if empty), "
+ "where TYPE is int), "
+ "program identifiers (string, in format "
+ "<TYPE>:<VALUE>,<TYPE>:<VALUE>,...,<TYPE>:<VALUE> or \"null\" (if empty), "
+ "where TYPE is int and VALUE is long), "
+ "includeCategories (string, should be either \"true\" or \"false\"), "
+ "excludeModifications (string, should be either \"true\" or \"false\")\n");
+ dprintf(fd, "--stopProgramListUpdates: stop current pending program list updates\n");
+ dprintf(fd,
+ "Note on <TYPE> for --startProgramList command: it is int for identifier type. "
+ "Please see broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl "
+ "for its definition.\n");
+ dprintf(fd,
+ "Note on <VALUE> for --startProgramList command: it is long type for identifier value. "
+ "Please see broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl "
+ "for its value.\n");
+
+ return STATUS_OK;
+}
+
+binder_status_t BroadcastRadio::cmdTune(int fd, const char** args, uint32_t numArgs) {
+ if (!checkDumpCallerHasWritePermissions(fd)) {
+ return STATUS_PERMISSION_DENIED;
+ }
+ if (numArgs != 3 && numArgs != 4) {
+ dprintf(fd,
+ "Invalid number of arguments: please provide --tune amfm <FREQUENCY> "
+ "or --tune dab <SID> <ENSEMBLE>\n");
+ return STATUS_BAD_VALUE;
+ }
+ bool isDab = false;
+ if (EqualsIgnoreCase(string(args[1]), "dab")) {
+ isDab = true;
+ } else if (!EqualsIgnoreCase(string(args[1]), "amfm")) {
+ dprintf(fd, "Unknown radio type provided with tune: %s\n", args[1]);
+ return STATUS_BAD_VALUE;
+ }
+ ProgramSelector sel = {};
+ if (isDab) {
+ if (numArgs != 4) {
+ dprintf(fd,
+ "Invalid number of arguments: please provide --tune dab <SID> <ENSEMBLE>\n");
+ return STATUS_BAD_VALUE;
+ }
+ int sid;
+ if (!utils::parseArgInt(string(args[2]), &sid)) {
+ dprintf(fd, "Non-integer sid provided with tune: %s\n", string(args[2]).c_str());
+ return STATUS_BAD_VALUE;
+ }
+ int ensemble;
+ if (!utils::parseArgInt(string(args[3]), &ensemble)) {
+ dprintf(fd, "Non-integer ensemble provided with tune: %s\n", string(args[3]).c_str());
+ return STATUS_BAD_VALUE;
+ }
+ sel = utils::makeSelectorDab(sid, ensemble);
+ } else {
+ if (numArgs != 3) {
+ dprintf(fd, "Invalid number of arguments: please provide --tune amfm <FREQUENCY>\n");
+ return STATUS_BAD_VALUE;
+ }
+ int freq;
+ if (!utils::parseArgInt(string(args[2]), &freq)) {
+ dprintf(fd, "Non-integer frequency provided with tune: %s\n", string(args[2]).c_str());
+ return STATUS_BAD_VALUE;
+ }
+ sel = utils::makeSelectorAmfm(freq);
+ }
+
+ auto tuneResult = tune(sel);
+ if (!tuneResult.isOk()) {
+ dprintf(fd, "Unable to tune %s radio to %s\n", args[1], sel.toString().c_str());
+ return STATUS_BAD_VALUE;
+ }
+ dprintf(fd, "Tune %s radio to %s \n", args[1], sel.toString().c_str());
+ return STATUS_OK;
+}
+
+binder_status_t BroadcastRadio::cmdSeek(int fd, const char** args, uint32_t numArgs) {
+ if (!checkDumpCallerHasWritePermissions(fd)) {
+ return STATUS_PERMISSION_DENIED;
+ }
+ if (numArgs != 3) {
+ dprintf(fd,
+ "Invalid number of arguments: please provide --seek <DIRECTION> "
+ "<SKIP_SUB_CHANNEL>\n");
+ return STATUS_BAD_VALUE;
+ }
+ string seekDirectionIn = string(args[1]);
+ bool seekDirectionUp;
+ if (!utils::parseArgDirection(seekDirectionIn, &seekDirectionUp)) {
+ dprintf(fd, "Invalid direction (\"up\" or \"down\") provided with seek: %s\n",
+ seekDirectionIn.c_str());
+ return STATUS_BAD_VALUE;
+ }
+ string skipSubChannelIn = string(args[2]);
+ bool skipSubChannel;
+ if (!utils::parseArgBool(skipSubChannelIn, &skipSubChannel)) {
+ dprintf(fd, "Invalid skipSubChannel (\"true\" or \"false\") provided with seek: %s\n",
+ skipSubChannelIn.c_str());
+ return STATUS_BAD_VALUE;
+ }
+
+ auto seekResult = seek(seekDirectionUp, skipSubChannel);
+ if (!seekResult.isOk()) {
+ dprintf(fd, "Unable to seek in %s direction\n", seekDirectionIn.c_str());
+ return STATUS_BAD_VALUE;
+ }
+ dprintf(fd, "Seek in %s direction\n", seekDirectionIn.c_str());
+ return STATUS_OK;
+}
+
+binder_status_t BroadcastRadio::cmdStep(int fd, const char** args, uint32_t numArgs) {
+ if (!checkDumpCallerHasWritePermissions(fd)) {
+ return STATUS_PERMISSION_DENIED;
+ }
+ if (numArgs != 2) {
+ dprintf(fd, "Invalid number of arguments: please provide --step <DIRECTION>\n");
+ return STATUS_BAD_VALUE;
+ }
+ string stepDirectionIn = string(args[1]);
+ bool stepDirectionUp;
+ if (!utils::parseArgDirection(stepDirectionIn, &stepDirectionUp)) {
+ dprintf(fd, "Invalid direction (\"up\" or \"down\") provided with step: %s\n",
+ stepDirectionIn.c_str());
+ return STATUS_BAD_VALUE;
+ }
+
+ auto stepResult = step(stepDirectionUp);
+ if (!stepResult.isOk()) {
+ dprintf(fd, "Unable to step in %s direction\n", stepDirectionIn.c_str());
+ return STATUS_BAD_VALUE;
+ }
+ dprintf(fd, "Step in %s direction\n", stepDirectionIn.c_str());
+ return STATUS_OK;
+}
+
+binder_status_t BroadcastRadio::cmdCancel(int fd, uint32_t numArgs) {
+ if (!checkDumpCallerHasWritePermissions(fd)) {
+ return STATUS_PERMISSION_DENIED;
+ }
+ if (numArgs != 1) {
+ dprintf(fd,
+ "Invalid number of arguments: please provide --cancel "
+ "only and no more arguments\n");
+ return STATUS_BAD_VALUE;
+ }
+
+ auto cancelResult = cancel();
+ if (!cancelResult.isOk()) {
+ dprintf(fd, "Unable to cancel pending tune, seek, and step\n");
+ return STATUS_BAD_VALUE;
+ }
+ dprintf(fd, "Canceled pending tune, seek, and step\n");
+ return STATUS_OK;
+}
+
+binder_status_t BroadcastRadio::cmdStartProgramListUpdates(int fd, const char** args,
+ uint32_t numArgs) {
+ if (!checkDumpCallerHasWritePermissions(fd)) {
+ return STATUS_PERMISSION_DENIED;
+ }
+ if (numArgs != 5) {
+ dprintf(fd,
+ "Invalid number of arguments: please provide --startProgramListUpdates "
+ "<IDENTIFIER_TYPES> <IDENTIFIERS> <INCLUDE_CATEGORIES> "
+ "<EXCLUDE_MODIFICATIONS>\n");
+ return STATUS_BAD_VALUE;
+ }
+ string filterTypesStr = string(args[1]);
+ std::vector<IdentifierType> filterTypeList;
+ if (!EqualsIgnoreCase(filterTypesStr, "null") &&
+ !utils::parseArgIdentifierTypeArray(filterTypesStr, &filterTypeList)) {
+ dprintf(fd,
+ "Invalid identifier types provided with startProgramListUpdates: %s, "
+ "should be: <TYPE>,<TYPE>,...,<TYPE>\n",
+ filterTypesStr.c_str());
+ return STATUS_BAD_VALUE;
+ }
+ string filtersStr = string(args[2]);
+ std::vector<ProgramIdentifier> filterList;
+ if (!EqualsIgnoreCase(filtersStr, "null") &&
+ !utils::parseProgramIdentifierList(filtersStr, &filterList)) {
+ dprintf(fd,
+ "Invalid program identifiers provided with startProgramListUpdates: %s, "
+ "should be: <TYPE>:<VALUE>,<TYPE>:<VALUE>,...,<TYPE>:<VALUE>\n",
+ filtersStr.c_str());
+ return STATUS_BAD_VALUE;
+ }
+ string includeCategoriesStr = string(args[3]);
+ bool includeCategories;
+ if (!utils::parseArgBool(includeCategoriesStr, &includeCategories)) {
+ dprintf(fd,
+ "Invalid includeCategories (\"true\" or \"false\") "
+ "provided with startProgramListUpdates : %s\n",
+ includeCategoriesStr.c_str());
+ return STATUS_BAD_VALUE;
+ }
+ string excludeModificationsStr = string(args[4]);
+ bool excludeModifications;
+ if (!utils::parseArgBool(excludeModificationsStr, &excludeModifications)) {
+ dprintf(fd,
+ "Invalid excludeModifications(\"true\" or \"false\") "
+ "provided with startProgramListUpdates : %s\n",
+ excludeModificationsStr.c_str());
+ return STATUS_BAD_VALUE;
+ }
+ ProgramFilter filter = {filterTypeList, filterList, includeCategories, excludeModifications};
+
+ auto updateResult = startProgramListUpdates(filter);
+ if (!updateResult.isOk()) {
+ dprintf(fd, "Unable to start program list update for filter %s \n",
+ filter.toString().c_str());
+ return STATUS_BAD_VALUE;
+ }
+ dprintf(fd, "Start program list update for filter %s\n", filter.toString().c_str());
+ return STATUS_OK;
+}
+
+binder_status_t BroadcastRadio::cmdStopProgramListUpdates(int fd, uint32_t numArgs) {
+ if (!checkDumpCallerHasWritePermissions(fd)) {
+ return STATUS_PERMISSION_DENIED;
+ }
+ if (numArgs != 1) {
+ dprintf(fd,
+ "Invalid number of arguments: please provide --stopProgramListUpdates "
+ "only and no more arguments\n");
+ return STATUS_BAD_VALUE;
+ }
+
+ auto stopResult = stopProgramListUpdates();
+ if (!stopResult.isOk()) {
+ dprintf(fd, "Unable to stop pending program list update\n");
+ return STATUS_BAD_VALUE;
+ }
+ dprintf(fd, "Stop pending program list update\n");
+ return STATUS_OK;
+}
+
} // namespace aidl::android::hardware::broadcastradio