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