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