summaryrefslogtreecommitdiff
path: root/usb
diff options
context:
space:
mode:
authorAndrew Chant <achant@google.com>2018-06-19 16:21:46 -0700
committerAndrew Chant <achant@google.com>2018-06-20 21:52:29 -0700
commit3b7aae824c67e6468d886c67bf90a6e14b386395 (patch)
tree6b10c885c87628b4a784c527e40056a39bd22e79 /usb
parent29659851e7f723a6f684520ff30b3a1567f89151 (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.bp17
-rw-r--r--usb/Usb.cpp122
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);