Remove native Android build: Android is now a separate priv-app repo

The Android side is being rewritten as a platform-signed system app +
device owner (android_packages_apps_PawletProfiled) instead of a native
NDK Binder daemon -- most of what these payloads need on Android
(DevicePolicyManager, VpnManager, WifiManager, WallpaperManager, KeyChain)
is Java-SDK-first and awkward or impossible to reach cleanly from a
native process.

Drops: Android.bp, main_android.cpp, PawletProfileBinderService.*,
platform/android/*.cpp, aidl/, sepolicy/, third_party/openssl-android/,
pawletprofiled.rc/.xml. Also strips the now-dead __ANDROID__ branches from
SignatureVerifier/ProfileStore. This repo is Linux-only from here on.
This commit is contained in:
2026-07-25 01:34:22 -07:00
parent a86ad3298e
commit 6eeac176ae
39 changed files with 31 additions and 1319 deletions
-112
View File
@@ -1,112 +0,0 @@
// vendor/oxmc/pawletprofiled/Android.bp
// ─────────────────────────────────────────────────────────────────────────
// Drop this entire directory at vendor/oxmc/pawletprofiled/ and add
// "pawletprofiled" to PRODUCT_PACKAGES in your device makefile.
//
// m pawletprofiled — build the daemon
// m os.pawlet.profiled-V1-java — build Java stubs for system apps
// ─────────────────────────────────────────────────────────────────────────
// ── AIDL interface ────────────────────────────────────────────────────────
aidl_interface {
name: "os.pawlet.profiled",
srcs: ["aidl/os/pawlet/profiled/IPawletProfileService.aidl"],
stability: "vintf",
vendor_available: false,
backend: {
ndk: {
enabled: true,
},
java: {
enabled: true,
sdk_version: "system_current",
},
cpp: {
enabled: false,
},
},
versions: ["1"],
}
// ── Vendored OpenSSL (Android-only, static, this binary only) ─────────────
// See third_party/openssl-android/README.md — BoringSSL (the system
// libcrypto/libssl) has no CMS/PKCS#7 support, so SignatureVerifier.cpp
// links a private static copy instead of touching the platform's crypto
// libs. third_party/openssl-android/Android.bp is picked up automatically
// by Soong's normal recursive discovery — nothing to reference here beyond
// the module names ("libssl_pawlet_static" / "libcrypto_pawlet_static")
// used in static_libs below.
// ── Native daemon ─────────────────────────────────────────────────────────
//
// This file is the Android/Soong build only — the Linux/D-Bus build lives
// in CMakeLists.txt and is entirely separate. Accordingly the source list
// below is the Android-specific set: main_android.cpp (Binder entry point)
// and PawletProfileBinderService.cpp instead of main.cpp/PawletProfileService.cpp
// (D-Bus), and no ZTE client (it watches NetworkManager over D-Bus, which
// doesn't exist on Android — separate follow-up work, see main_android.cpp's
// header comment).
cc_binary {
name: "pawletprofiled",
srcs: [
"src/main_android.cpp",
"src/PawletProfileBinderService.cpp",
"src/ProfileParser.cpp",
"src/ProfileStore.cpp",
"src/SignatureVerifier.cpp",
"src/payloads/PayloadHandlers.cpp", // shared dispatch — see its header comment
"src/platform/android/Wifi.cpp",
"src/platform/android/Ethernet.cpp",
"src/platform/android/Vpn.cpp",
"src/platform/android/Cert.cpp",
"src/platform/android/Pkcs12.cpp",
"src/platform/android/Passcode.cpp",
"src/platform/android/Mdm.cpp",
"src/platform/android/SoftwareUpdate.cpp",
"src/platform/android/TimeServer.cpp",
"src/platform/android/Proxy.cpp",
"src/platform/android/DnsProxy.cpp",
"src/platform/android/Firewall.cpp",
"src/platform/android/Ldap.cpp",
"src/platform/android/Wallpaper.cpp",
"src/platform/android/Screensaver.cpp",
"src/platform/android/FirstBoot.cpp",
"src/platform/android/ContentCache.cpp",
],
shared_libs: [
"libbinder_ndk",
"libbase",
"liblog",
"os.pawlet.profiled-V1-ndk",
],
static_libs: [
"libyaml",
"libssl_pawlet_static",
"libcrypto_pawlet_static",
],
cflags: [
"-Wall",
"-Wextra",
"-Werror",
"-std=c++17",
],
init_rc: ["pawletprofiled.rc"],
vintf_fragments: ["pawletprofiled.xml"],
required: ["pawletprofiled_sepolicy"],
}
// ── SELinux policy shim ───────────────────────────────────────────────────
prebuilt_etc {
name: "pawletprofiled_sepolicy",
src: "sepolicy/pawletprofiled.te",
sub_dir: "selinux",
}
+20 -26
View File
@@ -1,8 +1,14 @@
# pawletprofiled
PawletOS unified device management daemon.
PawletOS's Linux device management daemon — a native root-run systemd
service. One binary, two subsystems.
One binary. Two subsystems. Ships on every PawletOS device.
This repo is Linux-only. The Android implementation is a separate,
independently-written app (platform-signed priv-app + device owner, not a
native daemon — most of what these payloads need on Android is Java-SDK
first): [`android_packages_apps_PawletProfiled`](https://git.oxmc.me/PawletOS/android_packages_apps_PawletProfiled).
Same `.vconfig` profile format and payload types on both platforms; no
shared code between the two implementations.
---
@@ -30,24 +36,21 @@ enrolls on the first successful connection later.
```
pawletprofiled/
├── Android.bp AOSP Soong build
├── CMakeLists.txt Linux CMake build
├── pawletprofiled.rc Android init script
├── pawletprofiled.xml Android VINTF fragment
├── zte.conf.example ZTE client config
├── aidl/os/pawlet/profiled/
│ └── IPawletProfileService.aidl Binder interface (Android)
├── src/
│ ├── main.cpp Entry point
│ ├── PawletProfileService.h/.cpp D-Bus service (Linux)
│ ├── PawletProfileService.h/.cpp D-Bus service
│ ├── ProfileParser.h/.cpp YAML parser (libyaml)
│ ├── ProfileStore.h/.cpp Disk persistence + password hashing
│ ├── SignatureVerifier.h/.cpp CMS/PKCS#7 verification (OpenSSL)
── payloads/
├── PayloadHandler.h Base class + handler registry
└── PayloadHandlers.cpp All 55 payload implementations
── payloads/
├── PayloadHandler.h Handler contract + PayloadUtil.h helpers
└── PayloadHandlers.cpp Dispatch — forwards to platform/linux/*.cpp
│ └── platform/
│ ├── <Name>.h Per-payload-type contract (apply/revert)
│ └── linux/<Name>.cpp One real implementation per payload type
├── src/zte/
│ ├── DeviceIdentity.h/.cpp Hardware identity collection
@@ -57,7 +60,6 @@ pawletprofiled/
├── systemd/pawletprofiled.service Systemd unit
├── dbus/os.pawlet.ProfiledService.conf D-Bus policy
├── apparmor/pawletprofiled AppArmor MAC profile
├── sepolicy/ Android SELinux policy
└── debian/ Debian Trixie packaging
```
@@ -113,20 +115,12 @@ sudo cmake --install build
---
## Building — Android (AOSP)
## Android
```bash
cp -r pawletprofiled/ $AOSP_ROOT/vendor/oxmc/pawletprofiled/
# Add to device makefile
echo 'PRODUCT_PACKAGES += pawletprofiled' \
>> device/oxmc/pawletos/pawletos.mk
echo 'BOARD_SEPOLICY_DIRS += vendor/oxmc/pawletprofiled/sepolicy' \
>> device/oxmc/pawletos/BoardConfig.mk
source build/envsetup.sh && lunch pawletos_arm64-userdebug
m pawletprofiled
```
Not built from this repo — see
[`android_packages_apps_PawletProfiled`](https://git.oxmc.me/PawletOS/android_packages_apps_PawletProfiled),
a platform-signed priv-app + device owner with its own independent
implementation of every payload type in this daemon's schema.
---
@@ -1,45 +0,0 @@
package os.pawlet.profiled;
// IPawletProfileService — Binder interface exposed by pawletprofiled.
// Clients (system apps, Settings, installer UI) talk to the daemon via this.
// NDK backend; link against libpawletprofiled-ndk.
@VintfStability
interface IPawletProfileService {
// ── Profile lifecycle ─────────────────────────────────────────────────
// Install a profile from raw YAML bytes (unsigned) or a CMS/PKCS#7
// blob (signed). Returns the installed profile's UUID on success.
// Throws ServiceSpecificException on validation or signature failure.
String installProfile(in byte[] profileData);
// Remove an installed profile by UUID.
// Throws if the profile is MDM-locked or removal-password protected
// and no password is supplied.
void removeProfile(in String uuid, in String removalPassword);
// List all installed profile UUIDs.
String[] listProfiles();
// Return JSON-encoded metadata for a single profile.
String getProfileInfo(in String uuid);
// ── MDM state ─────────────────────────────────────────────────────────
// True if a valid MDM payload is enrolled.
boolean isDeviceManaged();
// Return the enrolled MDM server URL, or empty string if not managed.
String getMdmServerUrl();
// ── Supervised / kiosk state ──────────────────────────────────────────
// True if a kiosk or ASAM payload is active.
boolean isSupervised();
// ── Payload query helpers ─────────────────────────────────────────────
// Return JSON array of payloads of the given type across all profiles.
// e.g. getPayloadsOfType("wifi") → [{ssid:..., uuid:...}, ...]
String getPayloadsOfType(in String payloadType);
}
-30
View File
@@ -1,30 +0,0 @@
# vendor/oxmc/pawletprofiled/pawletprofiled.rc
# ─────────────────────────────────────────────────────────────────────────
# Android init language script — starts pawletprofiled at boot.
# Placed in /system/etc/init/ by the build system via init_rc in Android.bp.
# ─────────────────────────────────────────────────────────────────────────
service pawletprofiled /system/bin/pawletprofiled
class main
user system
group system
# Capabilities needed to write to /data/system/pawletos/ and to
# call privileged Binder services (DevicePolicyManager, KeyChain, etc.)
capabilities SETUID SETGID
# Restart automatically if the daemon crashes.
restart_period 5
# SELinux domain (matches the type defined in pawletprofiled.te)
seclabel u:r:pawletprofiled:s0
# Only start once the filesystem is decrypted and /data is available.
on_property:vold.decrypt=trigger_restart_framework
# Create the data directory on first boot.
on post-fs-data
mkdir /data/system/pawletos 0700 system system
mkdir /data/system/pawletos/profiles 0700 system system
mkdir /data/system/pawletos/preinstalled 0700 system system
# content-cache payload's policy override — world-readable by design,
# PawletCacheService (a regular app UID) reads it directly. See
# PayloadHandlers.cpp's ContentCacheHandler and PolicyOverride.kt.
# PawletOS-fork-specific (see PayloadHandlers.cpp's header comment).
mkdir /data/misc/pawletcache 0755 system system
-14
View File
@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
vendor/oxmc/pawletprofiled/pawletprofiled.xml
VINTF compatibility matrix fragment.
Declares that this device provides the IPawletProfileService AIDL HAL.
Installed to /system/etc/vintf/manifest/ by the build system.
-->
<manifest version="1.0" type="device">
<hal format="aidl">
<name>os.pawlet.profiled</name>
<version>1</version>
<fqname>IPawletProfileService/default</fqname>
</hal>
</manifest>
-11
View File
@@ -1,11 +0,0 @@
# vendor/oxmc/pawletprofiled/sepolicy/file_contexts
# ─────────────────────────────────────────────────────────────────────────
# Maps filesystem paths to SELinux security contexts.
# Included automatically when BOARD_SEPOLICY_DIRS points here.
# ─────────────────────────────────────────────────────────────────────────
# Daemon binary
/system/bin/pawletprofiled u:object_r:pawletprofiled_exec:s0
# Profile data directory and all contents
/data/system/pawletos(/.*)? u:object_r:pawletprofiled_data_file:s0
-69
View File
@@ -1,69 +0,0 @@
# vendor/oxmc/pawletprofiled/sepolicy/pawletprofiled.te
# SELinux policy for the pawletprofiled system daemon (Android/AOSP).
#
# To activate, add to your device's BoardConfig.mk:
# BOARD_SEPOLICY_DIRS += vendor/oxmc/pawletprofiled/sepolicy
# ── Type declarations ──────────────────────────────────────────────────────
type pawletprofiled, domain;
type pawletprofiled_exec, exec_type, file_type, system_file_type;
type pawletprofiled_data_file, file_type, data_file_type;
type pawletprofiled_service, service_manager_type;
# ── Domain transition ──────────────────────────────────────────────────────
init_daemon_domain(pawletprofiled)
# ── Binder IPC ────────────────────────────────────────────────────────────
binder_use(pawletprofiled)
add_service(pawletprofiled, pawletprofiled_service)
# Allow system apps and shell to call into pawletprofiled via Binder
binder_call(system_app, pawletprofiled)
binder_call(shell, pawletprofiled)
# ── Profile data directory ────────────────────────────────────────────────
allow pawletprofiled pawletprofiled_data_file:dir { create search getattr setattr add_name remove_name };
allow pawletprofiled pawletprofiled_data_file:file { create open read write getattr setattr unlink rename };
# ── System file access (CA certs for signature chain validation) ──────────
allow pawletprofiled system_file:dir { search getattr };
allow pawletprofiled system_file:file { open read getattr };
# ── Network (ZTE HTTPS lookups) ───────────────────────────────────────────
allow pawletprofiled self:tcp_socket { create connect read write shutdown };
allow pawletprofiled self:udp_socket { create connect read write };
allow pawletprofiled port:tcp_socket name_connect;
# ── Logging ───────────────────────────────────────────────────────────────
allow pawletprofiled log_device:chr_file { open read write };
# ── System properties (ZTE state and MDM enrollment state) ───────────────
set_prop(pawletprofiled, pawletos_prop)
get_prop(pawletprofiled, pawletos_prop)
# ── DevicePolicyManager / KeyStore Binder calls ───────────────────────────
allow pawletprofiled device_policy_service:service_manager { find };
allow pawletprofiled keystore_service:service_manager { find };
binder_call(pawletprofiled, system_server)
binder_call(pawletprofiled, keystore)
# ── Process self-permissions ──────────────────────────────────────────────
allow pawletprofiled self:process { fork sigchld };
allow pawletprofiled self:unix_stream_socket { create connect read write };
# ── content-cache payload's policy override file (PawletOS-fork-specific) ──
# Type declared in android_packages_apps_PawletCache/sepolicy/pawlet_cache.te
# (both dirs land in BOARD_SEPOLICY_DIRS) — see ContentCacheHandler and
# PolicyOverride.kt for the read/write contract on this file.
allow pawletprofiled pawletcache_policy_file:dir { create search getattr add_name };
allow pawletprofiled pawletcache_policy_file:file create_file_perms;
-4
View File
@@ -1,4 +0,0 @@
# vendor/oxmc/pawletprofiled/sepolicy/property_contexts
# Declares the persist.pawletos.* property namespace.
persist.pawletos. u:object_r:pawletos_prop:s0
-6
View File
@@ -1,6 +0,0 @@
# vendor/oxmc/pawletprofiled/sepolicy/service_contexts
# Maps the Binder service name to its SELinux type.
# This is what allows AServiceManager_addService / getService to work
# under SELinux enforcement.
os.pawlet.profiled.IPawletProfileService/default u:object_r:pawletprofiled_service:s0
-322
View File
@@ -1,322 +0,0 @@
#include "PawletProfileBinderService.h"
#include "payloads/PayloadHandler.h"
#include <cstring>
#include <sstream>
#include <syslog.h>
namespace pawletos::profile {
using ::ndk::ScopedAStatus;
// Service-specific error codes returned via ScopedAStatus — mirrors
// PawletProfileService's D-Bus error domain (kErrNotFound etc.) one-for-one
// so a future shared client-side error mapping stays simple.
namespace {
constexpr int kErrNotFound = 1;
constexpr int kErrSignature = 2;
constexpr int kErrParse = 3;
constexpr int kErrLocked = 4;
constexpr int kErrWrongPassword = 5;
constexpr int kErrSigningRequired = 6;
} // namespace
ScopedAStatus PawletProfileBinderService::serviceError(const char* name, const std::string& message) {
syslog(LOG_WARNING, "pawletprofiled: %s: %s", name, message.c_str());
int code = 0;
if (strcmp(name, "NotFound") == 0) code = kErrNotFound;
else if (strcmp(name, "Signature") == 0) code = kErrSignature;
else if (strcmp(name, "Parse") == 0) code = kErrParse;
else if (strcmp(name, "Locked") == 0) code = kErrLocked;
else if (strcmp(name, "WrongPassword") == 0) code = kErrWrongPassword;
else if (strcmp(name, "SigningRequired") == 0) code = kErrSigningRequired;
return ScopedAStatus::fromServiceSpecificErrorWithMessage(code, message.c_str());
}
PawletProfileBinderService::PawletProfileBinderService() {
syslog(LOG_INFO, "pawletprofiled: Binder service starting");
mStore.load();
}
// ── installProfileDirect (preinstalled profiles, same as D-Bus version) ────
bool PawletProfileBinderService::installProfileDirect(
const std::vector<uint8_t>& profileData, std::string& outUuid) {
std::lock_guard<std::mutex> lock(mLock);
std::vector<uint8_t> yamlBytes;
bool isSigned = false;
SignatureVerifier::TrustLevel trust = SignatureVerifier::TrustLevel::UNSIGNED;
if (mVerifier.isCmsWrapped(profileData)) {
auto result = mVerifier.verify(profileData, yamlBytes);
if (result == SignatureVerifier::VerifyResult::INVALID) {
syslog(LOG_ERR, "[installProfileDirect] signature invalid");
return false;
}
isSigned = true;
trust = (result == SignatureVerifier::VerifyResult::TRUSTED)
? SignatureVerifier::TrustLevel::TRUSTED
: SignatureVerifier::TrustLevel::UNVERIFIED;
} else {
yamlBytes = profileData;
}
ParsedProfile profile;
if (!mParser.parse(yamlBytes, profile)) {
syslog(LOG_ERR, "[installProfileDirect] parse failed");
return false;
}
ParsedProfile existing;
if (mStore.load(profile.uuid, existing)) {
syslog(LOG_INFO, "[installProfileDirect] already installed uuid=%s, skipping",
profile.uuid.c_str());
outUuid = profile.uuid;
return true;
}
for (const auto& payload : profile.payloads) {
bool sigRequired =
payload.type == "mdm" ||
payload.type == "removal-password" ||
payload.type == "kiosk" ||
payload.type == "asam";
if (sigRequired && !isSigned) {
syslog(LOG_ERR, "[installProfileDirect] type=%s requires signed profile",
payload.type.c_str());
return false;
}
}
profile.trustLevel = trust;
if (!mStore.save(profile)) {
syslog(LOG_ERR, "[installProfileDirect] save failed uuid=%s", profile.uuid.c_str());
return false;
}
applyProfile(profile);
outUuid = profile.uuid;
syslog(LOG_INFO, "[installProfileDirect] installed uuid=%s", profile.uuid.c_str());
return true;
}
// ── installProfile ──────────────────────────────────────────────────────
ScopedAStatus PawletProfileBinderService::installProfile(
const std::vector<uint8_t>& in_profileData, std::string* _aidl_return) {
std::lock_guard<std::mutex> lock(mLock);
std::vector<uint8_t> yamlBytes;
bool isSigned = false;
SignatureVerifier::TrustLevel trust = SignatureVerifier::TrustLevel::UNSIGNED;
if (mVerifier.isCmsWrapped(in_profileData)) {
auto result = mVerifier.verify(in_profileData, yamlBytes);
if (result == SignatureVerifier::VerifyResult::INVALID) {
return serviceError("Signature", "Profile signature is invalid or tampered.");
}
isSigned = true;
trust = (result == SignatureVerifier::VerifyResult::TRUSTED)
? SignatureVerifier::TrustLevel::TRUSTED
: SignatureVerifier::TrustLevel::UNVERIFIED;
} else {
yamlBytes = in_profileData;
}
ParsedProfile profile;
if (!mParser.parse(yamlBytes, profile)) {
return serviceError("Parse", "Profile YAML is malformed or schema-invalid.");
}
for (const auto& payload : profile.payloads) {
bool sigRequired =
payload.type == "mdm" ||
payload.type == "removal-password" ||
payload.type == "kiosk" ||
payload.type == "asam";
if (sigRequired && !isSigned) {
return serviceError("SigningRequired",
"Payload type '" + payload.type + "' requires a signed profile.");
}
}
profile.trustLevel = trust;
if (!mStore.save(profile)) {
return serviceError("Parse", "Failed to persist profile.");
}
applyProfile(profile);
syslog(LOG_INFO, "pawletprofiled: installed profile uuid=%s", profile.uuid.c_str());
*_aidl_return = profile.uuid;
return ScopedAStatus::ok();
}
// ── removeProfile ────────────────────────────────────────────────────────
ScopedAStatus PawletProfileBinderService::removeProfile(
const std::string& in_uuid, const std::string& in_removalPassword) {
std::lock_guard<std::mutex> lock(mLock);
ParsedProfile profile;
if (!mStore.load(in_uuid, profile)) {
return serviceError("NotFound", "Profile not found: " + in_uuid);
}
if (profile.lifecycle.removal == "locked") {
return serviceError("Locked", "This profile can only be removed by the MDM server.");
}
if (profile.lifecycle.removal == "password") {
if (in_removalPassword.empty() || !mStore.checkRemovalPassword(in_uuid, in_removalPassword)) {
return serviceError("WrongPassword", "Incorrect removal password.");
}
}
revertProfile(profile);
mStore.remove(in_uuid);
syslog(LOG_INFO, "pawletprofiled: removed profile uuid=%s", in_uuid.c_str());
return ScopedAStatus::ok();
}
// ── listProfiles ─────────────────────────────────────────────────────────
ScopedAStatus PawletProfileBinderService::listProfiles(std::vector<std::string>* _aidl_return) {
std::lock_guard<std::mutex> lock(mLock);
*_aidl_return = mStore.listUuids();
return ScopedAStatus::ok();
}
// ── getProfileInfo ───────────────────────────────────────────────────────
ScopedAStatus PawletProfileBinderService::getProfileInfo(
const std::string& in_uuid, std::string* _aidl_return) {
std::lock_guard<std::mutex> lock(mLock);
ParsedProfile profile;
if (!mStore.load(in_uuid, profile)) {
return serviceError("NotFound", "Not found: " + in_uuid);
}
std::ostringstream j;
j << "{"
<< "\"uuid\":\"" << profile.uuid << "\","
<< "\"id\":\"" << profile.id << "\","
<< "\"name\":\"" << profile.meta.name << "\","
<< "\"organization\":\"" << profile.meta.organization << "\","
<< "\"scope\":\"" << profile.scope << "\","
<< "\"removal\":\"" << profile.lifecycle.removal << "\","
<< "\"trusted\":" << (profile.trustLevel != SignatureVerifier::TrustLevel::UNSIGNED ? "true" : "false") << ","
<< "\"payloadCount\":" << profile.payloads.size()
<< "}";
*_aidl_return = j.str();
return ScopedAStatus::ok();
}
// ── isDeviceManaged ──────────────────────────────────────────────────────
ScopedAStatus PawletProfileBinderService::isDeviceManaged(bool* _aidl_return) {
std::lock_guard<std::mutex> lock(mLock);
bool managed = false;
for (const auto& uuid : mStore.listUuids()) {
ParsedProfile p;
if (mStore.load(uuid, p))
for (const auto& pl : p.payloads)
if (pl.type == "mdm") { managed = true; break; }
if (managed) break;
}
*_aidl_return = managed;
return ScopedAStatus::ok();
}
// ── getMdmServerUrl ──────────────────────────────────────────────────────
ScopedAStatus PawletProfileBinderService::getMdmServerUrl(std::string* _aidl_return) {
std::lock_guard<std::mutex> lock(mLock);
std::string url;
for (const auto& uuid : mStore.listUuids()) {
ParsedProfile p;
if (!mStore.load(uuid, p)) continue;
for (const auto& pl : p.payloads) {
if (pl.type == "mdm") {
auto it = pl.fields.find("server-url");
if (it != pl.fields.end()) url = it->second;
if (url.size() >= 2 && url.front() == '"') url = url.substr(1, url.size() - 2);
break;
}
}
if (!url.empty()) break;
}
*_aidl_return = url;
return ScopedAStatus::ok();
}
// ── isSupervised ─────────────────────────────────────────────────────────
ScopedAStatus PawletProfileBinderService::isSupervised(bool* _aidl_return) {
std::lock_guard<std::mutex> lock(mLock);
bool supervised = false;
for (const auto& uuid : mStore.listUuids()) {
ParsedProfile p;
if (!mStore.load(uuid, p)) continue;
for (const auto& pl : p.payloads)
if (pl.type == "kiosk" || pl.type == "asam") { supervised = true; break; }
if (supervised) break;
}
*_aidl_return = supervised;
return ScopedAStatus::ok();
}
// ── getPayloadsOfType ────────────────────────────────────────────────────
ScopedAStatus PawletProfileBinderService::getPayloadsOfType(
const std::string& in_payloadType, std::string* _aidl_return) {
std::lock_guard<std::mutex> lock(mLock);
std::ostringstream j;
j << "[";
bool first = true;
for (const auto& uuid : mStore.listUuids()) {
ParsedProfile p;
if (!mStore.load(uuid, p)) continue;
for (const auto& pl : p.payloads) {
if (pl.type != in_payloadType) continue;
if (!first) j << ",";
first = false;
j << "{\"profileUuid\":\"" << p.uuid << "\","
<< "\"payloadUuid\":\"" << pl.uuid << "\"";
for (const auto& [k, v] : pl.fields)
j << ",\"" << k << "\":" << v;
j << "}";
}
}
j << "]";
*_aidl_return = j.str();
return ScopedAStatus::ok();
}
// ── applyProfile / revertProfile ─────────────────────────────────────────
void PawletProfileBinderService::applyProfile(const ParsedProfile& profile) {
for (const auto& payload : profile.payloads) {
auto* handler = PayloadHandlerRegistry::get(payload.type);
if (handler) {
if (!handler->apply(payload))
syslog(LOG_WARNING, "pawletprofiled: handler failed type=%s uuid=%s",
payload.type.c_str(), payload.uuid.c_str());
} else {
syslog(LOG_WARNING, "pawletprofiled: no handler for type=%s", payload.type.c_str());
}
}
}
void PawletProfileBinderService::revertProfile(const ParsedProfile& profile) {
for (auto it = profile.payloads.rbegin(); it != profile.payloads.rend(); ++it) {
auto* handler = PayloadHandlerRegistry::get(it->type);
if (handler) handler->revert(*it);
}
}
} // namespace pawletos::profile
-57
View File
@@ -1,57 +0,0 @@
#pragma once
#include "ProfileParser.h"
#include "ProfileStore.h"
#include "SignatureVerifier.h"
#include <aidl/os/pawlet/profiled/BnPawletProfileService.h>
#include <mutex>
#include <string>
#include <vector>
namespace pawletos::profile {
// ── Android Binder counterpart to PawletProfileService (D-Bus) ─────────────
// Same install/remove/query logic, same ProfileStore/ProfileParser/
// PayloadHandlerRegistry underneath — only the transport differs. See
// main_android.cpp for how this gets registered with servicemanager.
//
// Registered service name: "os.pawlet.profiled.IPawletProfileService/default"
// (must match pawletprofiled.xml's VINTF fragment and sepolicy/service_contexts).
class PawletProfileBinderService
: public aidl::me::oxmc::pawletos::profile::BnPawletProfileService {
public:
PawletProfileBinderService();
// Same direct-install path PawletProfileService exposes for main.cpp's
// preinstalled-profile loader — see applyPreinstalledProfiles() in
// main_android.cpp.
bool installProfileDirect(const std::vector<uint8_t>& data, std::string& outUuid);
::ndk::ScopedAStatus installProfile(
const std::vector<uint8_t>& in_profileData, std::string* _aidl_return) override;
::ndk::ScopedAStatus removeProfile(
const std::string& in_uuid, const std::string& in_removalPassword) override;
::ndk::ScopedAStatus listProfiles(std::vector<std::string>* _aidl_return) override;
::ndk::ScopedAStatus getProfileInfo(
const std::string& in_uuid, std::string* _aidl_return) override;
::ndk::ScopedAStatus isDeviceManaged(bool* _aidl_return) override;
::ndk::ScopedAStatus getMdmServerUrl(std::string* _aidl_return) override;
::ndk::ScopedAStatus isSupervised(bool* _aidl_return) override;
::ndk::ScopedAStatus getPayloadsOfType(
const std::string& in_payloadType, std::string* _aidl_return) override;
private:
void applyProfile(const ParsedProfile& profile);
void revertProfile(const ParsedProfile& profile);
static ::ndk::ScopedAStatus serviceError(const char* name, const std::string& message);
std::mutex mLock;
ProfileStore mStore;
ProfileParser mParser;
SignatureVerifier mVerifier;
};
} // namespace pawletos::profile
+4 -11
View File
@@ -18,21 +18,14 @@ namespace pawletos::profile {
// meta.json install time, trust level, payload count
// removal_hash.bin PBKDF2-SHA256 hash of removal password (if set)
//
// Android's path matches what pawletprofiled.rc already mkdir's at
// post-fs-data and what sepolicy/file_contexts already labels
// pawletprofiled_data_file — see android_packages_apps_PawletCache's
// equivalent PolicyOverride.kt contract for the analogous device-side path.
#if defined(__ANDROID__)
static constexpr const char* kProfilesDir =
"/data/system/pawletos/profiles";
static constexpr const char* kIndexFile =
"/data/system/pawletos/profiles/index.json";
#else
// The Android implementation (git.oxmc.me/PawletOS/android_packages_apps_PawletProfiled's
// ProfileStore.kt) uses the same /data/system/pawletos/profiles path and
// on-disk layout, for whatever a shared UUID/profile means across both
// platforms — but it's an independent implementation, not shared code.
static constexpr const char* kProfilesDir =
"/var/lib/pawletprofiled/profiles";
static constexpr const char* kIndexFile =
"/var/lib/pawletprofiled/profiles/index.json";
#endif
class ProfileStore {
public:
+7 -12
View File
@@ -1,12 +1,12 @@
#include "SignatureVerifier.h"
// AOSP's system libcrypto/libssl is BoringSSL, which has no CMS/PKCS#7
// support — so this file links against a vendored, statically-linked real
// OpenSSL on Android instead of the system one (see
// third_party/openssl-android/ and Android.bp's Android-target static_libs).
// The Linux build (CMakeLists.txt) links Debian's system OpenSSL the normal
// way. Either way, the code below is the same real CMS_verify() — no
// platform split needed here, only at the link-config level.
// Links Debian's system OpenSSL (libcrypto/libssl) for real CMS_verify().
// The Android implementation lives in a separate app now
// (git.oxmc.me/PawletOS/android_packages_apps_PawletProfiled's
// SignatureVerifier.kt, via Bouncy Castle — BoringSSL has no CMS/PKCS#7
// support, the same gap that used to be solved here by vendoring a static
// OpenSSL for the Android build; a pure-Java CMS library sidesteps that
// entirely instead).
#include <openssl/cms.h>
#include <openssl/err.h>
#include <openssl/pem.h>
@@ -43,13 +43,8 @@ static StorePtr buildTrustStore() {
X509_STORE* store = X509_STORE_new();
if (!store) return nullptr;
#if defined(__ANDROID__)
// AOSP's cacerts dir is CApath-style (hash-named PEM files), not one bundle.
X509_STORE_load_locations(store, nullptr, SignatureVerifier::kTrustStorePath);
#else
// Debian's ca-certificates.crt is a single CAfile bundle.
X509_STORE_load_locations(store, SignatureVerifier::kTrustStorePath, nullptr);
#endif
// Load PawletOS profile signing CA if installed
struct stat st{};
-12
View File
@@ -25,24 +25,12 @@ public:
VerifyResult verify(const std::vector<uint8_t>& cmsData,
std::vector<uint8_t>& outPayload);
#if defined(__ANDROID__)
// AOSP's system CA store is a *directory* of hash-named PEM files
// (c_rehash layout), not one bundle file — buildTrustStore() loads it
// via X509_STORE's CApath, not CAfile. See SignatureVerifier.cpp.
static constexpr const char* kTrustStorePath =
"/system/etc/security/cacerts";
// PawletOS profile signing CA (optional) — writable partition, covered
// by sepolicy's pawletprofiled_data_file type.
static constexpr const char* kPawletCaPath =
"/data/system/pawletos/profile_ca.pem";
#else
// System CA trust bundle
static constexpr const char* kTrustStorePath =
"/etc/ssl/certs/ca-certificates.crt";
// PawletOS profile signing CA (optional; installed by the pawletos-ca package)
static constexpr const char* kPawletCaPath =
"/etc/pawletprofiled/profile_ca.pem";
#endif
};
} // namespace pawletos::profile
-96
View File
@@ -1,96 +0,0 @@
#include "PawletProfileBinderService.h"
#include "payloads/PayloadHandler.h"
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <dirent.h>
#include <fstream>
#include <sstream>
#include <sys/stat.h>
#include <syslog.h>
// ─────────────────────────────────────────────────────────────────────────
// pawletprofiled — Android entry point
//
// Counterpart to main.cpp (Linux/D-Bus). Registers PawletProfileBinderService
// as "os.pawlet.profiled.IPawletProfileService/default" — the exact
// name pawletprofiled.xml's VINTF fragment and sepolicy/service_contexts
// already declare — and applies preinstalled profiles the same way
// main.cpp does, from an Android-appropriate path.
//
// Not ported here: the ZTE ConnectivityWatcher (main.cpp's background
// thread) — it watches NetworkManager over D-Bus, which doesn't exist on
// Android. Zero-touch enrollment on PawletOS is separate follow-up work,
// not silently dropped-but-unmentioned.
// ─────────────────────────────────────────────────────────────────────────
static constexpr const char* kPreinstalledDir =
"/data/system/pawletos/preinstalled";
static bool fileExists(const std::string& path) {
struct stat st{};
return ::stat(path.c_str(), &st) == 0;
}
static void applyPreinstalledProfiles(pawletos::profile::PawletProfileBinderService& svc) {
DIR* d = opendir(kPreinstalledDir);
if (!d) return;
syslog(LOG_INFO, "pawletprofiled: scanning %s for preinstalled profiles", kPreinstalledDir);
struct dirent* ent;
while ((ent = readdir(d)) != nullptr) {
std::string name = ent->d_name;
if (name == "." || name == "..") continue;
if (name.find(".vconfig") == std::string::npos) continue;
std::string path = std::string(kPreinstalledDir) + "/" + name;
std::ifstream f(path, std::ios::binary);
if (!f) {
syslog(LOG_WARNING, "pawletprofiled: cannot read %s", path.c_str());
continue;
}
std::ostringstream buf;
buf << f.rdbuf();
std::string content = buf.str();
std::vector<uint8_t> data(content.begin(), content.end());
std::string uuid;
bool ok = svc.installProfileDirect(data, uuid);
if (ok)
syslog(LOG_INFO, "pawletprofiled: preinstalled %s -> uuid=%s", name.c_str(), uuid.c_str());
else
syslog(LOG_WARNING, "pawletprofiled: failed to apply %s", name.c_str());
}
closedir(d);
}
int main() {
openlog("pawletprofiled", LOG_PID | LOG_CONS, LOG_DAEMON);
syslog(LOG_INFO, "pawletprofiled starting (Android/Binder)");
pawletos::profile::PayloadHandlerRegistry::registerAll();
auto service = ndk::SharedRefBase::make<pawletos::profile::PawletProfileBinderService>();
if (fileExists(kPreinstalledDir)) {
applyPreinstalledProfiles(*service);
}
const char* instanceName = "os.pawlet.profiled.IPawletProfileService/default";
binder_status_t status = AServiceManager_addService(service->asBinder().get(), instanceName);
if (status != STATUS_OK) {
syslog(LOG_ERR, "pawletprofiled: AServiceManager_addService failed: %d", status);
return 1;
}
syslog(LOG_INFO, "pawletprofiled: registered as %s", instanceName);
ABinderProcess_setThreadPoolMaxThreadCount(4);
ABinderProcess_startThreadPool();
ABinderProcess_joinThreadPool(); // blocks forever
syslog(LOG_INFO, "pawletprofiled stopped");
closelog();
return 0;
}
-20
View File
@@ -1,20 +0,0 @@
#include "../Cert.h"
#include <syslog.h>
// Not yet implemented on Android. A real port needs DevicePolicyManager's
// installCaCert() (device-owner) or the KeyChain install-cert intent flow —
// AOSP has no /etc/ssl/certs-equivalent a daemon can just write files into.
namespace pawletos::profile::platform::cert {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[cert] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[cert] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::cert
-52
View File
@@ -1,52 +0,0 @@
#include "../ContentCache.h"
#include "../../payloads/PayloadUtil.h"
#include <sstream>
#include <syslog.h>
// ═══════════════════════════════════════════════════════════════════════════
// CONTENT CACHE HANDLER (Android)
// PawletOS-fork-specific — pawletprofiled's default PawletOS build doesn't
// register this handler at all (see PayloadHandlers.cpp). Writes the
// local-network-cache discovery override PawletCacheService reads — see
// pawletcache-server/README.md and
// android_packages_apps_PawletCache/src/os/pawlet/cache/PolicyOverride.kt.
// ═══════════════════════════════════════════════════════════════════════════
namespace pawletos::profile::platform::content_cache {
using namespace pawletos::profile::util;
namespace {
constexpr const char* kPolicyDir = "/data/misc/pawletcache";
constexpr const char* kPolicyFile = "/data/misc/pawletcache/policy.json";
}
bool apply(const ParsedPayload& p) {
std::string mode = field(p, "mode", "both");
std::ostringstream json;
json << "{\n \"mode\": \"" << mode << "\"";
auto pinned = p.fields.find("pinned-server");
if (pinned != p.fields.end()) {
// Already valid JSON text (ProfileParser re-serializes nested
// objects) — relay it verbatim under the camelCase key
// PolicyOverride.kt expects, no reparsing needed here.
json << ",\n \"pinnedServer\": " << pinned->second;
}
json << "\n}\n";
ensureDir(kPolicyDir);
// World-readable by design — PawletCacheService reads this as a
// regular app UID, and it's policy, not a secret (see PolicyOverride.kt).
writeFile(kPolicyFile, json.str(), 0644);
syslog(LOG_INFO, "[content-cache] applied mode=%s", mode.c_str());
return true;
}
void revert(const ParsedPayload& /*p*/) {
removeFile(kPolicyFile);
}
} // namespace pawletos::profile::platform::content_cache
-20
View File
@@ -1,20 +0,0 @@
#include "../DnsProxy.h"
#include <syslog.h>
// Not yet implemented on Android. A real port would write
// Settings.Global.PRIVATE_DNS_MODE / PRIVATE_DNS_SPECIFIER (needs
// WRITE_SECURE_SETTINGS) — no systemd-resolved.conf.d equivalent.
namespace pawletos::profile::platform::dns_proxy {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[dns-proxy] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[dns-proxy] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::dns_proxy
-19
View File
@@ -1,19 +0,0 @@
#include "../Ethernet.h"
#include <syslog.h>
// Not yet implemented on Android. A real port would use the hidden/system
// android.net.EthernetManager API — no NetworkManager equivalent exists.
namespace pawletos::profile::platform::ethernet {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[ethernet] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[ethernet] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::ethernet
-20
View File
@@ -1,20 +0,0 @@
#include "../Firewall.h"
#include <syslog.h>
// Not yet implemented on Android. There's no nftables/nft CLI on stock
// AOSP — a real port would need NetworkPolicyManager rules or a local
// VpnService-based firewall, a fundamentally different mechanism.
namespace pawletos::profile::platform::firewall {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[firewall] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[firewall] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::firewall
-20
View File
@@ -1,20 +0,0 @@
#include "../FirstBoot.h"
#include <syslog.h>
// Not yet implemented on Android. A real port would suppress AOSP's
// SetupWizard (Settings.Global DEVICE_PROVISIONED / USER_SETUP_COMPLETE) —
// no cloud-init/GNOME Initial Setup equivalent here.
namespace pawletos::profile::platform::first_boot {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[first-boot] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[first-boot] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::first_boot
-21
View File
@@ -1,21 +0,0 @@
#include "../Ldap.h"
#include <syslog.h>
// Not yet implemented on Android — and likely never will be as a direct
// port. Android has no system LDAP client at all (no nslcd/libnss-ldapd
// equivalent); this payload type doesn't map onto anything the platform
// exposes. Logged for visibility rather than silently accepted.
namespace pawletos::profile::platform::ldap {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[ldap] not supported on Android (no system LDAP client), uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[ldap] not supported on Android (no system LDAP client), uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::ldap
-20
View File
@@ -1,20 +0,0 @@
#include "../Mdm.h"
#include <syslog.h>
// Not yet implemented on Android. A real port needs Android's own
// device-owner/EMM provisioning flow (DevicePolicyManager), a fundamentally
// different enrollment model than cloud-init drop-ins.
namespace pawletos::profile::platform::mdm {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[mdm] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[mdm] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::mdm
-20
View File
@@ -1,20 +0,0 @@
#include "../Passcode.h"
#include <syslog.h>
// Not yet implemented on Android. A real port needs
// DevicePolicyManager.setPasswordQuality()/setPasswordMinimumLength() etc
// (device-owner) — no pam_pwquality-equivalent config file to write.
namespace pawletos::profile::platform::passcode {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[passcode] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[passcode] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::passcode
-20
View File
@@ -1,20 +0,0 @@
#include "../Pkcs12.h"
#include <syslog.h>
// Not yet implemented on Android. A real port needs
// DevicePolicyManager.installKeyPair() (device-owner) — no system NSSDB
// equivalent a daemon can write a .p12 into directly.
namespace pawletos::profile::platform::pkcs12 {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[pkcs12] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[pkcs12] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::pkcs12
-20
View File
@@ -1,20 +0,0 @@
#include "../Proxy.h"
#include <syslog.h>
// Not yet implemented on Android. A real port would use
// DevicePolicyManager.setRecommendedGlobalProxy()/ProxyInfo (device-owner) —
// no /etc/environment-equivalent to write.
namespace pawletos::profile::platform::proxy {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[proxy] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[proxy] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::proxy
-21
View File
@@ -1,21 +0,0 @@
#include "../Screensaver.h"
#include <syslog.h>
// Not yet implemented on Android. A real port would map to Daydream
// (Settings.Secure SCREENSAVER_ENABLED / SCREENSAVER_COMPONENTS) plus
// Settings.System SCREEN_OFF_TIMEOUT for the idle delay — no dconf profile
// to write.
namespace pawletos::profile::platform::screensaver {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[screensaver] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[screensaver] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::screensaver
-22
View File
@@ -1,22 +0,0 @@
#include "../SoftwareUpdate.h"
#include <syslog.h>
// Not yet implemented on Android. PawletOS already has a dedicated update
// policy path — BgUpd's install_mode ("silent"/"manual" per component, see
// android_packages_apps_BgUpd) — a real port would translate this payload's
// automatic/deferral fields into BgUpd's manifest/policy rather than apt
// settings, which don't apply here at all.
namespace pawletos::profile::platform::software_update {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[software-update] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[software-update] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::software_update
-20
View File
@@ -1,20 +0,0 @@
#include "../TimeServer.h"
#include <syslog.h>
// Not yet implemented on Android. A real port would write
// Settings.Global.NTP_SERVER (requires WRITE_SECURE_SETTINGS, same
// permission pattern BgUpd already holds for its own settings writes).
namespace pawletos::profile::platform::time_server {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[time-server] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[time-server] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::time_server
-21
View File
@@ -1,21 +0,0 @@
#include "../Vpn.h"
#include <syslog.h>
// Not yet implemented on Android. A real port needs an android.net.VpnService
// component (IKEv2/L2TP have no NetworkManager-plugin equivalent on Android;
// this would mean shipping a companion VPN app or a system VpnService, not
// just writing a config file).
namespace pawletos::profile::platform::vpn {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[vpn] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[vpn] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::vpn
-20
View File
@@ -1,20 +0,0 @@
#include "../Wallpaper.h"
#include <syslog.h>
// Not yet implemented on Android. A real port would use
// android.app.WallpaperManager (setStream/setResource) — no dconf profile
// to write.
namespace pawletos::profile::platform::wallpaper {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[wallpaper] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[wallpaper] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::wallpaper
-20
View File
@@ -1,20 +0,0 @@
#include "../Wifi.h"
#include <syslog.h>
// Not yet implemented on Android. A real port needs WifiManager /
// WifiNetworkSuggestion (API 29+) or a privileged wpa_supplicant config
// write — NetworkManager keyfiles (the Linux implementation) don't apply.
namespace pawletos::profile::platform::wifi {
bool apply(const ParsedPayload& p) {
syslog(LOG_WARNING, "[wifi] not implemented on Android yet, uuid=%s", p.uuid.c_str());
return false;
}
void revert(const ParsedPayload& p) {
syslog(LOG_WARNING, "[wifi] not implemented on Android yet, uuid=%s", p.uuid.c_str());
}
} // namespace pawletos::profile::platform::wifi
-32
View File
@@ -1,32 +0,0 @@
//
// Vendored, statically-linked real OpenSSL — pawletprofiled's Android build
// only, nothing else on the system links against these. See README.md for
// why (BoringSSL has no CMS support) and how to populate lib/*/*.a.
//
cc_prebuilt_library_static {
name: "libcrypto_pawlet_static",
arch: {
arm64: { srcs: ["lib/arm64-v8a/libcrypto.a"] },
arm: { srcs: ["lib/armeabi-v7a/libcrypto.a"] },
x86_64: { srcs: ["lib/x86_64/libcrypto.a"] },
x86: { srcs: ["lib/x86/libcrypto.a"] },
},
export_include_dirs: ["include"],
strip: { none: true },
}
cc_prebuilt_library_static {
name: "libssl_pawlet_static",
arch: {
arm64: { srcs: ["lib/arm64-v8a/libssl.a"] },
arm: { srcs: ["lib/armeabi-v7a/libssl.a"] },
x86_64: { srcs: ["lib/x86_64/libssl.a"] },
x86: { srcs: ["lib/x86/libssl.a"] },
},
export_include_dirs: ["include"],
strip: { none: true },
// libssl depends on libcrypto symbols; Soong needs this to order the
// static link correctly.
whole_static_libs: ["libcrypto_pawlet_static"],
}
-79
View File
@@ -1,79 +0,0 @@
# Vendored OpenSSL (Android, static, pawletprofiled-only)
AOSP's system `libcrypto`/`libssl` is BoringSSL, which has no CMS/PKCS#7
support. Rather than touch the platform's crypto stack (used by Keystore,
the TLS stack, other HALs — swapping it breaks far more than it fixes),
pawletprofiled statically links its **own** copy of real OpenSSL, scoped to
just this one binary. Nothing else on the system links against it or even
knows it's there.
This directory holds the prebuilt static libs + headers and the Soong
modules that expose them. **The `lib/*/` and `include/` directories are
empty placeholders** — populate them by cross-compiling OpenSSL yourself
(steps below) before `m pawletprofiled` will link on Android. Nothing here
fabricates or ships a prebuilt binary sight-unseen.
---
## Building OpenSSL for Android
Needs the Android NDK (r26+) on your PATH as `$ANDROID_NDK_ROOT`, and
OpenSSL source (3.x recommended — CMS support is stable there).
```bash
git clone --branch openssl-3.2 --depth 1 https://github.com/openssl/openssl.git
cd openssl
export ANDROID_NDK_ROOT=/path/to/android-ndk
export PATH="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH"
# Repeat per ABI. android-arm64 shown; swap target/API for the others.
for target in android-arm64 android-arm android-x86_64 android-x86; do
case $target in
android-arm64) abi=arm64-v8a ;;
android-arm) abi=armeabi-v7a ;;
android-x86_64) abi=x86_64 ;;
android-x86) abi=x86 ;;
esac
./Configure "$target" -D__ANDROID_API__=26 no-shared no-tests \
--prefix="$(pwd)/build-$abi"
make clean
make -j"$(nproc)"
make install_sw
mkdir -p "../lib/$abi"
cp "build-$abi/lib/libcrypto.a" "../lib/$abi/"
cp "build-$abi/lib/libssl.a" "../lib/$abi/"
done
# Headers are identical across ABIs — copy from any one build.
cp -r build-arm64-v8a/include/openssl ../include/
```
`no-shared` is what makes these static (`.a`) — deliberate, so nothing
depends on an OpenSSL `.so` being present on-device at runtime. `no-tests`
just skips building OpenSSL's own test suite to save time.
## Verifying
```
third_party/openssl-android/
├── include/openssl/*.h (same for every ABI)
└── lib/
├── arm64-v8a/{libcrypto,libssl}.a
├── armeabi-v7a/{libcrypto,libssl}.a
├── x86_64/{libcrypto,libssl}.a
└── x86/{libcrypto,libssl}.a
```
Once populated, `m pawletprofiled` picks these up via `Android.bp` in this
directory — see `libcrypto_pawlet_static` / `libssl_pawlet_static` /
`pawletprofiled_openssl_headers`, referenced from
`pawletprofiled/Android.bp`'s Android `static_libs`.
## Updating
OpenSSL ships security fixes regularly — treat these `.a` files as a
dependency you're responsible for rebuilding on new releases, same as any
other vendored library. Nothing here auto-updates them.
-1
View File
@@ -1 +0,0 @@
Not populated. Copy the openssl/ header directory from any one ABI build per ../README.md — headers are identical across ABIs.
@@ -1 +0,0 @@
Not populated. Build libcrypto.a and libssl.a for arm64-v8a per ../../README.md and drop them in this directory.
@@ -1 +0,0 @@
Not populated. Build libcrypto.a and libssl.a for armeabi-v7a per ../../README.md and drop them in this directory.
-1
View File
@@ -1 +0,0 @@
Not populated. Build libcrypto.a and libssl.a for x86 per ../../README.md and drop them in this directory.
@@ -1 +0,0 @@
Not populated. Build libcrypto.a and libssl.a for x86_64 per ../../README.md and drop them in this directory.