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

Commit 375b3c07 authored by Remi NGUYEN VAN's avatar Remi NGUYEN VAN Committed by Gerrit Code Review
Browse files

Merge "Add NetworkObserverRegistry to NetworkStack"

parents f4fb1b52 e4195cd6
Loading
Loading
Loading
Loading
+87 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server;

import android.net.LinkAddress;

/**
 * Observer for network events, to use with {@link NetworkObserverRegistry}.
 */
public interface NetworkObserver {

    /**
     * @see android.net.INetdUnsolicitedEventListener#onInterfaceChanged(java.lang.String, boolean)
     */
    default void onInterfaceChanged(String ifName, boolean up) {}

    /**
     * @see android.net.INetdUnsolicitedEventListener#onInterfaceRemoved(String)
     */
    default void onInterfaceRemoved(String ifName) {}

    /**
     * @see android.net.INetdUnsolicitedEventListener
     *          #onInterfaceAddressUpdated(String, String, int, int)
     */
    default void onInterfaceAddressUpdated(LinkAddress address, String ifName) {}

    /**
     * @see android.net.INetdUnsolicitedEventListener
     *          #onInterfaceAddressRemoved(String, String, int, int)
     */
    default void onInterfaceAddressRemoved(LinkAddress address, String ifName) {}

    /**
     * @see android.net.INetdUnsolicitedEventListener#onInterfaceLinkStateChanged(String, boolean)
     */
    default void onInterfaceLinkStateChanged(String ifName, boolean up) {}

    /**
     * @see android.net.INetdUnsolicitedEventListener#onInterfaceAdded(String)
     */
    default void onInterfaceAdded(String ifName) {}

    /**
     * @see android.net.INetdUnsolicitedEventListener
     *          #onInterfaceClassActivityChanged(boolean, int, long, int)
     */
    default void onInterfaceClassActivityChanged(
            boolean isActive, int label, long timestamp, int uid) {}

    /**
     * @see android.net.INetdUnsolicitedEventListener#onQuotaLimitReached(String, String)
     */
    default void onQuotaLimitReached(String alertName, String ifName) {}

    /**
     * @see android.net.INetdUnsolicitedEventListener
     *          #onInterfaceDnsServerInfo(String, long, String[])
     */
    default void onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers) {}

    /**
     * @see android.net.INetdUnsolicitedEventListener
     *          #onRouteChanged(boolean, String, String, String)
     */
    default void onRouteUpdated(String route, String gateway, String ifName) {}

    /**
     * @see android.net.INetdUnsolicitedEventListener
     *          #onRouteChanged(boolean, String, String, String)
     */
    default void onRouteRemoved(String route, String gateway, String ifName) {}
}
+150 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.server;

import android.annotation.NonNull;
import android.net.INetd;
import android.net.INetdUnsolicitedEventListener;
import android.net.LinkAddress;
import android.os.Handler;
import android.os.RemoteException;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * A class for reporting network events to clients.
 *
 * Implements INetdUnsolicitedEventListener and registers with netd, and relays those events to
 * all INetworkManagementEventObserver objects that have registered with it.
 */
