4e9f147e55
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.
87 lines
2.4 KiB
C++
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
|