blob: d339f69d3e2838f069806958d8c7e2729731db21 [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 Lemeb1a65ee2016-02-08 10:12:01 -080027import java.util.HashSet;
Felipe Lemede4e8e32016-02-02 18:55:22 -080028import java.util.List;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080029import java.util.Set;
Felipe Lemede4e8e32016-02-02 18:55:22 -080030
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080031import android.content.Context;
Felipe Leme50a235e2016-01-15 18:37:06 -080032import android.net.INetworkPolicyManager;
Felipe Lemede4e8e32016-02-02 18:55:22 -080033import android.net.NetworkPolicy;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080034import android.net.NetworkTemplate;
35import android.net.wifi.WifiConfiguration;
36import android.net.wifi.WifiManager;
Felipe Leme50a235e2016-01-15 18:37:06 -080037import android.os.RemoteException;
38import android.os.ShellCommand;
Felipe Lemede4e8e32016-02-02 18:55:22 -080039import android.util.Log;
Felipe Leme50a235e2016-01-15 18:37:06 -080040
Felipe Lemede4e8e32016-02-02 18:55:22 -080041class NetworkPolicyManagerShellCommand extends ShellCommand {
Felipe Leme50a235e2016-01-15 18:37:06 -080042
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080043 private final INetworkPolicyManager mInterface;
44 private final WifiManager mWifiManager;
Felipe Leme50a235e2016-01-15 18:37:06 -080045
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080046 NetworkPolicyManagerShellCommand(Context context, INetworkPolicyManager service) {
Felipe Leme50a235e2016-01-15 18:37:06 -080047 mInterface = service;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -080048 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Felipe Leme50a235e2016-01-15 18:37:06 -080049 }
50
51 @Override
52 public int onCommand(String cmd) {
53 if (cmd == null) {
54 return handleDefaultCommands(cmd);
55 }
56 final PrintWriter pw = getOutPrintWriter();
57 try {
58 switch(cmd) {
59 case "get":
60 return runGet();
61 case "set":
62 return runSet();
63 case "list":
64 return runList();
65 case "add":
66 return runAdd();
67 case "remove":
68 return runRemove();
69 default:
70 return handleDefaultCommands(cmd);
71 }
72 } catch (RemoteException e) {
73 pw.println("Remote exception: " + e);
74 }
75 return -1;
76 }
77
78 @Override
79 public void onHelp() {
80 final PrintWriter pw = getOutPrintWriter();
81 pw.println("Network policy manager (netpolicy) commands:");
82 pw.println(" help");
83 pw.println(" Print this help text.");
84 pw.println("");
Felipe Leme50a235e2016-01-15 18:37:06 -080085 pw.println(" add restrict-background-whitelist UID");
86 pw.println(" Adds a UID to the whitelist for restrict background usage.");
Felipe Leme9982b302016-03-01 13:40:31 -080087 pw.println(" add restrict-background-blacklist UID");
88 pw.println(" Adds a UID to the blacklist for restrict background usage.");
Felipe Lemede4e8e32016-02-02 18:55:22 -080089 pw.println(" get restrict-background");
90 pw.println(" Gets the global restrict background usage status.");
Felipe Lemeb9aee90a2016-03-30 16:14:54 -070091 pw.println(" list wifi-networks [BOOLEAN]");
92 pw.println(" Lists all saved wifi networks and whether they are metered or not.");
Felipe Lemede4e8e32016-02-02 18:55:22 -080093 pw.println(" If a boolean argument is passed, filters just the metered (or unmetered)");
94 pw.println(" networks.");
95 pw.println(" list restrict-background-whitelist");
96 pw.println(" Lists UIDs that are whitelisted for restrict background usage.");
Felipe Leme9982b302016-03-01 13:40:31 -080097 pw.println(" list restrict-background-blacklist");
98 pw.println(" Lists UIDs that are blacklisted for restrict background usage.");
Felipe Leme50a235e2016-01-15 18:37:06 -080099 pw.println(" remove restrict-background-whitelist UID");
100 pw.println(" Removes a UID from the whitelist for restrict background usage.");
Felipe Leme9982b302016-03-01 13:40:31 -0800101 pw.println(" remove restrict-background-blacklist UID");
102 pw.println(" Removes a UID from the blacklist for restrict background usage.");
Felipe Lemede4e8e32016-02-02 18:55:22 -0800103 pw.println(" set metered-network ID BOOLEAN");
Felipe Lemeb9aee90a2016-03-30 16:14:54 -0700104 pw.println(" Toggles whether the given wi-fi network is metered.");
Felipe Lemede4e8e32016-02-02 18:55:22 -0800105 pw.println(" set restrict-background BOOLEAN");
106 pw.println(" Sets the global restrict background usage status.");
Felipe Leme50a235e2016-01-15 18:37:06 -0800107 }
108
109 private int runGet() throws RemoteException {
110 final PrintWriter pw = getOutPrintWriter();
111 final String type = getNextArg();
112 if (type == null) {
113 pw.println("Error: didn't specify type of data to get");
114 return -1;
115 }
116 switch(type) {
117 case "restrict-background":
Felipe Leme9778f762016-01-27 14:46:39 -0800118 return getRestrictBackground();
Felipe Leme50a235e2016-01-15 18:37:06 -0800119 }
120 pw.println("Error: unknown get type '" + type + "'");
121 return -1;
122 }
123
124 private int runSet() throws RemoteException {
125 final PrintWriter pw = getOutPrintWriter();
126 final String type = getNextArg();
127 if (type == null) {
128 pw.println("Error: didn't specify type of data to set");
129 return -1;
130 }
131 switch(type) {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800132 case "metered-network":
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800133 return setMeteredWifiNetwork();
Felipe Leme50a235e2016-01-15 18:37:06 -0800134 case "restrict-background":
Felipe Leme9778f762016-01-27 14:46:39 -0800135 return setRestrictBackground();
Felipe Leme50a235e2016-01-15 18:37:06 -0800136 }
137 pw.println("Error: unknown set type '" + type + "'");
138 return -1;
139 }
140
141 private int runList() throws RemoteException {
142 final PrintWriter pw = getOutPrintWriter();
143 final String type = getNextArg();
144 if (type == null) {
145 pw.println("Error: didn't specify type of data to list");
146 return -1;
147 }
148 switch(type) {
Felipe Lemeb9aee90a2016-03-30 16:14:54 -0700149 case "wifi-networks":
150 return listWifiNetworks();
Felipe Leme50a235e2016-01-15 18:37:06 -0800151 case "restrict-background-whitelist":
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800152 return listRestrictBackgroundWhitelist();
Felipe Leme9982b302016-03-01 13:40:31 -0800153 case "restrict-background-blacklist":
154 return listRestrictBackgroundBlacklist();
Felipe Leme50a235e2016-01-15 18:37:06 -0800155 }
156 pw.println("Error: unknown list type '" + type + "'");
157 return -1;
158 }
159
160 private int runAdd() throws RemoteException {
161 final PrintWriter pw = getOutPrintWriter();
162 final String type = getNextArg();
163 if (type == null) {
164 pw.println("Error: didn't specify type of data to add");
165 return -1;
166 }
167 switch(type) {
168 case "restrict-background-whitelist":
169 return addRestrictBackgroundWhitelist();
Felipe Leme9982b302016-03-01 13:40:31 -0800170 case "restrict-background-blacklist":
171 return addRestrictBackgroundBlacklist();
Felipe Leme50a235e2016-01-15 18:37:06 -0800172 }
173 pw.println("Error: unknown add type '" + type + "'");
174 return -1;
175 }
176
177 private int runRemove() throws RemoteException {
178 final PrintWriter pw = getOutPrintWriter();
179 final String type = getNextArg();
180 if (type == null) {
181 pw.println("Error: didn't specify type of data to remove");
182 return -1;
183 }
184 switch(type) {
185 case "restrict-background-whitelist":
186 return removeRestrictBackgroundWhitelist();
Felipe Leme9982b302016-03-01 13:40:31 -0800187 case "restrict-background-blacklist":
188 return removeRestrictBackgroundBlacklist();
Felipe Leme50a235e2016-01-15 18:37:06 -0800189 }
190 pw.println("Error: unknown remove type '" + type + "'");
191 return -1;
192 }
193
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800194 private int listRestrictBackgroundWhitelist() throws RemoteException {
Felipe Leme50a235e2016-01-15 18:37:06 -0800195 final PrintWriter pw = getOutPrintWriter();
196 final int[] uids = mInterface.getRestrictBackgroundWhitelistedUids();
197 pw.print("Restrict background whitelisted UIDs: ");
198 if (uids.length == 0) {
199 pw.println("none");
200 } else {
201 for (int i = 0; i < uids.length; i++) {
202 int uid = uids[i];
203 pw.print(uid);
204 pw.print(' ');
205 }
206 }
207 pw.println();
208 return 0;
209 }
210
Felipe Leme9982b302016-03-01 13:40:31 -0800211 private int listRestrictBackgroundBlacklist() throws RemoteException {
212 final PrintWriter pw = getOutPrintWriter();
213
214 final int[] uids = mInterface.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND);
215 pw.print("Restrict background blacklisted UIDs: ");
216 if (uids.length == 0) {
217 pw.println("none");
218 } else {
219 for (int i = 0; i < uids.length; i++) {
220 int uid = uids[i];
221 pw.print(uid);
222 pw.print(' ');
223 }
224 }
225 pw.println();
226 return 0;
227 }
228
Felipe Leme9778f762016-01-27 14:46:39 -0800229 private int getRestrictBackground() throws RemoteException {
Felipe Leme50a235e2016-01-15 18:37:06 -0800230 final PrintWriter pw = getOutPrintWriter();
231 pw.print("Restrict background status: ");
232 pw.println(mInterface.getRestrictBackground() ? "enabled" : "disabled");
233 return 0;
234 }
235
Felipe Leme9778f762016-01-27 14:46:39 -0800236 private int setRestrictBackground() throws RemoteException {
Felipe Leme50a235e2016-01-15 18:37:06 -0800237 final int enabled = getNextBooleanArg();
238 if (enabled < 0) {
239 return enabled;
240 }
Felipe Leme6a05eee2016-02-19 14:43:51 -0800241 mInterface.setRestrictBackground(enabled > 0);
Felipe Leme50a235e2016-01-15 18:37:06 -0800242 return 0;
243 }
244
245 private int addRestrictBackgroundWhitelist() throws RemoteException {
246 final int uid = getUidFromNextArg();
247 if (uid < 0) {
248 return uid;
249 }
Felipe Leme6a05eee2016-02-19 14:43:51 -0800250 mInterface.addRestrictBackgroundWhitelistedUid(uid);
Felipe Leme50a235e2016-01-15 18:37:06 -0800251 return 0;
252 }
253
254 private int removeRestrictBackgroundWhitelist() throws RemoteException {
255 final int uid = getUidFromNextArg();
256 if (uid < 0) {
257 return uid;
258 }
Felipe Leme6a05eee2016-02-19 14:43:51 -0800259 mInterface.removeRestrictBackgroundWhitelistedUid(uid);
Felipe Leme50a235e2016-01-15 18:37:06 -0800260 return 0;
261 }
262
Felipe Leme9982b302016-03-01 13:40:31 -0800263 private int addRestrictBackgroundBlacklist() throws RemoteException {
264 final int uid = getUidFromNextArg();
265 if (uid < 0) {
266 return uid;
267 }
268 mInterface.setUidPolicy(uid, POLICY_REJECT_METERED_BACKGROUND);
269 return 0;
270 }
271
272 private int removeRestrictBackgroundBlacklist() throws RemoteException {
273 final int uid = getUidFromNextArg();
274 if (uid < 0) {
275 return uid;
276 }
277 mInterface.setUidPolicy(uid, POLICY_NONE);
278 return 0;
279 }
280
Felipe Lemeb9aee90a2016-03-30 16:14:54 -0700281 private int listWifiNetworks() throws RemoteException {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800282 final PrintWriter pw = getOutPrintWriter();
283 final String arg = getNextArg();
284 final Boolean filter = arg == null ? null : Boolean.valueOf(arg);
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800285 for (NetworkPolicy policy : getWifiPolicies()) {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800286 if (filter != null && filter.booleanValue() != policy.metered) {
287 continue;
288 }
289 pw.print(getNetworkId(policy));
290 pw.print(';');
291 pw.println(policy.metered);
292 }
293 return 0;
294 }
295
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800296 private int setMeteredWifiNetwork() throws RemoteException {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800297 final PrintWriter pw = getOutPrintWriter();
298 final String id = getNextArg();
299 if (id == null) {
300 pw.println("Error: didn't specify ID");
301 return -1;
302 }
303 final String arg = getNextArg();
304 if (arg == null) {
305 pw.println("Error: didn't specify BOOLEAN");
306 return -1;
307 }
308 final boolean metered = Boolean.valueOf(arg);
309 final NetworkPolicy[] policies = mInterface.getNetworkPolicies(null);
310 boolean changed = false;
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800311 // First try to find a policy with such id
Felipe Lemede4e8e32016-02-02 18:55:22 -0800312 for (NetworkPolicy policy : policies) {
313 if (policy.template.isMatchRuleMobile() || policy.metered == metered) {
314 continue;
315 }
316 final String networkId = getNetworkId(policy);
317 if (id.equals(networkId)) {
318 Log.i(TAG, "Changing " + networkId + " metered status to " + metered);
319 policy.metered = metered;
320 changed = true;
321 }
322 }
323 if (changed) {
324 mInterface.setNetworkPolicies(policies);
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800325 return 0;
326 }
327 // Policy not found: check if there is a saved wi-fi with such id.
328 for (WifiConfiguration config : mWifiManager.getConfiguredNetworks()) {
329 final String ssid = removeDoubleQuotes(config.SSID);
330 if (id.equals(ssid)) {
331 final NetworkPolicy policy = newPolicy(ssid);
332 Log.i(TAG, "Creating new policy for " + ssid + ": " + policy);
333 final NetworkPolicy[] newPolicies = new NetworkPolicy[policies.length + 1];
334 System.arraycopy(policies, 0, newPolicies, 0, policies.length);
335 newPolicies[newPolicies.length - 1] = policy;
336 mInterface.setNetworkPolicies(newPolicies);
337 }
Felipe Lemede4e8e32016-02-02 18:55:22 -0800338 }
339 return 0;
340 }
341
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800342 private List<NetworkPolicy> getWifiPolicies() throws RemoteException {
343 // First gets a list of saved wi-fi networks.
344 final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
Felipe Lemec8ce9a82016-03-04 16:11:29 -0800345 final int size = configs != null ? configs.size() : 0;
346 final Set<String> ssids = new HashSet<>(size);
347 if (configs != null) {
348 for (WifiConfiguration config : configs) {
349 ssids.add(removeDoubleQuotes(config.SSID));
350 }
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800351 }
352
353 // Then gets the saved policies.
Felipe Lemede4e8e32016-02-02 18:55:22 -0800354 final NetworkPolicy[] policies = mInterface.getNetworkPolicies(null);
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800355 final List<NetworkPolicy> wifiPolicies = new ArrayList<NetworkPolicy>(policies.length);
Felipe Lemede4e8e32016-02-02 18:55:22 -0800356 for (NetworkPolicy policy: policies) {
357 if (!policy.template.isMatchRuleMobile()) {
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800358 wifiPolicies.add(policy);
359 final String netId = getNetworkId(policy);
360 ssids.remove(netId);
Felipe Lemede4e8e32016-02-02 18:55:22 -0800361 }
362 }
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800363 // Finally, creates new default policies for saved WI-FIs not policied yet.
364 for (String ssid : ssids) {
365 final NetworkPolicy policy = newPolicy(ssid);
366 wifiPolicies.add(policy);
367 }
368 return wifiPolicies;
369 }
370
371 private NetworkPolicy newPolicy(String ssid) {
372 final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(ssid);
373 final NetworkPolicy policy = newWifiPolicy(template, false);
374 return policy;
Felipe Lemede4e8e32016-02-02 18:55:22 -0800375 }
376
377 private String getNetworkId(NetworkPolicy policy) {
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800378 return removeDoubleQuotes(policy.template.getNetworkId());
Felipe Lemede4e8e32016-02-02 18:55:22 -0800379 }
380
Felipe Leme50a235e2016-01-15 18:37:06 -0800381 private int getNextBooleanArg() {
382 final PrintWriter pw = getOutPrintWriter();
383 final String arg = getNextArg();
384 if (arg == null) {
385 pw.println("Error: didn't specify BOOLEAN");
386 return -1;
387 }
388 return Boolean.valueOf(arg) ? 1 : 0;
389 }
390
391 private int getUidFromNextArg() {
392 final PrintWriter pw = getOutPrintWriter();
393 final String arg = getNextArg();
394 if (arg == null) {
395 pw.println("Error: didn't specify UID");
396 return -1;
397 }
398 try {
399 return Integer.parseInt(arg);
400 } catch (NumberFormatException e) {
401 pw.println("Error: UID (" + arg + ") should be a number");
402 return -2;
403 }
404 }
405}