From fbfc56b8aaaaa4c19847c07affb7f111ce985834 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 24 Oct 2023 07:59:40 -0700 Subject: [PATCH 01/15] Run fsck to resolve possible data corruption Trigger fsck on mount of /data if the value of ro.preventative_fsck is not equal to the contents of /metadata/vold/preventative_fsck, then set the file to the property to prevent future runs See b/305658663 for context Bug: 305658663 Test: Make sure fsck run after first boot and not after second (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:e4a81c0e8f9f8d89f0e42e8fd7ec40cec6b887ed) Merged-In: I1263d2d55fe22d994ae8c8654b1e75ad9e4ddafe Change-Id: I1263d2d55fe22d994ae8c8654b1e75ad9e4ddafe --- device-common.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/device-common.mk b/device-common.mk index 5e3c5118..bfd64abb 100644 --- a/device-common.mk +++ b/device-common.mk @@ -48,3 +48,7 @@ PRODUCT_PRODUCT_PROPERTIES += \ # Set thermal warm reset PRODUCT_PRODUCT_PROPERTIES += \ ro.thermal_warmreset = true + +# Trigger fsck on upgrade (305658663) +PRODUCT_PRODUCT_PROPERTIES += \ + ro.preventative_fsck = 1 \ No newline at end of file From baca0e0e4d09bf5bd2dd2e595df44f00c4ead65c Mon Sep 17 00:00:00 2001 From: Edgar Arriaga Date: Wed, 25 Oct 2023 20:43:26 +0000 Subject: [PATCH 02/15] Add webview pinning for gs201 devices Bug: 307594624 Change-Id: I13f4c2020b699f68a679fd34f4f6b025c0bfdb98 --- overlay/frameworks/base/core/res/res/values/config.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/overlay/frameworks/base/core/res/res/values/config.xml b/overlay/frameworks/base/core/res/res/values/config.xml index f2ed7789..82cb06dd 100644 --- a/overlay/frameworks/base/core/res/res/values/config.xml +++ b/overlay/frameworks/base/core/res/res/values/config.xml @@ -252,6 +252,9 @@ true + + 20971520 + From ad362cf2590b84b39519c45d298dfe5ad9752946 Mon Sep 17 00:00:00 2001 From: Peter Lin Date: Thu, 30 Nov 2023 07:50:38 +0000 Subject: [PATCH 03/15] Update default color temperature for night light Bug: 302396607 Test: adb shell dumpsys color_display | grep "Color temp" Change-Id: I7812dcea6e2d6bceab13d9f103e434e19b6e9477 --- overlay/frameworks/base/core/res/res/values/config.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overlay/frameworks/base/core/res/res/values/config.xml b/overlay/frameworks/base/core/res/res/values/config.xml index 82cb06dd..e9e4f01b 100644 --- a/overlay/frameworks/base/core/res/res/values/config.xml +++ b/overlay/frameworks/base/core/res/res/values/config.xml @@ -215,7 +215,7 @@ - 3339 + 4000 true From 3555bbe0a8ef335a95080b8b91cd3e8257785365 Mon Sep 17 00:00:00 2001 From: Roy Luo Date: Tue, 14 Nov 2023 18:49:06 +0000 Subject: [PATCH 04/15] usb: introduce UsbDataSessionMonitor class Migrate the usb data session event functions to the class with the following additional functionalities; - Support detecting gadget soft pulldown (usually done during configfs function switch) and report usb data session correctly. - Support reporting usb data compliance warnings to the class USB by providing getDataComplianceWarnings call. - Use boot_clock instead of steady_clock to measure time correctly in the case of system suspend. UsbDataSessionMonitor is self-contained and can be migrated to pixel usb library after feature maturation. Bug: 297224564 Bug: 296119135 Test: usb data session upload in device and host mode Change-Id: Iba001933e193935d64cf5fd0a1257d02a4274fb1 (cherry picked from commit ea65ca11f6fbb6f13b89ef9ed03015f47ec1cedb) --- usb/usb/Android.bp | 1 + usb/usb/Usb.cpp | 308 +++++----------------- usb/usb/Usb.h | 34 +-- usb/usb/UsbDataSessionMonitor.cpp | 420 ++++++++++++++++++++++++++++++ usb/usb/UsbDataSessionMonitor.h | 114 ++++++++ 5 files changed, 598 insertions(+), 279 deletions(-) create mode 100644 usb/usb/UsbDataSessionMonitor.cpp create mode 100644 usb/usb/UsbDataSessionMonitor.h diff --git a/usb/usb/Android.bp b/usb/usb/Android.bp index 8fd373b2..609af179 100644 --- a/usb/usb/Android.bp +++ b/usb/usb/Android.bp @@ -34,6 +34,7 @@ cc_binary { srcs: [ "service.cpp", "Usb.cpp", + "UsbDataSessionMonitor.cpp", ], shared_libs: [ "libbase", diff --git a/usb/usb/Usb.cpp b/usb/usb/Usb.cpp index 224951a1..555e6576 100644 --- a/usb/usb/Usb.cpp +++ b/usb/usb/Usb.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -44,7 +43,6 @@ #include #include -#include #include #include @@ -57,9 +55,6 @@ 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; @@ -95,17 +90,22 @@ constexpr char kThermalZoneForTempReadSecondary2[] = "qi_therm"; constexpr char kPogoUsbActive[] = "/sys/devices/platform/google,pogo/pogo_usb_active"; constexpr char KPogoMoveDataToUsb[] = "/sys/devices/platform/google,pogo/move_data_to_usb"; constexpr char kPowerSupplyUsbType[] = "/sys/class/power_supply/usb/usb_type"; -constexpr char kUdcState[] = "/sys/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3/state"; -// xhci-hcd-exynos and usb device numbering could vary on different platforms -constexpr char kHostUeventRegex[] = "^(bind|unbind)@(/devices/platform/11210000\\.usb/11210000\\.dwc3/xhci-hcd-exynos\\.[0-9]\\.auto/)usb([0-9])/[0-9]-0:1\\.0"; +constexpr char kUdcUeventRegex[] = + "/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3"; +constexpr char kUdcStatePath[] = + "/sys/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3/state"; +constexpr char kHost1UeventRegex[] = + "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb2/2-0:1.0"; +constexpr char kHost1StatePath[] = "/sys/bus/usb/devices/usb2/2-0:1.0/usb2-port1/state"; +constexpr char kHost2UeventRegex[] = + "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb3/3-0:1.0"; +constexpr char kHost2StatePath[] = "/sys/bus/usb/devices/usb3/3-0:1.0/usb3-port1/state"; +constexpr char kDataRolePath[] = "/sys/devices/platform/11210000.usb/new_data_role"; constexpr int kSamplingIntervalSec = 5; void queryVersionHelper(android::hardware::usb::Usb *usb, std::vector *currentPortStatus); -void queryUsbDataSession(android::hardware::usb::Usb *usb, - std::vector *currentPortStatus); -#define USB_STATE_MAX_LEN 20 #define CTRL_TRANSFER_TIMEOUT_MSEC 1000 #define GL852G_VENDOR_ID 0x05e3 #define GL852G_PRODUCT_ID1 0x0608 @@ -538,11 +538,20 @@ void *usbHostWork(void *param) { return NULL; } +void updatePortStatus(android::hardware::usb::Usb *usb) { + std::vector currentPortStatus; + + queryVersionHelper(usb, ¤tPortStatus); +} + Usb::Usb() : mLock(PTHREAD_MUTEX_INITIALIZER), mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER), mPartnerLock(PTHREAD_MUTEX_INITIALIZER), mPartnerUp(false), + mUsbDataSessionMonitor(kUdcUeventRegex, kUdcStatePath, kHost1UeventRegex, kHost1StatePath, + kHost2UeventRegex, kHost2StatePath, kDataRolePath, + std::bind(&updatePortStatus, this)), mOverheat(ZoneInfo(TemperatureType::USB_PORT, kThermalZoneForTrip, ThrottlingSeverity::CRITICAL), {ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadPrimary, @@ -922,6 +931,18 @@ done: return Status::ERROR; } +void queryUsbDataSession(android::hardware::usb::Usb *usb, + std::vector *currentPortStatus) { + std::vector warnings; + + usb->mUsbDataSessionMonitor.getComplianceWarnings( + (*currentPortStatus)[0].currentDataRole, &warnings); + (*currentPortStatus)[0].complianceWarnings.insert( + (*currentPortStatus)[0].complianceWarnings.end(), + warnings.begin(), + warnings.end()); +} + void queryVersionHelper(android::hardware::usb::Usb *usb, std::vector *currentPortStatus) { Status status; @@ -1017,194 +1038,17 @@ void report_overheat_event(android::hardware::usb::Usb *usb) { } } -void report_usb_data_session_event(android::hardware::usb::Usb *usb) { - std::vector events; +struct data { + int uevent_fd; + ::aidl::android::hardware::usb::Usb *usb; +}; - 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 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 *map; - int fd; - - map = &usb->mEpollEntries; - auto it = map->find(name); - if (it != map->end()) { - ALOGI("epoll unregister %s", name.c_str()); - fd = it->second.payload.fd; - epoll_ctl(usb->mEpollFd, EPOLL_CTL_DEL, fd, NULL); - close(fd); - map->erase(it); - } -} - -static void unregisterEpollEntries(Usb *usb) { - std::map *map; - std::string name; - - map = &usb->mEpollEntries; - for (auto it = map->begin(); it != map->end();) { - name = it->first; - it++; - unregisterEpollEntry(usb, name); - } -} - -static int registerEpollEntry(Usb *usb, std::string name, int fd, int flags, - void (*func)(uint32_t, struct Usb::payload*)) { - std::map *map; - struct Usb::epollEntry *entry; - struct epoll_event ev; - - map = &usb->mEpollEntries; - if (map->find(name) != map->end()) { - ALOGE("%s already registered", name.c_str()); - unregisterEpollEntry(usb, name); - } - - entry = &(*map)[name]; - entry->payload.fd = fd; - entry->payload.name = name; - entry->payload.usb = usb; - entry->cb = std::bind(func, std::placeholders::_1, &entry->payload); - - ev.events = flags; - ev.data.ptr = (void *)&entry->cb; - - if (epoll_ctl(usb->mEpollFd, EPOLL_CTL_ADD, fd, &ev) != 0) { - ALOGE("epoll_ctl failed; errno=%d", errno); - unregisterEpollEntry(usb, name); - return -1; - } - - ALOGI("epoll register %s", name.c_str()); - - return 0; -} - -static int registerEpollEntryByFile(Usb *usb, std::string name, int flags, - void (*func)(uint32_t, struct Usb::payload*)) { - int fd; - - fd = open(name.c_str(), O_RDONLY); - if (fd < 0) { - ALOGE("Cannot open %s", name.c_str()); - return -1; - } - - return registerEpollEntry(usb, name, fd, flags, func); -} - -static void clearUsbDeviceState(struct Usb::usbDeviceState *device) { - 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->states.push_back(state); - device->timestamps.push_back(std::chrono::steady_clock::now()); - - if (!std::strcmp(state, "configured\n")) { - device->portResetCount = 0; - } else if (!std::strcmp(state, "default\n")) { - device->portResetCount++; - } -} - -static void host_event(uint32_t /*epevents*/, struct Usb::payload *payload) { - int n; - char state[USB_STATE_MAX_LEN] = {0}; - struct Usb::usbDeviceState *device; - - lseek(payload->fd, 0, SEEK_SET); - n = read(payload->fd, &state, USB_STATE_MAX_LEN); - - updateUsbDeviceState(&payload->usb->mHostStateMap[payload->name], state); -} - -void queryUsbDataSession(android::hardware::usb::Usb *usb, - std::vector *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 data *payload) { char msg[UEVENT_MSG_LEN + 2]; char *cp; int n; - std::cmatch match; - n = uevent_kernel_multicast_recv(payload->fd, msg, UEVENT_MSG_LEN); + n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN); if (n <= 0) return; if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ @@ -1250,28 +1094,6 @@ static void uevent_event(uint32_t /*epevents*/, struct Usb::payload *payload) { } else if (!strncmp(cp, kOverheatStatsDev, strlen(kOverheatStatsDev))) { ALOGV("Overheat Cooling device suez update"); report_overheat_event(payload->usb); - } else if (std::regex_match(cp, match, std::regex(kHostUeventRegex))) { - /* - * Matched strings: - * 1st: entire string - * 2nd: uevent action, either "bind" or "unbind" - * 3rd: xhci device path, e.g. devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.4.auto - * 4th: usb device number, e.g. 1 for usb1 - * - * The strings are used to composed usb device state path, e.g. - * /sys/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.4.auto/usb2/2-0:1.0/usb2-port1/state - */ - if (match.size() == 4) { - std::string action = match[1].str(); - std::string id = match[3].str(); - std::string path = "/sys" + match[2].str() + "usb" + id + "/" + - id + "-0:1.0/usb" + id + "-port1/state"; - if (action == "bind") { - registerEpollEntryByFile(payload->usb, path, EPOLLPRI, host_event); - } else if (action == "unbind") { - unregisterEpollEntry(payload->usb, path); - } - } } /* advance to after the next \0 */ while (*cp++) { @@ -1279,46 +1101,37 @@ static void uevent_event(uint32_t /*epevents*/, struct Usb::payload *payload) { } } -static void udc_event(uint32_t /*epevents*/, struct Usb::payload *payload) { - int n; - char state[USB_STATE_MAX_LEN] = {0}; - - lseek(payload->fd, 0, SEEK_SET); - n = read(payload->fd, &state, USB_STATE_MAX_LEN); - - updateUsbDeviceState(&payload->usb->mDeviceState, state); -} - void *work(void *param) { int epoll_fd, uevent_fd; + struct epoll_event ev; int nevents = 0; - Usb *usb = (Usb *)param; + struct data payload; ALOGE("creating thread"); + uevent_fd = uevent_open_socket(64 * 1024, true); + + if (uevent_fd < 0) { + ALOGE("uevent_init: uevent_open_socket failed\n"); + return NULL; + } + + payload.uevent_fd = uevent_fd; + payload.usb = (::aidl::android::hardware::usb::Usb *)param; + + fcntl(uevent_fd, F_SETFL, O_NONBLOCK); + + ev.events = EPOLLIN; + ev.data.ptr = (void *)uevent_event; + epoll_fd = epoll_create(64); if (epoll_fd == -1) { ALOGE("epoll_create failed; errno=%d", errno); - return NULL; - } - usb->mEpollFd = epoll_fd; - - // Monitor uevent - uevent_fd = uevent_open_socket(64 * 1024, true); - if (uevent_fd < 0) { - ALOGE("uevent_init: uevent_open_socket failed"); - goto error; - } - fcntl(uevent_fd, F_SETFL, O_NONBLOCK); - - if (registerEpollEntry(usb, "uevent", uevent_fd, EPOLLIN, uevent_event)) { - ALOGE("failed to monitor uevent"); goto error; } - // Monitor udc state - if (registerEpollEntryByFile(usb, kUdcState, EPOLLPRI, udc_event)) { - ALOGE("failed to monitor udc state"); + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) { + ALOGE("epoll_ctl failed; errno=%d", errno); goto error; } @@ -1335,15 +1148,14 @@ void *work(void *param) { for (int n = 0; n < nevents; ++n) { if (events[n].data.ptr) - (*(std::function*)events[n].data.ptr)(events[n].events); + (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events, + &payload); } } ALOGI("exiting worker thread"); error: - unregisterEpollEntries(usb); - - usb->mEpollFd = -1; + close(uevent_fd); if (epoll_fd >= 0) close(epoll_fd); diff --git a/usb/usb/Usb.h b/usb/usb/Usb.h index 83bae889..495a467f 100644 --- a/usb/usb/Usb.h +++ b/usb/usb/Usb.h @@ -19,9 +19,9 @@ #include #include #include -#include #include #include +#include #define UEVENT_MSG_LEN 2048 // The type-c stack waits for 4.5 - 5.5 secs before declaring a port non-pd. @@ -88,6 +88,8 @@ struct Usb : public BnUsb { // Variable to signal partner coming back online after type switch bool mPartnerUp; + // Report usb data session event and data incompliance warnings + UsbDataSessionMonitor mUsbDataSessionMonitor; // Usb Overheat object for push suez event UsbOverheatEvent mOverheat; // Temperature when connected @@ -98,36 +100,6 @@ struct Usb : public BnUsb { int mUsbHubVendorCmdValue; int mUsbHubVendorCmdIndex; - // USB device state monitoring - struct usbDeviceState { - // Usb device state raw strings read from sysfs - std::vector states; - // Timestamps of when the usb device states were captured - std::vector timestamps; - int portResetCount; - }; - struct usbDeviceState mDeviceState; - // Map host device path name to usbDeviceState - std::map 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; - struct payload { - int fd; - std::string name; - Usb *usb; - }; - struct epollEntry { - struct payload payload; - std::function cb; - }; - std::map mEpollEntries; - private: pthread_t mPoll; pthread_t mUsbHost; diff --git a/usb/usb/UsbDataSessionMonitor.cpp b/usb/usb/UsbDataSessionMonitor.cpp new file mode 100644 index 00000000..77defb30 --- /dev/null +++ b/usb/usb/UsbDataSessionMonitor.cpp @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ + +#define LOG_TAG "android.hardware.usb.aidl-service.UsbDataSessionMonitor" + +#include "UsbDataSessionMonitor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace usb_flags = android::hardware::usb::flags; + +using aidl::android::frameworks::stats::IStats; +using android::base::ReadFileToString; +using android::hardware::google::pixel::getStatsService; +using android::hardware::google::pixel::reportUsbDataSessionEvent; +using android::hardware::google::pixel::PixelAtoms::VendorUsbDataSessionEvent; +using android::hardware::google::pixel::usb::addEpollFd; +using android::hardware::google::pixel::usb::BuildVendorUsbDataSessionEvent; + +namespace aidl { +namespace android { +namespace hardware { +namespace usb { + +#define UEVENT_MSG_LEN 2048 +#define USB_STATE_MAX_LEN 20 +#define DATA_ROLE_MAX_LEN 10 + +constexpr char kUdcConfigfsPath[] = "/config/usb_gadget/g1/UDC"; +constexpr char kNotAttachedState[] = "not attached\n"; +constexpr char kAttachedState[] = "attached\n"; +constexpr char kPoweredState[] = "powered\n"; +constexpr char kDefaultState[] = "default\n"; +constexpr char kAddressedState[] = "addressed\n"; +constexpr char kConfiguredState[] = "configured\n"; +constexpr char kSuspendedState[] = "suspended\n"; +const std::set kValidStates = {kNotAttachedState, kAttachedState, kPoweredState, + kDefaultState, kAddressedState, kConfiguredState, + kSuspendedState}; + +static int addEpollFile(const int &epollFd, const std::string &filePath, unique_fd &fileFd) { + struct epoll_event ev; + + unique_fd fd(open(filePath.c_str(), O_RDONLY)); + + if (fd.get() == -1) { + ALOGI("Cannot open %s", filePath.c_str()); + return -1; + } + + ev.data.fd = fd.get(); + ev.events = EPOLLPRI; + + if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fd.get(), &ev) != 0) { + ALOGE("epoll_ctl failed; errno=%d", errno); + return -1; + } + + fileFd = std::move(fd); + ALOGI("epoll registered %s", filePath.c_str()); + return 0; +} + +static void removeEpollFile(const int &epollFd, const std::string &filePath, unique_fd &fileFd) { + epoll_ctl(epollFd, EPOLL_CTL_DEL, fileFd.get(), NULL); + fileFd.release(); + + ALOGI("epoll unregistered %s", filePath.c_str()); +} + +UsbDataSessionMonitor::UsbDataSessionMonitor( + const std::string &deviceUeventRegex, const std::string &deviceStatePath, + const std::string &host1UeventRegex, const std::string &host1StatePath, + const std::string &host2UeventRegex, const std::string &host2StatePath, + const std::string &dataRolePath, std::function updatePortStatusCb) { + struct epoll_event ev; + std::string udc; + + unique_fd epollFd(epoll_create(8)); + if (epollFd.get() == -1) { + ALOGE("epoll_create failed; errno=%d", errno); + abort(); + } + + unique_fd ueventFd(uevent_open_socket(64 * 1024, true)); + if (ueventFd.get() == -1) { + ALOGE("uevent_open_socket failed"); + abort(); + } + fcntl(ueventFd, F_SETFL, O_NONBLOCK); + + if (addEpollFd(epollFd, ueventFd)) + abort(); + + if (addEpollFile(epollFd.get(), dataRolePath, mDataRoleFd) != 0) { + ALOGE("monitor data role failed"); + abort(); + } + + /* + * The device state file could be absent depending on the current data role + * and driver architecture. It's ok for addEpollFile to fail here, the file + * will be monitored later when its presence is detected by uevent. + */ + mDeviceState.filePath = deviceStatePath; + mDeviceState.ueventRegex = deviceUeventRegex; + addEpollFile(epollFd.get(), mDeviceState.filePath, mDeviceState.fd); + + mHost1State.filePath = host1StatePath; + mHost1State.ueventRegex = host1UeventRegex; + addEpollFile(epollFd.get(), mHost1State.filePath, mHost1State.fd); + + mHost2State.filePath = host2StatePath; + mHost2State.ueventRegex = host2UeventRegex; + addEpollFile(epollFd.get(), mHost2State.filePath, mHost2State.fd); + + mEpollFd = std::move(epollFd); + mUeventFd = std::move(ueventFd); + mUpdatePortStatusCb = updatePortStatusCb; + + if (ReadFileToString(kUdcConfigfsPath, &udc) && !udc.empty()) + mUdcBind = true; + else + mUdcBind = false; + + if (pthread_create(&mMonitor, NULL, this->monitorThread, this)) { + ALOGE("pthread creation failed %d", errno); + abort(); + } +} + +UsbDataSessionMonitor::~UsbDataSessionMonitor() {} + +void UsbDataSessionMonitor::reportUsbDataSessionMetrics() { + std::vector events; + + if (mDataRole == PortDataRole::DEVICE) { + VendorUsbDataSessionEvent event; + BuildVendorUsbDataSessionEvent(false /* is_host */, boot_clock::now(), mDataSessionStart, + &mDeviceState.states, &mDeviceState.timestamps, &event); + events.push_back(event); + } else if (mDataRole == PortDataRole::HOST) { + bool empty = true; + for (auto e : {&mHost1State, &mHost2State}) { + /* + * Host port will at least get an not_attached event after enablement, + * skip upload if no additional state is added. + */ + if (e->states.size() > 1) { + VendorUsbDataSessionEvent event; + BuildVendorUsbDataSessionEvent(true /* is_host */, boot_clock::now(), + mDataSessionStart, &e->states, &e->timestamps, + &event); + events.push_back(event); + empty = false; + } + } + // All host ports have no state update, upload an event to reflect it + if (empty) { + VendorUsbDataSessionEvent event; + BuildVendorUsbDataSessionEvent(true /* is_host */, boot_clock::now(), mDataSessionStart, + &mHost1State.states, &mHost1State.timestamps, &event); + events.push_back(event); + } + } else { + return; + } + + const std::shared_ptr stats_client = getStatsService(); + if (!stats_client) { + ALOGE("Unable to get AIDL Stats service"); + return; + } + + for (auto &event : events) { + reportUsbDataSessionEvent(stats_client, event); + } +} + +void UsbDataSessionMonitor::getComplianceWarnings(const PortDataRole &role, + std::vector *warnings) { + if (!usb_flags::enable_report_usb_data_compliance_warning()) + return; + + if (role != mDataRole || role == PortDataRole::NONE) + return; + + for (auto w : mWarningSet) { + warnings->push_back(w); + } +} + +void UsbDataSessionMonitor::notifyComplianceWarning() { + if (!usb_flags::enable_report_usb_data_compliance_warning()) + return; + + if (mUpdatePortStatusCb) + mUpdatePortStatusCb(); +} + +void UsbDataSessionMonitor::evaluateComplianceWarning() { + std::set newWarningSet; + + // TODO: add heuristics and update newWarningSet + if (mDataRole == PortDataRole::DEVICE && mUdcBind) { + } else if (mDataRole == PortDataRole::HOST) { + } + + if (newWarningSet != mWarningSet) { + mWarningSet = newWarningSet; + notifyComplianceWarning(); + } +} + +void UsbDataSessionMonitor::clearDeviceStateEvents(struct usbDeviceState *deviceState) { + deviceState->states.clear(); + deviceState->timestamps.clear(); +} + +void UsbDataSessionMonitor::handleDeviceStateEvent(struct usbDeviceState *deviceState) { + int n; + char state[USB_STATE_MAX_LEN] = {0}; + + lseek(deviceState->fd.get(), 0, SEEK_SET); + n = read(deviceState->fd.get(), &state, USB_STATE_MAX_LEN); + + if (kValidStates.find(state) == kValidStates.end()) { + ALOGE("Invalid state %s", state); + return; + } + + ALOGI("Update USB device state: %s", state); + + deviceState->states.push_back(state); + deviceState->timestamps.push_back(boot_clock::now()); + evaluateComplianceWarning(); +} + +void UsbDataSessionMonitor::handleDataRoleEvent() { + int n; + PortDataRole newDataRole; + char role[DATA_ROLE_MAX_LEN] = {0}; + + lseek(mDataRoleFd.get(), 0, SEEK_SET); + n = read(mDataRoleFd.get(), &role, DATA_ROLE_MAX_LEN); + + ALOGI("Update USB data role %s", role); + + if (!std::strcmp(role, "host")) { + newDataRole = PortDataRole::HOST; + } else if (!std::strcmp(role, "device")) { + newDataRole = PortDataRole::DEVICE; + } else { + newDataRole = PortDataRole::NONE; + } + + if (newDataRole != mDataRole) { + // Upload metrics for the last data session that has ended + if (mDataRole == PortDataRole::HOST || (mDataRole == PortDataRole::DEVICE && mUdcBind)) { + reportUsbDataSessionMetrics(); + } + + // Set up for the new data session + mWarningSet.clear(); + mDataRole = newDataRole; + mDataSessionStart = boot_clock::now(); + + if (newDataRole == PortDataRole::DEVICE) { + clearDeviceStateEvents(&mDeviceState); + } else if (newDataRole == PortDataRole::HOST) { + clearDeviceStateEvents(&mHost1State); + clearDeviceStateEvents(&mHost2State); + } + } +} + +void UsbDataSessionMonitor::updateUdcBindStatus(const std::string &devname) { + std::string function; + bool newUdcBind; + + /* + * /sys/class/udc//function prints out name of currently running USB gadget driver + * Ref: https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-udc + * Empty name string means the udc device is not bound and gadget is pulldown. + */ + if (!ReadFileToString("/sys" + devname + "/function", &function)) + return; + + if (function == "") + newUdcBind = false; + else + newUdcBind = true; + + if (newUdcBind == mUdcBind) + return; + + if (mDataRole == PortDataRole::DEVICE) { + if (mUdcBind && !newUdcBind) { + /* + * Gadget soft pulldown: report metrics as the end of a data session and + * re-evaluate compliance warnings to clear existing warnings if any. + */ + reportUsbDataSessionMetrics(); + evaluateComplianceWarning(); + + } else if (!mUdcBind && newUdcBind) { + // Gadget soft pullup: reset and start accounting for a new data session. + clearDeviceStateEvents(&mDeviceState); + mDataSessionStart = boot_clock::now(); + } + } + + ALOGI("Udc bind status changes from %b to %b", mUdcBind, newUdcBind); + mUdcBind = newUdcBind; +} + +void UsbDataSessionMonitor::handleUevent() { + char msg[UEVENT_MSG_LEN + 2]; + char *cp; + int n; + + n = uevent_kernel_multicast_recv(mUeventFd.get(), msg, UEVENT_MSG_LEN); + if (n <= 0) + return; + if (n >= UEVENT_MSG_LEN) + return; + + msg[n] = '\0'; + msg[n + 1] = '\0'; + cp = msg; + + while (*cp) { + for (auto e : {&mHost1State, &mHost2State}) { + if (std::regex_search(cp, std::regex(e->ueventRegex))) { + if (!strncmp(cp, "bind@", strlen("bind@"))) { + addEpollFile(mEpollFd.get(), e->filePath, e->fd); + } else if (!strncmp(cp, "unbind@", strlen("unbind@"))) { + removeEpollFile(mEpollFd.get(), e->filePath, e->fd); + } + } + } + + // TODO: support bind@ unbind@ to detect dynamically allocated udc device + if (std::regex_search(cp, std::regex(mDeviceState.ueventRegex))) { + if (!strncmp(cp, "change@", strlen("change@"))) { + char *devname = cp + strlen("change@"); + /* + * Udc device emits a KOBJ_CHANGE event on configfs driver bind and unbind. + * TODO: upstream udc driver emits KOBJ_CHANGE event BEFORE unbind is actually + * executed. Add a short delay to get the correct state while working on a fix + * upstream. + */ + usleep(50000); + updateUdcBindStatus(devname); + } + } + /* advance to after the next \0 */ + while (*cp++) { + } + } +} + +void *UsbDataSessionMonitor::monitorThread(void *param) { + UsbDataSessionMonitor *monitor = (UsbDataSessionMonitor *)param; + struct epoll_event events[64]; + int nevents = 0; + + while (true) { + nevents = epoll_wait(monitor->mEpollFd.get(), events, 64, -1); + if (nevents == -1) { + if (errno == EINTR) + continue; + ALOGE("usb epoll_wait failed; errno=%d", errno); + break; + } + + for (int n = 0; n < nevents; ++n) { + if (events[n].data.fd == monitor->mUeventFd.get()) { + monitor->handleUevent(); + } else if (events[n].data.fd == monitor->mDataRoleFd.get()) { + monitor->handleDataRoleEvent(); + } else if (events[n].data.fd == monitor->mDeviceState.fd.get()) { + monitor->handleDeviceStateEvent(&monitor->mDeviceState); + } else if (events[n].data.fd == monitor->mHost1State.fd.get()) { + monitor->handleDeviceStateEvent(&monitor->mHost1State); + } else if (events[n].data.fd == monitor->mHost2State.fd.get()) { + monitor->handleDeviceStateEvent(&monitor->mHost2State); + } + } + } + return NULL; +} + +} // namespace usb +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/usb/usb/UsbDataSessionMonitor.h b/usb/usb/UsbDataSessionMonitor.h new file mode 100644 index 00000000..596f378f --- /dev/null +++ b/usb/usb/UsbDataSessionMonitor.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace usb { + +using ::aidl::android::hardware::usb::ComplianceWarning; +using ::aidl::android::hardware::usb::PortDataRole; +using ::android::base::boot_clock; +using ::android::base::unique_fd; + +/* + * UsbDataSessionMonitor monitors the usb device state sysfs of 3 different usb devices + * including device mode (udc), host mode high-speed port and host mode super-speed port. It + * reports Suez metrics for each data session and also provides API to query the compliance + * warnings detected in the current usb data session. + */ +class UsbDataSessionMonitor { + public: + /* + * The host mode high-speed port and super-speed port can be assigned to either host1 or + * host2 without affecting functionality. + * + * UeventRegex: name regex of the device that's being monitored. The regex is matched against + * uevent to detect dynamic creation/deletion/change of the device. + * StatePath: usb device state sysfs path of the device, monitored by epoll. + * dataRolePath: path to the usb data role sysfs, monitored by epoll. + * updatePortStatusCb: the callback is invoked when the compliance warings changes. + */ + UsbDataSessionMonitor(const std::string &deviceUeventRegex, const std::string &deviceStatePath, + const std::string &host1UeventRegex, const std::string &host1StatePath, + const std::string &host2UeventRegex, const std::string &host2StatePath, + const std::string &dataRolePath, + std::function updatePortStatusCb); + ~UsbDataSessionMonitor(); + // Returns the compliance warnings detected in the current data session. + void getComplianceWarnings(const PortDataRole &role, std::vector *warnings); + + private: + struct usbDeviceState { + unique_fd fd; + std::string filePath; + std::string ueventRegex; + // Usb device states reported by state sysfs + std::vector states; + // Timestamps of when the usb device states were captured + std::vector timestamps; + }; + + static void *monitorThread(void *param); + void handleUevent(); + void handleDataRoleEvent(); + void handleDeviceStateEvent(struct usbDeviceState *deviceState); + void clearDeviceStateEvents(struct usbDeviceState *deviceState); + void reportUsbDataSessionMetrics(); + void evaluateComplianceWarning(); + void notifyComplianceWarning(); + void updateUdcBindStatus(const std::string &devname); + + pthread_t mMonitor; + unique_fd mEpollFd; + unique_fd mUeventFd; + unique_fd mDataRoleFd; + struct usbDeviceState mDeviceState; + struct usbDeviceState mHost1State; + struct usbDeviceState mHost2State; + std::set mWarningSet; + // Callback function to notify the caller when there's a change in compliance warnings. + std::function mUpdatePortStatusCb; + /* + * Cache relevant info for a USB data session when one starts, including + * the data role and the time when the session starts. + */ + PortDataRole mDataRole; + boot_clock::time_point mDataSessionStart; + /* + * In gadget mode: this indicates whether the udc device is bound to the configfs driver, which + * is done by userspace writing the udc device name to /config/usb_gadget/g1/UDC. When unbound, + * the gadget is in soft pulldown state and is expected not to enumerate. During gadget + * function switch, the udc device usually go through unbind and bind. + */ + bool mUdcBind; +}; + +} // namespace usb +} // namespace hardware +} // namespace android +} // namespace aidl From c41e6f519bc79da4a1578a88a68f17d604660a3b Mon Sep 17 00:00:00 2001 From: Hiroshi Akiyama Date: Thu, 30 Nov 2023 19:44:58 +0000 Subject: [PATCH 05/15] bcl: adjust heavy clk divider ratio Bug: 314168856 Test: tbd Change-Id: If32830eb480a6db99e32b3c1a277a79f058cc43f Signed-off-by: Hiroshi Akiyama --- conf/init.gs201.rc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/conf/init.gs201.rc b/conf/init.gs201.rc index ae03ce9a..4c6da6df 100644 --- a/conf/init.gs201.rc +++ b/conf/init.gs201.rc @@ -934,13 +934,13 @@ on post-fs-data on property:vendor.brownout.mitigation.ready=1 # BCL - write /sys/devices/virtual/pmic/mitigation/clock_ratio/tpu_light_clk_ratio 0xfff041c1 #DFS - write /sys/devices/virtual/pmic/mitigation/clock_ratio/cpu1_heavy_clk_ratio 0xfff041c1 #DFS - write /sys/devices/virtual/pmic/mitigation/clock_ratio/cpu2_heavy_clk_ratio 0xfff041c1 #DFS - write /sys/devices/virtual/pmic/mitigation/clock_ratio/gpu_light_clk_ratio 0xfff041c1 #DFS + write /sys/devices/virtual/pmic/mitigation/clock_ratio/tpu_light_clk_ratio 0x80041c3 #DFS + write /sys/devices/virtual/pmic/mitigation/clock_ratio/cpu1_heavy_clk_ratio 0xfff041c0 #DFS + write /sys/devices/virtual/pmic/mitigation/clock_ratio/cpu2_heavy_clk_ratio 0xfff041c0 #DFS + write /sys/devices/virtual/pmic/mitigation/clock_ratio/gpu_light_clk_ratio 0x80041c3 #DFS write /sys/devices/virtual/pmic/mitigation/clock_ratio/cpu2_light_clk_ratio 0xfff041c3 #OCP - write /sys/devices/virtual/pmic/mitigation/clock_ratio/gpu_heavy_clk_ratio 0xfff04385 #OCP - write /sys/devices/virtual/pmic/mitigation/clock_ratio/tpu_heavy_clk_ratio 0xfff041c3 #OCP + write /sys/devices/virtual/pmic/mitigation/clock_ratio/gpu_heavy_clk_ratio 0xfff04381 #OCP + write /sys/devices/virtual/pmic/mitigation/clock_ratio/tpu_heavy_clk_ratio 0xfff041c1 #OCP write /sys/devices/virtual/pmic/mitigation/triggered_lvl/uvlo1_lvl 3200 write /sys/devices/virtual/pmic/mitigation/triggered_lvl/smpl_lvl 3100 write /sys/devices/virtual/pmic/mitigation/triggered_lvl/uvlo2_lvl 3000 From fcab3aa32fbfded0e76b60fabd0316afae2e2cd0 Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Thu, 9 Nov 2023 21:20:42 +0800 Subject: [PATCH 06/15] gs201: move bootctrl hal to gs-common Bug: 265063384 Change-Id: I11d07835c2785bdcc2a373befc1109bc12e4d11f Signed-off-by: Jason Chiu --- interfaces/boot/1.0/Android.bp | 66 --- interfaces/boot/1.0/BootControl.cpp | 272 ------------ interfaces/boot/1.0/BootControl.h | 59 --- interfaces/boot/1.0/GptUtils.cpp | 199 --------- interfaces/boot/1.0/GptUtils.h | 79 ---- ...android.hardware.boot@1.0-service-gs201.rc | 4 - interfaces/boot/1.0/service.cpp | 47 -- interfaces/boot/1.2/Android.bp | 81 ---- interfaces/boot/1.2/BootControl.cpp | 420 ------------------ interfaces/boot/1.2/BootControl.h | 69 --- interfaces/boot/1.2/DevInfo.h | 61 --- interfaces/boot/1.2/GptUtils.cpp | 193 -------- interfaces/boot/1.2/GptUtils.h | 79 ---- ...android.hardware.boot@1.2-service-gs201.rc | 7 - interfaces/boot/1.2/service.cpp | 50 --- 15 files changed, 1686 deletions(-) delete mode 100644 interfaces/boot/1.0/Android.bp delete mode 100644 interfaces/boot/1.0/BootControl.cpp delete mode 100644 interfaces/boot/1.0/BootControl.h delete mode 100644 interfaces/boot/1.0/GptUtils.cpp delete mode 100644 interfaces/boot/1.0/GptUtils.h delete mode 100644 interfaces/boot/1.0/android.hardware.boot@1.0-service-gs201.rc delete mode 100644 interfaces/boot/1.0/service.cpp delete mode 100644 interfaces/boot/1.2/Android.bp delete mode 100644 interfaces/boot/1.2/BootControl.cpp delete mode 100644 interfaces/boot/1.2/BootControl.h delete mode 100644 interfaces/boot/1.2/DevInfo.h delete mode 100644 interfaces/boot/1.2/GptUtils.cpp delete mode 100644 interfaces/boot/1.2/GptUtils.h delete mode 100644 interfaces/boot/1.2/android.hardware.boot@1.2-service-gs201.rc delete mode 100644 interfaces/boot/1.2/service.cpp diff --git a/interfaces/boot/1.0/Android.bp b/interfaces/boot/1.0/Android.bp deleted file mode 100644 index a5937e78..00000000 --- a/interfaces/boot/1.0/Android.bp +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// 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. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "//device/google/gs201:device_google_gs201_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: [ - "//device/google/gs201:device_google_gs201_license", - ], -} - -cc_binary { - name: "android.hardware.boot@1.0-service-gs201", - defaults: ["hidl_defaults"], - relative_install_path: "hw", - vendor: true, - init_rc: ["android.hardware.boot@1.0-service-gs201.rc"], - srcs: [ - "BootControl.cpp", - "GptUtils.cpp", - "service.cpp" - ], - shared_libs: [ - "libbase", - "liblog", - "libhidlbase", - "libutils", - "libcutils", - "libz", - "android.hardware.boot@1.0", - ], -} - -cc_library { - name: "android.hardware.boot@1.0-impl-gs201", - recovery: true, - srcs: [ - "BootControl.cpp", - "GptUtils.cpp", - ], - relative_install_path: "hw", - shared_libs: [ - "libbase", - "liblog", - "libhidlbase", - "libutils", - "libcutils", - "libz", - "android.hardware.boot@1.0", - ], -} diff --git a/interfaces/boot/1.0/BootControl.cpp b/interfaces/boot/1.0/BootControl.cpp deleted file mode 100644 index 1f155c9d..00000000 --- a/interfaces/boot/1.0/BootControl.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ - -#define LOG_TAG "bootcontrolhal" - -#include "BootControl.h" -#include "GptUtils.h" - -#include -#include -#include - -namespace android { -namespace hardware { -namespace boot { -namespace V1_0 { -namespace implementation { - -namespace { - -#define BOOT_A_PATH "/dev/block/by-name/boot_a" -#define BOOT_B_PATH "/dev/block/by-name/boot_b" - -// slot flags -#define AB_ATTR_PRIORITY_SHIFT 52 -#define AB_ATTR_PRIORITY_MASK (3UL << AB_ATTR_PRIORITY_SHIFT) -#define AB_ATTR_ACTIVE_SHIFT 54 -#define AB_ATTR_ACTIVE (1UL << AB_ATTR_ACTIVE_SHIFT) -#define AB_ATTR_RETRY_COUNT_SHIFT (55) -#define AB_ATTR_RETRY_COUNT_MASK (7UL << AB_ATTR_RETRY_COUNT_SHIFT) -#define AB_ATTR_SUCCESSFUL (1UL << 58) -#define AB_ATTR_UNBOOTABLE (1UL << 59) - -#define AB_ATTR_MAX_PRIORITY 3UL -#define AB_ATTR_MAX_RETRY_COUNT 3UL - -static std::string getDevPath(uint32_t slot) { - char real_path[PATH_MAX]; - - const char *path = slot == 0 ? BOOT_A_PATH : BOOT_B_PATH; - - int ret = readlink(path, real_path, sizeof real_path); - if (ret < 0) { - ALOGE("readlink failed for boot device %s\n", strerror(errno)); - return std::string(); - } - - std::string dp(real_path); - // extract /dev/sda.. part - return dp.substr(0, sizeof "/dev/block/sdX" - 1); -} - -static bool isSlotFlagSet(uint32_t slot, uint64_t flag) { - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - ALOGI("Could not get device path for slot %d\n", slot); - return false; - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - ALOGI("failed to load gpt data\n"); - return false; - } - - gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a"); - if (e == nullptr) { - ALOGI("failed to get gpt entry\n"); - return false; - } - - return !!(e->attr & flag); -} - -static int setSlotFlag(uint32_t slot, uint64_t flag) { - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - ALOGI("Could not get device path for slot %d\n", slot); - return -1; - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - ALOGI("failed to load gpt data\n"); - return -1; - } - - gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a"); - if (e == nullptr) { - ALOGI("failed to get gpt entry\n"); - return -1; - } - - e->attr |= flag; - gpt.Sync(); - - return 0; -} - -} - -// Methods from ::android::hardware::boot::V1_0::IBootControl follow. -Return BootControl::getNumberSlots() { - uint32_t slots = 0; - - if (access(BOOT_A_PATH, F_OK) == 0) - slots++; - - if (access(BOOT_B_PATH, F_OK) == 0) - slots++; - - return slots; -} - -Return BootControl::getCurrentSlot() { - char suffix[PROPERTY_VALUE_MAX]; - property_get("ro.boot.slot_suffix", suffix, "_a"); - return std::string(suffix) == "_b" ? 1 : 0; -} - -Return BootControl::markBootSuccessful(markBootSuccessful_cb _hidl_cb) { - if (getNumberSlots() == 0) { - // no slots, just return true otherwise Android keeps trying - _hidl_cb({true, ""}); - return Void(); - } - int ret = setSlotFlag(getCurrentSlot(), AB_ATTR_SUCCESSFUL); - ret ? _hidl_cb({false, "Failed to set successfull flag"}) : _hidl_cb({true, ""}); - return Void(); -} - -Return BootControl::setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) { - if (slot >= 2) { - _hidl_cb({false, "Invalid slot"}); - return Void(); - } - - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - _hidl_cb({false, "Could not get device path for slot"}); - return Void(); - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - _hidl_cb({false, "failed to load gpt data"}); - return Void(); - } - - gpt_entry *active_entry = gpt.GetPartitionEntry(slot == 0 ? "boot_a" : "boot_b"); - gpt_entry *inactive_entry = gpt.GetPartitionEntry(slot == 0 ? "boot_b" : "boot_a"); - if (active_entry == nullptr || inactive_entry == nullptr) { - _hidl_cb({false, "failed to get entries for boot partitions"}); - return Void(); - } - - ALOGV("slot active attributes %lx\n", active_entry->attr); - ALOGV("slot inactive attributes %lx\n", inactive_entry->attr); - - char boot_dev[PROPERTY_VALUE_MAX]; - property_get("ro.boot.bootdevice", boot_dev, ""); - if (boot_dev[0] == '\0') { - _hidl_cb({false, "invalid ro.boot.bootdevice prop"}); - return Void(); - } - - std::string boot_lun_path = std::string("/sys/devices/platform/") + - boot_dev + "/pixel/boot_lun_enabled"; - int fd = open(boot_lun_path.c_str(), O_RDWR); - if (fd < 0) { - // Try old path for kernels < 5.4 - // TODO: remove once kernel 4.19 support is deprecated - std::string boot_lun_path = std::string("/sys/devices/platform/") + - boot_dev + "/attributes/boot_lun_enabled"; - fd = open(boot_lun_path.c_str(), O_RDWR); - if (fd < 0) { - _hidl_cb({false, "failed to open ufs attr boot_lun_enabled"}); - return Void(); - } - } - - // update attributes for active and inactive - inactive_entry->attr &= ~AB_ATTR_ACTIVE; - active_entry->attr = AB_ATTR_ACTIVE | (AB_ATTR_MAX_PRIORITY << AB_ATTR_PRIORITY_SHIFT) | - (AB_ATTR_MAX_RETRY_COUNT << AB_ATTR_RETRY_COUNT_SHIFT); - - // - // bBootLunEn - // 0x1 => Boot LU A = enabled, Boot LU B = disable - // 0x2 => Boot LU A = disable, Boot LU B = enabled - // - int ret = android::base::WriteStringToFd(slot == 0 ? "1" : "2", fd); - close(fd); - if (ret < 0) { - _hidl_cb({false, "faied to write boot_lun_enabled attribute"}); - return Void(); - } - - _hidl_cb({true, ""}); - return Void(); -} - -Return BootControl::setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) { - if (slot >= 2) { - _hidl_cb({false, "Invalid slot"}); - return Void(); - } - - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - _hidl_cb({false, "Could not get device path for slot"}); - return Void(); - } - - GptUtils gpt(dev_path); - gpt.Load(); - - gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a"); - e->attr |= AB_ATTR_UNBOOTABLE; - - gpt.Sync(); - - _hidl_cb({true, ""}); - return Void(); -} - -Return<::android::hardware::boot::V1_0::BoolResult> BootControl::isSlotBootable(uint32_t slot) { - if (getNumberSlots() == 0) - return BoolResult::FALSE; - if (slot >= getNumberSlots()) - return BoolResult::INVALID_SLOT; - return isSlotFlagSet(slot, AB_ATTR_UNBOOTABLE) ? BoolResult::FALSE : BoolResult::TRUE; -} - -Return<::android::hardware::boot::V1_0::BoolResult> BootControl::isSlotMarkedSuccessful(uint32_t slot) { - if (getNumberSlots() == 0) { - // just return true so that we don't we another call trying to mark it as successful - // when there is no slots - return BoolResult::TRUE; - } - if (slot >= getNumberSlots()) - return BoolResult::INVALID_SLOT; - return isSlotFlagSet(slot, AB_ATTR_SUCCESSFUL) ? BoolResult::TRUE : BoolResult::FALSE; -} - -Return BootControl::getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) { - _hidl_cb(slot == 0 ? "_a" : slot == 1 ? "_b" : ""); - return Void(); -} - -extern "C" IBootControl* HIDL_FETCH_IBootControl(const char*) { - return new BootControl(); -} - -} // namespace implementation -} // namespace V1_0 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.0/BootControl.h b/interfaces/boot/1.0/BootControl.h deleted file mode 100644 index eb81cb07..00000000 --- a/interfaces/boot/1.0/BootControl.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ - -#pragma once - -#include -#include -#include - -namespace android { -namespace hardware { -namespace boot { -namespace V1_0 { -namespace implementation { - -using ::android::hardware::hidl_array; -using ::android::hardware::hidl_memory; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; -using ::android::hardware::Void; -using ::android::sp; - -struct BootControl : public IBootControl { - // Methods from ::android::hardware::boot::V1_0::IBootControl follow. - Return getNumberSlots() override; - Return getCurrentSlot() override; - Return markBootSuccessful(markBootSuccessful_cb _hidl_cb) override; - Return setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) override; - Return setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) override; - Return<::android::hardware::boot::V1_0::BoolResult> isSlotBootable(uint32_t slot) override; - Return<::android::hardware::boot::V1_0::BoolResult> isSlotMarkedSuccessful(uint32_t slot) override; - Return getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) override; - - // Methods from ::android::hidl::base::V1_0::IBase follow. - -}; - -// FIXME: most likely delete, this is only for passthrough implementations -extern "C" IBootControl* HIDL_FETCH_IBootControl(const char* name); - -} // namespace implementation -} // namespace V1_0 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.0/GptUtils.cpp b/interfaces/boot/1.0/GptUtils.cpp deleted file mode 100644 index f8936175..00000000 --- a/interfaces/boot/1.0/GptUtils.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ - -#define LOG_TAG "bootcontrolhal" - -#include "GptUtils.h" - -#include -#include -#include -#include -#include - -namespace android { -namespace hardware { -namespace boot { -namespace V1_0 { -namespace implementation { - -namespace { - -static int ValidateGptHeader(gpt_header *gpt) -{ - if (gpt->signature != GPT_SIGNATURE) { - ALOGE("invalid gpt signature 0x%lx\n", gpt->signature); - return -1; - } - - if (gpt->header_size != sizeof(gpt_header)) { - ALOGE("invalid gpt header size %u\n", gpt->header_size); - return -1; - } - - if (gpt->entry_size != sizeof(gpt_entry)) { - ALOGE("invalid gpt entry size %u\n", gpt->entry_size); - return -1; - } - - return 0; -} - -} - -GptUtils::GptUtils(const std::string dev_path) : dev_path(dev_path), fd(0) {} - -int GptUtils::Load(void) -{ - fd = open(dev_path.c_str(), O_RDWR); - if (fd < 0) { - ALOGE("failed to open block dev %s, %d\n", dev_path.c_str(), errno); - return -1; - } - - int ret = ioctl(fd, BLKSSZGET, &block_size); - if (ret < 0) { - ALOGE("failed to get block size %d\n", errno); - return -1; - } - - // read primary header - lseek64(fd, block_size, SEEK_SET); - ret = read(fd, &gpt_primary, sizeof gpt_primary); - if (ret < 0) { - ALOGE("failed to read gpt primary header %d\n", errno); - return -1; - } - - if (ValidateGptHeader(&gpt_primary)) { - ALOGE("error validating gpt header\n"); - return -1; - } - - // read partition entries - entry_array.resize(gpt_primary.entry_count); - uint32_t entries_size = gpt_primary.entry_size * gpt_primary.entry_count; - lseek64(fd, block_size * gpt_primary.start_lba, SEEK_SET); - ret = read(fd, entry_array.data(), entries_size); - if (ret < 0) { - ALOGE("failed to read gpt partition entries %d\n", errno); - return -1; - } - - // read gpt back header - lseek64(fd, block_size * gpt_primary.backup_lba, SEEK_SET); - ret = read(fd, &gpt_backup, sizeof gpt_backup); - if (ret < 0) { - ALOGE("failed to read gpt backup header %d\n", errno); - return -1; - } - - if (ValidateGptHeader(&gpt_backup)) { - ALOGW("error validating gpt backup\n"); // just warn about it, not fail - } - - // Create map - auto get_name = [](const uint16_t *efi_name) { - char name[37] = {}; - for (int i = 0; efi_name[i] && i < sizeof name - 1; ++i) - name[i] = efi_name[i]; - return std::string(name); - }; - - for (auto const &e: entry_array) { - if (e.name[0] == 0) - break; // stop at the first partition with no name - std::string s = get_name(e.name); - entries[s] = const_cast(&e); - } - - return 0; -} - -gpt_entry *GptUtils::GetPartitionEntry(std::string name) -{ - return entries.find(name) != entries.end() ? entries[name] : nullptr; -} - -int GptUtils::Sync(void) -{ - if (!fd) - return -1; - - // calculate crc and check if we need to update gpt - gpt_primary.entries_crc32 = crc32(0, reinterpret_cast(entry_array.data()), - entry_array.size() * sizeof(gpt_entry)); - - // save old crc - uint32_t crc = gpt_primary.crc32; - gpt_primary.crc32 = 0; - - gpt_primary.crc32 = crc32(0, reinterpret_cast(&gpt_primary), sizeof gpt_primary); - if (crc == gpt_primary.crc32) - return 0; // nothing to do (no changes) - - ALOGI("updating GPT\n"); - - lseek64(fd, block_size * gpt_primary.current_lba, SEEK_SET); - int ret = write(fd, &gpt_primary, sizeof gpt_primary); - if (ret < 0) { - ALOGE("failed to write gpt primary header %d\n", errno); - return -1; - } - - lseek64(fd, block_size * gpt_primary.start_lba, SEEK_SET); - ret = write(fd, entry_array.data(), entry_array.size() * sizeof(gpt_entry)); - if (ret < 0) { - ALOGE("failed to write gpt partition entries %d\n", errno); - return -1; - } - - //update GPT backup entries and backup - lseek64(fd, block_size * gpt_backup.start_lba, SEEK_SET); - ret = write(fd, entry_array.data(), entry_array.size() * sizeof(gpt_entry)); - if (ret < 0) { - ALOGE("failed to write gpt backup partition entries %d\n", errno); - return -1; - } - - gpt_backup.entries_crc32 = gpt_primary.entries_crc32; - gpt_backup.crc32 = 0; - gpt_backup.crc32 = crc32(0, reinterpret_cast(&gpt_backup), sizeof gpt_backup); - lseek64(fd, block_size * gpt_primary.backup_lba, SEEK_SET); - ret = write(fd, &gpt_backup, sizeof gpt_backup); - if (ret < 0) { - ALOGE("failed to write gpt backup header %d\n", errno); - return -1; - } - - fsync(fd); - - return 0; -} - -GptUtils::~GptUtils() -{ - if (fd) { - Sync(); - close(fd); - } -} - -} // namespace implementation -} // namespace V1_0 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.0/GptUtils.h b/interfaces/boot/1.0/GptUtils.h deleted file mode 100644 index d969d9d8..00000000 --- a/interfaces/boot/1.0/GptUtils.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ - -#pragma once - -#include -#include -#include - -namespace android { -namespace hardware { -namespace boot { -namespace V1_0 { -namespace implementation { - -#define GPT_SIGNATURE 0x5452415020494645UL - -typedef struct { - uint8_t type_guid[16]; - uint8_t guid[16]; - uint64_t first_lba; - uint64_t last_lba; - uint64_t attr; - uint16_t name[36]; -} __attribute__((packed)) gpt_entry; - -typedef struct { - uint64_t signature; - uint32_t revision; - uint32_t header_size; - uint32_t crc32; - uint32_t reserved; - uint64_t current_lba; - uint64_t backup_lba; - uint64_t first_usable_lba; - uint64_t last_usable_lba; - uint8_t disk_guid[16]; - uint64_t start_lba; - uint32_t entry_count; - uint32_t entry_size; - uint32_t entries_crc32; -} __attribute__((packed)) gpt_header; - -class GptUtils { - public: - GptUtils(const std::string dev_path); - int Load(void); - gpt_entry *GetPartitionEntry(std::string name); - int Sync(void); - ~GptUtils(); - - private: - std::string dev_path; - int fd; - uint32_t block_size; - gpt_header gpt_primary; - gpt_header gpt_backup; - std::vector entry_array; - std::mapentries; -}; - -} // namespace implementation -} // namespace V1_0 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.0/android.hardware.boot@1.0-service-gs201.rc b/interfaces/boot/1.0/android.hardware.boot@1.0-service-gs201.rc deleted file mode 100644 index 7a7849fd..00000000 --- a/interfaces/boot/1.0/android.hardware.boot@1.0-service-gs201.rc +++ /dev/null @@ -1,4 +0,0 @@ -service vendor.boot-hal-1-0 /vendor/bin/hw/android.hardware.boot@1.0-service-gs201 - class early_hal - user root - group root diff --git a/interfaces/boot/1.0/service.cpp b/interfaces/boot/1.0/service.cpp deleted file mode 100644 index 9dcd78cc..00000000 --- a/interfaces/boot/1.0/service.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ -#define LOG_TAG "android.hardware.boot@1.0-service" - -#include -#include -#include -#include -#include "BootControl.h" - -using ::android::status_t; - -using ::android::hardware::boot::V1_0::IBootControl; - -using ::android::hardware::boot::V1_0::implementation::BootControl; - -int main (int /* argc */, char * /* argv */ []) { - // This function must be called before you join to ensure the proper - // number of threads are created. The threadpool will never exceed - // size one because of this call. - ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/); - - ::android::sp bootctrl = new BootControl(); - const status_t status = bootctrl->registerAsService(); - if (status != ::android::OK) { - return 1; // or handle error - } - - // Adds this thread to the threadpool, resulting in one total - // thread in the threadpool. We could also do other things, but - // would have to specify 'false' to willJoin in configureRpcThreadpool. - ::android::hardware::joinRpcThreadpool(); - return 1; // joinRpcThreadpool should never return -} diff --git a/interfaces/boot/1.2/Android.bp b/interfaces/boot/1.2/Android.bp deleted file mode 100644 index a9fb7f49..00000000 --- a/interfaces/boot/1.2/Android.bp +++ /dev/null @@ -1,81 +0,0 @@ -// -// Copyright (C) 2020 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// 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. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "//device/google/gs201:device_google_gs201_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: [ - "//device/google/gs201:device_google_gs201_license", - ], -} - -cc_binary { - name: "android.hardware.boot@1.2-service-gs201", - defaults: ["hidl_defaults"], - relative_install_path: "hw", - vendor: true, - init_rc: ["android.hardware.boot@1.2-service-gs201.rc"], - srcs: [ - "BootControl.cpp", - "GptUtils.cpp", - "service.cpp" - ], - shared_libs: [ - "libbase", - "liblog", - "libhidlbase", - "libutils", - "libcutils", - "libz", - "android.hardware.boot@1.0", - "android.hardware.boot@1.1", - "android.hardware.boot@1.2", - ], - static_libs: [ - "libboot_control", - "libbootloader_message_vendor", - "libfstab", - ], -} - -cc_library { - name: "android.hardware.boot@1.2-impl-gs201", - stem: "android.hardware.boot@1.0-impl-1.2-impl-gs201", - recovery: true, - srcs: [ - "BootControl.cpp", - "GptUtils.cpp", - ], - relative_install_path: "hw", - shared_libs: [ - "libbase", - "liblog", - "libhidlbase", - "libutils", - "libcutils", - "libz", - "android.hardware.boot@1.0", - "android.hardware.boot@1.1", - "android.hardware.boot@1.2", - ], - static_libs: [ - "libboot_control", - "libbootloader_message_vendor", - "libfstab", - ], -} diff --git a/interfaces/boot/1.2/BootControl.cpp b/interfaces/boot/1.2/BootControl.cpp deleted file mode 100644 index a28be05a..00000000 --- a/interfaces/boot/1.2/BootControl.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ - -#define LOG_TAG "bootcontrolhal" - -#include "BootControl.h" - -#include -#include -#include -#include -#include -#include - -#include "DevInfo.h" -#include "GptUtils.h" - -namespace android { -namespace hardware { -namespace boot { -namespace V1_2 { -namespace implementation { - -using android::bootable::GetMiscVirtualAbMergeStatus; -using android::bootable::InitMiscVirtualAbMessageIfNeeded; -using android::bootable::SetMiscVirtualAbMergeStatus; -using android::hardware::boot::V1_0::BoolResult; -using android::hardware::boot::V1_0::CommandResult; -using android::hardware::boot::V1_1::MergeStatus; - -namespace { - -// clang-format off - -#define BOOT_A_PATH "/dev/block/by-name/boot_a" -#define BOOT_B_PATH "/dev/block/by-name/boot_b" -#define DEVINFO_PATH "/dev/block/by-name/devinfo" - -// slot flags -#define AB_ATTR_PRIORITY_SHIFT 52 -#define AB_ATTR_PRIORITY_MASK (3UL << AB_ATTR_PRIORITY_SHIFT) -#define AB_ATTR_ACTIVE_SHIFT 54 -#define AB_ATTR_ACTIVE (1UL << AB_ATTR_ACTIVE_SHIFT) -#define AB_ATTR_RETRY_COUNT_SHIFT (55) -#define AB_ATTR_RETRY_COUNT_MASK (7UL << AB_ATTR_RETRY_COUNT_SHIFT) -#define AB_ATTR_SUCCESSFUL (1UL << 58) -#define AB_ATTR_UNBOOTABLE (1UL << 59) - -#define AB_ATTR_MAX_PRIORITY 3UL -#define AB_ATTR_MAX_RETRY_COUNT 3UL - -// clang-format on - -static std::string getDevPath(uint32_t slot) { - char real_path[PATH_MAX]; - - const char *path = slot == 0 ? BOOT_A_PATH : BOOT_B_PATH; - - int ret = readlink(path, real_path, sizeof real_path); - if (ret < 0) { - ALOGE("readlink failed for boot device %s\n", strerror(errno)); - return std::string(); - } - - std::string dp(real_path); - // extract /dev/sda.. part - return dp.substr(0, sizeof "/dev/block/sdX" - 1); -} - -static bool isSlotFlagSet(uint32_t slot, uint64_t flag) { - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - ALOGI("Could not get device path for slot %d\n", slot); - return false; - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - ALOGI("failed to load gpt data\n"); - return false; - } - - gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a"); - if (e == nullptr) { - ALOGI("failed to get gpt entry\n"); - return false; - } - - return !!(e->attr & flag); -} - -static bool setSlotFlag(uint32_t slot, uint64_t flag) { - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - ALOGI("Could not get device path for slot %d\n", slot); - return false; - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - ALOGI("failed to load gpt data\n"); - return false; - } - - gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a"); - if (e == nullptr) { - ALOGI("failed to get gpt entry\n"); - return false; - } - - e->attr |= flag; - gpt.Sync(); - - return true; -} - -static bool is_devinfo_valid; -static bool is_devinfo_initialized; -static std::mutex devinfo_lock; -static devinfo_t devinfo; - -static bool isDevInfoValid() { - const std::lock_guard lock(devinfo_lock); - - if (is_devinfo_initialized) { - return is_devinfo_valid; - } - - is_devinfo_initialized = true; - - android::base::unique_fd fd(open(DEVINFO_PATH, O_RDONLY)); - android::base::ReadFully(fd, &devinfo, sizeof devinfo); - - if (devinfo.magic != DEVINFO_MAGIC) { - return is_devinfo_valid; - } - - uint32_t version = ((uint32_t)devinfo.ver_major << 16) | devinfo.ver_minor; - // only version 3.3+ supports A/B data - if (version >= 0x0003'0003) { - is_devinfo_valid = true; - } - - return is_devinfo_valid; -} - -static bool DevInfoSync() { - if (!isDevInfoValid()) { - return false; - } - - android::base::unique_fd fd(open(DEVINFO_PATH, O_WRONLY | O_DSYNC)); - return android::base::WriteFully(fd, &devinfo, sizeof devinfo); -} - -static void DevInfoInitSlot(devinfo_ab_slot_data_t &slot_data) { - slot_data.retry_count = AB_ATTR_MAX_RETRY_COUNT; - slot_data.unbootable = 0; - slot_data.successful = 0; - slot_data.active = 1; - slot_data.fastboot_ok = 0; -} - -} // namespace - -// Methods from ::android::hardware::boot::V1_0::IBootControl follow. -Return BootControl::getNumberSlots() { - uint32_t slots = 0; - - if (access(BOOT_A_PATH, F_OK) == 0) - slots++; - - if (access(BOOT_B_PATH, F_OK) == 0) - slots++; - - return slots; -} - -Return BootControl::getCurrentSlot() { - char suffix[PROPERTY_VALUE_MAX]; - property_get("ro.boot.slot_suffix", suffix, "_a"); - return std::string(suffix) == "_b" ? 1 : 0; -} - -Return BootControl::markBootSuccessful(markBootSuccessful_cb _hidl_cb) { - if (getNumberSlots() == 0) { - // no slots, just return true otherwise Android keeps trying - _hidl_cb({true, ""}); - return Void(); - } - - bool ret; - if (isDevInfoValid()) { - auto const slot = getCurrentSlot(); - devinfo.ab_data.slots[slot].successful = 1; - ret = DevInfoSync(); - } else { - ret = setSlotFlag(getCurrentSlot(), AB_ATTR_SUCCESSFUL); - } - - !ret ? _hidl_cb({false, "Failed to set successful flag"}) : _hidl_cb({true, ""}); - return Void(); -} - -Return BootControl::setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) { - if (slot >= 2) { - _hidl_cb({false, "Invalid slot"}); - return Void(); - } - - if (isDevInfoValid()) { - auto &active_slot_data = devinfo.ab_data.slots[slot]; - auto &inactive_slot_data = devinfo.ab_data.slots[!slot]; - - inactive_slot_data.active = 0; - DevInfoInitSlot(active_slot_data); - - if (!DevInfoSync()) { - _hidl_cb({false, "Could not update DevInfo data"}); - return Void(); - } - } else { - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - _hidl_cb({false, "Could not get device path for slot"}); - return Void(); - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - _hidl_cb({false, "failed to load gpt data"}); - return Void(); - } - - gpt_entry *active_entry = gpt.GetPartitionEntry(slot == 0 ? "boot_a" : "boot_b"); - gpt_entry *inactive_entry = gpt.GetPartitionEntry(slot == 0 ? "boot_b" : "boot_a"); - if (active_entry == nullptr || inactive_entry == nullptr) { - _hidl_cb({false, "failed to get entries for boot partitions"}); - return Void(); - } - - ALOGV("slot active attributes %lx\n", active_entry->attr); - ALOGV("slot inactive attributes %lx\n", inactive_entry->attr); - - // update attributes for active and inactive - inactive_entry->attr &= ~AB_ATTR_ACTIVE; - active_entry->attr = AB_ATTR_ACTIVE | (AB_ATTR_MAX_PRIORITY << AB_ATTR_PRIORITY_SHIFT) | - (AB_ATTR_MAX_RETRY_COUNT << AB_ATTR_RETRY_COUNT_SHIFT); - } - - char boot_dev[PROPERTY_VALUE_MAX]; - property_get("ro.boot.bootdevice", boot_dev, ""); - if (boot_dev[0] == '\0') { - _hidl_cb({false, "invalid ro.boot.bootdevice prop"}); - return Void(); - } - - std::string boot_lun_path = - std::string("/sys/devices/platform/") + boot_dev + "/pixel/boot_lun_enabled"; - int fd = open(boot_lun_path.c_str(), O_RDWR | O_DSYNC); - if (fd < 0) { - // Try old path for kernels < 5.4 - // TODO: remove once kernel 4.19 support is deprecated - std::string boot_lun_path = - std::string("/sys/devices/platform/") + boot_dev + "/attributes/boot_lun_enabled"; - fd = open(boot_lun_path.c_str(), O_RDWR | O_DSYNC); - if (fd < 0) { - _hidl_cb({false, "failed to open ufs attr boot_lun_enabled"}); - return Void(); - } - } - - // - // bBootLunEn - // 0x1 => Boot LU A = enabled, Boot LU B = disable - // 0x2 => Boot LU A = disable, Boot LU B = enabled - // - int ret = android::base::WriteStringToFd(slot == 0 ? "1" : "2", fd); - close(fd); - if (ret < 0) { - _hidl_cb({false, "faied to write boot_lun_enabled attribute"}); - return Void(); - } - - _hidl_cb({true, ""}); - return Void(); -} - -Return BootControl::setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) { - if (slot >= 2) { - _hidl_cb({false, "Invalid slot"}); - return Void(); - } - - if (isDevInfoValid()) { - auto &slot_data = devinfo.ab_data.slots[slot]; - slot_data.unbootable = 1; - if (!DevInfoSync()) { - _hidl_cb({false, "Could not update DevInfo data"}); - return Void(); - } - } else { - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - _hidl_cb({false, "Could not get device path for slot"}); - return Void(); - } - - GptUtils gpt(dev_path); - gpt.Load(); - - gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a"); - e->attr |= AB_ATTR_UNBOOTABLE; - - gpt.Sync(); - } - - _hidl_cb({true, ""}); - return Void(); -} - -Return<::android::hardware::boot::V1_0::BoolResult> BootControl::isSlotBootable(uint32_t slot) { - if (getNumberSlots() == 0) - return BoolResult::FALSE; - if (slot >= getNumberSlots()) - return BoolResult::INVALID_SLOT; - - bool unbootable; - if (isDevInfoValid()) { - auto &slot_data = devinfo.ab_data.slots[slot]; - unbootable = !!slot_data.unbootable; - } else { - unbootable = isSlotFlagSet(slot, AB_ATTR_UNBOOTABLE); - } - - return unbootable ? BoolResult::FALSE : BoolResult::TRUE; -} - -Return<::android::hardware::boot::V1_0::BoolResult> BootControl::isSlotMarkedSuccessful( - uint32_t slot) { - if (getNumberSlots() == 0) { - // just return true so that we don't we another call trying to mark it as successful - // when there is no slots - return BoolResult::TRUE; - } - if (slot >= getNumberSlots()) - return BoolResult::INVALID_SLOT; - - bool successful; - if (isDevInfoValid()) { - auto &slot_data = devinfo.ab_data.slots[slot]; - successful = !!slot_data.successful; - } else { - successful = isSlotFlagSet(slot, AB_ATTR_SUCCESSFUL); - } - - return successful ? BoolResult::TRUE : BoolResult::FALSE; -} - -Return BootControl::getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) { - _hidl_cb(slot == 0 ? "_a" : slot == 1 ? "_b" : ""); - return Void(); -} - -// Methods from ::android::hardware::boot::V1_1::IBootControl follow. -bool BootControl::Init() { - return InitMiscVirtualAbMessageIfNeeded(); -} - -Return BootControl::setSnapshotMergeStatus( - ::android::hardware::boot::V1_1::MergeStatus status) { - return SetMiscVirtualAbMergeStatus(getCurrentSlot(), status); -} - -Return<::android::hardware::boot::V1_1::MergeStatus> BootControl::getSnapshotMergeStatus() { - MergeStatus status; - if (!GetMiscVirtualAbMergeStatus(getCurrentSlot(), &status)) { - return MergeStatus::UNKNOWN; - } - return status; -} - -// Methods from ::android::hardware::boot::V1_2::IBootControl follow. -Return BootControl::getActiveBootSlot() { - if (getNumberSlots() == 0) - return 0; - - if (isDevInfoValid()) - return devinfo.ab_data.slots[1].active ? 1 : 0; - return isSlotFlagSet(1, AB_ATTR_ACTIVE) ? 1 : 0; -} - -// Methods from ::android::hidl::base::V1_0::IBase follow. - -IBootControl *HIDL_FETCH_IBootControl(const char * /* name */) { - auto module = new BootControl(); - - module->Init(); - - return module; -} - -} // namespace implementation -} // namespace V1_2 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.2/BootControl.h b/interfaces/boot/1.2/BootControl.h deleted file mode 100644 index 17b5f0fb..00000000 --- a/interfaces/boot/1.2/BootControl.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ - -#pragma once - -#include -#include -#include - -namespace android { -namespace hardware { -namespace boot { -namespace V1_2 { -namespace implementation { - -using ::android::sp; -using ::android::hardware::hidl_array; -using ::android::hardware::hidl_memory; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; -using ::android::hardware::Void; - -struct BootControl : public IBootControl { - bool Init(); - - // Methods from ::android::hardware::boot::V1_0::IBootControl follow. - Return getNumberSlots() override; - Return getCurrentSlot() override; - Return markBootSuccessful(markBootSuccessful_cb _hidl_cb) override; - Return setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) override; - Return setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) override; - Return<::android::hardware::boot::V1_0::BoolResult> isSlotBootable(uint32_t slot) override; - Return<::android::hardware::boot::V1_0::BoolResult> isSlotMarkedSuccessful( - uint32_t slot) override; - Return getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) override; - - // Methods from ::android::hardware::boot::V1_1::IBootControl follow. - Return setSnapshotMergeStatus( - ::android::hardware::boot::V1_1::MergeStatus status) override; - Return<::android::hardware::boot::V1_1::MergeStatus> getSnapshotMergeStatus() override; - - // Methods from ::android::hardware::boot::V1_2::IBootControl follow. - Return getActiveBootSlot() override; - - // Methods from ::android::hidl::base::V1_0::IBase follow. -}; - -// FIXME: most likely delete, this is only for passthrough implementations -extern "C" IBootControl *HIDL_FETCH_IBootControl(const char *name); - -} // namespace implementation -} // namespace V1_2 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.2/DevInfo.h b/interfaces/boot/1.2/DevInfo.h deleted file mode 100644 index a09a83a2..00000000 --- a/interfaces/boot/1.2/DevInfo.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ - -#pragma once - -namespace android { -namespace hardware { -namespace boot { -namespace V1_2 { -namespace implementation { - -// -// definitions taken from ABL code -// - -constexpr uint32_t DEVINFO_MAGIC = 0x49564544; -constexpr size_t DEVINFO_AB_SLOT_COUNT = 2; - -struct devinfo_ab_slot_data_t { - uint8_t retry_count; - uint8_t unbootable : 1; - uint8_t successful : 1; - uint8_t active : 1; - uint8_t fastboot_ok : 1; - uint8_t : 4; - uint8_t unused[2]; -} __attribute__((packed)); - -typedef struct { - devinfo_ab_slot_data_t slots[DEVINFO_AB_SLOT_COUNT]; -} __attribute__((packed)) devinfo_ab_data_t; - -struct devinfo_t { - uint32_t magic; - uint16_t ver_major; - uint16_t ver_minor; - uint8_t unused[40]; - devinfo_ab_data_t ab_data; - uint8_t unused1[72]; // use remaining up to complete 128 bytes -} __attribute__((packed)); - -static_assert(sizeof(devinfo_t) == 128, "invalid devinfo struct size"); - -} // namespace implementation -} // namespace V1_2 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.2/GptUtils.cpp b/interfaces/boot/1.2/GptUtils.cpp deleted file mode 100644 index 25088e79..00000000 --- a/interfaces/boot/1.2/GptUtils.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ - -#define LOG_TAG "bootcontrolhal" - -#include "GptUtils.h" - -#include -#include -#include -#include -#include - -namespace android { -namespace hardware { -namespace boot { -namespace V1_2 { -namespace implementation { - -namespace { - -static int ValidateGptHeader(gpt_header *gpt) { - if (gpt->signature != GPT_SIGNATURE) { - ALOGE("invalid gpt signature 0x%lx\n", gpt->signature); - return -1; - } - - if (gpt->header_size != sizeof(gpt_header)) { - ALOGE("invalid gpt header size %u\n", gpt->header_size); - return -1; - } - - if (gpt->entry_size != sizeof(gpt_entry)) { - ALOGE("invalid gpt entry size %u\n", gpt->entry_size); - return -1; - } - - return 0; -} - -} // namespace - -GptUtils::GptUtils(const std::string dev_path) : dev_path(dev_path), fd(0) {} - -int GptUtils::Load(void) { - fd = open(dev_path.c_str(), O_RDWR); - if (fd < 0) { - ALOGE("failed to open block dev %s, %d\n", dev_path.c_str(), errno); - return -1; - } - - int ret = ioctl(fd, BLKSSZGET, &block_size); - if (ret < 0) { - ALOGE("failed to get block size %d\n", errno); - return -1; - } - - // read primary header - lseek64(fd, block_size, SEEK_SET); - ret = read(fd, &gpt_primary, sizeof gpt_primary); - if (ret < 0) { - ALOGE("failed to read gpt primary header %d\n", errno); - return -1; - } - - if (ValidateGptHeader(&gpt_primary)) { - ALOGE("error validating gpt header\n"); - return -1; - } - - // read partition entries - entry_array.resize(gpt_primary.entry_count); - uint32_t entries_size = gpt_primary.entry_size * gpt_primary.entry_count; - lseek64(fd, block_size * gpt_primary.start_lba, SEEK_SET); - ret = read(fd, entry_array.data(), entries_size); - if (ret < 0) { - ALOGE("failed to read gpt partition entries %d\n", errno); - return -1; - } - - // read gpt back header - lseek64(fd, block_size * gpt_primary.backup_lba, SEEK_SET); - ret = read(fd, &gpt_backup, sizeof gpt_backup); - if (ret < 0) { - ALOGE("failed to read gpt backup header %d\n", errno); - return -1; - } - - if (ValidateGptHeader(&gpt_backup)) { - ALOGW("error validating gpt backup\n"); // just warn about it, not fail - } - - // Create map - auto get_name = [](const uint16_t *efi_name) { - char name[37] = {}; - for (int i = 0; efi_name[i] && i < sizeof name - 1; ++i) name[i] = efi_name[i]; - return std::string(name); - }; - - for (auto const &e : entry_array) { - if (e.name[0] == 0) - break; // stop at the first partition with no name - std::string s = get_name(e.name); - entries[s] = const_cast(&e); - } - - return 0; -} - -gpt_entry *GptUtils::GetPartitionEntry(std::string name) { - return entries.find(name) != entries.end() ? entries[name] : nullptr; -} - -int GptUtils::Sync(void) { - if (!fd) - return -1; - - // calculate crc and check if we need to update gpt - gpt_primary.entries_crc32 = crc32(0, reinterpret_cast(entry_array.data()), - entry_array.size() * sizeof(gpt_entry)); - - // save old crc - uint32_t crc = gpt_primary.crc32; - gpt_primary.crc32 = 0; - - gpt_primary.crc32 = crc32(0, reinterpret_cast(&gpt_primary), sizeof gpt_primary); - if (crc == gpt_primary.crc32) - return 0; // nothing to do (no changes) - - ALOGI("updating GPT\n"); - - lseek64(fd, block_size * gpt_primary.current_lba, SEEK_SET); - int ret = write(fd, &gpt_primary, sizeof gpt_primary); - if (ret < 0) { - ALOGE("failed to write gpt primary header %d\n", errno); - return -1; - } - - lseek64(fd, block_size * gpt_primary.start_lba, SEEK_SET); - ret = write(fd, entry_array.data(), entry_array.size() * sizeof(gpt_entry)); - if (ret < 0) { - ALOGE("failed to write gpt partition entries %d\n", errno); - return -1; - } - - // update GPT backup entries and backup - lseek64(fd, block_size * gpt_backup.start_lba, SEEK_SET); - ret = write(fd, entry_array.data(), entry_array.size() * sizeof(gpt_entry)); - if (ret < 0) { - ALOGE("failed to write gpt backup partition entries %d\n", errno); - return -1; - } - - gpt_backup.entries_crc32 = gpt_primary.entries_crc32; - gpt_backup.crc32 = 0; - gpt_backup.crc32 = crc32(0, reinterpret_cast(&gpt_backup), sizeof gpt_backup); - lseek64(fd, block_size * gpt_primary.backup_lba, SEEK_SET); - ret = write(fd, &gpt_backup, sizeof gpt_backup); - if (ret < 0) { - ALOGE("failed to write gpt backup header %d\n", errno); - return -1; - } - - fsync(fd); - - return 0; -} - -GptUtils::~GptUtils() { - if (fd) { - Sync(); - close(fd); - } -} - -} // namespace implementation -} // namespace V1_2 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.2/GptUtils.h b/interfaces/boot/1.2/GptUtils.h deleted file mode 100644 index a2bed334..00000000 --- a/interfaces/boot/1.2/GptUtils.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ - -#pragma once - -#include -#include -#include - -namespace android { -namespace hardware { -namespace boot { -namespace V1_2 { -namespace implementation { - -#define GPT_SIGNATURE 0x5452415020494645UL - -typedef struct { - uint8_t type_guid[16]; - uint8_t guid[16]; - uint64_t first_lba; - uint64_t last_lba; - uint64_t attr; - uint16_t name[36]; -} __attribute__((packed)) gpt_entry; - -typedef struct { - uint64_t signature; - uint32_t revision; - uint32_t header_size; - uint32_t crc32; - uint32_t reserved; - uint64_t current_lba; - uint64_t backup_lba; - uint64_t first_usable_lba; - uint64_t last_usable_lba; - uint8_t disk_guid[16]; - uint64_t start_lba; - uint32_t entry_count; - uint32_t entry_size; - uint32_t entries_crc32; -} __attribute__((packed)) gpt_header; - -class GptUtils { - public: - GptUtils(const std::string dev_path); - int Load(void); - gpt_entry *GetPartitionEntry(std::string name); - int Sync(void); - ~GptUtils(); - - private: - std::string dev_path; - int fd; - uint32_t block_size; - gpt_header gpt_primary; - gpt_header gpt_backup; - std::vector entry_array; - std::map entries; -}; - -} // namespace implementation -} // namespace V1_2 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.2/android.hardware.boot@1.2-service-gs201.rc b/interfaces/boot/1.2/android.hardware.boot@1.2-service-gs201.rc deleted file mode 100644 index 3457b5f0..00000000 --- a/interfaces/boot/1.2/android.hardware.boot@1.2-service-gs201.rc +++ /dev/null @@ -1,7 +0,0 @@ -service vendor.boot-hal-1-2 /vendor/bin/hw/android.hardware.boot@1.2-service-gs201 - interface android.hardware.boot@1.0::IBootControl default - interface android.hardware.boot@1.1::IBootControl default - interface android.hardware.boot@1.2::IBootControl default - class early_hal - user root - group root diff --git a/interfaces/boot/1.2/service.cpp b/interfaces/boot/1.2/service.cpp deleted file mode 100644 index f07682e9..00000000 --- a/interfaces/boot/1.2/service.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ - -#define LOG_TAG "android.hardware.boot@1.2-service" - -#include -#include -#include -#include - -#include "BootControl.h" - -using ::android::status_t; - -using ::android::hardware::boot::V1_2::IBootControl; - -using ::android::hardware::boot::V1_2::implementation::BootControl; -// using ::android::hardware::boot::implementation::BootControl; - -int main(int /* argc */, char * /* argv */[]) { - // This function must be called before you join to ensure the proper - // number of threads are created. The threadpool will never exceed - // size one because of this call. - ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/); - - ::android::sp bootctrl = new BootControl(); - const status_t status = bootctrl->registerAsService(); - if (status != ::android::OK) { - return 1; // or handle error - } - - // Adds this thread to the threadpool, resulting in one total - // thread in the threadpool. We could also do other things, but - // would have to specify 'false' to willJoin in configureRpcThreadpool. - ::android::hardware::joinRpcThreadpool(); - return 1; // joinRpcThreadpool should never return -} From 2baf1d63eb96e34fff54b6a8ad50dcaeeed14a88 Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Mon, 27 Nov 2023 17:27:55 +0800 Subject: [PATCH 07/15] gs201: move bootctrl service declaration to gs-common Bug: 265063384 Change-Id: If265211d9b433eef789d0d68df1cae7cc369cfa1 --- device.mk | 5 ----- 1 file changed, 5 deletions(-) diff --git a/device.mk b/device.mk index 4342a53a..41cb5c04 100644 --- a/device.mk +++ b/device.mk @@ -922,11 +922,6 @@ PRODUCT_PACKAGES_DEBUG += \ PRODUCT_PACKAGES += ShannonRcs endif -# Boot Control HAL -PRODUCT_PACKAGES += \ - android.hardware.boot@1.2-impl-gs201 \ - android.hardware.boot@1.2-service-gs201 - # Exynos RIL and telephony # Multi SIM(DSDS) SIM_COUNT := 2 From ca538bb2b4c3d3b812c266773ce7494163c8c975 Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Thu, 9 Nov 2023 21:25:52 +0800 Subject: [PATCH 08/15] gs201: include bootctrl_hidl_1.2.mk from gs-common Bug: 265063384 Change-Id: I2e00ddafe970dcda873da691bd64908f5ef1c0f9 Signed-off-by: Jason Chiu --- device.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/device.mk b/device.mk index 41cb5c04..68bd8793 100644 --- a/device.mk +++ b/device.mk @@ -36,6 +36,7 @@ include device/google/gs-common/widevine/widevine.mk include device/google/gs-common/sota_app/factoryota.mk include device/google/gs-common/misc_writer/misc_writer.mk include device/google/gs-common/gyotaku_app/gyotaku.mk +include device/google/gs-common/bootctrl/bootctrl_hidl_1.2.mk TARGET_BOARD_PLATFORM := gs201 From a9ac5d5869eb22c1e99f81161b711cdf6c7c6270 Mon Sep 17 00:00:00 2001 From: Qian-Hao Huang Date: Tue, 5 Dec 2023 09:36:02 +0000 Subject: [PATCH 09/15] Revert "usb: introduce UsbDataSessionMonitor class" Revert submission 25524752-usbDataSessionMonitor Reason for revert: Test for gs101/gs201 boot blocking issue (b/314904288) Reverted changes: /q/submissionid:25524752-usbDataSessionMonitor Change-Id: I0f762a9ba8345d2963ebfb2d50cb8a7460885221 --- usb/usb/Android.bp | 1 - usb/usb/Usb.cpp | 308 +++++++++++++++++----- usb/usb/Usb.h | 34 ++- usb/usb/UsbDataSessionMonitor.cpp | 420 ------------------------------ usb/usb/UsbDataSessionMonitor.h | 114 -------- 5 files changed, 279 insertions(+), 598 deletions(-) delete mode 100644 usb/usb/UsbDataSessionMonitor.cpp delete mode 100644 usb/usb/UsbDataSessionMonitor.h diff --git a/usb/usb/Android.bp b/usb/usb/Android.bp index 609af179..8fd373b2 100644 --- a/usb/usb/Android.bp +++ b/usb/usb/Android.bp @@ -34,7 +34,6 @@ cc_binary { srcs: [ "service.cpp", "Usb.cpp", - "UsbDataSessionMonitor.cpp", ], shared_libs: [ "libbase", diff --git a/usb/usb/Usb.cpp b/usb/usb/Usb.cpp index 555e6576..224951a1 100644 --- a/usb/usb/Usb.cpp +++ b/usb/usb/Usb.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ #include #include +#include #include #include @@ -55,6 +57,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; @@ -90,22 +95,17 @@ constexpr char kThermalZoneForTempReadSecondary2[] = "qi_therm"; constexpr char kPogoUsbActive[] = "/sys/devices/platform/google,pogo/pogo_usb_active"; constexpr char KPogoMoveDataToUsb[] = "/sys/devices/platform/google,pogo/move_data_to_usb"; constexpr char kPowerSupplyUsbType[] = "/sys/class/power_supply/usb/usb_type"; -constexpr char kUdcUeventRegex[] = - "/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3"; -constexpr char kUdcStatePath[] = - "/sys/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3/state"; -constexpr char kHost1UeventRegex[] = - "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb2/2-0:1.0"; -constexpr char kHost1StatePath[] = "/sys/bus/usb/devices/usb2/2-0:1.0/usb2-port1/state"; -constexpr char kHost2UeventRegex[] = - "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb3/3-0:1.0"; -constexpr char kHost2StatePath[] = "/sys/bus/usb/devices/usb3/3-0:1.0/usb3-port1/state"; -constexpr char kDataRolePath[] = "/sys/devices/platform/11210000.usb/new_data_role"; +constexpr char kUdcState[] = "/sys/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3/state"; +// xhci-hcd-exynos and usb device numbering could vary on different platforms +constexpr char kHostUeventRegex[] = "^(bind|unbind)@(/devices/platform/11210000\\.usb/11210000\\.dwc3/xhci-hcd-exynos\\.[0-9]\\.auto/)usb([0-9])/[0-9]-0:1\\.0"; constexpr int kSamplingIntervalSec = 5; void queryVersionHelper(android::hardware::usb::Usb *usb, std::vector *currentPortStatus); +void queryUsbDataSession(android::hardware::usb::Usb *usb, + std::vector *currentPortStatus); +#define USB_STATE_MAX_LEN 20 #define CTRL_TRANSFER_TIMEOUT_MSEC 1000 #define GL852G_VENDOR_ID 0x05e3 #define GL852G_PRODUCT_ID1 0x0608 @@ -538,20 +538,11 @@ void *usbHostWork(void *param) { return NULL; } -void updatePortStatus(android::hardware::usb::Usb *usb) { - std::vector currentPortStatus; - - queryVersionHelper(usb, ¤tPortStatus); -} - Usb::Usb() : mLock(PTHREAD_MUTEX_INITIALIZER), mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER), mPartnerLock(PTHREAD_MUTEX_INITIALIZER), mPartnerUp(false), - mUsbDataSessionMonitor(kUdcUeventRegex, kUdcStatePath, kHost1UeventRegex, kHost1StatePath, - kHost2UeventRegex, kHost2StatePath, kDataRolePath, - std::bind(&updatePortStatus, this)), mOverheat(ZoneInfo(TemperatureType::USB_PORT, kThermalZoneForTrip, ThrottlingSeverity::CRITICAL), {ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadPrimary, @@ -931,18 +922,6 @@ done: return Status::ERROR; } -void queryUsbDataSession(android::hardware::usb::Usb *usb, - std::vector *currentPortStatus) { - std::vector warnings; - - usb->mUsbDataSessionMonitor.getComplianceWarnings( - (*currentPortStatus)[0].currentDataRole, &warnings); - (*currentPortStatus)[0].complianceWarnings.insert( - (*currentPortStatus)[0].complianceWarnings.end(), - warnings.begin(), - warnings.end()); -} - void queryVersionHelper(android::hardware::usb::Usb *usb, std::vector *currentPortStatus) { Status status; @@ -1038,17 +1017,194 @@ void report_overheat_event(android::hardware::usb::Usb *usb) { } } -struct data { - int uevent_fd; - ::aidl::android::hardware::usb::Usb *usb; -}; +void report_usb_data_session_event(android::hardware::usb::Usb *usb) { + std::vector events; -static void uevent_event(uint32_t /*epevents*/, struct data *payload) { + 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 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 *map; + int fd; + + map = &usb->mEpollEntries; + auto it = map->find(name); + if (it != map->end()) { + ALOGI("epoll unregister %s", name.c_str()); + fd = it->second.payload.fd; + epoll_ctl(usb->mEpollFd, EPOLL_CTL_DEL, fd, NULL); + close(fd); + map->erase(it); + } +} + +static void unregisterEpollEntries(Usb *usb) { + std::map *map; + std::string name; + + map = &usb->mEpollEntries; + for (auto it = map->begin(); it != map->end();) { + name = it->first; + it++; + unregisterEpollEntry(usb, name); + } +} + +static int registerEpollEntry(Usb *usb, std::string name, int fd, int flags, + void (*func)(uint32_t, struct Usb::payload*)) { + std::map *map; + struct Usb::epollEntry *entry; + struct epoll_event ev; + + map = &usb->mEpollEntries; + if (map->find(name) != map->end()) { + ALOGE("%s already registered", name.c_str()); + unregisterEpollEntry(usb, name); + } + + entry = &(*map)[name]; + entry->payload.fd = fd; + entry->payload.name = name; + entry->payload.usb = usb; + entry->cb = std::bind(func, std::placeholders::_1, &entry->payload); + + ev.events = flags; + ev.data.ptr = (void *)&entry->cb; + + if (epoll_ctl(usb->mEpollFd, EPOLL_CTL_ADD, fd, &ev) != 0) { + ALOGE("epoll_ctl failed; errno=%d", errno); + unregisterEpollEntry(usb, name); + return -1; + } + + ALOGI("epoll register %s", name.c_str()); + + return 0; +} + +static int registerEpollEntryByFile(Usb *usb, std::string name, int flags, + void (*func)(uint32_t, struct Usb::payload*)) { + int fd; + + fd = open(name.c_str(), O_RDONLY); + if (fd < 0) { + ALOGE("Cannot open %s", name.c_str()); + return -1; + } + + return registerEpollEntry(usb, name, fd, flags, func); +} + +static void clearUsbDeviceState(struct Usb::usbDeviceState *device) { + 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->states.push_back(state); + device->timestamps.push_back(std::chrono::steady_clock::now()); + + if (!std::strcmp(state, "configured\n")) { + device->portResetCount = 0; + } else if (!std::strcmp(state, "default\n")) { + device->portResetCount++; + } +} + +static void host_event(uint32_t /*epevents*/, struct Usb::payload *payload) { + int n; + char state[USB_STATE_MAX_LEN] = {0}; + struct Usb::usbDeviceState *device; + + lseek(payload->fd, 0, SEEK_SET); + n = read(payload->fd, &state, USB_STATE_MAX_LEN); + + updateUsbDeviceState(&payload->usb->mHostStateMap[payload->name], state); +} + +void queryUsbDataSession(android::hardware::usb::Usb *usb, + std::vector *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; int n; + std::cmatch match; - n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN); + n = uevent_kernel_multicast_recv(payload->fd, msg, UEVENT_MSG_LEN); if (n <= 0) return; if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ @@ -1094,6 +1250,28 @@ static void uevent_event(uint32_t /*epevents*/, struct data *payload) { } else if (!strncmp(cp, kOverheatStatsDev, strlen(kOverheatStatsDev))) { ALOGV("Overheat Cooling device suez update"); report_overheat_event(payload->usb); + } else if (std::regex_match(cp, match, std::regex(kHostUeventRegex))) { + /* + * Matched strings: + * 1st: entire string + * 2nd: uevent action, either "bind" or "unbind" + * 3rd: xhci device path, e.g. devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.4.auto + * 4th: usb device number, e.g. 1 for usb1 + * + * The strings are used to composed usb device state path, e.g. + * /sys/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.4.auto/usb2/2-0:1.0/usb2-port1/state + */ + if (match.size() == 4) { + std::string action = match[1].str(); + std::string id = match[3].str(); + std::string path = "/sys" + match[2].str() + "usb" + id + "/" + + id + "-0:1.0/usb" + id + "-port1/state"; + if (action == "bind") { + registerEpollEntryByFile(payload->usb, path, EPOLLPRI, host_event); + } else if (action == "unbind") { + unregisterEpollEntry(payload->usb, path); + } + } } /* advance to after the next \0 */ while (*cp++) { @@ -1101,37 +1279,46 @@ static void uevent_event(uint32_t /*epevents*/, struct data *payload) { } } +static void udc_event(uint32_t /*epevents*/, struct Usb::payload *payload) { + int n; + char state[USB_STATE_MAX_LEN] = {0}; + + lseek(payload->fd, 0, SEEK_SET); + n = read(payload->fd, &state, USB_STATE_MAX_LEN); + + updateUsbDeviceState(&payload->usb->mDeviceState, state); +} + void *work(void *param) { int epoll_fd, uevent_fd; - struct epoll_event ev; int nevents = 0; - struct data payload; + Usb *usb = (Usb *)param; ALOGE("creating thread"); - uevent_fd = uevent_open_socket(64 * 1024, true); - - if (uevent_fd < 0) { - ALOGE("uevent_init: uevent_open_socket failed\n"); - return NULL; - } - - payload.uevent_fd = uevent_fd; - payload.usb = (::aidl::android::hardware::usb::Usb *)param; - - fcntl(uevent_fd, F_SETFL, O_NONBLOCK); - - ev.events = EPOLLIN; - ev.data.ptr = (void *)uevent_event; - epoll_fd = epoll_create(64); if (epoll_fd == -1) { ALOGE("epoll_create failed; errno=%d", errno); + return NULL; + } + usb->mEpollFd = epoll_fd; + + // Monitor uevent + uevent_fd = uevent_open_socket(64 * 1024, true); + if (uevent_fd < 0) { + ALOGE("uevent_init: uevent_open_socket failed"); + goto error; + } + fcntl(uevent_fd, F_SETFL, O_NONBLOCK); + + if (registerEpollEntry(usb, "uevent", uevent_fd, EPOLLIN, uevent_event)) { + ALOGE("failed to monitor uevent"); goto error; } - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) { - ALOGE("epoll_ctl failed; errno=%d", errno); + // Monitor udc state + if (registerEpollEntryByFile(usb, kUdcState, EPOLLPRI, udc_event)) { + ALOGE("failed to monitor udc state"); goto error; } @@ -1148,14 +1335,15 @@ void *work(void *param) { for (int n = 0; n < nevents; ++n) { if (events[n].data.ptr) - (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events, - &payload); + (*(std::function*)events[n].data.ptr)(events[n].events); } } ALOGI("exiting worker thread"); error: - close(uevent_fd); + unregisterEpollEntries(usb); + + usb->mEpollFd = -1; if (epoll_fd >= 0) close(epoll_fd); diff --git a/usb/usb/Usb.h b/usb/usb/Usb.h index 495a467f..83bae889 100644 --- a/usb/usb/Usb.h +++ b/usb/usb/Usb.h @@ -19,9 +19,9 @@ #include #include #include +#include #include #include -#include #define UEVENT_MSG_LEN 2048 // The type-c stack waits for 4.5 - 5.5 secs before declaring a port non-pd. @@ -88,8 +88,6 @@ struct Usb : public BnUsb { // Variable to signal partner coming back online after type switch bool mPartnerUp; - // Report usb data session event and data incompliance warnings - UsbDataSessionMonitor mUsbDataSessionMonitor; // Usb Overheat object for push suez event UsbOverheatEvent mOverheat; // Temperature when connected @@ -100,6 +98,36 @@ struct Usb : public BnUsb { int mUsbHubVendorCmdValue; int mUsbHubVendorCmdIndex; + // USB device state monitoring + struct usbDeviceState { + // Usb device state raw strings read from sysfs + std::vector states; + // Timestamps of when the usb device states were captured + std::vector timestamps; + int portResetCount; + }; + struct usbDeviceState mDeviceState; + // Map host device path name to usbDeviceState + std::map 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; + struct payload { + int fd; + std::string name; + Usb *usb; + }; + struct epollEntry { + struct payload payload; + std::function cb; + }; + std::map mEpollEntries; + private: pthread_t mPoll; pthread_t mUsbHost; diff --git a/usb/usb/UsbDataSessionMonitor.cpp b/usb/usb/UsbDataSessionMonitor.cpp deleted file mode 100644 index 77defb30..00000000 --- a/usb/usb/UsbDataSessionMonitor.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ - -#define LOG_TAG "android.hardware.usb.aidl-service.UsbDataSessionMonitor" - -#include "UsbDataSessionMonitor.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace usb_flags = android::hardware::usb::flags; - -using aidl::android::frameworks::stats::IStats; -using android::base::ReadFileToString; -using android::hardware::google::pixel::getStatsService; -using android::hardware::google::pixel::reportUsbDataSessionEvent; -using android::hardware::google::pixel::PixelAtoms::VendorUsbDataSessionEvent; -using android::hardware::google::pixel::usb::addEpollFd; -using android::hardware::google::pixel::usb::BuildVendorUsbDataSessionEvent; - -namespace aidl { -namespace android { -namespace hardware { -namespace usb { - -#define UEVENT_MSG_LEN 2048 -#define USB_STATE_MAX_LEN 20 -#define DATA_ROLE_MAX_LEN 10 - -constexpr char kUdcConfigfsPath[] = "/config/usb_gadget/g1/UDC"; -constexpr char kNotAttachedState[] = "not attached\n"; -constexpr char kAttachedState[] = "attached\n"; -constexpr char kPoweredState[] = "powered\n"; -constexpr char kDefaultState[] = "default\n"; -constexpr char kAddressedState[] = "addressed\n"; -constexpr char kConfiguredState[] = "configured\n"; -constexpr char kSuspendedState[] = "suspended\n"; -const std::set kValidStates = {kNotAttachedState, kAttachedState, kPoweredState, - kDefaultState, kAddressedState, kConfiguredState, - kSuspendedState}; - -static int addEpollFile(const int &epollFd, const std::string &filePath, unique_fd &fileFd) { - struct epoll_event ev; - - unique_fd fd(open(filePath.c_str(), O_RDONLY)); - - if (fd.get() == -1) { - ALOGI("Cannot open %s", filePath.c_str()); - return -1; - } - - ev.data.fd = fd.get(); - ev.events = EPOLLPRI; - - if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fd.get(), &ev) != 0) { - ALOGE("epoll_ctl failed; errno=%d", errno); - return -1; - } - - fileFd = std::move(fd); - ALOGI("epoll registered %s", filePath.c_str()); - return 0; -} - -static void removeEpollFile(const int &epollFd, const std::string &filePath, unique_fd &fileFd) { - epoll_ctl(epollFd, EPOLL_CTL_DEL, fileFd.get(), NULL); - fileFd.release(); - - ALOGI("epoll unregistered %s", filePath.c_str()); -} - -UsbDataSessionMonitor::UsbDataSessionMonitor( - const std::string &deviceUeventRegex, const std::string &deviceStatePath, - const std::string &host1UeventRegex, const std::string &host1StatePath, - const std::string &host2UeventRegex, const std::string &host2StatePath, - const std::string &dataRolePath, std::function updatePortStatusCb) { - struct epoll_event ev; - std::string udc; - - unique_fd epollFd(epoll_create(8)); - if (epollFd.get() == -1) { - ALOGE("epoll_create failed; errno=%d", errno); - abort(); - } - - unique_fd ueventFd(uevent_open_socket(64 * 1024, true)); - if (ueventFd.get() == -1) { - ALOGE("uevent_open_socket failed"); - abort(); - } - fcntl(ueventFd, F_SETFL, O_NONBLOCK); - - if (addEpollFd(epollFd, ueventFd)) - abort(); - - if (addEpollFile(epollFd.get(), dataRolePath, mDataRoleFd) != 0) { - ALOGE("monitor data role failed"); - abort(); - } - - /* - * The device state file could be absent depending on the current data role - * and driver architecture. It's ok for addEpollFile to fail here, the file - * will be monitored later when its presence is detected by uevent. - */ - mDeviceState.filePath = deviceStatePath; - mDeviceState.ueventRegex = deviceUeventRegex; - addEpollFile(epollFd.get(), mDeviceState.filePath, mDeviceState.fd); - - mHost1State.filePath = host1StatePath; - mHost1State.ueventRegex = host1UeventRegex; - addEpollFile(epollFd.get(), mHost1State.filePath, mHost1State.fd); - - mHost2State.filePath = host2StatePath; - mHost2State.ueventRegex = host2UeventRegex; - addEpollFile(epollFd.get(), mHost2State.filePath, mHost2State.fd); - - mEpollFd = std::move(epollFd); - mUeventFd = std::move(ueventFd); - mUpdatePortStatusCb = updatePortStatusCb; - - if (ReadFileToString(kUdcConfigfsPath, &udc) && !udc.empty()) - mUdcBind = true; - else - mUdcBind = false; - - if (pthread_create(&mMonitor, NULL, this->monitorThread, this)) { - ALOGE("pthread creation failed %d", errno); - abort(); - } -} - -UsbDataSessionMonitor::~UsbDataSessionMonitor() {} - -void UsbDataSessionMonitor::reportUsbDataSessionMetrics() { - std::vector events; - - if (mDataRole == PortDataRole::DEVICE) { - VendorUsbDataSessionEvent event; - BuildVendorUsbDataSessionEvent(false /* is_host */, boot_clock::now(), mDataSessionStart, - &mDeviceState.states, &mDeviceState.timestamps, &event); - events.push_back(event); - } else if (mDataRole == PortDataRole::HOST) { - bool empty = true; - for (auto e : {&mHost1State, &mHost2State}) { - /* - * Host port will at least get an not_attached event after enablement, - * skip upload if no additional state is added. - */ - if (e->states.size() > 1) { - VendorUsbDataSessionEvent event; - BuildVendorUsbDataSessionEvent(true /* is_host */, boot_clock::now(), - mDataSessionStart, &e->states, &e->timestamps, - &event); - events.push_back(event); - empty = false; - } - } - // All host ports have no state update, upload an event to reflect it - if (empty) { - VendorUsbDataSessionEvent event; - BuildVendorUsbDataSessionEvent(true /* is_host */, boot_clock::now(), mDataSessionStart, - &mHost1State.states, &mHost1State.timestamps, &event); - events.push_back(event); - } - } else { - return; - } - - const std::shared_ptr stats_client = getStatsService(); - if (!stats_client) { - ALOGE("Unable to get AIDL Stats service"); - return; - } - - for (auto &event : events) { - reportUsbDataSessionEvent(stats_client, event); - } -} - -void UsbDataSessionMonitor::getComplianceWarnings(const PortDataRole &role, - std::vector *warnings) { - if (!usb_flags::enable_report_usb_data_compliance_warning()) - return; - - if (role != mDataRole || role == PortDataRole::NONE) - return; - - for (auto w : mWarningSet) { - warnings->push_back(w); - } -} - -void UsbDataSessionMonitor::notifyComplianceWarning() { - if (!usb_flags::enable_report_usb_data_compliance_warning()) - return; - - if (mUpdatePortStatusCb) - mUpdatePortStatusCb(); -} - -void UsbDataSessionMonitor::evaluateComplianceWarning() { - std::set newWarningSet; - - // TODO: add heuristics and update newWarningSet - if (mDataRole == PortDataRole::DEVICE && mUdcBind) { - } else if (mDataRole == PortDataRole::HOST) { - } - - if (newWarningSet != mWarningSet) { - mWarningSet = newWarningSet; - notifyComplianceWarning(); - } -} - -void UsbDataSessionMonitor::clearDeviceStateEvents(struct usbDeviceState *deviceState) { - deviceState->states.clear(); - deviceState->timestamps.clear(); -} - -void UsbDataSessionMonitor::handleDeviceStateEvent(struct usbDeviceState *deviceState) { - int n; - char state[USB_STATE_MAX_LEN] = {0}; - - lseek(deviceState->fd.get(), 0, SEEK_SET); - n = read(deviceState->fd.get(), &state, USB_STATE_MAX_LEN); - - if (kValidStates.find(state) == kValidStates.end()) { - ALOGE("Invalid state %s", state); - return; - } - - ALOGI("Update USB device state: %s", state); - - deviceState->states.push_back(state); - deviceState->timestamps.push_back(boot_clock::now()); - evaluateComplianceWarning(); -} - -void UsbDataSessionMonitor::handleDataRoleEvent() { - int n; - PortDataRole newDataRole; - char role[DATA_ROLE_MAX_LEN] = {0}; - - lseek(mDataRoleFd.get(), 0, SEEK_SET); - n = read(mDataRoleFd.get(), &role, DATA_ROLE_MAX_LEN); - - ALOGI("Update USB data role %s", role); - - if (!std::strcmp(role, "host")) { - newDataRole = PortDataRole::HOST; - } else if (!std::strcmp(role, "device")) { - newDataRole = PortDataRole::DEVICE; - } else { - newDataRole = PortDataRole::NONE; - } - - if (newDataRole != mDataRole) { - // Upload metrics for the last data session that has ended - if (mDataRole == PortDataRole::HOST || (mDataRole == PortDataRole::DEVICE && mUdcBind)) { - reportUsbDataSessionMetrics(); - } - - // Set up for the new data session - mWarningSet.clear(); - mDataRole = newDataRole; - mDataSessionStart = boot_clock::now(); - - if (newDataRole == PortDataRole::DEVICE) { - clearDeviceStateEvents(&mDeviceState); - } else if (newDataRole == PortDataRole::HOST) { - clearDeviceStateEvents(&mHost1State); - clearDeviceStateEvents(&mHost2State); - } - } -} - -void UsbDataSessionMonitor::updateUdcBindStatus(const std::string &devname) { - std::string function; - bool newUdcBind; - - /* - * /sys/class/udc//function prints out name of currently running USB gadget driver - * Ref: https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-udc - * Empty name string means the udc device is not bound and gadget is pulldown. - */ - if (!ReadFileToString("/sys" + devname + "/function", &function)) - return; - - if (function == "") - newUdcBind = false; - else - newUdcBind = true; - - if (newUdcBind == mUdcBind) - return; - - if (mDataRole == PortDataRole::DEVICE) { - if (mUdcBind && !newUdcBind) { - /* - * Gadget soft pulldown: report metrics as the end of a data session and - * re-evaluate compliance warnings to clear existing warnings if any. - */ - reportUsbDataSessionMetrics(); - evaluateComplianceWarning(); - - } else if (!mUdcBind && newUdcBind) { - // Gadget soft pullup: reset and start accounting for a new data session. - clearDeviceStateEvents(&mDeviceState); - mDataSessionStart = boot_clock::now(); - } - } - - ALOGI("Udc bind status changes from %b to %b", mUdcBind, newUdcBind); - mUdcBind = newUdcBind; -} - -void UsbDataSessionMonitor::handleUevent() { - char msg[UEVENT_MSG_LEN + 2]; - char *cp; - int n; - - n = uevent_kernel_multicast_recv(mUeventFd.get(), msg, UEVENT_MSG_LEN); - if (n <= 0) - return; - if (n >= UEVENT_MSG_LEN) - return; - - msg[n] = '\0'; - msg[n + 1] = '\0'; - cp = msg; - - while (*cp) { - for (auto e : {&mHost1State, &mHost2State}) { - if (std::regex_search(cp, std::regex(e->ueventRegex))) { - if (!strncmp(cp, "bind@", strlen("bind@"))) { - addEpollFile(mEpollFd.get(), e->filePath, e->fd); - } else if (!strncmp(cp, "unbind@", strlen("unbind@"))) { - removeEpollFile(mEpollFd.get(), e->filePath, e->fd); - } - } - } - - // TODO: support bind@ unbind@ to detect dynamically allocated udc device - if (std::regex_search(cp, std::regex(mDeviceState.ueventRegex))) { - if (!strncmp(cp, "change@", strlen("change@"))) { - char *devname = cp + strlen("change@"); - /* - * Udc device emits a KOBJ_CHANGE event on configfs driver bind and unbind. - * TODO: upstream udc driver emits KOBJ_CHANGE event BEFORE unbind is actually - * executed. Add a short delay to get the correct state while working on a fix - * upstream. - */ - usleep(50000); - updateUdcBindStatus(devname); - } - } - /* advance to after the next \0 */ - while (*cp++) { - } - } -} - -void *UsbDataSessionMonitor::monitorThread(void *param) { - UsbDataSessionMonitor *monitor = (UsbDataSessionMonitor *)param; - struct epoll_event events[64]; - int nevents = 0; - - while (true) { - nevents = epoll_wait(monitor->mEpollFd.get(), events, 64, -1); - if (nevents == -1) { - if (errno == EINTR) - continue; - ALOGE("usb epoll_wait failed; errno=%d", errno); - break; - } - - for (int n = 0; n < nevents; ++n) { - if (events[n].data.fd == monitor->mUeventFd.get()) { - monitor->handleUevent(); - } else if (events[n].data.fd == monitor->mDataRoleFd.get()) { - monitor->handleDataRoleEvent(); - } else if (events[n].data.fd == monitor->mDeviceState.fd.get()) { - monitor->handleDeviceStateEvent(&monitor->mDeviceState); - } else if (events[n].data.fd == monitor->mHost1State.fd.get()) { - monitor->handleDeviceStateEvent(&monitor->mHost1State); - } else if (events[n].data.fd == monitor->mHost2State.fd.get()) { - monitor->handleDeviceStateEvent(&monitor->mHost2State); - } - } - } - return NULL; -} - -} // namespace usb -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/usb/usb/UsbDataSessionMonitor.h b/usb/usb/UsbDataSessionMonitor.h deleted file mode 100644 index 596f378f..00000000 --- a/usb/usb/UsbDataSessionMonitor.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * 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. - */ - -#pragma once - -#include -#include -#include -#include - -#include -#include -#include - -namespace aidl { -namespace android { -namespace hardware { -namespace usb { - -using ::aidl::android::hardware::usb::ComplianceWarning; -using ::aidl::android::hardware::usb::PortDataRole; -using ::android::base::boot_clock; -using ::android::base::unique_fd; - -/* - * UsbDataSessionMonitor monitors the usb device state sysfs of 3 different usb devices - * including device mode (udc), host mode high-speed port and host mode super-speed port. It - * reports Suez metrics for each data session and also provides API to query the compliance - * warnings detected in the current usb data session. - */ -class UsbDataSessionMonitor { - public: - /* - * The host mode high-speed port and super-speed port can be assigned to either host1 or - * host2 without affecting functionality. - * - * UeventRegex: name regex of the device that's being monitored. The regex is matched against - * uevent to detect dynamic creation/deletion/change of the device. - * StatePath: usb device state sysfs path of the device, monitored by epoll. - * dataRolePath: path to the usb data role sysfs, monitored by epoll. - * updatePortStatusCb: the callback is invoked when the compliance warings changes. - */ - UsbDataSessionMonitor(const std::string &deviceUeventRegex, const std::string &deviceStatePath, - const std::string &host1UeventRegex, const std::string &host1StatePath, - const std::string &host2UeventRegex, const std::string &host2StatePath, - const std::string &dataRolePath, - std::function updatePortStatusCb); - ~UsbDataSessionMonitor(); - // Returns the compliance warnings detected in the current data session. - void getComplianceWarnings(const PortDataRole &role, std::vector *warnings); - - private: - struct usbDeviceState { - unique_fd fd; - std::string filePath; - std::string ueventRegex; - // Usb device states reported by state sysfs - std::vector states; - // Timestamps of when the usb device states were captured - std::vector timestamps; - }; - - static void *monitorThread(void *param); - void handleUevent(); - void handleDataRoleEvent(); - void handleDeviceStateEvent(struct usbDeviceState *deviceState); - void clearDeviceStateEvents(struct usbDeviceState *deviceState); - void reportUsbDataSessionMetrics(); - void evaluateComplianceWarning(); - void notifyComplianceWarning(); - void updateUdcBindStatus(const std::string &devname); - - pthread_t mMonitor; - unique_fd mEpollFd; - unique_fd mUeventFd; - unique_fd mDataRoleFd; - struct usbDeviceState mDeviceState; - struct usbDeviceState mHost1State; - struct usbDeviceState mHost2State; - std::set mWarningSet; - // Callback function to notify the caller when there's a change in compliance warnings. - std::function mUpdatePortStatusCb; - /* - * Cache relevant info for a USB data session when one starts, including - * the data role and the time when the session starts. - */ - PortDataRole mDataRole; - boot_clock::time_point mDataSessionStart; - /* - * In gadget mode: this indicates whether the udc device is bound to the configfs driver, which - * is done by userspace writing the udc device name to /config/usb_gadget/g1/UDC. When unbound, - * the gadget is in soft pulldown state and is expected not to enumerate. During gadget - * function switch, the udc device usually go through unbind and bind. - */ - bool mUdcBind; -}; - -} // namespace usb -} // namespace hardware -} // namespace android -} // namespace aidl From dc7845e89af802793b7a76dfb34e48636b2a1086 Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Fri, 1 Dec 2023 11:36:08 +0800 Subject: [PATCH 10/15] gs201: update manifest HAL android.hardware.boot from hidl 1.2 to aidl Bug: 314215524 Change-Id: I59988d13f9bedc3a2067f9ffc49d690048383d66 Signed-off-by: Jason Chiu --- manifest-gralloc3.xml | 5 ++--- manifest.xml | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/manifest-gralloc3.xml b/manifest-gralloc3.xml index 82ff14ab..cd405200 100644 --- a/manifest-gralloc3.xml +++ b/manifest-gralloc3.xml @@ -68,10 +68,9 @@ default - + android.hardware.boot - hwbinder - @1.2::IBootControl/default + IBootControl/default android.hardware.sensors diff --git a/manifest.xml b/manifest.xml index 031b46f3..a5cf98dc 100644 --- a/manifest.xml +++ b/manifest.xml @@ -8,10 +8,9 @@ default - + android.hardware.boot - hwbinder - @1.2::IBootControl/default + IBootControl/default com.google.input From a509a4b067ffe877dfed0e360c581edb89edd3e0 Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Fri, 1 Dec 2023 11:37:20 +0800 Subject: [PATCH 11/15] gs201: use android.hardware.boot aidl interface Bug: 314215524 Change-Id: Id6e4083674e8e42572952ea516eae244d4d5e8e7 Signed-off-by: Jason Chiu --- device.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device.mk b/device.mk index 68bd8793..fd91d880 100644 --- a/device.mk +++ b/device.mk @@ -36,7 +36,7 @@ include device/google/gs-common/widevine/widevine.mk include device/google/gs-common/sota_app/factoryota.mk include device/google/gs-common/misc_writer/misc_writer.mk include device/google/gs-common/gyotaku_app/gyotaku.mk -include device/google/gs-common/bootctrl/bootctrl_hidl_1.2.mk +include device/google/gs-common/bootctrl/bootctrl_aidl.mk TARGET_BOARD_PLATFORM := gs201 From 8d10e34fe05fc31b0604bad062424404f91cfbab Mon Sep 17 00:00:00 2001 From: Roy Luo Date: Fri, 8 Dec 2023 15:35:14 +0000 Subject: [PATCH 12/15] Revert^2 "usb: introduce UsbDataSessionMonitor class" a9ac5d5869eb22c1e99f81161b711cdf6c7c6270 Bug: 297224564 Bug: 296119135 Change-Id: I0e15924ff133c8070c923f9072497bfda4370b5b --- usb/usb/Android.bp | 1 + usb/usb/Usb.cpp | 308 +++++----------------- usb/usb/Usb.h | 34 +-- usb/usb/UsbDataSessionMonitor.cpp | 420 ++++++++++++++++++++++++++++++ usb/usb/UsbDataSessionMonitor.h | 114 ++++++++ 5 files changed, 598 insertions(+), 279 deletions(-) create mode 100644 usb/usb/UsbDataSessionMonitor.cpp create mode 100644 usb/usb/UsbDataSessionMonitor.h diff --git a/usb/usb/Android.bp b/usb/usb/Android.bp index 8fd373b2..609af179 100644 --- a/usb/usb/Android.bp +++ b/usb/usb/Android.bp @@ -34,6 +34,7 @@ cc_binary { srcs: [ "service.cpp", "Usb.cpp", + "UsbDataSessionMonitor.cpp", ], shared_libs: [ "libbase", diff --git a/usb/usb/Usb.cpp b/usb/usb/Usb.cpp index 224951a1..555e6576 100644 --- a/usb/usb/Usb.cpp +++ b/usb/usb/Usb.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -44,7 +43,6 @@ #include #include -#include #include #include @@ -57,9 +55,6 @@ 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; @@ -95,17 +90,22 @@ constexpr char kThermalZoneForTempReadSecondary2[] = "qi_therm"; constexpr char kPogoUsbActive[] = "/sys/devices/platform/google,pogo/pogo_usb_active"; constexpr char KPogoMoveDataToUsb[] = "/sys/devices/platform/google,pogo/move_data_to_usb"; constexpr char kPowerSupplyUsbType[] = "/sys/class/power_supply/usb/usb_type"; -constexpr char kUdcState[] = "/sys/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3/state"; -// xhci-hcd-exynos and usb device numbering could vary on different platforms -constexpr char kHostUeventRegex[] = "^(bind|unbind)@(/devices/platform/11210000\\.usb/11210000\\.dwc3/xhci-hcd-exynos\\.[0-9]\\.auto/)usb([0-9])/[0-9]-0:1\\.0"; +constexpr char kUdcUeventRegex[] = + "/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3"; +constexpr char kUdcStatePath[] = + "/sys/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3/state"; +constexpr char kHost1UeventRegex[] = + "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb2/2-0:1.0"; +constexpr char kHost1StatePath[] = "/sys/bus/usb/devices/usb2/2-0:1.0/usb2-port1/state"; +constexpr char kHost2UeventRegex[] = + "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb3/3-0:1.0"; +constexpr char kHost2StatePath[] = "/sys/bus/usb/devices/usb3/3-0:1.0/usb3-port1/state"; +constexpr char kDataRolePath[] = "/sys/devices/platform/11210000.usb/new_data_role"; constexpr int kSamplingIntervalSec = 5; void queryVersionHelper(android::hardware::usb::Usb *usb, std::vector *currentPortStatus); -void queryUsbDataSession(android::hardware::usb::Usb *usb, - std::vector *currentPortStatus); -#define USB_STATE_MAX_LEN 20 #define CTRL_TRANSFER_TIMEOUT_MSEC 1000 #define GL852G_VENDOR_ID 0x05e3 #define GL852G_PRODUCT_ID1 0x0608 @@ -538,11 +538,20 @@ void *usbHostWork(void *param) { return NULL; } +void updatePortStatus(android::hardware::usb::Usb *usb) { + std::vector currentPortStatus; + + queryVersionHelper(usb, ¤tPortStatus); +} + Usb::Usb() : mLock(PTHREAD_MUTEX_INITIALIZER), mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER), mPartnerLock(PTHREAD_MUTEX_INITIALIZER), mPartnerUp(false), + mUsbDataSessionMonitor(kUdcUeventRegex, kUdcStatePath, kHost1UeventRegex, kHost1StatePath, + kHost2UeventRegex, kHost2StatePath, kDataRolePath, + std::bind(&updatePortStatus, this)), mOverheat(ZoneInfo(TemperatureType::USB_PORT, kThermalZoneForTrip, ThrottlingSeverity::CRITICAL), {ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadPrimary, @@ -922,6 +931,18 @@ done: return Status::ERROR; } +void queryUsbDataSession(android::hardware::usb::Usb *usb, + std::vector *currentPortStatus) { + std::vector warnings; + + usb->mUsbDataSessionMonitor.getComplianceWarnings( + (*currentPortStatus)[0].currentDataRole, &warnings); + (*currentPortStatus)[0].complianceWarnings.insert( + (*currentPortStatus)[0].complianceWarnings.end(), + warnings.begin(), + warnings.end()); +} + void queryVersionHelper(android::hardware::usb::Usb *usb, std::vector *currentPortStatus) { Status status; @@ -1017,194 +1038,17 @@ void report_overheat_event(android::hardware::usb::Usb *usb) { } } -void report_usb_data_session_event(android::hardware::usb::Usb *usb) { - std::vector events; +struct data { + int uevent_fd; + ::aidl::android::hardware::usb::Usb *usb; +}; - 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 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 *map; - int fd; - - map = &usb->mEpollEntries; - auto it = map->find(name); - if (it != map->end()) { - ALOGI("epoll unregister %s", name.c_str()); - fd = it->second.payload.fd; - epoll_ctl(usb->mEpollFd, EPOLL_CTL_DEL, fd, NULL); - close(fd); - map->erase(it); - } -} - -static void unregisterEpollEntries(Usb *usb) { - std::map *map; - std::string name; - - map = &usb->mEpollEntries; - for (auto it = map->begin(); it != map->end();) { - name = it->first; - it++; - unregisterEpollEntry(usb, name); - } -} - -static int registerEpollEntry(Usb *usb, std::string name, int fd, int flags, - void (*func)(uint32_t, struct Usb::payload*)) { - std::map *map; - struct Usb::epollEntry *entry; - struct epoll_event ev; - - map = &usb->mEpollEntries; - if (map->find(name) != map->end()) { - ALOGE("%s already registered", name.c_str()); - unregisterEpollEntry(usb, name); - } - - entry = &(*map)[name]; - entry->payload.fd = fd; - entry->payload.name = name; - entry->payload.usb = usb; - entry->cb = std::bind(func, std::placeholders::_1, &entry->payload); - - ev.events = flags; - ev.data.ptr = (void *)&entry->cb; - - if (epoll_ctl(usb->mEpollFd, EPOLL_CTL_ADD, fd, &ev) != 0) { - ALOGE("epoll_ctl failed; errno=%d", errno); - unregisterEpollEntry(usb, name); - return -1; - } - - ALOGI("epoll register %s", name.c_str()); - - return 0; -} - -static int registerEpollEntryByFile(Usb *usb, std::string name, int flags, - void (*func)(uint32_t, struct Usb::payload*)) { - int fd; - - fd = open(name.c_str(), O_RDONLY); - if (fd < 0) { - ALOGE("Cannot open %s", name.c_str()); - return -1; - } - - return registerEpollEntry(usb, name, fd, flags, func); -} - -static void clearUsbDeviceState(struct Usb::usbDeviceState *device) { - 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->states.push_back(state); - device->timestamps.push_back(std::chrono::steady_clock::now()); - - if (!std::strcmp(state, "configured\n")) { - device->portResetCount = 0; - } else if (!std::strcmp(state, "default\n")) { - device->portResetCount++; - } -} - -static void host_event(uint32_t /*epevents*/, struct Usb::payload *payload) { - int n; - char state[USB_STATE_MAX_LEN] = {0}; - struct Usb::usbDeviceState *device; - - lseek(payload->fd, 0, SEEK_SET); - n = read(payload->fd, &state, USB_STATE_MAX_LEN); - - updateUsbDeviceState(&payload->usb->mHostStateMap[payload->name], state); -} - -void queryUsbDataSession(android::hardware::usb::Usb *usb, - std::vector *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 data *payload) { char msg[UEVENT_MSG_LEN + 2]; char *cp; int n; - std::cmatch match; - n = uevent_kernel_multicast_recv(payload->fd, msg, UEVENT_MSG_LEN); + n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN); if (n <= 0) return; if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ @@ -1250,28 +1094,6 @@ static void uevent_event(uint32_t /*epevents*/, struct Usb::payload *payload) { } else if (!strncmp(cp, kOverheatStatsDev, strlen(kOverheatStatsDev))) { ALOGV("Overheat Cooling device suez update"); report_overheat_event(payload->usb); - } else if (std::regex_match(cp, match, std::regex(kHostUeventRegex))) { - /* - * Matched strings: - * 1st: entire string - * 2nd: uevent action, either "bind" or "unbind" - * 3rd: xhci device path, e.g. devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.4.auto - * 4th: usb device number, e.g. 1 for usb1 - * - * The strings are used to composed usb device state path, e.g. - * /sys/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.4.auto/usb2/2-0:1.0/usb2-port1/state - */ - if (match.size() == 4) { - std::string action = match[1].str(); - std::string id = match[3].str(); - std::string path = "/sys" + match[2].str() + "usb" + id + "/" + - id + "-0:1.0/usb" + id + "-port1/state"; - if (action == "bind") { - registerEpollEntryByFile(payload->usb, path, EPOLLPRI, host_event); - } else if (action == "unbind") { - unregisterEpollEntry(payload->usb, path); - } - } } /* advance to after the next \0 */ while (*cp++) { @@ -1279,46 +1101,37 @@ static void uevent_event(uint32_t /*epevents*/, struct Usb::payload *payload) { } } -static void udc_event(uint32_t /*epevents*/, struct Usb::payload *payload) { - int n; - char state[USB_STATE_MAX_LEN] = {0}; - - lseek(payload->fd, 0, SEEK_SET); - n = read(payload->fd, &state, USB_STATE_MAX_LEN); - - updateUsbDeviceState(&payload->usb->mDeviceState, state); -} - void *work(void *param) { int epoll_fd, uevent_fd; + struct epoll_event ev; int nevents = 0; - Usb *usb = (Usb *)param; + struct data payload; ALOGE("creating thread"); + uevent_fd = uevent_open_socket(64 * 1024, true); + + if (uevent_fd < 0) { + ALOGE("uevent_init: uevent_open_socket failed\n"); + return NULL; + } + + payload.uevent_fd = uevent_fd; + payload.usb = (::aidl::android::hardware::usb::Usb *)param; + + fcntl(uevent_fd, F_SETFL, O_NONBLOCK); + + ev.events = EPOLLIN; + ev.data.ptr = (void *)uevent_event; + epoll_fd = epoll_create(64); if (epoll_fd == -1) { ALOGE("epoll_create failed; errno=%d", errno); - return NULL; - } - usb->mEpollFd = epoll_fd; - - // Monitor uevent - uevent_fd = uevent_open_socket(64 * 1024, true); - if (uevent_fd < 0) { - ALOGE("uevent_init: uevent_open_socket failed"); - goto error; - } - fcntl(uevent_fd, F_SETFL, O_NONBLOCK); - - if (registerEpollEntry(usb, "uevent", uevent_fd, EPOLLIN, uevent_event)) { - ALOGE("failed to monitor uevent"); goto error; } - // Monitor udc state - if (registerEpollEntryByFile(usb, kUdcState, EPOLLPRI, udc_event)) { - ALOGE("failed to monitor udc state"); + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) { + ALOGE("epoll_ctl failed; errno=%d", errno); goto error; } @@ -1335,15 +1148,14 @@ void *work(void *param) { for (int n = 0; n < nevents; ++n) { if (events[n].data.ptr) - (*(std::function*)events[n].data.ptr)(events[n].events); + (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events, + &payload); } } ALOGI("exiting worker thread"); error: - unregisterEpollEntries(usb); - - usb->mEpollFd = -1; + close(uevent_fd); if (epoll_fd >= 0) close(epoll_fd); diff --git a/usb/usb/Usb.h b/usb/usb/Usb.h index 83bae889..495a467f 100644 --- a/usb/usb/Usb.h +++ b/usb/usb/Usb.h @@ -19,9 +19,9 @@ #include #include #include -#include #include #include +#include #define UEVENT_MSG_LEN 2048 // The type-c stack waits for 4.5 - 5.5 secs before declaring a port non-pd. @@ -88,6 +88,8 @@ struct Usb : public BnUsb { // Variable to signal partner coming back online after type switch bool mPartnerUp; + // Report usb data session event and data incompliance warnings + UsbDataSessionMonitor mUsbDataSessionMonitor; // Usb Overheat object for push suez event UsbOverheatEvent mOverheat; // Temperature when connected @@ -98,36 +100,6 @@ struct Usb : public BnUsb { int mUsbHubVendorCmdValue; int mUsbHubVendorCmdIndex; - // USB device state monitoring - struct usbDeviceState { - // Usb device state raw strings read from sysfs - std::vector states; - // Timestamps of when the usb device states were captured - std::vector timestamps; - int portResetCount; - }; - struct usbDeviceState mDeviceState; - // Map host device path name to usbDeviceState - std::map 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; - struct payload { - int fd; - std::string name; - Usb *usb; - }; - struct epollEntry { - struct payload payload; - std::function cb; - }; - std::map mEpollEntries; - private: pthread_t mPoll; pthread_t mUsbHost; diff --git a/usb/usb/UsbDataSessionMonitor.cpp b/usb/usb/UsbDataSessionMonitor.cpp new file mode 100644 index 00000000..77defb30 --- /dev/null +++ b/usb/usb/UsbDataSessionMonitor.cpp @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ + +#define LOG_TAG "android.hardware.usb.aidl-service.UsbDataSessionMonitor" + +#include "UsbDataSessionMonitor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace usb_flags = android::hardware::usb::flags; + +using aidl::android::frameworks::stats::IStats; +using android::base::ReadFileToString; +using android::hardware::google::pixel::getStatsService; +using android::hardware::google::pixel::reportUsbDataSessionEvent; +using android::hardware::google::pixel::PixelAtoms::VendorUsbDataSessionEvent; +using android::hardware::google::pixel::usb::addEpollFd; +using android::hardware::google::pixel::usb::BuildVendorUsbDataSessionEvent; + +namespace aidl { +namespace android { +namespace hardware { +namespace usb { + +#define UEVENT_MSG_LEN 2048 +#define USB_STATE_MAX_LEN 20 +#define DATA_ROLE_MAX_LEN 10 + +constexpr char kUdcConfigfsPath[] = "/config/usb_gadget/g1/UDC"; +constexpr char kNotAttachedState[] = "not attached\n"; +constexpr char kAttachedState[] = "attached\n"; +constexpr char kPoweredState[] = "powered\n"; +constexpr char kDefaultState[] = "default\n"; +constexpr char kAddressedState[] = "addressed\n"; +constexpr char kConfiguredState[] = "configured\n"; +constexpr char kSuspendedState[] = "suspended\n"; +const std::set kValidStates = {kNotAttachedState, kAttachedState, kPoweredState, + kDefaultState, kAddressedState, kConfiguredState, + kSuspendedState}; + +static int addEpollFile(const int &epollFd, const std::string &filePath, unique_fd &fileFd) { + struct epoll_event ev; + + unique_fd fd(open(filePath.c_str(), O_RDONLY)); + + if (fd.get() == -1) { + ALOGI("Cannot open %s", filePath.c_str()); + return -1; + } + + ev.data.fd = fd.get(); + ev.events = EPOLLPRI; + + if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fd.get(), &ev) != 0) { + ALOGE("epoll_ctl failed; errno=%d", errno); + return -1; + } + + fileFd = std::move(fd); + ALOGI("epoll registered %s", filePath.c_str()); + return 0; +} + +static void removeEpollFile(const int &epollFd, const std::string &filePath, unique_fd &fileFd) { + epoll_ctl(epollFd, EPOLL_CTL_DEL, fileFd.get(), NULL); + fileFd.release(); + + ALOGI("epoll unregistered %s", filePath.c_str()); +} + +UsbDataSessionMonitor::UsbDataSessionMonitor( + const std::string &deviceUeventRegex, const std::string &deviceStatePath, + const std::string &host1UeventRegex, const std::string &host1StatePath, + const std::string &host2UeventRegex, const std::string &host2StatePath, + const std::string &dataRolePath, std::function updatePortStatusCb) { + struct epoll_event ev; + std::string udc; + + unique_fd epollFd(epoll_create(8)); + if (epollFd.get() == -1) { + ALOGE("epoll_create failed; errno=%d", errno); + abort(); + } + + unique_fd ueventFd(uevent_open_socket(64 * 1024, true)); + if (ueventFd.get() == -1) { + ALOGE("uevent_open_socket failed"); + abort(); + } + fcntl(ueventFd, F_SETFL, O_NONBLOCK); + + if (addEpollFd(epollFd, ueventFd)) + abort(); + + if (addEpollFile(epollFd.get(), dataRolePath, mDataRoleFd) != 0) { + ALOGE("monitor data role failed"); + abort(); + } + + /* + * The device state file could be absent depending on the current data role + * and driver architecture. It's ok for addEpollFile to fail here, the file + * will be monitored later when its presence is detected by uevent. + */ + mDeviceState.filePath = deviceStatePath; + mDeviceState.ueventRegex = deviceUeventRegex; + addEpollFile(epollFd.get(), mDeviceState.filePath, mDeviceState.fd); + + mHost1State.filePath = host1StatePath; + mHost1State.ueventRegex = host1UeventRegex; + addEpollFile(epollFd.get(), mHost1State.filePath, mHost1State.fd); + + mHost2State.filePath = host2StatePath; + mHost2State.ueventRegex = host2UeventRegex; + addEpollFile(epollFd.get(), mHost2State.filePath, mHost2State.fd); + + mEpollFd = std::move(epollFd); + mUeventFd = std::move(ueventFd); + mUpdatePortStatusCb = updatePortStatusCb; + + if (ReadFileToString(kUdcConfigfsPath, &udc) && !udc.empty()) + mUdcBind = true; + else + mUdcBind = false; + + if (pthread_create(&mMonitor, NULL, this->monitorThread, this)) { + ALOGE("pthread creation failed %d", errno); + abort(); + } +} + +UsbDataSessionMonitor::~UsbDataSessionMonitor() {} + +void UsbDataSessionMonitor::reportUsbDataSessionMetrics() { + std::vector events; + + if (mDataRole == PortDataRole::DEVICE) { + VendorUsbDataSessionEvent event; + BuildVendorUsbDataSessionEvent(false /* is_host */, boot_clock::now(), mDataSessionStart, + &mDeviceState.states, &mDeviceState.timestamps, &event); + events.push_back(event); + } else if (mDataRole == PortDataRole::HOST) { + bool empty = true; + for (auto e : {&mHost1State, &mHost2State}) { + /* + * Host port will at least get an not_attached event after enablement, + * skip upload if no additional state is added. + */ + if (e->states.size() > 1) { + VendorUsbDataSessionEvent event; + BuildVendorUsbDataSessionEvent(true /* is_host */, boot_clock::now(), + mDataSessionStart, &e->states, &e->timestamps, + &event); + events.push_back(event); + empty = false; + } + } + // All host ports have no state update, upload an event to reflect it + if (empty) { + VendorUsbDataSessionEvent event; + BuildVendorUsbDataSessionEvent(true /* is_host */, boot_clock::now(), mDataSessionStart, + &mHost1State.states, &mHost1State.timestamps, &event); + events.push_back(event); + } + } else { + return; + } + + const std::shared_ptr stats_client = getStatsService(); + if (!stats_client) { + ALOGE("Unable to get AIDL Stats service"); + return; + } + + for (auto &event : events) { + reportUsbDataSessionEvent(stats_client, event); + } +} + +void UsbDataSessionMonitor::getComplianceWarnings(const PortDataRole &role, + std::vector *warnings) { + if (!usb_flags::enable_report_usb_data_compliance_warning()) + return; + + if (role != mDataRole || role == PortDataRole::NONE) + return; + + for (auto w : mWarningSet) { + warnings->push_back(w); + } +} + +void UsbDataSessionMonitor::notifyComplianceWarning() { + if (!usb_flags::enable_report_usb_data_compliance_warning()) + return; + + if (mUpdatePortStatusCb) + mUpdatePortStatusCb(); +} + +void UsbDataSessionMonitor::evaluateComplianceWarning() { + std::set newWarningSet; + + // TODO: add heuristics and update newWarningSet + if (mDataRole == PortDataRole::DEVICE && mUdcBind) { + } else if (mDataRole == PortDataRole::HOST) { + } + + if (newWarningSet != mWarningSet) { + mWarningSet = newWarningSet; + notifyComplianceWarning(); + } +} + +void UsbDataSessionMonitor::clearDeviceStateEvents(struct usbDeviceState *deviceState) { + deviceState->states.clear(); + deviceState->timestamps.clear(); +} + +void UsbDataSessionMonitor::handleDeviceStateEvent(struct usbDeviceState *deviceState) { + int n; + char state[USB_STATE_MAX_LEN] = {0}; + + lseek(deviceState->fd.get(), 0, SEEK_SET); + n = read(deviceState->fd.get(), &state, USB_STATE_MAX_LEN); + + if (kValidStates.find(state) == kValidStates.end()) { + ALOGE("Invalid state %s", state); + return; + } + + ALOGI("Update USB device state: %s", state); + + deviceState->states.push_back(state); + deviceState->timestamps.push_back(boot_clock::now()); + evaluateComplianceWarning(); +} + +void UsbDataSessionMonitor::handleDataRoleEvent() { + int n; + PortDataRole newDataRole; + char role[DATA_ROLE_MAX_LEN] = {0}; + + lseek(mDataRoleFd.get(), 0, SEEK_SET); + n = read(mDataRoleFd.get(), &role, DATA_ROLE_MAX_LEN); + + ALOGI("Update USB data role %s", role); + + if (!std::strcmp(role, "host")) { + newDataRole = PortDataRole::HOST; + } else if (!std::strcmp(role, "device")) { + newDataRole = PortDataRole::DEVICE; + } else { + newDataRole = PortDataRole::NONE; + } + + if (newDataRole != mDataRole) { + // Upload metrics for the last data session that has ended + if (mDataRole == PortDataRole::HOST || (mDataRole == PortDataRole::DEVICE && mUdcBind)) { + reportUsbDataSessionMetrics(); + } + + // Set up for the new data session + mWarningSet.clear(); + mDataRole = newDataRole; + mDataSessionStart = boot_clock::now(); + + if (newDataRole == PortDataRole::DEVICE) { + clearDeviceStateEvents(&mDeviceState); + } else if (newDataRole == PortDataRole::HOST) { + clearDeviceStateEvents(&mHost1State); + clearDeviceStateEvents(&mHost2State); + } + } +} + +void UsbDataSessionMonitor::updateUdcBindStatus(const std::string &devname) { + std::string function; + bool newUdcBind; + + /* + * /sys/class/udc//function prints out name of currently running USB gadget driver + * Ref: https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-udc + * Empty name string means the udc device is not bound and gadget is pulldown. + */ + if (!ReadFileToString("/sys" + devname + "/function", &function)) + return; + + if (function == "") + newUdcBind = false; + else + newUdcBind = true; + + if (newUdcBind == mUdcBind) + return; + + if (mDataRole == PortDataRole::DEVICE) { + if (mUdcBind && !newUdcBind) { + /* + * Gadget soft pulldown: report metrics as the end of a data session and + * re-evaluate compliance warnings to clear existing warnings if any. + */ + reportUsbDataSessionMetrics(); + evaluateComplianceWarning(); + + } else if (!mUdcBind && newUdcBind) { + // Gadget soft pullup: reset and start accounting for a new data session. + clearDeviceStateEvents(&mDeviceState); + mDataSessionStart = boot_clock::now(); + } + } + + ALOGI("Udc bind status changes from %b to %b", mUdcBind, newUdcBind); + mUdcBind = newUdcBind; +} + +void UsbDataSessionMonitor::handleUevent() { + char msg[UEVENT_MSG_LEN + 2]; + char *cp; + int n; + + n = uevent_kernel_multicast_recv(mUeventFd.get(), msg, UEVENT_MSG_LEN); + if (n <= 0) + return; + if (n >= UEVENT_MSG_LEN) + return; + + msg[n] = '\0'; + msg[n + 1] = '\0'; + cp = msg; + + while (*cp) { + for (auto e : {&mHost1State, &mHost2State}) { + if (std::regex_search(cp, std::regex(e->ueventRegex))) { + if (!strncmp(cp, "bind@", strlen("bind@"))) { + addEpollFile(mEpollFd.get(), e->filePath, e->fd); + } else if (!strncmp(cp, "unbind@", strlen("unbind@"))) { + removeEpollFile(mEpollFd.get(), e->filePath, e->fd); + } + } + } + + // TODO: support bind@ unbind@ to detect dynamically allocated udc device + if (std::regex_search(cp, std::regex(mDeviceState.ueventRegex))) { + if (!strncmp(cp, "change@", strlen("change@"))) { + char *devname = cp + strlen("change@"); + /* + * Udc device emits a KOBJ_CHANGE event on configfs driver bind and unbind. + * TODO: upstream udc driver emits KOBJ_CHANGE event BEFORE unbind is actually + * executed. Add a short delay to get the correct state while working on a fix + * upstream. + */ + usleep(50000); + updateUdcBindStatus(devname); + } + } + /* advance to after the next \0 */ + while (*cp++) { + } + } +} + +void *UsbDataSessionMonitor::monitorThread(void *param) { + UsbDataSessionMonitor *monitor = (UsbDataSessionMonitor *)param; + struct epoll_event events[64]; + int nevents = 0; + + while (true) { + nevents = epoll_wait(monitor->mEpollFd.get(), events, 64, -1); + if (nevents == -1) { + if (errno == EINTR) + continue; + ALOGE("usb epoll_wait failed; errno=%d", errno); + break; + } + + for (int n = 0; n < nevents; ++n) { + if (events[n].data.fd == monitor->mUeventFd.get()) { + monitor->handleUevent(); + } else if (events[n].data.fd == monitor->mDataRoleFd.get()) { + monitor->handleDataRoleEvent(); + } else if (events[n].data.fd == monitor->mDeviceState.fd.get()) { + monitor->handleDeviceStateEvent(&monitor->mDeviceState); + } else if (events[n].data.fd == monitor->mHost1State.fd.get()) { + monitor->handleDeviceStateEvent(&monitor->mHost1State); + } else if (events[n].data.fd == monitor->mHost2State.fd.get()) { + monitor->handleDeviceStateEvent(&monitor->mHost2State); + } + } + } + return NULL; +} + +} // namespace usb +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/usb/usb/UsbDataSessionMonitor.h b/usb/usb/UsbDataSessionMonitor.h new file mode 100644 index 00000000..596f378f --- /dev/null +++ b/usb/usb/UsbDataSessionMonitor.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace usb { + +using ::aidl::android::hardware::usb::ComplianceWarning; +using ::aidl::android::hardware::usb::PortDataRole; +using ::android::base::boot_clock; +using ::android::base::unique_fd; + +/* + * UsbDataSessionMonitor monitors the usb device state sysfs of 3 different usb devices + * including device mode (udc), host mode high-speed port and host mode super-speed port. It + * reports Suez metrics for each data session and also provides API to query the compliance + * warnings detected in the current usb data session. + */ +class UsbDataSessionMonitor { + public: + /* + * The host mode high-speed port and super-speed port can be assigned to either host1 or + * host2 without affecting functionality. + * + * UeventRegex: name regex of the device that's being monitored. The regex is matched against + * uevent to detect dynamic creation/deletion/change of the device. + * StatePath: usb device state sysfs path of the device, monitored by epoll. + * dataRolePath: path to the usb data role sysfs, monitored by epoll. + * updatePortStatusCb: the callback is invoked when the compliance warings changes. + */ + UsbDataSessionMonitor(const std::string &deviceUeventRegex, const std::string &deviceStatePath, + const std::string &host1UeventRegex, const std::string &host1StatePath, + const std::string &host2UeventRegex, const std::string &host2StatePath, + const std::string &dataRolePath, + std::function updatePortStatusCb); + ~UsbDataSessionMonitor(); + // Returns the compliance warnings detected in the current data session. + void getComplianceWarnings(const PortDataRole &role, std::vector *warnings); + + private: + struct usbDeviceState { + unique_fd fd; + std::string filePath; + std::string ueventRegex; + // Usb device states reported by state sysfs + std::vector states; + // Timestamps of when the usb device states were captured + std::vector timestamps; + }; + + static void *monitorThread(void *param); + void handleUevent(); + void handleDataRoleEvent(); + void handleDeviceStateEvent(struct usbDeviceState *deviceState); + void clearDeviceStateEvents(struct usbDeviceState *deviceState); + void reportUsbDataSessionMetrics(); + void evaluateComplianceWarning(); + void notifyComplianceWarning(); + void updateUdcBindStatus(const std::string &devname); + + pthread_t mMonitor; + unique_fd mEpollFd; + unique_fd mUeventFd; + unique_fd mDataRoleFd; + struct usbDeviceState mDeviceState; + struct usbDeviceState mHost1State; + struct usbDeviceState mHost2State; + std::set mWarningSet; + // Callback function to notify the caller when there's a change in compliance warnings. + std::function mUpdatePortStatusCb; + /* + * Cache relevant info for a USB data session when one starts, including + * the data role and the time when the session starts. + */ + PortDataRole mDataRole; + boot_clock::time_point mDataSessionStart; + /* + * In gadget mode: this indicates whether the udc device is bound to the configfs driver, which + * is done by userspace writing the udc device name to /config/usb_gadget/g1/UDC. When unbound, + * the gadget is in soft pulldown state and is expected not to enumerate. During gadget + * function switch, the udc device usually go through unbind and bind. + */ + bool mUdcBind; +}; + +} // namespace usb +} // namespace hardware +} // namespace android +} // namespace aidl From 8dbc173f2bf04255ce22dd1e13e888050aad36ca Mon Sep 17 00:00:00 2001 From: Hungyen Weng Date: Mon, 11 Dec 2023 11:22:13 -0800 Subject: [PATCH 13/15] config: Use carrier config in ROM by default Bug: 314890118 Test: Flash ROM and confirm the carrier config follows the ROM. Change-Id: Id0407802e2027397ca7a409345c51273b75079e7 --- device.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device.mk b/device.mk index 91364b02..fedeaf5d 100644 --- a/device.mk +++ b/device.mk @@ -190,7 +190,7 @@ PRODUCT_PRODUCT_PROPERTIES += \ # Carrier configuration default location PRODUCT_PROPERTY_OVERRIDES += \ - persist.vendor.radio.config.carrier_config_dir=/mnt/vendor/modem_img/images/default/confpack + persist.vendor.radio.config.carrier_config_dir=/vendor/firmware/carrierconfig PRODUCT_PROPERTY_OVERRIDES += \ telephony.active_modems.max_count=2 From 2ae9b5a025b08fce2af5fecac1fd935cc6dbb1f3 Mon Sep 17 00:00:00 2001 From: Poomarin Phloyphisut Date: Fri, 6 Oct 2023 03:11:22 +0000 Subject: [PATCH 14/15] pixelstats: Fix access permission by adding total call count and update cca path sysfs Related changes : ag/24513108 Bug: 289857250 Test: Local test uploading atoms. Change-Id: I584af796d03585ba3e27baeb8d006af2cab8c24d --- pixelstats/service.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pixelstats/service.cpp b/pixelstats/service.cpp index 5d739b18..ab6f85f2 100644 --- a/pixelstats/service.cpp +++ b/pixelstats/service.cpp @@ -71,7 +71,7 @@ const struct SysfsCollector::SysfsPaths sysfs_paths = { "/sys/devices/platform/100b0000.TPU/trip_counter", "/sys/devices/platform/100b0000.AUR/trip_counter", }, - .CCARatePath = "/sys/devices/platform/audiometrics/cca_rate_read_once", + .CCARatePath = "/sys/devices/platform/audiometrics/cca_count_read_once", .TempResidencyAndResetPaths = { { "/sys/kernel/metrics/thermal/tr_by_group/tmu/stats", @@ -88,7 +88,8 @@ const struct SysfsCollector::SysfsPaths sysfs_paths = { .IRQStatsResetPath = "/sys/kernel/metrics/irq/stats_reset", .ModemPcieLinkStatsPath = "/sys/devices/platform/11920000.pcie/link_stats", .WifiPcieLinkStatsPath = "/sys/devices/platform/14520000.pcie/link_stats", - .GMSRPath = "/sys/class/power_supply/maxfg/gmsr" + .GMSRPath = "/sys/class/power_supply/maxfg/gmsr", + .TotalCallCountPath = "/sys/devices/platform/audiometrics/call_count" }; const struct UeventListener::UeventPaths ueventPaths = { From 84128834583cb62308d1daddc3ebb1fbc538cce2 Mon Sep 17 00:00:00 2001 From: Kuen-Han Tsai Date: Tue, 12 Dec 2023 13:39:21 +0800 Subject: [PATCH 15/15] usb: enable media-presence polling for SD cards After USB enumeration, some SD card readers do not send signals to the device when the SD card is inserted or removed. To support SD card hotplugging, this patch enables in-kernel media-presence polling, which will check the SD card status every 2 seconds after a SD card reader is attached. Bug: 186479576 Test: SD card insertion/removal and data copy (see b/301566595) Change-Id: Ibd7816b717d2fbcb038a7c0ff703b7fab7d2a46c Signed-off-by: Kuen-Han Tsai --- conf/init.gs201.usb.rc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/init.gs201.usb.rc b/conf/init.gs201.usb.rc index 6a52fb07..9ba9eb8a 100644 --- a/conf/init.gs201.usb.rc +++ b/conf/init.gs201.usb.rc @@ -371,6 +371,8 @@ on boot write sys/module/usbcore/parameters/initial_descriptor_timeout 500 # Use USB Gadget HAL setprop sys.usb.configfs 2 + # Enable in-kernel media-presence polling for SD cards + write /sys/module/block/parameters/events_dfl_poll_msecs 2000 on property:sys.usb.ffs.ready=1 && property:sys.usb.config=adb && property:sys.usb.configfs=1 write /config/usb_gadget/g1/idProduct 0x4EE7