NetworkPolicyManagerService.java revision 8e28b7d78232f6cf08739ca0d129cc7f9e650801
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 com.android.server.net;
18
19import static android.Manifest.permission.ACCESS_NETWORK_STATE;
20import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
21import static android.Manifest.permission.DUMP;
22import static android.Manifest.permission.MANAGE_APP_TOKENS;
23import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
24import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
25import static android.Manifest.permission.READ_PHONE_STATE;
26import static android.content.Intent.ACTION_PACKAGE_ADDED;
27import static android.content.Intent.ACTION_UID_REMOVED;
28import static android.content.Intent.EXTRA_UID;
29import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
30import static android.net.ConnectivityManager.TYPE_ETHERNET;
31import static android.net.ConnectivityManager.TYPE_MOBILE;
32import static android.net.ConnectivityManager.TYPE_WIFI;
33import static android.net.ConnectivityManager.TYPE_WIMAX;
34import static android.net.NetworkPolicy.LIMIT_DISABLED;
35import static android.net.NetworkPolicy.SNOOZE_NEVER;
36import static android.net.NetworkPolicy.WARNING_DISABLED;
37import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
38import static android.net.NetworkPolicyManager.POLICY_NONE;
39import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
40import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
41import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
42import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
43import static android.net.NetworkPolicyManager.dumpPolicy;
44import static android.net.NetworkPolicyManager.dumpRules;
45import static android.net.NetworkPolicyManager.isUidValidForPolicy;
46import static android.net.NetworkTemplate.MATCH_ETHERNET;
47import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
48import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
49import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
50import static android.net.NetworkTemplate.MATCH_WIFI;
51import static android.net.NetworkTemplate.buildTemplateMobileAll;
52import static android.text.format.DateUtils.DAY_IN_MILLIS;
53import static com.android.internal.util.Preconditions.checkNotNull;
54import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readBooleanAttribute;
55import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readIntAttribute;
56import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readLongAttribute;
57import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeBooleanAttribute;
58import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeIntAttribute;
59import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeLongAttribute;
60import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
61import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
62import static org.xmlpull.v1.XmlPullParser.START_TAG;
63
64import android.app.IActivityManager;
65import android.app.INotificationManager;
66import android.app.IProcessObserver;
67import android.app.Notification;
68import android.app.PendingIntent;
69import android.content.BroadcastReceiver;
70import android.content.ComponentName;
71import android.content.Context;
72import android.content.Intent;
73import android.content.IntentFilter;
74import android.content.pm.ApplicationInfo;
75import android.content.pm.PackageManager;
76import android.content.res.Resources;
77import android.net.ConnectivityManager;
78import android.net.IConnectivityManager;
79import android.net.INetworkManagementEventObserver;
80import android.net.INetworkPolicyListener;
81import android.net.INetworkPolicyManager;
82import android.net.INetworkStatsService;
83import android.net.NetworkIdentity;
84import android.net.NetworkPolicy;
85import android.net.NetworkQuotaInfo;
86import android.net.NetworkState;
87import android.net.NetworkStats;
88import android.net.NetworkTemplate;
89import android.os.Binder;
90import android.os.Environment;
91import android.os.Handler;
92import android.os.HandlerThread;
93import android.os.INetworkManagementService;
94import android.os.IPowerManager;
95import android.os.Message;
96import android.os.RemoteCallbackList;
97import android.os.RemoteException;
98import android.provider.Settings;
99import android.telephony.TelephonyManager;
100import android.text.format.Formatter;
101import android.text.format.Time;
102import android.util.NtpTrustedTime;
103import android.util.Slog;
104import android.util.SparseArray;
105import android.util.SparseBooleanArray;
106import android.util.SparseIntArray;
107import android.util.TrustedTime;
108import android.util.Xml;
109
110import com.android.internal.R;
111import com.android.internal.os.AtomicFile;
112import com.android.internal.util.FastXmlSerializer;
113import com.android.internal.util.Objects;
114import com.google.android.collect.Lists;
115import com.google.android.collect.Maps;
116import com.google.android.collect.Sets;
117
118import org.xmlpull.v1.XmlPullParser;
119import org.xmlpull.v1.XmlPullParserException;
120import org.xmlpull.v1.XmlSerializer;
121
122import java.io.File;
123import java.io.FileDescriptor;
124import java.io.FileInputStream;
125import java.io.FileNotFoundException;
126import java.io.FileOutputStream;
127import java.io.IOException;
128import java.io.PrintWriter;
129import java.net.ProtocolException;
130import java.util.ArrayList;
131import java.util.Arrays;
132import java.util.HashMap;
133import java.util.HashSet;
134import java.util.List;
135
136import libcore.io.IoUtils;
137
138/**
139 * Service that maintains low-level network policy rules, using
140 * {@link NetworkStatsService} statistics to drive those rules.
141 * <p>
142 * Derives active rules by combining a given policy with other system status,
143 * and delivers to listeners, such as {@link ConnectivityManager}, for
144 * enforcement.
145 */
146public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
147    private static final String TAG = "NetworkPolicy";
148    private static final boolean LOGD = true;
149    private static final boolean LOGV = false;
150
151    private static final int VERSION_INIT = 1;
152    private static final int VERSION_ADDED_SNOOZE = 2;
153    private static final int VERSION_ADDED_RESTRICT_BACKGROUND = 3;
154
155    private static final long KB_IN_BYTES = 1024;
156    private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
157    private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
158
159    // @VisibleForTesting
160    public static final int TYPE_WARNING = 0x1;
161    public static final int TYPE_LIMIT = 0x2;
162    public static final int TYPE_LIMIT_SNOOZED = 0x3;
163
164    private static final String TAG_POLICY_LIST = "policy-list";
165    private static final String TAG_NETWORK_POLICY = "network-policy";
166    private static final String TAG_UID_POLICY = "uid-policy";
167
168    private static final String ATTR_VERSION = "version";
169    private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground";
170    private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate";
171    private static final String ATTR_SUBSCRIBER_ID = "subscriberId";
172    private static final String ATTR_CYCLE_DAY = "cycleDay";
173    private static final String ATTR_WARNING_BYTES = "warningBytes";
174    private static final String ATTR_LIMIT_BYTES = "limitBytes";
175    private static final String ATTR_LAST_SNOOZE = "lastSnooze";
176    private static final String ATTR_UID = "uid";
177    private static final String ATTR_POLICY = "policy";
178
179    private static final String TAG_ALLOW_BACKGROUND = TAG + ":allowBackground";
180
181    // @VisibleForTesting
182    public static final String ACTION_ALLOW_BACKGROUND =
183            "com.android.server.action.ACTION_ALLOW_BACKGROUND";
184
185    private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
186
187    private static final int MSG_RULES_CHANGED = 0x1;
188    private static final int MSG_METERED_IFACES_CHANGED = 0x2;
189
190    private final Context mContext;
191    private final IActivityManager mActivityManager;
192    private final IPowerManager mPowerManager;
193    private final INetworkStatsService mNetworkStats;
194    private final INetworkManagementService mNetworkManager;
195    private final TrustedTime mTime;
196
197    private IConnectivityManager mConnManager;
198    private INotificationManager mNotifManager;
199
200    private final Object mRulesLock = new Object();
201
202    private volatile boolean mScreenOn;
203    private volatile boolean mRestrictBackground;
204
205    private final boolean mSuppressDefaultPolicy;
206
207    /** Defined network policies. */
208    private HashMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = Maps.newHashMap();
209    /** Currently active network rules for ifaces. */
210    private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap();
211
212    /** Defined UID policies. */
213    private SparseIntArray mUidPolicy = new SparseIntArray();
214    /** Currently derived rules for each UID. */
215    private SparseIntArray mUidRules = new SparseIntArray();
216
217    /** Set of ifaces that are metered. */
218    private HashSet<String> mMeteredIfaces = Sets.newHashSet();
219    /** Set of over-limit templates that have been notified. */
220    private HashSet<NetworkTemplate> mOverLimitNotified = Sets.newHashSet();
221
222    /** Set of currently active {@link Notification} tags. */
223    private HashSet<String> mActiveNotifs = Sets.newHashSet();
224    /** Current values from {@link #setPolicyDataEnable(int, boolean)}. */
225    private SparseBooleanArray mActiveNetworkEnabled = new SparseBooleanArray();
226
227    /** Foreground at both UID and PID granularity. */
228    private SparseBooleanArray mUidForeground = new SparseBooleanArray();
229    private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
230            SparseBooleanArray>();
231
232    private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
233            INetworkPolicyListener>();
234
235    private final HandlerThread mHandlerThread;
236    private final Handler mHandler;
237
238    private final AtomicFile mPolicyFile;
239
240    // TODO: keep whitelist of system-critical services that should never have
241    // rules enforced, such as system, phone, and radio UIDs.
242
243    // TODO: migrate notifications to SystemUI
244
245    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
246            IPowerManager powerManager, INetworkStatsService networkStats,
247            INetworkManagementService networkManagement) {
248        this(context, activityManager, powerManager, networkStats, networkManagement,
249                NtpTrustedTime.getInstance(context), getSystemDir(), false);
250    }
251
252    private static File getSystemDir() {
253        return new File(Environment.getDataDirectory(), "system");
254    }
255
256    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
257            IPowerManager powerManager, INetworkStatsService networkStats,
258            INetworkManagementService networkManagement, TrustedTime time, File systemDir,
259            boolean suppressDefaultPolicy) {
260        mContext = checkNotNull(context, "missing context");
261        mActivityManager = checkNotNull(activityManager, "missing activityManager");
262        mPowerManager = checkNotNull(powerManager, "missing powerManager");
263        mNetworkStats = checkNotNull(networkStats, "missing networkStats");
264        mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
265        mTime = checkNotNull(time, "missing TrustedTime");
266
267        mHandlerThread = new HandlerThread(TAG);
268        mHandlerThread.start();
269        mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
270
271        mSuppressDefaultPolicy = suppressDefaultPolicy;
272
273        mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
274    }
275
276    public void bindConnectivityManager(IConnectivityManager connManager) {
277        mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
278    }
279
280    public void bindNotificationManager(INotificationManager notifManager) {
281        mNotifManager = checkNotNull(notifManager, "missing INotificationManager");
282    }
283
284    public void systemReady() {
285        synchronized (mRulesLock) {
286            // read policy from disk
287            readPolicyLocked();
288
289            if (mRestrictBackground) {
290                updateRulesForRestrictBackgroundLocked();
291                updateNotificationsLocked();
292            }
293        }
294
295        updateScreenOn();
296
297        try {
298            mActivityManager.registerProcessObserver(mProcessObserver);
299        } catch (RemoteException e) {
300            // ouch, no foregroundActivities updates means some processes may
301            // never get network access.
302            Slog.e(TAG, "unable to register IProcessObserver", e);
303        }
304
305        try {
306            mNetworkManager.registerObserver(mAlertObserver);
307        } catch (RemoteException e) {
308            // ouch, no alert updates means we fall back to
309            // ACTION_NETWORK_STATS_UPDATED broadcasts.
310            Slog.e(TAG, "unable to register INetworkManagementEventObserver", e);
311        }
312
313        // TODO: traverse existing processes to know foreground state, or have
314        // activitymanager dispatch current state when new observer attached.
315
316        final IntentFilter screenFilter = new IntentFilter();
317        screenFilter.addAction(Intent.ACTION_SCREEN_ON);
318        screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
319        mContext.registerReceiver(mScreenReceiver, screenFilter, null, mHandler);
320
321        // watch for network interfaces to be claimed
322        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
323        mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
324
325        // listen for package/uid changes to update policy
326        final IntentFilter packageFilter = new IntentFilter();
327        packageFilter.addAction(ACTION_PACKAGE_ADDED);
328        packageFilter.addAction(ACTION_UID_REMOVED);
329        mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
330
331        // listen for stats update events
332        final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
333        mContext.registerReceiver(
334                mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
335
336        // listen for restrict background changes from notifications
337        final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
338        mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
339
340    }
341
342    private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
343        @Override
344        public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
345            // only someone like AMS should only be calling us
346            mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
347
348            synchronized (mRulesLock) {
349                // because a uid can have multiple pids running inside, we need to
350                // remember all pid states and summarize foreground at uid level.
351
352                // record foreground for this specific pid
353                SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
354                if (pidForeground == null) {
355                    pidForeground = new SparseBooleanArray(2);
356                    mUidPidForeground.put(uid, pidForeground);
357                }
358                pidForeground.put(pid, foregroundActivities);
359                computeUidForegroundLocked(uid);
360            }
361        }
362
363        @Override
364        public void onProcessDied(int pid, int uid) {
365            // only someone like AMS should only be calling us
366            mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
367
368            synchronized (mRulesLock) {
369                // clear records and recompute, when they exist
370                final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
371                if (pidForeground != null) {
372                    pidForeground.delete(pid);
373                    computeUidForegroundLocked(uid);
374                }
375            }
376        }
377    };
378
379    private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
380        @Override
381        public void onReceive(Context context, Intent intent) {
382            synchronized (mRulesLock) {
383                // screen-related broadcasts are protected by system, no need
384                // for permissions check.
385                updateScreenOn();
386            }
387        }
388    };
389
390    private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
391        @Override
392        public void onReceive(Context context, Intent intent) {
393            // on background handler thread, and PACKAGE_ADDED and UID_REMOVED
394            // are protected broadcasts.
395
396            final String action = intent.getAction();
397            final int uid = intent.getIntExtra(EXTRA_UID, 0);
398            synchronized (mRulesLock) {
399                if (ACTION_PACKAGE_ADDED.equals(action)) {
400                    // update rules for UID, since it might be subject to
401                    // global background data policy.
402                    if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
403                    updateRulesForUidLocked(uid);
404
405                } else if (ACTION_UID_REMOVED.equals(action)) {
406                    // remove any policy and update rules to clean up.
407                    if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
408                    mUidPolicy.delete(uid);
409                    updateRulesForUidLocked(uid);
410                    writePolicyLocked();
411                }
412            }
413        }
414    };
415
416    /**
417     * Receiver that watches for {@link INetworkStatsService} updates, which we
418     * use to check against {@link NetworkPolicy#warningBytes}.
419     */
420    private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() {
421        @Override
422        public void onReceive(Context context, Intent intent) {
423            // on background handler thread, and verified
424            // READ_NETWORK_USAGE_HISTORY permission above.
425
426            synchronized (mRulesLock) {
427                updateNetworkEnabledLocked();
428                updateNotificationsLocked();
429            }
430        }
431    };
432
433    /**
434     * Receiver that watches for {@link Notification} control of
435     * {@link #mRestrictBackground}.
436     */
437    private BroadcastReceiver mAllowReceiver = new BroadcastReceiver() {
438        @Override
439        public void onReceive(Context context, Intent intent) {
440            // on background handler thread, and verified MANAGE_NETWORK_POLICY
441            // permission above.
442
443            setRestrictBackground(false);
444        }
445    };
446
447    /**
448     * Observer that watches for {@link INetworkManagementService} alerts.
449     */
450    private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() {
451        @Override
452        public void limitReached(String limitName, String iface) {
453            // only someone like NMS should be calling us
454            mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
455
456            synchronized (mRulesLock) {
457                if (mMeteredIfaces.contains(iface)) {
458                    try {
459                        // force stats update to make sure we have numbers that
460                        // caused alert to trigger.
461                        mNetworkStats.forceUpdate();
462                    } catch (RemoteException e) {
463                        Slog.w(TAG, "problem updating network stats");
464                    }
465
466                    updateNetworkEnabledLocked();
467                    updateNotificationsLocked();
468                }
469            }
470        }
471    };
472
473    /**
474     * Check {@link NetworkPolicy} against current {@link INetworkStatsService}
475     * to show visible notifications as needed.
476     */
477    private void updateNotificationsLocked() {
478        if (LOGV) Slog.v(TAG, "updateNotificationsLocked()");
479
480        // keep track of previously active notifications
481        final HashSet<String> beforeNotifs = Sets.newHashSet();
482        beforeNotifs.addAll(mActiveNotifs);
483        mActiveNotifs.clear();
484
485        // TODO: when switching to kernel notifications, compute next future
486        // cycle boundary to recompute notifications.
487
488        // examine stats for each active policy
489        final long currentTime = currentTimeMillis(true);
490        for (NetworkPolicy policy : mNetworkPolicy.values()) {
491            // ignore policies that aren't relevant to user
492            if (!isTemplateRelevant(policy.template)) continue;
493
494            final long start = computeLastCycleBoundary(currentTime, policy);
495            final long end = currentTime;
496
497            final long totalBytes = getTotalBytes(policy.template, start, end);
498            if (totalBytes == UNKNOWN_BYTES) continue;
499
500            if (policy.limitBytes != LIMIT_DISABLED && totalBytes >= policy.limitBytes) {
501                if (policy.lastSnooze >= start) {
502                    enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
503                } else {
504                    enqueueNotification(policy, TYPE_LIMIT, totalBytes);
505                    notifyOverLimitLocked(policy.template);
506                }
507
508            } else {
509                notifyUnderLimitLocked(policy.template);
510
511                if (policy.warningBytes != WARNING_DISABLED && totalBytes >= policy.warningBytes) {
512                    enqueueNotification(policy, TYPE_WARNING, totalBytes);
513                }
514            }
515        }
516
517        // ongoing notification when restricting background data
518        if (mRestrictBackground) {
519            enqueueRestrictedNotification(TAG_ALLOW_BACKGROUND);
520        }
521
522        // cancel stale notifications that we didn't renew above
523        for (String tag : beforeNotifs) {
524            if (!mActiveNotifs.contains(tag)) {
525                cancelNotification(tag);
526            }
527        }
528    }
529
530    /**
531     * Test if given {@link NetworkTemplate} is relevant to user based on
532     * current device state, such as when {@link #getActiveSubscriberId()}
533     * matches. This is regardless of data connection status.
534     */
535    private boolean isTemplateRelevant(NetworkTemplate template) {
536        switch (template.getMatchRule()) {
537            case MATCH_MOBILE_3G_LOWER:
538            case MATCH_MOBILE_4G:
539            case MATCH_MOBILE_ALL:
540                // mobile templates are relevant when subscriberid is active
541                return Objects.equal(getActiveSubscriberId(), template.getSubscriberId());
542        }
543        return true;
544    }
545
546    /**
547     * Notify that given {@link NetworkTemplate} is over
548     * {@link NetworkPolicy#limitBytes}, potentially showing dialog to user.
549     */
550    private void notifyOverLimitLocked(NetworkTemplate template) {
551        if (!mOverLimitNotified.contains(template)) {
552            mContext.startActivity(buildNetworkOverLimitIntent(template));
553            mOverLimitNotified.add(template);
554        }
555    }
556
557    private void notifyUnderLimitLocked(NetworkTemplate template) {
558        mOverLimitNotified.remove(template);
559    }
560
561    /**
562     * Build unique tag that identifies an active {@link NetworkPolicy}
563     * notification of a specific type, like {@link #TYPE_LIMIT}.
564     */
565    private String buildNotificationTag(NetworkPolicy policy, int type) {
566        return TAG + ":" + policy.template.hashCode() + ":" + type;
567    }
568
569    /**
570     * Show notification for combined {@link NetworkPolicy} and specific type,
571     * like {@link #TYPE_LIMIT}. Okay to call multiple times.
572     */
573    private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes) {
574        final String tag = buildNotificationTag(policy, type);
575        final Notification.Builder builder = new Notification.Builder(mContext);
576        builder.setOnlyAlertOnce(true);
577        builder.setOngoing(true);
578
579        final Resources res = mContext.getResources();
580        switch (type) {
581            case TYPE_WARNING: {
582                final CharSequence title = res.getText(R.string.data_usage_warning_title);
583                final CharSequence body = res.getString(R.string.data_usage_warning_body,
584                        Formatter.formatFileSize(mContext, policy.warningBytes));
585
586                builder.setSmallIcon(R.drawable.ic_menu_info_details);
587                builder.setTicker(title);
588                builder.setContentTitle(title);
589                builder.setContentText(body);
590
591                final Intent intent = buildViewDataUsageIntent(policy.template);
592                builder.setContentIntent(PendingIntent.getActivity(
593                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
594                break;
595            }
596            case TYPE_LIMIT: {
597                final CharSequence body = res.getText(R.string.data_usage_limit_body);
598
599                final CharSequence title;
600                switch (policy.template.getMatchRule()) {
601                    case MATCH_MOBILE_3G_LOWER:
602                        title = res.getText(R.string.data_usage_3g_limit_title);
603                        break;
604                    case MATCH_MOBILE_4G:
605                        title = res.getText(R.string.data_usage_4g_limit_title);
606                        break;
607                    case MATCH_MOBILE_ALL:
608                        title = res.getText(R.string.data_usage_mobile_limit_title);
609                        break;
610                    case MATCH_WIFI:
611                        title = res.getText(R.string.data_usage_wifi_limit_title);
612                        break;
613                    default:
614                        title = null;
615                        break;
616                }
617
618                builder.setSmallIcon(com.android.internal.R.drawable.ic_menu_block);
619                builder.setTicker(title);
620                builder.setContentTitle(title);
621                builder.setContentText(body);
622
623                final Intent intent = buildNetworkOverLimitIntent(policy.template);
624                builder.setContentIntent(PendingIntent.getActivity(
625                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
626                break;
627            }
628            case TYPE_LIMIT_SNOOZED: {
629                final long overBytes = totalBytes - policy.limitBytes;
630                final CharSequence body = res.getString(R.string.data_usage_limit_snoozed_body,
631                        Formatter.formatFileSize(mContext, overBytes));
632
633                final CharSequence title;
634                switch (policy.template.getMatchRule()) {
635                    case MATCH_MOBILE_3G_LOWER:
636                        title = res.getText(R.string.data_usage_3g_limit_snoozed_title);
637                        break;
638                    case MATCH_MOBILE_4G:
639                        title = res.getText(R.string.data_usage_4g_limit_snoozed_title);
640                        break;
641                    case MATCH_MOBILE_ALL:
642                        title = res.getText(R.string.data_usage_mobile_limit_snoozed_title);
643                        break;
644                    case MATCH_WIFI:
645                        title = res.getText(R.string.data_usage_wifi_limit_snoozed_title);
646                        break;
647                    default:
648                        title = null;
649                        break;
650                }
651
652                builder.setSmallIcon(R.drawable.ic_menu_info_details);
653                builder.setTicker(title);
654                builder.setContentTitle(title);
655                builder.setContentText(body);
656
657                final Intent intent = buildViewDataUsageIntent(policy.template);
658                builder.setContentIntent(PendingIntent.getActivity(
659                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
660                break;
661            }
662        }
663
664        // TODO: move to NotificationManager once we can mock it
665        try {
666            final String packageName = mContext.getPackageName();
667            final int[] idReceived = new int[1];
668            mNotifManager.enqueueNotificationWithTag(
669                    packageName, tag, 0x0, builder.getNotification(), idReceived);
670            mActiveNotifs.add(tag);
671        } catch (RemoteException e) {
672            Slog.w(TAG, "problem during enqueueNotification: " + e);
673        }
674    }
675
676    /**
677     * Show ongoing notification to reflect that {@link #mRestrictBackground}
678     * has been enabled.
679     */
680    private void enqueueRestrictedNotification(String tag) {
681        final Resources res = mContext.getResources();
682        final Notification.Builder builder = new Notification.Builder(mContext);
683
684        final CharSequence title = res.getText(R.string.data_usage_restricted_title);
685        final CharSequence body = res.getString(R.string.data_usage_restricted_body);
686
687        builder.setOnlyAlertOnce(true);
688        builder.setOngoing(true);
689        builder.setSmallIcon(R.drawable.ic_menu_info_details);
690        builder.setTicker(title);
691        builder.setContentTitle(title);
692        builder.setContentText(body);
693
694        final Intent intent = buildAllowBackgroundDataIntent();
695        builder.setContentIntent(
696                PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
697
698        // TODO: move to NotificationManager once we can mock it
699        try {
700            final String packageName = mContext.getPackageName();
701            final int[] idReceived = new int[1];
702            mNotifManager.enqueueNotificationWithTag(packageName, tag,
703                    0x0, builder.getNotification(), idReceived);
704            mActiveNotifs.add(tag);
705        } catch (RemoteException e) {
706            Slog.w(TAG, "problem during enqueueNotification: " + e);
707        }
708    }
709
710    private void cancelNotification(String tag) {
711        // TODO: move to NotificationManager once we can mock it
712        try {
713            final String packageName = mContext.getPackageName();
714            mNotifManager.cancelNotificationWithTag(
715                    packageName, tag, 0x0);
716        } catch (RemoteException e) {
717            Slog.w(TAG, "problem during enqueueNotification: " + e);
718        }
719    }
720
721    /**
722     * Receiver that watches for {@link IConnectivityManager} to claim network
723     * interfaces. Used to apply {@link NetworkPolicy} to matching networks.
724     */
725    private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
726        @Override
727        public void onReceive(Context context, Intent intent) {
728            // on background handler thread, and verified CONNECTIVITY_INTERNAL
729            // permission above.
730            synchronized (mRulesLock) {
731                ensureActiveMobilePolicyLocked();
732                updateNetworkEnabledLocked();
733                updateNetworkRulesLocked();
734                updateNotificationsLocked();
735            }
736        }
737    };
738
739    /**
740     * Proactively control network data connections when they exceed
741     * {@link NetworkPolicy#limitBytes}.
742     */
743    private void updateNetworkEnabledLocked() {
744        if (LOGV) Slog.v(TAG, "updateNetworkEnabledLocked()");
745
746        // TODO: reset any policy-disabled networks when any policy is removed
747        // completely, which is currently rare case.
748
749        final long currentTime = currentTimeMillis(true);
750        for (NetworkPolicy policy : mNetworkPolicy.values()) {
751            // shortcut when policy has no limit
752            if (policy.limitBytes == LIMIT_DISABLED) {
753                setNetworkTemplateEnabled(policy.template, true);
754                continue;
755            }
756
757            final long start = computeLastCycleBoundary(currentTime, policy);
758            final long end = currentTime;
759
760            final long totalBytes = getTotalBytes(policy.template, start, end);
761            if (totalBytes == UNKNOWN_BYTES) continue;
762
763            // disable data connection when over limit and not snoozed
764            final boolean overLimit = policy.limitBytes != LIMIT_DISABLED
765                    && totalBytes > policy.limitBytes && policy.lastSnooze < start;
766            setNetworkTemplateEnabled(policy.template, !overLimit);
767        }
768    }
769
770    /**
771     * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}
772     * for the given {@link NetworkTemplate}.
773     */
774    private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) {
775        if (LOGD) Slog.d(TAG, "setting template=" + template + " enabled=" + enabled);
776        switch (template.getMatchRule()) {
777            case MATCH_MOBILE_3G_LOWER:
778            case MATCH_MOBILE_4G:
779            case MATCH_MOBILE_ALL:
780                // TODO: offer more granular control over radio states once
781                // 4965893 is available.
782                if (Objects.equal(getActiveSubscriberId(), template.getSubscriberId())) {
783                    setPolicyDataEnable(TYPE_MOBILE, enabled);
784                    setPolicyDataEnable(TYPE_WIMAX, enabled);
785                }
786                break;
787            case MATCH_WIFI:
788                setPolicyDataEnable(TYPE_WIFI, enabled);
789                break;
790            case MATCH_ETHERNET:
791                setPolicyDataEnable(TYPE_ETHERNET, enabled);
792                break;
793            default:
794                throw new IllegalArgumentException("unexpected template");
795        }
796    }
797
798    /**
799     * Examine all connected {@link NetworkState}, looking for
800     * {@link NetworkPolicy} that need to be enforced. When matches found, set
801     * remaining quota based on usage cycle and historical stats.
802     */
803    private void updateNetworkRulesLocked() {
804        if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
805
806        final NetworkState[] states;
807        try {
808            states = mConnManager.getAllNetworkState();
809        } catch (RemoteException e) {
810            Slog.w(TAG, "problem reading network state");
811            return;
812        }
813
814        // first, derive identity for all connected networks, which can be used
815        // to match against templates.
816        final HashMap<NetworkIdentity, String> networks = Maps.newHashMap();
817        for (NetworkState state : states) {
818            // stash identity and iface away for later use
819            if (state.networkInfo.isConnected()) {
820                final String iface = state.linkProperties.getInterfaceName();
821                final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
822                networks.put(ident, iface);
823            }
824        }
825
826        // build list of rules and ifaces to enforce them against
827        mNetworkRules.clear();
828        final ArrayList<String> ifaceList = Lists.newArrayList();
829        for (NetworkPolicy policy : mNetworkPolicy.values()) {
830
831            // collect all active ifaces that match this template
832            ifaceList.clear();
833            for (NetworkIdentity ident : networks.keySet()) {
834                if (policy.template.matches(ident)) {
835                    final String iface = networks.get(ident);
836                    ifaceList.add(iface);
837                }
838            }
839
840            if (ifaceList.size() > 0) {
841                final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
842                mNetworkRules.put(policy, ifaces);
843            }
844        }
845
846        final HashSet<String> newMeteredIfaces = Sets.newHashSet();
847
848        // apply each policy that we found ifaces for; compute remaining data
849        // based on current cycle and historical stats, and push to kernel.
850        final long currentTime = currentTimeMillis(true);
851        for (NetworkPolicy policy : mNetworkRules.keySet()) {
852            final String[] ifaces = mNetworkRules.get(policy);
853
854            final long start = computeLastCycleBoundary(currentTime, policy);
855            final long end = currentTime;
856
857            final long totalBytes = getTotalBytes(policy.template, start, end);
858            if (totalBytes == UNKNOWN_BYTES) continue;
859
860            if (LOGD) {
861                Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
862                        + Arrays.toString(ifaces));
863            }
864
865            final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED;
866            if (hasLimit) {
867                final long quotaBytes;
868                if (policy.lastSnooze >= start) {
869                    // snoozing past quota, but we still need to restrict apps,
870                    // so push really high quota.
871                    quotaBytes = Long.MAX_VALUE;
872                } else {
873                    // remaining "quota" bytes are based on total usage in
874                    // current cycle. kernel doesn't like 0-byte rules, so we
875                    // set 1-byte quota and disable the radio later.
876                    quotaBytes = Math.max(1, policy.limitBytes - totalBytes);
877                }
878
879                if (ifaces.length > 1) {
880                    // TODO: switch to shared quota once NMS supports
881                    Slog.w(TAG, "shared quota unsupported; generating rule for each iface");
882                }
883
884                for (String iface : ifaces) {
885                    removeInterfaceQuota(iface);
886                    setInterfaceQuota(iface, quotaBytes);
887                    newMeteredIfaces.add(iface);
888                }
889            }
890        }
891
892        // remove quota on any trailing interfaces
893        for (String iface : mMeteredIfaces) {
894            if (!newMeteredIfaces.contains(iface)) {
895                removeInterfaceQuota(iface);
896            }
897        }
898        mMeteredIfaces = newMeteredIfaces;
899
900        final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
901        mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
902    }
903
904    /**
905     * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
906     * have at least a default mobile policy defined.
907     */
908    private void ensureActiveMobilePolicyLocked() {
909        if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()");
910        if (mSuppressDefaultPolicy) return;
911
912        final String subscriberId = getActiveSubscriberId();
913        final NetworkIdentity probeIdent = new NetworkIdentity(
914                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, false);
915
916        // examine to see if any policy is defined for active mobile
917        boolean mobileDefined = false;
918        for (NetworkPolicy policy : mNetworkPolicy.values()) {
919            if (policy.template.matches(probeIdent)) {
920                mobileDefined = true;
921            }
922        }
923
924        if (!mobileDefined) {
925            Slog.i(TAG, "no policy for active mobile network; generating default policy");
926
927            // build default mobile policy, and assume usage cycle starts today
928            final long warningBytes = mContext.getResources().getInteger(
929                    com.android.internal.R.integer.config_networkPolicyDefaultWarning)
930                    * MB_IN_BYTES;
931
932            final Time time = new Time(Time.TIMEZONE_UTC);
933            time.setToNow();
934            final int cycleDay = time.monthDay;
935
936            final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
937            mNetworkPolicy.put(template, new NetworkPolicy(
938                    template, cycleDay, warningBytes, LIMIT_DISABLED, SNOOZE_NEVER));
939            writePolicyLocked();
940        }
941    }
942
943    private void readPolicyLocked() {
944        if (LOGV) Slog.v(TAG, "readPolicyLocked()");
945
946        // clear any existing policy and read from disk
947        mNetworkPolicy.clear();
948        mUidPolicy.clear();
949
950        FileInputStream fis = null;
951        try {
952            fis = mPolicyFile.openRead();
953            final XmlPullParser in = Xml.newPullParser();
954            in.setInput(fis, null);
955
956            int type;
957            int version = VERSION_INIT;
958            while ((type = in.next()) != END_DOCUMENT) {
959                final String tag = in.getName();
960                if (type == START_TAG) {
961                    if (TAG_POLICY_LIST.equals(tag)) {
962                        version = readIntAttribute(in, ATTR_VERSION);
963                        if (version >= VERSION_ADDED_RESTRICT_BACKGROUND) {
964                            mRestrictBackground = readBooleanAttribute(
965                                    in, ATTR_RESTRICT_BACKGROUND);
966                        } else {
967                            mRestrictBackground = false;
968                        }
969
970                    } else if (TAG_NETWORK_POLICY.equals(tag)) {
971                        final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
972                        final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID);
973                        final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
974                        final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
975                        final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
976                        final long lastSnooze;
977                        if (version >= VERSION_ADDED_SNOOZE) {
978                            lastSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
979                        } else {
980                            lastSnooze = SNOOZE_NEVER;
981                        }
982
983                        final NetworkTemplate template = new NetworkTemplate(
984                                networkTemplate, subscriberId);
985                        mNetworkPolicy.put(template, new NetworkPolicy(
986                                template, cycleDay, warningBytes, limitBytes, lastSnooze));
987
988                    } else if (TAG_UID_POLICY.equals(tag)) {
989                        final int uid = readIntAttribute(in, ATTR_UID);
990                        final int policy = readIntAttribute(in, ATTR_POLICY);
991
992                        if (isUidValidForPolicy(mContext, uid)) {
993                            setUidPolicyUnchecked(uid, policy, false);
994                        } else {
995                            Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
996                        }
997                    }
998                }
999            }
1000
1001        } catch (FileNotFoundException e) {
1002            // missing policy is okay, probably first boot
1003            upgradeLegacyBackgroundData();
1004        } catch (IOException e) {
1005            Slog.e(TAG, "problem reading network stats", e);
1006        } catch (XmlPullParserException e) {
1007            Slog.e(TAG, "problem reading network stats", e);
1008        } finally {
1009            IoUtils.closeQuietly(fis);
1010        }
1011    }
1012
1013    /**
1014     * Upgrade legacy background data flags, notifying listeners of one last
1015     * change to always-true.
1016     */
1017    private void upgradeLegacyBackgroundData() {
1018        mRestrictBackground = Settings.Secure.getInt(
1019                mContext.getContentResolver(), Settings.Secure.BACKGROUND_DATA, 1) != 1;
1020
1021        // kick off one last broadcast if restricted
1022        if (mRestrictBackground) {
1023            final Intent broadcast = new Intent(
1024                    ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
1025            mContext.sendBroadcast(broadcast);
1026        }
1027    }
1028
1029    private void writePolicyLocked() {
1030        if (LOGV) Slog.v(TAG, "writePolicyLocked()");
1031
1032        FileOutputStream fos = null;
1033        try {
1034            fos = mPolicyFile.startWrite();
1035
1036            XmlSerializer out = new FastXmlSerializer();
1037            out.setOutput(fos, "utf-8");
1038            out.startDocument(null, true);
1039
1040            out.startTag(null, TAG_POLICY_LIST);
1041            writeIntAttribute(out, ATTR_VERSION, VERSION_ADDED_RESTRICT_BACKGROUND);
1042            writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
1043
1044            // write all known network policies
1045            for (NetworkPolicy policy : mNetworkPolicy.values()) {
1046                final NetworkTemplate template = policy.template;
1047
1048                out.startTag(null, TAG_NETWORK_POLICY);
1049                writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule());
1050                final String subscriberId = template.getSubscriberId();
1051                if (subscriberId != null) {
1052                    out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId);
1053                }
1054                writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
1055                writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
1056                writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
1057                writeLongAttribute(out, ATTR_LAST_SNOOZE, policy.lastSnooze);
1058                out.endTag(null, TAG_NETWORK_POLICY);
1059            }
1060
1061            // write all known uid policies
1062            for (int i = 0; i < mUidPolicy.size(); i++) {
1063                final int uid = mUidPolicy.keyAt(i);
1064                final int policy = mUidPolicy.valueAt(i);
1065
1066                // skip writing empty policies
1067                if (policy == POLICY_NONE) continue;
1068
1069                out.startTag(null, TAG_UID_POLICY);
1070                writeIntAttribute(out, ATTR_UID, uid);
1071                writeIntAttribute(out, ATTR_POLICY, policy);
1072                out.endTag(null, TAG_UID_POLICY);
1073            }
1074
1075            out.endTag(null, TAG_POLICY_LIST);
1076            out.endDocument();
1077
1078            mPolicyFile.finishWrite(fos);
1079        } catch (IOException e) {
1080            if (fos != null) {
1081                mPolicyFile.failWrite(fos);
1082            }
1083        }
1084    }
1085
1086    @Override
1087    public void setUidPolicy(int uid, int policy) {
1088        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1089
1090        if (!isUidValidForPolicy(mContext, uid)) {
1091            throw new IllegalArgumentException("cannot apply policy to UID " + uid);
1092        }
1093
1094        setUidPolicyUnchecked(uid, policy, true);
1095    }
1096
1097    private void setUidPolicyUnchecked(int uid, int policy, boolean persist) {
1098        final int oldPolicy;
1099        synchronized (mRulesLock) {
1100            oldPolicy = getUidPolicy(uid);
1101            mUidPolicy.put(uid, policy);
1102
1103            // uid policy changed, recompute rules and persist policy.
1104            updateRulesForUidLocked(uid);
1105            if (persist) {
1106                writePolicyLocked();
1107            }
1108        }
1109    }
1110
1111    @Override
1112    public int getUidPolicy(int uid) {
1113        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1114
1115        synchronized (mRulesLock) {
1116            return mUidPolicy.get(uid, POLICY_NONE);
1117        }
1118    }
1119
1120    @Override
1121    public void registerListener(INetworkPolicyListener listener) {
1122        // TODO: create permission for observing network policy
1123        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1124
1125        mListeners.register(listener);
1126
1127        // TODO: consider dispatching existing rules to new listeners
1128    }
1129
1130    @Override
1131    public void unregisterListener(INetworkPolicyListener listener) {
1132        // TODO: create permission for observing network policy
1133        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1134
1135        mListeners.unregister(listener);
1136    }
1137
1138    @Override
1139    public void setNetworkPolicies(NetworkPolicy[] policies) {
1140        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1141
1142        synchronized (mRulesLock) {
1143            mNetworkPolicy.clear();
1144            for (NetworkPolicy policy : policies) {
1145                mNetworkPolicy.put(policy.template, policy);
1146            }
1147
1148            updateNetworkEnabledLocked();
1149            updateNetworkRulesLocked();
1150            updateNotificationsLocked();
1151            writePolicyLocked();
1152        }
1153    }
1154
1155    @Override
1156    public NetworkPolicy[] getNetworkPolicies() {
1157        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1158        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
1159
1160        synchronized (mRulesLock) {
1161            return mNetworkPolicy.values().toArray(new NetworkPolicy[mNetworkPolicy.size()]);
1162        }
1163    }
1164
1165    @Override
1166    public void snoozePolicy(NetworkTemplate template) {
1167        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1168
1169        final long currentTime = currentTimeMillis(true);
1170        synchronized (mRulesLock) {
1171            // find and snooze local policy that matches
1172            final NetworkPolicy policy = mNetworkPolicy.get(template);
1173            if (policy == null) {
1174                throw new IllegalArgumentException("unable to find policy for " + template);
1175            }
1176
1177            policy.lastSnooze = currentTime;
1178
1179            updateNetworkEnabledLocked();
1180            updateNetworkRulesLocked();
1181            updateNotificationsLocked();
1182            writePolicyLocked();
1183        }
1184    }
1185
1186    @Override
1187    public void setRestrictBackground(boolean restrictBackground) {
1188        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1189
1190        synchronized (mRulesLock) {
1191            mRestrictBackground = restrictBackground;
1192            updateRulesForRestrictBackgroundLocked();
1193            updateNotificationsLocked();
1194            writePolicyLocked();
1195        }
1196    }
1197
1198    @Override
1199    public boolean getRestrictBackground() {
1200        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1201
1202        synchronized (mRulesLock) {
1203            return mRestrictBackground;
1204        }
1205    }
1206
1207    private NetworkPolicy findPolicyForNetworkLocked(NetworkIdentity ident) {
1208        for (NetworkPolicy policy : mNetworkPolicy.values()) {
1209            if (policy.template.matches(ident)) {
1210                return policy;
1211            }
1212        }
1213        return null;
1214    }
1215
1216    @Override
1217    public NetworkQuotaInfo getNetworkQuotaInfo(NetworkState state) {
1218        mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
1219
1220        // only returns usage summary, so we don't require caller to have
1221        // READ_NETWORK_USAGE_HISTORY.
1222        final long token = Binder.clearCallingIdentity();
1223        try {
1224            return getNetworkQuotaInfoUnchecked(state);
1225        } finally {
1226            Binder.restoreCallingIdentity(token);
1227        }
1228    }
1229
1230    private NetworkQuotaInfo getNetworkQuotaInfoUnchecked(NetworkState state) {
1231        final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
1232
1233        final NetworkPolicy policy;
1234        synchronized (mRulesLock) {
1235            policy = findPolicyForNetworkLocked(ident);
1236        }
1237
1238        if (policy == null) {
1239            // missing policy means we can't derive useful quota info
1240            return null;
1241        }
1242
1243        final long currentTime = currentTimeMillis(false);
1244
1245        final long start = computeLastCycleBoundary(currentTime, policy);
1246        final long end = currentTime;
1247
1248        // find total bytes used under policy
1249        final long totalBytes = getTotalBytes(policy.template, start, end);
1250        if (totalBytes == UNKNOWN_BYTES) return null;
1251
1252        // report soft and hard limits under policy
1253        final long softLimitBytes = policy.warningBytes != WARNING_DISABLED ? policy.warningBytes
1254                : NetworkQuotaInfo.NO_LIMIT;
1255        final long hardLimitBytes = policy.limitBytes != LIMIT_DISABLED ? policy.limitBytes
1256                : NetworkQuotaInfo.NO_LIMIT;
1257
1258        return new NetworkQuotaInfo(totalBytes, softLimitBytes, hardLimitBytes);
1259    }
1260
1261    @Override
1262    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
1263        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1264
1265        final HashSet<String> argSet = new HashSet<String>();
1266        for (String arg : args) {
1267            argSet.add(arg);
1268        }
1269
1270        synchronized (mRulesLock) {
1271            if (argSet.contains("unsnooze")) {
1272                for (NetworkPolicy policy : mNetworkPolicy.values()) {
1273                    policy.lastSnooze = SNOOZE_NEVER;
1274                }
1275                writePolicyLocked();
1276                fout.println("Wiped snooze timestamps");
1277                return;
1278            }
1279
1280            fout.print("Restrict background: "); fout.println(mRestrictBackground);
1281            fout.println("Network policies:");
1282            for (NetworkPolicy policy : mNetworkPolicy.values()) {
1283                fout.print("  "); fout.println(policy.toString());
1284            }
1285
1286            fout.println("Policy status for known UIDs:");
1287
1288            final SparseBooleanArray knownUids = new SparseBooleanArray();
1289            collectKeys(mUidPolicy, knownUids);
1290            collectKeys(mUidForeground, knownUids);
1291            collectKeys(mUidRules, knownUids);
1292
1293            final int size = knownUids.size();
1294            for (int i = 0; i < size; i++) {
1295                final int uid = knownUids.keyAt(i);
1296                fout.print("  UID=");
1297                fout.print(uid);
1298
1299                fout.print(" policy=");
1300                final int policyIndex = mUidPolicy.indexOfKey(uid);
1301                if (policyIndex < 0) {
1302                    fout.print("UNKNOWN");
1303                } else {
1304                    dumpPolicy(fout, mUidPolicy.valueAt(policyIndex));
1305                }
1306
1307                fout.print(" foreground=");
1308                final int foregroundIndex = mUidPidForeground.indexOfKey(uid);
1309                if (foregroundIndex < 0) {
1310                    fout.print("UNKNOWN");
1311                } else {
1312                    dumpSparseBooleanArray(fout, mUidPidForeground.valueAt(foregroundIndex));
1313                }
1314
1315                fout.print(" rules=");
1316                final int rulesIndex = mUidRules.indexOfKey(uid);
1317                if (rulesIndex < 0) {
1318                    fout.print("UNKNOWN");
1319                } else {
1320                    dumpRules(fout, mUidRules.valueAt(rulesIndex));
1321                }
1322
1323                fout.println();
1324            }
1325        }
1326    }
1327
1328    @Override
1329    public boolean isUidForeground(int uid) {
1330        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1331
1332        synchronized (mRulesLock) {
1333            // only really in foreground when screen is also on
1334            return mUidForeground.get(uid, false) && mScreenOn;
1335        }
1336    }
1337
1338    /**
1339     * Foreground for PID changed; recompute foreground at UID level. If
1340     * changed, will trigger {@link #updateRulesForUidLocked(int)}.
1341     */
1342    private void computeUidForegroundLocked(int uid) {
1343        final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
1344
1345        // current pid is dropping foreground; examine other pids
1346        boolean uidForeground = false;
1347        final int size = pidForeground.size();
1348        for (int i = 0; i < size; i++) {
1349            if (pidForeground.valueAt(i)) {
1350                uidForeground = true;
1351                break;
1352            }
1353        }
1354
1355        final boolean oldUidForeground = mUidForeground.get(uid, false);
1356        if (oldUidForeground != uidForeground) {
1357            // foreground changed, push updated rules
1358            mUidForeground.put(uid, uidForeground);
1359            updateRulesForUidLocked(uid);
1360        }
1361    }
1362
1363    private void updateScreenOn() {
1364        synchronized (mRulesLock) {
1365            try {
1366                mScreenOn = mPowerManager.isScreenOn();
1367            } catch (RemoteException e) {
1368            }
1369            updateRulesForScreenLocked();
1370        }
1371    }
1372
1373    /**
1374     * Update rules that might be changed by {@link #mScreenOn} value.
1375     */
1376    private void updateRulesForScreenLocked() {
1377        // only update rules for anyone with foreground activities
1378        final int size = mUidForeground.size();
1379        for (int i = 0; i < size; i++) {
1380            if (mUidForeground.valueAt(i)) {
1381                final int uid = mUidForeground.keyAt(i);
1382                updateRulesForUidLocked(uid);
1383            }
1384        }
1385    }
1386
1387    /**
1388     * Update rules that might be changed by {@link #mRestrictBackground} value.
1389     */
1390    private void updateRulesForRestrictBackgroundLocked() {
1391        // update rules for all installed applications
1392        final PackageManager pm = mContext.getPackageManager();
1393        final List<ApplicationInfo> apps = pm.getInstalledApplications(0);
1394        for (ApplicationInfo app : apps) {
1395            updateRulesForUidLocked(app.uid);
1396        }
1397
1398        // and catch system UIDs
1399        // TODO: keep in sync with android_filesystem_config.h
1400        for (int uid = 1000; uid <= 1025; uid++) {
1401            updateRulesForUidLocked(uid);
1402        }
1403        for (int uid = 2000; uid <= 2002; uid++) {
1404            updateRulesForUidLocked(uid);
1405        }
1406        for (int uid = 3000; uid <= 3007; uid++) {
1407            updateRulesForUidLocked(uid);
1408        }
1409        for (int uid = 9998; uid <= 9999; uid++) {
1410            updateRulesForUidLocked(uid);
1411        }
1412    }
1413
1414    private void updateRulesForUidLocked(int uid) {
1415        final int uidPolicy = getUidPolicy(uid);
1416        final boolean uidForeground = isUidForeground(uid);
1417
1418        // derive active rules based on policy and active state
1419        int uidRules = RULE_ALLOW_ALL;
1420        if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
1421            // uid in background, and policy says to block metered data
1422            uidRules = RULE_REJECT_METERED;
1423        }
1424        if (!uidForeground && mRestrictBackground) {
1425            // uid in background, and global background disabled
1426            uidRules = RULE_REJECT_METERED;
1427        }
1428
1429        // TODO: only dispatch when rules actually change
1430
1431        if (uidRules == RULE_ALLOW_ALL) {
1432            mUidRules.delete(uid);
1433        } else {
1434            mUidRules.put(uid, uidRules);
1435        }
1436
1437        final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
1438        setUidNetworkRules(uid, rejectMetered);
1439
1440        // dispatch changed rule to existing listeners
1441        mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
1442
1443        try {
1444            // adjust stats accounting based on foreground status
1445            mNetworkStats.setUidForeground(uid, uidForeground);
1446        } catch (RemoteException e) {
1447            Slog.w(TAG, "problem dispatching foreground change");
1448        }
1449    }
1450
1451    private Handler.Callback mHandlerCallback = new Handler.Callback() {
1452        /** {@inheritDoc} */
1453        public boolean handleMessage(Message msg) {
1454            switch (msg.what) {
1455                case MSG_RULES_CHANGED: {
1456                    final int uid = msg.arg1;
1457                    final int uidRules = msg.arg2;
1458                    final int length = mListeners.beginBroadcast();
1459                    for (int i = 0; i < length; i++) {
1460                        final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
1461                        if (listener != null) {
1462                            try {
1463                                listener.onUidRulesChanged(uid, uidRules);
1464                            } catch (RemoteException e) {
1465                            }
1466                        }
1467                    }
1468                    mListeners.finishBroadcast();
1469                    return true;
1470                }
1471                case MSG_METERED_IFACES_CHANGED: {
1472                    final String[] meteredIfaces = (String[]) msg.obj;
1473                    final int length = mListeners.beginBroadcast();
1474                    for (int i = 0; i < length; i++) {
1475                        final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
1476                        if (listener != null) {
1477                            try {
1478                                listener.onMeteredIfacesChanged(meteredIfaces);
1479                            } catch (RemoteException e) {
1480                            }
1481                        }
1482                    }
1483                    mListeners.finishBroadcast();
1484                    return true;
1485                }
1486                default: {
1487                    return false;
1488                }
1489            }
1490        }
1491    };
1492
1493    private void setInterfaceQuota(String iface, long quotaBytes) {
1494        try {
1495            mNetworkManager.setInterfaceQuota(iface, quotaBytes);
1496        } catch (IllegalStateException e) {
1497            Slog.e(TAG, "problem setting interface quota", e);
1498        } catch (RemoteException e) {
1499            Slog.e(TAG, "problem setting interface quota", e);
1500        }
1501    }
1502
1503    private void removeInterfaceQuota(String iface) {
1504        try {
1505            mNetworkManager.removeInterfaceQuota(iface);
1506        } catch (IllegalStateException e) {
1507            Slog.e(TAG, "problem removing interface quota", e);
1508        } catch (RemoteException e) {
1509            Slog.e(TAG, "problem removing interface quota", e);
1510        }
1511    }
1512
1513    private void setInterfaceAlert(String iface, long alertBytes) {
1514        try {
1515            mNetworkManager.setInterfaceAlert(iface, alertBytes);
1516        } catch (IllegalStateException e) {
1517            Slog.e(TAG, "problem setting interface alert", e);
1518        } catch (RemoteException e) {
1519            Slog.e(TAG, "problem setting interface alert", e);
1520        }
1521    }
1522
1523    private void removeInterfaceAlert(String iface) {
1524        try {
1525            mNetworkManager.removeInterfaceAlert(iface);
1526        } catch (IllegalStateException e) {
1527            Slog.e(TAG, "problem removing interface alert", e);
1528        } catch (RemoteException e) {
1529            Slog.e(TAG, "problem removing interface alert", e);
1530        }
1531    }
1532
1533    private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1534        try {
1535            mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
1536        } catch (IllegalStateException e) {
1537            Slog.e(TAG, "problem setting uid rules", e);
1538        } catch (RemoteException e) {
1539            Slog.e(TAG, "problem setting uid rules", e);
1540        }
1541    }
1542
1543    /**
1544     * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)},
1545     * dispatching only when actually changed.
1546     */
1547    private void setPolicyDataEnable(int networkType, boolean enabled) {
1548        synchronized (mActiveNetworkEnabled) {
1549            final boolean prevEnabled = mActiveNetworkEnabled.get(networkType, true);
1550            if (prevEnabled == enabled) return;
1551
1552            try {
1553                mConnManager.setPolicyDataEnable(networkType, enabled);
1554            } catch (RemoteException e) {
1555                Slog.e(TAG, "problem setting network enabled", e);
1556            }
1557
1558            mActiveNetworkEnabled.put(networkType, enabled);
1559        }
1560    }
1561
1562    private String getActiveSubscriberId() {
1563        final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
1564                Context.TELEPHONY_SERVICE);
1565        return telephony.getSubscriberId();
1566    }
1567
1568    private static final long UNKNOWN_BYTES = -1;
1569
1570    private long getTotalBytes(NetworkTemplate template, long start, long end) {
1571        try {
1572            final NetworkStats stats = mNetworkStats.getSummaryForNetwork(
1573                    template, start, end);
1574            final NetworkStats.Entry entry = stats.getValues(0, null);
1575            return entry.rxBytes + entry.txBytes;
1576        } catch (RemoteException e) {
1577            Slog.w(TAG, "problem reading summary for template " + template);
1578            return UNKNOWN_BYTES;
1579        }
1580    }
1581
1582    private long currentTimeMillis(boolean allowRefresh) {
1583        // try refreshing time source when stale
1584        if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE && allowRefresh) {
1585            mTime.forceRefresh();
1586        }
1587
1588        return mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
1589    }
1590
1591    private static Intent buildAllowBackgroundDataIntent() {
1592        return new Intent(ACTION_ALLOW_BACKGROUND);
1593    }
1594
1595    private static Intent buildNetworkOverLimitIntent(NetworkTemplate template) {
1596        final Intent intent = new Intent();
1597        intent.setComponent(new ComponentName(
1598                "com.android.systemui", "com.android.systemui.net.NetworkOverLimitActivity"));
1599        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1600        intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
1601        return intent;
1602    }
1603
1604    private static Intent buildViewDataUsageIntent(NetworkTemplate template) {
1605        final Intent intent = new Intent();
1606        intent.setComponent(new ComponentName(
1607                "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
1608        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1609        intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
1610        return intent;
1611    }
1612
1613    private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
1614        final int size = source.size();
1615        for (int i = 0; i < size; i++) {
1616            target.put(source.keyAt(i), true);
1617        }
1618    }
1619
1620    private static void collectKeys(SparseBooleanArray source, SparseBooleanArray target) {
1621        final int size = source.size();
1622        for (int i = 0; i < size; i++) {
1623            target.put(source.keyAt(i), true);
1624        }
1625    }
1626
1627    private static void dumpSparseBooleanArray(PrintWriter fout, SparseBooleanArray value) {
1628        fout.print("[");
1629        final int size = value.size();
1630        for (int i = 0; i < size; i++) {
1631            fout.print(value.keyAt(i) + "=" + value.valueAt(i));
1632            if (i < size - 1) fout.print(",");
1633        }
1634        fout.print("]");
1635    }
1636
1637    public static class XmlUtils {
1638        public static int readIntAttribute(XmlPullParser in, String name) throws IOException {
1639            final String value = in.getAttributeValue(null, name);
1640            try {
1641                return Integer.parseInt(value);
1642            } catch (NumberFormatException e) {
1643                throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
1644            }
1645        }
1646
1647        public static void writeIntAttribute(XmlSerializer out, String name, int value)
1648                throws IOException {
1649            out.attribute(null, name, Integer.toString(value));
1650        }
1651
1652        public static long readLongAttribute(XmlPullParser in, String name) throws IOException {
1653            final String value = in.getAttributeValue(null, name);
1654            try {
1655                return Long.parseLong(value);
1656            } catch (NumberFormatException e) {
1657                throw new ProtocolException("problem parsing " + name + "=" + value + " as long");
1658            }
1659        }
1660
1661        public static void writeLongAttribute(XmlSerializer out, String name, long value)
1662                throws IOException {
1663            out.attribute(null, name, Long.toString(value));
1664        }
1665
1666        public static boolean readBooleanAttribute(XmlPullParser in, String name) {
1667            final String value = in.getAttributeValue(null, name);
1668            return Boolean.parseBoolean(value);
1669        }
1670
1671        public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value)
1672                throws IOException {
1673            out.attribute(null, name, Boolean.toString(value));
1674        }
1675    }
1676}
1677