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.LIMIT_DISABLED; 20 import static android.net.NetworkPolicy.SNOOZE_NEVER; 21 import static android.net.NetworkPolicy.WARNING_DISABLED; 22 import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER; 23 import static android.net.NetworkTemplate.MATCH_MOBILE_4G; 24 import static android.net.NetworkTemplate.MATCH_WIFI; 25 import static android.net.NetworkTemplate.buildTemplateMobile3gLower; 26 import static android.net.NetworkTemplate.buildTemplateMobile4g; 27 import static android.net.NetworkTemplate.buildTemplateMobileAll; 28 import static com.android.internal.util.Preconditions.checkNotNull; 29 30 import android.net.INetworkPolicyManager; 31 import android.net.NetworkPolicy; 32 import android.net.NetworkTemplate; 33 import android.os.AsyncTask; 34 import android.os.RemoteException; 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. Not thread safe. 47 */ 48 public class NetworkPolicyEditor { 49 // TODO: be more robust when missing policies from service 50 51 public static final boolean ENABLE_SPLIT_POLICIES = false; 52 53 private INetworkPolicyManager mPolicyService; 54 private ArrayList<NetworkPolicy> mPolicies = Lists.newArrayList(); 55 56 public NetworkPolicyEditor(INetworkPolicyManager policyService) { 57 mPolicyService = checkNotNull(policyService); 58 } 59 60 public void read() { 61 final NetworkPolicy[] policies; 62 try { 63 policies = mPolicyService.getNetworkPolicies(); 64 } catch (RemoteException e) { 65 throw new RuntimeException("problem reading policies", e); 66 } 67 68 boolean modified = false; 69 mPolicies.clear(); 70 for (NetworkPolicy policy : policies) { 71 // TODO: find better place to clamp these 72 if (policy.limitBytes < -1) { 73 policy.limitBytes = LIMIT_DISABLED; 74 modified = true; 75 } 76 if (policy.warningBytes < -1) { 77 policy.warningBytes = WARNING_DISABLED; 78 modified = true; 79 } 80 81 // drop any WIFI policies that were defined 82 if (policy.template.getMatchRule() == MATCH_WIFI) { 83 modified = true; 84 continue; 85 } 86 87 mPolicies.add(policy); 88 } 89 90 // force combine any split policies when disabled 91 if (!ENABLE_SPLIT_POLICIES) { 92 modified |= forceMobilePolicyCombined(); 93 } 94 95 // when we cleaned policies above, write back changes 96 if (modified) writeAsync(); 97 } 98 99 public void writeAsync() { 100 // TODO: consider making more robust by passing through service 101 final NetworkPolicy[] policies = mPolicies.toArray(new NetworkPolicy[mPolicies.size()]); 102 new AsyncTask<Void, Void, Void>() { 103 @Override 104 protected Void doInBackground(Void... params) { 105 write(policies); 106 return null; 107 } 108 }.execute(); 109 } 110 111 public void write(NetworkPolicy[] policies) { 112 try { 113 mPolicyService.setNetworkPolicies(policies); 114 } catch (RemoteException e) { 115 throw new RuntimeException("problem writing policies", e); 116 } 117 } 118 119 public boolean hasLimitedPolicy(NetworkTemplate template) { 120 final NetworkPolicy policy = getPolicy(template); 121 return policy != null && policy.limitBytes != LIMIT_DISABLED; 122 } 123 124 public NetworkPolicy getOrCreatePolicy(NetworkTemplate template) { 125 NetworkPolicy policy = getPolicy(template); 126 if (policy == null) { 127 policy = buildDefaultPolicy(template); 128 mPolicies.add(policy); 129 } 130 return policy; 131 } 132 133 public NetworkPolicy getPolicy(NetworkTemplate template) { 134 for (NetworkPolicy policy : mPolicies) { 135 if (policy.template.equals(template)) { 136 return policy; 137 } 138 } 139 return null; 140 } 141 142 private static NetworkPolicy buildDefaultPolicy(NetworkTemplate template) { 143 // TODO: move this into framework to share with NetworkPolicyManagerService 144 final Time time = new Time(); 145 time.setToNow(); 146 final int cycleDay = time.monthDay; 147 148 return new NetworkPolicy( 149 template, cycleDay, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER); 150 } 151 152 public int getPolicyCycleDay(NetworkTemplate template) { 153 return getPolicy(template).cycleDay; 154 } 155 156 public void setPolicyCycleDay(NetworkTemplate template, int cycleDay) { 157 final NetworkPolicy policy = getOrCreatePolicy(template); 158 policy.cycleDay = cycleDay; 159 policy.lastSnooze = SNOOZE_NEVER; 160 writeAsync(); 161 } 162 163 public long getPolicyWarningBytes(NetworkTemplate template) { 164 return getPolicy(template).warningBytes; 165 } 166 167 public void setPolicyWarningBytes(NetworkTemplate template, long warningBytes) { 168 final NetworkPolicy policy = getOrCreatePolicy(template); 169 policy.warningBytes = warningBytes; 170 policy.lastSnooze = SNOOZE_NEVER; 171 writeAsync(); 172 } 173 174 public long getPolicyLimitBytes(NetworkTemplate template) { 175 return getPolicy(template).limitBytes; 176 } 177 178 public void setPolicyLimitBytes(NetworkTemplate template, long limitBytes) { 179 final NetworkPolicy policy = getOrCreatePolicy(template); 180 policy.limitBytes = limitBytes; 181 policy.lastSnooze = SNOOZE_NEVER; 182 writeAsync(); 183 } 184 185 /** 186 * Remove any split {@link NetworkPolicy}. 187 */ 188 private boolean forceMobilePolicyCombined() { 189 final HashSet<String> subscriberIds = Sets.newHashSet(); 190 for (NetworkPolicy policy : mPolicies) { 191 subscriberIds.add(policy.template.getSubscriberId()); 192 } 193 194 boolean modified = false; 195 for (String subscriberId : subscriberIds) { 196 modified |= setMobilePolicySplitInternal(subscriberId, false); 197 } 198 return modified; 199 } 200 201 public boolean isMobilePolicySplit(String subscriberId) { 202 boolean has3g = false; 203 boolean has4g = false; 204 for (NetworkPolicy policy : mPolicies) { 205 final NetworkTemplate template = policy.template; 206 if (Objects.equal(subscriberId, template.getSubscriberId())) { 207 switch (template.getMatchRule()) { 208 case MATCH_MOBILE_3G_LOWER: 209 has3g = true; 210 break; 211 case MATCH_MOBILE_4G: 212 has4g = true; 213 break; 214 } 215 } 216 } 217 return has3g && has4g; 218 } 219 220 public void setMobilePolicySplit(String subscriberId, boolean split) { 221 if (setMobilePolicySplitInternal(subscriberId, split)) { 222 writeAsync(); 223 } 224 } 225 226 /** 227 * Mutate {@link NetworkPolicy} for given subscriber, combining or splitting 228 * the policy as requested. 229 * 230 * @return {@code true} when any {@link NetworkPolicy} was mutated. 231 */ 232 private boolean setMobilePolicySplitInternal(String subscriberId, boolean split) { 233 final boolean beforeSplit = isMobilePolicySplit(subscriberId); 234 235 final NetworkTemplate template3g = buildTemplateMobile3gLower(subscriberId); 236 final NetworkTemplate template4g = buildTemplateMobile4g(subscriberId); 237 final NetworkTemplate templateAll = buildTemplateMobileAll(subscriberId); 238 239 if (split == beforeSplit) { 240 // already in requested state; skip 241 return false; 242 243 } else if (beforeSplit && !split) { 244 // combine, picking most restrictive policy 245 final NetworkPolicy policy3g = getPolicy(template3g); 246 final NetworkPolicy policy4g = getPolicy(template4g); 247 248 final NetworkPolicy restrictive = policy3g.compareTo(policy4g) < 0 ? policy3g 249 : policy4g; 250 mPolicies.remove(policy3g); 251 mPolicies.remove(policy4g); 252 mPolicies.add( 253 new NetworkPolicy(templateAll, restrictive.cycleDay, restrictive.warningBytes, 254 restrictive.limitBytes, SNOOZE_NEVER)); 255 return true; 256 257 } else if (!beforeSplit && split) { 258 // duplicate existing policy into two rules 259 final NetworkPolicy policyAll = getPolicy(templateAll); 260 mPolicies.remove(policyAll); 261 mPolicies.add( 262 new NetworkPolicy(template3g, policyAll.cycleDay, policyAll.warningBytes, 263 policyAll.limitBytes, SNOOZE_NEVER)); 264 mPolicies.add( 265 new NetworkPolicy(template4g, policyAll.cycleDay, policyAll.warningBytes, 266 policyAll.limitBytes, SNOOZE_NEVER)); 267 return true; 268 } else { 269 return false; 270 } 271 } 272 } 273