• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 
17 package com.android.settings.net;
18 
19 import static android.net.NetworkPolicy.CYCLE_NONE;
20 import static android.net.NetworkPolicy.LIMIT_DISABLED;
21 import static android.net.NetworkPolicy.SNOOZE_NEVER;
22 import static android.net.NetworkPolicy.WARNING_DISABLED;
23 import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
24 import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
25 import static android.net.NetworkTemplate.MATCH_WIFI;
26 import static android.net.NetworkTemplate.buildTemplateMobile3gLower;
27 import static android.net.NetworkTemplate.buildTemplateMobile4g;
28 import static android.net.NetworkTemplate.buildTemplateMobileAll;
29 import static com.android.internal.util.Preconditions.checkNotNull;
30 
31 import android.net.NetworkPolicy;
32 import android.net.NetworkPolicyManager;
33 import android.net.NetworkTemplate;
34 import android.net.wifi.WifiInfo;
35 import android.os.AsyncTask;
36 import android.text.TextUtils;
37 import android.text.format.Time;
38 
39 import com.android.internal.util.Objects;
40 import com.google.android.collect.Lists;
41 import com.google.android.collect.Sets;
42 
43 import java.util.ArrayList;
44 import java.util.HashSet;
45 
46 /**
47  * Utility class to modify list of {@link NetworkPolicy}. Specifically knows
48  * about which policies can coexist. This editor offers thread safety when
49  * talking with {@link NetworkPolicyManager}.
50  */
51 public class NetworkPolicyEditor {
52     // TODO: be more robust when missing policies from service
53 
54     public static final boolean ENABLE_SPLIT_POLICIES = false;
55 
56     private NetworkPolicyManager mPolicyManager;
57     private ArrayList<NetworkPolicy> mPolicies = Lists.newArrayList();
58 
NetworkPolicyEditor(NetworkPolicyManager policyManager)59     public NetworkPolicyEditor(NetworkPolicyManager policyManager) {
60         mPolicyManager = checkNotNull(policyManager);
61     }
62 
read()63     public void read() {
64         final NetworkPolicy[] policies = mPolicyManager.getNetworkPolicies();
65 
66         boolean modified = false;
67         mPolicies.clear();
68         for (NetworkPolicy policy : policies) {
69             // TODO: find better place to clamp these
70             if (policy.limitBytes < -1) {
71                 policy.limitBytes = LIMIT_DISABLED;
72                 modified = true;
73             }
74             if (policy.warningBytes < -1) {
75                 policy.warningBytes = WARNING_DISABLED;
76                 modified = true;
77             }
78 
79             mPolicies.add(policy);
80         }
81 
82         // force combine any split policies when disabled
83         if (!ENABLE_SPLIT_POLICIES) {
84             modified |= forceMobilePolicyCombined();
85         }
86 
87         // when we cleaned policies above, write back changes
88         if (modified) writeAsync();
89     }
90 
writeAsync()91     public void writeAsync() {
92         // TODO: consider making more robust by passing through service
93         final NetworkPolicy[] policies = mPolicies.toArray(new NetworkPolicy[mPolicies.size()]);
94         new AsyncTask<Void, Void, Void>() {
95             @Override
96             protected Void doInBackground(Void... params) {
97                 write(policies);
98                 return null;
99             }
100         }.execute();
101     }
102 
write(NetworkPolicy[] policies)103     public void write(NetworkPolicy[] policies) {
104         mPolicyManager.setNetworkPolicies(policies);
105     }
106 
hasLimitedPolicy(NetworkTemplate template)107     public boolean hasLimitedPolicy(NetworkTemplate template) {
108         final NetworkPolicy policy = getPolicy(template);
109         return policy != null && policy.limitBytes != LIMIT_DISABLED;
110     }
111 
getOrCreatePolicy(NetworkTemplate template)112     public NetworkPolicy getOrCreatePolicy(NetworkTemplate template) {
113         NetworkPolicy policy = getPolicy(template);
114         if (policy == null) {
115             policy = buildDefaultPolicy(template);
116             mPolicies.add(policy);
117         }
118         return policy;
119     }
120 
getPolicy(NetworkTemplate template)121     public NetworkPolicy getPolicy(NetworkTemplate template) {
122         for (NetworkPolicy policy : mPolicies) {
123             if (policy.template.equals(template)) {
124                 return policy;
125             }
126         }
127         return null;
128     }
129 
getPolicyMaybeUnquoted(NetworkTemplate template)130     public NetworkPolicy getPolicyMaybeUnquoted(NetworkTemplate template) {
131         NetworkPolicy policy = getPolicy(template);
132         if (policy != null) {
133             return policy;
134         } else {
135             return getPolicy(buildUnquotedNetworkTemplate(template));
136         }
137     }
138 
139     @Deprecated
buildDefaultPolicy(NetworkTemplate template)140     private static NetworkPolicy buildDefaultPolicy(NetworkTemplate template) {
141         // TODO: move this into framework to share with NetworkPolicyManagerService
142         final int cycleDay;
143         final String cycleTimezone;
144         final boolean metered;
145 
146         if (template.getMatchRule() == MATCH_WIFI) {
147             cycleDay = CYCLE_NONE;
148             cycleTimezone = Time.TIMEZONE_UTC;
149             metered = false;
150         } else {
151             final Time time = new Time();
152             time.setToNow();
153             cycleDay = time.monthDay;
154             cycleTimezone = time.timezone;
155             metered = true;
156         }
157 
158         return new NetworkPolicy(template, cycleDay, cycleTimezone, WARNING_DISABLED,
159                 LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, metered, true);
160     }
161 
getPolicyCycleDay(NetworkTemplate template)162     public int getPolicyCycleDay(NetworkTemplate template) {
163         return getPolicy(template).cycleDay;
164     }
165 
setPolicyCycleDay(NetworkTemplate template, int cycleDay, String cycleTimezone)166     public void setPolicyCycleDay(NetworkTemplate template, int cycleDay, String cycleTimezone) {
167         final NetworkPolicy policy = getOrCreatePolicy(template);
168         policy.cycleDay = cycleDay;
169         policy.cycleTimezone = cycleTimezone;
170         policy.inferred = false;
171         policy.clearSnooze();
172         writeAsync();
173     }
174 
getPolicyWarningBytes(NetworkTemplate template)175     public long getPolicyWarningBytes(NetworkTemplate template) {
176         return getPolicy(template).warningBytes;
177     }
178 
setPolicyWarningBytes(NetworkTemplate template, long warningBytes)179     public void setPolicyWarningBytes(NetworkTemplate template, long warningBytes) {
180         final NetworkPolicy policy = getOrCreatePolicy(template);
181         policy.warningBytes = warningBytes;
182         policy.inferred = false;
183         policy.clearSnooze();
184         writeAsync();
185     }
186 
getPolicyLimitBytes(NetworkTemplate template)187     public long getPolicyLimitBytes(NetworkTemplate template) {
188         return getPolicy(template).limitBytes;
189     }
190 
setPolicyLimitBytes(NetworkTemplate template, long limitBytes)191     public void setPolicyLimitBytes(NetworkTemplate template, long limitBytes) {
192         final NetworkPolicy policy = getOrCreatePolicy(template);
193         policy.limitBytes = limitBytes;
194         policy.inferred = false;
195         policy.clearSnooze();
196         writeAsync();
197     }
198 
getPolicyMetered(NetworkTemplate template)199     public boolean getPolicyMetered(NetworkTemplate template) {
200         NetworkPolicy policy = getPolicy(template);
201         if (policy != null) {
202             return policy.metered;
203         } else {
204             return false;
205         }
206     }
207 
setPolicyMetered(NetworkTemplate template, boolean metered)208     public void setPolicyMetered(NetworkTemplate template, boolean metered) {
209         boolean modified = false;
210 
211         NetworkPolicy policy = getPolicy(template);
212         if (metered) {
213             if (policy == null) {
214                 policy = buildDefaultPolicy(template);
215                 policy.metered = true;
216                 policy.inferred = false;
217                 mPolicies.add(policy);
218                 modified = true;
219             } else if (!policy.metered) {
220                 policy.metered = true;
221                 policy.inferred = false;
222                 modified = true;
223             }
224 
225         } else {
226             if (policy == null) {
227                 // ignore when policy doesn't exist
228             } else if (policy.metered) {
229                 policy.metered = false;
230                 policy.inferred = false;
231                 modified = true;
232             }
233         }
234 
235         // Remove legacy unquoted policies while we're here
236         final NetworkTemplate unquoted = buildUnquotedNetworkTemplate(template);
237         final NetworkPolicy unquotedPolicy = getPolicy(unquoted);
238         if (unquotedPolicy != null) {
239             mPolicies.remove(unquotedPolicy);
240             modified = true;
241         }
242 
243         if (modified) writeAsync();
244     }
245 
246     /**
247      * Remove any split {@link NetworkPolicy}.
248      */
forceMobilePolicyCombined()249     private boolean forceMobilePolicyCombined() {
250         final HashSet<String> subscriberIds = Sets.newHashSet();
251         for (NetworkPolicy policy : mPolicies) {
252             subscriberIds.add(policy.template.getSubscriberId());
253         }
254 
255         boolean modified = false;
256         for (String subscriberId : subscriberIds) {
257             modified |= setMobilePolicySplitInternal(subscriberId, false);
258         }
259         return modified;
260     }
261 
262     @Deprecated
isMobilePolicySplit(String subscriberId)263     public boolean isMobilePolicySplit(String subscriberId) {
264         boolean has3g = false;
265         boolean has4g = false;
266         for (NetworkPolicy policy : mPolicies) {
267             final NetworkTemplate template = policy.template;
268             if (Objects.equal(subscriberId, template.getSubscriberId())) {
269                 switch (template.getMatchRule()) {
270                     case MATCH_MOBILE_3G_LOWER:
271                         has3g = true;
272                         break;
273                     case MATCH_MOBILE_4G:
274                         has4g = true;
275                         break;
276                 }
277             }
278         }
279         return has3g && has4g;
280     }
281 
282     @Deprecated
setMobilePolicySplit(String subscriberId, boolean split)283     public void setMobilePolicySplit(String subscriberId, boolean split) {
284         if (setMobilePolicySplitInternal(subscriberId, split)) {
285             writeAsync();
286         }
287     }
288 
289     /**
290      * Mutate {@link NetworkPolicy} for given subscriber, combining or splitting
291      * the policy as requested.
292      *
293      * @return {@code true} when any {@link NetworkPolicy} was mutated.
294      */
295     @Deprecated
setMobilePolicySplitInternal(String subscriberId, boolean split)296     private boolean setMobilePolicySplitInternal(String subscriberId, boolean split) {
297         final boolean beforeSplit = isMobilePolicySplit(subscriberId);
298 
299         final NetworkTemplate template3g = buildTemplateMobile3gLower(subscriberId);
300         final NetworkTemplate template4g = buildTemplateMobile4g(subscriberId);
301         final NetworkTemplate templateAll = buildTemplateMobileAll(subscriberId);
302 
303         if (split == beforeSplit) {
304             // already in requested state; skip
305             return false;
306 
307         } else if (beforeSplit && !split) {
308             // combine, picking most restrictive policy
309             final NetworkPolicy policy3g = getPolicy(template3g);
310             final NetworkPolicy policy4g = getPolicy(template4g);
311 
312             final NetworkPolicy restrictive = policy3g.compareTo(policy4g) < 0 ? policy3g
313                     : policy4g;
314             mPolicies.remove(policy3g);
315             mPolicies.remove(policy4g);
316             mPolicies.add(new NetworkPolicy(templateAll, restrictive.cycleDay,
317                     restrictive.cycleTimezone, restrictive.warningBytes, restrictive.limitBytes,
318                     SNOOZE_NEVER, SNOOZE_NEVER, restrictive.metered, restrictive.inferred));
319             return true;
320 
321         } else if (!beforeSplit && split) {
322             // duplicate existing policy into two rules
323             final NetworkPolicy policyAll = getPolicy(templateAll);
324             mPolicies.remove(policyAll);
325             mPolicies.add(new NetworkPolicy(template3g, policyAll.cycleDay, policyAll.cycleTimezone,
326                     policyAll.warningBytes, policyAll.limitBytes, SNOOZE_NEVER, SNOOZE_NEVER,
327                     policyAll.metered, policyAll.inferred));
328             mPolicies.add(new NetworkPolicy(template4g, policyAll.cycleDay, policyAll.cycleTimezone,
329                     policyAll.warningBytes, policyAll.limitBytes, SNOOZE_NEVER, SNOOZE_NEVER,
330                     policyAll.metered, policyAll.inferred));
331             return true;
332         } else {
333             return false;
334         }
335     }
336 
337     /**
338      * Build a revised {@link NetworkTemplate} that matches the same rule, but
339      * with an unquoted {@link NetworkTemplate#getNetworkId()}. Used to work
340      * around legacy bugs.
341      */
342     private static NetworkTemplate buildUnquotedNetworkTemplate(NetworkTemplate template) {
343         if (template == null) return null;
344         final String networkId = template.getNetworkId();
345         final String strippedNetworkId = WifiInfo.removeDoubleQuotes(networkId);
346         if (!TextUtils.equals(strippedNetworkId, networkId)) {
347             return new NetworkTemplate(
348                     template.getMatchRule(), template.getSubscriberId(), strippedNetworkId);
349         } else {
350             return null;
351         }
352     }
353 }
354