NetworkPolicyManager.java revision 41ff7ec82422a5b6d00892afdb3232bc0e53d851
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
17package android.net;
18
19import static android.content.pm.PackageManager.GET_SIGNATURES;
20import static android.text.format.Time.MONTH_DAY;
21
22import android.content.Context;
23import android.content.Intent;
24import android.content.pm.PackageManager;
25import android.content.pm.PackageManager.NameNotFoundException;
26import android.content.pm.Signature;
27import android.os.RemoteException;
28import android.text.format.Time;
29
30import com.google.android.collect.Sets;
31
32import java.io.PrintWriter;
33import java.util.HashSet;
34
35/**
36 * Manager for creating and modifying network policy rules.
37 *
38 * {@hide}
39 */
40public class NetworkPolicyManager {
41
42    /** No specific network policy, use system default. */
43    public static final int POLICY_NONE = 0x0;
44    /** Reject network usage on metered networks when application in background. */
45    public static final int POLICY_REJECT_METERED_BACKGROUND = 0x1;
46
47    /** All network traffic should be allowed. */
48    public static final int RULE_ALLOW_ALL = 0x0;
49    /** Reject traffic on metered networks. */
50    public static final int RULE_REJECT_METERED = 0x1;
51
52    private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
53
54    /**
55     * {@link Intent} extra that indicates which {@link NetworkTemplate} rule it
56     * applies to.
57     */
58    public static final String EXTRA_NETWORK_TEMPLATE = "android.net.NETWORK_TEMPLATE";
59
60    private INetworkPolicyManager mService;
61
62    public NetworkPolicyManager(INetworkPolicyManager service) {
63        if (service == null) {
64            throw new IllegalArgumentException("missing INetworkPolicyManager");
65        }
66        mService = service;
67    }
68
69    public static NetworkPolicyManager getSystemService(Context context) {
70        return (NetworkPolicyManager) context.getSystemService(Context.NETWORK_POLICY_SERVICE);
71    }
72
73    /** {@hide} */
74    public void setNetworkPolicies(NetworkPolicy[] policies) {
75        try {
76            mService.setNetworkPolicies(policies);
77        } catch (RemoteException e) {
78        }
79    }
80
81    /** {@hide} */
82    public NetworkPolicy[] getNetworkPolicies() {
83        try {
84            return mService.getNetworkPolicies();
85        } catch (RemoteException e) {
86            return null;
87        }
88    }
89
90    /**
91     * Set policy flags for specific UID.
92     *
93     * @param policy {@link #POLICY_NONE} or combination of flags like
94     *            {@link #POLICY_REJECT_METERED_BACKGROUND}.
95     */
96    public void setUidPolicy(int uid, int policy) {
97        try {
98            mService.setUidPolicy(uid, policy);
99        } catch (RemoteException e) {
100        }
101    }
102
103    public int getUidPolicy(int uid) {
104        try {
105            return mService.getUidPolicy(uid);
106        } catch (RemoteException e) {
107            return POLICY_NONE;
108        }
109    }
110
111    public void registerListener(INetworkPolicyListener listener) {
112        try {
113            mService.registerListener(listener);
114        } catch (RemoteException e) {
115        }
116    }
117
118    public void unregisterListener(INetworkPolicyListener listener) {
119        try {
120            mService.unregisterListener(listener);
121        } catch (RemoteException e) {
122        }
123    }
124
125    /**
126     * Compute the last cycle boundary for the given {@link NetworkPolicy}. For
127     * example, if cycle day is 20th, and today is June 15th, it will return May
128     * 20th. When cycle day doesn't exist in current month, it snaps to the 1st
129     * of following month.
130     *
131     * @hide
132     */
133    public static long computeLastCycleBoundary(long currentTime, NetworkPolicy policy) {
134        final Time now = new Time(Time.TIMEZONE_UTC);
135        now.set(currentTime);
136
137        // first, find cycle boundary for current month
138        final Time cycle = new Time(now);
139        cycle.hour = cycle.minute = cycle.second = 0;
140        snapToCycleDay(cycle, policy.cycleDay);
141
142        if (Time.compare(cycle, now) >= 0) {
143            // cycle boundary is beyond now, use last cycle boundary; start by
144            // pushing ourselves squarely into last month.
145            final Time lastMonth = new Time(now);
146            lastMonth.hour = lastMonth.minute = lastMonth.second = 0;
147            lastMonth.monthDay = 1;
148            lastMonth.month -= 1;
149            lastMonth.normalize(true);
150
151            cycle.set(lastMonth);
152            snapToCycleDay(cycle, policy.cycleDay);
153        }
154
155        return cycle.toMillis(true);
156    }
157
158    /** {@hide} */
159    public static long computeNextCycleBoundary(long currentTime, NetworkPolicy policy) {
160        final Time now = new Time(Time.TIMEZONE_UTC);
161        now.set(currentTime);
162
163        // first, find cycle boundary for current month
164        final Time cycle = new Time(now);
165        cycle.hour = cycle.minute = cycle.second = 0;
166        snapToCycleDay(cycle, policy.cycleDay);
167
168        if (Time.compare(cycle, now) <= 0) {
169            // cycle boundary is before now, use next cycle boundary; start by
170            // pushing ourselves squarely into next month.
171            final Time nextMonth = new Time(now);
172            nextMonth.hour = nextMonth.minute = nextMonth.second = 0;
173            nextMonth.monthDay = 1;
174            nextMonth.month += 1;
175            nextMonth.normalize(true);
176
177            cycle.set(nextMonth);
178            snapToCycleDay(cycle, policy.cycleDay);
179        }
180
181        return cycle.toMillis(true);
182    }
183
184    /**
185     * Snap to the cycle day for the current month given; when cycle day doesn't
186     * exist, it snaps to 1st of following month.
187     *
188     * @hide
189     */
190    public static void snapToCycleDay(Time time, int cycleDay) {
191        if (cycleDay > time.getActualMaximum(MONTH_DAY)) {
192            // cycle day isn't valid this month; snap to 1st of next month
193            time.month += 1;
194            time.monthDay = 1;
195        } else {
196            time.monthDay = cycleDay;
197        }
198        time.normalize(true);
199    }
200
201    /**
202     * Check if given UID can have a {@link #setUidPolicy(int, int)} defined,
203     * usually to protect critical system services.
204     */
205    public static boolean isUidValidForPolicy(Context context, int uid) {
206        // first, quick-reject non-applications
207        if (uid < android.os.Process.FIRST_APPLICATION_UID
208                || uid > android.os.Process.LAST_APPLICATION_UID) {
209            return false;
210        }
211
212        if (!ALLOW_PLATFORM_APP_POLICY) {
213            final PackageManager pm = context.getPackageManager();
214            final HashSet<Signature> systemSignature;
215            try {
216                systemSignature = Sets.newHashSet(
217                        pm.getPackageInfo("android", GET_SIGNATURES).signatures);
218            } catch (NameNotFoundException e) {
219                throw new RuntimeException("problem finding system signature", e);
220            }
221
222            try {
223                // reject apps signed with platform cert
224                for (String packageName : pm.getPackagesForUid(uid)) {
225                    final HashSet<Signature> packageSignature = Sets.newHashSet(
226                            pm.getPackageInfo(packageName, GET_SIGNATURES).signatures);
227                    if (packageSignature.containsAll(systemSignature)) {
228                        return false;
229                    }
230                }
231            } catch (NameNotFoundException e) {
232            }
233        }
234
235        // nothing found above; we can apply policy to UID
236        return true;
237    }
238
239    /** {@hide} */
240    public static void dumpPolicy(PrintWriter fout, int policy) {
241        fout.write("[");
242        if ((policy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
243            fout.write("REJECT_METERED_BACKGROUND");
244        }
245        fout.write("]");
246    }
247
248    /** {@hide} */
249    public static void dumpRules(PrintWriter fout, int rules) {
250        fout.write("[");
251        if ((rules & RULE_REJECT_METERED) != 0) {
252            fout.write("REJECT_METERED");
253        }
254        fout.write("]");
255    }
256
257}
258