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.
92 lines
3.0 KiB
C++
92 lines
3.0 KiB
C++
/*
|
|
* Copyright (C) 2026 oxmc / PawletOS
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include "catalog.h"
|
|
|
|
#include <curl/curl.h>
|
|
#include <json/json.h>
|
|
|
|
#include <sstream>
|
|
|
|
#include <android-base/logging.h>
|
|
|
|
#include "http.h"
|
|
|
|
namespace pawlet::hwupdate {
|
|
namespace {
|
|
|
|
std::string Escape(CURL* c, const std::string& s) {
|
|
char* e = curl_easy_escape(c, s.c_str(), static_cast<int>(s.size()));
|
|
std::string out = e ? e : s;
|
|
if (e) curl_free(e);
|
|
return out;
|
|
}
|
|
|
|
std::string BuildUrl(const std::string& baseUrl, const CheckRequest& r) {
|
|
CURL* c = curl_easy_init();
|
|
std::ostringstream u;
|
|
u << baseUrl;
|
|
// baseUrl already contains "?mode=hardware"; append remaining params.
|
|
u << "&target=update";
|
|
u << "&device=" << Escape(c, r.device);
|
|
u << "&pawlet_version=" << Escape(c, r.pawletVersion);
|
|
u << "&hardware_id=" << Escape(c, r.hardwareId);
|
|
u << "&component_id=" << Escape(c, r.componentId);
|
|
if (!r.hardwareRevision.empty()) u << "&hardware_revision=" << Escape(c, r.hardwareRevision);
|
|
if (!r.currentVersion.empty()) u << "¤t_version=" << Escape(c, r.currentVersion);
|
|
if (!r.bootloaderVersion.empty()) u << "&bootloader_version=" << Escape(c, r.bootloaderVersion);
|
|
if (c) curl_easy_cleanup(c);
|
|
return u.str();
|
|
}
|
|
|
|
std::optional<UpdateEntry> ParseUpdate(const std::string& body) {
|
|
Json::Value root;
|
|
Json::CharReaderBuilder b;
|
|
std::string errs;
|
|
std::istringstream in(body);
|
|
if (!Json::parseFromStream(b, in, &root, &errs)) {
|
|
LOG(WARNING) << "hwupdate: bad update response: " << errs;
|
|
return std::nullopt;
|
|
}
|
|
const Json::Value& u = root["update"];
|
|
if (!u.isObject()) return std::nullopt;
|
|
|
|
UpdateEntry e;
|
|
e.version = u.get("version", "").asString();
|
|
e.datetime = u.get("datetime", 0).asInt64();
|
|
e.filename = u.get("filename", "").asString();
|
|
e.id = u.get("id", "").asString();
|
|
e.sizeBytes = u.get("size_bytes", 0).asInt64();
|
|
e.url = u.get("url", "").asString();
|
|
e.checksumSha256 = u.get("checksum_sha256", "").asString();
|
|
e.changelogUrl = u.get("changelog_url", "").asString();
|
|
const Json::Value& inst = u["installer"];
|
|
e.installerType = inst.get("type", "").asString();
|
|
e.installerHandler = inst.get("handler", "").asString();
|
|
|
|
if (e.url.empty() || e.checksumSha256.empty() || e.installerHandler.empty()) {
|
|
LOG(WARNING) << "hwupdate: update entry missing required fields";
|
|
return std::nullopt;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
std::optional<UpdateEntry> CheckUpdate(const std::string& baseUrl, const CheckRequest& req) {
|
|
std::string url = BuildUrl(baseUrl, req);
|
|
std::string body;
|
|
long code = 0;
|
|
if (!http::Get(url, &body, &code)) return std::nullopt;
|
|
|
|
if (code == 204) return std::nullopt; // up to date
|
|
if (code != 200) {
|
|
LOG(WARNING) << "hwupdate: update check http=" << code << " for " << req.componentId;
|
|
return std::nullopt;
|
|
}
|
|
return ParseUpdate(body);
|
|
}
|
|
|
|
} // namespace pawlet::hwupdate
|