diff options
| author | Andrew Chant <achant@google.com> | 2018-06-19 16:21:46 -0700 |
|---|---|---|
| committer | Andrew Chant <achant@google.com> | 2018-06-20 21:52:29 -0700 |
| commit | 3b7aae824c67e6468d886c67bf90a6e14b386395 (patch) | |
| tree | 6b10c885c87628b4a784c527e40056a39bd22e79 /usb | |
| parent | 29659851e7f723a6f684520ff30b3a1567f89151 (diff) | |
crosshatch: usb: Add USB PixelStats reporting.
Report to PixelStats on USB-C connector connect/disconnect,
as well as USB-C audio device connect/disconnect.
If a device is connected at boot, the disconnect will not
be reported.
Test: checked eventlog for reported events, saw:
06-19 16:12:55.251 775 775 I sysui_multi_action: [757,1422,758,4]
06-19 16:17:00.250 775 775 I sysui_multi_action: [757,1423,758,4,1304,244991]
06-19 16:17:09.378 775 775 I sysui_multi_action: [757,1422,758,4]
06-19 16:17:11.939 775 775 I sysui_multi_action: [757,1424,758,4,1425,416370725]
06-19 16:17:14.320 775 775 I sysui_multi_action: [757,1426,758,4,1425,416370725,1304,2380]
06-19 16:17:14.610 775 775 I sysui_multi_action: [757,1423,758,4,1304,5231]
06-19 16:17:18.946 775 775 I sysui_multi_action: [757,1422,758,4]
06-19 16:18:23.672 775 775 I sysui_multi_action: [757,1423,758,4,1304,64725]
06-19 16:18:25.166 775 775 I sysui_multi_action: [757,1422,758,4]
These were:
USB-C connect
USB-C disconnect, connected for 244s.
USB-C connect
USB-C audio device connected, VIDPID 0x18d15025 == 416370725
USB-C audio device disconnected, VIDPID, connected for 2.38 seconds.
USB-C disconnected, connected for 5.231 seconds (3 second enumeration)
USB-C connected
USB-C disconnected, connected for 64.725 seconds
USB-C connected
Bug: 67749298
Change-Id: I1fc750b9ca578c40c663ec9806dd7b2804ab264b
Diffstat (limited to 'usb')
| -rw-r--r-- | usb/Android.bp | 17 | ||||
| -rw-r--r-- | usb/Usb.cpp | 122 |
2 files changed, 134 insertions, 5 deletions
diff --git a/usb/Android.bp b/usb/Android.bp index 511af20..244630c 100644 --- a/usb/Android.bp +++ b/usb/Android.bp @@ -12,22 +12,29 @@ // 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. + +// Placing Crosshatch USB in it's own soong namespace +soong_namespace { + imports: ["hardware/google/interfaces",], +} + cc_binary { name: "android.hardware.usb@1.1-service.crosshatch", relative_install_path: "hw", init_rc: ["android.hardware.usb@1.1-service.crosshatch.rc"], srcs: ["service.cpp", "Usb.cpp", "UsbGadget.cpp"], shared_libs: [ + "android.hardware.usb@1.0", + "android.hardware.usb@1.1", + "android.hardware.usb.gadget@1.0", + "hardware.google.pixelstats@1.0", "libbase", + "libcutils", + "libhardware", "libhidlbase", "libhidltransport", "liblog", "libutils", - "libhardware", - "android.hardware.usb@1.0", - "android.hardware.usb@1.1", - "android.hardware.usb.gadget@1.0", - "libcutils", ], proprietary: true, } diff --git a/usb/Usb.cpp b/usb/Usb.cpp index f0ecedd..5b28b19 100644 --- a/usb/Usb.cpp +++ b/usb/Usb.cpp @@ -16,7 +16,10 @@ #define LOG_TAG "android.hardware.usb@1.1-service.crosshatch" +#include <android-base/chrono_utils.h> #include <android-base/logging.h> +#include <android-base/parseint.h> +#include <android-base/strings.h> #include <assert.h> #include <chrono> #include <dirent.h> @@ -29,6 +32,7 @@ #include <unordered_map> #include <cutils/uevent.h> +#include <hardware/google/pixelstats/1.0/IPixelStats.h> #include <sys/epoll.h> #include <utils/Errors.h> #include <utils/StrongPointer.h> @@ -502,14 +506,114 @@ Return<void> Usb::queryPortStatus() { return Void(); } +/* uevent_event() data that is persistent across uevents. */ struct data { int uevent_fd; android::hardware::usb::V1_1::implementation::Usb *usb; + bool isUsbAttached; // Tracks USB port connectivity state. + base::Timer usbConnectTime; // Time of last USB port connection. + base::Timer usbAudioConnectTime; // Time of last USB audio connection. + char* attachedProduct; // PRODUCT= string of currently attached USB audio device. }; +// Report connection & disconnection of devices into the USB-C connector. +static void reportUsbConnectorUevents(struct data *payload, const char *power_supply_typec_mode) { + using ::hardware::google::pixelstats::V1_0::IPixelStats; + if (!power_supply_typec_mode) { + // No mode reported -> No reporting. + return; + } + + // It's attached if the string *doesn't* match. + int attached = !!strcmp(power_supply_typec_mode, "POWER_SUPPLY_TYPEC_MODE=Nothing attached"); + if (attached == payload->isUsbAttached) { + return; + } + payload->isUsbAttached = attached; + + sp<IPixelStats> client = IPixelStats::tryGetService(); + if (!client) { + ALOGE("Unable to connect to PixelStats service"); + return; + } + + if (attached) { + client->reportUsbConnectorConnected(); + payload->usbConnectTime = base::Timer(); + } else { + client->reportUsbConnectorDisconnected(payload->usbConnectTime.duration().count()); + } +} + +// Report connection & disconnection of USB audio devices. +static void reportUsbAudioUevents(struct data *payload, const char* driver, const char* product, + const char* action) { + using ::hardware::google::pixelstats::V1_0::IPixelStats; + // driver is not provided on remove, so it can be NULL. Check in remove branch. + if (!product || !action) { + return; + } + + // The PRODUCT of a USB audio device is PRODUCT=VID/PID/VERSION + std::vector<std::string> halves = android::base::Split(product, "="); + if (halves.size() != 2) { + return; + } + std::vector<std::string> vidPidVer = android::base::Split(halves[1], "/"); + if (vidPidVer.size() != 3) { + return; + } + + sp<IPixelStats> client = IPixelStats::tryGetService(); + if (!client) { + ALOGE("Couldn't connect to PixelStats service"); + return; + } + + // Parse the VID/PID as hex values. + const int kBaseHex = 16; + int32_t vid, pid; + char *vidEnd = NULL, *pidEnd = NULL; + + const char* vidC = vidPidVer[0].c_str(); + vid = strtol(vidC, &vidEnd, kBaseHex); + if ((vidC == vidEnd) || !vidEnd || (*vidEnd != '\0')) { + return; + } + + const char* pidC = vidPidVer[1].c_str(); + pid = strtol(pidC, &pidEnd, kBaseHex); + if ((pidC == pidEnd) || !pidEnd || (*pidEnd != '\0')) { + return; + } + + /* A uevent is generated for each audio interface - only report the first connected one + * for each device by storing its PRODUCT= string in payload->attachedProduct, and clearing + * it on disconnect. This also means we will only report the first USB audio device attached to + * the system. + */ + if (payload->attachedProduct == NULL && !strcmp(action, "ACTION=add")) { + if (!driver || strcmp(driver, "DRIVER=snd-usb-audio")) { + return; + } + // Reset connect time counter. + payload->usbAudioConnectTime = base::Timer(); + client->reportUsbAudioConnected(vid, pid); + payload->attachedProduct = strdup(product); + } else if (!strcmp(action, "ACTION=remove")) { + if (strcmp(payload->attachedProduct, product)) { + return; + } + free(payload->attachedProduct); + payload->attachedProduct = NULL; + client->reportUsbAudioDisconnected(vid, pid, payload->usbAudioConnectTime.duration().count()); + } +} + static void uevent_event(uint32_t /*epevents*/, struct data *payload) { char msg[UEVENT_MSG_LEN + 2]; char *cp; + const char *action, *power_supply_typec_mode, *driver, *product; int n; n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN); @@ -521,7 +625,19 @@ static void uevent_event(uint32_t /*epevents*/, struct data *payload) { msg[n + 1] = '\0'; cp = msg; + action = power_supply_typec_mode = driver = product = NULL; + while (*cp) { + if (!strncmp(cp, "ACTION=", strlen("ACTION="))) { + action = cp; + } else if (!strncmp(cp, "POWER_SUPPLY_TYPEC_MODE=", strlen("POWER_SUPPLY_TYPEC_MODE="))) { + power_supply_typec_mode = cp; + } else if (!strncmp(cp, "DRIVER=", strlen("DRIVER="))) { + driver = cp; + } else if (!strncmp(cp, "PRODUCT=", strlen("PRODUCT="))) { + product = cp; + } + if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) { ALOGI("partner added"); pthread_mutex_lock(&payload->usb->mPartnerLock); @@ -583,6 +699,8 @@ static void uevent_event(uint32_t /*epevents*/, struct data *payload) { /* advance to after the next \0 */ while (*cp++) {} } + reportUsbConnectorUevents(payload, power_supply_typec_mode); + reportUsbAudioUevents(payload, driver, product, action); } void *work(void *param) { @@ -602,6 +720,10 @@ void *work(void *param) { payload.uevent_fd = uevent_fd; payload.usb = (android::hardware::usb::V1_1::implementation::Usb *)param; + payload.isUsbAttached = false; + payload.attachedProduct = NULL; + payload.usbConnectTime = base::Timer(); + payload.usbAudioConnectTime = base::Timer(); fcntl(uevent_fd, F_SETFL, O_NONBLOCK); |
