AOSP Framework & Internals
5 min read

PowerManagerService, NetworkManagementService, and Other Services

Learn about PowerManagerService, NetworkManagementService, and Other Services.

If every application could freely keep the CPU awake, a single buggy app would drain your battery in an hour. Direct hardware control is too dangerous to expose to untrusted code. The system requires a central authority to track power requests and decide when the device should actually sleep.

PowerManagerService

Android solves this power problem with PowerManagerService. You will often see it abbreviated as PowerMS to avoid confusion with the PackageManagerService. This service acts as the strict gatekeeper between application wake locks and the kernel suspend mechanisms.

During initialization, PowerMS sets up a Notifier to handle screen broadcasts. It connects directly to the SuspendControlService to communicate with native kernel power states. When an application requests a wake lock, PowerMS evaluates the global device state and passes the final decision down to the hardware.

This flowchart shows the path a wake lock request takes from an application down to the kernel. It visualizes how PowerMS acts as the single choke point protecting the hardware. Notice that the application never talks to the native layer directly.

The request travels linearly through the framework before hitting the native daemon. This structure ensures no app can bypass the central power policy.

By forcing all power requests through this single service, Android can enforce global states like battery saver mode reliably. But protecting the battery is only one part of system security. The platform also has to manage network traffic without giving apps root access.

NetworkManagementService

Configuring routing tables and firewall rules in Linux requires root privileges. Giving root access to the entire Java framework would create a massive security vulnerability. The system needs a way to modify kernel network policies without exposing elevated permissions to the upper layers.

NetworkManagementService exists to bridge this gap. This service connects the unprivileged Java framework to the privileged kernel networking stack. It does not manage Wi-Fi connections directly. Instead, it provides a safe API surface for low-level policy enforcement.

NetworkManagementService communicates with netd, the native network daemon, over a local socket. When a user enables Data Saver, ConnectivityService notifies NetworkManagementService about the policy change. The service sends a string command over the socket to netd. The native daemon then manipulates the actual kernel iptables rules to block background packets.

This sequence diagram illustrates the flow of a network policy change from the framework to the native layer. It clarifies the strict boundary between unprivileged Java services and privileged native daemons. Pay attention to how the high-level policy translates into a simple socket command.

The Java layer never touches iptables directly. It simply asks the native layer to do the privileged work on its behalf.

This separation of privilege keeps the system secure while enabling complex network routing. It provides a standard pattern for framework services to interact with native hardware capabilities. However, all these distinct services must start up cleanly without crashing into each other.

Service Dependency Management

SystemServer initializes dozens of system services sequentially during boot. If your new service starts early but tries to post a notification, the system will crash. The NotificationManagerService might not exist yet. Relying on other services in your constructor guarantees a null reference exception.

Android solves this timing problem through deliberate dependency management. Services do not assume the rest of the platform is awake. They use specific callback mechanisms to delay their interactions until the system is fully operational.

Late-starting services wait for the systemReady() callback before fetching dependencies. Other components register for specific broadcast intents to know when it is safe to act. You must build your service to wake up gracefully as its required dependencies come online.

Understanding this boot sequence prevents race conditions and random crashes during startup. Your code only interacts with the system when the system is actually ready to listen. This becomes critical when you want to expand the framework with your own hardware features.

Adding a Custom System Service

Hardware vendors frequently need to expose proprietary sensors that standard AOSP does not understand. You cannot just drop a plain Java class into the framework and expect applications to find it. Apps run in separate processes and need a way to communicate with your new hardware safely. The system requires a registered IPC path.

The standard solution is adding a custom system service directly into SystemServer. This exposes your new hardware capabilities through a formal Binder interface. It gives your proprietary feature the exact same security guarantees as core framework services.

You start by defining an AIDL file for the interface. You then write a Java class that extends the generated stub to implement your logic. Inside SystemServer.java, you instantiate your service within the startOtherServices() method. Finally, you register it with the ServiceManager so applications can discover it by name.

try {
    Slog.i(TAG, "Custom Service");
    ServiceManager.addService("my_custom", new CustomService(context));
} catch (Throwable e) {
    reportWtf("starting Custom Service", e);
}

Warning: You must declare the new service context in your SELinux policy files. If you skip the permissions step, ServiceManager will reject the registration and crash the SystemServer.

By following this pattern, you extend the Android OS organically. Applications can bind to your custom service exactly like they bind to the core system services. You have seen how Android protects the hardware, routes network policies safely, and manages complex boot dependencies. The framework provides a secure home for your proprietary features. But eventually, those features will need to draw pixels on the screen, which requires understanding the system graphics architecture.