summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usb/usb/Android.bp1
-rw-r--r--usb/usb/Usb.cpp93
-rw-r--r--usb/usb/Usb.h11
3 files changed, 101 insertions, 4 deletions
diff --git a/usb/usb/Android.bp b/usb/usb/Android.bp
index c35666a..e28667f 100644
--- a/usb/usb/Android.bp
+++ b/usb/usb/Android.bp
@@ -53,6 +53,7 @@ cc_binary {
"android.frameworks.stats-V2-ndk",
"pixelatoms-cpp",
"libbinder_ndk",
+ "libprotobuf-cpp-lite",
],
static_libs: [
"libpixelusb-aidl",
diff --git a/usb/usb/Usb.cpp b/usb/usb/Usb.cpp
index bae5463..9aa09da 100644
--- a/usb/usb/Usb.cpp
+++ b/usb/usb/Usb.cpp
@@ -43,6 +43,7 @@
#include "Usb.h"
#include <aidl/android/frameworks/stats/IStats.h>
+#include <pixelusb/CommonUtils.h>
#include <pixelusb/UsbGadgetAidlCommon.h>
#include <pixelstats/StatsHelper.h>
@@ -53,6 +54,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;
using android::String8;
using android::Vector;
@@ -94,6 +98,8 @@ constexpr char kHostUeventRegex[] = "^(bind|unbind)@(/devices/platform/11210000\
constexpr int kSamplingIntervalSec = 5;
void queryVersionHelper(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus);
+void queryUsbDataSession(android::hardware::usb::Usb *usb,
+ std::vector<PortStatus> *currentPortStatus);
#define USB_STATE_MAX_LEN 20
#define CTRL_TRANSFER_TIMEOUT_MSEC 1000
@@ -909,6 +915,7 @@ void queryVersionHelper(android::hardware::usb::Usb *usb,
queryMoistureDetectionStatus(currentPortStatus);
queryPowerTransferStatus(currentPortStatus);
queryNonCompliantChargerStatus(currentPortStatus);
+ queryUsbDataSession(usb, currentPortStatus);
if (usb->mCallback != NULL) {
ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus,
status);
@@ -995,6 +1002,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);
+ }
+}
+
static void unregisterEpollEntry(Usb *usb, std::string name) {
std::map<std::string, struct Usb::epollEntry> *map;
int fd;
@@ -1068,14 +1123,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;
@@ -1095,6 +1152,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;
@@ -1167,7 +1255,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]);
}
}
}
diff --git a/usb/usb/Usb.h b/usb/usb/Usb.h
index faaa270..83bae88 100644
--- a/usb/usb/Usb.h
+++ b/usb/usb/Usb.h
@@ -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 <utils/Log.h>
@@ -99,12 +100,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;