Files
android_vendor_pawlet/hwupdate/daemon/detect.cpp
T
oxmc 4e9f147e55 hwupdate: PawletOS hardware/peripheral firmware update subsystem
Adds pawlethwd, a native C++ system_ext daemon (coredomain) that detects
peripherals, checks the hardware update catalog (ota.php?mode=hardware),
verifies payloads, and flashes firmware via authorized handler plugins.

- daemon/: manifest parse, libcurl HTTP + sha256, sysfs USB detection,
  catalog client, dlopen handler registry (fixed path + ABI + allowlist),
  state persistence, orchestration engine, AIDL service, main.
- aidl/: IPawletHardwareUpdate (getComponents/getPendingUpdates/checkNow/...).
- include/pawlet/hwh_abi.h: stable C plugin ABI.
- handlers/usbdfu/: libpawlethwh_usbdfu.so, DFU 1.1 download over libusb.
- sepolicy/: pawlethwd domain, pawlet_hw_data_file, service type.
- schemas/, etc/supported_hardware.default.json, README design doc.
- hwupdate.mk wires packages + ro.pawlet.hardware.manifest + sepolicy dir;
  inherited from config/common.mk.

Trust: a server-named installer handler is honored only if allowlisted in
the immutable supported_hardware.json, maps to a fixed dm-verity-protected
.so path, is ABI/id-checked, and every payload is sha256-verified before a
handler runs.
2026-07-18 01:11:15 -07:00

106 lines
3.1 KiB
C++

/*
* Copyright (C) 2026 oxmc / PawletOS
* SPDX-License-Identifier: Apache-2.0
*/
#include "detect.h"
#include <cstdio>
#include <filesystem>
#include <map>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
namespace pawlet::hwupdate {
namespace {
namespace fs = std::filesystem;
struct UsbDev {
std::string vid; // lowercase hex, e.g. "1209"
std::string pid; // lowercase hex
std::string node; // /dev/bus/usb/BBB/DDD
};
std::string ReadTrimmed(const std::string& path) {
std::string s;
if (!android::base::ReadFileToString(path, &s)) return {};
return android::base::Trim(s);
}
// Enumerate connected USB devices from sysfs.
std::vector<UsbDev> EnumUsb() {
std::vector<UsbDev> out;
const std::string base = "/sys/bus/usb/devices";
std::error_code ec;
if (!fs::exists(base, ec)) return out;
for (const auto& entry : fs::directory_iterator(base, ec)) {
const std::string dir = entry.path().string();
std::string vid = ReadTrimmed(dir + "/idVendor");
std::string pid = ReadTrimmed(dir + "/idProduct");
if (vid.empty() || pid.empty()) continue; // hubs/interfaces, skip
UsbDev d;
d.vid = android::base::Trim(vid);
d.pid = android::base::Trim(pid);
std::string bus = ReadTrimmed(dir + "/busnum");
std::string dev = ReadTrimmed(dir + "/devnum");
if (!bus.empty() && !dev.empty()) {
char node[64];
snprintf(node, sizeof(node), "/dev/bus/usb/%03d/%03d", atoi(bus.c_str()),
atoi(dev.c_str()));
d.node = node;
}
out.push_back(std::move(d));
}
return out;
}
bool UsbMatch(const std::vector<UsbDev>& devs, const std::string& vid, const std::string& pid,
std::string* node) {
for (const auto& d : devs) {
if (android::base::EqualsIgnoreCase(d.vid, vid) &&
android::base::EqualsIgnoreCase(d.pid, pid)) {
if (node) *node = d.node;
return true;
}
}
return false;
}
} // namespace
std::vector<DetectedComponent> Detect(const Manifest& manifest) {
std::vector<UsbDev> usb = EnumUsb();
std::vector<DetectedComponent> out;
for (const auto& prod : manifest.products) {
for (const auto& comp : prod.components) {
DetectedComponent dc;
dc.product = &prod;
dc.comp = &comp;
if (!comp.usbVendorId.empty() && !comp.usbProductId.empty()) {
std::string node;
if (UsbMatch(usb, comp.usbVendorId, comp.usbProductId, &node)) {
dc.present = true;
dc.transport = "usb";
dc.usbVendorId = comp.usbVendorId;
dc.usbProductId = comp.usbProductId;
dc.devPath = node;
}
}
// TODO: device-tree / i2c / spi detectors go here.
if (dc.present) {
LOG(INFO) << "hwupdate: detected " << comp.id << " on " << dc.transport;
}
out.push_back(std::move(dc));
}
}
return out;
}
} // namespace pawlet::hwupdate