• 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.google.android.collect.Lists;
40 import com.google.android.collect.Sets;
41 
42 import java.util.ArrayList;
43 import java.util.HashSet;
44 import java.util.Objects;
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         final NetworkPolicy policy = getPolicy(template);
164         return (policy != null) ? policy.cycleDay : -1;
165     }
166 
setPolicyCycleDay(NetworkTemplate template, int cycleDay, String cycleTimezone)167     public void setPolicyCycleDay(NetworkTemplate template, int cycleDay, String cycleTimezone) {
168         final NetworkPolicy policy = getOrCreatePolicy(template);
169         policy.cycleDay = cycleDay;
170         policy.cycleTimezone = cycleTimezone;
171         policy.inferred = false;
172         policy.clearSnooze();
173         writeAsync();
174     }
175 
getPolicyWarningBytes(NetworkTemplate template)176     public long getPolicyWarningBytes(NetworkTemplate template) {
177         final NetworkPolicy policy = getPolicy(template);
178         return (policy != null) ? policy.warningBytes : WARNING_DISABLED;
179     }
180 
setPolicyWarningBytes(NetworkTemplate template, long warningBytes)181     public void setPolicyWarningBytes(NetworkTemplate template, long warningBytes) {
182         final NetworkPolicy policy = getOrCreatePolicy(template);
183         policy.warningBytes = warningBytes;
184         policy.inferred = false;
185         policy.clearSnooze();
186         writeAsync();
187     }
188 
getPolicyLimitBytes(NetworkTemplate template)189     public long getPolicyLimitBytes(NetworkTemplate template) {
190         final NetworkPolicy policy = getPolicy(template);
191         return (policy != null) ? policy.limitBytes : LIMIT_DISABLED;
192     }
193 
setPolicyLimitBytes(NetworkTemplate template, long limitBytes)194     public void setPolicyLimitBytes(NetworkTemplate template, long limitBytes) {
195         final NetworkPolicy policy = getOrCreatePolicy(template);
196         policy.limitBytes = limitBytes;
197         policy.inferred = false;
198         policy.clearSnooze();
199         writeAsync();
200     }
201 
getPolicyMetered(NetworkTemplate template)202     public boolean getPolicyMetered(NetworkTemplate template) {
203         NetworkPolicy policy = getPolicy(template);
204         if (policy != null) {
205             return policy.metered;
206         } else {
207             return false;
208         }
209     }
210 
setPolicyMetered(NetworkTemplate template, boolean metered)211     public void setPolicyMetered(NetworkTemplate template, boolean metered) {
212         boolean modified = false;
213 
214         NetworkPolicy policy = getPolicy(template);
215         if (metered) {
216             if (policy == null) {
217                 policy = buildDefaultPolicy(template);
218                 policy.metered = true;
219                 policy.inferred = false;
220                 mPolicies.add(policy);
221                 modified = true;
222             } else if (!policy.metered) {
223                 policy.metered = true;
224                 policy.inferred = false;
225                 modified = true;
226             }
227 
228         } else {
229             if (policy == null) {
230                 // ignore when policy doesn't exist
231             } else if (policy.metered) {
232                 policy.metered = false;
233                 policy.inferred = false;
234                 modified = true;
235             }
236         }
237 
238         // Remove legacy unquoted policies while we're here
239         final NetworkTemplate unquoted = buildUnquotedNetworkTemplate(template);
240         final NetworkPolicy unquotedPolicy = getPolicy(unquoted);
241         if (unquotedPolicy != null) {
242             mPolicies.remove(unquotedPolicy);
243             modified = true;
244         }
245 
246         if (modified) writeAsync();
247     }
248 
249     /**
250      * Remove any split {@link NetworkPolicy}.
251      */
forceMobilePolicyCombined()252     private boolean forceMobilePolicyCombined() {
253         final HashSet<String> subscriberIds = Sets.newHashSet();
254         for (NetworkPolicy policy : mPolicies) {
255             subscriberIds.add(policy.template.getSubscriberId());
256         }
257 
258         boolean modified = false;
259         for (String subscriberId : subscriberIds) {
260             modified |= setMobilePolicySplitInternal(subscriberId, false);
261         }
262         return modified;
263     }
264 
265     @Deprecated
isMobilePolicySplit(String subscriberId)266     public boolean isMobilePolicySplit(String subscriberId) {
267         boolean has3g = false;
268         boolean has4g = false;
269         for (NetworkPolicy policy : mPolicies) {
270             final NetworkTemplate template = policy.template;
271             if (Objects.equals(subscriberId, template.getSubscriberId())) {
272                 switch (template.getMatchRule()) {
273                     case MATCH_MOBILE_3G_LOWER:
274                         has3g = true;
275                         break;
276                     case MATCH_MOBILE_4G:
277                         has4g = true;
278                         break;
279                 }
280             }
281         }
282         return has3g && has4g;
283     }
284 
285     @Deprecated
setMobilePolicySplit(String subscriberId, boolean split)286     public void setMobilePolicySplit(String subscriberId, boolean split) {
287         if (setMobilePolicySplitInternal(subscriberId, split)) {
288             writeAsync();
289         }
290     }
291 
292     /**
293      * Mutate {@link NetworkPolicy} for given subscriber, combining or splitting
294      * the policy as requested.
295      *
296      * @return {@code true} when any {@link NetworkPolicy} was mutated.
297      */
298     @Deprecated
setMobilePolicySplitInternal(String subscriberId, boolean split)299     private boolean setMobilePolicySplitInternal(String subscriberId, boolean split) {
300         final boolean beforeSplit = isMobilePolicySplit(subscriberId);
301 
302         final NetworkTemplate template3g = buildTemplateMobile3gLower(subscriberId);
303         final NetworkTemplate template4g = buildTemplateMobile4g(subscriberId);
304         final NetworkTemplate templateAll = buildTemplateMobileAll(subscriberId);
305 
306         if (split == beforeSplit) {
307             // already in requested state; skip
308             return false;
309 
310         } else if (beforeSplit && !split) {
311             // combine, picking most restrictive policy
312             final NetworkPolicy policy3g = getPolicy(template3g);
313             final NetworkPolicy policy4g = getPolicy(template4g);
314 
315             NetworkPolicy restrictive = null;
316             if ((policy3g == null) && (policy4g == null)) {
317                 return false;
318             } else if (policy3g == null) {
319                 restrictive = policy4g;
320             } else if (policy4g == null) {
321                 restrictive = policy3g;
322             } else {
323                 restrictive = policy3g.compareTo(policy4g) < 0 ? policy3g : policy4g;
324             }
325             mPolicies.remove(policy3g);
326             mPolicies.remove(policy4g);
327             mPolicies.add(new NetworkPolicy(templateAll, restrictive.cycleDay,
328                     restrictive.cycleTimezone, restrictive.warningBytes, restrictive.limitBytes,
329                     SNOOZE_NEVER, SNOOZE_NEVER, restrictive.metered, restrictive.inferred));
330             return true;
331 
332         } else if (!beforeSplit && split) {
333             // duplicate existing policy into two rules
334             final NetworkPolicy policyAll = getPolicy(templateAll);
335             if (policyAll == null) {
336                 return false;
337             }
338             mPolicies.remove(policyAll);
339             mPolicies.add(new NetworkPolicy(template3g, policyAll.cycleDay, policyAll.cycleTimezone,
340                     policyAll.warningBytes, policyAll.limitBytes, SNOOZE_NEVER, SNOOZE_NEVER,
341                     policyAll.metered, policyAll.inferred));
342             mPolicies.add(new NetworkPolicy(template4g, policyAll.cycleDay, policyAll.cycleTimezone,
343                     policyAll.warningBytes, policyAll.limitBytes, SNOOZE_NEVER, SNOOZE_NEVER,
344                     policyAll.metered, policyAll.inferred));
345             return true;
346         } else {
347             return false;
348         }
349     }
350 
351     /**
352      * Build a revised {@link NetworkTemplate} that matches the same rule, but
353      * with an unquoted {@link NetworkTemplate#getNetworkId()}. Used to work
354      * around legacy bugs.
355      */
356     private static NetworkTemplate buildUnquotedNetworkTemplate(NetworkTemplate template) {
357         if (template == null) return null;
358         final String networkId = template.getNetworkId();
359         final String strippedNetworkId = WifiInfo.removeDoubleQuotes(networkId);
360         if (!TextUtils.equals(strippedNetworkId, networkId)) {
361             return new NetworkTemplate(
362                     template.getMatchRule(), template.getSubscriberId(), strippedNetworkId);
363         } else {
364             return null;
365         }
366     }
367 }
368