blob: 8594e444438fb97111e1426264da77a017c7ad48 [file] [log] [blame]
San Mehat873f2142010-01-14 10:25:07 -08001/*
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;
San Mehated4fc8a2010-01-22 12:28:36 -080027import android.net.InterfaceConfiguration;
San Mehat4d02d002010-01-22 16:07:46 -080028import android.net.INetworkManagementEventObserver;
San Mehat873f2142010-01-14 10:25:07 -080029import android.os.INetworkManagementService;
30import android.os.Handler;
31import android.text.TextUtils;
32import android.util.Log;
33import java.util.ArrayList;
San Mehated4fc8a2010-01-22 12:28:36 -080034import java.util.StringTokenizer;
San Mehat873f2142010-01-14 10:25:07 -080035import 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;
San Mehat72759df2010-01-19 13:50:37 -080057 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -080058
59 public static final int TetherStatusResult = 210;
60 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -080061 public static final int InterfaceGetCfgResult = 213;
San Mehat873f2142010-01-14 10:25:07 -080062 }
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
San Mehat4d02d002010-01-22 16:07:46 -080074 private ArrayList<INetworkManagementEventObserver> mObservers;
75
San Mehat873f2142010-01-14 10:25:07 -080076 /**
77 * Constructs a new NetworkManagementService instance
78 *
79 * @param context Binder context for this service
80 */
81 private NetworkManagementService(Context context) {
82 mContext = context;
83
San Mehat4d02d002010-01-22 16:07:46 -080084 mObservers = new ArrayList<INetworkManagementEventObserver>();
85
San Mehat873f2142010-01-14 10:25:07 -080086 mConnector = new NativeDaemonConnector(
87 new NetdCallbackReceiver(), "netd", 10, "NetdConnector");
88 Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
89 thread.start();
90 }
91
San Mehat4d02d002010-01-22 16:07:46 -080092 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
San Mehat873f2142010-01-14 10:25:07 -0800142 //
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
San Mehated4fc8a2010-01-22 12:28:36 -0800159 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
San Mehat873f2142010-01-14 10:25:07 -0800182 //
183 // INetworkManagementService members
184 //
185
186 public String[] listInterfaces() throws IllegalStateException {
187 mContext.enforceCallingOrSelfPermission(
188 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
189
San Mehated4fc8a2010-01-22 12:28:36 -0800190 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);
San Mehat873f2142010-01-14 10:25:07 -0800237 }
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");
San Mehat72759df2010-01-19 13:50:37 -0800329 return mConnector.doListCommand(
330 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
San Mehat873f2142010-01-14 10:25:07 -0800331 }
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");
San Mehat72759df2010-01-19 13:50:37 -0800350 return mConnector.doListCommand(
351 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
San Mehat873f2142010-01-14 10:25:07 -0800352 }
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 }
San Mehat72759df2010-01-19 13:50:37 -0800369
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 }
San Mehat873f2142010-01-14 10:25:07 -0800394}
395