Home | History | Annotate | Download | only in net
      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 
     59     public NetworkPolicyEditor(NetworkPolicyManager policyManager) {
     60         mPolicyManager = checkNotNull(policyManager);
     61     }
     62 
     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 
     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 
    103     public void write(NetworkPolicy[] policies) {
    104         mPolicyManager.setNetworkPolicies(policies);
    105     }
    106 
    107     public boolean hasLimitedPolicy(NetworkTemplate template) {
    108         final NetworkPolicy policy = getPolicy(template);
    109         return policy != null && policy.limitBytes != LIMIT_DISABLED;
    110     }
    111 
    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 
    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 
    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
    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 
    162     public int getPolicyCycleDay(NetworkTemplate template) {
    163         return getPolicy(template).cycleDay;
    164     }
    165 
    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 
    175     public long getPolicyWarningBytes(NetworkTemplate template) {
    176         return getPolicy(template).warningBytes;
    177     }
    178 
    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 
    187     public long getPolicyLimitBytes(NetworkTemplate template) {
    188         return getPolicy(template).limitBytes;
    189     }
    190 
    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 
    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 
    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      */
    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
    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
    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
    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