blob: 9cfb590c9234a71e176401e5205c4b38b23f1c4b [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 Leme9982b302016-03-01 13:40:31 -080019import static android.net.NetworkPolicyManager.POLICY_NONE;
20import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080021import static android.net.wifi.WifiInfo.removeDoubleQuotes;
22import static com.android.server.net.NetworkPolicyManagerService.newWifiPolicy;
Felipe Lemede4e8e32016-02-02 18:55:22 -080023import static com.android.server.net.NetworkPolicyManagerService.TAG;
Felipe Leme50a235e2016-01-15 18:37:06 -080024
Felipe Lemede4e8e32016-02-02 18:55:22 -080025import java.io.PrintWriter;
26import java.util.ArrayList;
Felipe Lemec8ce9a82016-03-04 16:11:29 -080027import java.util.Collections;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080028import java.util.HashSet;
Felipe Lemede4e8e32016-02-02 18:55:22 -080029import java.util.List;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080030import java.util.Set;
Felipe Lemede4e8e32016-02-02 18:55:22 -080031
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080032import android.content.Context;
Felipe Leme50a235e2016-01-15 18:37:06 -080033import android.net.INetworkPolicyManager;
Felipe Lemede4e8e32016-02-02 18:55:22 -080034import android.net.NetworkPolicy;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080035import android.net.NetworkTemplate;
36import android.net.wifi.WifiConfiguration;
37import android.net.wifi.WifiManager;
Felipe Leme9778f762016-01-27 14:46:39 -080038import android.os.Binder;
Felipe Leme50a235e2016-01-15 18:37:06 -080039import android.os.RemoteException;
40import android.os.ShellCommand;
Felipe Lemede4e8e32016-02-02 18:55:22 -080041import android.util.Log;
Felipe Leme50a235e2016-01-15 18:37:06 -080042
Felipe Lemede4e8e32016-02-02 18:55:22 -080043class NetworkPolicyManagerShellCommand extends ShellCommand {
Felipe Leme50a235e2016-01-15 18:37:06 -080044
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080045 private final INetworkPolicyManager mInterface;
46 private final WifiManager mWifiManager;
Felipe Leme50a235e2016-01-15 18:37:06 -080047
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080048 NetworkPolicyManagerShellCommand(Context context, INetworkPolicyManager service) {
Felipe Leme50a235e2016-01-15 18:37:06 -080049 mInterface = service;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080050 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Felipe Leme50a235e2016-01-15 18:37:06 -080051 }
52
53 @Override
54 public int onCommand(String cmd) {
55 if (cmd == null) {
56 return handleDefaultCommands(cmd);
57 }
58 final PrintWriter pw = getOutPrintWriter();
59 try {
60 switch(cmd) {
61 case "get":
62 return runGet();
63 case "set":
64 return runSet();
65 case "list":
66 return runList();
67 case "add":
68 return runAdd();
69 case "remove":
70 return runRemove();
71 default:
72 return handleDefaultCommands(cmd);
73 }
74 } catch (RemoteException e) {
75 pw.println("Remote exception: " + e);
76 }
77 return -1;
78 }
79
80 @Override
81 public void onHelp() {
82 final PrintWriter pw = getOutPrintWriter();
83 pw.println("Network policy manager (netpolicy) commands:");
84 pw.println(" help");
85 pw.println(" Print this help text.");
86 pw.println("");
Felipe Leme50a235e2016-01-15 18:37:06 -080087 pw.println(" add restrict-background-whitelist UID");
88 pw.println(" Adds a UID to the whitelist for restrict background usage.");
Felipe Leme9982b302016-03-01 13:40:31 -080089 pw.println(" add restrict-background-blacklist UID");
90 pw.println(" Adds a UID to the blacklist for restrict background usage.");
Felipe Lemede4e8e32016-02-02 18:55:22 -080091 pw.println(" get metered-network ID");
92 pw.println(" Checks whether the given non-mobile network is metered or not.");
93 pw.println(" get restrict-background");
94 pw.println(" Gets the global restrict background usage status.");
95 pw.println(" list metered-networks [BOOLEAN]");
96 pw.println(" Lists all non-mobile networks and whether they are metered or not.");
97 pw.println(" If a boolean argument is passed, filters just the metered (or unmetered)");
98 pw.println(" networks.");
99 pw.println(" list restrict-background-whitelist");
100 pw.println(" Lists UIDs that are whitelisted for restrict background usage.");
Felipe Leme9982b302016-03-01 13:40:31 -0800101 pw.println(" list restrict-background-blacklist");
102 pw.println(" Lists UIDs that are blacklisted for restrict background usage.");
Felipe Leme50a235e2016-01-15 18:37:06 -0800103 pw.println(" remove restrict-background-whitelist UID");
104 pw.println(" Removes a UID from the whitelist for restrict background usage.");
Felipe Leme9982b302016-03-01 13:40:31 -0800105 pw.println(" remove restrict-background-blacklist UID");
106 pw.println(" Removes a UID from the blacklist for restrict background usage.");
Felipe Lemede4e8e32016-02-02 18:55:22 -0800107 pw.println(" set metered-network ID BOOLEAN");
108 pw.println(" Toggles whether the given non-mobile network is metered.");
109 pw.println(" set restrict-background BOOLEAN");
110 pw.println(" Sets the global restrict background usage status.");
Felipe Leme50a235e2016-01-15 18:37:06 -0800111 }
112
113 private int runGet() throws RemoteException {
114 final PrintWriter pw = getOutPrintWriter();
115 final String type = getNextArg();
116 if (type == null) {
117 pw.println("Error: didn't specify type of data to get");
118 return -1;
119 }
120 switch(type) {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800121 case "metered-network":
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800122 return getMeteredWifiNetwork();
Felipe Leme50a235e2016-01-15 18:37:06 -0800123 case "restrict-background":
Felipe Leme9778f762016-01-27 14:46:39 -0800124 return getRestrictBackground();
Felipe Leme50a235e2016-01-15 18:37:06 -0800125 }
126 pw.println("Error: unknown get type '" + type + "'");
127 return -1;
128 }
129
130 private int runSet() throws RemoteException {
131 final PrintWriter pw = getOutPrintWriter();
132 final String type = getNextArg();
133 if (type == null) {
134 pw.println("Error: didn't specify type of data to set");
135 return -1;
136 }
137 switch(type) {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800138 case "metered-network":
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800139 return setMeteredWifiNetwork();
Felipe Leme50a235e2016-01-15 18:37:06 -0800140 case "restrict-background":
Felipe Leme9778f762016-01-27 14:46:39 -0800141 return setRestrictBackground();
Felipe Leme50a235e2016-01-15 18:37:06 -0800142 }
143 pw.println("Error: unknown set type '" + type + "'");
144 return -1;
145 }
146
147 private int runList() throws RemoteException {
148 final PrintWriter pw = getOutPrintWriter();
149 final String type = getNextArg();
150 if (type == null) {
151 pw.println("Error: didn't specify type of data to list");
152 return -1;
153 }
154 switch(type) {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800155 case "metered-networks":
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800156 return listMeteredWifiNetworks();
Felipe Leme50a235e2016-01-15 18:37:06 -0800157 case "restrict-background-whitelist":
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800158 return listRestrictBackgroundWhitelist();
Felipe Leme9982b302016-03-01 13:40:31 -0800159 case "restrict-background-blacklist":
160 return listRestrictBackgroundBlacklist();
Felipe Leme50a235e2016-01-15 18:37:06 -0800161 }
162 pw.println("Error: unknown list type '" + type + "'");
163 return -1;
164 }
165
166 private int runAdd() throws RemoteException {
167 final PrintWriter pw = getOutPrintWriter();
168 final String type = getNextArg();
169 if (type == null) {
170 pw.println("Error: didn't specify type of data to add");
171 return -1;
172 }
173 switch(type) {
174 case "restrict-background-whitelist":
175 return addRestrictBackgroundWhitelist();
Felipe Leme9982b302016-03-01 13:40:31 -0800176 case "restrict-background-blacklist":
177 return addRestrictBackgroundBlacklist();
Felipe Leme50a235e2016-01-15 18:37:06 -0800178 }
179 pw.println("Error: unknown add type '" + type + "'");
180 return -1;
181 }
182
183 private int runRemove() throws RemoteException {
184 final PrintWriter pw = getOutPrintWriter();
185 final String type = getNextArg();
186 if (type == null) {
187 pw.println("Error: didn't specify type of data to remove");
188 return -1;
189 }
190 switch(type) {
191 case "restrict-background-whitelist":
192 return removeRestrictBackgroundWhitelist();
Felipe Leme9982b302016-03-01 13:40:31 -0800193 case "restrict-background-blacklist":
194 return removeRestrictBackgroundBlacklist();
Felipe Leme50a235e2016-01-15 18:37:06 -0800195 }
196 pw.println("Error: unknown remove type '" + type + "'");
197 return -1;
198 }
199
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800200 private int listRestrictBackgroundWhitelist() throws RemoteException {
Felipe Leme50a235e2016-01-15 18:37:06 -0800201 final PrintWriter pw = getOutPrintWriter();
202 final int[] uids = mInterface.getRestrictBackgroundWhitelistedUids();
203 pw.print("Restrict background whitelisted UIDs: ");
204 if (uids.length == 0) {
205 pw.println("none");
206 } else {
207 for (int i = 0; i < uids.length; i++) {
208 int uid = uids[i];
209 pw.print(uid);
210 pw.print(' ');
211 }
212 }
213 pw.println();
214 return 0;
215 }
216
Felipe Leme9982b302016-03-01 13:40:31 -0800217 private int listRestrictBackgroundBlacklist() throws RemoteException {
218 final PrintWriter pw = getOutPrintWriter();
219
220 final int[] uids = mInterface.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND);
221 pw.print("Restrict background blacklisted UIDs: ");
222 if (uids.length == 0) {
223 pw.println("none");
224 } else {
225 for (int i = 0; i < uids.length; i++) {
226 int uid = uids[i];
227 pw.print(uid);
228 pw.print(' ');
229 }
230 }
231 pw.println();
232 return 0;
233 }
234
Felipe Leme9778f762016-01-27 14:46:39 -0800235 private int getRestrictBackground() throws RemoteException {
Felipe Leme50a235e2016-01-15 18:37:06 -0800236 final PrintWriter pw = getOutPrintWriter();
237 pw.print("Restrict background status: ");
238 pw.println(mInterface.getRestrictBackground() ? "enabled" : "disabled");
239 return 0;
240 }
241
Felipe Leme9778f762016-01-27 14:46:39 -0800242 private int setRestrictBackground() throws RemoteException {
Felipe Leme50a235e2016-01-15 18:37:06 -0800243 final int enabled = getNextBooleanArg();
244 if (enabled < 0) {
245 return enabled;
246 }
Felipe Leme6a05eee2016-02-19 14:43:51 -0800247 mInterface.setRestrictBackground(enabled > 0);
Felipe Leme50a235e2016-01-15 18:37:06 -0800248 return 0;
249 }
250
251 private int addRestrictBackgroundWhitelist() throws RemoteException {
252 final int uid = getUidFromNextArg();
253 if (uid < 0) {
254 return uid;
255 }
Felipe Leme6a05eee2016-02-19 14:43:51 -0800256 mInterface.addRestrictBackgroundWhitelistedUid(uid);
Felipe Leme50a235e2016-01-15 18:37:06 -0800257 return 0;
258 }
259
260 private int removeRestrictBackgroundWhitelist() throws RemoteException {
261 final int uid = getUidFromNextArg();
262 if (uid < 0) {
263 return uid;
264 }
Felipe Leme6a05eee2016-02-19 14:43:51 -0800265 mInterface.removeRestrictBackgroundWhitelistedUid(uid);
Felipe Leme50a235e2016-01-15 18:37:06 -0800266 return 0;
267 }
268
Felipe Leme9982b302016-03-01 13:40:31 -0800269 private int addRestrictBackgroundBlacklist() throws RemoteException {
270 final int uid = getUidFromNextArg();
271 if (uid < 0) {
272 return uid;
273 }
274 mInterface.setUidPolicy(uid, POLICY_REJECT_METERED_BACKGROUND);
275 return 0;
276 }
277
278 private int removeRestrictBackgroundBlacklist() throws RemoteException {
279 final int uid = getUidFromNextArg();
280 if (uid < 0) {
281 return uid;
282 }
283 mInterface.setUidPolicy(uid, POLICY_NONE);
284 return 0;
285 }
286
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800287 private int listMeteredWifiNetworks() throws RemoteException {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800288 final PrintWriter pw = getOutPrintWriter();
289 final String arg = getNextArg();
290 final Boolean filter = arg == null ? null : Boolean.valueOf(arg);
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800291 for (NetworkPolicy policy : getWifiPolicies()) {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800292 if (filter != null && filter.booleanValue() != policy.metered) {
293 continue;
294 }
295 pw.print(getNetworkId(policy));
296 pw.print(';');
297 pw.println(policy.metered);
298 }
299 return 0;
300 }
301
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800302 private int getMeteredWifiNetwork() throws RemoteException {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800303 final PrintWriter pw = getOutPrintWriter();
304 final String id = getNextArg();
305 if (id == null) {
306 pw.println("Error: didn't specify ID");
307 return -1;
308 }
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800309 final List<NetworkPolicy> policies = getWifiPolicies();
Felipe Lemede4e8e32016-02-02 18:55:22 -0800310 for (NetworkPolicy policy: policies) {
311 if (id.equals(getNetworkId(policy))) {
312 pw.println(policy.metered);
313 return 0;
314 }
315 }
316 return 0;
317 }
318
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800319 private int setMeteredWifiNetwork() throws RemoteException {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800320 final PrintWriter pw = getOutPrintWriter();
321 final String id = getNextArg();
322 if (id == null) {
323 pw.println("Error: didn't specify ID");
324 return -1;
325 }
326 final String arg = getNextArg();
327 if (arg == null) {
328 pw.println("Error: didn't specify BOOLEAN");
329 return -1;
330 }
331 final boolean metered = Boolean.valueOf(arg);
332 final NetworkPolicy[] policies = mInterface.getNetworkPolicies(null);
333 boolean changed = false;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800334 // First try to find a policy with such id
Felipe Lemede4e8e32016-02-02 18:55:22 -0800335 for (NetworkPolicy policy : policies) {
336 if (policy.template.isMatchRuleMobile() || policy.metered == metered) {
337 continue;
338 }
339 final String networkId = getNetworkId(policy);
340 if (id.equals(networkId)) {
341 Log.i(TAG, "Changing " + networkId + " metered status to " + metered);
342 policy.metered = metered;
343 changed = true;
344 }
345 }
346 if (changed) {
347 mInterface.setNetworkPolicies(policies);
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800348 return 0;
349 }
350 // Policy not found: check if there is a saved wi-fi with such id.
351 for (WifiConfiguration config : mWifiManager.getConfiguredNetworks()) {
352 final String ssid = removeDoubleQuotes(config.SSID);
353 if (id.equals(ssid)) {
354 final NetworkPolicy policy = newPolicy(ssid);
355 Log.i(TAG, "Creating new policy for " + ssid + ": " + policy);
356 final NetworkPolicy[] newPolicies = new NetworkPolicy[policies.length + 1];
357 System.arraycopy(policies, 0, newPolicies, 0, policies.length);
358 newPolicies[newPolicies.length - 1] = policy;
359 mInterface.setNetworkPolicies(newPolicies);
360 }
Felipe Lemede4e8e32016-02-02 18:55:22 -0800361 }
362 return 0;
363 }
364
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800365 private List<NetworkPolicy> getWifiPolicies() throws RemoteException {
366 // First gets a list of saved wi-fi networks.
367 final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
Felipe Lemec8ce9a82016-03-04 16:11:29 -0800368 final int size = configs != null ? configs.size() : 0;
369 final Set<String> ssids = new HashSet<>(size);
370 if (configs != null) {
371 for (WifiConfiguration config : configs) {
372 ssids.add(removeDoubleQuotes(config.SSID));
373 }
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800374 }
375
376 // Then gets the saved policies.
Felipe Lemede4e8e32016-02-02 18:55:22 -0800377 final NetworkPolicy[] policies = mInterface.getNetworkPolicies(null);
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800378 final List<NetworkPolicy> wifiPolicies = new ArrayList<NetworkPolicy>(policies.length);
Felipe Lemede4e8e32016-02-02 18:55:22 -0800379 for (NetworkPolicy policy: policies) {
380 if (!policy.template.isMatchRuleMobile()) {
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800381 wifiPolicies.add(policy);
382 final String netId = getNetworkId(policy);
383 ssids.remove(netId);
Felipe Lemede4e8e32016-02-02 18:55:22 -0800384 }
385 }
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800386 // Finally, creates new default policies for saved WI-FIs not policied yet.
387 for (String ssid : ssids) {
388 final NetworkPolicy policy = newPolicy(ssid);
389 wifiPolicies.add(policy);
390 }
391 return wifiPolicies;
392 }
393
394 private NetworkPolicy newPolicy(String ssid) {
395 final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(ssid);
396 final NetworkPolicy policy = newWifiPolicy(template, false);
397 return policy;
Felipe Lemede4e8e32016-02-02 18:55:22 -0800398 }
399
400 private String getNetworkId(NetworkPolicy policy) {
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800401 return removeDoubleQuotes(policy.template.getNetworkId());
Felipe Lemede4e8e32016-02-02 18:55:22 -0800402 }
403
Felipe Leme50a235e2016-01-15 18:37:06 -0800404 private int getNextBooleanArg() {
405 final PrintWriter pw = getOutPrintWriter();
406 final String arg = getNextArg();
407 if (arg == null) {
408 pw.println("Error: didn't specify BOOLEAN");
409 return -1;
410 }
411 return Boolean.valueOf(arg) ? 1 : 0;
412 }
413
414 private int getUidFromNextArg() {
415 final PrintWriter pw = getOutPrintWriter();
416 final String arg = getNextArg();
417 if (arg == null) {
418 pw.println("Error: didn't specify UID");
419 return -1;
420 }
421 try {
422 return Integer.parseInt(arg);
423 } catch (NumberFormatException e) {
424 pw.println("Error: UID (" + arg + ") should be a number");
425 return -2;
426 }
427 }
428}