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

Commit 088f29f5 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Cleaner controls between Vpn and init services.

Change-Id: I35edf054f4a1190f7fb7b4c48ee832e899c9528b
parent 216c181e
Loading
Loading
Loading
Loading
+117 −6
Original line number Diff line number Diff line
@@ -16,9 +16,47 @@

package android.os;

/** @hide */
public class SystemService
{
import com.google.android.collect.Maps;

import java.util.HashMap;
import java.util.concurrent.TimeoutException;

/**
 * Controls and utilities for low-level {@code init} services.
 *
 * @hide
 */
public class SystemService {

    private static HashMap<String, State> sStates = Maps.newHashMap();

    /**
     * State of a known {@code init} service.
     */
    public enum State {
        RUNNING("running"),
        STOPPING("stopping"),
        STOPPED("stopped"),
        RESTARTING("restarting");

        State(String state) {
            sStates.put(state, this);
        }
    }

    private static Object sPropertyLock = new Object();

    static {
        SystemProperties.addChangeCallback(new Runnable() {
            @Override
            public void run() {
                synchronized (sPropertyLock) {
                    sPropertyLock.notifyAll();
                }
            }
        });
    }

    /** Request that the init daemon start a named service. */
    public static void start(String name) {
        SystemProperties.set("ctl.start", name);
@@ -33,4 +71,77 @@ public class SystemService
    public static void restart(String name) {
        SystemProperties.set("ctl.restart", name);
    }

    /**
     * Return current state of given service.
     */
    public static State getState(String service) {
        final String rawState = SystemProperties.get("init.svc." + service);
        final State state = sStates.get(rawState);
        if (state != null) {
            return state;
        } else {
            throw new IllegalStateException("Service " + service + " in unknown state " + rawState);
        }
    }

    /**
     * Check if given service is {@link State#STOPPED}.
     */
    public static boolean isStopped(String service) {
        return State.STOPPED.equals(getState(service));
    }

    /**
     * Check if given service is {@link State#RUNNING}.
     */
    public static boolean isRunning(String service) {
        return State.RUNNING.equals(getState(service));
    }

    /**
     * Wait until given service has entered specific state.
     */
    public static void waitForState(String service, State state, long timeoutMillis)
            throws TimeoutException {
        final long endMillis = SystemClock.elapsedRealtime() + timeoutMillis;
        while (true) {
            synchronized (sPropertyLock) {
                final State currentState = getState(service);
                if (state.equals(currentState)) {
                    return;
                }

                if (SystemClock.elapsedRealtime() >= endMillis) {
                    throw new TimeoutException("Service " + service + " currently " + currentState
                            + "; waited " + timeoutMillis + "ms for " + state);
                }

                try {
                    sPropertyLock.wait(timeoutMillis);
                } catch (InterruptedException e) {
                }
            }
        }
    }

    /**
     * Wait until any of given services enters {@link State#STOPPED}.
     */
    public static void waitForAnyStopped(String... services)  {
        while (true) {
            synchronized (sPropertyLock) {
                for (String service : services) {
                    if (State.STOPPED.equals(getState(service))) {
                        return;
                    }
                }

                try {
                    sPropertyLock.wait();
                } catch (InterruptedException e) {
                }
            }
        }
    }
}
+6 −10
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
@@ -39,7 +38,7 @@ import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.SystemService;
import android.util.Log;

import com.android.internal.R;
@@ -485,8 +484,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {

                // Wait for the daemons to stop.
                for (String daemon : mDaemons) {
                    String key = "init.svc." + daemon;
                    while (!"stopped".equals(SystemProperties.get(key, "stopped"))) {
                    while (!SystemService.isStopped(daemon)) {
                        checkpoint(true);
                    }
                }
@@ -519,11 +517,10 @@ public class Vpn extends INetworkManagementEventObserver.Stub {

                    // Start the daemon.
                    String daemon = mDaemons[i];
                    SystemProperties.set("ctl.start", daemon);
                    SystemService.start(daemon);

                    // Wait for the daemon to start.
                    String key = "init.svc." + daemon;
                    while (!"running".equals(SystemProperties.get(key))) {
                    while (!SystemService.isRunning(daemon)) {
                        checkpoint(true);
                    }

@@ -579,8 +576,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
                    // Check if a running daemon is dead.
                    for (int i = 0; i < mDaemons.length; ++i) {
                        String daemon = mDaemons[i];
                        if (mArguments[i] != null && !"running".equals(
                                SystemProperties.get("init.svc." + daemon))) {
                        if (mArguments[i] != null && !SystemService.isRunning(daemon)) {
                            throw new IllegalStateException(daemon + " is dead");
                        }
                    }
@@ -647,7 +643,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
                // Kill the daemons if they fail to stop.
                if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING) {
                    for (String daemon : mDaemons) {
                        SystemProperties.set("ctl.stop", daemon);
                        SystemService.stop(daemon);
                    }
                }