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

87 lines
2.4 KiB
C++

/*
* Copyright (C) 2026 oxmc / PawletOS
* SPDX-License-Identifier: Apache-2.0
*/
#include "state.h"
#include <json/json.h>
#include <fstream>
#include <android-base/logging.h>
namespace pawlet::hwupdate {
State::State(std::string path) : path_(std::move(path)) {}
void State::Load() {
entries_.clear();
std::ifstream in(path_, std::ios::binary);
if (!in) return; // first run
Json::Value root;
Json::CharReaderBuilder b;
std::string errs;
if (!Json::parseFromStream(b, in, &root, &errs)) {
LOG(WARNING) << "hwupdate: state parse error: " << errs;
return;
}
const Json::Value& comps = root["components"];
for (const auto& id : comps.getMemberNames()) {
Entry e;
e.installedVersion = comps[id].get("installed_version", "").asString();
e.retryCount = comps[id].get("retry_count", 0).asInt();
entries_[id] = e;
}
}
bool State::Save() const {
Json::Value root;
root["schema_version"] = 1;
Json::Value comps(Json::objectValue);
for (const auto& [id, e] : entries_) {
Json::Value c(Json::objectValue);
c["installed_version"] = e.installedVersion;
c["retry_count"] = e.retryCount;
comps[id] = c;
}
root["components"] = comps;
// Write atomically: temp file + rename.
std::string tmp = path_ + ".tmp";
{
std::ofstream out(tmp, std::ios::binary | std::ios::trunc);
if (!out) {
LOG(ERROR) << "hwupdate: cannot write state " << tmp;
return false;
}
Json::StreamWriterBuilder w;
out << Json::writeString(w, root);
}
if (rename(tmp.c_str(), path_.c_str()) != 0) {
LOG(ERROR) << "hwupdate: cannot rename state into place";
return false;
}
return true;
}
std::string State::InstalledVersion(const std::string& componentId) const {
auto it = entries_.find(componentId);
return it == entries_.end() ? std::string() : it->second.installedVersion;
}
void State::SetInstalledVersion(const std::string& componentId, const std::string& version) {
entries_[componentId].installedVersion = version;
}
int State::RetryCount(const std::string& componentId) const {
auto it = entries_.find(componentId);
return it == entries_.end() ? 0 : it->second.retryCount;
}
void State::SetRetryCount(const std::string& componentId, int count) {
entries_[componentId].retryCount = count;
}
} // namespace pawlet::hwupdate