blob: a5dc008d4e6c6fbbb2b05c0650301485c2174e17 [file] [log] [blame]
Felipe Leme50a235e2016-01-15 18:37:06 -08001/*
2 * Copyright (C) 2016 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.net;
18
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080019import static android.net.wifi.WifiInfo.removeDoubleQuotes;
20import static com.android.server.net.NetworkPolicyManagerService.newWifiPolicy;
Felipe Lemede4e8e32016-02-02 18:55:22 -080021import static com.android.server.net.NetworkPolicyManagerService.TAG;
Felipe Leme50a235e2016-01-15 18:37:06 -080022
Felipe Lemede4e8e32016-02-02 18:55:22 -080023import java.io.PrintWriter;
24import java.util.ArrayList;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080025import java.util.HashSet;
Felipe Lemede4e8e32016-02-02 18:55:22 -080026import java.util.List;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080027import java.util.Set;
Felipe Lemede4e8e32016-02-02 18:55:22 -080028
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080029import android.content.Context;
Felipe Leme50a235e2016-01-15 18:37:06 -080030import android.net.INetworkPolicyManager;
Felipe Lemede4e8e32016-02-02 18:55:22 -080031import android.net.NetworkPolicy;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080032import android.net.NetworkTemplate;
33import android.net.wifi.WifiConfiguration;
34import android.net.wifi.WifiManager;
Felipe Leme9778f762016-01-27 14:46:39 -080035import android.os.Binder;
Felipe Leme50a235e2016-01-15 18:37:06 -080036import android.os.RemoteException;
37import android.os.ShellCommand;
Felipe Lemede4e8e32016-02-02 18:55:22 -080038import android.util.Log;
Felipe Leme50a235e2016-01-15 18:37:06 -080039
Felipe Lemede4e8e32016-02-02 18:55:22 -080040class NetworkPolicyManagerShellCommand extends ShellCommand {
Felipe Leme50a235e2016-01-15 18:37:06 -080041
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080042 private final INetworkPolicyManager mInterface;
43 private final WifiManager mWifiManager;
Felipe Leme50a235e2016-01-15 18:37:06 -080044
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080045 NetworkPolicyManagerShellCommand(Context context, INetworkPolicyManager service) {
Felipe Leme50a235e2016-01-15 18:37:06 -080046 mInterface = service;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080047 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Felipe Leme50a235e2016-01-15 18:37:06 -080048 }
49
50 @Override
51 public int onCommand(String cmd) {
52 if (cmd == null) {
53 return handleDefaultCommands(cmd);
54 }
55 final PrintWriter pw = getOutPrintWriter();
56 try {
57 switch(cmd) {
58 case "get":
59 return runGet();
60 case "set":
61 return runSet();
62 case "list":
63 return runList();
64 case "add":
65 return runAdd();
66 case "remove":
67 return runRemove();
68 default:
69 return handleDefaultCommands(cmd);
70 }
71 } catch (RemoteException e) {
72 pw.println("Remote exception: " + e);
73 }
74 return -1;
75 }
76
77 @Override
78 public void onHelp() {
79 final PrintWriter pw = getOutPrintWriter();
80 pw.println("Network policy manager (netpolicy) commands:");
81 pw.println(" help");
82 pw.println(" Print this help text.");
83 pw.println("");
Felipe Leme50a235e2016-01-15 18:37:06 -080084 pw.println(" add restrict-background-whitelist UID");
85 pw.println(" Adds a UID to the whitelist for restrict background usage.");
Felipe Lemede4e8e32016-02-02 18:55:22 -080086 pw.println(" get metered-network ID");
87 pw.println(" Checks whether the given non-mobile network is metered or not.");
88 pw.println(" get restrict-background");
89 pw.println(" Gets the global restrict background usage status.");
90 pw.println(" list metered-networks [BOOLEAN]");
91 pw.println(" Lists all non-mobile networks and whether they are metered or not.");
92 pw.println(" If a boolean argument is passed, filters just the metered (or unmetered)");
93 pw.println(" networks.");
94 pw.println(" list restrict-background-whitelist");
95 pw.println(" Lists UIDs that are whitelisted for restrict background usage.");
Felipe Leme50a235e2016-01-15 18:37:06 -080096 pw.println(" remove restrict-background-whitelist UID");
97 pw.println(" Removes a UID from the whitelist for restrict background usage.");
Felipe Lemede4e8e32016-02-02 18:55:22 -080098 pw.println(" set metered-network ID BOOLEAN");
99 pw.println(" Toggles whether the given non-mobile network is metered.");
100 pw.println(" set restrict-background BOOLEAN");
101 pw.println(" Sets the global restrict background usage status.");
Felipe Leme50a235e2016-01-15 18:37:06 -0800102 }
103
104 private int runGet() throws RemoteException {
105 final PrintWriter pw = getOutPrintWriter();
106 final String type = getNextArg();
107 if (type == null) {
108 pw.println("Error: didn't specify type of data to get");
109 return -1;
110 }
111 switch(type) {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800112 case "metered-network":
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800113 return getMeteredWifiNetwork();
Felipe Leme50a235e2016-01-15 18:37:06 -0800114 case "restrict-background":
Felipe Leme9778f762016-01-27 14:46:39 -0800115 return getRestrictBackground();
Felipe Leme50a235e2016-01-15 18:37:06 -0800116 }
117 pw.println("Error: unknown get type '" + type + "'");
118 return -1;
119 }
120
121 private int runSet() throws RemoteException {
122 final PrintWriter pw = getOutPrintWriter();
123 final String type = getNextArg();
124 if (type == null) {
125 pw.println("Error: didn't specify type of data to set");
126 return -1;
127 }
128 switch(type) {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800129 case "metered-network":
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800130 return setMeteredWifiNetwork();
Felipe Leme50a235e2016-01-15 18:37:06 -0800131 case "restrict-background":
Felipe Leme9778f762016-01-27 14:46:39 -0800132 return setRestrictBackground();
Felipe Leme50a235e2016-01-15 18:37:06 -0800133 }
134 pw.println("Error: unknown set type '" + type + "'");
135 return -1;
136 }
137
138 private int runList() throws RemoteException {
139 final PrintWriter pw = getOutPrintWriter();
140 final String type = getNextArg();
141 if (type == null) {
142 pw.println("Error: didn't specify type of data to list");
143 return -1;
144 }
145 switch(type) {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800146 case "metered-networks":
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800147 return listMeteredWifiNetworks();
Felipe Leme50a235e2016-01-15 18:37:06 -0800148 case "restrict-background-whitelist":
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800149 return listRestrictBackgroundWhitelist();
Felipe Leme50a235e2016-01-15 18:37:06 -0800150 }
151 pw.println("Error: unknown list type '" + type + "'");
152 return -1;
153 }
154
155 private int runAdd() throws RemoteException {
156 final PrintWriter pw = getOutPrintWriter();
157 final String type = getNextArg();
158 if (type == null) {
159 pw.println("Error: didn't specify type of data to add");
160 return -1;
161 }
162 switch(type) {
163 case "restrict-background-whitelist":
164 return addRestrictBackgroundWhitelist();
165 }
166 pw.println("Error: unknown add type '" + type + "'");
167 return -1;
168 }
169
170 private int runRemove() throws RemoteException {
171 final PrintWriter pw = getOutPrintWriter();
172 final String type = getNextArg();
173 if (type == null) {
174 pw.println("Error: didn't specify type of data to remove");
175 return -1;
176 }
177 switch(type) {
178 case "restrict-background-whitelist":
179 return removeRestrictBackgroundWhitelist();
180 }
181 pw.println("Error: unknown remove type '" + type + "'");
182 return -1;
183 }
184
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800185 private int listRestrictBackgroundWhitelist() throws RemoteException {
Felipe Leme50a235e2016-01-15 18:37:06 -0800186 final PrintWriter pw = getOutPrintWriter();
187 final int[] uids = mInterface.getRestrictBackgroundWhitelistedUids();
188 pw.print("Restrict background whitelisted UIDs: ");
189 if (uids.length == 0) {
190 pw.println("none");
191 } else {
192 for (int i = 0; i < uids.length; i++) {
193 int uid = uids[i];
194 pw.print(uid);
195 pw.print(' ');
196 }
197 }
198 pw.println();
199 return 0;
200 }
201
Felipe Leme9778f762016-01-27 14:46:39 -0800202 private int getRestrictBackground() throws RemoteException {
Felipe Leme50a235e2016-01-15 18:37:06 -0800203 final PrintWriter pw = getOutPrintWriter();
204 pw.print("Restrict background status: ");
205 pw.println(mInterface.getRestrictBackground() ? "enabled" : "disabled");
206 return 0;
207 }
208
Felipe Leme9778f762016-01-27 14:46:39 -0800209 private int setRestrictBackground() throws RemoteException {
Felipe Leme50a235e2016-01-15 18:37:06 -0800210 final int enabled = getNextBooleanArg();
211 if (enabled < 0) {
212 return enabled;
213 }
Felipe Leme6a05eee2016-02-19 14:43:51 -0800214 mInterface.setRestrictBackground(enabled > 0);
Felipe Leme50a235e2016-01-15 18:37:06 -0800215 return 0;
216 }
217
218 private int addRestrictBackgroundWhitelist() throws RemoteException {
219 final int uid = getUidFromNextArg();
220 if (uid < 0) {
221 return uid;
222 }
Felipe Leme6a05eee2016-02-19 14:43:51 -0800223 mInterface.addRestrictBackgroundWhitelistedUid(uid);
Felipe Leme50a235e2016-01-15 18:37:06 -0800224 return 0;
225 }
226
227 private int removeRestrictBackgroundWhitelist() throws RemoteException {
228 final int uid = getUidFromNextArg();
229 if (uid < 0) {
230 return uid;
231 }
Felipe Leme6a05eee2016-02-19 14:43:51 -0800232 mInterface.removeRestrictBackgroundWhitelistedUid(uid);
Felipe Leme50a235e2016-01-15 18:37:06 -0800233 return 0;
234 }
235
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800236 private int listMeteredWifiNetworks() throws RemoteException {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800237 final PrintWriter pw = getOutPrintWriter();
238 final String arg = getNextArg();
239 final Boolean filter = arg == null ? null : Boolean.valueOf(arg);
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800240 for (NetworkPolicy policy : getWifiPolicies()) {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800241 if (filter != null && filter.booleanValue() != policy.metered) {
242 continue;
243 }
244 pw.print(getNetworkId(policy));
245 pw.print(';');
246 pw.println(policy.metered);
247 }
248 return 0;
249 }
250
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800251 private int getMeteredWifiNetwork() throws RemoteException {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800252 final PrintWriter pw = getOutPrintWriter();
253 final String id = getNextArg();
254 if (id == null) {
255 pw.println("Error: didn't specify ID");
256 return -1;
257 }
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800258 final List<NetworkPolicy> policies = getWifiPolicies();
Felipe Lemede4e8e32016-02-02 18:55:22 -0800259 for (NetworkPolicy policy: policies) {
260 if (id.equals(getNetworkId(policy))) {
261 pw.println(policy.metered);
262 return 0;
263 }
264 }
265 return 0;
266 }
267
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800268 private int setMeteredWifiNetwork() throws RemoteException {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800269 final PrintWriter pw = getOutPrintWriter();
270 final String id = getNextArg();
271 if (id == null) {
272 pw.println("Error: didn't specify ID");
273 return -1;
274 }
275 final String arg = getNextArg();
276 if (arg == null) {
277 pw.println("Error: didn't specify BOOLEAN");
278 return -1;
279 }
280 final boolean metered = Boolean.valueOf(arg);
281 final NetworkPolicy[] policies = mInterface.getNetworkPolicies(null);
282 boolean changed = false;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800283 // First try to find a policy with such id
Felipe Lemede4e8e32016-02-02 18:55:22 -0800284 for (NetworkPolicy policy : policies) {
285 if (policy.template.isMatchRuleMobile() || policy.metered == metered) {
286 continue;
287 }
288 final String networkId = getNetworkId(policy);
289 if (id.equals(networkId)) {
290 Log.i(TAG, "Changing " + networkId + " metered status to " + metered);
291 policy.metered = metered;
292 changed = true;
293 }
294 }
295 if (changed) {
296 mInterface.setNetworkPolicies(policies);
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800297 return 0;
298 }
299 // Policy not found: check if there is a saved wi-fi with such id.
300 for (WifiConfiguration config : mWifiManager.getConfiguredNetworks()) {
301 final String ssid = removeDoubleQuotes(config.SSID);
302 if (id.equals(ssid)) {
303 final NetworkPolicy policy = newPolicy(ssid);
304 Log.i(TAG, "Creating new policy for " + ssid + ": " + policy);
305 final NetworkPolicy[] newPolicies = new NetworkPolicy[policies.length + 1];
306 System.arraycopy(policies, 0, newPolicies, 0, policies.length);
307 newPolicies[newPolicies.length - 1] = policy;
308 mInterface.setNetworkPolicies(newPolicies);
309 }
Felipe Lemede4e8e32016-02-02 18:55:22 -0800310 }
311 return 0;
312 }
313
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800314 private List<NetworkPolicy> getWifiPolicies() throws RemoteException {
315 // First gets a list of saved wi-fi networks.
316 final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
317 final Set<String> ssids = new HashSet<>(configs.size());
318 for (WifiConfiguration config : configs) {
319 ssids.add(removeDoubleQuotes(config.SSID));
320 }
321
322 // Then gets the saved policies.
Felipe Lemede4e8e32016-02-02 18:55:22 -0800323 final NetworkPolicy[] policies = mInterface.getNetworkPolicies(null);
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800324 final List<NetworkPolicy> wifiPolicies = new ArrayList<NetworkPolicy>(policies.length);
Felipe Lemede4e8e32016-02-02 18:55:22 -0800325 for (NetworkPolicy policy: policies) {
326 if (!policy.template.isMatchRuleMobile()) {
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800327 wifiPolicies.add(policy);
328 final String netId = getNetworkId(policy);
329 ssids.remove(netId);
Felipe Lemede4e8e32016-02-02 18:55:22 -0800330 }
331 }
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800332 // Finally, creates new default policies for saved WI-FIs not policied yet.
333 for (String ssid : ssids) {
334 final NetworkPolicy policy = newPolicy(ssid);
335 wifiPolicies.add(policy);
336 }
337 return wifiPolicies;
338 }
339
340 private NetworkPolicy newPolicy(String ssid) {
341 final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(ssid);
342 final NetworkPolicy policy = newWifiPolicy(template, false);
343 return policy;
Felipe Lemede4e8e32016-02-02 18:55:22 -0800344 }
345
346 private String getNetworkId(NetworkPolicy policy) {
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800347 return removeDoubleQuotes(policy.template.getNetworkId());
Felipe Lemede4e8e32016-02-02 18:55:22 -0800348 }
349
Felipe Leme50a235e2016-01-15 18:37:06 -0800350 private int getNextBooleanArg() {
351 final PrintWriter pw = getOutPrintWriter();
352 final String arg = getNextArg();
353 if (arg == null) {
354 pw.println("Error: didn't specify BOOLEAN");
355 return -1;
356 }
357 return Boolean.valueOf(arg) ? 1 : 0;
358 }
359
360 private int getUidFromNextArg() {
361 final PrintWriter pw = getOutPrintWriter();
362 final String arg = getNextArg();
363 if (arg == null) {
364 pw.println("Error: didn't specify UID");
365 return -1;
366 }
367 try {
368 return Integer.parseInt(arg);
369 } catch (NumberFormatException e) {
370 pw.println("Error: UID (" + arg + ") should be a number");
371 return -2;
372 }
373 }
374}