NetworkPolicyManagerService.java revision 4414cea13908b8230640f84ef39603d68ff9c377
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
1921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport static android.Manifest.permission.CONNECTIVITY_INTERNAL;
201b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkeyimport static android.Manifest.permission.DUMP;
21d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport static android.Manifest.permission.MANAGE_APP_TOKENS;
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;
25b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkeyimport static android.content.Intent.ACTION_UID_REMOVED;
26b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkeyimport static android.content.Intent.EXTRA_UID;
2721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
281b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport static android.net.ConnectivityManager.TYPE_MOBILE;
2922c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkeyimport static android.net.NetworkPolicy.LIMIT_DISABLED;
30497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport static android.net.NetworkPolicy.WARNING_DISABLED;
3114711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkeyimport static android.net.NetworkPolicyManager.ACTION_DATA_USAGE_LIMIT;
3214711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkeyimport static android.net.NetworkPolicyManager.ACTION_DATA_USAGE_WARNING;
3314711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkeyimport static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
34d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport static android.net.NetworkPolicyManager.POLICY_NONE;
35fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkeyimport static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
36c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkeyimport static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
37fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkeyimport static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
38cd2ca4038a027315832c38c68be5076000bc4b53Jeff Sharkeyimport static android.net.NetworkPolicyManager.computeLastCycleBoundary;
391b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkeyimport static android.net.NetworkPolicyManager.dumpPolicy;
401b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkeyimport static android.net.NetworkPolicyManager.dumpRules;
41497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport static android.net.NetworkPolicyManager.isUidValidForPolicy;
421b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
431b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport static android.net.NetworkTemplate.MATCH_MOBILE_4G;
441b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
4521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport static android.text.format.DateUtils.DAY_IN_MILLIS;
4621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport static com.android.internal.util.Preconditions.checkNotNull;
47497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
4821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
4921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport static org.xmlpull.v1.XmlPullParser.START_TAG;
50d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
51a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.app.IActivityManager;
52497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport android.app.INotificationManager;
53a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.app.IProcessObserver;
54497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport android.app.Notification;
55497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport android.app.PendingIntent;
56a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.content.BroadcastReceiver;
57d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport android.content.Context;
58a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.content.Intent;
59a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.content.IntentFilter;
60497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport android.content.res.Resources;
61c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkeyimport android.net.ConnectivityManager;
6221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.net.IConnectivityManager;
63c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkeyimport android.net.INetworkPolicyListener;
64d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport android.net.INetworkPolicyManager;
6575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.net.INetworkStatsService;
661b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport android.net.NetworkIdentity;
6721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.net.NetworkPolicy;
6821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.net.NetworkState;
6921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.net.NetworkStats;
701b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkeyimport android.net.NetworkTemplate;
7121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.os.Environment;
7221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.os.Handler;
7321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.os.HandlerThread;
74a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.os.IPowerManager;
754414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkeyimport android.os.Message;
76c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkeyimport android.os.RemoteCallbackList;
77a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.os.RemoteException;
7822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkeyimport android.telephony.TelephonyManager;
79497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport android.text.format.Formatter;
8022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkeyimport android.text.format.Time;
8121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.util.NtpTrustedTime;
82a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkeyimport android.util.Slog;
83d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport android.util.SparseArray;
84d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport android.util.SparseBooleanArray;
85d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeyimport android.util.SparseIntArray;
8621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.util.TrustedTime;
8721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport android.util.Xml;
88d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
89497e4437af386930dff3bd55296d128bd4520959Jeff Sharkeyimport com.android.internal.R;
9021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport com.android.internal.os.AtomicFile;
9121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport com.android.internal.util.FastXmlSerializer;
9221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport com.google.android.collect.Lists;
9321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport com.google.android.collect.Maps;
94fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkeyimport com.google.android.collect.Sets;
9521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
9621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport org.xmlpull.v1.XmlPullParser;
9721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport org.xmlpull.v1.XmlPullParserException;
9821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport org.xmlpull.v1.XmlSerializer;
9921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
10021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.io.File;
1011b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkeyimport java.io.FileDescriptor;
10221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.io.FileInputStream;
10321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.io.FileNotFoundException;
10421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.io.FileOutputStream;
10521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.io.IOException;
1061b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkeyimport java.io.PrintWriter;
10721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.net.ProtocolException;
10821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.util.ArrayList;
10921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.util.Arrays;
11021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport java.util.HashMap;
111fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkeyimport java.util.HashSet;
11221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
11321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkeyimport libcore.io.IoUtils;
1141b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
115d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey/**
116d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey * Service that maintains low-level network policy rules and collects usage
117d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey * statistics to drive those rules.
118c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey * <p>
119c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey * Derives active rules by combining a given policy with other system status,
120c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey * and delivers to listeners, such as {@link ConnectivityManager}, for
121c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey * enforcement.
122d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey */
123d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkeypublic class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
124d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    private static final String TAG = "NetworkPolicy";
125d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    private static final boolean LOGD = true;
12622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private static final boolean LOGV = false;
127d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
12821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final int VERSION_CURRENT = 1;
12921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
13022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private static final long KB_IN_BYTES = 1024;
13122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
13222c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
13322c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
134497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private static final int TYPE_WARNING = 0x1;
135497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private static final int TYPE_LIMIT = 0x2;
136497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
13721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String TAG_POLICY_LIST = "policy-list";
13821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String TAG_NETWORK_POLICY = "network-policy";
13921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String TAG_UID_POLICY = "uid-policy";
14021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
14121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_VERSION = "version";
14221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate";
14321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_SUBSCRIBER_ID = "subscriberId";
14421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_CYCLE_DAY = "cycleDay";
14521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_WARNING_BYTES = "warningBytes";
14621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_LIMIT_BYTES = "limitBytes";
14721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_UID = "uid";
14821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final String ATTR_POLICY = "policy";
14921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
15021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
15121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
1524414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey    private static final int MSG_RULES_CHANGED = 0x1;
1534414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey    private static final int MSG_METERED_IFACES_CHANGED = 0x2;
1544414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey
15575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private final Context mContext;
15675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private final IActivityManager mActivityManager;
15775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private final IPowerManager mPowerManager;
15875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private final INetworkStatsService mNetworkStats;
15921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private final TrustedTime mTime;
16021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
16121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private IConnectivityManager mConnManager;
162497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private INotificationManager mNotifManager;
163a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
16475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private final Object mRulesLock = new Object();
165a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
166c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    private boolean mScreenOn;
167d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
16822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    /** Current policy for network templates. */
16922c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
17022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
17122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    /** Current policy for each UID. */
172a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    private SparseIntArray mUidPolicy = new SparseIntArray();
173c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    /** Current derived network rules for each UID. */
174c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    private SparseIntArray mUidRules = new SparseIntArray();
175d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
176fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey    /** Set of ifaces that are metered. */
177fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey    private HashSet<String> mMeteredIfaces = Sets.newHashSet();
178fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey
179d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    /** Foreground at both UID and PID granularity. */
180a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    private SparseBooleanArray mUidForeground = new SparseBooleanArray();
181a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
182a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            SparseBooleanArray>();
183d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
184c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
185c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey            INetworkPolicyListener>();
186c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
18721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private final HandlerThread mHandlerThread;
18821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private final Handler mHandler;
18921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
19021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private final AtomicFile mPolicyFile;
191d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
192c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    // TODO: keep whitelist of system-critical services that should never have
193c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    // rules enforced, such as system, phone, and radio UIDs.
194c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
19575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
19675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            IPowerManager powerManager, INetworkStatsService networkStats) {
19721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // TODO: move to using cached NtpTrustedTime
19821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        this(context, activityManager, powerManager, networkStats, new NtpTrustedTime(),
19921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                getSystemDir());
20021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
20121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
20221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static File getSystemDir() {
20321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        return new File(Environment.getDataDirectory(), "system");
20421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
20521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
20621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
20721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            IPowerManager powerManager, INetworkStatsService networkStats, TrustedTime time,
20821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            File systemDir) {
209a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        mContext = checkNotNull(context, "missing context");
210a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        mActivityManager = checkNotNull(activityManager, "missing activityManager");
211a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        mPowerManager = checkNotNull(powerManager, "missing powerManager");
21275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        mNetworkStats = checkNotNull(networkStats, "missing networkStats");
21321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mTime = checkNotNull(time, "missing TrustedTime");
21421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
21521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mHandlerThread = new HandlerThread(TAG);
21621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mHandlerThread.start();
2174414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey        mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
21821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
21921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
22021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
22121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
22221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    public void bindConnectivityManager(IConnectivityManager connManager) {
22321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
224a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    }
225d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
226497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    public void bindNotificationManager(INotificationManager notifManager) {
227497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        mNotifManager = checkNotNull(notifManager, "missing INotificationManager");
228497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    }
229497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
230a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    public void systemReady() {
23121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        synchronized (mRulesLock) {
23221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // read policy from disk
23321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            readPolicyLocked();
234497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            updateNotificationsLocked();
23521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
236d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
237a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        updateScreenOn();
238d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
239a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        try {
240a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            mActivityManager.registerProcessObserver(mProcessObserver);
241a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        } catch (RemoteException e) {
242a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            // ouch, no foregroundActivities updates means some processes may
243a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            // never get network access.
244a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            Slog.e(TAG, "unable to register IProcessObserver", e);
245a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        }
246d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
247a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        // TODO: traverse existing processes to know foreground state, or have
248a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        // activitymanager dispatch current state when new observer attached.
249d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
250a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        final IntentFilter screenFilter = new IntentFilter();
251a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        screenFilter.addAction(Intent.ACTION_SCREEN_ON);
252a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
253a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        mContext.registerReceiver(mScreenReceiver, screenFilter);
254d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
25521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // watch for network interfaces to be claimed
256b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey        final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
257b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey        mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
258b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey
259b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey        // listen for uid removal to clean policy
260b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey        final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
261b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey        mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
26221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
263497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        // listen for warning polling events; currently dispatched by
264497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
265497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        mContext.registerReceiver(
266497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
267497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
268a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    }
269d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
270a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
271a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        @Override
272a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
273a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            // only someone like AMS should only be calling us
27475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
275a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
276a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            synchronized (mRulesLock) {
277a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                // because a uid can have multiple pids running inside, we need to
278a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                // remember all pid states and summarize foreground at uid level.
279a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
280a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                // record foreground for this specific pid
281a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
282a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                if (pidForeground == null) {
283a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                    pidForeground = new SparseBooleanArray(2);
284a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                    mUidPidForeground.put(uid, pidForeground);
285a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                }
286a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                pidForeground.put(pid, foregroundActivities);
28721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                computeUidForegroundLocked(uid);
288a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            }
289d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        }
290d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
291a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        @Override
292a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        public void onProcessDied(int pid, int uid) {
293a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            // only someone like AMS should only be calling us
29475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
295a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
296a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            synchronized (mRulesLock) {
297a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                // clear records and recompute, when they exist
298a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
299a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                if (pidForeground != null) {
300a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                    pidForeground.delete(pid);
30121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                    computeUidForegroundLocked(uid);
302a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                }
303a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            }
304a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        }
305a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    };
306a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
307a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
308a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        @Override
309a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        public void onReceive(Context context, Intent intent) {
310a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            synchronized (mRulesLock) {
311a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                // screen-related broadcasts are protected by system, no need
312a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                // for permissions check.
313a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                updateScreenOn();
314a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            }
315a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        }
316a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    };
317d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
318b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey    private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
319b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey        @Override
320b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey        public void onReceive(Context context, Intent intent) {
321b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey            // on background handler thread, and UID_REMOVED is protected
322b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey            // broadcast.
323b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey            final int uid = intent.getIntExtra(EXTRA_UID, 0);
324b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey            synchronized (mRulesLock) {
325b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey                // remove any policy and update rules to clean up
326b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey                mUidPolicy.delete(uid);
327b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey                updateRulesForUidLocked(uid);
328b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey                writePolicyLocked();
329b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey            }
330b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey        }
331b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey    };
332b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey
33321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    /**
334497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * Receiver that watches for {@link INetworkStatsService} updates, which we
335497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * use to check against {@link NetworkPolicy#warningBytes}.
336497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     */
337497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() {
338497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        @Override
339497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        public void onReceive(Context context, Intent intent) {
340497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            // on background handler thread, and verified
341497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            // READ_NETWORK_USAGE_HISTORY permission above.
342497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
343497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            synchronized (mRulesLock) {
344497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                updateNotificationsLocked();
345497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            }
346497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        }
347497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    };
348497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
349497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    /**
350497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * Check {@link NetworkPolicy} against current {@link INetworkStatsService}
351497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * to show visible notifications as needed.
352497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     */
353497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private void updateNotificationsLocked() {
354497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        if (LOGV) Slog.v(TAG, "updateNotificationsLocked()");
355497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
356497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        // try refreshing time source when stale
357497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
358497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            mTime.forceRefresh();
359497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        }
360497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
361497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
362497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                : System.currentTimeMillis();
363497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
364497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        // TODO: when switching to kernel notifications, compute next future
365497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        // cycle boundary to recompute notifications.
366497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
367497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        // examine stats for each policy defined
368497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        for (NetworkPolicy policy : mNetworkPolicy) {
369497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            final long start = computeLastCycleBoundary(currentTime, policy);
370497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            final long end = currentTime;
371497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
372497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            final long total;
373497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            try {
374497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                final NetworkStats stats = mNetworkStats.getSummaryForNetwork(
3751b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                        policy.template, start, end);
376497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                total = stats.rx[0] + stats.tx[0];
377497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            } catch (RemoteException e) {
3781b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                Slog.w(TAG, "problem reading summary for template " + policy.template);
379497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                continue;
380497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            }
381497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
382497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            if (policy.limitBytes != LIMIT_DISABLED && total >= policy.limitBytes) {
383497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                cancelNotification(policy, TYPE_WARNING);
384497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                enqueueNotification(policy, TYPE_LIMIT);
385497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            } else {
386497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                cancelNotification(policy, TYPE_LIMIT);
387497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
388497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                if (policy.warningBytes != WARNING_DISABLED && total >= policy.warningBytes) {
389497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                    enqueueNotification(policy, TYPE_WARNING);
390497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                } else {
391497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                    cancelNotification(policy, TYPE_WARNING);
392497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                }
393497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            }
394497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        }
395497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    }
396497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
397497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    /**
398497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * Build unique tag that identifies an active {@link NetworkPolicy}
399497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * notification of a specific type, like {@link #TYPE_LIMIT}.
400497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     */
401497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private String buildNotificationTag(NetworkPolicy policy, int type) {
4021b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        return TAG + ":" + policy.template.hashCode() + ":" + type;
403497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    }
404497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
405497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    /**
406497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * Show notification for combined {@link NetworkPolicy} and specific type,
407497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * like {@link #TYPE_LIMIT}. Okay to call multiple times.
408497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     */
409497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private void enqueueNotification(NetworkPolicy policy, int type) {
410497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        final String tag = buildNotificationTag(policy, type);
411497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        final Notification.Builder builder = new Notification.Builder(mContext);
412497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        builder.setOnlyAlertOnce(true);
413497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        builder.setOngoing(true);
414497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
415497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        final Resources res = mContext.getResources();
416497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        switch (type) {
417497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            case TYPE_WARNING: {
418497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                final String title = res.getString(R.string.data_usage_warning_title);
419497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                final String body = res.getString(R.string.data_usage_warning_body,
420497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        Formatter.formatFileSize(mContext, policy.warningBytes));
421497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
422497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setSmallIcon(R.drawable.ic_menu_info_details);
423497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setTicker(title);
424497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setContentTitle(title);
425497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setContentText(body);
42614711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey
42714711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey                final Intent intent = new Intent(ACTION_DATA_USAGE_WARNING);
42814711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey                intent.addCategory(Intent.CATEGORY_DEFAULT);
4291b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.template.getMatchRule());
43014711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey                builder.setContentIntent(PendingIntent.getActivity(
43114711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
432497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                break;
433497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            }
434497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            case TYPE_LIMIT: {
435497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                final String title;
436497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                final String body = res.getString(R.string.data_usage_limit_body);
4371b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                switch (policy.template.getMatchRule()) {
4381b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                    case MATCH_MOBILE_3G_LOWER:
439497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        title = res.getString(R.string.data_usage_3g_limit_title);
440497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        break;
4411b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                    case MATCH_MOBILE_4G:
442497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        title = res.getString(R.string.data_usage_4g_limit_title);
443497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        break;
444497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                    default:
445497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        title = res.getString(R.string.data_usage_mobile_limit_title);
446497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        break;
447497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                }
448497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
449497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setSmallIcon(com.android.internal.R.drawable.ic_menu_block);
450497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setTicker(title);
451497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setContentTitle(title);
452497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                builder.setContentText(body);
45314711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey
45414711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey                final Intent intent = new Intent(ACTION_DATA_USAGE_LIMIT);
45514711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey                intent.addCategory(Intent.CATEGORY_DEFAULT);
4561b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.template.getMatchRule());
45714711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey                builder.setContentIntent(PendingIntent.getActivity(
45814711eb5b6a45b587222ae71c57a381beb7b1a7eJeff Sharkey                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
459497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                break;
460497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            }
461497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        }
462497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
463497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        // TODO: move to NotificationManager once we can mock it
464497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        try {
465497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            final String packageName = mContext.getPackageName();
466497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            final int[] idReceived = new int[1];
467497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            mNotifManager.enqueueNotificationWithTag(
468497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                    packageName, tag, 0x0, builder.getNotification(), idReceived);
469497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        } catch (RemoteException e) {
470497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            Slog.w(TAG, "problem during enqueueNotification: " + e);
471497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        }
472497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    }
473497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
474497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    /**
475497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * Cancel any notification for combined {@link NetworkPolicy} and specific
476497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     * type, like {@link #TYPE_LIMIT}.
477497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey     */
478497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private void cancelNotification(NetworkPolicy policy, int type) {
479497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        final String tag = buildNotificationTag(policy, type);
480497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
481497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        // TODO: move to NotificationManager once we can mock it
482497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        try {
483497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            final String packageName = mContext.getPackageName();
484497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            mNotifManager.cancelNotificationWithTag(packageName, tag, 0x0);
485497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        } catch (RemoteException e) {
486497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            Slog.w(TAG, "problem during enqueueNotification: " + e);
487497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        }
488497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    }
489497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
490497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    /**
49121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     * Receiver that watches for {@link IConnectivityManager} to claim network
49222c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey     * interfaces. Used to apply {@link NetworkPolicy} to matching networks.
49321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     */
494b09540f33a6cabe50edec0ef32d0b1d0b0d96fffJeff Sharkey    private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
49521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        @Override
49621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        public void onReceive(Context context, Intent intent) {
49721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // on background handler thread, and verified CONNECTIVITY_INTERNAL
49821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // permission above.
49921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            synchronized (mRulesLock) {
50022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                ensureActiveMobilePolicyLocked();
50121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                updateIfacesLocked();
50221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
50321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
50421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    };
50521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
50621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    /**
50721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     * Examine all connected {@link NetworkState}, looking for
50821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     * {@link NetworkPolicy} that need to be enforced. When matches found, set
50921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     * remaining quota based on usage cycle and historical stats.
51021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     */
51121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private void updateIfacesLocked() {
51222c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
51321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
51421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        final NetworkState[] states;
51521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        try {
51621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            states = mConnManager.getAllNetworkState();
51721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } catch (RemoteException e) {
51821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            Slog.w(TAG, "problem reading network state");
51921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            return;
52021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
52121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
52221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // first, derive identity for all connected networks, which can be used
52321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // to match against templates.
52421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        final HashMap<NetworkIdentity, String> networks = Maps.newHashMap();
52521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        for (NetworkState state : states) {
52621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // stash identity and iface away for later use
52721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            if (state.networkInfo.isConnected()) {
52821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                final String iface = state.linkProperties.getInterfaceName();
52921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
53021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                networks.put(ident, iface);
53121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
53221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
53321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
53421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // build list of rules and ifaces to enforce them against
53522c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        final HashMap<NetworkPolicy, String[]> rules = Maps.newHashMap();
53621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        final ArrayList<String> ifaceList = Lists.newArrayList();
53722c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        for (NetworkPolicy policy : mNetworkPolicy) {
53821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
53921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // collect all active ifaces that match this template
54021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            ifaceList.clear();
54121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            for (NetworkIdentity ident : networks.keySet()) {
5421b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                if (policy.template.matches(ident)) {
54321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                    final String iface = networks.get(ident);
54421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                    ifaceList.add(iface);
54521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                }
54621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
54721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
54821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            if (ifaceList.size() > 0) {
54921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
55022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                rules.put(policy, ifaces);
55121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
55221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
55321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
55421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // try refreshing time source when stale
55521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
55621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            mTime.forceRefresh();
55721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
55821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
55921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
56021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                : System.currentTimeMillis();
56121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
562fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey        mMeteredIfaces.clear();
563fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey
56421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // apply each policy that we found ifaces for; compute remaining data
56521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // based on current cycle and historical stats, and push to kernel.
56622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        for (NetworkPolicy policy : rules.keySet()) {
56721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            final String[] ifaces = rules.get(policy);
56821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
56921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            final long start = computeLastCycleBoundary(currentTime, policy);
57021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            final long end = currentTime;
57121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
57221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            final NetworkStats stats;
57322c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            final long total;
57421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            try {
5751b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                stats = mNetworkStats.getSummaryForNetwork(policy.template, start, end);
57622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                total = stats.rx[0] + stats.tx[0];
57721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            } catch (RemoteException e) {
5781b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                Slog.w(TAG, "problem reading summary for template " + policy.template);
57921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                continue;
58021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
58121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
58221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            if (LOGD) {
58321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
58422c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                        + Arrays.toString(ifaces));
58522c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            }
58622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
58722c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            // TODO: register for warning notification trigger through NMS
58822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
58922c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
59022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                // remaining "quota" is based on usage in current cycle
59122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                final long quota = Math.max(0, policy.limitBytes - total);
592497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                //kernelSetIfacesQuota(ifaces, quota);
593fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey
594fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey                for (String iface : ifaces) {
595fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey                    mMeteredIfaces.add(iface);
596fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey                }
59722c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            }
59822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        }
599fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey
600fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey        final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
6014414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey        mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
60222c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    }
60322c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
60422c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    /**
60522c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey     * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
60622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey     * have at least a default mobile policy defined.
60722c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey     */
60822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private void ensureActiveMobilePolicyLocked() {
60922c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()");
61022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        final String subscriberId = getActiveSubscriberId();
6111b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        final NetworkIdentity probeIdent = new NetworkIdentity(
6125dc0c26cffbbc62ff84f9f4c8a451e68e2c05d2dJeff Sharkey                TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, false);
61322c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
61422c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        // examine to see if any policy is defined for active mobile
61522c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        boolean mobileDefined = false;
61622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        for (NetworkPolicy policy : mNetworkPolicy) {
6171b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey            if (policy.template.matches(probeIdent)) {
61822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                mobileDefined = true;
61921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
62022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        }
62121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
62222c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        if (!mobileDefined) {
62322c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            Slog.i(TAG, "no policy for active mobile network; generating default policy");
62421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
62522c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            // default mobile policy has combined 4GB warning, and assume usage
62622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            // cycle starts today today.
62722c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
62822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            // TODO: move this policy definition to overlay or secure setting
62922c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            final Time time = new Time(Time.TIMEZONE_UTC);
63022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            time.setToNow();
63122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            final int cycleDay = time.monthDay;
63222c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
6331b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey            final NetworkTemplate template = new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId);
6341b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey            mNetworkPolicy.add(
6351b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                    new NetworkPolicy(template, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED));
636fcc79771f092f34505b1accb80365cbcaa379667Jeff Sharkey            writePolicyLocked();
63721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
63821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
63921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
64021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private void readPolicyLocked() {
64122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        if (LOGV) Slog.v(TAG, "readPolicyLocked()");
64221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
64321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        // clear any existing policy and read from disk
64422c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        mNetworkPolicy.clear();
64521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mUidPolicy.clear();
64621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
64721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        FileInputStream fis = null;
64821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        try {
64921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            fis = mPolicyFile.openRead();
65021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            final XmlPullParser in = Xml.newPullParser();
65121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            in.setInput(fis, null);
65221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
65321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            int type;
65421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            int version = VERSION_CURRENT;
65521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            while ((type = in.next()) != END_DOCUMENT) {
65621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                final String tag = in.getName();
65721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                if (type == START_TAG) {
65821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                    if (TAG_POLICY_LIST.equals(tag)) {
65921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        version = readIntAttribute(in, ATTR_VERSION);
66021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
66121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                    } else if (TAG_NETWORK_POLICY.equals(tag)) {
66221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
66321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID);
66421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
66521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
66621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
66721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
6681b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                        final NetworkTemplate template = new NetworkTemplate(
6691b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                                networkTemplate, subscriberId);
6701b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                        mNetworkPolicy.add(
6711b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                                new NetworkPolicy(template, cycleDay, warningBytes, limitBytes));
67221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
67321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                    } else if (TAG_UID_POLICY.equals(tag)) {
67421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final int uid = readIntAttribute(in, ATTR_UID);
67521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                        final int policy = readIntAttribute(in, ATTR_POLICY);
67621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
677497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        if (isUidValidForPolicy(mContext, uid)) {
678497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                            setUidPolicyUnchecked(uid, policy, false);
679497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        } else {
680497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                            Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
681497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                        }
68221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                    }
68321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                }
68421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
68521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
68621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } catch (FileNotFoundException e) {
68721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // missing policy is okay, probably first boot
68821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } catch (IOException e) {
68921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            Slog.e(TAG, "problem reading network stats", e);
69021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } catch (XmlPullParserException e) {
69121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            Slog.e(TAG, "problem reading network stats", e);
69221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } finally {
69321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            IoUtils.closeQuietly(fis);
69421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
69521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
69621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
69721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private void writePolicyLocked() {
69822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        if (LOGV) Slog.v(TAG, "writePolicyLocked()");
69921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
70021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        FileOutputStream fos = null;
70121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        try {
70221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            fos = mPolicyFile.startWrite();
70321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
70421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            XmlSerializer out = new FastXmlSerializer();
70521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            out.setOutput(fos, "utf-8");
70621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            out.startDocument(null, true);
70721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
70821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            out.startTag(null, TAG_POLICY_LIST);
70921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            writeIntAttribute(out, ATTR_VERSION, VERSION_CURRENT);
71021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
71121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // write all known network policies
71222c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            for (NetworkPolicy policy : mNetworkPolicy) {
7131b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                final NetworkTemplate template = policy.template;
7141b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey
71521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                out.startTag(null, TAG_NETWORK_POLICY);
7161b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule());
7171b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                final String subscriberId = template.getSubscriberId();
7181b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                if (subscriberId != null) {
7191b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey                    out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId);
72021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                }
72121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
72221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
72321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
72421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                out.endTag(null, TAG_NETWORK_POLICY);
72521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
72621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
72721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // write all known uid policies
72821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            for (int i = 0; i < mUidPolicy.size(); i++) {
72921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                final int uid = mUidPolicy.keyAt(i);
73021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                final int policy = mUidPolicy.valueAt(i);
73121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
732497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                // skip writing empty policies
733497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                if (policy == POLICY_NONE) continue;
734497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
73521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                out.startTag(null, TAG_UID_POLICY);
73621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                writeIntAttribute(out, ATTR_UID, uid);
73721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                writeIntAttribute(out, ATTR_POLICY, policy);
73821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                out.endTag(null, TAG_UID_POLICY);
73921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
74021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
74121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            out.endTag(null, TAG_POLICY_LIST);
74221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            out.endDocument();
74321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
74421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            mPolicyFile.finishWrite(fos);
74521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } catch (IOException e) {
74621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            if (fos != null) {
74721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                mPolicyFile.failWrite(fos);
74821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
74921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
75021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
75121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
752d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    @Override
753d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    public void setUidPolicy(int uid, int policy) {
75421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
755a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
756497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        if (!isUidValidForPolicy(mContext, uid)) {
757497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            throw new IllegalArgumentException("cannot apply policy to UID " + uid);
758497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        }
759497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
760497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        setUidPolicyUnchecked(uid, policy, true);
761497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    }
762497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
763497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey    private void setUidPolicyUnchecked(int uid, int policy, boolean persist) {
764c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        final int oldPolicy;
765a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        synchronized (mRulesLock) {
766c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey            oldPolicy = getUidPolicy(uid);
767a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            mUidPolicy.put(uid, policy);
768c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
76921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            // uid policy changed, recompute rules and persist policy.
77021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            updateRulesForUidLocked(uid);
771497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            if (persist) {
772497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey                writePolicyLocked();
773497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            }
77421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
775d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    }
776d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
777d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    @Override
778d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    public int getUidPolicy(int uid) {
77921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
78021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
781a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        synchronized (mRulesLock) {
782a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            return mUidPolicy.get(uid, POLICY_NONE);
783a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        }
784d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    }
785d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
786c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    @Override
787c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    public void registerListener(INetworkPolicyListener listener) {
7881a303953589fdddf21d88b8fa660136f5b060d0dJeff Sharkey        // TODO: create permission for observing network policy
7891a303953589fdddf21d88b8fa660136f5b060d0dJeff Sharkey        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
7901a303953589fdddf21d88b8fa660136f5b060d0dJeff Sharkey
791c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        mListeners.register(listener);
792c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
7934414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey        // TODO: consider dispatching existing rules to new listeners
794c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    }
795c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
796c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    @Override
797c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    public void unregisterListener(INetworkPolicyListener listener) {
7981a303953589fdddf21d88b8fa660136f5b060d0dJeff Sharkey        // TODO: create permission for observing network policy
7991a303953589fdddf21d88b8fa660136f5b060d0dJeff Sharkey        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
8001a303953589fdddf21d88b8fa660136f5b060d0dJeff Sharkey
801c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        mListeners.unregister(listener);
802c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    }
803c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
8041b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    @Override
80522c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    public void setNetworkPolicies(NetworkPolicy[] policies) {
80621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
80721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
80821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        synchronized (mRulesLock) {
80922c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            mNetworkPolicy.clear();
81022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            for (NetworkPolicy policy : policies) {
81122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                mNetworkPolicy.add(policy);
81222c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            }
81321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
81421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            updateIfacesLocked();
815497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey            updateNotificationsLocked();
81621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            writePolicyLocked();
81721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
81821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
81921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
82021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    @Override
82122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    public NetworkPolicy[] getNetworkPolicies() {
82221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
82322c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
82421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
82521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        synchronized (mRulesLock) {
82622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            return mNetworkPolicy.toArray(new NetworkPolicy[mNetworkPolicy.size()]);
82721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
82821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
82921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
83021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    @Override
8311b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
83275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
8331b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
8341b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        synchronized (mRulesLock) {
83521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            fout.println("Network policies:");
83622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey            for (NetworkPolicy policy : mNetworkPolicy) {
83722c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                fout.print("  "); fout.println(policy.toString());
83821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            }
83921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
8401b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            fout.println("Policy status for known UIDs:");
8411b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
8421b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            final SparseBooleanArray knownUids = new SparseBooleanArray();
8431b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            collectKeys(mUidPolicy, knownUids);
8441b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            collectKeys(mUidForeground, knownUids);
8451b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            collectKeys(mUidRules, knownUids);
8461b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
8471b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            final int size = knownUids.size();
8481b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            for (int i = 0; i < size; i++) {
8491b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                final int uid = knownUids.keyAt(i);
8501b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                fout.print("  UID=");
8511b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                fout.print(uid);
8521b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
8531b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                fout.print(" policy=");
8541b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                final int policyIndex = mUidPolicy.indexOfKey(uid);
8551b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                if (policyIndex < 0) {
8561b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                    fout.print("UNKNOWN");
8571b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                } else {
8581b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                    dumpPolicy(fout, mUidPolicy.valueAt(policyIndex));
8591b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                }
8601b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
8611b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                fout.print(" foreground=");
8621b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                final int foregroundIndex = mUidPidForeground.indexOfKey(uid);
8631b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                if (foregroundIndex < 0) {
8641b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                    fout.print("UNKNOWN");
8651b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                } else {
8661b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                    dumpSparseBooleanArray(fout, mUidPidForeground.valueAt(foregroundIndex));
8671b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                }
8681b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
8691b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                fout.print(" rules=");
8701b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                final int rulesIndex = mUidRules.indexOfKey(uid);
8711b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                if (rulesIndex < 0) {
8721b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                    fout.print("UNKNOWN");
8731b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                } else {
8741b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                    dumpRules(fout, mUidRules.valueAt(rulesIndex));
8751b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                }
8761b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
8771b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey                fout.println();
8781b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            }
8791b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        }
8801b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    }
8819599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey
8829599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey    @Override
8839599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey    public boolean isUidForeground(int uid) {
884497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
885497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
8869599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey        synchronized (mRulesLock) {
8879599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey            // only really in foreground when screen is also on
8889599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey            return mUidForeground.get(uid, false) && mScreenOn;
8899599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey        }
890c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey    }
891c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
892d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    /**
893d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey     * Foreground for PID changed; recompute foreground at UID level. If
89421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey     * changed, will trigger {@link #updateRulesForUidLocked(int)}.
895d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey     */
89621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private void computeUidForegroundLocked(int uid) {
897d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
898d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
899d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        // current pid is dropping foreground; examine other pids
900d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        boolean uidForeground = false;
901d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        final int size = pidForeground.size();
902d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        for (int i = 0; i < size; i++) {
903d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey            if (pidForeground.valueAt(i)) {
904d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey                uidForeground = true;
905d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey                break;
906d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey            }
907d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        }
908d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
909d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        final boolean oldUidForeground = mUidForeground.get(uid, false);
910d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        if (oldUidForeground != uidForeground) {
911d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey            // foreground changed, push updated rules
912d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey            mUidForeground.put(uid, uidForeground);
91321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            updateRulesForUidLocked(uid);
914a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        }
915a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    }
916a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
917a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    private void updateScreenOn() {
918a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        synchronized (mRulesLock) {
919a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            try {
920a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                mScreenOn = mPowerManager.isScreenOn();
921a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            } catch (RemoteException e) {
922a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            }
92321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            updateRulesForScreenLocked();
924d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        }
925d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey    }
926d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
927a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    /**
928a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey     * Update rules that might be changed by {@link #mScreenOn} value.
929a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey     */
93021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private void updateRulesForScreenLocked() {
931a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        // only update rules for anyone with foreground activities
932a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        final int size = mUidForeground.size();
933a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        for (int i = 0; i < size; i++) {
934a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            if (mUidForeground.valueAt(i)) {
935a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey                final int uid = mUidForeground.keyAt(i);
93621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey                updateRulesForUidLocked(uid);
937a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey            }
938a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey        }
939a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey    }
940a4620793038b9a9163b26c6ece882cb454fcbf87Jeff Sharkey
94121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private void updateRulesForUidLocked(int uid) {
942d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        final int uidPolicy = getUidPolicy(uid);
9439599cc5f21152860af9d18015b1398b50743da76Jeff Sharkey        final boolean uidForeground = isUidForeground(uid);
944d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
945c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        // derive active rules based on policy and active state
946c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        int uidRules = RULE_ALLOW_ALL;
947fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey        if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
948fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey            // uid in background, and policy says to block metered data
949fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey            uidRules = RULE_REJECT_METERED;
950d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey        }
951d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey
952c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        // TODO: only dispatch when rules actually change
953c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
954c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        // record rule locally to dispatch to new listeners
955c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        mUidRules.put(uid, uidRules);
956c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey
957fdfef57f498e3021a34342538aef9f1c7ccbae78Jeff Sharkey        final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
958497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey        //kernelSetUidRejectPaid(uid, rejectPaid);
959497e4437af386930dff3bd55296d128bd4520959Jeff Sharkey
960c006f1aec15454782c35e028ad64d79a5c161cc1Jeff Sharkey        // dispatch changed rule to existing listeners
9614414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey        mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
9624414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey    }
9634414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey
9644414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey    private Handler.Callback mHandlerCallback = new Handler.Callback() {
9654414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey        /** {@inheritDoc} */
9664414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey        public boolean handleMessage(Message msg) {
9674414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey            switch (msg.what) {
9684414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                case MSG_RULES_CHANGED: {
9694414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    final int uid = msg.arg1;
9704414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    final int uidRules = msg.arg2;
9714414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    final int length = mListeners.beginBroadcast();
9724414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    for (int i = 0; i < length; i++) {
9734414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                        final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
9744414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                        if (listener != null) {
9754414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                            try {
9764414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                                listener.onUidRulesChanged(uid, uidRules);
9774414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                            } catch (RemoteException e) {
9784414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                            }
9794414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                        }
9804414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    }
9814414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    mListeners.finishBroadcast();
9824414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    return true;
9834414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                }
9844414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                case MSG_METERED_IFACES_CHANGED: {
9854414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    final String[] meteredIfaces = (String[]) msg.obj;
9864414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    final int length = mListeners.beginBroadcast();
9874414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    for (int i = 0; i < length; i++) {
9884414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                        final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
9894414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                        if (listener != null) {
9904414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                            try {
9914414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                                listener.onMeteredIfacesChanged(meteredIfaces);
9924414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                            } catch (RemoteException e) {
9934414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                            }
9944414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                        }
9954414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    }
9964414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    mListeners.finishBroadcast();
9974414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    return true;
9984414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                }
9994414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                default: {
10004414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey                    return false;
1001af11d4859582a9736aa204562f0beac5a7d60934Jeff Sharkey                }
1002af11d4859582a9736aa204562f0beac5a7d60934Jeff Sharkey            }
1003af11d4859582a9736aa204562f0beac5a7d60934Jeff Sharkey        }
10044414cea13908b8230640f84ef39603d68ff9c377Jeff Sharkey    };
100522c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
100622c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    private String getActiveSubscriberId() {
100722c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
100822c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey                Context.TELEPHONY_SERVICE);
100922c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey        return telephony.getSubscriberId();
101022c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey    }
101122c055e6424e0e9579711545d8f4800c0f796db8Jeff Sharkey
10121b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
10131b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        final int size = source.size();
10141b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        for (int i = 0; i < size; i++) {
10151b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            target.put(source.keyAt(i), true);
10161b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        }
10171b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    }
10181b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
10191b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    private static void collectKeys(SparseBooleanArray source, SparseBooleanArray target) {
10201b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        final int size = source.size();
10211b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        for (int i = 0; i < size; i++) {
10221b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            target.put(source.keyAt(i), true);
10231b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        }
10241b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    }
10251b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey
10261b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    private static void dumpSparseBooleanArray(PrintWriter fout, SparseBooleanArray value) {
10271b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        fout.print("[");
10281b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        final int size = value.size();
10291b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        for (int i = 0; i < size; i++) {
10301b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            fout.print(value.keyAt(i) + "=" + value.valueAt(i));
10311b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey            if (i < size - 1) fout.print(",");
10321b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        }
10331b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey        fout.print("]");
10341b861278a2051f53ce7955fb7992fa536dc975d9Jeff Sharkey    }
103521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
103621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static int readIntAttribute(XmlPullParser in, String name) throws IOException {
103721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        final String value = in.getAttributeValue(null, name);
103821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        try {
103921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            return Integer.parseInt(value);
104021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } catch (NumberFormatException e) {
104121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
104221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
104321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
104421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
104521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static long readLongAttribute(XmlPullParser in, String name) throws IOException {
104621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        final String value = in.getAttributeValue(null, name);
104721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        try {
104821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            return Long.parseLong(value);
104921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        } catch (NumberFormatException e) {
105021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
105121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        }
105221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
105321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
105421c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static void writeIntAttribute(XmlSerializer out, String name, int value)
105521c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            throws IOException {
105621c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        out.attribute(null, name, Integer.toString(value));
105721c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
105821c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
105921c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    private static void writeLongAttribute(XmlSerializer out, String name, long value)
106021c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey            throws IOException {
106121c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey        out.attribute(null, name, Long.toString(value));
106221c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey    }
106321c9c45e5caf62b935354b74392fb40c4bf18529Jeff Sharkey
1064d5cdd597b895a48ffa9a8e39f8a2504cd9b905c4Jeff Sharkey}
1065