NetworkManagementService.java revision 873f2145941cc28f6931dc18b5e9987bd22e2e19
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.os.INetworkManagementService;
28import android.os.Handler;
29import android.text.TextUtils;
30import android.util.Log;
31import java.util.ArrayList;
32
33import android.provider.Settings;
34import android.content.ContentResolver;
35import android.database.ContentObserver;
36
37import java.io.File;
38import java.io.FileReader;
39import java.lang.IllegalStateException;
40
41import java.net.InetAddress;
42import java.net.UnknownHostException;
43
44/**
45 * @hide
46 */
47class NetworkManagementService extends INetworkManagementService.Stub {
48
49    private static final String TAG = "NetworkManagmentService";
50
51    class NetdResponseCode {
52        public static final int InterfaceListResult       = 110;
53        public static final int TetherInterfaceListResult = 111;
54        public static final int TetherDnsFwdTgtListResult = 112;
55
56        public static final int TetherStatusResult        = 210;
57        public static final int IpFwdStatusResult         = 211;
58    }
59
60    /**
61     * Binder context for this service
62     */
63    private Context mContext;
64
65    /**
66     * connector object for communicating with netd
67     */
68    private NativeDaemonConnector mConnector;
69
70    /**
71     * Constructs a new NetworkManagementService instance
72     *
73     * @param context  Binder context for this service
74     */
75    private NetworkManagementService(Context context) {
76        mContext = context;
77
78        mConnector = new NativeDaemonConnector(
79                new NetdCallbackReceiver(), "netd", 10, "NetdConnector");
80        Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
81        thread.start();
82    }
83
84    //
85    // Netd Callback handling
86    //
87
88    class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
89        public void onDaemonConnected() {
90            new Thread() {
91                public void run() {
92                    // XXX: Run some tests
93                }
94            }.start();
95        }
96        public boolean onEvent(int code, String raw, String[] cooked) {
97           return false;
98        }
99    }
100
101    //
102    // INetworkManagementService members
103    //
104
105    public String[] listInterfaces() throws IllegalStateException {
106        mContext.enforceCallingOrSelfPermission(
107                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
108
109        ArrayList<String> rsp = mConnector.doCommand("list_interfaces");
110
111        String[] rdata = new String[rsp.size()];
112        int idx = 0;
113
114        for (String line : rsp) {
115            String []tok = line.split(" ");
116            int code = Integer.parseInt(tok[0]);
117            if (code == NetdResponseCode.InterfaceListResult) {
118                if (tok.length !=2) {
119                    throw new IllegalStateException(
120                            String.format("Malformatted list entry '%s'", line));
121                }
122                rdata[idx++] = tok[1];
123            } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
124                return rdata;
125            } else {
126                throw new IllegalStateException(String.format("Unexpected response code %d", code));
127            }
128        }
129        throw new IllegalStateException("Got an empty response");
130    }
131
132    public void shutdown() {
133        if (mContext.checkCallingOrSelfPermission(
134                android.Manifest.permission.SHUTDOWN)
135                != PackageManager.PERMISSION_GRANTED) {
136            throw new SecurityException("Requires SHUTDOWN permission");
137        }
138
139        Log.d(TAG, "Shutting down");
140    }
141
142    public boolean getIpForwardingEnabled() throws IllegalStateException{
143        mContext.enforceCallingOrSelfPermission(
144                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
145
146        ArrayList<String> rsp = mConnector.doCommand("ipfwd status");
147
148        for (String line : rsp) {
149            String []tok = line.split(" ");
150            int code = Integer.parseInt(tok[0]);
151            if (code == NetdResponseCode.IpFwdStatusResult) {
152                // 211 Forwarding <enabled/disabled>
153                if (tok.length !=2) {
154                    throw new IllegalStateException(
155                            String.format("Malformatted list entry '%s'", line));
156                }
157                if (tok[2].equals("enabled"))
158                    return true;
159                return false;
160            } else {
161                throw new IllegalStateException(String.format("Unexpected response code %d", code));
162            }
163        }
164        throw new IllegalStateException("Got an empty response");
165    }
166
167    public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
168        mContext.enforceCallingOrSelfPermission(
169                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
170        mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
171    }
172
173    public void startTethering(String dhcpRangeStart, String dhcpRangeEnd)
174             throws IllegalStateException {
175        mContext.enforceCallingOrSelfPermission(
176                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
177        mConnector.doCommand(String.format("tether start %s %s", dhcpRangeStart, dhcpRangeEnd));
178    }
179
180    public void stopTethering() throws IllegalStateException {
181        mContext.enforceCallingOrSelfPermission(
182                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
183        mConnector.doCommand("tether stop");
184    }
185
186    public boolean isTetheringStarted() throws IllegalStateException {
187        mContext.enforceCallingOrSelfPermission(
188                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
189
190        ArrayList<String> rsp = mConnector.doCommand("tether status");
191
192        for (String line : rsp) {
193            String []tok = line.split(" ");
194            int code = Integer.parseInt(tok[0]);
195            if (code == NetdResponseCode.TetherStatusResult) {
196                // XXX: Tethering services <started/stopped> <TBD>...
197                if (tok[2].equals("started"))
198                    return true;
199                return false;
200            } else {
201                throw new IllegalStateException(String.format("Unexpected response code %d", code));
202            }
203        }
204        throw new IllegalStateException("Got an empty response");
205    }
206
207    public void tetherInterface(String iface) throws IllegalStateException {
208        mContext.enforceCallingOrSelfPermission(
209                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
210        mConnector.doCommand("tether interface add " + iface);
211    }
212
213    public void untetherInterface(String iface) {
214        mContext.enforceCallingOrSelfPermission(
215                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
216        mConnector.doCommand("tether interface remove " + iface);
217    }
218
219    public String[] listTetheredInterfaces() throws IllegalStateException {
220        mContext.enforceCallingOrSelfPermission(
221                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
222
223        ArrayList<String> rsp = mConnector.doCommand("tether interface list");
224
225        String[] rdata = new String[rsp.size()];
226        int idx = 0;
227
228        for (String line : rsp) {
229            String []tok = line.split(" ");
230            int code = Integer.parseInt(tok[0]);
231            if (code == NetdResponseCode.TetherInterfaceListResult) {
232                if (tok.length !=2) {
233                    throw new IllegalStateException(
234                            String.format("Malformatted list entry '%s'", line));
235                }
236                rdata[idx++] = tok[1];
237            } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
238                return rdata;
239            } else {
240                throw new IllegalStateException(String.format("Unexpected response code %d", code));
241            }
242        }
243        throw new IllegalStateException("Got an empty response");
244    }
245
246    public void setDnsForwarders(String[] dns) throws IllegalStateException {
247        mContext.enforceCallingOrSelfPermission(
248                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
249        try {
250            String cmd = "tether dns set ";
251            for (String s : dns) {
252                cmd += InetAddress.getByName(s).toString() + " ";
253            }
254            mConnector.doCommand(cmd);
255        } catch (UnknownHostException e) {
256            throw new IllegalStateException("Error resolving dns name", e);
257        }
258    }
259
260    public String[] getDnsForwarders() throws IllegalStateException {
261        mContext.enforceCallingOrSelfPermission(
262                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
263
264        ArrayList<String> rsp = mConnector.doCommand("tether dns list");
265
266        String[] rdata = new String[rsp.size()];
267        int idx = 0;
268
269        for (String line : rsp) {
270            String []tok = line.split(" ");
271            int code = Integer.parseInt(tok[0]);
272            if (code == NetdResponseCode.TetherDnsFwdTgtListResult) {
273                if (tok.length !=2) {
274                    throw new IllegalStateException(
275                            String.format("Malformatted list entry '%s'", line));
276                }
277                rdata[idx++] = tok[1];
278            } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
279                return rdata;
280            } else {
281                throw new IllegalStateException(String.format("Unexpected response code %d", code));
282            }
283        }
284        throw new IllegalStateException("Got an empty response");
285    }
286
287    public void enableNat(String internalInterface, String externalInterface)
288            throws IllegalStateException {
289        mContext.enforceCallingOrSelfPermission(
290                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
291        mConnector.doCommand(
292                String.format("nat enable %s %s", internalInterface, externalInterface));
293    }
294
295    public void disableNat(String internalInterface, String externalInterface)
296            throws IllegalStateException {
297        mContext.enforceCallingOrSelfPermission(
298                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
299        mConnector.doCommand(
300                String.format("nat disable %s %s", internalInterface, externalInterface));
301    }
302}
303
304