From ec3e75de5d7981ba926acfb1a7c6a8249a3d2b68 Mon Sep 17 00:00:00 2001
From: oxmc <67136658+oxmc@users.noreply.github.com>
Date: Fri, 12 Jun 2026 20:02:46 -0700
Subject: [PATCH] frameworks_pawlet: add PawletManager service + clean up APIs
Add IPawletManager AIDL interface, PawletManager client wrapper, and
PawletManagerService implementation. The service is hosted by a
privileged system app which calls:
ServiceManager.addService(PawletManager.SERVICE_NAME, new PawletManagerService(this));
API surface:
- Build info: getPawletVersion, getDisplayVersion, getReleaseType, getBuildDate
- Device info: getDeviceCodename, getDeviceModel, getHardwarePlatform, getSerialNumber
- Provisioning: isDeviceProvisioned, isUserSetupComplete
- Feature flags: isFeatureEnabled / setFeatureEnabled (persist.pawlet.feature.*)
- SDK version: getPawletSdkVersion
PawletDevice: remove broken resource lookup, use system props directly;
add isPawletDevice, getBuildVersion, getDisplayVersion, getReleaseType,
getHardwarePlatform, getSerialNumber, getBuildDate.
PawletSystem: remove dead SDK<24 branches; improve isRooted to check su
binary paths and Magisk; keep isEmulator with same logic.
sepolicy: vendor_internal_prop for persist.* and vendor.* props,
dontaudit for system domains; fix file_contexts JAR labels.
Android.bp: add aidl block, pawlet-manager-service java_library.
AndroidManifest: minSdk 26, targetSdk 36.
---
Android.bp | 28 +++-
AndroidManifest.xml | 8 +-
core/java/pawletos/device/PawletDevice.java | 81 +++++++----
.../device/system/IPawletManager.aidl | 61 ++++++++
.../pawletos/device/system/PawletManager.java | 118 +++++++++++++++
.../device/system/PawletManagerService.java | 135 ++++++++++++++++++
.../pawletos/device/system/PawletSystem.java | 113 +++++++--------
sepolicy/file_contexts | 5 +-
sepolicy/pawlet_device.te | 18 +--
sepolicy/property_contexts | 15 +-
10 files changed, 478 insertions(+), 104 deletions(-)
create mode 100644 core/java/pawletos/device/system/IPawletManager.aidl
create mode 100644 core/java/pawletos/device/system/PawletManager.java
create mode 100644 core/java/pawletos/device/system/PawletManagerService.java
diff --git a/Android.bp b/Android.bp
index 8b7118b..7706b21 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,6 @@
+// PawletOS Framework API Extensions
+// Installed to product partition; visible to system apps and vendor subpackages.
+
java_sdk_library {
name: "pawlet-device",
srcs: ["core/java/pawletos/device/PawletDevice.java"],
@@ -15,7 +18,14 @@ java_sdk_library {
java_sdk_library {
name: "pawlet-system",
- srcs: ["core/java/pawletos/device/system/PawletSystem.java"],
+ srcs: [
+ "core/java/pawletos/device/system/PawletSystem.java",
+ "core/java/pawletos/device/system/PawletManager.java",
+ "core/java/pawletos/device/system/IPawletManager.aidl",
+ ],
+ aidl: {
+ local_include_dirs: ["core/java"],
+ },
api_packages: ["pawletos.device.system"],
sdk_version: "system_current",
product_specific: true,
@@ -24,6 +34,20 @@ java_sdk_library {
visibility: [
"//frameworks/base:__subpackages__",
"//packages/apps:__subpackages__",
+ "//vendor:__subpackages__",
],
unsafe_ignore_missing_latest_api: true,
-}
\ No newline at end of file
+}
+
+// Service-side implementation — used by the privileged app that hosts the service.
+java_library {
+ name: "pawlet-manager-service",
+ srcs: ["core/java/pawletos/device/system/PawletManagerService.java"],
+ libs: ["pawlet-system"],
+ sdk_version: "system_current",
+ product_specific: true,
+ visibility: [
+ "//packages/apps:__subpackages__",
+ "//vendor:__subpackages__",
+ ],
+}
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d36d542..7f72fc5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3,12 +3,12 @@
package="pawletos.device">
-
+ android:minSdkVersion="26"
+ android:targetSdkVersion="36" />
+
-
\ No newline at end of file
+
diff --git a/core/java/pawletos/device/PawletDevice.java b/core/java/pawletos/device/PawletDevice.java
index 56c78c4..226a226 100644
--- a/core/java/pawletos/device/PawletDevice.java
+++ b/core/java/pawletos/device/PawletDevice.java
@@ -1,48 +1,79 @@
package pawletos.device;
-import android.content.Context;
+import android.os.Build;
import android.os.SystemProperties;
/**
- * PawletOS Device API for apps running on PawletOS builds.
+ * Public PawletOS device information API.
+ * Available to all apps via the pawlet-device SDK library.
*/
-public class PawletDevice {
+public final class PawletDevice {
- /**
- * Get the brand name.
- */
- public static String getBrandName(Context ctx) {
- int resId = ctx.getResources().getIdentifier("oxmc_brand_name", "string", ctx.getPackageName());
- if (resId != 0) {
- return ctx.getString(resId);
- }
- return "PawletOS";
+ private PawletDevice() {}
+
+ /** Returns true if this device is running PawletOS. */
+ public static boolean isPawletDevice() {
+ return !SystemProperties.get("ro.pawlet.build.version", "").isEmpty();
}
- /**
- * Get the codename.
- */
- public static String getCodename(Context ctx) {
- int resId = ctx.getResources().getIdentifier("oxmc_codename", "string", ctx.getPackageName());
- if (resId != 0) {
- return ctx.getString(resId);
- }
- return "generic-pawlet-device";
+ /** PawletOS major.minor version string, e.g. "1.0". */
+ public static String getBuildVersion() {
+ return SystemProperties.get("ro.pawlet.build.version", "unknown");
}
- // ─────────────────────────────
- // Custom build property access
- // ─────────────────────────────
+ /** Full display version including date and type, e.g. "1-20260101-RELEASE-pawlet_rpi4". */
+ public static String getDisplayVersion() {
+ return SystemProperties.get("ro.pawlet.display.version", getBuildVersion());
+ }
+ /** Release type: RELEASE, NIGHTLY, SNAPSHOT, EXPERIMENTAL, or UNOFFICIAL. */
+ public static String getReleaseType() {
+ return SystemProperties.get("ro.pawlet.releasetype", "UNOFFICIAL");
+ }
+
+ /** Device codename as used in builds, e.g. "pawlet_rpi4". */
+ public static String getDeviceCodename() {
+ return SystemProperties.get("ro.product.device", Build.DEVICE);
+ }
+
+ /** Human-readable device model string. */
+ public static String getDeviceModel() {
+ return SystemProperties.get("ro.product.model", Build.MODEL);
+ }
+
+ /** Hardware platform, e.g. "bcm2711" (RPi 4) or "bcm2712" (RPi 5). */
+ public static String getHardwarePlatform() {
+ return SystemProperties.get("ro.hardware", Build.HARDWARE);
+ }
+
+ /** Device serial number. */
+ public static String getSerialNumber() {
+ return SystemProperties.get("ro.serialno", Build.UNKNOWN);
+ }
+
+ /** Build date as a Unix timestamp string from ro.build.date.utc. */
+ public static long getBuildDate() {
+ try {
+ return Long.parseLong(SystemProperties.get("ro.build.date.utc", "0"));
+ } catch (NumberFormatException e) {
+ return 0L;
+ }
+ }
+
+ // ── Legacy vendor properties ──────────────────────────────────────────────
+
+ /** Manufacture date from vendor property, or "unknown". */
public static String getManufactureDate() {
return SystemProperties.get("ro.oxmc.build.manufacture_date", "unknown");
}
+ /** Warranty exclusion string from vendor property, or "none". */
public static String getWarrantyExclusion() {
return SystemProperties.get("ro.oxmc.build.warranty_exclusion", "none");
}
+ /** Product series from vendor property, or "generic". */
public static String getSeries() {
return SystemProperties.get("ro.oxmc.build.series", "generic");
}
-}
\ No newline at end of file
+}
diff --git a/core/java/pawletos/device/system/IPawletManager.aidl b/core/java/pawletos/device/system/IPawletManager.aidl
new file mode 100644
index 0000000..9c94cb5
--- /dev/null
+++ b/core/java/pawletos/device/system/IPawletManager.aidl
@@ -0,0 +1,61 @@
+package pawletos.device.system;
+
+/**
+ * System service interface for PawletOS platform APIs.
+ * Obtain via PawletManager.get(context).
+ * @hide
+ */
+interface IPawletManager {
+
+ // ── Build info ────────────────────────────────────────────────────────────
+
+ /** PawletOS major.minor version string, e.g. "1.0". */
+ String getPawletVersion();
+
+ /** Full display version, e.g. "1-20260101-RELEASE-pawlet_rpi4". */
+ String getDisplayVersion();
+
+ /** Release type: RELEASE, NIGHTLY, SNAPSHOT, EXPERIMENTAL, or UNOFFICIAL. */
+ String getReleaseType();
+
+ /** Build date as Unix timestamp. */
+ long getBuildDate();
+
+ // ── Device info ───────────────────────────────────────────────────────────
+
+ /** Device codename, e.g. "pawlet_rpi4". */
+ String getDeviceCodename();
+
+ /** Human-readable device model string. */
+ String getDeviceModel();
+
+ /** Hardware platform, e.g. "bcm2711". */
+ String getHardwarePlatform();
+
+ /** Device serial number. */
+ String getSerialNumber();
+
+ // ── Provisioning ─────────────────────────────────────────────────────────
+
+ /** True if DEVICE_PROVISIONED=1. */
+ boolean isDeviceProvisioned();
+
+ /** True if USER_SETUP_COMPLETE=1. */
+ boolean isUserSetupComplete();
+
+ // ── Feature flags ─────────────────────────────────────────────────────────
+
+ /**
+ * Check if a named feature flag is enabled.
+ * Backed by persist.pawlet.feature.=1.
+ */
+ boolean isFeatureEnabled(in String feature);
+
+ /** Enable or disable a named feature flag (requires MANAGE_PAWLET_FEATURES permission). */
+ void setFeatureEnabled(in String feature, boolean enabled);
+
+ // ── SDK ───────────────────────────────────────────────────────────────────
+
+ /** PawletOS SDK/API version integer. */
+ int getPawletSdkVersion();
+}
diff --git a/core/java/pawletos/device/system/PawletManager.java b/core/java/pawletos/device/system/PawletManager.java
new file mode 100644
index 0000000..50ba5eb
--- /dev/null
+++ b/core/java/pawletos/device/system/PawletManager.java
@@ -0,0 +1,118 @@
+package pawletos.device.system;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * Client-side manager for the PawletOS system service.
+ *
+ * Usage:
+ * PawletManager pm = PawletManager.get(context);
+ * if (pm != null) {
+ * String version = pm.getPawletVersion();
+ * }
+ *
+ * The service is registered by a privileged system app at boot via:
+ * ServiceManager.addService(PawletManager.SERVICE_NAME, new PawletManagerService(context));
+ */
+public final class PawletManager {
+
+ public static final String SERVICE_NAME = "pawlet";
+ private static final String TAG = "PawletManager";
+
+ private final IPawletManager mService;
+
+ private PawletManager(IPawletManager service) {
+ mService = service;
+ }
+
+ /**
+ * Get the PawletManager instance, or null if the service is not running.
+ */
+ public static PawletManager get(Context context) {
+ IBinder binder = ServiceManager.getService(SERVICE_NAME);
+ if (binder == null) {
+ Log.w(TAG, "pawlet service not available");
+ return null;
+ }
+ return new PawletManager(IPawletManager.Stub.asInterface(binder));
+ }
+
+ // ── Build info ────────────────────────────────────────────────────────────
+
+ public String getPawletVersion() {
+ try { return mService.getPawletVersion(); }
+ catch (RemoteException e) { return null; }
+ }
+
+ public String getDisplayVersion() {
+ try { return mService.getDisplayVersion(); }
+ catch (RemoteException e) { return null; }
+ }
+
+ public String getReleaseType() {
+ try { return mService.getReleaseType(); }
+ catch (RemoteException e) { return null; }
+ }
+
+ public long getBuildDate() {
+ try { return mService.getBuildDate(); }
+ catch (RemoteException e) { return 0L; }
+ }
+
+ // ── Device info ───────────────────────────────────────────────────────────
+
+ public String getDeviceCodename() {
+ try { return mService.getDeviceCodename(); }
+ catch (RemoteException e) { return null; }
+ }
+
+ public String getDeviceModel() {
+ try { return mService.getDeviceModel(); }
+ catch (RemoteException e) { return null; }
+ }
+
+ public String getHardwarePlatform() {
+ try { return mService.getHardwarePlatform(); }
+ catch (RemoteException e) { return null; }
+ }
+
+ public String getSerialNumber() {
+ try { return mService.getSerialNumber(); }
+ catch (RemoteException e) { return null; }
+ }
+
+ // ── Provisioning ─────────────────────────────────────────────────────────
+
+ public boolean isDeviceProvisioned() {
+ try { return mService.isDeviceProvisioned(); }
+ catch (RemoteException e) { return false; }
+ }
+
+ public boolean isUserSetupComplete() {
+ try { return mService.isUserSetupComplete(); }
+ catch (RemoteException e) { return false; }
+ }
+
+ // ── Feature flags ─────────────────────────────────────────────────────────
+
+ public boolean isFeatureEnabled(String feature) {
+ try { return mService.isFeatureEnabled(feature); }
+ catch (RemoteException e) { return false; }
+ }
+
+ public void setFeatureEnabled(String feature, boolean enabled) {
+ try { mService.setFeatureEnabled(feature, enabled); }
+ catch (RemoteException e) { Log.e(TAG, "setFeatureEnabled failed", e); }
+ }
+
+ // ── SDK ───────────────────────────────────────────────────────────────────
+
+ public int getPawletSdkVersion() {
+ try { return mService.getPawletSdkVersion(); }
+ catch (RemoteException e) { return 0; }
+ }
+}
diff --git a/core/java/pawletos/device/system/PawletManagerService.java b/core/java/pawletos/device/system/PawletManagerService.java
new file mode 100644
index 0000000..cc21edd
--- /dev/null
+++ b/core/java/pawletos/device/system/PawletManagerService.java
@@ -0,0 +1,135 @@
+package pawletos.device.system;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.util.Log;
+
+/**
+ * Implementation of IPawletManager, hosted by a privileged system app.
+ *
+ * The hosting app registers this on boot:
+ * ServiceManager.addService(PawletManager.SERVICE_NAME, new PawletManagerService(this));
+ *
+ * Requires the hosting app to hold INTERACT_ACROSS_USERS_FULL for Settings access.
+ */
+public class PawletManagerService extends IPawletManager.Stub {
+
+ public static final int PAWLET_SDK_VERSION = 1;
+
+ private static final String TAG = "PawletManagerService";
+ private static final String FEATURE_PROP_PREFIX = "persist.pawlet.feature.";
+
+ private final Context mContext;
+
+ public PawletManagerService(Context context) {
+ mContext = context.getApplicationContext();
+ }
+
+ // ── Build info ────────────────────────────────────────────────────────────
+
+ @Override
+ public String getPawletVersion() {
+ return SystemProperties.get("ro.pawlet.build.version", "unknown");
+ }
+
+ @Override
+ public String getDisplayVersion() {
+ return SystemProperties.get("ro.pawlet.display.version", getPawletVersion());
+ }
+
+ @Override
+ public String getReleaseType() {
+ return SystemProperties.get("ro.pawlet.releasetype", "UNOFFICIAL");
+ }
+
+ @Override
+ public long getBuildDate() {
+ try {
+ return Long.parseLong(SystemProperties.get("ro.build.date.utc", "0"));
+ } catch (NumberFormatException e) {
+ return 0L;
+ }
+ }
+
+ // ── Device info ───────────────────────────────────────────────────────────
+
+ @Override
+ public String getDeviceCodename() {
+ return SystemProperties.get("ro.product.device", Build.DEVICE);
+ }
+
+ @Override
+ public String getDeviceModel() {
+ return SystemProperties.get("ro.product.model", Build.MODEL);
+ }
+
+ @Override
+ public String getHardwarePlatform() {
+ return SystemProperties.get("ro.hardware", Build.HARDWARE);
+ }
+
+ @Override
+ public String getSerialNumber() {
+ return SystemProperties.get("ro.serialno", Build.UNKNOWN);
+ }
+
+ // ── Provisioning ─────────────────────────────────────────────────────────
+
+ @Override
+ public boolean isDeviceProvisioned() {
+ try {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 0) == 1;
+ } catch (Exception e) {
+ Log.w(TAG, "isDeviceProvisioned: " + e.getMessage());
+ return false;
+ }
+ }
+
+ @Override
+ public boolean isUserSetupComplete() {
+ try {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0) == 1;
+ } catch (Exception e) {
+ Log.w(TAG, "isUserSetupComplete: " + e.getMessage());
+ return false;
+ }
+ }
+
+ // ── Feature flags ─────────────────────────────────────────────────────────
+
+ @Override
+ public boolean isFeatureEnabled(String feature) {
+ if (feature == null || feature.isEmpty()) return false;
+ return "1".equals(SystemProperties.get(FEATURE_PROP_PREFIX + feature, "0"));
+ }
+
+ @Override
+ public void setFeatureEnabled(String feature, boolean enabled) {
+ if (feature == null || feature.isEmpty()) return;
+ enforceFeaturePermission();
+ SystemProperties.set(FEATURE_PROP_PREFIX + feature, enabled ? "1" : "0");
+ Log.i(TAG, "Feature " + feature + " " + (enabled ? "enabled" : "disabled")
+ + " by uid=" + Binder.getCallingUid());
+ }
+
+ // ── SDK ───────────────────────────────────────────────────────────────────
+
+ @Override
+ public int getPawletSdkVersion() {
+ return PAWLET_SDK_VERSION;
+ }
+
+ // ── Internal ──────────────────────────────────────────────────────────────
+
+ private void enforceFeaturePermission() {
+ mContext.enforceCallingOrSelfPermission(
+ "pawletos.permission.MANAGE_PAWLET_FEATURES",
+ "Requires MANAGE_PAWLET_FEATURES permission");
+ }
+}
diff --git a/core/java/pawletos/device/system/PawletSystem.java b/core/java/pawletos/device/system/PawletSystem.java
index dfe396d..0cc08d9 100644
--- a/core/java/pawletos/device/system/PawletSystem.java
+++ b/core/java/pawletos/device/system/PawletSystem.java
@@ -5,75 +5,72 @@ import android.os.Build;
import android.os.SystemProperties;
/**
- * PawletOS System API for system apps (OTA, device management, etc.)
+ * Static system utilities for PawletOS system apps.
+ * For richer runtime data, use PawletManager.get(context) instead.
*/
-public class PawletSystem {
- private static final double PAWLET_SDK_VERSION = 1.0;
+public final class PawletSystem {
- /**
- * Check if running on an emulator.
- */
+ public static final int PAWLET_SDK_VERSION = 1;
+
+ private PawletSystem() {}
+
+ /** True if running on a PawletOS build. */
+ public static boolean isPawletOS() {
+ return !SystemProperties.get("ro.pawlet.build.version", "").isEmpty();
+ }
+
+ /** True if this is a debug/userdebug build. */
+ public static boolean isDebugBuild() {
+ return "1".equals(SystemProperties.get("ro.debuggable", "0"));
+ }
+
+ /** True if this is a release-signed build (not test-keys). */
+ public static boolean isReleaseBuild() {
+ String tags = Build.TAGS;
+ return tags != null && tags.contains("release-keys");
+ }
+
+ /** Current locale tag, e.g. "en_US". */
+ public static String getCurrentLocale(Context ctx) {
+ return ctx.getResources().getConfiguration().getLocales().get(0).toString();
+ }
+
+ /** True if the device appears to be an emulator. */
public static boolean isEmulator() {
- String fingerprint = Build.FINGERPRINT;
- String model = Build.MODEL;
- String manufacturer = Build.MANUFACTURER;
- String brand = Build.BRAND;
- String device = Build.DEVICE;
- String product = Build.PRODUCT;
- return fingerprint != null && (fingerprint.startsWith("generic") || fingerprint.startsWith("unknown"))
- || model != null && model.contains("google_sdk")
- || model != null && model.contains("Emulator")
- || model != null && model.contains("Android SDK built for x86")
- || manufacturer != null && manufacturer.contains("Genymotion")
- || brand != null && brand.startsWith("generic") && device != null && device.startsWith("generic")
- || product != null && product.equals("google_sdk");
+ String fp = Build.FINGERPRINT;
+ return (fp != null && (fp.startsWith("generic") || fp.startsWith("unknown")))
+ || Build.MODEL.contains("google_sdk")
+ || Build.MODEL.contains("Emulator")
+ || Build.MODEL.contains("Android SDK built for x86")
+ || Build.MANUFACTURER.contains("Genymotion")
+ || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
+ || "google_sdk".equals(Build.PRODUCT);
}
/**
- * Basic check if device is rooted.
+ * Heuristic check for whether the device has root access.
+ * Checks for su binaries in common locations and the ro.debuggable property.
+ * Not foolproof — a determined user can hide root.
*/
public static boolean isRooted() {
- String buildTags = Build.TAGS;
- if (buildTags != null && buildTags.contains("test-keys")) {
- return true;
- }
- try {
- java.io.File file = new java.io.File("/system/app/Superuser.apk");
- if (file.exists()) {
- return true;
- }
- } catch (Exception e) {
- // ignore
+ // Common su locations
+ String[] suPaths = {
+ "/system/bin/su",
+ "/system/xbin/su",
+ "/sbin/su",
+ "/vendor/bin/su",
+ "/system/su",
+ };
+ for (String path : suPaths) {
+ if (new java.io.File(path).exists()) return true;
}
+ // Magisk manager package presence
+ if (new java.io.File("/data/adb/magisk").exists()) return true;
return false;
}
- /**
- * Get the current language/locale.
- */
- public static String getCurrentLocale(Context ctx) {
- java.util.Locale locale;
- if (android.os.Build.VERSION.SDK_INT >= 24) {
- locale = ctx.getResources().getConfiguration().getLocales().get(0);
- } else {
- locale = ctx.getResources().getConfiguration().locale;
- }
- return locale.toString();
- }
-
- /**
- * Check if device is running PawletOS.
- * Returns true if running on PawletOS, false otherwise.
- */
- public static boolean isPawletOS() {
- return "Pawlet".equalsIgnoreCase(Build.MANUFACTURER)
- || "PawletOS".equalsIgnoreCase(SystemProperties.get("ro.oxmc.os_name", ""));
- }
-
- /**
- * Get the PawletSDK version.
- */
- public static double getPawletSDKVersion() {
+ /** PawletOS SDK version integer. Matches PawletManagerService.PAWLET_SDK_VERSION. */
+ public static int getPawletSdkVersion() {
return PAWLET_SDK_VERSION;
}
-}
\ No newline at end of file
+}
diff --git a/sepolicy/file_contexts b/sepolicy/file_contexts
index dd964ac..82d2c15 100644
--- a/sepolicy/file_contexts
+++ b/sepolicy/file_contexts
@@ -1,2 +1,3 @@
-# Label the JAR file
-/system/framework/pawlet-device.jar u:object_r:pawlet_device_exec:s0
\ No newline at end of file
+# PawletOS framework JARs
+/system/framework/pawlet-device\.jar u:object_r:system_file:s0
+/system/framework/pawlet-system\.jar u:object_r:system_file:s0
diff --git a/sepolicy/pawlet_device.te b/sepolicy/pawlet_device.te
index 99bfa68..1883583 100644
--- a/sepolicy/pawlet_device.te
+++ b/sepolicy/pawlet_device.te
@@ -1,14 +1,14 @@
-# Domain declaration
+# PawletOS framework service domain
type pawlet_device, domain, coredomain;
type pawlet_device_exec, exec_type, file_type;
-# Inherit from core domain
-typeattribute pawlet_device coredomain;
-
-# Basic file access for your domain
-allow pawlet_device pawlet_device_exec:file { execute read open map };
-
-# Binder communication
+# Binder communication with system_server and servicemanager
binder_use(pawlet_device)
binder_call(pawlet_device, system_server)
-binder_call(pawlet_device, servicemanager)
\ No newline at end of file
+binder_call(pawlet_device, servicemanager)
+
+# Allow reading PawletOS system properties
+get_prop(pawlet_device, system_prop)
+
+# Silence audit noise from system domains reading vendor props they don't need
+dontaudit domain vendor_internal_prop:file { read open getattr map };
diff --git a/sepolicy/property_contexts b/sepolicy/property_contexts
index a18f681..33cd8d2 100644
--- a/sepolicy/property_contexts
+++ b/sepolicy/property_contexts
@@ -1,4 +1,11 @@
-# Custom properties for the pawlet device
-ro.vendor.oxmc.* u:object_r:vendor_default_prop:s0
-ro.vendor.pawlet.* u:object_r:vendor_default_prop:s0
-persist.vendor.pawlet.* u:object_r:vendor_default_prop:s0
\ No newline at end of file
+# PawletOS system properties
+ro.pawlet. u:object_r:system_prop:s0
+ro.oxmc. u:object_r:system_prop:s0
+
+# Vendor-internal properties (vendor domain only)
+ro.vendor.oxmc. u:object_r:vendor_internal_prop:s0
+ro.vendor.pawlet. u:object_r:vendor_internal_prop:s0
+persist.vendor.pawlet. u:object_r:vendor_internal_prop:s0
+
+# Feature flags (writable by pawlet service)
+persist.pawlet.feature. u:object_r:vendor_internal_prop:s0