Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c43c339 authored by Jeff Brown's avatar Jeff Brown
Browse files

Resolve boot time dependencies related to the power manager.

This change fixes a bug where native daemons may try to communicate
with the power manager before it was fully initialized due to a race
between publishing the binder service and completing init().

The solution was to simplify the dependencies related to the power
manager.  It turns out that most services that were passed in
init are not actually needed until systemReady.  What remained
was a dependency on the activity manager to check permissions for
incoming calls.  So now we start activity manager first.
However, the activity manager also depends on power manager for
wakelocks.  To break the cycle, we now defer initializing the activity
manager's wakelocks until after the power manager has been started.

Cleaned up a bunch of boot-time service dependencies so that we
can have better confidence that they are correctly maintained.

Bug: 13884219
Change-Id: If08e2d7ccd44e7026a72441bb6bd5afd7bb9fffe
parent 12758423
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -513,6 +513,9 @@ class ContextImpl extends Context {
                public Object createService(ContextImpl ctx) {
                    IBinder b = ServiceManager.getService(POWER_SERVICE);
                    IPowerManager service = IPowerManager.Stub.asInterface(b);
                    if (service == null) {
                        Log.wtf(TAG, "Failed to get power manager service.");
                    }
                    return new PowerManager(ctx.getOuterContext(),
                            service, ctx.mMainThread.getHandler());
                }});
+2 −7
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package android.os;

import android.view.WindowManagerPolicy;

/**
 * Power manager local system service interface.
 *
@@ -57,12 +55,9 @@ public abstract class PowerManagerInternal {

    public abstract boolean getLowPowerModeEnabled();

    public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);

    public interface LowPowerModeListener {
        public void onLowPowerModeChanged(boolean enabled);
    }

    public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);

    // TODO: Remove this and retrieve as a local service instead.
    public abstract void setPolicy(WindowManagerPolicy policy);
}
+13 −2
Original line number Diff line number Diff line
@@ -50,8 +50,19 @@ public class SystemServiceManager {
     * @return The service instance.
     */
    @SuppressWarnings("unchecked")
    public SystemService startService(String className) throws ClassNotFoundException {
        return startService((Class<SystemService>) Class.forName(className));
    public SystemService startService(String className) {
        final Class<SystemService> serviceClass;
        try {
            serviceClass = (Class<SystemService>)Class.forName(className);
        } catch (ClassNotFoundException ex) {
            Slog.i(TAG, "Starting " + className);
            throw new RuntimeException("Failed to create service " + className
                    + ": service class not found, usually indicates that the caller should "
                    + "have called PackageManager.hasSystemFeature() to check whether the "
                    + "feature is available on this device before trying to start the "
                    + "services that implement it", ex);
        }
        return startService(serviceClass);
    }

    /**
+5 −0
Original line number Diff line number Diff line
@@ -2194,6 +2194,11 @@ public final class ActivityManagerService extends ActivityManagerNative
        LocalServices.addService(ActivityManagerInternal.class, new LocalService());
    }
    public void initPowerManagement() {
        mStackSupervisor.initPowerManagement();
        mBatteryStatsService.initPowerManagement();
    }
    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
+10 −6
Original line number Diff line number Diff line
@@ -227,14 +227,14 @@ public final class ActivityStackSupervisor implements DisplayListener {
     * receivers to launch an activity and get that to run before the device
     * goes back to sleep.
     */
    final PowerManager.WakeLock mLaunchingActivity;
    PowerManager.WakeLock mLaunchingActivity;

    /**
     * Set when the system is going to sleep, until we have
     * successfully paused the current activity and released our wake lock.
     * At that point the system is allowed to actually sleep.
     */
    final PowerManager.WakeLock mGoingToSleep;
    PowerManager.WakeLock mGoingToSleep;

    /** Stack id of the front stack when user switched, indexed by userId. */
    SparseIntArray mUserStackInFront = new SparseIntArray(2);
@@ -255,12 +255,16 @@ public final class ActivityStackSupervisor implements DisplayListener {

    public ActivityStackSupervisor(ActivityManagerService service) {
        mService = service;
        PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE);
        mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
        mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
        if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
            throw new IllegalStateException("Calling must be system uid");
    }

    /**
     * At the time when the constructor runs, the power manager has not yet been
     * initialized.  So we initialize our wakelocks afterwards.
     */
    void initPowerManagement() {
        PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE);
        mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
        mLaunchingActivity =
                pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
        mLaunchingActivity.setReferenceCounted(false);
Loading