1d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey/*
2d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey * Copyright (C) 2011 The Android Open Source Project
3d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey *
4d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey * you may not use this file except in compliance with the License.
6d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey * You may obtain a copy of the License at
7d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey *
8d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey *
10d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
11d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey * See the License for the specific language governing permissions and
14d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey * limitations under the License.
15d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey */
16d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
17d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeypackage com.android.server.net;
18d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
19f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkeyimport static android.Manifest.permission.ACCESS_NETWORK_STATE;
2021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport static android.Manifest.permission.CONNECTIVITY_INTERNAL;
211b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkeyimport static android.Manifest.permission.DUMP;
2221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport static android.Manifest.permission.MANAGE_NETWORK_POLICY;
23497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
2422c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkeyimport static android.Manifest.permission.READ_PHONE_STATE;
2502e21d6a5b5117d494777a36783909854854f751Jeff Sharkeyimport static android.content.Intent.ACTION_PACKAGE_ADDED;
26b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkeyimport static android.content.Intent.ACTION_UID_REMOVED;
27b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkeyimport static android.content.Intent.EXTRA_UID;
28961e30458319cfd50e1892ba7dd14a1d0ebe4cc7Jeff Sharkeyimport static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
298e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkeyimport static android.net.ConnectivityManager.TYPE_ETHERNET;
301b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport static android.net.ConnectivityManager.TYPE_MOBILE;
318e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkeyimport static android.net.ConnectivityManager.TYPE_WIFI;
328e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkeyimport static android.net.ConnectivityManager.TYPE_WIMAX;
3322c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkeyimport static android.net.NetworkPolicy.LIMIT_DISABLED;
3441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkeyimport static android.net.NetworkPolicy.SNOOZE_NEVER;
35497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport static android.net.NetworkPolicy.WARNING_DISABLED;
3614711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkeyimport static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
37d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport static android.net.NetworkPolicyManager.POLICY_NONE;
38fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkeyimport static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
39c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkeyimport static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
40fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkeyimport static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
41cd2ca4038a027315832c38c68be5076000bc4b53Jeff Sharkeyimport static android.net.NetworkPolicyManager.computeLastCycleBoundary;
421b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkeyimport static android.net.NetworkPolicyManager.dumpPolicy;
431b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkeyimport static android.net.NetworkPolicyManager.dumpRules;
44497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport static android.net.NetworkPolicyManager.isUidValidForPolicy;
458e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkeyimport static android.net.NetworkTemplate.MATCH_ETHERNET;
461b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
471b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport static android.net.NetworkTemplate.MATCH_MOBILE_4G;
488e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkeyimport static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
498e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkeyimport static android.net.NetworkTemplate.MATCH_WIFI;
504e814c348ce205fcc1a273427f95ef1d100ed60cJeff Sharkeyimport static android.net.NetworkTemplate.buildTemplateMobileAll;
5121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport static android.text.format.DateUtils.DAY_IN_MILLIS;
5221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport static com.android.internal.util.Preconditions.checkNotNull;
53961e30458319cfd50e1892ba7dd14a1d0ebe4cc7Jeff Sharkeyimport static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
544664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkeyimport static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readBooleanAttribute;
554664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkeyimport static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readIntAttribute;
564664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkeyimport static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readLongAttribute;
574664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkeyimport static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeBooleanAttribute;
584664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkeyimport static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeIntAttribute;
594664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkeyimport static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeLongAttribute;
60497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
6121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
6221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.START_TAG;
63d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
64a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.app.IActivityManager;
65497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport android.app.INotificationManager;
66a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.app.IProcessObserver;
67497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport android.app.Notification;
68497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport android.app.PendingIntent;
69a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.content.BroadcastReceiver;
7041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkeyimport android.content.ComponentName;
71d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport android.content.Context;
72a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.content.Intent;
73a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.content.IntentFilter;
74b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkeyimport android.content.pm.ApplicationInfo;
75b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkeyimport android.content.pm.PackageManager;
76497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport android.content.res.Resources;
77c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkeyimport android.net.ConnectivityManager;
7821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.net.IConnectivityManager;
7941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkeyimport android.net.INetworkManagementEventObserver;
80c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkeyimport android.net.INetworkPolicyListener;
81d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport android.net.INetworkPolicyManager;
8275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.net.INetworkStatsService;
831b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport android.net.NetworkIdentity;
8421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.net.NetworkPolicy;
85f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkeyimport android.net.NetworkQuotaInfo;
8621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.net.NetworkState;
871b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport android.net.NetworkTemplate;
88f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkeyimport android.os.Binder;
8921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.os.Environment;
9021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.os.Handler;
9121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.os.HandlerThread;
9250fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharmaimport android.os.INetworkManagementService;
93a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.os.IPowerManager;
944414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkeyimport android.os.Message;
95163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkeyimport android.os.MessageQueue.IdleHandler;
96c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkeyimport android.os.RemoteCallbackList;
97a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.os.RemoteException;
983a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkeyimport android.provider.Settings;
9922c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkeyimport android.telephony.TelephonyManager;
100497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport android.text.format.Formatter;
10122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkeyimport android.text.format.Time;
102b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkeyimport android.util.Log;
10321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.util.NtpTrustedTime;
104a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.util.Slog;
105d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport android.util.SparseArray;
106d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport android.util.SparseBooleanArray;
107d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport android.util.SparseIntArray;
10821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.util.TrustedTime;
10921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.util.Xml;
110d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
111497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport com.android.internal.R;
11221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport com.android.internal.os.AtomicFile;
11321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport com.android.internal.util.FastXmlSerializer;
1148e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkeyimport com.android.internal.util.Objects;
11521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport com.google.android.collect.Lists;
11621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport com.google.android.collect.Maps;
117fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkeyimport com.google.android.collect.Sets;
11821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
11921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport org.xmlpull.v1.XmlPullParser;
12021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport org.xmlpull.v1.XmlPullParserException;
12121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport org.xmlpull.v1.XmlSerializer;
12221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
12321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.io.File;
1241b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkeyimport java.io.FileDescriptor;
12521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.io.FileInputStream;
12621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.io.FileNotFoundException;
12721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.io.FileOutputStream;
12821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.io.IOException;
1291b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkeyimport java.io.PrintWriter;
13021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.net.ProtocolException;
13121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.util.ArrayList;
13221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.util.Arrays;
13321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.util.HashMap;
134fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkeyimport java.util.HashSet;
135b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkeyimport java.util.List;
13647eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkeyimport java.util.Map;
13721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
13821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport libcore.io.IoUtils;
1391b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
140d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey/**
1418e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey * Service that maintains low-level network policy rules, using
1428e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey * {@link NetworkStatsService} statistics to drive those rules.
143c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey * <p>
144c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey * Derives active rules by combining a given policy with other system status,
145c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey * and delivers to listeners, such as {@link ConnectivityManager}, for
146c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey * enforcement.
147d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey */
148d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeypublic class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
149d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    private static final String TAG = "NetworkPolicy";
150d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    private static final boolean LOGD = true;
15122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private static final boolean LOGV = false;
152d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
15341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private static final int VERSION_INIT = 1;
15441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private static final int VERSION_ADDED_SNOOZE = 2;
1554664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey    private static final int VERSION_ADDED_RESTRICT_BACKGROUND = 3;
15621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
15722c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private static final long KB_IN_BYTES = 1024;
15822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
15922c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
16022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
16141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    // @VisibleForTesting
16241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    public static final int TYPE_WARNING = 0x1;
16341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    public static final int TYPE_LIMIT = 0x2;
16441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    public static final int TYPE_LIMIT_SNOOZED = 0x3;
165497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
16621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String TAG_POLICY_LIST = "policy-list";
16721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String TAG_NETWORK_POLICY = "network-policy";
16821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String TAG_UID_POLICY = "uid-policy";
16921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
17021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_VERSION = "version";
1714664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey    private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground";
17221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate";
17321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_SUBSCRIBER_ID = "subscriberId";
17421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_CYCLE_DAY = "cycleDay";
17521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_WARNING_BYTES = "warningBytes";
17621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_LIMIT_BYTES = "limitBytes";
17741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private static final String ATTR_LAST_SNOOZE = "lastSnooze";
17821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_UID = "uid";
17921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_POLICY = "policy";
18021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
1813a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    private static final String TAG_ALLOW_BACKGROUND = TAG + ":allowBackground";
1823a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
1833a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    // @VisibleForTesting
1843a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    public static final String ACTION_ALLOW_BACKGROUND =
1853a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            "com.android.server.action.ACTION_ALLOW_BACKGROUND";
1863a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
18721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
18821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
1896f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey    private static final int MSG_RULES_CHANGED = 1;
1906f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey    private static final int MSG_METERED_IFACES_CHANGED = 2;
1916f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey    private static final int MSG_FOREGROUND_ACTIVITIES_CHANGED = 3;
1926f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey    private static final int MSG_PROCESS_DIED = 4;
1937e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey    private static final int MSG_LIMIT_REACHED = 5;
1944414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey
19575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private final Context mContext;
19675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private final IActivityManager mActivityManager;
19775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private final IPowerManager mPowerManager;
19875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private final INetworkStatsService mNetworkStats;
19941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private final INetworkManagementService mNetworkManager;
20021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private final TrustedTime mTime;
20121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
20221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private IConnectivityManager mConnManager;
203497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private INotificationManager mNotifManager;
204a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
20575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private final Object mRulesLock = new Object();
206a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
2073a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    private volatile boolean mScreenOn;
2083a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    private volatile boolean mRestrictBackground;
209d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
2108e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    private final boolean mSuppressDefaultPolicy;
2118e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
21241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    /** Defined network policies. */
21341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private HashMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = Maps.newHashMap();
21441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    /** Currently active network rules for ifaces. */
21502e21d6a5b5117d494777a36783909854854f751Jeff Sharkey    private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap();
21622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
21741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    /** Defined UID policies. */
218a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    private SparseIntArray mUidPolicy = new SparseIntArray();
21941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    /** Currently derived rules for each UID. */
220c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    private SparseIntArray mUidRules = new SparseIntArray();
221d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
222fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey    /** Set of ifaces that are metered. */
223fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey    private HashSet<String> mMeteredIfaces = Sets.newHashSet();
22441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    /** Set of over-limit templates that have been notified. */
22541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private HashSet<NetworkTemplate> mOverLimitNotified = Sets.newHashSet();
226fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey
2278e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    /** Set of currently active {@link Notification} tags. */
2288e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    private HashSet<String> mActiveNotifs = Sets.newHashSet();
2298e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
230d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    /** Foreground at both UID and PID granularity. */
231a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    private SparseBooleanArray mUidForeground = new SparseBooleanArray();
232a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
233a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            SparseBooleanArray>();
234d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
235c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
236c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey            INetworkPolicyListener>();
237c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
23821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private final HandlerThread mHandlerThread;
23921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private final Handler mHandler;
24021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
24121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private final AtomicFile mPolicyFile;
242d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
243c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    // TODO: keep whitelist of system-critical services that should never have
244c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    // rules enforced, such as system, phone, and radio UIDs.
245c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
24641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    // TODO: migrate notifications to SystemUI
24741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
24875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
24950fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma            IPowerManager powerManager, INetworkStatsService networkStats,
25050fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma            INetworkManagementService networkManagement) {
251b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        this(context, activityManager, powerManager, networkStats, networkManagement,
2528e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                NtpTrustedTime.getInstance(context), getSystemDir(), false);
25321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
25421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
25521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static File getSystemDir() {
25621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        return new File(Environment.getDataDirectory(), "system");
25721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
25821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
25921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
26050fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma            IPowerManager powerManager, INetworkStatsService networkStats,
2618e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            INetworkManagementService networkManagement, TrustedTime time, File systemDir,
2628e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            boolean suppressDefaultPolicy) {
263a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        mContext = checkNotNull(context, "missing context");
264a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        mActivityManager = checkNotNull(activityManager, "missing activityManager");
265a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        mPowerManager = checkNotNull(powerManager, "missing powerManager");
26675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        mNetworkStats = checkNotNull(networkStats, "missing networkStats");
26741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
26821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mTime = checkNotNull(time, "missing TrustedTime");
26921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
27021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mHandlerThread = new HandlerThread(TAG);
27121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mHandlerThread.start();
2724414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey        mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
27321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
2748e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        mSuppressDefaultPolicy = suppressDefaultPolicy;
2758e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
27621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
27721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
27821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
27921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    public void bindConnectivityManager(IConnectivityManager connManager) {
28021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
281a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    }
282d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
283497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    public void bindNotificationManager(INotificationManager notifManager) {
284497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        mNotifManager = checkNotNull(notifManager, "missing INotificationManager");
285497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    }
286497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
287a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    public void systemReady() {
28821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        synchronized (mRulesLock) {
28921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // read policy from disk
29021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            readPolicyLocked();
2914664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey
2924664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            if (mRestrictBackground) {
2934664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                updateRulesForRestrictBackgroundLocked();
2943a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey                updateNotificationsLocked();
2954664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            }
29621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
297d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
298a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        updateScreenOn();
299d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
300a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        try {
301a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            mActivityManager.registerProcessObserver(mProcessObserver);
30241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            mNetworkManager.registerObserver(mAlertObserver);
30341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        } catch (RemoteException e) {
304b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            // ignored; both services live in system_server
30541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        }
30641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
307a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        // TODO: traverse existing processes to know foreground state, or have
308a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        // activitymanager dispatch current state when new observer attached.
309d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
310a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        final IntentFilter screenFilter = new IntentFilter();
311a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        screenFilter.addAction(Intent.ACTION_SCREEN_ON);
312a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
31341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        mContext.registerReceiver(mScreenReceiver, screenFilter, null, mHandler);
314d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
31521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // watch for network interfaces to be claimed
316961e30458319cfd50e1892ba7dd14a1d0ebe4cc7Jeff Sharkey        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
317b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey        mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
318b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey
31902e21d6a5b5117d494777a36783909854854f751Jeff Sharkey        // listen for package/uid changes to update policy
32002e21d6a5b5117d494777a36783909854854f751Jeff Sharkey        final IntentFilter packageFilter = new IntentFilter();
32102e21d6a5b5117d494777a36783909854854f751Jeff Sharkey        packageFilter.addAction(ACTION_PACKAGE_ADDED);
32202e21d6a5b5117d494777a36783909854854f751Jeff Sharkey        packageFilter.addAction(ACTION_UID_REMOVED);
32302e21d6a5b5117d494777a36783909854854f751Jeff Sharkey        mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
32421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
325b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        // listen for stats update events
326497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
327497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        mContext.registerReceiver(
328497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
329497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
3303a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        // listen for restrict background changes from notifications
3313a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
3323a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
3333a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
334a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    }
335d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
336a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
337a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        @Override
338a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
3396f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey            mHandler.obtainMessage(MSG_FOREGROUND_ACTIVITIES_CHANGED,
3406f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                    pid, uid, foregroundActivities).sendToTarget();
341d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        }
342d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
343a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        @Override
344a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        public void onProcessDied(int pid, int uid) {
3456f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey            mHandler.obtainMessage(MSG_PROCESS_DIED, pid, uid).sendToTarget();
346a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        }
347a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    };
348a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
349a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
350a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        @Override
351a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        public void onReceive(Context context, Intent intent) {
352a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            synchronized (mRulesLock) {
353a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                // screen-related broadcasts are protected by system, no need
354a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                // for permissions check.
355a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                updateScreenOn();
356a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            }
357a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        }
358a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    };
359d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
36002e21d6a5b5117d494777a36783909854854f751Jeff Sharkey    private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
361b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey        @Override
362b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey        public void onReceive(Context context, Intent intent) {
36302e21d6a5b5117d494777a36783909854854f751Jeff Sharkey            // on background handler thread, and PACKAGE_ADDED and UID_REMOVED
36402e21d6a5b5117d494777a36783909854854f751Jeff Sharkey            // are protected broadcasts.
36502e21d6a5b5117d494777a36783909854854f751Jeff Sharkey
36602e21d6a5b5117d494777a36783909854854f751Jeff Sharkey            final String action = intent.getAction();
367b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey            final int uid = intent.getIntExtra(EXTRA_UID, 0);
368b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey            synchronized (mRulesLock) {
36902e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                if (ACTION_PACKAGE_ADDED.equals(action)) {
37002e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                    // update rules for UID, since it might be subject to
37102e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                    // global background data policy.
37202e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                    if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
37302e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                    updateRulesForUidLocked(uid);
37402e21d6a5b5117d494777a36783909854854f751Jeff Sharkey
37502e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                } else if (ACTION_UID_REMOVED.equals(action)) {
37602e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                    // remove any policy and update rules to clean up.
37702e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                    if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
37802e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                    mUidPolicy.delete(uid);
37902e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                    updateRulesForUidLocked(uid);
38002e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                    writePolicyLocked();
38102e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                }
382b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey            }
383b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey        }
384b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey    };
385b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey
38621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    /**
387497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * Receiver that watches for {@link INetworkStatsService} updates, which we
388497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * use to check against {@link NetworkPolicy#warningBytes}.
389497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     */
390497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() {
391497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        @Override
392497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        public void onReceive(Context context, Intent intent) {
393497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            // on background handler thread, and verified
394497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            // READ_NETWORK_USAGE_HISTORY permission above.
395497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
396684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey            maybeRefreshTrustedTime();
397497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            synchronized (mRulesLock) {
3988e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                updateNetworkEnabledLocked();
399497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                updateNotificationsLocked();
400497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            }
401497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        }
402497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    };
403497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
404497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    /**
4053a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey     * Receiver that watches for {@link Notification} control of
4063a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey     * {@link #mRestrictBackground}.
4073a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey     */
4083a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    private BroadcastReceiver mAllowReceiver = new BroadcastReceiver() {
4093a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        @Override
4103a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        public void onReceive(Context context, Intent intent) {
4113a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            // on background handler thread, and verified MANAGE_NETWORK_POLICY
4123a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            // permission above.
4133a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
4143a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            setRestrictBackground(false);
4153a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        }
4163a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    };
4173a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
4183a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    /**
41941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey     * Observer that watches for {@link INetworkManagementService} alerts.
42041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey     */
42141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() {
42241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        @Override
42341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        public void limitReached(String limitName, String iface) {
42441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            // only someone like NMS should be calling us
42541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
42641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
4277e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey            if (!LIMIT_GLOBAL_ALERT.equals(limitName)) {
4287e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                mHandler.obtainMessage(MSG_LIMIT_REACHED, iface).sendToTarget();
42941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            }
43041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        }
43141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    };
43241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
43341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    /**
434497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * Check {@link NetworkPolicy} against current {@link INetworkStatsService}
435497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * to show visible notifications as needed.
436497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     */
437497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private void updateNotificationsLocked() {
438497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        if (LOGV) Slog.v(TAG, "updateNotificationsLocked()");
439497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
4408e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        // keep track of previously active notifications
4418e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        final HashSet<String> beforeNotifs = Sets.newHashSet();
4428e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        beforeNotifs.addAll(mActiveNotifs);
4438e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        mActiveNotifs.clear();
444497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
445497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        // TODO: when switching to kernel notifications, compute next future
446497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        // cycle boundary to recompute notifications.
447497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
44802e21d6a5b5117d494777a36783909854854f751Jeff Sharkey        // examine stats for each active policy
449684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey        final long currentTime = currentTimeMillis();
4508e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        for (NetworkPolicy policy : mNetworkPolicy.values()) {
4518e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            // ignore policies that aren't relevant to user
4528e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            if (!isTemplateRelevant(policy.template)) continue;
4538e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
454497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            final long start = computeLastCycleBoundary(currentTime, policy);
455497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            final long end = currentTime;
4568e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            final long totalBytes = getTotalBytes(policy.template, start, end);
457497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
45850e7e51d68e3b01c3362fe9ab7b3448132e48b43Jeff Sharkey            if (policy.isOverLimit(totalBytes)) {
45941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                if (policy.lastSnooze >= start) {
46041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                    enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
46141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                } else {
46241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                    enqueueNotification(policy, TYPE_LIMIT, totalBytes);
46341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                    notifyOverLimitLocked(policy.template);
46441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                }
46541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
466497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            } else {
46741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                notifyUnderLimitLocked(policy.template);
468497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
46941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                if (policy.warningBytes != WARNING_DISABLED && totalBytes >= policy.warningBytes) {
47041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                    enqueueNotification(policy, TYPE_WARNING, totalBytes);
471497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                }
472497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            }
47302e21d6a5b5117d494777a36783909854854f751Jeff Sharkey        }
47402e21d6a5b5117d494777a36783909854854f751Jeff Sharkey
4753a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        // ongoing notification when restricting background data
4763a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        if (mRestrictBackground) {
4773a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            enqueueRestrictedNotification(TAG_ALLOW_BACKGROUND);
4783a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        }
4798e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
4808e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        // cancel stale notifications that we didn't renew above
4818e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        for (String tag : beforeNotifs) {
4828e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            if (!mActiveNotifs.contains(tag)) {
4838e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                cancelNotification(tag);
4848e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            }
4858e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        }
4868e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    }
4878e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
4888e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    /**
4898e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey     * Test if given {@link NetworkTemplate} is relevant to user based on
4908e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey     * current device state, such as when {@link #getActiveSubscriberId()}
4918e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey     * matches. This is regardless of data connection status.
4928e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey     */
4938e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    private boolean isTemplateRelevant(NetworkTemplate template) {
4948e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        switch (template.getMatchRule()) {
4958e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            case MATCH_MOBILE_3G_LOWER:
4968e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            case MATCH_MOBILE_4G:
4978e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            case MATCH_MOBILE_ALL:
4988e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                // mobile templates are relevant when subscriberid is active
4998e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                return Objects.equal(getActiveSubscriberId(), template.getSubscriberId());
5008e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        }
5018e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        return true;
502497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    }
503497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
504497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    /**
50541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey     * Notify that given {@link NetworkTemplate} is over
50641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey     * {@link NetworkPolicy#limitBytes}, potentially showing dialog to user.
50741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey     */
50841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private void notifyOverLimitLocked(NetworkTemplate template) {
50941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        if (!mOverLimitNotified.contains(template)) {
51041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            mContext.startActivity(buildNetworkOverLimitIntent(template));
51141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            mOverLimitNotified.add(template);
51241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        }
51341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    }
51441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
51541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private void notifyUnderLimitLocked(NetworkTemplate template) {
51641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        mOverLimitNotified.remove(template);
51741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    }
51841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
51941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    /**
520497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * Build unique tag that identifies an active {@link NetworkPolicy}
521497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * notification of a specific type, like {@link #TYPE_LIMIT}.
522497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     */
523497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private String buildNotificationTag(NetworkPolicy policy, int type) {
5241b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        return TAG + ":" + policy.template.hashCode() + ":" + type;
525497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    }
526497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
527497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    /**
528497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * Show notification for combined {@link NetworkPolicy} and specific type,
529497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * like {@link #TYPE_LIMIT}. Okay to call multiple times.
530497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     */
53141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes) {
532497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        final String tag = buildNotificationTag(policy, type);
533497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        final Notification.Builder builder = new Notification.Builder(mContext);
534497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        builder.setOnlyAlertOnce(true);
535497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        builder.setOngoing(true);
536497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
537497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        final Resources res = mContext.getResources();
538497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        switch (type) {
539497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            case TYPE_WARNING: {
54041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                final CharSequence title = res.getText(R.string.data_usage_warning_title);
5418ca953da93eb8679574abba535f75f72d50016f2Jeff Sharkey                final CharSequence body = res.getString(R.string.data_usage_warning_body);
542497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
54350e7e51d68e3b01c3362fe9ab7b3448132e48b43Jeff Sharkey                builder.setSmallIcon(R.drawable.stat_notify_error);
544497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setTicker(title);
545497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setContentTitle(title);
546497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setContentText(body);
54714711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey
54841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                final Intent intent = buildViewDataUsageIntent(policy.template);
54914711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey                builder.setContentIntent(PendingIntent.getActivity(
55014711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
551497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                break;
552497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            }
553497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            case TYPE_LIMIT: {
55441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                final CharSequence body = res.getText(R.string.data_usage_limit_body);
55541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
55641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                final CharSequence title;
5571b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                switch (policy.template.getMatchRule()) {
5581b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                    case MATCH_MOBILE_3G_LOWER:
55941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        title = res.getText(R.string.data_usage_3g_limit_title);
560497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        break;
5611b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                    case MATCH_MOBILE_4G:
56241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        title = res.getText(R.string.data_usage_4g_limit_title);
563497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        break;
5648e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    case MATCH_MOBILE_ALL:
56541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        title = res.getText(R.string.data_usage_mobile_limit_title);
566497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        break;
5678e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    case MATCH_WIFI:
5688e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                        title = res.getText(R.string.data_usage_wifi_limit_title);
5698e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                        break;
5708e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    default:
5718e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                        title = null;
5728e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                        break;
573497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                }
574497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
57550e7e51d68e3b01c3362fe9ab7b3448132e48b43Jeff Sharkey                builder.setSmallIcon(R.drawable.stat_notify_disabled);
576497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setTicker(title);
577497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setContentTitle(title);
578497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setContentText(body);
57914711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey
58041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                final Intent intent = buildNetworkOverLimitIntent(policy.template);
58141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                builder.setContentIntent(PendingIntent.getActivity(
58241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
58341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                break;
58441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            }
58541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            case TYPE_LIMIT_SNOOZED: {
58641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                final long overBytes = totalBytes - policy.limitBytes;
58741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                final CharSequence body = res.getString(R.string.data_usage_limit_snoozed_body,
58841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        Formatter.formatFileSize(mContext, overBytes));
58941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
59041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                final CharSequence title;
59141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                switch (policy.template.getMatchRule()) {
59241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                    case MATCH_MOBILE_3G_LOWER:
59341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        title = res.getText(R.string.data_usage_3g_limit_snoozed_title);
59441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        break;
59541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                    case MATCH_MOBILE_4G:
59641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        title = res.getText(R.string.data_usage_4g_limit_snoozed_title);
59741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        break;
5988e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    case MATCH_MOBILE_ALL:
59941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        title = res.getText(R.string.data_usage_mobile_limit_snoozed_title);
60041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        break;
6018e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    case MATCH_WIFI:
6028e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                        title = res.getText(R.string.data_usage_wifi_limit_snoozed_title);
6038e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                        break;
6048e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    default:
6058e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                        title = null;
6068e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                        break;
60741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                }
60841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
60950e7e51d68e3b01c3362fe9ab7b3448132e48b43Jeff Sharkey                builder.setSmallIcon(R.drawable.stat_notify_error);
61041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                builder.setTicker(title);
61141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                builder.setContentTitle(title);
61241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                builder.setContentText(body);
61341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
61441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                final Intent intent = buildViewDataUsageIntent(policy.template);
61514711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey                builder.setContentIntent(PendingIntent.getActivity(
61614711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
617497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                break;
618497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            }
619497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        }
620497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
621497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        // TODO: move to NotificationManager once we can mock it
622497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        try {
623497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            final String packageName = mContext.getPackageName();
624497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            final int[] idReceived = new int[1];
625497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            mNotifManager.enqueueNotificationWithTag(
626497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                    packageName, tag, 0x0, builder.getNotification(), idReceived);
6278e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            mActiveNotifs.add(tag);
628497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        } catch (RemoteException e) {
629b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            // ignored; service lives in system_server
630497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        }
631497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    }
632497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
633497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    /**
6343a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey     * Show ongoing notification to reflect that {@link #mRestrictBackground}
6353a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey     * has been enabled.
6363a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey     */
6373a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    private void enqueueRestrictedNotification(String tag) {
6383a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        final Resources res = mContext.getResources();
6393a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        final Notification.Builder builder = new Notification.Builder(mContext);
6403a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
6413a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        final CharSequence title = res.getText(R.string.data_usage_restricted_title);
6423a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        final CharSequence body = res.getString(R.string.data_usage_restricted_body);
6433a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
6443a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        builder.setOnlyAlertOnce(true);
6453a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        builder.setOngoing(true);
64650e7e51d68e3b01c3362fe9ab7b3448132e48b43Jeff Sharkey        builder.setSmallIcon(R.drawable.stat_notify_error);
6473a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        builder.setTicker(title);
6483a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        builder.setContentTitle(title);
6493a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        builder.setContentText(body);
6503a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
6513a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        final Intent intent = buildAllowBackgroundDataIntent();
6523a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        builder.setContentIntent(
6533a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey                PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
6543a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
6553a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        // TODO: move to NotificationManager once we can mock it
6563a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        try {
6573a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            final String packageName = mContext.getPackageName();
6583a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            final int[] idReceived = new int[1];
6593a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            mNotifManager.enqueueNotificationWithTag(packageName, tag,
6603a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey                    0x0, builder.getNotification(), idReceived);
6618e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            mActiveNotifs.add(tag);
6623a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        } catch (RemoteException e) {
663b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            // ignored; service lives in system_server
6643a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        }
6653a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    }
6663a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
6673a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    private void cancelNotification(String tag) {
668497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        // TODO: move to NotificationManager once we can mock it
669497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        try {
670497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            final String packageName = mContext.getPackageName();
6713a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            mNotifManager.cancelNotificationWithTag(
6723a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey                    packageName, tag, 0x0);
673497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        } catch (RemoteException e) {
674b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            // ignored; service lives in system_server
675497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        }
676497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    }
677497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
678497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    /**
67921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     * Receiver that watches for {@link IConnectivityManager} to claim network
68022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey     * interfaces. Used to apply {@link NetworkPolicy} to matching networks.
68121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     */
682b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey    private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
68321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        @Override
68421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        public void onReceive(Context context, Intent intent) {
68521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // on background handler thread, and verified CONNECTIVITY_INTERNAL
68621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // permission above.
687684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey
688684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey            maybeRefreshTrustedTime();
68921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            synchronized (mRulesLock) {
69022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                ensureActiveMobilePolicyLocked();
6918e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                updateNetworkEnabledLocked();
69202e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                updateNetworkRulesLocked();
69302e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                updateNotificationsLocked();
69421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
69521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
69621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    };
69721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
69821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    /**
6998e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey     * Proactively control network data connections when they exceed
7008e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey     * {@link NetworkPolicy#limitBytes}.
7018e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey     */
7028e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    private void updateNetworkEnabledLocked() {
7038e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        if (LOGV) Slog.v(TAG, "updateNetworkEnabledLocked()");
7048e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
7058e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        // TODO: reset any policy-disabled networks when any policy is removed
7068e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        // completely, which is currently rare case.
7078e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
708684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey        final long currentTime = currentTimeMillis();
7098e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        for (NetworkPolicy policy : mNetworkPolicy.values()) {
7108e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            // shortcut when policy has no limit
7118e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            if (policy.limitBytes == LIMIT_DISABLED) {
7128e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                setNetworkTemplateEnabled(policy.template, true);
7138e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                continue;
7148e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            }
7158e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
7168e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            final long start = computeLastCycleBoundary(currentTime, policy);
7178e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            final long end = currentTime;
7188e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            final long totalBytes = getTotalBytes(policy.template, start, end);
7198e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
7208e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            // disable data connection when over limit and not snoozed
72150e7e51d68e3b01c3362fe9ab7b3448132e48b43Jeff Sharkey            final boolean overLimit = policy.isOverLimit(totalBytes) && policy.lastSnooze < start;
7228e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey            final boolean enabled = !overLimit;
7238e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey
7248e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey            setNetworkTemplateEnabled(policy.template, enabled);
7258e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        }
7268e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    }
7278e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
7288e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    /**
7298e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey     * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}
7308e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey     * for the given {@link NetworkTemplate}.
7318e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey     */
7328e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) {
7338e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        switch (template.getMatchRule()) {
7348e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            case MATCH_MOBILE_3G_LOWER:
7358e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            case MATCH_MOBILE_4G:
7368e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            case MATCH_MOBILE_ALL:
7378e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                // TODO: offer more granular control over radio states once
7388e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                // 4965893 is available.
7398e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                if (Objects.equal(getActiveSubscriberId(), template.getSubscriberId())) {
7408e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    setPolicyDataEnable(TYPE_MOBILE, enabled);
7418e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    setPolicyDataEnable(TYPE_WIMAX, enabled);
7428e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                }
7438e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                break;
7448e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            case MATCH_WIFI:
7458e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                setPolicyDataEnable(TYPE_WIFI, enabled);
7468e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                break;
7478e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            case MATCH_ETHERNET:
7488e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                setPolicyDataEnable(TYPE_ETHERNET, enabled);
7498e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                break;
7508e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            default:
7518e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                throw new IllegalArgumentException("unexpected template");
7528e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        }
7538e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    }
7548e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
7558e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    /**
75621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     * Examine all connected {@link NetworkState}, looking for
75721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     * {@link NetworkPolicy} that need to be enforced. When matches found, set
75821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     * remaining quota based on usage cycle and historical stats.
75921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     */
76002e21d6a5b5117d494777a36783909854854f751Jeff Sharkey    private void updateNetworkRulesLocked() {
76122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
76221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
76321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        final NetworkState[] states;
76421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        try {
76521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            states = mConnManager.getAllNetworkState();
76621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } catch (RemoteException e) {
767b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            // ignored; service lives in system_server
76821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            return;
76921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
77021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
77121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // first, derive identity for all connected networks, which can be used
77221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // to match against templates.
77321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        final HashMap<NetworkIdentity, String> networks = Maps.newHashMap();
77421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        for (NetworkState state : states) {
77521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // stash identity and iface away for later use
77621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            if (state.networkInfo.isConnected()) {
77721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                final String iface = state.linkProperties.getInterfaceName();
77821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
77921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                networks.put(ident, iface);
78021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
78121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
78221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
78321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // build list of rules and ifaces to enforce them against
78402e21d6a5b5117d494777a36783909854854f751Jeff Sharkey        mNetworkRules.clear();
78521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        final ArrayList<String> ifaceList = Lists.newArrayList();
78641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        for (NetworkPolicy policy : mNetworkPolicy.values()) {
78721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
78821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // collect all active ifaces that match this template
78921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            ifaceList.clear();
79047eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            for (Map.Entry<NetworkIdentity, String> entry : networks.entrySet()) {
79147eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey                final NetworkIdentity ident = entry.getKey();
7921b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                if (policy.template.matches(ident)) {
79347eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey                    final String iface = entry.getValue();
79421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                    ifaceList.add(iface);
79521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                }
79621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
79721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
79821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            if (ifaceList.size() > 0) {
79921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
80002e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                mNetworkRules.put(policy, ifaces);
80121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
80221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
80321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
804b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        final HashSet<String> newMeteredIfaces = Sets.newHashSet();
805fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey
80621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // apply each policy that we found ifaces for; compute remaining data
80721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // based on current cycle and historical stats, and push to kernel.
808684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey        final long currentTime = currentTimeMillis();
80902e21d6a5b5117d494777a36783909854854f751Jeff Sharkey        for (NetworkPolicy policy : mNetworkRules.keySet()) {
81002e21d6a5b5117d494777a36783909854854f751Jeff Sharkey            final String[] ifaces = mNetworkRules.get(policy);
81121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
81221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            final long start = computeLastCycleBoundary(currentTime, policy);
81321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            final long end = currentTime;
8148e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            final long totalBytes = getTotalBytes(policy.template, start, end);
81521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
81621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            if (LOGD) {
81721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
81822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                        + Arrays.toString(ifaces));
81922c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            }
82022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
82141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED;
8223a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            if (hasLimit) {
8238e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                final long quotaBytes;
8248e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                if (policy.lastSnooze >= start) {
8258e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    // snoozing past quota, but we still need to restrict apps,
8268e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    // so push really high quota.
8278e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    quotaBytes = Long.MAX_VALUE;
8288e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                } else {
8298e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    // remaining "quota" bytes are based on total usage in
8308e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    // current cycle. kernel doesn't like 0-byte rules, so we
8318e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    // set 1-byte quota and disable the radio later.
8328e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    quotaBytes = Math.max(1, policy.limitBytes - totalBytes);
8338e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                }
83450fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma
835b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                if (ifaces.length > 1) {
836b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                    // TODO: switch to shared quota once NMS supports
837b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                    Slog.w(TAG, "shared quota unsupported; generating rule for each iface");
838b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                }
839fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey
840fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey                for (String iface : ifaces) {
841b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                    removeInterfaceQuota(iface);
8428e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    setInterfaceQuota(iface, quotaBytes);
8438e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey                    newMeteredIfaces.add(iface);
84441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                }
84541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            }
84622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        }
847fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey
848b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        // remove quota on any trailing interfaces
849b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        for (String iface : mMeteredIfaces) {
850b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            if (!newMeteredIfaces.contains(iface)) {
851b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey                removeInterfaceQuota(iface);
85250fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma            }
85350fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma        }
854b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        mMeteredIfaces = newMeteredIfaces;
855b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
856b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
857b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
85850fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma    }
85950fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma
86022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    /**
86122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey     * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
86222c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey     * have at least a default mobile policy defined.
86322c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey     */
86422c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private void ensureActiveMobilePolicyLocked() {
86522c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()");
8668e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        if (mSuppressDefaultPolicy) return;
8678e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
86822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        final String subscriberId = getActiveSubscriberId();
8691b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        final NetworkIdentity probeIdent = new NetworkIdentity(
8705dc0c26cffbbc62ff84f9f4c8a451e68e2c05d2dJeff Sharkey                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, false);
87122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
87222c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        // examine to see if any policy is defined for active mobile
87322c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        boolean mobileDefined = false;
87441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        for (NetworkPolicy policy : mNetworkPolicy.values()) {
8751b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey            if (policy.template.matches(probeIdent)) {
87622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                mobileDefined = true;
87721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
87822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        }
87921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
88022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        if (!mobileDefined) {
88122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            Slog.i(TAG, "no policy for active mobile network; generating default policy");
88221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
88302e21d6a5b5117d494777a36783909854854f751Jeff Sharkey            // build default mobile policy, and assume usage cycle starts today
88402e21d6a5b5117d494777a36783909854854f751Jeff Sharkey            final long warningBytes = mContext.getResources().getInteger(
88502e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                    com.android.internal.R.integer.config_networkPolicyDefaultWarning)
88602e21d6a5b5117d494777a36783909854854f751Jeff Sharkey                    * MB_IN_BYTES;
88722c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
88822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            final Time time = new Time(Time.TIMEZONE_UTC);
88922c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            time.setToNow();
89022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            final int cycleDay = time.monthDay;
89122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
8924e814c348ce205fcc1a273427f95ef1d100ed60cJeff Sharkey            final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
89341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            mNetworkPolicy.put(template, new NetworkPolicy(
89441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                    template, cycleDay, warningBytes, LIMIT_DISABLED, SNOOZE_NEVER));
895fcc79771f092f34505b1accb80365cbcaa379667Jeff Sharkey            writePolicyLocked();
89621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
89721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
89821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
89921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private void readPolicyLocked() {
90022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        if (LOGV) Slog.v(TAG, "readPolicyLocked()");
90121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
90221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // clear any existing policy and read from disk
90322c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        mNetworkPolicy.clear();
90421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mUidPolicy.clear();
90521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
90621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        FileInputStream fis = null;
90721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        try {
90821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            fis = mPolicyFile.openRead();
90921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            final XmlPullParser in = Xml.newPullParser();
91021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            in.setInput(fis, null);
91121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
91221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            int type;
91341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            int version = VERSION_INIT;
91421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            while ((type = in.next()) != END_DOCUMENT) {
91521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                final String tag = in.getName();
91621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                if (type == START_TAG) {
91721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                    if (TAG_POLICY_LIST.equals(tag)) {
91821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        version = readIntAttribute(in, ATTR_VERSION);
9194664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                        if (version >= VERSION_ADDED_RESTRICT_BACKGROUND) {
9204664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                            mRestrictBackground = readBooleanAttribute(
9214664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                                    in, ATTR_RESTRICT_BACKGROUND);
9224664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                        } else {
9233a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey                            mRestrictBackground = false;
9244664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                        }
92521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
92621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                    } else if (TAG_NETWORK_POLICY.equals(tag)) {
92721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
92821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID);
92921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
93021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
93121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
93241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        final long lastSnooze;
93341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        if (version >= VERSION_ADDED_SNOOZE) {
93441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                            lastSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
93541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        } else {
93641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                            lastSnooze = SNOOZE_NEVER;
93741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        }
93821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
9391b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                        final NetworkTemplate template = new NetworkTemplate(
9401b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                                networkTemplate, subscriberId);
94141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                        mNetworkPolicy.put(template, new NetworkPolicy(
94241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                                template, cycleDay, warningBytes, limitBytes, lastSnooze));
94321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
94421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                    } else if (TAG_UID_POLICY.equals(tag)) {
94521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final int uid = readIntAttribute(in, ATTR_UID);
94621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final int policy = readIntAttribute(in, ATTR_POLICY);
94721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
948497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        if (isUidValidForPolicy(mContext, uid)) {
949497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                            setUidPolicyUnchecked(uid, policy, false);
950497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        } else {
951497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                            Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
952497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        }
95321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                    }
95421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                }
95521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
95621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
95721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } catch (FileNotFoundException e) {
95821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // missing policy is okay, probably first boot
9593a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            upgradeLegacyBackgroundData();
96021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } catch (IOException e) {
961b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            Log.wtf(TAG, "problem reading network policy", e);
96221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } catch (XmlPullParserException e) {
963b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            Log.wtf(TAG, "problem reading network policy", e);
96421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } finally {
96521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            IoUtils.closeQuietly(fis);
96621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
96721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
96821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
9693a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    /**
9703a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey     * Upgrade legacy background data flags, notifying listeners of one last
9713a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey     * change to always-true.
9723a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey     */
9733a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    private void upgradeLegacyBackgroundData() {
9743a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        mRestrictBackground = Settings.Secure.getInt(
9753a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey                mContext.getContentResolver(), Settings.Secure.BACKGROUND_DATA, 1) != 1;
9763a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
9773a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        // kick off one last broadcast if restricted
9783a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        if (mRestrictBackground) {
9793a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            final Intent broadcast = new Intent(
9803a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey                    ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
9813a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            mContext.sendBroadcast(broadcast);
9823a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        }
9833a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    }
9843a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
98521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private void writePolicyLocked() {
98622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        if (LOGV) Slog.v(TAG, "writePolicyLocked()");
98721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
98821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        FileOutputStream fos = null;
98921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        try {
99021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            fos = mPolicyFile.startWrite();
99121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
99221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            XmlSerializer out = new FastXmlSerializer();
99321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            out.setOutput(fos, "utf-8");
99421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            out.startDocument(null, true);
99521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
99621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            out.startTag(null, TAG_POLICY_LIST);
9974664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            writeIntAttribute(out, ATTR_VERSION, VERSION_ADDED_RESTRICT_BACKGROUND);
9984664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
99921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
100021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // write all known network policies
100141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            for (NetworkPolicy policy : mNetworkPolicy.values()) {
10021b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                final NetworkTemplate template = policy.template;
10031b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey
100421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                out.startTag(null, TAG_NETWORK_POLICY);
10051b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule());
10061b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                final String subscriberId = template.getSubscriberId();
10071b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                if (subscriberId != null) {
10081b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                    out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId);
100921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                }
101021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
101121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
101221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
101341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                writeLongAttribute(out, ATTR_LAST_SNOOZE, policy.lastSnooze);
101421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                out.endTag(null, TAG_NETWORK_POLICY);
101521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
101621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
101721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // write all known uid policies
101821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            for (int i = 0; i < mUidPolicy.size(); i++) {
101921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                final int uid = mUidPolicy.keyAt(i);
102021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                final int policy = mUidPolicy.valueAt(i);
102121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
1022497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                // skip writing empty policies
1023497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                if (policy == POLICY_NONE) continue;
1024497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
102521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                out.startTag(null, TAG_UID_POLICY);
102621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                writeIntAttribute(out, ATTR_UID, uid);
102721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                writeIntAttribute(out, ATTR_POLICY, policy);
102821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                out.endTag(null, TAG_UID_POLICY);
102921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
103021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
103121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            out.endTag(null, TAG_POLICY_LIST);
103221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            out.endDocument();
103321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
103421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            mPolicyFile.finishWrite(fos);
103521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } catch (IOException e) {
103621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            if (fos != null) {
103721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                mPolicyFile.failWrite(fos);
103821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
103921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
104021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
104121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
1042d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    @Override
1043d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    public void setUidPolicy(int uid, int policy) {
104421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1045a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
1046497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        if (!isUidValidForPolicy(mContext, uid)) {
1047497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            throw new IllegalArgumentException("cannot apply policy to UID " + uid);
1048497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        }
1049497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
1050497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        setUidPolicyUnchecked(uid, policy, true);
1051497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    }
1052497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
1053497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private void setUidPolicyUnchecked(int uid, int policy, boolean persist) {
1054c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        final int oldPolicy;
1055a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        synchronized (mRulesLock) {
1056c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey            oldPolicy = getUidPolicy(uid);
1057a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            mUidPolicy.put(uid, policy);
1058c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
105921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // uid policy changed, recompute rules and persist policy.
106021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            updateRulesForUidLocked(uid);
1061497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            if (persist) {
1062497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                writePolicyLocked();
1063497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            }
106421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
1065d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    }
1066d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
1067d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    @Override
1068d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    public int getUidPolicy(int uid) {
106921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
107021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
1071a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        synchronized (mRulesLock) {
1072a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            return mUidPolicy.get(uid, POLICY_NONE);
1073a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        }
1074d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    }
1075d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
1076c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    @Override
1077c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    public void registerListener(INetworkPolicyListener listener) {
10781a303953589fdddf21d88b8fa660136f5b060d0dJeff Sharkey        // TODO: create permission for observing network policy
10791a303953589fdddf21d88b8fa660136f5b060d0dJeff Sharkey        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
10801a303953589fdddf21d88b8fa660136f5b060d0dJeff Sharkey
1081c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        mListeners.register(listener);
1082c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
10834414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey        // TODO: consider dispatching existing rules to new listeners
1084c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    }
1085c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
1086c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    @Override
1087c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    public void unregisterListener(INetworkPolicyListener listener) {
10881a303953589fdddf21d88b8fa660136f5b060d0dJeff Sharkey        // TODO: create permission for observing network policy
10891a303953589fdddf21d88b8fa660136f5b060d0dJeff Sharkey        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
10901a303953589fdddf21d88b8fa660136f5b060d0dJeff Sharkey
1091c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        mListeners.unregister(listener);
1092c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    }
1093c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
10941b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    @Override
109522c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    public void setNetworkPolicies(NetworkPolicy[] policies) {
109621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
109721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
1098684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey        maybeRefreshTrustedTime();
109921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        synchronized (mRulesLock) {
110022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            mNetworkPolicy.clear();
110122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            for (NetworkPolicy policy : policies) {
110241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                mNetworkPolicy.put(policy.template, policy);
110322c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            }
110421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
11058e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            updateNetworkEnabledLocked();
110602e21d6a5b5117d494777a36783909854854f751Jeff Sharkey            updateNetworkRulesLocked();
1107497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            updateNotificationsLocked();
110821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            writePolicyLocked();
110921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
111021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
111121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
111221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    @Override
111322c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    public NetworkPolicy[] getNetworkPolicies() {
111421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
111522c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
111621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
111721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        synchronized (mRulesLock) {
111841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            return mNetworkPolicy.values().toArray(new NetworkPolicy[mNetworkPolicy.size()]);
111941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        }
112041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    }
112141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
112241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    @Override
112341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    public void snoozePolicy(NetworkTemplate template) {
112441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
112541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
1126684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey        maybeRefreshTrustedTime();
1127684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey        final long currentTime = currentTimeMillis();
112841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        synchronized (mRulesLock) {
112941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            // find and snooze local policy that matches
113041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            final NetworkPolicy policy = mNetworkPolicy.get(template);
113141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            if (policy == null) {
113241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                throw new IllegalArgumentException("unable to find policy for " + template);
113341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            }
113441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
113541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            policy.lastSnooze = currentTime;
113641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
11378e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            updateNetworkEnabledLocked();
113841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            updateNetworkRulesLocked();
113941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            updateNotificationsLocked();
114041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            writePolicyLocked();
114121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
114221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
114321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
114421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    @Override
11454664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey    public void setRestrictBackground(boolean restrictBackground) {
11464664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
11474664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey
1148684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey        maybeRefreshTrustedTime();
11494664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        synchronized (mRulesLock) {
11504664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            mRestrictBackground = restrictBackground;
11514664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            updateRulesForRestrictBackgroundLocked();
11523a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey            updateNotificationsLocked();
1153f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey            writePolicyLocked();
11544664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        }
11554664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey    }
11564664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey
11574664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey    @Override
11584664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey    public boolean getRestrictBackground() {
11594664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
11604664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey
11614664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        synchronized (mRulesLock) {
11624664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            return mRestrictBackground;
11634664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        }
11644664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey    }
11654664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey
1166f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey    private NetworkPolicy findPolicyForNetworkLocked(NetworkIdentity ident) {
1167f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        for (NetworkPolicy policy : mNetworkPolicy.values()) {
1168f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey            if (policy.template.matches(ident)) {
1169f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey                return policy;
1170f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey            }
1171f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        }
1172f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        return null;
1173f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey    }
1174f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
1175f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey    @Override
1176f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey    public NetworkQuotaInfo getNetworkQuotaInfo(NetworkState state) {
1177f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
1178f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
1179f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        // only returns usage summary, so we don't require caller to have
1180f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        // READ_NETWORK_USAGE_HISTORY.
1181f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        final long token = Binder.clearCallingIdentity();
1182f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        try {
1183f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey            return getNetworkQuotaInfoUnchecked(state);
1184f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        } finally {
1185f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey            Binder.restoreCallingIdentity(token);
1186f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        }
1187f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey    }
1188f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
1189f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey    private NetworkQuotaInfo getNetworkQuotaInfoUnchecked(NetworkState state) {
1190f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
1191f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
1192f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        final NetworkPolicy policy;
1193f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        synchronized (mRulesLock) {
1194f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey            policy = findPolicyForNetworkLocked(ident);
1195f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        }
1196f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
1197f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        if (policy == null) {
1198f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey            // missing policy means we can't derive useful quota info
1199f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey            return null;
1200f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        }
1201f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
1202684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey        final long currentTime = currentTimeMillis();
1203f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
1204b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        // find total bytes used under policy
1205f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        final long start = computeLastCycleBoundary(currentTime, policy);
1206f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        final long end = currentTime;
12078e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        final long totalBytes = getTotalBytes(policy.template, start, end);
1208f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
1209f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        // report soft and hard limits under policy
1210f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        final long softLimitBytes = policy.warningBytes != WARNING_DISABLED ? policy.warningBytes
1211f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey                : NetworkQuotaInfo.NO_LIMIT;
1212f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        final long hardLimitBytes = policy.limitBytes != LIMIT_DISABLED ? policy.limitBytes
1213f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey                : NetworkQuotaInfo.NO_LIMIT;
1214f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
1215f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey        return new NetworkQuotaInfo(totalBytes, softLimitBytes, hardLimitBytes);
1216f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey    }
1217f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
12184664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey    @Override
12191b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
122075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
12211b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
122241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        final HashSet<String> argSet = new HashSet<String>();
122341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        for (String arg : args) {
122441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            argSet.add(arg);
122541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        }
122641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
12271b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        synchronized (mRulesLock) {
122841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            if (argSet.contains("unsnooze")) {
122941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                for (NetworkPolicy policy : mNetworkPolicy.values()) {
123041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                    policy.lastSnooze = SNOOZE_NEVER;
123141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                }
123241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                writePolicyLocked();
123341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                fout.println("Wiped snooze timestamps");
123441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                return;
123541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            }
123641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
12374664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            fout.print("Restrict background: "); fout.println(mRestrictBackground);
123821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            fout.println("Network policies:");
123941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            for (NetworkPolicy policy : mNetworkPolicy.values()) {
124022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                fout.print("  "); fout.println(policy.toString());
124121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
124221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
12431b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            fout.println("Policy status for known UIDs:");
12441b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
12451b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            final SparseBooleanArray knownUids = new SparseBooleanArray();
12461b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            collectKeys(mUidPolicy, knownUids);
12471b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            collectKeys(mUidForeground, knownUids);
12481b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            collectKeys(mUidRules, knownUids);
12491b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
12501b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            final int size = knownUids.size();
12511b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            for (int i = 0; i < size; i++) {
12521b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                final int uid = knownUids.keyAt(i);
12531b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                fout.print("  UID=");
12541b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                fout.print(uid);
12551b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
12561b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                fout.print(" policy=");
12571b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                final int policyIndex = mUidPolicy.indexOfKey(uid);
12581b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                if (policyIndex < 0) {
12591b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                    fout.print("UNKNOWN");
12601b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                } else {
12611b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                    dumpPolicy(fout, mUidPolicy.valueAt(policyIndex));
12621b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                }
12631b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
12641b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                fout.print(" foreground=");
12651b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                final int foregroundIndex = mUidPidForeground.indexOfKey(uid);
12661b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                if (foregroundIndex < 0) {
12671b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                    fout.print("UNKNOWN");
12681b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                } else {
12691b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                    dumpSparseBooleanArray(fout, mUidPidForeground.valueAt(foregroundIndex));
12701b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                }
12711b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
12721b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                fout.print(" rules=");
12731b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                final int rulesIndex = mUidRules.indexOfKey(uid);
12741b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                if (rulesIndex < 0) {
12751b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                    fout.print("UNKNOWN");
12761b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                } else {
12771b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                    dumpRules(fout, mUidRules.valueAt(rulesIndex));
12781b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                }
12791b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
12801b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                fout.println();
12811b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            }
12821b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        }
12831b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    }
12849599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey
12859599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey    @Override
12869599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey    public boolean isUidForeground(int uid) {
1287497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1288497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
12899599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey        synchronized (mRulesLock) {
12909599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey            // only really in foreground when screen is also on
12919599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey            return mUidForeground.get(uid, false) && mScreenOn;
12929599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey        }
1293c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    }
1294c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
1295d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    /**
1296d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey     * Foreground for PID changed; recompute foreground at UID level. If
129721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     * changed, will trigger {@link #updateRulesForUidLocked(int)}.
1298d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey     */
129921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private void computeUidForegroundLocked(int uid) {
1300d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
1301d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
1302d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        // current pid is dropping foreground; examine other pids
1303d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        boolean uidForeground = false;
1304d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        final int size = pidForeground.size();
1305d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        for (int i = 0; i < size; i++) {
1306d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey            if (pidForeground.valueAt(i)) {
1307d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey                uidForeground = true;
1308d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey                break;
1309d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey            }
1310d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        }
1311d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
1312d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        final boolean oldUidForeground = mUidForeground.get(uid, false);
1313d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        if (oldUidForeground != uidForeground) {
1314d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey            // foreground changed, push updated rules
1315d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey            mUidForeground.put(uid, uidForeground);
131621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            updateRulesForUidLocked(uid);
1317a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        }
1318a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    }
1319a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
1320a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    private void updateScreenOn() {
1321a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        synchronized (mRulesLock) {
1322a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            try {
1323a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                mScreenOn = mPowerManager.isScreenOn();
1324a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            } catch (RemoteException e) {
1325b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey                // ignored; service lives in system_server
1326a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            }
132721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            updateRulesForScreenLocked();
1328d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        }
1329d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    }
1330d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
1331a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    /**
1332a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey     * Update rules that might be changed by {@link #mScreenOn} value.
1333a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey     */
133421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private void updateRulesForScreenLocked() {
1335a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        // only update rules for anyone with foreground activities
1336a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        final int size = mUidForeground.size();
1337a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        for (int i = 0; i < size; i++) {
1338a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            if (mUidForeground.valueAt(i)) {
1339a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                final int uid = mUidForeground.keyAt(i);
134021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                updateRulesForUidLocked(uid);
1341a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            }
1342a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        }
1343a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    }
1344a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
1345b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    /**
13464664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey     * Update rules that might be changed by {@link #mRestrictBackground} value.
1347b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey     */
13484664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey    private void updateRulesForRestrictBackgroundLocked() {
1349b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        // update rules for all installed applications
1350b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        final PackageManager pm = mContext.getPackageManager();
1351b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        final List<ApplicationInfo> apps = pm.getInstalledApplications(0);
1352b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        for (ApplicationInfo app : apps) {
1353b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            updateRulesForUidLocked(app.uid);
1354b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        }
1355b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
1356b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        // and catch system UIDs
1357b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        // TODO: keep in sync with android_filesystem_config.h
1358b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        for (int uid = 1000; uid <= 1025; uid++) {
1359b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            updateRulesForUidLocked(uid);
1360b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        }
1361b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        for (int uid = 2000; uid <= 2002; uid++) {
1362b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            updateRulesForUidLocked(uid);
1363b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        }
1364b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        for (int uid = 3000; uid <= 3007; uid++) {
1365b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            updateRulesForUidLocked(uid);
1366b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        }
1367b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        for (int uid = 9998; uid <= 9999; uid++) {
1368b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            updateRulesForUidLocked(uid);
1369b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        }
1370b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    }
1371b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
137221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private void updateRulesForUidLocked(int uid) {
1373d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        final int uidPolicy = getUidPolicy(uid);
13749599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey        final boolean uidForeground = isUidForeground(uid);
1375d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
1376c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        // derive active rules based on policy and active state
1377c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        int uidRules = RULE_ALLOW_ALL;
1378fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey        if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
1379fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey            // uid in background, and policy says to block metered data
1380fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey            uidRules = RULE_REJECT_METERED;
1381d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        }
13824664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        if (!uidForeground && mRestrictBackground) {
1383b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            // uid in background, and global background disabled
1384b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey            uidRules = RULE_REJECT_METERED;
1385b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        }
1386d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
1387c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        // TODO: only dispatch when rules actually change
1388c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
1389350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        if (uidRules == RULE_ALLOW_ALL) {
1390350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey            mUidRules.delete(uid);
1391350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        } else {
1392350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey            mUidRules.put(uid, uidRules);
1393350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        }
1394c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
1395fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey        final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
139650fd36d7c38c40b087c8f3e3172478abe0c051d9Ashish Sharma        setUidNetworkRules(uid, rejectMetered);
1397497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
1398c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        // dispatch changed rule to existing listeners
13994414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey        mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
1400b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
1401b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        try {
1402b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            // adjust stats accounting based on foreground status
1403b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            mNetworkStats.setUidForeground(uid, uidForeground);
1404b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        } catch (RemoteException e) {
1405b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            // ignored; service lives in system_server
1406b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        }
14074414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey    }
14084414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey
14094414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey    private Handler.Callback mHandlerCallback = new Handler.Callback() {
14104414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey        /** {@inheritDoc} */
14114414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey        public boolean handleMessage(Message msg) {
14124414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey            switch (msg.what) {
14134414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                case MSG_RULES_CHANGED: {
14144414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    final int uid = msg.arg1;
14154414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    final int uidRules = msg.arg2;
14164414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    final int length = mListeners.beginBroadcast();
14174414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    for (int i = 0; i < length; i++) {
14184414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                        final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
14194414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                        if (listener != null) {
14204414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                            try {
14214414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                                listener.onUidRulesChanged(uid, uidRules);
14224414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                            } catch (RemoteException e) {
14234414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                            }
14244414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                        }
14254414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    }
14264414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    mListeners.finishBroadcast();
14274414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    return true;
14284414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                }
14294414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                case MSG_METERED_IFACES_CHANGED: {
14304414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    final String[] meteredIfaces = (String[]) msg.obj;
14314414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    final int length = mListeners.beginBroadcast();
14324414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    for (int i = 0; i < length; i++) {
14334414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                        final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
14344414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                        if (listener != null) {
14354414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                            try {
14364414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                                listener.onMeteredIfacesChanged(meteredIfaces);
14374414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                            } catch (RemoteException e) {
14384414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                            }
14394414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                        }
14404414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    }
14414414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    mListeners.finishBroadcast();
14424414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    return true;
14434414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                }
14446f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                case MSG_FOREGROUND_ACTIVITIES_CHANGED: {
14456f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                    final int pid = msg.arg1;
14466f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                    final int uid = msg.arg2;
14476f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                    final boolean foregroundActivities = (Boolean) msg.obj;
14486f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey
14496f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                    synchronized (mRulesLock) {
14506f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                        // because a uid can have multiple pids running inside, we need to
14516f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                        // remember all pid states and summarize foreground at uid level.
14526f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey
14536f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                        // record foreground for this specific pid
14546f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                        SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
14556f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                        if (pidForeground == null) {
14566f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                            pidForeground = new SparseBooleanArray(2);
14576f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                            mUidPidForeground.put(uid, pidForeground);
14586f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                        }
14596f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                        pidForeground.put(pid, foregroundActivities);
14606f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                        computeUidForegroundLocked(uid);
14616f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                    }
14626f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                    return true;
14636f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                }
14646f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                case MSG_PROCESS_DIED: {
14656f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                    final int pid = msg.arg1;
14666f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                    final int uid = msg.arg2;
14676f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey
14686f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                    synchronized (mRulesLock) {
14696f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                        // clear records and recompute, when they exist
14706f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                        final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
14716f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                        if (pidForeground != null) {
14726f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                            pidForeground.delete(pid);
14736f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                            computeUidForegroundLocked(uid);
14746f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                        }
14756f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                    }
14766f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                    return true;
14776f7af03cf13f76f48e63937e13e4a1c508d100d6Jeff Sharkey                }
14787e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                case MSG_LIMIT_REACHED: {
14797e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                    final String iface = (String) msg.obj;
14807e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey
1481684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey                    maybeRefreshTrustedTime();
14827e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                    synchronized (mRulesLock) {
14837e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                        if (mMeteredIfaces.contains(iface)) {
14847e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                            try {
14857e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                                // force stats update to make sure we have
14867e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                                // numbers that caused alert to trigger.
14877e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                                mNetworkStats.forceUpdate();
14887e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                            } catch (RemoteException e) {
14897e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                                // ignored; service lives in system_server
14907e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                            }
14917e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey
14927e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                            updateNetworkEnabledLocked();
14937e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                            updateNotificationsLocked();
14947e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                        }
14957e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                    }
14967e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                    return true;
14977e25b0ea8891ffc0ac472d61f21610a9ac4e270aJeff Sharkey                }
14984414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                default: {
14994414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    return false;
1500af11d4859582a9736aa204562f0beac5a7d60934Jeff Sharkey                }
1501af11d4859582a9736aa204562f0beac5a7d60934Jeff Sharkey            }
1502af11d4859582a9736aa204562f0beac5a7d60934Jeff Sharkey        }
15034414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey    };
150422c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
150541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private void setInterfaceQuota(String iface, long quotaBytes) {
1506b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        try {
150741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            mNetworkManager.setInterfaceQuota(iface, quotaBytes);
1508b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        } catch (IllegalStateException e) {
1509b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            Log.wtf(TAG, "problem setting interface quota", e);
1510b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        } catch (RemoteException e) {
1511b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            // ignored; service lives in system_server
1512b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        }
1513b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    }
1514b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
1515b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    private void removeInterfaceQuota(String iface) {
1516b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        try {
151741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            mNetworkManager.removeInterfaceQuota(iface);
1518b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        } catch (IllegalStateException e) {
1519b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            Log.wtf(TAG, "problem removing interface quota", e);
1520b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        } catch (RemoteException e) {
1521b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            // ignored; service lives in system_server
152241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        }
152341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    }
152441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
1525b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1526b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        try {
152741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey            mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
1528b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        } catch (IllegalStateException e) {
1529b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            Log.wtf(TAG, "problem setting uid rules", e);
1530b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        } catch (RemoteException e) {
1531b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            // ignored; service lives in system_server
1532b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey        }
1533b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey    }
1534b3f19ca36c8c1301893c621d8f2150e06210722cJeff Sharkey
15358e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    /**
15363f3115b27733a822104385284b1ec1f39d91f839Jeff Sharkey     * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}.
15378e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey     */
15388e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    private void setPolicyDataEnable(int networkType, boolean enabled) {
15393f3115b27733a822104385284b1ec1f39d91f839Jeff Sharkey        try {
15403f3115b27733a822104385284b1ec1f39d91f839Jeff Sharkey            mConnManager.setPolicyDataEnable(networkType, enabled);
15413f3115b27733a822104385284b1ec1f39d91f839Jeff Sharkey        } catch (RemoteException e) {
15423f3115b27733a822104385284b1ec1f39d91f839Jeff Sharkey            // ignored; service lives in system_server
15438e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        }
15448e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    }
15458e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
154622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private String getActiveSubscriberId() {
154722c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
154822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                Context.TELEPHONY_SERVICE);
154922c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        return telephony.getSubscriberId();
155022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    }
155122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
15528e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    private long getTotalBytes(NetworkTemplate template, long start, long end) {
15538e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        try {
155450e7e51d68e3b01c3362fe9ab7b3448132e48b43Jeff Sharkey            return mNetworkStats.getSummaryForNetwork(template, start, end).getTotalBytes();
15558e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        } catch (RemoteException e) {
1556b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            // ignored; service lives in system_server
1557b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            return 0;
15588e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        }
15598e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    }
15608e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
1561684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey    /**
1562684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey     * Try refreshing {@link #mTime} when stale.
1563684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey     */
1564684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey    private void maybeRefreshTrustedTime() {
1565684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey        if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
15668e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey            mTime.forceRefresh();
15678e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        }
1568684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey    }
15698e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
1570684c54a2eb860062f1960f4eba6bc71aa1cfa71dJeff Sharkey    private long currentTimeMillis() {
15718e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey        return mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
15728e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey    }
15738e28b7d78232f6cf08739ca0d129cc7f9e650801Jeff Sharkey
15743a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    private static Intent buildAllowBackgroundDataIntent() {
15753a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey        return new Intent(ACTION_ALLOW_BACKGROUND);
15763a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey    }
15773a844fcf5a0e70a19c38dc500306b9ebe4e1413bJeff Sharkey
157841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private static Intent buildNetworkOverLimitIntent(NetworkTemplate template) {
157941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        final Intent intent = new Intent();
158041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        intent.setComponent(new ComponentName(
158141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                "com.android.systemui", "com.android.systemui.net.NetworkOverLimitActivity"));
158241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
158341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
158441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        return intent;
158541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    }
158641ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
158741ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    private static Intent buildViewDataUsageIntent(NetworkTemplate template) {
158841ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        final Intent intent = new Intent();
158941ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        intent.setComponent(new ComponentName(
159041ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey                "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
159141ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
159241ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
159341ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey        return intent;
159441ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey    }
159541ff7ec82422a5b6d00892afdb3232bc0e53d851Jeff Sharkey
1596163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    // @VisibleForTesting
1597163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    public void addIdleHandler(IdleHandler handler) {
1598163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        mHandler.getLooper().getQueue().addIdleHandler(handler);
1599163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    }
1600163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
16011b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
16021b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        final int size = source.size();
16031b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        for (int i = 0; i < size; i++) {
16041b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            target.put(source.keyAt(i), true);
16051b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        }
16061b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    }
16071b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
16081b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    private static void collectKeys(SparseBooleanArray source, SparseBooleanArray target) {
16091b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        final int size = source.size();
16101b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        for (int i = 0; i < size; i++) {
16111b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            target.put(source.keyAt(i), true);
16121b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        }
16131b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    }
16141b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
16151b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    private static void dumpSparseBooleanArray(PrintWriter fout, SparseBooleanArray value) {
16161b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        fout.print("[");
16171b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        final int size = value.size();
16181b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        for (int i = 0; i < size; i++) {
16191b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            fout.print(value.keyAt(i) + "=" + value.valueAt(i));
16201b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            if (i < size - 1) fout.print(",");
16211b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        }
16221b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        fout.print("]");
16231b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    }
162421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
16254664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey    public static class XmlUtils {
16264664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        public static int readIntAttribute(XmlPullParser in, String name) throws IOException {
16274664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            final String value = in.getAttributeValue(null, name);
16284664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            try {
16294664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                return Integer.parseInt(value);
16304664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            } catch (NumberFormatException e) {
16314664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
16324664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            }
163321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
163421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
16354664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        public static void writeIntAttribute(XmlSerializer out, String name, int value)
16364664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                throws IOException {
16374664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            out.attribute(null, name, Integer.toString(value));
163821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
163921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
16404664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        public static long readLongAttribute(XmlPullParser in, String name) throws IOException {
16414664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            final String value = in.getAttributeValue(null, name);
16424664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            try {
16434664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                return Long.parseLong(value);
16444664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            } catch (NumberFormatException e) {
16454664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                throw new ProtocolException("problem parsing " + name + "=" + value + " as long");
16464664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            }
16474664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        }
164821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
16494664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        public static void writeLongAttribute(XmlSerializer out, String name, long value)
16504664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                throws IOException {
16514664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            out.attribute(null, name, Long.toString(value));
16524664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        }
165321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
16544664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        public static boolean readBooleanAttribute(XmlPullParser in, String name) {
16554664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            final String value = in.getAttributeValue(null, name);
16564664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            return Boolean.parseBoolean(value);
16574664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        }
16584664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey
16594664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value)
16604664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey                throws IOException {
16614664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey            out.attribute(null, name, Boolean.toString(value));
16624664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey        }
16634664500de0c1b270bce4991a400ab439ff2ef77bJeff Sharkey    }
1664d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey}
1665