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