1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server; 17 18 import static android.net.RouteInfo.RTN_UNICAST; 19 20 import android.annotation.NonNull; 21 import android.net.INetd; 22 import android.net.INetdUnsolicitedEventListener; 23 import android.net.InetAddresses; 24 import android.net.IpPrefix; 25 import android.net.LinkAddress; 26 import android.net.RouteInfo; 27 import android.os.Handler; 28 import android.os.RemoteException; 29 import android.util.Log; 30 31 import java.util.Map; 32 import java.util.Optional; 33 import java.util.concurrent.ConcurrentHashMap; 34 35 /** 36 * A class for reporting network events to clients. 37 * 38 * Implements INetdUnsolicitedEventListener and registers with netd, and relays those events to 39 * all INetworkManagementEventObserver objects that have registered with it. 40 */ 41 public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub { 42 private static final String TAG = NetworkObserverRegistry.class.getSimpleName(); 43 44 /** 45 * Constructs a new NetworkObserverRegistry. 46 * 47 * <p>Only one registry should be used per process since netd will silently ignore multiple 48 * registrations from the same process. 49 */ NetworkObserverRegistry()50 NetworkObserverRegistry() {} 51 52 /** 53 * Start listening for Netd events. 54 * 55 * <p>This should be called before allowing any observer to be registered. 56 */ register(@onNull INetd netd)57 void register(@NonNull INetd netd) throws RemoteException { 58 netd.registerUnsolicitedEventListener(this); 59 } 60 61 private final ConcurrentHashMap<NetworkObserver, Optional<Handler>> mObservers = 62 new ConcurrentHashMap<>(); 63 64 /** 65 * Registers the specified observer and start sending callbacks to it. 66 * This method may be called on any thread. 67 */ registerObserver(@onNull NetworkObserver observer, @NonNull Handler handler)68 public void registerObserver(@NonNull NetworkObserver observer, @NonNull Handler handler) { 69 if (handler == null) { 70 throw new IllegalArgumentException("handler must be non-null"); 71 } 72 mObservers.put(observer, Optional.of(handler)); 73 } 74 75 /** 76 * Registers the specified observer, and start sending callbacks to it. 77 * 78 * <p>This method must only be called with callbacks that are nonblocking, such as callbacks 79 * that only send a message to a StateMachine. 80 */ registerObserverForNonblockingCallback(@onNull NetworkObserver observer)81 public void registerObserverForNonblockingCallback(@NonNull NetworkObserver observer) { 82 mObservers.put(observer, Optional.empty()); 83 } 84 85 /** 86 * Unregisters the specified observer and stop sending callbacks to it. 87 * This method may be called on any thread. 88 */ unregisterObserver(@onNull NetworkObserver observer)89 public void unregisterObserver(@NonNull NetworkObserver observer) { 90 mObservers.remove(observer); 91 } 92 93 @FunctionalInterface 94 private interface NetworkObserverEventCallback { sendCallback(NetworkObserver o)95 void sendCallback(NetworkObserver o); 96 } 97 invokeForAllObservers(@onNull final NetworkObserverEventCallback callback)98 private void invokeForAllObservers(@NonNull final NetworkObserverEventCallback callback) { 99 // ConcurrentHashMap#entrySet is weakly consistent: observers that were in the map before 100 // creation will be processed, those added during traversal may or may not. 101 for (Map.Entry<NetworkObserver, Optional<Handler>> entry : mObservers.entrySet()) { 102 final NetworkObserver observer = entry.getKey(); 103 final Optional<Handler> handler = entry.getValue(); 104 if (handler.isPresent()) { 105 handler.get().post(() -> callback.sendCallback(observer)); 106 return; 107 } 108 109 try { 110 callback.sendCallback(observer); 111 } catch (RuntimeException e) { 112 Log.e(TAG, "Error sending callback to observer", e); 113 } 114 } 115 } 116 117 @Override onInterfaceClassActivityChanged(boolean isActive, int label, long timestamp, int uid)118 public void onInterfaceClassActivityChanged(boolean isActive, 119 int label, long timestamp, int uid) { 120 invokeForAllObservers(o -> o.onInterfaceClassActivityChanged( 121 isActive, label, timestamp, uid)); 122 } 123 124 /** 125 * Notify our observers of a limit reached. 126 */ 127 @Override onQuotaLimitReached(String alertName, String ifName)128 public void onQuotaLimitReached(String alertName, String ifName) { 129 invokeForAllObservers(o -> o.onQuotaLimitReached(alertName, ifName)); 130 } 131 132 @Override onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers)133 public void onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers) { 134 invokeForAllObservers(o -> o.onInterfaceDnsServerInfo(ifName, lifetime, servers)); 135 } 136 137 @Override onInterfaceAddressUpdated(String addr, String ifName, int flags, int scope)138 public void onInterfaceAddressUpdated(String addr, String ifName, int flags, int scope) { 139 final LinkAddress address = new LinkAddress(addr, flags, scope); 140 invokeForAllObservers(o -> o.onInterfaceAddressUpdated(address, ifName)); 141 } 142 143 @Override onInterfaceAddressRemoved(String addr, String ifName, int flags, int scope)144 public void onInterfaceAddressRemoved(String addr, 145 String ifName, int flags, int scope) { 146 final LinkAddress address = new LinkAddress(addr, flags, scope); 147 invokeForAllObservers(o -> o.onInterfaceAddressRemoved(address, ifName)); 148 } 149 150 @Override onInterfaceAdded(String ifName)151 public void onInterfaceAdded(String ifName) { 152 invokeForAllObservers(o -> o.onInterfaceAdded(ifName)); 153 } 154 155 @Override onInterfaceRemoved(String ifName)156 public void onInterfaceRemoved(String ifName) { 157 invokeForAllObservers(o -> o.onInterfaceRemoved(ifName)); 158 } 159 160 @Override onInterfaceChanged(String ifName, boolean up)161 public void onInterfaceChanged(String ifName, boolean up) { 162 invokeForAllObservers(o -> o.onInterfaceChanged(ifName, up)); 163 } 164 165 @Override onInterfaceLinkStateChanged(String ifName, boolean up)166 public void onInterfaceLinkStateChanged(String ifName, boolean up) { 167 invokeForAllObservers(o -> o.onInterfaceLinkStateChanged(ifName, up)); 168 } 169 170 @Override onRouteChanged(boolean updated, String route, String gateway, String ifName)171 public void onRouteChanged(boolean updated, String route, String gateway, String ifName) { 172 final RouteInfo processRoute = new RouteInfo(new IpPrefix(route), 173 ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway), 174 ifName, RTN_UNICAST); 175 if (updated) { 176 invokeForAllObservers(o -> o.onRouteUpdated(processRoute)); 177 } else { 178 invokeForAllObservers(o -> o.onRouteRemoved(processRoute)); 179 } 180 } 181 182 @Override onStrictCleartextDetected(int uid, String hex)183 public void onStrictCleartextDetected(int uid, String hex) {} 184 185 @Override getInterfaceVersion()186 public int getInterfaceVersion() { 187 return INetdUnsolicitedEventListener.VERSION; 188 } 189 } 190