Usb: capture and upload Suez metric VendorUsbDataSessionEvent

Upload metrics for the last data session that just ends upon
data role changes. The change is purely metric collection and
does not change any business logic.

Bug: 297224564
Test: Trigger metric upload for both host and device mode and
      verify it by statsd_testdrive
Change-Id: I823ae8712b7914cfc7f6c6379acb3749d13c0974
This commit is contained in:
Roy Luo 2023-09-20 21:52:08 +00:00
parent 03fd3d9a37
commit ccb35c81ff
3 changed files with 101 additions and 5 deletions

View file

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

View file

@ -42,6 +42,7 @@
#include "Usb.h" #include "Usb.h"
#include <aidl/android/frameworks/stats/IStats.h> #include <aidl/android/frameworks/stats/IStats.h>
#include <pixelusb/CommonUtils.h>
#include <pixelusb/UsbGadgetAidlCommon.h> #include <pixelusb/UsbGadgetAidlCommon.h>
#include <pixelstats/StatsHelper.h> #include <pixelstats/StatsHelper.h>
@ -54,6 +55,9 @@ using android::base::Trim;
using android::hardware::google::pixel::getStatsService; using android::hardware::google::pixel::getStatsService;
using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat; using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat;
using android::hardware::google::pixel::reportUsbPortOverheat; 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 aidl {
namespace android { namespace android {
@ -98,6 +102,8 @@ void queryVersionHelper(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus); std::vector<PortStatus> *currentPortStatus);
AltModeData::DisplayPortAltModeData constructAltModeData(string hpd, string pin_assignment, AltModeData::DisplayPortAltModeData constructAltModeData(string hpd, string pin_assignment,
string link_status, string vdo); string link_status, string vdo);
void queryUsbDataSession(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus);
#define USB_STATE_MAX_LEN 20 #define USB_STATE_MAX_LEN 20
@ -957,6 +963,7 @@ void queryVersionHelper(android::hardware::usb::Usb *usb,
queryMoistureDetectionStatus(currentPortStatus); queryMoistureDetectionStatus(currentPortStatus);
queryPowerTransferStatus(currentPortStatus); queryPowerTransferStatus(currentPortStatus);
queryNonCompliantChargerStatus(currentPortStatus); queryNonCompliantChargerStatus(currentPortStatus);
queryUsbDataSession(usb, currentPortStatus);
pthread_mutex_lock(&usb->mDisplayPortLock); pthread_mutex_lock(&usb->mDisplayPortLock);
if (!usb->mDisplayPortFirstSetupDone && if (!usb->mDisplayPortFirstSetupDone &&
usb->getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::SUCCESS) { 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 { struct data {
int uevent_fd; int uevent_fd;
::aidl::android::hardware::usb::Usb *usb; ::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) { static void clearUsbDeviceState(struct Usb::usbDeviceState *device) {
device->latestState.clear(); device->states.clear();
device->timestamps.clear();
device->portResetCount = 0; device->portResetCount = 0;
} }
static void updateUsbDeviceState(struct Usb::usbDeviceState *device, char *state) { static void updateUsbDeviceState(struct Usb::usbDeviceState *device, char *state) {
ALOGI("Update USB device state: %s", 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")) { if (!std::strcmp(state, "configured\n")) {
device->portResetCount = 0; 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); 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) { static void uevent_event(uint32_t /*epevents*/, struct Usb::payload *payload) {
char msg[UEVENT_MSG_LEN + 2]; char msg[UEVENT_MSG_LEN + 2];
char *cp; char *cp;
@ -1263,7 +1351,6 @@ static void uevent_event(uint32_t /*epevents*/, struct Usb::payload *payload) {
registerEpollEntryByFile(payload->usb, path, EPOLLPRI, host_event); registerEpollEntryByFile(payload->usb, path, EPOLLPRI, host_event);
} else if (action == "unbind") { } else if (action == "unbind") {
unregisterEpollEntry(payload->usb, path); unregisterEpollEntry(payload->usb, path);
clearUsbDeviceState(&payload->usb->mHostStateMap[path]);
} }
} }
} }

View file

@ -19,6 +19,7 @@
#include <android-base/file.h> #include <android-base/file.h>
#include <aidl/android/hardware/usb/BnUsb.h> #include <aidl/android/hardware/usb/BnUsb.h>
#include <aidl/android/hardware/usb/BnUsbCallback.h> #include <aidl/android/hardware/usb/BnUsbCallback.h>
#include <chrono>
#include <pixelusb/UsbOverheatEvent.h> #include <pixelusb/UsbOverheatEvent.h>
#include <sys/eventfd.h> #include <sys/eventfd.h>
#include <utils/Log.h> #include <utils/Log.h>
@ -132,12 +133,20 @@ struct Usb : public BnUsb {
// USB device state monitoring // USB device state monitoring
struct usbDeviceState { 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; int portResetCount;
}; };
struct usbDeviceState mDeviceState; struct usbDeviceState mDeviceState;
// Map host device path name to usbDeviceState // Map host device path name to usbDeviceState
std::map<std::string, struct usbDeviceState> mHostStateMap; 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 // File monitoring through epoll
int mEpollFd; int mEpollFd;