NetworkPolicyManagerService.java revision af11d4859582a9736aa204562f0beac5a7d60934
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_PHONE_STATE;
24import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
25import static android.net.NetworkPolicy.LIMIT_DISABLED;
26import static android.net.NetworkPolicyManager.POLICY_NONE;
27import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID_BACKGROUND;
28import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
29import static android.net.NetworkPolicyManager.RULE_REJECT_PAID;
30import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
31import static android.net.NetworkPolicyManager.dumpPolicy;
32import static android.net.NetworkPolicyManager.dumpRules;
33import static android.net.TrafficStats.TEMPLATE_MOBILE_ALL;
34import static android.net.TrafficStats.isNetworkTemplateMobile;
35import static android.text.format.DateUtils.DAY_IN_MILLIS;
36import static com.android.internal.util.Preconditions.checkNotNull;
37import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
38import static org.xmlpull.v1.XmlPullParser.START_TAG;
39
40import android.app.IActivityManager;
41import android.app.IProcessObserver;
42import android.content.BroadcastReceiver;
43import android.content.Context;
44import android.content.Intent;
45import android.content.IntentFilter;
46import android.net.ConnectivityManager;
47import android.net.IConnectivityManager;
48import android.net.INetworkPolicyListener;
49import android.net.INetworkPolicyManager;
50import android.net.INetworkStatsService;
51import android.net.NetworkPolicy;
52import android.net.NetworkState;
53import android.net.NetworkStats;
54import android.os.Environment;
55import android.os.Handler;
56import android.os.HandlerThread;
57import android.os.IPowerManager;
58import android.os.RemoteCallbackList;
59import android.os.RemoteException;
60import android.telephony.TelephonyManager;
61import android.text.format.Time;
62import android.util.NtpTrustedTime;
63import android.util.Slog;
64import android.util.SparseArray;
65import android.util.SparseBooleanArray;
66import android.util.SparseIntArray;
67import android.util.TrustedTime;
68import android.util.Xml;
69
70import com.android.internal.os.AtomicFile;
71import com.android.internal.util.FastXmlSerializer;
72import com.android.internal.util.Objects;
73import com.google.android.collect.Lists;
74import com.google.android.collect.Maps;
75
76import org.xmlpull.v1.XmlPullParser;
77import org.xmlpull.v1.XmlPullParserException;
78import org.xmlpull.v1.XmlSerializer;
79
80import java.io.File;
81import java.io.FileDescriptor;
82import java.io.FileInputStream;
83import java.io.FileNotFoundException;
84import java.io.FileOutputStream;
85import java.io.IOException;
86import java.io.PrintWriter;
87import java.net.ProtocolException;
88import java.util.ArrayList;
89import java.util.Arrays;
90import java.util.HashMap;
91
92import libcore.io.IoUtils;
93
94/**
95 * Service that maintains low-level network policy rules and collects usage
96 * statistics to drive those rules.
97 * <p>
98 * Derives active rules by combining a given policy with other system status,
99 * and delivers to listeners, such as {@link ConnectivityManager}, for
100 * enforcement.
101 */
102public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
103    private static final String TAG = "NetworkPolicy";
104    private static final boolean LOGD = true;
105    private static final boolean LOGV = false;
106
107    private static final int VERSION_CURRENT = 1;
108
109    private static final long KB_IN_BYTES = 1024;
110    private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
111    private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
112
113    private static final String TAG_POLICY_LIST = "policy-list";
114    private static final String TAG_NETWORK_POLICY = "network-policy";
115    private static final String TAG_UID_POLICY = "uid-policy";
116
117    private static final String ATTR_VERSION = "version";
118    private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate";
119    private static final String ATTR_SUBSCRIBER_ID = "subscriberId";
120    private static final String ATTR_CYCLE_DAY = "cycleDay";
121    private static final String ATTR_WARNING_BYTES = "warningBytes";
122    private static final String ATTR_LIMIT_BYTES = "limitBytes";
123    private static final String ATTR_UID = "uid";
124    private static final String ATTR_POLICY = "policy";
125
126    private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
127
128    private final Context mContext;
129    private final IActivityManager mActivityManager;
130    private final IPowerManager mPowerManager;
131    private final INetworkStatsService mNetworkStats;
132    private final TrustedTime mTime;
133
134    private IConnectivityManager mConnManager;
135
136    private final Object mRulesLock = new Object();
137
138    private boolean mScreenOn;
139
140    /** Current policy for network templates. */
141    private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
142
143    /** Current policy for each UID. */
144    private SparseIntArray mUidPolicy = new SparseIntArray();
145    /** Current derived network rules for each UID. */
146    private SparseIntArray mUidRules = new SparseIntArray();
147
148    /** Foreground at both UID and PID granularity. */
149    private SparseBooleanArray mUidForeground = new SparseBooleanArray();
150    private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
151            SparseBooleanArray>();
152
153    private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
154            INetworkPolicyListener>();
155
156    private final HandlerThread mHandlerThread;
157    private final Handler mHandler;
158
159    private final AtomicFile mPolicyFile;
160
161    // TODO: keep whitelist of system-critical services that should never have
162    // rules enforced, such as system, phone, and radio UIDs.
163
164    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
165            IPowerManager powerManager, INetworkStatsService networkStats) {
166        // TODO: move to using cached NtpTrustedTime
167        this(context, activityManager, powerManager, networkStats, new NtpTrustedTime(),
168                getSystemDir());
169    }
170
171    private static File getSystemDir() {
172        return new File(Environment.getDataDirectory(), "system");
173    }
174
175    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
176            IPowerManager powerManager, INetworkStatsService networkStats, TrustedTime time,
177            File systemDir) {
178        mContext = checkNotNull(context, "missing context");
179        mActivityManager = checkNotNull(activityManager, "missing activityManager");
180        mPowerManager = checkNotNull(powerManager, "missing powerManager");
181        mNetworkStats = checkNotNull(networkStats, "missing networkStats");
182        mTime = checkNotNull(time, "missing TrustedTime");
183
184        mHandlerThread = new HandlerThread(TAG);
185        mHandlerThread.start();
186        mHandler = new Handler(mHandlerThread.getLooper());
187
188        mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
189    }
190
191    public void bindConnectivityManager(IConnectivityManager connManager) {
192        mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
193    }
194
195    public void systemReady() {
196        synchronized (mRulesLock) {
197            // read policy from disk
198            readPolicyLocked();
199        }
200
201        updateScreenOn();
202
203        try {
204            mActivityManager.registerProcessObserver(mProcessObserver);
205        } catch (RemoteException e) {
206            // ouch, no foregroundActivities updates means some processes may
207            // never get network access.
208            Slog.e(TAG, "unable to register IProcessObserver", e);
209        }
210
211        // TODO: traverse existing processes to know foreground state, or have
212        // activitymanager dispatch current state when new observer attached.
213
214        final IntentFilter screenFilter = new IntentFilter();
215        screenFilter.addAction(Intent.ACTION_SCREEN_ON);
216        screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
217        mContext.registerReceiver(mScreenReceiver, screenFilter);
218
219        // watch for network interfaces to be claimed
220        final IntentFilter ifaceFilter = new IntentFilter();
221        ifaceFilter.addAction(CONNECTIVITY_ACTION);
222        mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler);
223
224    }
225
226    private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
227        @Override
228        public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
229            // only someone like AMS should only be calling us
230            mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
231
232            synchronized (mRulesLock) {
233                // because a uid can have multiple pids running inside, we need to
234                // remember all pid states and summarize foreground at uid level.
235
236                // record foreground for this specific pid
237                SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
238                if (pidForeground == null) {
239                    pidForeground = new SparseBooleanArray(2);
240                    mUidPidForeground.put(uid, pidForeground);
241                }
242                pidForeground.put(pid, foregroundActivities);
243                computeUidForegroundLocked(uid);
244            }
245        }
246
247        @Override
248        public void onProcessDied(int pid, int uid) {
249            // only someone like AMS should only be calling us
250            mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
251
252            synchronized (mRulesLock) {
253                // clear records and recompute, when they exist
254                final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
255                if (pidForeground != null) {
256                    pidForeground.delete(pid);
257                    computeUidForegroundLocked(uid);
258                }
259            }
260        }
261    };
262
263    private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
264        @Override
265        public void onReceive(Context context, Intent intent) {
266            synchronized (mRulesLock) {
267                // screen-related broadcasts are protected by system, no need
268                // for permissions check.
269                updateScreenOn();
270            }
271        }
272    };
273
274    /**
275     * Receiver that watches for {@link IConnectivityManager} to claim network
276     * interfaces. Used to apply {@link NetworkPolicy} to matching networks.
277     */
278    private BroadcastReceiver mIfaceReceiver = new BroadcastReceiver() {
279        @Override
280        public void onReceive(Context context, Intent intent) {
281            // on background handler thread, and verified CONNECTIVITY_INTERNAL
282            // permission above.
283            synchronized (mRulesLock) {
284                ensureActiveMobilePolicyLocked();
285                updateIfacesLocked();
286            }
287        }
288    };
289
290    /**
291     * Examine all connected {@link NetworkState}, looking for
292     * {@link NetworkPolicy} that need to be enforced. When matches found, set
293     * remaining quota based on usage cycle and historical stats.
294     */
295    private void updateIfacesLocked() {
296        if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
297
298        final NetworkState[] states;
299        try {
300            states = mConnManager.getAllNetworkState();
301        } catch (RemoteException e) {
302            Slog.w(TAG, "problem reading network state");
303            return;
304        }
305
306        // first, derive identity for all connected networks, which can be used
307        // to match against templates.
308        final HashMap<NetworkIdentity, String> networks = Maps.newHashMap();
309        for (NetworkState state : states) {
310            // stash identity and iface away for later use
311            if (state.networkInfo.isConnected()) {
312                final String iface = state.linkProperties.getInterfaceName();
313                final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
314                networks.put(ident, iface);
315            }
316        }
317
318        // build list of rules and ifaces to enforce them against
319        final HashMap<NetworkPolicy, String[]> rules = Maps.newHashMap();
320        final ArrayList<String> ifaceList = Lists.newArrayList();
321        for (NetworkPolicy policy : mNetworkPolicy) {
322
323            // collect all active ifaces that match this template
324            ifaceList.clear();
325            for (NetworkIdentity ident : networks.keySet()) {
326                if (ident.matchesTemplate(policy.networkTemplate, policy.subscriberId)) {
327                    final String iface = networks.get(ident);
328                    ifaceList.add(iface);
329                }
330            }
331
332            if (ifaceList.size() > 0) {
333                final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
334                rules.put(policy, ifaces);
335            }
336        }
337
338        // try refreshing time source when stale
339        if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
340            mTime.forceRefresh();
341        }
342
343        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
344                : System.currentTimeMillis();
345
346        // apply each policy that we found ifaces for; compute remaining data
347        // based on current cycle and historical stats, and push to kernel.
348        for (NetworkPolicy policy : rules.keySet()) {
349            final String[] ifaces = rules.get(policy);
350
351            final long start = computeLastCycleBoundary(currentTime, policy);
352            final long end = currentTime;
353
354            final NetworkStats stats;
355            final long total;
356            try {
357                stats = mNetworkStats.getSummaryForNetwork(
358                        start, end, policy.networkTemplate, policy.subscriberId);
359                total = stats.rx[0] + stats.tx[0];
360            } catch (RemoteException e) {
361                Slog.w(TAG, "problem reading summary for template " + policy.networkTemplate);
362                continue;
363            }
364
365            if (LOGD) {
366                Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
367                        + Arrays.toString(ifaces));
368            }
369
370            // TODO: register for warning notification trigger through NMS
371
372            if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
373                // remaining "quota" is based on usage in current cycle
374                final long quota = Math.max(0, policy.limitBytes - total);
375
376                // TODO: push quota rule down through NMS
377            }
378        }
379    }
380
381    /**
382     * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
383     * have at least a default mobile policy defined.
384     */
385    private void ensureActiveMobilePolicyLocked() {
386        if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()");
387        final String subscriberId = getActiveSubscriberId();
388        if (subscriberId == null) {
389            if (LOGV) Slog.v(TAG, "no active mobile network, ignoring policy check");
390            return;
391        }
392
393        // examine to see if any policy is defined for active mobile
394        boolean mobileDefined = false;
395        for (NetworkPolicy policy : mNetworkPolicy) {
396            if (isNetworkTemplateMobile(policy.networkTemplate)
397                    && Objects.equal(subscriberId, policy.subscriberId)) {
398                mobileDefined = true;
399            }
400        }
401
402        if (!mobileDefined) {
403            Slog.i(TAG, "no policy for active mobile network; generating default policy");
404
405            // default mobile policy has combined 4GB warning, and assume usage
406            // cycle starts today today.
407
408            // TODO: move this policy definition to overlay or secure setting
409            final Time time = new Time(Time.TIMEZONE_UTC);
410            time.setToNow();
411            final int cycleDay = time.monthDay;
412
413            mNetworkPolicy.add(new NetworkPolicy(
414                    TEMPLATE_MOBILE_ALL, subscriberId, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED));
415        }
416    }
417
418    private void readPolicyLocked() {
419        if (LOGV) Slog.v(TAG, "readPolicyLocked()");
420
421        // clear any existing policy and read from disk
422        mNetworkPolicy.clear();
423        mUidPolicy.clear();
424
425        FileInputStream fis = null;
426        try {
427            fis = mPolicyFile.openRead();
428            final XmlPullParser in = Xml.newPullParser();
429            in.setInput(fis, null);
430
431            int type;
432            int version = VERSION_CURRENT;
433            while ((type = in.next()) != END_DOCUMENT) {
434                final String tag = in.getName();
435                if (type == START_TAG) {
436                    if (TAG_POLICY_LIST.equals(tag)) {
437                        version = readIntAttribute(in, ATTR_VERSION);
438
439                    } else if (TAG_NETWORK_POLICY.equals(tag)) {
440                        final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
441                        final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID);
442                        final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
443                        final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
444                        final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
445
446                        mNetworkPolicy.add(new NetworkPolicy(
447                                networkTemplate, subscriberId, cycleDay, warningBytes, limitBytes));
448
449                    } else if (TAG_UID_POLICY.equals(tag)) {
450                        final int uid = readIntAttribute(in, ATTR_UID);
451                        final int policy = readIntAttribute(in, ATTR_POLICY);
452
453                        mUidPolicy.put(uid, policy);
454                    }
455                }
456            }
457
458        } catch (FileNotFoundException e) {
459            // missing policy is okay, probably first boot
460        } catch (IOException e) {
461            Slog.e(TAG, "problem reading network stats", e);
462        } catch (XmlPullParserException e) {
463            Slog.e(TAG, "problem reading network stats", e);
464        } finally {
465            IoUtils.closeQuietly(fis);
466        }
467    }
468
469    private void writePolicyLocked() {
470        if (LOGV) Slog.v(TAG, "writePolicyLocked()");
471
472        FileOutputStream fos = null;
473        try {
474            fos = mPolicyFile.startWrite();
475
476            XmlSerializer out = new FastXmlSerializer();
477            out.setOutput(fos, "utf-8");
478            out.startDocument(null, true);
479
480            out.startTag(null, TAG_POLICY_LIST);
481            writeIntAttribute(out, ATTR_VERSION, VERSION_CURRENT);
482
483            // write all known network policies
484            for (NetworkPolicy policy : mNetworkPolicy) {
485                out.startTag(null, TAG_NETWORK_POLICY);
486                writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, policy.networkTemplate);
487                if (policy.subscriberId != null) {
488                    out.attribute(null, ATTR_SUBSCRIBER_ID, policy.subscriberId);
489                }
490                writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
491                writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
492                writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
493                out.endTag(null, TAG_NETWORK_POLICY);
494            }
495
496            // write all known uid policies
497            for (int i = 0; i < mUidPolicy.size(); i++) {
498                final int uid = mUidPolicy.keyAt(i);
499                final int policy = mUidPolicy.valueAt(i);
500
501                out.startTag(null, TAG_UID_POLICY);
502                writeIntAttribute(out, ATTR_UID, uid);
503                writeIntAttribute(out, ATTR_POLICY, policy);
504                out.endTag(null, TAG_UID_POLICY);
505            }
506
507            out.endTag(null, TAG_POLICY_LIST);
508            out.endDocument();
509
510            mPolicyFile.finishWrite(fos);
511        } catch (IOException e) {
512            if (fos != null) {
513                mPolicyFile.failWrite(fos);
514            }
515        }
516    }
517
518    @Override
519    public void setUidPolicy(int uid, int policy) {
520        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
521
522        final int oldPolicy;
523        synchronized (mRulesLock) {
524            oldPolicy = getUidPolicy(uid);
525            mUidPolicy.put(uid, policy);
526
527            // uid policy changed, recompute rules and persist policy.
528            updateRulesForUidLocked(uid);
529            writePolicyLocked();
530        }
531    }
532
533    @Override
534    public int getUidPolicy(int uid) {
535        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
536
537        synchronized (mRulesLock) {
538            return mUidPolicy.get(uid, POLICY_NONE);
539        }
540    }
541
542    @Override
543    public void registerListener(INetworkPolicyListener listener) {
544        mListeners.register(listener);
545
546        synchronized (mRulesLock) {
547            // dispatch any existing rules to new listeners
548            final int size = mUidRules.size();
549            for (int i = 0; i < size; i++) {
550                final int uid = mUidRules.keyAt(i);
551                final int uidRules = mUidRules.valueAt(i);
552                if (uidRules != RULE_ALLOW_ALL) {
553                    try {
554                        listener.onRulesChanged(uid, uidRules);
555                    } catch (RemoteException e) {
556                    }
557                }
558            }
559        }
560    }
561
562    @Override
563    public void unregisterListener(INetworkPolicyListener listener) {
564        mListeners.unregister(listener);
565    }
566
567    @Override
568    public void setNetworkPolicies(NetworkPolicy[] policies) {
569        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
570
571        synchronized (mRulesLock) {
572            mNetworkPolicy.clear();
573            for (NetworkPolicy policy : policies) {
574                mNetworkPolicy.add(policy);
575            }
576
577            updateIfacesLocked();
578            writePolicyLocked();
579        }
580    }
581
582    @Override
583    public NetworkPolicy[] getNetworkPolicies() {
584        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
585        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
586
587        synchronized (mRulesLock) {
588            return mNetworkPolicy.toArray(new NetworkPolicy[mNetworkPolicy.size()]);
589        }
590    }
591
592    @Override
593    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
594        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
595
596        synchronized (mRulesLock) {
597            fout.println("Network policies:");
598            for (NetworkPolicy policy : mNetworkPolicy) {
599                fout.print("  "); fout.println(policy.toString());
600            }
601
602            fout.println("Policy status for known UIDs:");
603
604            final SparseBooleanArray knownUids = new SparseBooleanArray();
605            collectKeys(mUidPolicy, knownUids);
606            collectKeys(mUidForeground, knownUids);
607            collectKeys(mUidRules, knownUids);
608
609            final int size = knownUids.size();
610            for (int i = 0; i < size; i++) {
611                final int uid = knownUids.keyAt(i);
612                fout.print("  UID=");
613                fout.print(uid);
614
615                fout.print(" policy=");
616                final int policyIndex = mUidPolicy.indexOfKey(uid);
617                if (policyIndex < 0) {
618                    fout.print("UNKNOWN");
619                } else {
620                    dumpPolicy(fout, mUidPolicy.valueAt(policyIndex));
621                }
622
623                fout.print(" foreground=");
624                final int foregroundIndex = mUidPidForeground.indexOfKey(uid);
625                if (foregroundIndex < 0) {
626                    fout.print("UNKNOWN");
627                } else {
628                    dumpSparseBooleanArray(fout, mUidPidForeground.valueAt(foregroundIndex));
629                }
630
631                fout.print(" rules=");
632                final int rulesIndex = mUidRules.indexOfKey(uid);
633                if (rulesIndex < 0) {
634                    fout.print("UNKNOWN");
635                } else {
636                    dumpRules(fout, mUidRules.valueAt(rulesIndex));
637                }
638
639                fout.println();
640            }
641        }
642    }
643
644    @Override
645    public boolean isUidForeground(int uid) {
646        synchronized (mRulesLock) {
647            // only really in foreground when screen is also on
648            return mUidForeground.get(uid, false) && mScreenOn;
649        }
650    }
651
652    /**
653     * Foreground for PID changed; recompute foreground at UID level. If
654     * changed, will trigger {@link #updateRulesForUidLocked(int)}.
655     */
656    private void computeUidForegroundLocked(int uid) {
657        final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
658
659        // current pid is dropping foreground; examine other pids
660        boolean uidForeground = false;
661        final int size = pidForeground.size();
662        for (int i = 0; i < size; i++) {
663            if (pidForeground.valueAt(i)) {
664                uidForeground = true;
665                break;
666            }
667        }
668
669        final boolean oldUidForeground = mUidForeground.get(uid, false);
670        if (oldUidForeground != uidForeground) {
671            // foreground changed, push updated rules
672            mUidForeground.put(uid, uidForeground);
673            updateRulesForUidLocked(uid);
674        }
675    }
676
677    private void updateScreenOn() {
678        synchronized (mRulesLock) {
679            try {
680                mScreenOn = mPowerManager.isScreenOn();
681            } catch (RemoteException e) {
682            }
683            updateRulesForScreenLocked();
684        }
685    }
686
687    /**
688     * Update rules that might be changed by {@link #mScreenOn} value.
689     */
690    private void updateRulesForScreenLocked() {
691        // only update rules for anyone with foreground activities
692        final int size = mUidForeground.size();
693        for (int i = 0; i < size; i++) {
694            if (mUidForeground.valueAt(i)) {
695                final int uid = mUidForeground.keyAt(i);
696                updateRulesForUidLocked(uid);
697            }
698        }
699    }
700
701    private void updateRulesForUidLocked(int uid) {
702        final int uidPolicy = getUidPolicy(uid);
703        final boolean uidForeground = isUidForeground(uid);
704
705        // derive active rules based on policy and active state
706        int uidRules = RULE_ALLOW_ALL;
707        if (!uidForeground && (uidPolicy & POLICY_REJECT_PAID_BACKGROUND) != 0) {
708            // uid in background, and policy says to block paid data
709            uidRules = RULE_REJECT_PAID;
710        }
711
712        // TODO: only dispatch when rules actually change
713
714        // record rule locally to dispatch to new listeners
715        mUidRules.put(uid, uidRules);
716
717        // dispatch changed rule to existing listeners
718        final int length = mListeners.beginBroadcast();
719        for (int i = 0; i < length; i++) {
720            final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
721            if (listener != null) {
722                try {
723                    listener.onRulesChanged(uid, uidRules);
724                } catch (RemoteException e) {
725                }
726            }
727        }
728        mListeners.finishBroadcast();
729    }
730
731    private String getActiveSubscriberId() {
732        final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
733                Context.TELEPHONY_SERVICE);
734        return telephony.getSubscriberId();
735    }
736
737    private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
738        final int size = source.size();
739        for (int i = 0; i < size; i++) {
740            target.put(source.keyAt(i), true);
741        }
742    }
743
744    private static void collectKeys(SparseBooleanArray source, SparseBooleanArray target) {
745        final int size = source.size();
746        for (int i = 0; i < size; i++) {
747            target.put(source.keyAt(i), true);
748        }
749    }
750
751    private static void dumpSparseBooleanArray(PrintWriter fout, SparseBooleanArray value) {
752        fout.print("[");
753        final int size = value.size();
754        for (int i = 0; i < size; i++) {
755            fout.print(value.keyAt(i) + "=" + value.valueAt(i));
756            if (i < size - 1) fout.print(",");
757        }
758        fout.print("]");
759    }
760
761    private static int readIntAttribute(XmlPullParser in, String name) throws IOException {
762        final String value = in.getAttributeValue(null, name);
763        try {
764            return Integer.parseInt(value);
765        } catch (NumberFormatException e) {
766            throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
767        }
768    }
769
770    private static long readLongAttribute(XmlPullParser in, String name) throws IOException {
771        final String value = in.getAttributeValue(null, name);
772        try {
773            return Long.parseLong(value);
774        } catch (NumberFormatException e) {
775            throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
776        }
777    }
778
779    private static void writeIntAttribute(XmlSerializer out, String name, int value)
780            throws IOException {
781        out.attribute(null, name, Integer.toString(value));
782    }
783
784    private static void writeLongAttribute(XmlSerializer out, String name, long value)
785            throws IOException {
786        out.attribute(null, name, Long.toString(value));
787    }
788
789}
790