NetworkManagementService.java revision d1df8ac6d076ef15ba8857211da2e447b6505fb3
1/* 2 * Copyright (C) 2007 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 17package com.android.server; 18 19import android.app.PendingIntent; 20import android.content.BroadcastReceiver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.content.res.Resources; 25import android.content.pm.PackageManager; 26import android.net.Uri; 27import android.net.InterfaceConfiguration; 28import android.net.INetworkManagementEventObserver; 29import android.os.INetworkManagementService; 30import android.os.Handler; 31import android.text.TextUtils; 32import android.util.Log; 33import java.util.ArrayList; 34import java.util.StringTokenizer; 35import android.provider.Settings; 36import android.content.ContentResolver; 37import android.database.ContentObserver; 38 39import java.io.File; 40import java.io.FileReader; 41import java.lang.IllegalStateException; 42 43import java.net.InetAddress; 44import java.net.UnknownHostException; 45 46/** 47 * @hide 48 */ 49class NetworkManagementService extends INetworkManagementService.Stub { 50 51 private static final String TAG = "NetworkManagmentService"; 52 53 class NetdResponseCode { 54 public static final int InterfaceListResult = 110; 55 public static final int TetherInterfaceListResult = 111; 56 public static final int TetherDnsFwdTgtListResult = 112; 57 public static final int TtyListResult = 113; 58 59 public static final int TetherStatusResult = 210; 60 public static final int IpFwdStatusResult = 211; 61 public static final int InterfaceGetCfgResult = 213; 62 } 63 64 /** 65 * Binder context for this service 66 */ 67 private Context mContext; 68 69 /** 70 * connector object for communicating with netd 71 */ 72 private NativeDaemonConnector mConnector; 73 74 private ArrayList<INetworkManagementEventObserver> mObservers; 75 76 /** 77 * Constructs a new NetworkManagementService instance 78 * 79 * @param context Binder context for this service 80 */ 81 public NetworkManagementService(Context context) { 82 mContext = context; 83 84 mObservers = new ArrayList<INetworkManagementEventObserver>(); 85 86 mConnector = new NativeDaemonConnector( 87 new NetdCallbackReceiver(), "netd", 10, "NetdConnector"); 88 Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName()); 89 thread.start(); 90 } 91 92 public void registerObserver(INetworkManagementEventObserver obs) { 93 Log.d(TAG, "Registering observer"); 94 mObservers.add(obs); 95 } 96 97 public void unregisterObserver(INetworkManagementEventObserver obs) { 98 Log.d(TAG, "Unregistering observer"); 99 mObservers.remove(mObservers.indexOf(obs)); 100 } 101 102 /** 103 * Notify our observers of an interface link status change 104 */ 105 private void notifyInterfaceLinkStatusChanged(String iface, boolean link) { 106 for (INetworkManagementEventObserver obs : mObservers) { 107 try { 108 obs.interfaceLinkStatusChanged(iface, link); 109 } catch (Exception ex) { 110 Log.w(TAG, "Observer notifier failed", ex); 111 } 112 } 113 } 114 115 /** 116 * Notify our observers of an interface addition. 117 */ 118 private void notifyInterfaceAdded(String iface) { 119 for (INetworkManagementEventObserver obs : mObservers) { 120 try { 121 obs.interfaceAdded(iface); 122 } catch (Exception ex) { 123 Log.w(TAG, "Observer notifier failed", ex); 124 } 125 } 126 } 127 128 /** 129 * Notify our observers of an interface removal. 130 */ 131 private void notifyInterfaceRemoved(String iface) { 132 for (INetworkManagementEventObserver obs : mObservers) { 133 try { 134 obs.interfaceRemoved(iface); 135 } catch (Exception ex) { 136 Log.w(TAG, "Observer notifier failed", ex); 137 } 138 } 139 } 140 141 142 // 143 // Netd Callback handling 144 // 145 146 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks { 147 public void onDaemonConnected() { 148 new Thread() { 149 public void run() { 150 // XXX: Run some tests 151 } 152 }.start(); 153 } 154 public boolean onEvent(int code, String raw, String[] cooked) { 155 return false; 156 } 157 } 158 159 private static int stringToIpAddr(String addrString) throws UnknownHostException { 160 try { 161 String[] parts = addrString.split("\\."); 162 if (parts.length != 4) { 163 throw new UnknownHostException(addrString); 164 } 165 166 int a = Integer.parseInt(parts[0]) ; 167 int b = Integer.parseInt(parts[1]) << 8; 168 int c = Integer.parseInt(parts[2]) << 16; 169 int d = Integer.parseInt(parts[3]) << 24; 170 171 return a | b | c | d; 172 } catch (NumberFormatException ex) { 173 throw new UnknownHostException(addrString); 174 } 175 } 176 177 public static String intToIpString(int i) { 178 return ((i >> 24 ) & 0xFF) + "." + ((i >> 16 ) & 0xFF) + "." + ((i >> 8 ) & 0xFF) + "." + 179 (i & 0xFF); 180 } 181 182 // 183 // INetworkManagementService members 184 // 185 186 public String[] listInterfaces() throws IllegalStateException { 187 mContext.enforceCallingOrSelfPermission( 188 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 189 190 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult); 191 } 192 193 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException { 194 String rsp = mConnector.doCommand("interface getcfg " + iface).get(0); 195 Log.d(TAG, String.format("rsp <%s>", rsp)); 196 197 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz.zzz.zzz.zzz [flag1 flag2 flag3] 198 StringTokenizer st = new StringTokenizer(rsp); 199 200 try { 201 int code = Integer.parseInt(st.nextToken(" ")); 202 if (code != NetdResponseCode.InterfaceGetCfgResult) { 203 throw new IllegalStateException( 204 String.format("Expected code %d, but got %d", 205 NetdResponseCode.InterfaceGetCfgResult, code)); 206 } 207 } catch (NumberFormatException nfe) { 208 throw new IllegalStateException( 209 String.format("Invalid response from daemon (%s)", rsp)); 210 } 211 212 InterfaceConfiguration cfg = new InterfaceConfiguration(); 213 cfg.hwAddr = st.nextToken(" "); 214 try { 215 cfg.ipAddr = stringToIpAddr(st.nextToken(" ")); 216 } catch (UnknownHostException uhe) { 217 Log.e(TAG, "Failed to parse ipaddr", uhe); 218 cfg.ipAddr = 0; 219 } 220 221 try { 222 cfg.netmask = stringToIpAddr(st.nextToken(" ")); 223 } catch (UnknownHostException uhe) { 224 Log.e(TAG, "Failed to parse netmask", uhe); 225 cfg.netmask = 0; 226 } 227 cfg.interfaceFlags = st.nextToken("]"); 228 Log.d(TAG, String.format("flags <%s>", cfg.interfaceFlags)); 229 return cfg; 230 } 231 232 public void setInterfaceConfig( 233 String iface, InterfaceConfiguration cfg) throws IllegalStateException { 234 String cmd = String.format("interface setcfg %s %s %s", iface, 235 intToIpString(cfg.ipAddr), intToIpString(cfg.netmask), cfg.interfaceFlags); 236 mConnector.doCommand(cmd); 237 } 238 239 public void shutdown() { 240 if (mContext.checkCallingOrSelfPermission( 241 android.Manifest.permission.SHUTDOWN) 242 != PackageManager.PERMISSION_GRANTED) { 243 throw new SecurityException("Requires SHUTDOWN permission"); 244 } 245 246 Log.d(TAG, "Shutting down"); 247 } 248 249 public boolean getIpForwardingEnabled() throws IllegalStateException{ 250 mContext.enforceCallingOrSelfPermission( 251 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 252 253 ArrayList<String> rsp = mConnector.doCommand("ipfwd status"); 254 255 for (String line : rsp) { 256 String []tok = line.split(" "); 257 int code = Integer.parseInt(tok[0]); 258 if (code == NetdResponseCode.IpFwdStatusResult) { 259 // 211 Forwarding <enabled/disabled> 260 if (tok.length !=2) { 261 throw new IllegalStateException( 262 String.format("Malformatted list entry '%s'", line)); 263 } 264 if (tok[2].equals("enabled")) 265 return true; 266 return false; 267 } else { 268 throw new IllegalStateException(String.format("Unexpected response code %d", code)); 269 } 270 } 271 throw new IllegalStateException("Got an empty response"); 272 } 273 274 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException { 275 mContext.enforceCallingOrSelfPermission( 276 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 277 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis"))); 278 } 279 280 public void startTethering(String dhcpRangeStart, String dhcpRangeEnd) 281 throws IllegalStateException { 282 mContext.enforceCallingOrSelfPermission( 283 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 284 mConnector.doCommand(String.format("tether start %s %s", dhcpRangeStart, dhcpRangeEnd)); 285 } 286 287 public void stopTethering() throws IllegalStateException { 288 mContext.enforceCallingOrSelfPermission( 289 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 290 mConnector.doCommand("tether stop"); 291 } 292 293 public boolean isTetheringStarted() throws IllegalStateException { 294 mContext.enforceCallingOrSelfPermission( 295 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 296 297 ArrayList<String> rsp = mConnector.doCommand("tether status"); 298 299 for (String line : rsp) { 300 String []tok = line.split(" "); 301 int code = Integer.parseInt(tok[0]); 302 if (code == NetdResponseCode.TetherStatusResult) { 303 // XXX: Tethering services <started/stopped> <TBD>... 304 if (tok[2].equals("started")) 305 return true; 306 return false; 307 } else { 308 throw new IllegalStateException(String.format("Unexpected response code %d", code)); 309 } 310 } 311 throw new IllegalStateException("Got an empty response"); 312 } 313 314 public void tetherInterface(String iface) throws IllegalStateException { 315 mContext.enforceCallingOrSelfPermission( 316 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 317 mConnector.doCommand("tether interface add " + iface); 318 } 319 320 public void untetherInterface(String iface) { 321 mContext.enforceCallingOrSelfPermission( 322 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 323 mConnector.doCommand("tether interface remove " + iface); 324 } 325 326 public String[] listTetheredInterfaces() throws IllegalStateException { 327 mContext.enforceCallingOrSelfPermission( 328 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 329 return mConnector.doListCommand( 330 "tether interface list", NetdResponseCode.TetherInterfaceListResult); 331 } 332 333 public void setDnsForwarders(String[] dns) throws IllegalStateException { 334 mContext.enforceCallingOrSelfPermission( 335 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 336 try { 337 String cmd = "tether dns set "; 338 for (String s : dns) { 339 cmd += InetAddress.getByName(s).toString() + " "; 340 } 341 mConnector.doCommand(cmd); 342 } catch (UnknownHostException e) { 343 throw new IllegalStateException("Error resolving dns name", e); 344 } 345 } 346 347 public String[] getDnsForwarders() throws IllegalStateException { 348 mContext.enforceCallingOrSelfPermission( 349 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 350 return mConnector.doListCommand( 351 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult); 352 } 353 354 public void enableNat(String internalInterface, String externalInterface) 355 throws IllegalStateException { 356 mContext.enforceCallingOrSelfPermission( 357 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 358 mConnector.doCommand( 359 String.format("nat enable %s %s", internalInterface, externalInterface)); 360 } 361 362 public void disableNat(String internalInterface, String externalInterface) 363 throws IllegalStateException { 364 mContext.enforceCallingOrSelfPermission( 365 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 366 mConnector.doCommand( 367 String.format("nat disable %s %s", internalInterface, externalInterface)); 368 } 369 370 public String[] listTtys() throws IllegalStateException { 371 mContext.enforceCallingOrSelfPermission( 372 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 373 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult); 374 } 375 376 public void attachPppd(String tty, String localAddr, String remoteAddr) 377 throws IllegalStateException { 378 try { 379 mContext.enforceCallingOrSelfPermission( 380 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 381 mConnector.doCommand(String.format("pppd attach %s %s %s", tty, 382 InetAddress.getByName(localAddr).toString(), 383 InetAddress.getByName(localAddr).toString())); 384 } catch (UnknownHostException e) { 385 throw new IllegalStateException("Error resolving addr", e); 386 } 387 } 388 389 public void detachPppd(String tty) throws IllegalStateException { 390 mContext.enforceCallingOrSelfPermission( 391 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 392 mConnector.doCommand(String.format("pppd detach %s", tty)); 393 } 394} 395 396