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