NetworkPolicyManagerService.java revision 1b5a2a96f793211bfbd39aa29cc41031dfa23950
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.net.ConnectivityManager.CONNECTIVITY_ACTION;
26import static android.net.ConnectivityManager.TYPE_MOBILE;
27import static android.net.NetworkPolicy.LIMIT_DISABLED;
28import static android.net.NetworkPolicy.WARNING_DISABLED;
29import static android.net.NetworkPolicyManager.ACTION_DATA_USAGE_LIMIT;
30import static android.net.NetworkPolicyManager.ACTION_DATA_USAGE_WARNING;
31import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
32import static android.net.NetworkPolicyManager.POLICY_NONE;
33import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
34import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
35import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
36import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
37import static android.net.NetworkPolicyManager.dumpPolicy;
38import static android.net.NetworkPolicyManager.dumpRules;
39import static android.net.NetworkPolicyManager.isUidValidForPolicy;
40import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
41import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
42import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
43import static android.text.format.DateUtils.DAY_IN_MILLIS;
44import static com.android.internal.util.Preconditions.checkNotNull;
45import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
46import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
47import static org.xmlpull.v1.XmlPullParser.START_TAG;
48
49import android.app.IActivityManager;
50import android.app.INotificationManager;
51import android.app.IProcessObserver;
52import android.app.Notification;
53import android.app.PendingIntent;
54import android.content.BroadcastReceiver;
55import android.content.Context;
56import android.content.Intent;
57import android.content.IntentFilter;
58import android.content.res.Resources;
59import android.net.ConnectivityManager;
60import android.net.IConnectivityManager;
61import android.net.INetworkPolicyListener;
62import android.net.INetworkPolicyManager;
63import android.net.INetworkStatsService;
64import android.net.NetworkIdentity;
65import android.net.NetworkPolicy;
66import android.net.NetworkState;
67import android.net.NetworkStats;
68import android.net.NetworkTemplate;
69import android.os.Environment;
70import android.os.Handler;
71import android.os.HandlerThread;
72import android.os.IPowerManager;
73import android.os.RemoteCallbackList;
74import android.os.RemoteException;
75import android.telephony.TelephonyManager;
76import android.text.format.Formatter;
77import android.text.format.Time;
78import android.util.NtpTrustedTime;
79import android.util.Slog;
80import android.util.SparseArray;
81import android.util.SparseBooleanArray;
82import android.util.SparseIntArray;
83import android.util.TrustedTime;
84import android.util.Xml;
85
86import com.android.internal.R;
87import com.android.internal.os.AtomicFile;
88import com.android.internal.util.FastXmlSerializer;
89import com.google.android.collect.Lists;
90import com.google.android.collect.Maps;
91import com.google.android.collect.Sets;
92
93import org.xmlpull.v1.XmlPullParser;
94import org.xmlpull.v1.XmlPullParserException;
95import org.xmlpull.v1.XmlSerializer;
96
97import java.io.File;
98import java.io.FileDescriptor;
99import java.io.FileInputStream;
100import java.io.FileNotFoundException;
101import java.io.FileOutputStream;
102import java.io.IOException;
103import java.io.PrintWriter;
104import java.net.ProtocolException;
105import java.util.ArrayList;
106import java.util.Arrays;
107import java.util.HashMap;
108import java.util.HashSet;
109
110import libcore.io.IoUtils;
111
112/**
113 * Service that maintains low-level network policy rules and collects usage
114 * statistics to drive those rules.
115 * <p>
116 * Derives active rules by combining a given policy with other system status,
117 * and delivers to listeners, such as {@link ConnectivityManager}, for
118 * enforcement.
119 */
120public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
121    private static final String TAG = "NetworkPolicy";
122    private static final boolean LOGD = true;
123    private static final boolean LOGV = false;
124
125    private static final int VERSION_CURRENT = 1;
126
127    private static final long KB_IN_BYTES = 1024;
128    private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
129    private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
130
131    private static final int TYPE_WARNING = 0x1;
132    private static final int TYPE_LIMIT = 0x2;
133
134    private static final String TAG_POLICY_LIST = "policy-list";
135    private static final String TAG_NETWORK_POLICY = "network-policy";
136    private static final String TAG_UID_POLICY = "uid-policy";
137
138    private static final String ATTR_VERSION = "version";
139    private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate";
140    private static final String ATTR_SUBSCRIBER_ID = "subscriberId";
141    private static final String ATTR_CYCLE_DAY = "cycleDay";
142    private static final String ATTR_WARNING_BYTES = "warningBytes";
143    private static final String ATTR_LIMIT_BYTES = "limitBytes";
144    private static final String ATTR_UID = "uid";
145    private static final String ATTR_POLICY = "policy";
146
147    private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
148
149    private final Context mContext;
150    private final IActivityManager mActivityManager;
151    private final IPowerManager mPowerManager;
152    private final INetworkStatsService mNetworkStats;
153    private final TrustedTime mTime;
154
155    private IConnectivityManager mConnManager;
156    private INotificationManager mNotifManager;
157
158    private final Object mRulesLock = new Object();
159
160    private boolean mScreenOn;
161
162    /** Current policy for network templates. */
163    private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
164
165    /** Current policy for each UID. */
166    private SparseIntArray mUidPolicy = new SparseIntArray();
167    /** Current derived network rules for each UID. */
168    private SparseIntArray mUidRules = new SparseIntArray();
169
170    /** Set of ifaces that are metered. */
171    private HashSet<String> mMeteredIfaces = Sets.newHashSet();
172
173    /** Foreground at both UID and PID granularity. */
174    private SparseBooleanArray mUidForeground = new SparseBooleanArray();
175    private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
176            SparseBooleanArray>();
177
178    private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
179            INetworkPolicyListener>();
180
181    private final HandlerThread mHandlerThread;
182    private final Handler mHandler;
183
184    private final AtomicFile mPolicyFile;
185
186    // TODO: keep whitelist of system-critical services that should never have
187    // rules enforced, such as system, phone, and radio UIDs.
188
189    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
190            IPowerManager powerManager, INetworkStatsService networkStats) {
191        // TODO: move to using cached NtpTrustedTime
192        this(context, activityManager, powerManager, networkStats, new NtpTrustedTime(),
193                getSystemDir());
194    }
195
196    private static File getSystemDir() {
197        return new File(Environment.getDataDirectory(), "system");
198    }
199
200    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
201            IPowerManager powerManager, INetworkStatsService networkStats, TrustedTime time,
202            File systemDir) {
203        mContext = checkNotNull(context, "missing context");
204        mActivityManager = checkNotNull(activityManager, "missing activityManager");
205        mPowerManager = checkNotNull(powerManager, "missing powerManager");
206        mNetworkStats = checkNotNull(networkStats, "missing networkStats");
207        mTime = checkNotNull(time, "missing TrustedTime");
208
209        mHandlerThread = new HandlerThread(TAG);
210        mHandlerThread.start();
211        mHandler = new Handler(mHandlerThread.getLooper());
212
213        mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
214    }
215
216    public void bindConnectivityManager(IConnectivityManager connManager) {
217        mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
218    }
219
220    public void bindNotificationManager(INotificationManager notifManager) {
221        mNotifManager = checkNotNull(notifManager, "missing INotificationManager");
222    }
223
224    public void systemReady() {
225        synchronized (mRulesLock) {
226            // read policy from disk
227            readPolicyLocked();
228            updateNotificationsLocked();
229        }
230
231        updateScreenOn();
232
233        try {
234            mActivityManager.registerProcessObserver(mProcessObserver);
235        } catch (RemoteException e) {
236            // ouch, no foregroundActivities updates means some processes may
237            // never get network access.
238            Slog.e(TAG, "unable to register IProcessObserver", e);
239        }
240
241        // TODO: traverse existing processes to know foreground state, or have
242        // activitymanager dispatch current state when new observer attached.
243
244        final IntentFilter screenFilter = new IntentFilter();
245        screenFilter.addAction(Intent.ACTION_SCREEN_ON);
246        screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
247        mContext.registerReceiver(mScreenReceiver, screenFilter);
248
249        // watch for network interfaces to be claimed
250        final IntentFilter ifaceFilter = new IntentFilter();
251        ifaceFilter.addAction(CONNECTIVITY_ACTION);
252        mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler);
253
254        // listen for warning polling events; currently dispatched by
255        final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
256        mContext.registerReceiver(
257                mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
258
259    }
260
261    private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
262        @Override
263        public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
264            // only someone like AMS should only be calling us
265            mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
266
267            // skip when UID couldn't have any policy
268            if (!isUidValidForPolicy(mContext, uid)) return;
269
270            synchronized (mRulesLock) {
271                // because a uid can have multiple pids running inside, we need to
272                // remember all pid states and summarize foreground at uid level.
273
274                // record foreground for this specific pid
275                SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
276                if (pidForeground == null) {
277                    pidForeground = new SparseBooleanArray(2);
278                    mUidPidForeground.put(uid, pidForeground);
279                }
280                pidForeground.put(pid, foregroundActivities);
281                computeUidForegroundLocked(uid);
282            }
283        }
284
285        @Override
286        public void onProcessDied(int pid, int uid) {
287            // only someone like AMS should only be calling us
288            mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
289
290            // skip when UID couldn't have any policy
291            if (!isUidValidForPolicy(mContext, uid)) return;
292
293            synchronized (mRulesLock) {
294                // clear records and recompute, when they exist
295                final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
296                if (pidForeground != null) {
297                    pidForeground.delete(pid);
298                    computeUidForegroundLocked(uid);
299                }
300            }
301        }
302    };
303
304    private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
305        @Override
306        public void onReceive(Context context, Intent intent) {
307            synchronized (mRulesLock) {
308                // screen-related broadcasts are protected by system, no need
309                // for permissions check.
310                updateScreenOn();
311            }
312        }
313    };
314
315    /**
316     * Receiver that watches for {@link INetworkStatsService} updates, which we
317     * use to check against {@link NetworkPolicy#warningBytes}.
318     */
319    private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() {
320        @Override
321        public void onReceive(Context context, Intent intent) {
322            // on background handler thread, and verified
323            // READ_NETWORK_USAGE_HISTORY permission above.
324
325            synchronized (mRulesLock) {
326                updateNotificationsLocked();
327            }
328        }
329    };
330
331    /**
332     * Check {@link NetworkPolicy} against current {@link INetworkStatsService}
333     * to show visible notifications as needed.
334     */
335    private void updateNotificationsLocked() {
336        if (LOGV) Slog.v(TAG, "updateNotificationsLocked()");
337
338        // try refreshing time source when stale
339        if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
340            mTime.forceRefresh();
341        }
342
343        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
344                : System.currentTimeMillis();
345
346        // TODO: when switching to kernel notifications, compute next future
347        // cycle boundary to recompute notifications.
348
349        // examine stats for each policy defined
350        for (NetworkPolicy policy : mNetworkPolicy) {
351            final long start = computeLastCycleBoundary(currentTime, policy);
352            final long end = currentTime;
353
354            final long total;
355            try {
356                final NetworkStats stats = mNetworkStats.getSummaryForNetwork(
357                        policy.template, start, end);
358                total = stats.rx[0] + stats.tx[0];
359            } catch (RemoteException e) {
360                Slog.w(TAG, "problem reading summary for template " + policy.template);
361                continue;
362            }
363
364            if (policy.limitBytes != LIMIT_DISABLED && total >= policy.limitBytes) {
365                cancelNotification(policy, TYPE_WARNING);
366                enqueueNotification(policy, TYPE_LIMIT);
367            } else {
368                cancelNotification(policy, TYPE_LIMIT);
369
370                if (policy.warningBytes != WARNING_DISABLED && total >= policy.warningBytes) {
371                    enqueueNotification(policy, TYPE_WARNING);
372                } else {
373                    cancelNotification(policy, TYPE_WARNING);
374                }
375            }
376        }
377    }
378
379    /**
380     * Build unique tag that identifies an active {@link NetworkPolicy}
381     * notification of a specific type, like {@link #TYPE_LIMIT}.
382     */
383    private String buildNotificationTag(NetworkPolicy policy, int type) {
384        return TAG + ":" + policy.template.hashCode() + ":" + type;
385    }
386
387    /**
388     * Show notification for combined {@link NetworkPolicy} and specific type,
389     * like {@link #TYPE_LIMIT}. Okay to call multiple times.
390     */
391    private void enqueueNotification(NetworkPolicy policy, int type) {
392        final String tag = buildNotificationTag(policy, type);
393        final Notification.Builder builder = new Notification.Builder(mContext);
394        builder.setOnlyAlertOnce(true);
395        builder.setOngoing(true);
396
397        final Resources res = mContext.getResources();
398        switch (type) {
399            case TYPE_WARNING: {
400                final String title = res.getString(R.string.data_usage_warning_title);
401                final String body = res.getString(R.string.data_usage_warning_body,
402                        Formatter.formatFileSize(mContext, policy.warningBytes));
403
404                builder.setSmallIcon(R.drawable.ic_menu_info_details);
405                builder.setTicker(title);
406                builder.setContentTitle(title);
407                builder.setContentText(body);
408
409                final Intent intent = new Intent(ACTION_DATA_USAGE_WARNING);
410                intent.addCategory(Intent.CATEGORY_DEFAULT);
411                intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.template.getMatchRule());
412                builder.setContentIntent(PendingIntent.getActivity(
413                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
414                break;
415            }
416            case TYPE_LIMIT: {
417                final String title;
418                final String body = res.getString(R.string.data_usage_limit_body);
419                switch (policy.template.getMatchRule()) {
420                    case MATCH_MOBILE_3G_LOWER:
421                        title = res.getString(R.string.data_usage_3g_limit_title);
422                        break;
423                    case MATCH_MOBILE_4G:
424                        title = res.getString(R.string.data_usage_4g_limit_title);
425                        break;
426                    default:
427                        title = res.getString(R.string.data_usage_mobile_limit_title);
428                        break;
429                }
430
431                builder.setSmallIcon(com.android.internal.R.drawable.ic_menu_block);
432                builder.setTicker(title);
433                builder.setContentTitle(title);
434                builder.setContentText(body);
435
436                final Intent intent = new Intent(ACTION_DATA_USAGE_LIMIT);
437                intent.addCategory(Intent.CATEGORY_DEFAULT);
438                intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.template.getMatchRule());
439                builder.setContentIntent(PendingIntent.getActivity(
440                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
441                break;
442            }
443        }
444
445        // TODO: move to NotificationManager once we can mock it
446        try {
447            final String packageName = mContext.getPackageName();
448            final int[] idReceived = new int[1];
449            mNotifManager.enqueueNotificationWithTag(
450                    packageName, tag, 0x0, builder.getNotification(), idReceived);
451        } catch (RemoteException e) {
452            Slog.w(TAG, "problem during enqueueNotification: " + e);
453        }
454    }
455
456    /**
457     * Cancel any notification for combined {@link NetworkPolicy} and specific
458     * type, like {@link #TYPE_LIMIT}.
459     */
460    private void cancelNotification(NetworkPolicy policy, int type) {
461        final String tag = buildNotificationTag(policy, type);
462
463        // TODO: move to NotificationManager once we can mock it
464        try {
465            final String packageName = mContext.getPackageName();
466            mNotifManager.cancelNotificationWithTag(packageName, tag, 0x0);
467        } catch (RemoteException e) {
468            Slog.w(TAG, "problem during enqueueNotification: " + e);
469        }
470    }
471
472    /**
473     * Receiver that watches for {@link IConnectivityManager} to claim network
474     * interfaces. Used to apply {@link NetworkPolicy} to matching networks.
475     */
476    private BroadcastReceiver mIfaceReceiver = new BroadcastReceiver() {
477        @Override
478        public void onReceive(Context context, Intent intent) {
479            // on background handler thread, and verified CONNECTIVITY_INTERNAL
480            // permission above.
481            synchronized (mRulesLock) {
482                ensureActiveMobilePolicyLocked();
483                updateIfacesLocked();
484            }
485        }
486    };
487
488    /**
489     * Examine all connected {@link NetworkState}, looking for
490     * {@link NetworkPolicy} that need to be enforced. When matches found, set
491     * remaining quota based on usage cycle and historical stats.
492     */
493    private void updateIfacesLocked() {
494        if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
495
496        final NetworkState[] states;
497        try {
498            states = mConnManager.getAllNetworkState();
499        } catch (RemoteException e) {
500            Slog.w(TAG, "problem reading network state");
501            return;
502        }
503
504        // first, derive identity for all connected networks, which can be used
505        // to match against templates.
506        final HashMap<NetworkIdentity, String> networks = Maps.newHashMap();
507        for (NetworkState state : states) {
508            // stash identity and iface away for later use
509            if (state.networkInfo.isConnected()) {
510                final String iface = state.linkProperties.getInterfaceName();
511                final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
512                networks.put(ident, iface);
513            }
514        }
515
516        // build list of rules and ifaces to enforce them against
517        final HashMap<NetworkPolicy, String[]> rules = Maps.newHashMap();
518        final ArrayList<String> ifaceList = Lists.newArrayList();
519        for (NetworkPolicy policy : mNetworkPolicy) {
520
521            // collect all active ifaces that match this template
522            ifaceList.clear();
523            for (NetworkIdentity ident : networks.keySet()) {
524                if (policy.template.matches(ident)) {
525                    final String iface = networks.get(ident);
526                    ifaceList.add(iface);
527                }
528            }
529
530            if (ifaceList.size() > 0) {
531                final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
532                rules.put(policy, ifaces);
533            }
534        }
535
536        // try refreshing time source when stale
537        if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
538            mTime.forceRefresh();
539        }
540
541        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
542                : System.currentTimeMillis();
543
544        mMeteredIfaces.clear();
545
546        // apply each policy that we found ifaces for; compute remaining data
547        // based on current cycle and historical stats, and push to kernel.
548        for (NetworkPolicy policy : rules.keySet()) {
549            final String[] ifaces = rules.get(policy);
550
551            final long start = computeLastCycleBoundary(currentTime, policy);
552            final long end = currentTime;
553
554            final NetworkStats stats;
555            final long total;
556            try {
557                stats = mNetworkStats.getSummaryForNetwork(policy.template, start, end);
558                total = stats.rx[0] + stats.tx[0];
559            } catch (RemoteException e) {
560                Slog.w(TAG, "problem reading summary for template " + policy.template);
561                continue;
562            }
563
564            if (LOGD) {
565                Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
566                        + Arrays.toString(ifaces));
567            }
568
569            // TODO: register for warning notification trigger through NMS
570
571            if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
572                // remaining "quota" is based on usage in current cycle
573                final long quota = Math.max(0, policy.limitBytes - total);
574                //kernelSetIfacesQuota(ifaces, quota);
575
576                for (String iface : ifaces) {
577                    mMeteredIfaces.add(iface);
578                }
579            }
580        }
581
582        // dispatch changed rule to existing listeners
583        // TODO: dispatch outside of holding lock
584        final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
585        final int length = mListeners.beginBroadcast();
586        for (int i = 0; i < length; i++) {
587            final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
588            if (listener != null) {
589                try {
590                    listener.onMeteredIfacesChanged(meteredIfaces);
591                } catch (RemoteException e) {
592                }
593            }
594        }
595        mListeners.finishBroadcast();
596    }
597
598    /**
599     * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
600     * have at least a default mobile policy defined.
601     */
602    private void ensureActiveMobilePolicyLocked() {
603        if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()");
604        final String subscriberId = getActiveSubscriberId();
605        final NetworkIdentity probeIdent = new NetworkIdentity(
606                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId);
607
608        // examine to see if any policy is defined for active mobile
609        boolean mobileDefined = false;
610        for (NetworkPolicy policy : mNetworkPolicy) {
611            if (policy.template.matches(probeIdent)) {
612                mobileDefined = true;
613            }
614        }
615
616        if (!mobileDefined) {
617            Slog.i(TAG, "no policy for active mobile network; generating default policy");
618
619            // default mobile policy has combined 4GB warning, and assume usage
620            // cycle starts today today.
621
622            // TODO: move this policy definition to overlay or secure setting
623            final Time time = new Time(Time.TIMEZONE_UTC);
624            time.setToNow();
625            final int cycleDay = time.monthDay;
626
627            final NetworkTemplate template = new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId);
628            mNetworkPolicy.add(
629                    new NetworkPolicy(template, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED));
630            writePolicyLocked();
631        }
632    }
633
634    private void readPolicyLocked() {
635        if (LOGV) Slog.v(TAG, "readPolicyLocked()");
636
637        // clear any existing policy and read from disk
638        mNetworkPolicy.clear();
639        mUidPolicy.clear();
640
641        FileInputStream fis = null;
642        try {
643            fis = mPolicyFile.openRead();
644            final XmlPullParser in = Xml.newPullParser();
645            in.setInput(fis, null);
646
647            int type;
648            int version = VERSION_CURRENT;
649            while ((type = in.next()) != END_DOCUMENT) {
650                final String tag = in.getName();
651                if (type == START_TAG) {
652                    if (TAG_POLICY_LIST.equals(tag)) {
653                        version = readIntAttribute(in, ATTR_VERSION);
654
655                    } else if (TAG_NETWORK_POLICY.equals(tag)) {
656                        final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
657                        final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID);
658                        final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
659                        final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
660                        final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
661
662                        final NetworkTemplate template = new NetworkTemplate(
663                                networkTemplate, subscriberId);
664                        mNetworkPolicy.add(
665                                new NetworkPolicy(template, cycleDay, warningBytes, limitBytes));
666
667                    } else if (TAG_UID_POLICY.equals(tag)) {
668                        final int uid = readIntAttribute(in, ATTR_UID);
669                        final int policy = readIntAttribute(in, ATTR_POLICY);
670
671                        if (isUidValidForPolicy(mContext, uid)) {
672                            setUidPolicyUnchecked(uid, policy, false);
673                        } else {
674                            Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
675                        }
676                    }
677                }
678            }
679
680        } catch (FileNotFoundException e) {
681            // missing policy is okay, probably first boot
682        } catch (IOException e) {
683            Slog.e(TAG, "problem reading network stats", e);
684        } catch (XmlPullParserException e) {
685            Slog.e(TAG, "problem reading network stats", e);
686        } finally {
687            IoUtils.closeQuietly(fis);
688        }
689    }
690
691    private void writePolicyLocked() {
692        if (LOGV) Slog.v(TAG, "writePolicyLocked()");
693
694        FileOutputStream fos = null;
695        try {
696            fos = mPolicyFile.startWrite();
697
698            XmlSerializer out = new FastXmlSerializer();
699            out.setOutput(fos, "utf-8");
700            out.startDocument(null, true);
701
702            out.startTag(null, TAG_POLICY_LIST);
703            writeIntAttribute(out, ATTR_VERSION, VERSION_CURRENT);
704
705            // write all known network policies
706            for (NetworkPolicy policy : mNetworkPolicy) {
707                final NetworkTemplate template = policy.template;
708
709                out.startTag(null, TAG_NETWORK_POLICY);
710                writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule());
711                final String subscriberId = template.getSubscriberId();
712                if (subscriberId != null) {
713                    out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId);
714                }
715                writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
716                writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
717                writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
718                out.endTag(null, TAG_NETWORK_POLICY);
719            }
720
721            // write all known uid policies
722            for (int i = 0; i < mUidPolicy.size(); i++) {
723                final int uid = mUidPolicy.keyAt(i);
724                final int policy = mUidPolicy.valueAt(i);
725
726                // skip writing empty policies
727                if (policy == POLICY_NONE) continue;
728
729                out.startTag(null, TAG_UID_POLICY);
730                writeIntAttribute(out, ATTR_UID, uid);
731                writeIntAttribute(out, ATTR_POLICY, policy);
732                out.endTag(null, TAG_UID_POLICY);
733            }
734
735            out.endTag(null, TAG_POLICY_LIST);
736            out.endDocument();
737
738            mPolicyFile.finishWrite(fos);
739        } catch (IOException e) {
740            if (fos != null) {
741                mPolicyFile.failWrite(fos);
742            }
743        }
744    }
745
746    @Override
747    public void setUidPolicy(int uid, int policy) {
748        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
749
750        if (!isUidValidForPolicy(mContext, uid)) {
751            throw new IllegalArgumentException("cannot apply policy to UID " + uid);
752        }
753
754        setUidPolicyUnchecked(uid, policy, true);
755    }
756
757    private void setUidPolicyUnchecked(int uid, int policy, boolean persist) {
758        final int oldPolicy;
759        synchronized (mRulesLock) {
760            oldPolicy = getUidPolicy(uid);
761            mUidPolicy.put(uid, policy);
762
763            // uid policy changed, recompute rules and persist policy.
764            updateRulesForUidLocked(uid);
765            if (persist) {
766                writePolicyLocked();
767            }
768        }
769    }
770
771    @Override
772    public int getUidPolicy(int uid) {
773        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
774
775        synchronized (mRulesLock) {
776            return mUidPolicy.get(uid, POLICY_NONE);
777        }
778    }
779
780    @Override
781    public void registerListener(INetworkPolicyListener listener) {
782        // TODO: create permission for observing network policy
783        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
784
785        mListeners.register(listener);
786
787        synchronized (mRulesLock) {
788            // dispatch any existing rules to new listeners
789            // TODO: dispatch outside of holding lock
790            final int size = mUidRules.size();
791            for (int i = 0; i < size; i++) {
792                final int uid = mUidRules.keyAt(i);
793                final int uidRules = mUidRules.valueAt(i);
794                if (uidRules != RULE_ALLOW_ALL) {
795                    try {
796                        listener.onUidRulesChanged(uid, uidRules);
797                    } catch (RemoteException e) {
798                    }
799                }
800            }
801
802            // dispatch any metered ifaces to new listeners
803            // TODO: dispatch outside of holding lock
804            if (mMeteredIfaces.size() > 0) {
805                final String[] meteredIfaces = mMeteredIfaces.toArray(
806                        new String[mMeteredIfaces.size()]);
807                try {
808                    listener.onMeteredIfacesChanged(meteredIfaces);
809                } catch (RemoteException e) {
810                }
811            }
812        }
813    }
814
815    @Override
816    public void unregisterListener(INetworkPolicyListener listener) {
817        // TODO: create permission for observing network policy
818        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
819
820        mListeners.unregister(listener);
821    }
822
823    @Override
824    public void setNetworkPolicies(NetworkPolicy[] policies) {
825        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
826
827        synchronized (mRulesLock) {
828            mNetworkPolicy.clear();
829            for (NetworkPolicy policy : policies) {
830                mNetworkPolicy.add(policy);
831            }
832
833            updateIfacesLocked();
834            updateNotificationsLocked();
835            writePolicyLocked();
836        }
837    }
838
839    @Override
840    public NetworkPolicy[] getNetworkPolicies() {
841        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
842        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
843
844        synchronized (mRulesLock) {
845            return mNetworkPolicy.toArray(new NetworkPolicy[mNetworkPolicy.size()]);
846        }
847    }
848
849    @Override
850    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
851        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
852
853        synchronized (mRulesLock) {
854            fout.println("Network policies:");
855            for (NetworkPolicy policy : mNetworkPolicy) {
856                fout.print("  "); fout.println(policy.toString());
857            }
858
859            fout.println("Policy status for known UIDs:");
860
861            final SparseBooleanArray knownUids = new SparseBooleanArray();
862            collectKeys(mUidPolicy, knownUids);
863            collectKeys(mUidForeground, knownUids);
864            collectKeys(mUidRules, knownUids);
865
866            final int size = knownUids.size();
867            for (int i = 0; i < size; i++) {
868                final int uid = knownUids.keyAt(i);
869                fout.print("  UID=");
870                fout.print(uid);
871
872                fout.print(" policy=");
873                final int policyIndex = mUidPolicy.indexOfKey(uid);
874                if (policyIndex < 0) {
875                    fout.print("UNKNOWN");
876                } else {
877                    dumpPolicy(fout, mUidPolicy.valueAt(policyIndex));
878                }
879
880                fout.print(" foreground=");
881                final int foregroundIndex = mUidPidForeground.indexOfKey(uid);
882                if (foregroundIndex < 0) {
883                    fout.print("UNKNOWN");
884                } else {
885                    dumpSparseBooleanArray(fout, mUidPidForeground.valueAt(foregroundIndex));
886                }
887
888                fout.print(" rules=");
889                final int rulesIndex = mUidRules.indexOfKey(uid);
890                if (rulesIndex < 0) {
891                    fout.print("UNKNOWN");
892                } else {
893                    dumpRules(fout, mUidRules.valueAt(rulesIndex));
894                }
895
896                fout.println();
897            }
898        }
899    }
900
901    @Override
902    public boolean isUidForeground(int uid) {
903        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
904
905        synchronized (mRulesLock) {
906            // only really in foreground when screen is also on
907            return mUidForeground.get(uid, false) && mScreenOn;
908        }
909    }
910
911    /**
912     * Foreground for PID changed; recompute foreground at UID level. If
913     * changed, will trigger {@link #updateRulesForUidLocked(int)}.
914     */
915    private void computeUidForegroundLocked(int uid) {
916        final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
917
918        // current pid is dropping foreground; examine other pids
919        boolean uidForeground = false;
920        final int size = pidForeground.size();
921        for (int i = 0; i < size; i++) {
922            if (pidForeground.valueAt(i)) {
923                uidForeground = true;
924                break;
925            }
926        }
927
928        final boolean oldUidForeground = mUidForeground.get(uid, false);
929        if (oldUidForeground != uidForeground) {
930            // foreground changed, push updated rules
931            mUidForeground.put(uid, uidForeground);
932            updateRulesForUidLocked(uid);
933        }
934    }
935
936    private void updateScreenOn() {
937        synchronized (mRulesLock) {
938            try {
939                mScreenOn = mPowerManager.isScreenOn();
940            } catch (RemoteException e) {
941            }
942            updateRulesForScreenLocked();
943        }
944    }
945
946    /**
947     * Update rules that might be changed by {@link #mScreenOn} value.
948     */
949    private void updateRulesForScreenLocked() {
950        // only update rules for anyone with foreground activities
951        final int size = mUidForeground.size();
952        for (int i = 0; i < size; i++) {
953            if (mUidForeground.valueAt(i)) {
954                final int uid = mUidForeground.keyAt(i);
955                updateRulesForUidLocked(uid);
956            }
957        }
958    }
959
960    private void updateRulesForUidLocked(int uid) {
961        if (!isUidValidForPolicy(mContext, uid)) return;
962
963        final int uidPolicy = getUidPolicy(uid);
964        final boolean uidForeground = isUidForeground(uid);
965
966        // derive active rules based on policy and active state
967        int uidRules = RULE_ALLOW_ALL;
968        if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
969            // uid in background, and policy says to block metered data
970            uidRules = RULE_REJECT_METERED;
971        }
972
973        // TODO: only dispatch when rules actually change
974
975        // record rule locally to dispatch to new listeners
976        mUidRules.put(uid, uidRules);
977
978        final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
979        //kernelSetUidRejectPaid(uid, rejectPaid);
980
981        // dispatch changed rule to existing listeners
982        // TODO: dispatch outside of holding lock
983        final int length = mListeners.beginBroadcast();
984        for (int i = 0; i < length; i++) {
985            final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
986            if (listener != null) {
987                try {
988                    listener.onUidRulesChanged(uid, uidRules);
989                } catch (RemoteException e) {
990                }
991            }
992        }
993        mListeners.finishBroadcast();
994    }
995
996    private String getActiveSubscriberId() {
997        final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
998                Context.TELEPHONY_SERVICE);
999        return telephony.getSubscriberId();
1000    }
1001
1002    private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
1003        final int size = source.size();
1004        for (int i = 0; i < size; i++) {
1005            target.put(source.keyAt(i), true);
1006        }
1007    }
1008
1009    private static void collectKeys(SparseBooleanArray source, SparseBooleanArray target) {
1010        final int size = source.size();
1011        for (int i = 0; i < size; i++) {
1012            target.put(source.keyAt(i), true);
1013        }
1014    }
1015
1016    private static void dumpSparseBooleanArray(PrintWriter fout, SparseBooleanArray value) {
1017        fout.print("[");
1018        final int size = value.size();
1019        for (int i = 0; i < size; i++) {
1020            fout.print(value.keyAt(i) + "=" + value.valueAt(i));
1021            if (i < size - 1) fout.print(",");
1022        }
1023        fout.print("]");
1024    }
1025
1026    private static int readIntAttribute(XmlPullParser in, String name) throws IOException {
1027        final String value = in.getAttributeValue(null, name);
1028        try {
1029            return Integer.parseInt(value);
1030        } catch (NumberFormatException e) {
1031            throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
1032        }
1033    }
1034
1035    private static long readLongAttribute(XmlPullParser in, String name) throws IOException {
1036        final String value = in.getAttributeValue(null, name);
1037        try {
1038            return Long.parseLong(value);
1039        } catch (NumberFormatException e) {
1040            throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
1041        }
1042    }
1043
1044    private static void writeIntAttribute(XmlSerializer out, String name, int value)
1045            throws IOException {
1046        out.attribute(null, name, Integer.toString(value));
1047    }
1048
1049    private static void writeLongAttribute(XmlSerializer out, String name, long value)
1050            throws IOException {
1051        out.attribute(null, name, Long.toString(value));
1052    }
1053
1054}
1055