diff options
-rw-r--r-- | src/com/android/server/NetworkObserver.java | 87 | ||||
-rw-r--r-- | src/com/android/server/NetworkObserverRegistry.java | 150 | ||||
-rw-r--r-- | src/com/android/server/NetworkStackService.java | 15 |
3 files changed, 250 insertions, 2 deletions
diff --git a/src/com/android/server/NetworkObserver.java b/src/com/android/server/NetworkObserver.java new file mode 100644 index 0000000..d3b40a6 --- /dev/null +++ b/src/com/android/server/NetworkObserver.java @@ -0,0 +1,87 @@ +/* + * 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) {} +} diff --git a/src/com/android/server/NetworkObserverRegistry.java b/src/com/android/server/NetworkObserverRegistry.java new file mode 100644 index 0000000..14e6c5f --- /dev/null +++ b/src/com/android/server/NetworkObserverRegistry.java @@ -0,0 +1,150 @@ +/* + * 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) {} +} diff --git a/src/com/android/server/NetworkStackService.java b/src/com/android/server/NetworkStackService.java index 4080ddf..631ee45 100644 --- a/src/com/android/server/NetworkStackService.java +++ b/src/com/android/server/NetworkStackService.java @@ -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 |