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