Merge "Usb: capture and upload Suez metric VendorUsbDataSessionEvent" into main

This commit is contained in:
Roy Luo 2023-10-05 20:24:46 +00:00 committed by Android (Google) Code Review
commit 2685dda06f
3 changed files with 101 additions and 5 deletions

View file

@ -52,7 +52,7 @@ cc_binary {
"android.frameworks.stats-V2-ndk",
"pixelatoms-cpp",
"libbinder_ndk",
"libprotobuf-cpp-lite",
],
static_libs: [
"libpixelusb-aidl",

View file

@ -42,6 +42,7 @@
#include "Usb.h"
#include <aidl/android/frameworks/stats/IStats.h>
#include <pixelusb/CommonUtils.h>
#include <pixelusb/UsbGadgetAidlCommon.h>
#include <pixelstats/StatsHelper.h>
@ -54,6 +55,9 @@ using android::base::Trim;
using android::hardware::google::pixel::getStatsService;
using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat;
using android::hardware::google::pixel::reportUsbPortOverheat;
using android::hardware::google::pixel::PixelAtoms::VendorUsbDataSessionEvent;
using android::hardware::google::pixel::reportUsbDataSessionEvent;
using android::hardware::google::pixel::usb::BuildVendorUsbDataSessionEvent;
namespace aidl {
namespace android {
@ -98,6 +102,8 @@ void queryVersionHelper(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus);
AltModeData::DisplayPortAltModeData constructAltModeData(string hpd, string pin_assignment,
string link_status, string vdo);
void queryUsbDataSession(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus);
#define USB_STATE_MAX_LEN 20
@ -957,6 +963,7 @@ void queryVersionHelper(android::hardware::usb::Usb *usb,
queryMoistureDetectionStatus(currentPortStatus);
queryPowerTransferStatus(currentPortStatus);
queryNonCompliantChargerStatus(currentPortStatus);
queryUsbDataSession(usb, currentPortStatus);
pthread_mutex_lock(&usb->mDisplayPortLock);
if (!usb->mDisplayPortFirstSetupDone &&
usb->getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::SUCCESS) {
@ -1052,6 +1059,54 @@ void report_overheat_event(android::hardware::usb::Usb *usb) {
}
}
void report_usb_data_session_event(android::hardware::usb::Usb *usb) {
std::vector<VendorUsbDataSessionEvent> events;
if (usb->mDataRole == PortDataRole::DEVICE) {
VendorUsbDataSessionEvent event;
BuildVendorUsbDataSessionEvent(false /* is_host */, std::chrono::steady_clock::now(),
usb->mDataSessionStart, &usb->mDeviceState.states,
&usb->mDeviceState.timestamps, &event);
events.push_back(event);
} else if (usb->mDataRole == PortDataRole::HOST) {
bool empty = true;
for (auto &entry : usb->mHostStateMap) {
// Host port will at least get an not_attached event after enablement,
// skip upload if no additional state is added.
if (entry.second.states.size() > 1) {
VendorUsbDataSessionEvent event;
BuildVendorUsbDataSessionEvent(true /* is_host */, std::chrono::steady_clock::now(),
usb->mDataSessionStart, &entry.second.states,
&entry.second.timestamps, &event);
events.push_back(event);
empty = false;
}
}
// All host ports have no state update, upload an event to reflect it
if (empty && usb->mHostStateMap.size() > 0) {
VendorUsbDataSessionEvent event;
BuildVendorUsbDataSessionEvent(true /* is_host */, std::chrono::steady_clock::now(),
usb->mDataSessionStart,
&usb->mHostStateMap.begin()->second.states,
&usb->mHostStateMap.begin()->second.timestamps,
&event);
events.push_back(event);
}
} else {
return;
}
const shared_ptr<IStats> stats_client = getStatsService();
if (!stats_client) {
ALOGE("Unable to get AIDL Stats service");
return;
}
for (auto &event : events) {
reportUsbDataSessionEvent(stats_client, event);
}
}
struct data {
int uevent_fd;
::aidl::android::hardware::usb::Usb *usb;
@ -1141,14 +1196,16 @@ static int registerEpollEntryByFile(Usb *usb, std::string name, int flags,
}
static void clearUsbDeviceState(struct Usb::usbDeviceState *device) {
device->latestState.clear();
device->states.clear();
device->timestamps.clear();
device->portResetCount = 0;
}
static void updateUsbDeviceState(struct Usb::usbDeviceState *device, char *state) {
ALOGI("Update USB device state: %s", state);
device->latestState = state;
device->states.push_back(state);
device->timestamps.push_back(std::chrono::steady_clock::now());
if (!std::strcmp(state, "configured\n")) {
device->portResetCount = 0;
@ -1168,6 +1225,37 @@ static void host_event(uint32_t /*epevents*/, struct Usb::payload *payload) {
updateUsbDeviceState(&payload->usb->mHostStateMap[payload->name], state);
}
void queryUsbDataSession(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus) {
PortDataRole newDataRole = (*currentPortStatus)[0].currentDataRole;
PowerBrickStatus newPowerBrickStatus = (*currentPortStatus)[0].powerBrickStatus;
if (newDataRole != usb->mDataRole) {
// Upload metrics for the last non-powerbrick data session that has ended
if (usb->mDataRole != PortDataRole::NONE && !usb->mIsPowerBrickConnected) {
report_usb_data_session_event(usb);
}
// Set up for the new data session
usb->mDataRole = newDataRole;
usb->mDataSessionStart = std::chrono::steady_clock::now();
usb->mIsPowerBrickConnected = (newPowerBrickStatus == PowerBrickStatus::CONNECTED);
if (newDataRole == PortDataRole::DEVICE) {
clearUsbDeviceState(&usb->mDeviceState);
} else if (newDataRole == PortDataRole::HOST) {
for (auto &entry : usb->mHostStateMap) {
clearUsbDeviceState(&entry.second);
}
}
}
// PowerBrickStatus could flip from DISCONNECTED to CONNECTED during the same data
// session when BC1.2 SDP times out and falls back to DCP
if (newPowerBrickStatus == PowerBrickStatus::CONNECTED) {
usb->mIsPowerBrickConnected = true;
}
}
static void uevent_event(uint32_t /*epevents*/, struct Usb::payload *payload) {
char msg[UEVENT_MSG_LEN + 2];
char *cp;
@ -1263,7 +1351,6 @@ static void uevent_event(uint32_t /*epevents*/, struct Usb::payload *payload) {
registerEpollEntryByFile(payload->usb, path, EPOLLPRI, host_event);
} else if (action == "unbind") {
unregisterEpollEntry(payload->usb, path);
clearUsbDeviceState(&payload->usb->mHostStateMap[path]);
}
}
}

View file

@ -19,6 +19,7 @@
#include <android-base/file.h>
#include <aidl/android/hardware/usb/BnUsb.h>
#include <aidl/android/hardware/usb/BnUsbCallback.h>
#include <chrono>
#include <pixelusb/UsbOverheatEvent.h>
#include <sys/eventfd.h>
#include <utils/Log.h>
@ -132,12 +133,20 @@ struct Usb : public BnUsb {
// USB device state monitoring
struct usbDeviceState {
std::string latestState;
// Usb device state raw strings read from sysfs
std::vector<std::string> states;
// Timestamps of when the usb device states were captured
std::vector<std::chrono::steady_clock::time_point> timestamps;
int portResetCount;
};
struct usbDeviceState mDeviceState;
// Map host device path name to usbDeviceState
std::map<std::string, struct usbDeviceState> mHostStateMap;
// Cache relevant info for USB data session metrics collection when a session starts, including
// the data role, power brick status and the time when the session starts.
PortDataRole mDataRole;
bool mIsPowerBrickConnected;
std::chrono::steady_clock::time_point mDataSessionStart;
// File monitoring through epoll
int mEpollFd;