public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub {

    /**
     * Constructs a new NetworkObserverRegistry.
     *
     * <p>Only one registry should be used per process since netd will silently ignore multiple
     * registrations from the same process.
     */
    NetworkObserverRegistry() {}

    /**
     * Start listening for Netd events.
     *
     * <p>This should be called before allowing any observer to be registered.
     */
    void register(@NonNull INetd netd) throws RemoteException {
        netd.registerUnsolicitedEventListener(this);
    }

    private final ConcurrentHashMap<NetworkObserver, Handler> mObservers =
            new ConcurrentHashMap<>();

    /**
     * Registers the specified observer and start sending callbacks to it.
     * This method may be called on any thread.
     */
    public void registerObserver(@NonNull NetworkObserver observer, @NonNull Handler handler) {
        mObservers.put(observer, handler);
    }

    /**
     * Unregisters the specified observer and stop sending callbacks to it.
     * This method may be called on any thread.
     */
    public void unregisterObserver(@NonNull NetworkObserver observer) {
        mObservers.remove(observer);
    }

    @FunctionalInterface
    private interface NetworkObserverEventCallback {
        void sendCallback(NetworkObserver o);
    }

    private void invokeForAllObservers(@NonNull final NetworkObserverEventCallback callback) {
        // ConcurrentHashMap#entrySet is weakly consistent: observers that were in the map before
        // creation will be processed, those added during traversal may or may not.
        for (Map.Entry<NetworkObserver, Handler> entry : mObservers.entrySet()) {
            final NetworkObserver observer = entry.getKey();
            entry.getValue().post(() -> callback.sendCallback(observer));
        }
    }

    @Override
    public void onInterfaceClassActivityChanged(boolean isActive,
            int label, long timestamp, int uid) {
        invokeForAllObservers(o -> o.onInterfaceClassActivityChanged(
                isActive, label, timestamp, uid));
    }

    /**
     * Notify our observers of a limit reached.
     */
    @Override
    public void onQuotaLimitReached(String alertName, String ifName) {
        invokeForAllObservers(o -> o.onQuotaLimitReached(alertName, ifName));
    }

    @Override
    public void onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers) {
        invokeForAllObservers(o -> o.onInterfaceDnsServerInfo(ifName, lifetime, servers));
    }

    @Override
    public void onInterfaceAddressUpdated(String addr, String ifName, int flags, int scope) {
        final LinkAddress address = new LinkAddress(addr, flags, scope);
        invokeForAllObservers(o -> o.onInterfaceAddressUpdated(address, ifName));
    }

    @Override
    public void onInterfaceAddressRemoved(String addr,
            String ifName, int flags, int scope) {
        final LinkAddress address = new LinkAddress(addr, flags, scope);
        invokeForAllObservers(o -> o.onInterfaceAddressRemoved(address, ifName));
    }

    @Override
    public void onInterfaceAdded(String ifName) {
        invokeForAllObservers(o -> o.onInterfaceAdded(ifName));
    }

    @Override
    public void onInterfaceRemoved(String ifName) {
        invokeForAllObservers(o -> o.onInterfaceRemoved(ifName));
    }

    @Override
    public void onInterfaceChanged(String ifName, boolean up) {
        invokeForAllObservers(o -> o.onInterfaceChanged(ifName, up));
    }

    @Override
    public void onInterfaceLinkStateChanged(String ifName, boolean up) {
        invokeForAllObservers(o -> o.onInterfaceLinkStateChanged(ifName, up));
    }

    @Override
    public void onRouteChanged(boolean updated, String route, String gateway, String ifName) {
        if (updated) {
            invokeForAllObservers(o -> o.onRouteUpdated(route, gateway, ifName));
        } else {
            invokeForAllObservers(o -> o.onRouteRemoved(route, gateway, ifName));
        }
    }

    @Override
    public void onStrictCleartextDetected(int uid, String hex) {}
}
+13 −2
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkStackConnector;
@@ -65,6 +66,7 @@ import java.util.Iterator;
 */
public class NetworkStackService extends Service {
    private static final String TAG = NetworkStackService.class.getSimpleName();
    private static NetworkStackConnector sConnector;

    /**
     * Create a binder connector for the system server to communicate with the network stack.
@@ -72,8 +74,11 @@ public class NetworkStackService extends Service {
     * <p>On platforms where the network stack runs in the system server process, this method may
     * be called directly instead of obtaining the connector by binding to the service.
     */
    public static IBinder makeConnector(Context context) {
        return new NetworkStackConnector(context);
    public static synchronized IBinder makeConnector(Context context) {
        if (sConnector == null) {
            sConnector = new NetworkStackConnector(context);
        }
        return sConnector;
    }

    @NonNull
@@ -85,6 +90,8 @@ public class NetworkStackService extends Service {
    private static class NetworkStackConnector extends INetworkStackConnector.Stub {
        private static final int NUM_VALIDATION_LOG_LINES = 20;
        private final Context mContext;
        private final INetd mNetd;
        private final NetworkObserverRegistry mObserverRegistry;
        private final ConnectivityManager mCm;
        @GuardedBy("mIpClients")
        private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>();
@@ -106,7 +113,11 @@ public class NetworkStackService extends Service {

        NetworkStackConnector(Context context) {
            mContext = context;
            mNetd = (INetd) context.getSystemService(Context.NETD_SERVICE);
            mObserverRegistry = new NetworkObserverRegistry();
            mCm = context.getSystemService(ConnectivityManager.class);

            // TODO: call mObserverRegistry here after adding sepolicy changes
        }

        @NonNull