blob: 65a5aa5a9a9b0d8f5607bb76190f116e1d3d8f6e [file] [log] [blame]
/*
* Copyright (C) 2019 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 <cutils/sockets.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <utils/StrongPointer.h>
#include <chrono>
#include <cinttypes>
#include <condition_variable>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>
#include "chre/util/nanoapp/app_id.h"
#include "chre/version.h"
#include "chre_host/host_protocol_host.h"
#include "chre_host/log.h"
#include "chre_host/socket_client.h"
#include "generated/chre_power_test_generated.h"
/**
* @file
* A test utility that connects to the CHRE daemon and provides commands to take
* control the power test nanoapp located at system/chre/apps/power_test
*
* Usage:
* chre_power_test_client load <optional: tcm> <optional: path>
* chre_power_test_client unload <optional: tcm>
* chre_power_test_client unloadall
* chre_power_test_client timer <optional: tcm> <enable> <interval_ns>
* chre_power_test_client wifi <optional: tcm> <enable> <interval_ns>
* chre_power_test_client gnss <optional: tcm> <enable> <interval_ms>
* <optional: next_fix_ms>
* chre_power_test_client cell <optional: tcm> <enable> <interval_ns>
* chre_power_test_client audio <optional: tcm> <enable> <duration_ns>
* chre_power_test_client sensor <optional: tcm> <enable> <sensor_type>
* <interval_ns> <optional: latency_ns>
* chre_power_test_client breakit <optional: tcm> <enable>
* chre_power_test_client gnss_meas <optional: tcm> <enable> <interval_ms>
*
* Command:
* load: load power test nanoapp to CHRE
* unload: unload power test nanoapp from CHRE
* unloadall: unload all nanoapps in CHRE
* timer: start/stop timer wake up
* wifi: start/stop periodic wifi scan
* gnss: start/stop periodic GPS scan
* cell: start/stop periodic cellular scan
* audio: start/stop periodic audio capture
* sensor: start/stop periodic sensor sampling
* breakit: start/stop all action for stress tests
* gnss_meas: start/stop periodic GNSS measurement
*
* <optional: tcm>: tcm for micro image, default for big image
* <enable>: enable/disable
*
* <sensor_type>:
* accelerometer
* instant_motion
* stationary
* gyroscope
* uncalibrated_gyroscope
* geomagnetic
* uncalibrated_geomagnetic
* pressure
* light
* proximity
* step
* uncalibrated_accelerometer
* accelerometer_temperature
* gyroscope_temperature
* geomagnetic_temperature
*
* For instant_motion and stationary sensor, it is not necessary to provide the
* interval and latency
*/
using android::sp;
using android::chre::FragmentedLoadTransaction;
using android::chre::getStringFromByteVector;
using android::chre::HostProtocolHost;
using android::chre::IChreMessageHandlers;
using android::chre::SocketClient;
using chre::power_test::MessageType;
using chre::power_test::SensorType;
using flatbuffers::FlatBufferBuilder;
using std::string;
// Aliased for consistency with the way these symbols are referenced in
// CHRE-side code
namespace fbs = ::chre::fbs;
namespace ptest = ::chre::power_test;
namespace {
constexpr uint16_t kHostEndpoint = 0xfffd;
constexpr uint32_t kAppVersion = 1;
constexpr uint32_t kApiVersion = CHRE_API_VERSION;
constexpr uint64_t kPowerTestAppId = 0x012345678900000f;
constexpr uint64_t kPowerTestTcmAppId = 0x0123456789000010;
constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
constexpr auto kTimeout = std::chrono::seconds(10);
const char *kPowerTestPath = "/vendor/dsp/sdsp/power_test.so";
const char *kPowerTestTcmPath = "/vendor/dsp/sdsp/power_test_tcm.so";
std::condition_variable kReadyCond;
std::mutex kReadyMutex;
std::unique_lock<std::mutex> kReadyCondLock(kReadyMutex);
enum class Command : uint32_t {
kUnloadAll = 0,
kLoad,
kUnload,
kTimer,
kWifi,
kGnss,
kCell,
kAudio,
kSensor,
kBreakIt,
kGnssMeas
};
std::unordered_map<string, Command> commandMap{
{"unloadall", Command::kUnloadAll}, {"load", Command::kLoad},
{"unload", Command::kUnload}, {"timer", Command::kTimer},
{"wifi", Command::kWifi}, {"gnss", Command::kGnss},
{"cell", Command::kCell}, {"audio", Command::kAudio},
{"sensor", Command::kSensor}, {"breakit", Command::kBreakIt},
{"gnss_meas", Command::kGnssMeas}};
std::unordered_map<string, MessageType> messageTypeMap{
{"timer", MessageType::TIMER_TEST},
{"wifi", MessageType::WIFI_SCAN_TEST},
{"gnss", MessageType::GNSS_LOCATION_TEST},
{"cell", MessageType::CELL_QUERY_TEST},
{"audio", MessageType::AUDIO_REQUEST_TEST},
{"sensor", MessageType::SENSOR_REQUEST_TEST},
{"breakit", MessageType::BREAK_IT_TEST},
{"gnss_meas", MessageType::GNSS_MEASUREMENT_TEST}};
std::unordered_map<string, SensorType> sensorTypeMap{
{"accelerometer", SensorType::ACCELEROMETER},
{"instant_motion", SensorType::INSTANT_MOTION_DETECT},
{"stationary", SensorType::STATIONARY_DETECT},
{"gyroscope", SensorType::GYROSCOPE},
{"uncalibrated_gyroscope", SensorType::UNCALIBRATED_GYROSCOPE},
{"geomagnetic", SensorType::GEOMAGNETIC_FIELD},
{"uncalibrated_geomagnetic", SensorType::UNCALIBRATED_GEOMAGNETIC_FIELD},
{"pressure", SensorType::PRESSURE},
{"light", SensorType::LIGHT},
{"proximity", SensorType::PROXIMITY},
{"step", SensorType::STEP_DETECT},
{"uncalibrated_accelerometer", SensorType::UNCALIBRATED_ACCELEROMETER},
{"accelerometer_temperature", SensorType::ACCELEROMETER_TEMPERATURE},
{"gyroscope_temperature", SensorType::GYROSCOPE_TEMPERATURE},
{"geomagnetic_temperature", SensorType::GEOMAGNETIC_FIELD_TEMPERATURE}};
class SocketCallbacks : public SocketClient::ICallbacks,
public IChreMessageHandlers {
public:
SocketCallbacks(std::condition_variable &readyCond)
: mConditionVariable(readyCond) {}
void onMessageReceived(const void *data, size_t length) override {
if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
LOGE("Failed to decode message");
}
}
void onConnected() override {
LOGI("Socket (re)connected");
}
void onConnectionAborted() override {
LOGI("Socket (re)connection aborted");
}
void onDisconnected() override {
LOGI("Socket disconnected");
}
void handleNanoappMessage(const fbs::NanoappMessageT &message) override {
LOGI("Got message from nanoapp 0x%" PRIx64 " to endpoint 0x%" PRIx16
" with type 0x%" PRIx32 " and length %zu",
message.app_id, message.host_endpoint, message.message_type,
message.message.size());
if (message.message_type ==
static_cast<uint32_t>(MessageType::NANOAPP_RESPONSE)) {
handlePowerTestNanoappResponse(message.message);
}
}
void handlePowerTestNanoappResponse(const std::vector<uint8_t> &message) {
auto response =
flatbuffers::GetRoot<ptest::NanoappResponseMessage>(message.data());
flatbuffers::Verifier verifier(message.data(), message.size());
bool success = response->Verify(verifier);
mSuccess = success ? response->success() : false;
mConditionVariable.notify_all();
}
void handleNanoappListResponse(
const fbs::NanoappListResponseT &response) override {
LOGI("Got nanoapp list response with %zu apps:", response.nanoapps.size());
mAppIdVector.clear();
for (const auto &nanoapp : response.nanoapps) {
LOGI("App ID 0x%016" PRIx64 " version 0x%" PRIx32 " enabled %d system %d",
nanoapp->app_id, nanoapp->version, nanoapp->enabled,
nanoapp->is_system);
mAppIdVector.push_back(nanoapp->app_id);
}
mConditionVariable.notify_all();
}
void handleLoadNanoappResponse(
const fbs::LoadNanoappResponseT &response) override {
LOGI("Got load nanoapp response, transaction ID 0x%" PRIx32 " result %d",
response.transaction_id, response.success);
mSuccess = response.success;
mConditionVariable.notify_all();
}
void handleUnloadNanoappResponse(
const fbs::UnloadNanoappResponseT &response) override {
LOGI("Got unload nanoapp response, transaction ID 0x%" PRIx32 " result %d",
response.transaction_id, response.success);
mSuccess = response.success;
mConditionVariable.notify_all();
}
bool actionSucceeded() {
return mSuccess;
}
std::vector<uint64_t> &getAppIdVector() {
return mAppIdVector;
}
private:
bool mSuccess = false;
std::condition_variable &mConditionVariable;
std::vector<uint64_t> mAppIdVector;
};
bool requestNanoappList(SocketClient &client) {
FlatBufferBuilder builder(64);
HostProtocolHost::encodeNanoappListRequest(builder);
LOGI("Sending app list request (%" PRIu32 " bytes)", builder.GetSize());
if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
LOGE("Failed to send message");
return false;
}
return true;
}
bool sendLoadNanoappRequest(SocketClient &client, const char *filename,
uint64_t appId, uint32_t appVersion,
uint32_t apiVersion) {
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if (!file) {
LOGE("Couldn't open file '%s': %s", filename, strerror(errno));
return false;
}
ssize_t size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<uint8_t> buffer(size);
if (!file.read(reinterpret_cast<char *>(buffer.data()), size)) {
LOGE("Couldn't read from file: %s", strerror(errno));
file.close();
return false;
}
// Perform loading with 1 fragment for simplicity
FlatBufferBuilder builder(size + 128);
FragmentedLoadTransaction transaction = FragmentedLoadTransaction(
1 /* transactionId */, appId, appVersion, apiVersion, buffer,
buffer.size() /* fragmentSize */);
HostProtocolHost::encodeFragmentedLoadNanoappRequest(
builder, transaction.getNextRequest());
LOGI("Sending load nanoapp request (%" PRIu32
" bytes total w/ %zu bytes of payload)",
builder.GetSize(), buffer.size());
bool success =
client.sendMessage(builder.GetBufferPointer(), builder.GetSize());
if (!success) {
LOGE("Failed to send message");
}
file.close();
return success;
}
bool loadNanoapp(SocketClient &client, sp<SocketCallbacks> callbacks,
const char *filename, uint64_t appId, uint32_t appVersion,
uint32_t apiVersion) {
if (!sendLoadNanoappRequest(client, filename, appId, appVersion,
apiVersion)) {
return false;
}
auto status = kReadyCond.wait_for(kReadyCondLock, kTimeout);
bool success =
(status == std::cv_status::no_timeout && callbacks->actionSucceeded());
LOGI("Loaded the nanoapp with appId: %" PRIx64 " success: %d", appId,
success);
return success;
}
bool sendUnloadNanoappRequest(SocketClient &client, uint64_t appId) {
FlatBufferBuilder builder(64);
constexpr uint32_t kTransactionId = 4321;
HostProtocolHost::encodeUnloadNanoappRequest(
builder, kTransactionId, appId, true /* allowSystemNanoappUnload */);
LOGI("Sending unload request for nanoapp 0x%016" PRIx64 " (size %" PRIu32 ")",
appId, builder.GetSize());
if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
LOGE("Failed to send message");
return false;
}
return true;
}
bool unloadNanoapp(SocketClient &client, sp<SocketCallbacks> callbacks,
uint64_t appId) {
if (!sendUnloadNanoappRequest(client, appId)) {
return false;
}
auto status = kReadyCond.wait_for(kReadyCondLock, kTimeout);
bool success =
(status == std::cv_status::no_timeout && callbacks->actionSucceeded());
LOGI("Unloaded the nanoapp with appId: %" PRIx64 " success: %d", appId,
success);
return success;
}
bool listNanoapps(SocketClient &client) {
if (!requestNanoappList(client)) {
LOGE("Failed in listing nanoapps");
return false;
}
auto status = kReadyCond.wait_for(kReadyCondLock, kTimeout);
bool success = (status == std::cv_status::no_timeout);
LOGI("Listed nanoapps success: %d", success);
return success;
}
bool unloadAllNanoapps(SocketClient &client, sp<SocketCallbacks> callbacks) {
if (!listNanoapps(client)) {
return false;
}
for (auto appId : callbacks->getAppIdVector()) {
if (!unloadNanoapp(client, callbacks, appId)) {
LOGE("Failed in unloading nanoapps, unloading aborted");
return false;
}
}
LOGI("Unloaded all nanoapps succeeded");
return true;
}
inline uint64_t getId(std::vector<string> &args) {
if (!args.empty() && args[0] == "tcm") {
return kPowerTestTcmAppId;
}
return kPowerTestAppId;
}
/**
* When user provides the customized path in tcm mode, the args[1] is the path.
* In this case, the args[0] has to be "tcm". When user provide customized path
* for non-tcm mode, the args[0] is the path.
*/
inline const char *getPath(std::vector<string> &args) {
if (args.empty()) {
return kPowerTestPath;
}
if (args[0] == "tcm") {
if (args.size() > 1) {
return args[1].c_str();
}
return kPowerTestTcmPath;
}
return args[0].c_str();
}
inline uint64_t getNanoseconds(std::vector<string> &args, size_t index) {
return args.size() > index ? strtoull(args[index].c_str(), NULL, 0) : 0;
}
inline uint32_t getMilliseconds(std::vector<string> &args, size_t index) {
return args.size() > index ? strtoul(args[index].c_str(), NULL, 0) : 0;
}
bool isLoaded(SocketClient &client, sp<SocketCallbacks> callbacks,
std::vector<string> &args) {
uint64_t id = getId(args);
if (!listNanoapps(client)) {
return false;
}
for (auto appId : callbacks->getAppIdVector()) {
if (appId == id) {
LOGI("The required nanoapp was loaded");
return true;
}
}
LOGE("The required nanoapp was not loaded");
return false;
}
bool validateArguments(Command commandEnum, std::vector<string> &args) {
if (static_cast<uint32_t>(commandEnum) < 3) return true;
if (args.empty()) {
LOGE("Not enough parameters");
return false;
}
// For non tcm option, add one item to the head of args to align argument
// position with that with tcm option.
if (args[0] != "tcm") args.insert(args.begin(), "");
if (args.size() < 2) {
LOGE("Not enough parameters");
return false;
}
if (args[1] != "enable" && args[1] != "disable") {
LOGE("<enable> was neither enable nor disable");
return false;
}
if (commandEnum == Command::kBreakIt) return true;
if (args[1] == "disable") {
if (commandEnum != Command::kSensor) return true;
if (args.size() > 2 && sensorTypeMap.find(args[2]) != sensorTypeMap.end())
return true;
LOGE("No sensor type or invalid sensor type");
return false;
}
// Case of "enable":
if (commandEnum != Command::kSensor) {
if (args.size() < 3) {
LOGE("The interval or duration was not provided");
return false;
}
// For checking if the interval is 0. The getNanoseconds and
// and the getMilliseconds are exchangable in this case.
if (getNanoseconds(args, 2) == 0) {
LOGE("Non zero interval or duration is required when enable");
return false;
}
return true;
}
// Case of enable sensor request
if (args.size() < 3) {
LOGE("Sensor type is required");
return false;
}
if (sensorTypeMap.find(args[2]) == sensorTypeMap.end()) {
LOGE("Invalid sensor type");
return false;
}
SensorType sensorType = sensorTypeMap[args[2]];
if (sensorType == SensorType::STATIONARY_DETECT ||
sensorType == SensorType::INSTANT_MOTION_DETECT)
return true;
uint64_t intervalNanoseconds = getNanoseconds(args, 3);
uint64_t latencyNanoseconds = getNanoseconds(args, 4);
if (intervalNanoseconds == 0) {
LOGE("Non zero sensor sampling interval is required when enable");
return false;
}
if (latencyNanoseconds != 0 && latencyNanoseconds < intervalNanoseconds) {
LOGE("The latency is not zero and smaller than the interval");
return false;
}
return true;
}
void createTimerMessage(FlatBufferBuilder &fbb, std::vector<string> &args) {
bool enable = (args[1] == "enable");
uint64_t intervalNanoseconds = getNanoseconds(args, 2);
fbb.Finish(ptest::CreateTimerMessage(fbb, enable, intervalNanoseconds));
LOGI("Created TimerMessage, enable %d, wakeup interval ns %" PRIu64, enable,
intervalNanoseconds);
}
void createWifiMessage(FlatBufferBuilder &fbb, std::vector<string> &args) {
bool enable = (args[1] == "enable");
uint64_t intervalNanoseconds = getNanoseconds(args, 2);
fbb.Finish(ptest::CreateWifiScanMessage(fbb, enable, intervalNanoseconds));
LOGI("Created WifiScanMessage, enable %d, scan interval ns %" PRIu64, enable,
intervalNanoseconds);
}
void createGnssMessage(FlatBufferBuilder &fbb, std::vector<string> &args) {
bool enable = (args[1] == "enable");
uint32_t intervalMilliseconds = getMilliseconds(args, 2);
uint32_t toNextFixMilliseconds = getMilliseconds(args, 3);
fbb.Finish(ptest::CreateGnssLocationMessage(fbb, enable, intervalMilliseconds,
toNextFixMilliseconds));
LOGI("Created GnssLocationMessage, enable %d, scan interval ms %" PRIu32
" min time to next fix ms %" PRIu32,
enable, intervalMilliseconds, toNextFixMilliseconds);
}
void createCellMessage(FlatBufferBuilder &fbb, std::vector<string> &args) {
bool enable = (args[1] == "enable");
uint64_t intervalNanoseconds = getNanoseconds(args, 2);
fbb.Finish(ptest::CreateCellQueryMessage(fbb, enable, intervalNanoseconds));
LOGI("Created CellQueryMessage, enable %d, query interval ns %" PRIu64,
enable, intervalNanoseconds);
}
void createAudioMessage(FlatBufferBuilder &fbb, std::vector<string> &args) {
bool enable = (args[1] == "enable");
uint64_t durationNanoseconds = getNanoseconds(args, 2);
fbb.Finish(
ptest::CreateAudioRequestMessage(fbb, enable, durationNanoseconds));
LOGI("Created AudioRequestMessage, enable %d, buffer duration ns %" PRIu64,
enable, durationNanoseconds);
}
void createSensorMessage(FlatBufferBuilder &fbb, std::vector<string> &args) {
bool enable = (args[1] == "enable");
SensorType sensorType = sensorTypeMap[args[2]];
uint64_t intervalNanoseconds = getNanoseconds(args, 3);
uint64_t latencyNanoseconds = getNanoseconds(args, 4);
if (sensorType == SensorType::STATIONARY_DETECT ||
sensorType == SensorType::INSTANT_MOTION_DETECT) {
intervalNanoseconds = kUint64Max;
latencyNanoseconds = 0;
}
fbb.Finish(ptest::CreateSensorRequestMessage(
fbb, enable, sensorType, intervalNanoseconds, latencyNanoseconds));
LOGI(
"Created SensorRequestMessage, enable %d, %s sensor, sampling "
"interval ns %" PRIu64 ", latency ns %" PRIu64,
enable, ptest::EnumNameSensorType(sensorType), intervalNanoseconds,
latencyNanoseconds);
}
void createBreakItMessage(FlatBufferBuilder &fbb, std::vector<string> &args) {
bool enable = (args[1] == "enable");
fbb.Finish(ptest::CreateBreakItMessage(fbb, enable));
LOGI("Created BreakItMessage, enable %d", enable);
}
void createGnssMeasMessage(FlatBufferBuilder &fbb, std::vector<string> &args) {
bool enable = (args[1] == "enable");
uint32_t intervalMilliseconds = getMilliseconds(args, 2);
fbb.Finish(
ptest::CreateGnssMeasurementMessage(fbb, enable, intervalMilliseconds));
LOGI("Created GnssMeasurementMessage, enable %d, interval ms %" PRIu32,
enable, intervalMilliseconds);
}
bool sendMessageToNanoapp(SocketClient &client, sp<SocketCallbacks> callbacks,
FlatBufferBuilder &fbb, uint64_t appId,
MessageType messageType) {
FlatBufferBuilder builder(128);
HostProtocolHost::encodeNanoappMessage(
builder, appId, static_cast<uint32_t>(messageType), kHostEndpoint,
fbb.GetBufferPointer(), fbb.GetSize());
LOGI("sending %s message to nanoapp (%" PRIu32 " bytes w/%" PRIu32
" bytes of payload)",
ptest::EnumNameMessageType(messageType), builder.GetSize(),
fbb.GetSize());
if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
LOGE("Failed to send %s message", ptest::EnumNameMessageType(messageType));
return false;
}
auto status = kReadyCond.wait_for(kReadyCondLock, kTimeout);
bool success =
(status == std::cv_status::no_timeout && callbacks->actionSucceeded());
LOGI("Sent %s message to nanoapp success: %d",
ptest::EnumNameMessageType(messageType), success);
if (status == std::cv_status::timeout) {
LOGE("Sent %s message to nanoapp timeout",
ptest::EnumNameMessageType(messageType));
}
return success;
}
static void usage() {
LOGI(
"\n"
"Usage:\n"
" chre_power_test_client load <optional: tcm> <optional: path>\n"
" chre_power_test_client unload <optional: tcm>\n"
" chre_power_test_client unloadall\n"
" chre_power_test_client timer <optional: tcm> <enable> <interval_ns>\n"
" chre_power_test_client wifi <optional: tcm> <enable> <interval_ns>\n"
" chre_power_test_client gnss <optional: tcm> <enable> <interval_ms>"
" <next_fix_ms>\n"
" chre_power_test_client cell <optional: tcm> <enable> <interval_ns>\n"
" chre_power_test_client audio <optional: tcm> <enable> <duration_ns>\n"
" chre_power_test_client sensor <optional: tcm> <enable> <sensor_type>"
" <interval_ns> <optional: latency_ns>\n"
" chre_power_test_client breakit <optional: tcm> <enable>\n"
" chre_power_test_client gnss_meas <optional: tcm> <enable> <interval_ms>"
"\n"
"Command:\n"
"load: load power test nanoapp to CHRE\n"
"unload: unload power test nanoapp from CHRE\n"
"unloadall: unload all nanoapps in CHRE\n"
"timer: start/stop timer wake up\n"
"wifi: start/stop periodic wifi scan\n"
"gnss: start/stop periodic GPS scan\n"
"cell: start/stop periodic cellular scan\n"
"audio: start/stop periodic audio capture\n"
"sensor: start/stop periodic sensor sampling\n"
"breakit: start/stop all action for stress tests\n"
"gnss_meas: start/stop periodic GNSS measurement\n"
"\n"
"<optional: tcm>: tcm for micro image, default for big image\n"
"<enable>: enable/disable\n"
"\n"
"<sensor_type>:\n"
" accelerometer\n"
" instant_motion\n"
" stationary\n"
" gyroscope\n"
" uncalibrated_gyroscope\n"
" geomagnetic\n"
" uncalibrated_geomagnetic\n"
" pressure\n"
" light\n"
" proximity\n"
" step\n"
" uncalibrated_accelerometer\n"
" accelerometer_temperature\n"
" gyroscope_temperature\n"
" geomanetic_temperature\n"
"\n"
" For instant_montion and stationary sersor, it is not necessary to"
" provide the interval and latency");
}
void createRequestMessage(Command commandEnum, FlatBufferBuilder &fbb,
std::vector<string> &args) {
switch (commandEnum) {
case Command::kTimer: {
createTimerMessage(fbb, args);
break;
}
case Command::kWifi: {
createWifiMessage(fbb, args);
break;
}
case Command::kGnss: {
createGnssMessage(fbb, args);
break;
}
case Command::kCell: {
createCellMessage(fbb, args);
break;
}
case Command::kAudio: {
createAudioMessage(fbb, args);
break;
}
case Command::kSensor: {
createSensorMessage(fbb, args);
break;
}
case Command::kBreakIt: {
createBreakItMessage(fbb, args);
break;
}
case Command::kGnssMeas: {
createGnssMeasMessage(fbb, args);
break;
}
default: {
usage();
}
}
}
} // anonymous namespace
int main(int argc, char *argv[]) {
int argi = 0;
const std::string name{argv[argi++]};
const std::string cmd{argi < argc ? argv[argi++] : ""};
string commandLine(name);
if (commandMap.find(cmd) == commandMap.end()) {
usage();
return -1;
}
commandLine.append(" " + cmd);
Command commandEnum = commandMap[cmd];
std::vector<std::string> args;
while (argi < argc) {
args.push_back(std::string(argv[argi++]));
commandLine.append(" " + args.back());
}
LOGI("Command line: %s", commandLine.c_str());
if (!validateArguments(commandEnum, args)) {
LOGE("Invalid arguments");
usage();
return -1;
}
SocketClient client;
sp<SocketCallbacks> callbacks = new SocketCallbacks(kReadyCond);
if (!client.connect("chre", callbacks)) {
LOGE("Couldn't connect to socket");
return -1;
}
bool success = false;
switch (commandEnum) {
case Command::kUnloadAll: {
success = unloadAllNanoapps(client, callbacks);
break;
}
case Command::kUnload: {
success = unloadNanoapp(client, callbacks, getId(args));
break;
}
case Command::kLoad: {
success = loadNanoapp(client, callbacks, getPath(args), getId(args),
kAppVersion, kApiVersion);
break;
}
default: {
if (!isLoaded(client, callbacks, args)) {
LOGE("The power test nanoapp has to be loaded before sending request");
return -1;
}
FlatBufferBuilder fbb(64);
createRequestMessage(commandEnum, fbb, args);
success = sendMessageToNanoapp(client, callbacks, fbb, getId(args),
messageTypeMap[cmd]);
}
}
client.disconnect();
return success ? 0 : -1;
}