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