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