Add inject-task-next-reboot debug command.

Support a debug command that will inject a fake remote task for
testing on next reboot with specified latency. This is used to
simulate the situation when a remote task arrives while the device
is not booted up and the task will be delivered once the device
boots up.

Test: Manually test on seahawk.
Bug: 275880463
Change-Id: I6eb064893bea0700da80dfa2dcf3079ddb0b59a1
This commit is contained in:
Yu Shan 2023-04-19 11:44:35 -07:00
parent 30925ee9a4
commit 194757d25f
2 changed files with 86 additions and 3 deletions

View file

@ -105,6 +105,8 @@ class RemoteAccessService
size_t mRetryWaitInMs = 10'000;
std::shared_ptr<DebugRemoteTaskCallback> mDebugCallback;
std::thread mInjectDebugTaskThread;
void runTaskLoop();
void maybeStartTaskLoop();
void maybeStopTaskLoop();
@ -116,6 +118,8 @@ class RemoteAccessService
void printCurrentStatus(int fd);
std::string clientIdToTaskCountToStringLocked() REQUIRES(mLock);
void debugInjectTask(int fd, std::string_view clientId, std::string_view taskData);
void debugInjectTaskNextReboot(int fd, std::string_view clientId, std::string_view taskData,
const char* latencyInSecStr);
void updateGrpcConnected(bool connected);
android::base::Result<void> deliverRemoteTaskThroughCallback(const std::string& clientId,
std::string_view taskData);

View file

