Files
android_vendor_pawlet/hwupdate/daemon/handlers.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

70 lines
2.1 KiB
C++

/*
* Copyright (C) 2026 oxmc / PawletOS
* SPDX-License-Identifier: Apache-2.0
*/
#include "handlers.h"
#include <dlfcn.h>
#include <android-base/logging.h>
#include "util.h"
namespace pawlet::hwupdate {
namespace {
constexpr char kHandlerDir[] = "/system_ext/lib64/pawlet/hwh/";
// Handler ids come from the local allowlist; still, only accept a conservative
// character set so the id can never escape kHandlerDir.
bool ValidId(const std::string& id) {
if (id.empty() || id.size() > 64) return false;
for (char c : id) {
bool ok = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || c == '_' || c == '-';
if (!ok) return false;
}
return true;
}
} // namespace
const pawlet_hwh_api* HandlerRegistry::Get(const std::string& id) {
if (auto it = cache_.find(id); it != cache_.end()) return it->second;
if (!ValidId(id)) {
LOG(ERROR) << "hwupdate: rejecting invalid handler id '" << id << "'";
return nullptr;
}
std::string path = std::string(kHandlerDir) + "libpawlethwh_" + id + ".so";
void* dl = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
if (!dl) {
LOG(ERROR) << "hwupdate: dlopen(" << path << ") failed: " << dlerror();
return nullptr;
}
auto entry = reinterpret_cast<const pawlet_hwh_api* (*)()>(dlsym(dl, "pawlet_hwh_entry"));
if (!entry) {
LOG(ERROR) << "hwupdate: " << path << " missing pawlet_hwh_entry";
dlclose(dl);
return nullptr;
}
const pawlet_hwh_api* api = entry();
if (!api || api->abi_version != PAWLET_HWH_ABI || !api->handler_id ||
!util::IEquals(api->handler_id, id) || !api->detect || !api->get_version ||
!api->flash) {
LOG(ERROR) << "hwupdate: " << path << " failed ABI/id validation";
dlclose(dl);
return nullptr;
}
LOG(INFO) << "hwupdate: loaded handler '" << id << "' (abi " << api->abi_version << ")";
// Intentionally keep dl open for the daemon's lifetime.
cache_[id] = api;
return api;
}
} // namespace pawlet::hwupdate