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