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.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