@ -18,12 +18,16 @@
#include <VehicleUtils.h>
#include <aidl/android/hardware/automotive/vehicle/VehicleProperty.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android/binder_status.h>
#include <grpc++/grpc++.h>
#include <private/android_filesystem_config.h>
#include <sys/stat.h>
#include <utils/Log.h>
#include <chrono>
#include <fstream>
#include <iostream>
#include <thread>
namespace android {
@ -37,6 +41,7 @@ using ::aidl::android::hardware::automotive::remoteaccess::ApState;
using ::aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback;
using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
using ::android::base::Error;
using ::android::base::ParseInt;
using ::android::base::Result;
using ::android::base::ScopedLockAssertion;
using ::android::base::StringAppendF;
@ -57,8 +62,12 @@ constexpr char COMMAND_STOP_DEBUG_CALLBACK[] = "--stop-debug-callback";
constexpr char COMMAND_SHOW_TASK[] = "--show-task";
constexpr char COMMAND_GET_VEHICLE_ID[] = "--get-vehicle-id";
constexpr char COMMAND_INJECT_TASK[] = "--inject-task";
constexpr char COMMAND_INJECT_TASK_NEXT_REBOOT[] = "--inject-task-next-reboot";
constexpr char COMMAND_STATUS[] = "--status";
constexpr char DEBUG_TASK_FOLDER[] = "/data/local/tests";
constexpr char DEBUG_TASK_FILE[] = "/data/local/tests/debugTask";
std::vector<uint8_t> stringToBytes(std::string_view s) {
const char* data = s.data();
return std::vector<uint8_t>(data, data + s.size());
@ -92,10 +101,43 @@ std::string boolToString(bool x) {
} // namespace
RemoteAccessService::RemoteAccessService(WakeupClient::StubInterface* grpcStub)
: mGrpcStub(grpcStub){};
: mGrpcStub(grpcStub) {
std::ifstream debugTaskFile;
debugTaskFile.open(DEBUG_TASK_FILE, std::ios::in);
if (!debugTaskFile.is_open()) {
ALOGD("No debug task available");
return;
}
char buffer[1024] = {};
debugTaskFile.getline(buffer, sizeof(buffer));
std::string clientId = std::string(buffer);
debugTaskFile.getline(buffer, sizeof(buffer));
std::string taskData = std::string(buffer);
int latencyInSec;
debugTaskFile >> latencyInSec;
debugTaskFile.close();
ALOGD("Task for client: %s, data: [%s], latency: %d\n", clientId.c_str(), taskData.c_str(),
latencyInSec);
mInjectDebugTaskThread = std::thread([this, clientId, taskData, latencyInSec] {
std::this_thread::sleep_for(std::chrono::seconds(latencyInSec));
if (auto result = deliverRemoteTaskThroughCallback(clientId, taskData); !result.ok()) {
ALOGE("Failed to inject debug task, clientID: %s, taskData: %s, error: %s",
clientId.c_str(), taskData.c_str(), result.error().message().c_str());
return;
}
ALOGD("Task for client: %s, data: [%s] successfully injected\n", clientId.c_str(),
taskData.c_str());
});
}
RemoteAccessService::~RemoteAccessService() {
maybeStopTaskLoop();
if (mInjectDebugTaskThread.joinable()) {
mInjectDebugTaskThread.join();
}
}
void RemoteAccessService::maybeStartTaskLoop() {
@ -286,9 +328,12 @@ void RemoteAccessService::dumpHelp(int fd) {
"%s: Show tasks received by debug callback\n"
"%s: Get vehicle id\n"
"%s [client_id] [task_data]: Inject a task\n"
"%s [client_id] [task_data] [latencyInSec]: "
"Inject a task on next reboot after latencyInSec seconds\n"
"%s: Show status\n",
COMMAND_SET_AP_STATE, COMMAND_START_DEBUG_CALLBACK, COMMAND_STOP_DEBUG_CALLBACK,
COMMAND_SHOW_TASK, COMMAND_GET_VEHICLE_ID, COMMAND_INJECT_TASK, COMMAND_STATUS);
COMMAND_SHOW_TASK, COMMAND_GET_VEHICLE_ID, COMMAND_INJECT_TASK,
COMMAND_INJECT_TASK_NEXT_REBOOT, COMMAND_STATUS);
}
binder_status_t RemoteAccessService::dump(int fd, const char** args, uint32_t numArgs) {
@ -365,6 +410,12 @@ binder_status_t RemoteAccessService::dump(int fd, const char** args, uint32_t nu
return STATUS_OK;
}
debugInjectTask(fd, args[1], args[2]);
} else if (!strcmp(args[0], COMMAND_INJECT_TASK_NEXT_REBOOT)) {
if (numArgs < 4) {
dumpHelp(fd);
return STATUS_OK;
}
debugInjectTaskNextReboot(fd, args[1], args[2], args[3]);
} else if (!strcmp(args[0], COMMAND_STATUS)) {
printCurrentStatus(fd);
} else {
@ -389,13 +440,41 @@ void RemoteAccessService::debugInjectTask(int fd, std::string_view clientId,
std::string_view taskData) {
std::string clientIdCopy = std::string(clientId);
if (auto result = deliverRemoteTaskThroughCallback(clientIdCopy, taskData); !result.ok()) {
dprintf(fd, "Failed to inject task: %s", result.error().message().c_str());
dprintf(fd, "Failed to inject task: %s\n", result.error().message().c_str());
return;
}
dprintf(fd, "Task for client: %s, data: [%s] successfully injected\n", clientId.data(),
taskData.data());
}
void RemoteAccessService::debugInjectTaskNextReboot(int fd, std::string_view clientId,
std::string_view taskData,
const char* latencyInSecStr) {
int latencyInSec;
if (!ParseInt(latencyInSecStr, &latencyInSec)) {
dprintf(fd, "The input latency in second is not a valid integer");
return;
}
std::ofstream debugTaskFile;
debugTaskFile.open(DEBUG_TASK_FILE, std::ios::out);
if (!debugTaskFile.is_open()) {
dprintf(fd,
"Failed to open debug task file, please run the command: "
"'adb shell touch %s' first\n",
DEBUG_TASK_FILE);
return;
}
if (taskData.find("\n") != std::string::npos) {
dprintf(fd, "Task data must not contain newline\n");
return;
}
debugTaskFile << clientId << "\n" << taskData << "\n" << latencyInSec;
debugTaskFile.close();
dprintf(fd,
"Task with clientId: %s, task data: %s, latency: %d sec scheduled for next reboot\n",
clientId.data(), taskData.data(), latencyInSec);
}
std::string RemoteAccessService::clientIdToTaskCountToStringLocked() {
// Print the table header
std::string output = "| ClientId | Count |\n";