blob: 612bae21b24cdb2a081a684183439e7d99115382 [file] [log] [blame]
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.net;
18
Jeff Sharkeyf0ceede2011-08-02 17:22:34 -070019import static android.Manifest.permission.ACCESS_NETWORK_STATE;
Jeff Sharkey21c9c452011-06-07 12:26:43 -070020import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
Jeff Sharkey1b861272011-05-22 00:34:52 -070021import static android.Manifest.permission.DUMP;
Jeff Sharkey21c9c452011-06-07 12:26:43 -070022import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
Jeff Sharkey497e4432011-06-14 17:27:29 -070023import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
Jeff Sharkey22c055e2011-06-12 21:13:51 -070024import static android.Manifest.permission.READ_PHONE_STATE;
Amit Mahajan7c5befa2015-07-14 10:26:00 -070025import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
Jeff Sharkey02e21d62011-07-17 15:53:33 -070026import static android.content.Intent.ACTION_PACKAGE_ADDED;
Jeff Sharkeyb09540f2011-06-19 01:08:12 -070027import static android.content.Intent.ACTION_UID_REMOVED;
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -070028import static android.content.Intent.ACTION_USER_ADDED;
29import static android.content.Intent.ACTION_USER_REMOVED;
Jeff Sharkeyb09540f2011-06-19 01:08:12 -070030import static android.content.Intent.EXTRA_UID;
Erik Klinef851d6d2015-04-20 16:03:48 +090031import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
Felipe Leme1b103232016-01-22 09:44:57 -080032import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
33import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
34import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
Jeff Sharkey7474fe7b2016-03-21 13:12:59 -060035import static android.net.ConnectivityManager.TYPE_MOBILE;
36import static android.net.ConnectivityManager.TYPE_WIMAX;
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -070037import static android.net.ConnectivityManager.isNetworkTypeMobile;
38import static android.net.NetworkPolicy.CYCLE_NONE;
Jeff Sharkey22c055e2011-06-12 21:13:51 -070039import static android.net.NetworkPolicy.LIMIT_DISABLED;
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -070040import static android.net.NetworkPolicy.SNOOZE_NEVER;
Jeff Sharkey497e4432011-06-14 17:27:29 -070041import static android.net.NetworkPolicy.WARNING_DISABLED;
Jeff Sharkey14711eb2011-06-15 10:29:17 -070042import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
Xiaohui Chenb41c9f72015-06-17 15:55:37 -070043import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
Felipe Leme011b98f2016-02-10 17:28:31 -080044import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
Xiaohui Chenb41c9f72015-06-17 15:55:37 -070045import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
46import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
Jeff Sharkeydc988062015-09-14 10:09:47 -070047import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
Amith Yamasani15e472352015-04-24 19:06:07 -070048import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -070049import static android.net.NetworkPolicyManager.POLICY_NONE;
Jeff Sharkeyfdfef572011-06-16 15:07:48 -070050import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -070051import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
Felipe Leme70c57c22016-03-29 10:45:13 -070052import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
Jeff Sharkeyfdfef572011-06-16 15:07:48 -070053import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
Felipe Leme70c57c22016-03-29 10:45:13 -070054import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
Jeff Sharkeydc988062015-09-14 10:09:47 -070055import static android.net.NetworkPolicyManager.RULE_UNKNOWN;
Jeff Sharkeycd2ca402011-06-10 15:14:07 -070056import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070057import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
58import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -070059import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
60import static android.net.NetworkTemplate.MATCH_WIFI;
Jeff Sharkey4e814c32011-07-14 20:37:37 -070061import static android.net.NetworkTemplate.buildTemplateMobileAll;
Jeff Sharkey241dde22012-02-03 14:50:07 -080062import static android.net.TrafficStats.MB_IN_BYTES;
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -070063import static android.net.wifi.WifiManager.CHANGE_REASON_ADDED;
64import static android.net.wifi.WifiManager.CHANGE_REASON_REMOVED;
65import static android.net.wifi.WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION;
66import static android.net.wifi.WifiManager.EXTRA_CHANGE_REASON;
67import static android.net.wifi.WifiManager.EXTRA_NETWORK_INFO;
68import static android.net.wifi.WifiManager.EXTRA_WIFI_CONFIGURATION;
69import static android.net.wifi.WifiManager.EXTRA_WIFI_INFO;
Jeff Sharkey21c9c452011-06-07 12:26:43 -070070import static android.text.format.DateUtils.DAY_IN_MILLIS;
Felipe Leme03e689d2016-03-02 16:17:38 -080071
Jeff Sharkey854b2b12012-04-13 16:03:40 -070072import static com.android.internal.util.ArrayUtils.appendInt;
Jeff Sharkey21c9c452011-06-07 12:26:43 -070073import static com.android.internal.util.Preconditions.checkNotNull;
Jeff Sharkeyded7b752013-03-22 13:43:41 -070074import static com.android.internal.util.XmlUtils.readBooleanAttribute;
75import static com.android.internal.util.XmlUtils.readIntAttribute;
76import static com.android.internal.util.XmlUtils.readLongAttribute;
77import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
78import static com.android.internal.util.XmlUtils.writeIntAttribute;
79import static com.android.internal.util.XmlUtils.writeLongAttribute;
Jeff Sharkey961e3042011-08-29 16:02:57 -070080import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
Jeff Sharkey497e4432011-06-14 17:27:29 -070081import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
Jeff Sharkey7474fe7b2016-03-21 13:12:59 -060082
Jeff Sharkey21c9c452011-06-07 12:26:43 -070083import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
Felipe Lemeb85a6372016-01-14 16:16:16 -080084import static org.xmlpull.v1.XmlPullParser.END_TAG;
Jeff Sharkey21c9c452011-06-07 12:26:43 -070085import static org.xmlpull.v1.XmlPullParser.START_TAG;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070086
Dianne Hackborn88e98df2015-03-23 13:29:14 -070087import android.Manifest;
Dianne Hackborn497175b2014-07-01 12:56:08 -070088import android.app.ActivityManager;
Dianne Hackborn88e98df2015-03-23 13:29:14 -070089import android.app.AppGlobals;
Svet Ganov16a16892015-04-16 10:32:04 -070090import android.app.AppOpsManager;
Jeff Sharkeya4620792011-05-20 15:29:23 -070091import android.app.IActivityManager;
Jeff Sharkey497e4432011-06-14 17:27:29 -070092import android.app.INotificationManager;
Dianne Hackbornd23e0d62015-05-15 16:36:12 -070093import android.app.IUidObserver;
Jeff Sharkey497e4432011-06-14 17:27:29 -070094import android.app.Notification;
95import android.app.PendingIntent;
Amith Yamasani15e472352015-04-24 19:06:07 -070096import android.app.usage.UsageStatsManagerInternal;
Jeff Sharkeya4620792011-05-20 15:29:23 -070097import android.content.BroadcastReceiver;
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -070098import android.content.ComponentName;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070099import android.content.Context;
Jeff Sharkeya4620792011-05-20 15:29:23 -0700100import android.content.Intent;
101import android.content.IntentFilter;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700102import android.content.pm.ApplicationInfo;
Dianne Hackborn88e98df2015-03-23 13:29:14 -0700103import android.content.pm.IPackageManager;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700104import android.content.pm.PackageManager;
Amith Yamasani15e472352015-04-24 19:06:07 -0700105import android.content.pm.PackageManager.NameNotFoundException;
Jeff Sharkey8a8b5812012-03-21 18:13:36 -0700106import android.content.pm.UserInfo;
Jeff Sharkey497e4432011-06-14 17:27:29 -0700107import android.content.res.Resources;
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700108import android.net.ConnectivityManager;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700109import android.net.IConnectivityManager;
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700110import android.net.INetworkManagementEventObserver;
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700111import android.net.INetworkPolicyListener;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700112import android.net.INetworkPolicyManager;
Jeff Sharkey75279902011-05-24 18:39:45 -0700113import android.net.INetworkStatsService;
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -0700114import android.net.LinkProperties;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700115import android.net.NetworkIdentity;
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -0700116import android.net.NetworkInfo;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700117import android.net.NetworkPolicy;
Jeff Sharkey7c3e4422015-10-12 18:07:38 -0700118import android.net.NetworkPolicyManager;
Jeff Sharkeyf0ceede2011-08-02 17:22:34 -0700119import android.net.NetworkQuotaInfo;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700120import android.net.NetworkState;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700121import android.net.NetworkTemplate;
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -0700122import android.net.wifi.WifiConfiguration;
123import android.net.wifi.WifiInfo;
124import android.net.wifi.WifiManager;
Jeff Sharkeyf0ceede2011-08-02 17:22:34 -0700125import android.os.Binder;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700126import android.os.Environment;
127import android.os.Handler;
Amith Yamasani450a16b2013-09-18 16:28:50 -0700128import android.os.HandlerThread;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700129import android.os.IDeviceIdleController;
Ashish Sharma50fd36d2011-06-15 19:34:53 -0700130import android.os.INetworkManagementService;
Jeff Sharkeya4620792011-05-20 15:29:23 -0700131import android.os.IPowerManager;
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700132import android.os.Message;
Jeff Sharkey163e6442011-10-31 16:37:52 -0700133import android.os.MessageQueue.IdleHandler;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700134import android.os.PowerManager;
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700135import android.os.PowerManagerInternal;
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700136import android.os.RemoteCallbackList;
Jeff Sharkeya4620792011-05-20 15:29:23 -0700137import android.os.RemoteException;
Jeff Sharkey7474fe7b2016-03-21 13:12:59 -0600138import android.os.ResultReceiver;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700139import android.os.ServiceManager;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700140import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -0700141import android.os.UserManager;
Jeff Sharkey3a844fc2011-08-16 14:37:57 -0700142import android.provider.Settings;
Jeff Sharkey32566012014-12-02 18:30:14 -0800143import android.telephony.SubscriptionManager;
Jeff Sharkey22c055e2011-06-12 21:13:51 -0700144import android.telephony.TelephonyManager;
Jeff Sharkey497e4432011-06-14 17:27:29 -0700145import android.text.format.Formatter;
Jeff Sharkey22c055e2011-06-12 21:13:51 -0700146import android.text.format.Time;
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700147import android.util.ArrayMap;
148import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700149import android.util.AtomicFile;
Jeff Sharkeydc988062015-09-14 10:09:47 -0700150import android.util.DebugUtils;
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700151import android.util.Log;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700152import android.util.NtpTrustedTime;
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -0700153import android.util.Pair;
Jeff Sharkeya4620792011-05-20 15:29:23 -0700154import android.util.Slog;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700155import android.util.SparseBooleanArray;
156import android.util.SparseIntArray;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700157import android.util.TrustedTime;
158import android.util.Xml;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700159
Jeff Sharkey497e4432011-06-14 17:27:29 -0700160import com.android.internal.R;
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800161import com.android.internal.annotations.VisibleForTesting;
Felipe Lemeb85a6372016-01-14 16:16:16 -0800162import com.android.internal.content.PackageMonitor;
Jeff Sharkey32566012014-12-02 18:30:14 -0800163import com.android.internal.util.ArrayUtils;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700164import com.android.internal.util.FastXmlSerializer;
Jeff Sharkey8fc27e82012-04-04 20:40:58 -0700165import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkeydc988062015-09-14 10:09:47 -0700166import com.android.server.DeviceIdleController;
167import com.android.server.EventLogTags;
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700168import com.android.server.LocalServices;
Felipe Lemea9505cc2016-02-26 10:28:41 -0800169import com.android.server.SystemConfig;
Jeff Sharkey7474fe7b2016-03-21 13:12:59 -0600170
171import libcore.io.IoUtils;
172
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700173import com.google.android.collect.Lists;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700174
175import org.xmlpull.v1.XmlPullParser;
176import org.xmlpull.v1.XmlPullParserException;
177import org.xmlpull.v1.XmlSerializer;
178
179import java.io.File;
Jeff Sharkey1b861272011-05-22 00:34:52 -0700180import java.io.FileDescriptor;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700181import java.io.FileInputStream;
182import java.io.FileNotFoundException;
183import java.io.FileOutputStream;
184import java.io.IOException;
Jeff Sharkey1b861272011-05-22 00:34:52 -0700185import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100186import java.nio.charset.StandardCharsets;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700187import java.util.ArrayList;
188import java.util.Arrays;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700189import java.util.List;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700190
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700191/**
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700192 * Service that maintains low-level network policy rules, using
193 * {@link NetworkStatsService} statistics to drive those rules.
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700194 * <p>
195 * Derives active rules by combining a given policy with other system status,
196 * and delivers to listeners, such as {@link ConnectivityManager}, for
197 * enforcement.
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700198 */
Xiaohui Chen8dca36d2015-06-19 12:44:59 -0700199public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
Felipe Lemede4e8e32016-02-02 18:55:22 -0800200 static final String TAG = "NetworkPolicy";
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -0700201 private static final boolean LOGD = false;
Jeff Sharkey22c055e2011-06-12 21:13:51 -0700202 private static final boolean LOGV = false;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700203
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700204 private static final int VERSION_INIT = 1;
205 private static final int VERSION_ADDED_SNOOZE = 2;
Jeff Sharkey46645002011-07-27 21:11:21 -0700206 private static final int VERSION_ADDED_RESTRICT_BACKGROUND = 3;
Jeff Sharkeyf60d0af2011-11-30 15:28:02 -0800207 private static final int VERSION_ADDED_METERED = 4;
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -0800208 private static final int VERSION_SPLIT_SNOOZE = 5;
Jeff Sharkey9bf31502012-03-09 17:07:21 -0800209 private static final int VERSION_ADDED_TIMEZONE = 6;
Jeff Sharkey837f9242012-03-20 16:52:20 -0700210 private static final int VERSION_ADDED_INFERRED = 7;
Jeff Sharkey8a8b5812012-03-21 18:13:36 -0700211 private static final int VERSION_SWITCH_APP_ID = 8;
Jeff Sharkey8fc27e82012-04-04 20:40:58 -0700212 private static final int VERSION_ADDED_NETWORK_ID = 9;
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -0700213 private static final int VERSION_SWITCH_UID = 10;
214 private static final int VERSION_LATEST = VERSION_SWITCH_UID;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700215
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800216 @VisibleForTesting
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700217 public static final int TYPE_WARNING = 0x1;
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800218 @VisibleForTesting
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700219 public static final int TYPE_LIMIT = 0x2;
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800220 @VisibleForTesting
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700221 public static final int TYPE_LIMIT_SNOOZED = 0x3;
Jeff Sharkey497e4432011-06-14 17:27:29 -0700222
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700223 private static final String TAG_POLICY_LIST = "policy-list";
224 private static final String TAG_NETWORK_POLICY = "network-policy";
225 private static final String TAG_UID_POLICY = "uid-policy";
Jeff Sharkey8a8b5812012-03-21 18:13:36 -0700226 private static final String TAG_APP_POLICY = "app-policy";
Felipe Lemeb85a6372016-01-14 16:16:16 -0800227 private static final String TAG_WHITELIST = "whitelist";
228 private static final String TAG_RESTRICT_BACKGROUND = "restrict-background";
Felipe Lemea9505cc2016-02-26 10:28:41 -0800229 private static final String TAG_REVOKED_RESTRICT_BACKGROUND = "revoked-restrict-background";
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700230
231 private static final String ATTR_VERSION = "version";
Jeff Sharkey46645002011-07-27 21:11:21 -0700232 private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground";
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700233 private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate";
234 private static final String ATTR_SUBSCRIBER_ID = "subscriberId";
Jeff Sharkey8fc27e82012-04-04 20:40:58 -0700235 private static final String ATTR_NETWORK_ID = "networkId";
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700236 private static final String ATTR_CYCLE_DAY = "cycleDay";
Jeff Sharkey9bf31502012-03-09 17:07:21 -0800237 private static final String ATTR_CYCLE_TIMEZONE = "cycleTimezone";
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700238 private static final String ATTR_WARNING_BYTES = "warningBytes";
239 private static final String ATTR_LIMIT_BYTES = "limitBytes";
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700240 private static final String ATTR_LAST_SNOOZE = "lastSnooze";
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -0800241 private static final String ATTR_LAST_WARNING_SNOOZE = "lastWarningSnooze";
242 private static final String ATTR_LAST_LIMIT_SNOOZE = "lastLimitSnooze";
Jeff Sharkeyf60d0af2011-11-30 15:28:02 -0800243 private static final String ATTR_METERED = "metered";
Jeff Sharkey837f9242012-03-20 16:52:20 -0700244 private static final String ATTR_INFERRED = "inferred";
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700245 private static final String ATTR_UID = "uid";
Jeff Sharkey8a8b5812012-03-21 18:13:36 -0700246 private static final String ATTR_APP_ID = "appId";
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700247 private static final String ATTR_POLICY = "policy";
248
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800249 private static final String ACTION_ALLOW_BACKGROUND =
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -0800250 "com.android.server.net.action.ALLOW_BACKGROUND";
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800251 private static final String ACTION_SNOOZE_WARNING =
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -0800252 "com.android.server.net.action.SNOOZE_WARNING";
Jeff Sharkey3a844fc2011-08-16 14:37:57 -0700253
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700254 private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
255
Jeff Sharkey6f7af032011-11-01 18:25:15 -0700256 private static final int MSG_RULES_CHANGED = 1;
257 private static final int MSG_METERED_IFACES_CHANGED = 2;
Jeff Sharkey7e25b0e2011-11-08 15:43:12 -0800258 private static final int MSG_LIMIT_REACHED = 5;
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -0800259 private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6;
Jeff Sharkeye19f39b2012-05-24 10:21:16 -0700260 private static final int MSG_ADVISE_PERSIST_THRESHOLD = 7;
Jeff Sharkey0abe5562012-06-19 13:32:22 -0700261 private static final int MSG_SCREEN_ON_CHANGED = 8;
Felipe Leme9778f762016-01-27 14:46:39 -0800262 private static final int MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED = 9;
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700263
Jeff Sharkey75279902011-05-24 18:39:45 -0700264 private final Context mContext;
265 private final IActivityManager mActivityManager;
266 private final IPowerManager mPowerManager;
267 private final INetworkStatsService mNetworkStats;
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700268 private final INetworkManagementService mNetworkManager;
Amith Yamasani15e472352015-04-24 19:06:07 -0700269 private UsageStatsManagerInternal mUsageStats;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700270 private final TrustedTime mTime;
Stuart Scotte3e314d2015-04-20 14:07:45 -0700271 private final UserManager mUserManager;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700272
273 private IConnectivityManager mConnManager;
Jeff Sharkey497e4432011-06-14 17:27:29 -0700274 private INotificationManager mNotifManager;
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700275 private PowerManagerInternal mPowerManagerInternal;
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700276 private IDeviceIdleController mDeviceIdleController;
Jeff Sharkeya4620792011-05-20 15:29:23 -0700277
Dianne Hackborn497175b2014-07-01 12:56:08 -0700278 final Object mRulesLock = new Object();
Jeff Sharkeya4620792011-05-20 15:29:23 -0700279
Dianne Hackborn8ad2af72015-03-17 17:00:24 -0700280 volatile boolean mSystemReady;
Dianne Hackborn497175b2014-07-01 12:56:08 -0700281 volatile boolean mScreenOn;
282 volatile boolean mRestrictBackground;
283 volatile boolean mRestrictPower;
Dianne Hackborn8ad2af72015-03-17 17:00:24 -0700284 volatile boolean mDeviceIdleMode;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700285
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700286 private final boolean mSuppressDefaultPolicy;
287
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700288 /** Defined network policies. */
Jeff Sharkey32566012014-12-02 18:30:14 -0800289 final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<>();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700290 /** Currently active network rules for ifaces. */
Jeff Sharkey32566012014-12-02 18:30:14 -0800291 final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap<>();
Jeff Sharkey22c055e2011-06-12 21:13:51 -0700292
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -0700293 /** Defined UID policies. */
Dianne Hackborn497175b2014-07-01 12:56:08 -0700294 final SparseIntArray mUidPolicy = new SparseIntArray();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700295 /** Currently derived rules for each UID. */
Jeff Sharkey32566012014-12-02 18:30:14 -0800296 final SparseIntArray mUidRules = new SparseIntArray();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700297
Jeff Sharkeydc988062015-09-14 10:09:47 -0700298 final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
299 final SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
Felipe Leme011b98f2016-02-10 17:28:31 -0800300 final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
Jeff Sharkeydc988062015-09-14 10:09:47 -0700301
Jeff Sharkey02e21d62011-07-17 15:53:33 -0700302 /** Set of states for the child firewall chains. True if the chain is active. */
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700303 final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
304
Jeff Sharkey32566012014-12-02 18:30:14 -0800305 /**
306 * UIDs that have been white-listed to always be able to have network access
Dianne Hackborn4a503b12015-08-06 22:19:06 -0700307 * in power save mode, except device idle (doze) still applies.
308 * TODO: An int array might be sufficient
309 */
310 private final SparseBooleanArray mPowerSaveWhitelistExceptIdleAppIds = new SparseBooleanArray();
311
312 /**
313 * UIDs that have been white-listed to always be able to have network access
Jeff Sharkey32566012014-12-02 18:30:14 -0800314 * in power save mode.
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700315 * TODO: An int array might be sufficient
Jeff Sharkey32566012014-12-02 18:30:14 -0800316 */
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700317 private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700318
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700319 private final SparseBooleanArray mPowerSaveTempWhitelistAppIds = new SparseBooleanArray();
320
Felipe Lemeb85a6372016-01-14 16:16:16 -0800321 /**
322 * UIDs that have been white-listed to avoid restricted background.
323 */
324 private final SparseBooleanArray mRestrictBackgroundWhitelistUids = new SparseBooleanArray();
325
Felipe Lemea9505cc2016-02-26 10:28:41 -0800326 /**
327 * UIDs that have been initially white-listed by system to avoid restricted background.
328 */
329 private final SparseBooleanArray mDefaultRestrictBackgroundWhitelistUids =
330 new SparseBooleanArray();
331
332 /**
333 * UIDs that have been initially white-listed by system to avoid restricted background,
334 * but later revoked by user.
335 */
336 private final SparseBooleanArray mRestrictBackgroundWhitelistRevokedUids =
337 new SparseBooleanArray();
338
Jeff Sharkeyfdfef572011-06-16 15:07:48 -0700339 /** Set of ifaces that are metered. */
Jeff Sharkey32566012014-12-02 18:30:14 -0800340 private ArraySet<String> mMeteredIfaces = new ArraySet<>();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700341 /** Set of over-limit templates that have been notified. */
Jeff Sharkey32566012014-12-02 18:30:14 -0800342 private final ArraySet<NetworkTemplate> mOverLimitNotified = new ArraySet<>();
Jeff Sharkeyfdfef572011-06-16 15:07:48 -0700343
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700344 /** Set of currently active {@link Notification} tags. */
Dianne Hackborn497175b2014-07-01 12:56:08 -0700345 private final ArraySet<String> mActiveNotifs = new ArraySet<String>();
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700346
Dianne Hackbornd23e0d62015-05-15 16:36:12 -0700347 /** Foreground at UID granularity. */
Jeff Sharkey32566012014-12-02 18:30:14 -0800348 final SparseIntArray mUidState = new SparseIntArray();
Dianne Hackborn497175b2014-07-01 12:56:08 -0700349
Jeff Sharkey32566012014-12-02 18:30:14 -0800350 private final RemoteCallbackList<INetworkPolicyListener>
351 mListeners = new RemoteCallbackList<>();
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700352
Dianne Hackborn497175b2014-07-01 12:56:08 -0700353 final Handler mHandler;
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700354
355 private final AtomicFile mPolicyFile;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700356
Svet Ganov16a16892015-04-16 10:32:04 -0700357 private final AppOpsManager mAppOps;
358
Felipe Lemeb85a6372016-01-14 16:16:16 -0800359 private final MyPackageMonitor mPackageMonitor;
Amith Yamasani2a4ac4e2016-02-12 12:43:15 -0800360 private final IPackageManager mIPm;
361
Felipe Lemeb85a6372016-01-14 16:16:16 -0800362
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700363 // TODO: keep whitelist of system-critical services that should never have
364 // rules enforced, such as system, phone, and radio UIDs.
365
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700366 // TODO: migrate notifications to SystemUI
367
Jeff Sharkey75279902011-05-24 18:39:45 -0700368 public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
Ashish Sharma50fd36d2011-06-15 19:34:53 -0700369 IPowerManager powerManager, INetworkStatsService networkStats,
370 INetworkManagementService networkManagement) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700371 this(context, activityManager, powerManager, networkStats, networkManagement,
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700372 NtpTrustedTime.getInstance(context), getSystemDir(), false);
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700373 }
374
375 private static File getSystemDir() {
376 return new File(Environment.getDataDirectory(), "system");
377 }
378
379 public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
Ashish Sharma50fd36d2011-06-15 19:34:53 -0700380 IPowerManager powerManager, INetworkStatsService networkStats,
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700381 INetworkManagementService networkManagement, TrustedTime time, File systemDir,
382 boolean suppressDefaultPolicy) {
Jeff Sharkeya4620792011-05-20 15:29:23 -0700383 mContext = checkNotNull(context, "missing context");
384 mActivityManager = checkNotNull(activityManager, "missing activityManager");
385 mPowerManager = checkNotNull(powerManager, "missing powerManager");
Jeff Sharkey75279902011-05-24 18:39:45 -0700386 mNetworkStats = checkNotNull(networkStats, "missing networkStats");
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700387 mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700388 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService(
Dianne Hackborn1958e5e2015-06-12 18:11:41 -0700389 Context.DEVICE_IDLE_CONTROLLER));
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700390 mTime = checkNotNull(time, "missing TrustedTime");
Stuart Scotte3e314d2015-04-20 14:07:45 -0700391 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Amith Yamasani2a4ac4e2016-02-12 12:43:15 -0800392 mIPm = AppGlobals.getPackageManager();
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700393
Amith Yamasani450a16b2013-09-18 16:28:50 -0700394 HandlerThread thread = new HandlerThread(TAG);
395 thread.start();
396 mHandler = new Handler(thread.getLooper(), mHandlerCallback);
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700397
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700398 mSuppressDefaultPolicy = suppressDefaultPolicy;
399
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700400 mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
Svet Ganov16a16892015-04-16 10:32:04 -0700401
402 mAppOps = context.getSystemService(AppOpsManager.class);
Felipe Lemeb85a6372016-01-14 16:16:16 -0800403
404 mPackageMonitor = new MyPackageMonitor();
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700405 }
406
407 public void bindConnectivityManager(IConnectivityManager connManager) {
408 mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
Jeff Sharkeya4620792011-05-20 15:29:23 -0700409 }
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700410
Jeff Sharkey497e4432011-06-14 17:27:29 -0700411 public void bindNotificationManager(INotificationManager notifManager) {
412 mNotifManager = checkNotNull(notifManager, "missing INotificationManager");
413 }
414
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700415 void updatePowerSaveWhitelistLocked() {
416 try {
Dianne Hackborn4a503b12015-08-06 22:19:06 -0700417 int[] whitelist = mDeviceIdleController.getAppIdWhitelistExceptIdle();
418 mPowerSaveWhitelistExceptIdleAppIds.clear();
419 if (whitelist != null) {
420 for (int uid : whitelist) {
421 mPowerSaveWhitelistExceptIdleAppIds.put(uid, true);
422 }
423 }
424 whitelist = mDeviceIdleController.getAppIdWhitelist();
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700425 mPowerSaveWhitelistAppIds.clear();
426 if (whitelist != null) {
427 for (int uid : whitelist) {
428 mPowerSaveWhitelistAppIds.put(uid, true);
429 }
430 }
431 } catch (RemoteException e) {
432 }
433 }
434
Felipe Lemea9505cc2016-02-26 10:28:41 -0800435 /**
436 * Whitelists pre-defined apps for restrict background, but only if the user didn't already
437 * revoke the whitelist.
438 *
439 * @return whether any uid has been added to {@link #mRestrictBackgroundWhitelistUids}.
440 */
441 boolean addDefaultRestrictBackgroundWhitelistUids() {
442 final SystemConfig sysConfig = SystemConfig.getInstance();
443 final PackageManager pm = mContext.getPackageManager();
444 final List<UserInfo> users = mUserManager.getUsers();
445 final int numberUsers = users.size();
446
447 final ArraySet<String> allowDataUsage = sysConfig.getAllowInDataUsageSave();
448 boolean changed = false;
449 for (int i = 0; i < allowDataUsage.size(); i++) {
450 final String pkg = allowDataUsage.valueAt(i);
451 if (LOGD)
452 Slog.d(TAG, "checking restricted background whitelisting for package " + pkg);
453 final ApplicationInfo app;
454 try {
455 app = pm.getApplicationInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY);
456 } catch (PackageManager.NameNotFoundException e) {
457 // Should not happen
458 Slog.wtf(TAG, "No ApplicationInfo for package " + pkg);
459 continue;
460 }
461 if (!app.isPrivilegedApp()) {
462 Slog.w(TAG, "getAllowInDataUsageSave() returned non-privileged app: " + pkg);
463 continue;
464 }
465 for (int j = 0; j < numberUsers; j++) {
466 final UserInfo user = users.get(i);
467 final int uid = UserHandle.getUid(user.id, app.uid);
468 mDefaultRestrictBackgroundWhitelistUids.append(uid, true);
469 if (LOGD) Slog.d(TAG, "revoked whistelist status for uid " + uid + ": "
470 + mRestrictBackgroundWhitelistRevokedUids.get(uid));
471 if (!mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
472 Slog.i(TAG, "adding default package " + pkg + " (uid " + uid + " for user "
473 + user.id + ") to restrict background whitelist");
474 mRestrictBackgroundWhitelistUids.append(uid, true);
475 changed = true;
476 }
477 }
478 }
479 return changed;
480 }
481
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700482 void updatePowerSaveTempWhitelistLocked() {
483 try {
Amith Yamasani06f08062015-06-12 13:23:33 -0700484 // Clear the states of the current whitelist
485 final int N = mPowerSaveTempWhitelistAppIds.size();
486 for (int i = 0; i < N; i++) {
487 mPowerSaveTempWhitelistAppIds.setValueAt(i, false);
488 }
489 // Update the states with the new whitelist
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700490 final int[] whitelist = mDeviceIdleController.getAppIdTempWhitelist();
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700491 if (whitelist != null) {
492 for (int uid : whitelist) {
493 mPowerSaveTempWhitelistAppIds.put(uid, true);
494 }
495 }
496 } catch (RemoteException e) {
497 }
498 }
499
Amith Yamasani06f08062015-06-12 13:23:33 -0700500 /**
501 * Remove unnecessary entries in the temp whitelist
502 */
503 void purgePowerSaveTempWhitelistLocked() {
504 final int N = mPowerSaveTempWhitelistAppIds.size();
505 for (int i = N - 1; i >= 0; i--) {
506 if (mPowerSaveTempWhitelistAppIds.valueAt(i) == false) {
507 mPowerSaveTempWhitelistAppIds.removeAt(i);
508 }
509 }
510 }
511
Jeff Sharkeya4620792011-05-20 15:29:23 -0700512 public void systemReady() {
Jeff Sharkey8c1dc722012-05-04 14:49:37 -0700513 if (!isBandwidthControlEnabled()) {
514 Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
515 return;
516 }
517
Amith Yamasani15e472352015-04-24 19:06:07 -0700518 mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
519
Felipe Lemeb85a6372016-01-14 16:16:16 -0800520 mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
521
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700522 synchronized (mRulesLock) {
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700523 updatePowerSaveWhitelistLocked();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700524 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
525 mPowerManagerInternal.registerLowPowerModeObserver(
526 new PowerManagerInternal.LowPowerModeListener() {
527 @Override
528 public void onLowPowerModeChanged(boolean enabled) {
Felipe Leme011b98f2016-02-10 17:28:31 -0800529 if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700530 synchronized (mRulesLock) {
531 if (mRestrictPower != enabled) {
532 mRestrictPower = enabled;
Felipe Leme011b98f2016-02-10 17:28:31 -0800533 updateRulesForRestrictPowerLocked();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700534 updateRulesForGlobalChangeLocked(true);
535 }
536 }
537 }
538 });
539 mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
Dianne Hackborn8ad2af72015-03-17 17:00:24 -0700540 mSystemReady = true;
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700541
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700542 // read policy from disk
543 readPolicyLocked();
Jeff Sharkey46645002011-07-27 21:11:21 -0700544
Felipe Lemea9505cc2016-02-26 10:28:41 -0800545 if (addDefaultRestrictBackgroundWhitelistUids()) {
546 writePolicyLocked();
547 }
548
Jeff Sharkeydc988062015-09-14 10:09:47 -0700549 updateRulesForGlobalChangeLocked(false);
550 updateNotificationsLocked();
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700551 }
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700552
Jeff Sharkeya4620792011-05-20 15:29:23 -0700553 updateScreenOn();
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700554
Jeff Sharkeya4620792011-05-20 15:29:23 -0700555 try {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700556 mActivityManager.registerUidObserver(mUidObserver,
557 ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE);
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700558 mNetworkManager.registerObserver(mAlertObserver);
559 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700560 // ignored; both services live in system_server
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700561 }
562
Jeff Sharkeya4620792011-05-20 15:29:23 -0700563 // TODO: traverse existing processes to know foreground state, or have
564 // activitymanager dispatch current state when new observer attached.
565
566 final IntentFilter screenFilter = new IntentFilter();
567 screenFilter.addAction(Intent.ACTION_SCREEN_ON);
568 screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
Jeff Sharkey0abe5562012-06-19 13:32:22 -0700569 mContext.registerReceiver(mScreenReceiver, screenFilter);
Jeff Sharkeya4620792011-05-20 15:29:23 -0700570
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700571 // listen for changes to power save whitelist
572 final IntentFilter whitelistFilter = new IntentFilter(
573 PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
574 mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
575
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700576 DeviceIdleController.LocalService deviceIdleService
577 = LocalServices.getService(DeviceIdleController.LocalService.class);
578 deviceIdleService.setNetworkPolicyTempWhitelistCallback(mTempPowerSaveChangedCallback);
579
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700580 // watch for network interfaces to be claimed
Erik Klinef851d6d2015-04-20 16:03:48 +0900581 final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
Jeff Sharkeyb09540f2011-06-19 01:08:12 -0700582 mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
583
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -0700584 // listen for package changes to update policy
Jeff Sharkey02e21d62011-07-17 15:53:33 -0700585 final IntentFilter packageFilter = new IntentFilter();
586 packageFilter.addAction(ACTION_PACKAGE_ADDED);
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -0700587 packageFilter.addDataScheme("package");
Jeff Sharkey02e21d62011-07-17 15:53:33 -0700588 mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700589
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -0700590 // listen for UID changes to update policy
591 mContext.registerReceiver(
592 mUidRemovedReceiver, new IntentFilter(ACTION_UID_REMOVED), null, mHandler);
593
594 // listen for user changes to update policy
595 final IntentFilter userFilter = new IntentFilter();
596 userFilter.addAction(ACTION_USER_ADDED);
597 userFilter.addAction(ACTION_USER_REMOVED);
598 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
599
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700600 // listen for stats update events
Jeff Sharkey497e4432011-06-14 17:27:29 -0700601 final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
602 mContext.registerReceiver(
603 mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
604
Jeff Sharkey3a844fc2011-08-16 14:37:57 -0700605 // listen for restrict background changes from notifications
606 final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
607 mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
608
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -0800609 // listen for snooze warning from notifications
610 final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING);
611 mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
612 MANAGE_NETWORK_POLICY, mHandler);
613
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -0700614 // listen for configured wifi networks to be removed
615 final IntentFilter wifiConfigFilter = new IntentFilter(CONFIGURED_NETWORKS_CHANGED_ACTION);
Vinit Deshpande92d141f2014-09-10 18:05:10 -0700616 mContext.registerReceiver(mWifiConfigReceiver, wifiConfigFilter, null, mHandler);
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -0700617
618 // listen for wifi state changes to catch metered hint
619 final IntentFilter wifiStateFilter = new IntentFilter(
620 WifiManager.NETWORK_STATE_CHANGED_ACTION);
Vinit Deshpande92d141f2014-09-10 18:05:10 -0700621 mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -0700622
Xiaohui Chen8dca36d2015-06-19 12:44:59 -0700623 mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
Amith Yamasani15e472352015-04-24 19:06:07 -0700624
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700625 }
626
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700627 final private IUidObserver mUidObserver = new IUidObserver.Stub() {
Dianne Hackbornd23e0d62015-05-15 16:36:12 -0700628 @Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
Dianne Hackborn497175b2014-07-01 12:56:08 -0700629 synchronized (mRulesLock) {
Dianne Hackbornd23e0d62015-05-15 16:36:12 -0700630 updateUidStateLocked(uid, procState);
Dianne Hackborn497175b2014-07-01 12:56:08 -0700631 }
Dianne Hackborna93c2c12012-05-31 15:29:36 -0700632 }
633
Dianne Hackbornd23e0d62015-05-15 16:36:12 -0700634 @Override public void onUidGone(int uid) throws RemoteException {
Dianne Hackborn497175b2014-07-01 12:56:08 -0700635 synchronized (mRulesLock) {
Dianne Hackbornd23e0d62015-05-15 16:36:12 -0700636 removeUidStateLocked(uid);
Dianne Hackborn497175b2014-07-01 12:56:08 -0700637 }
Jeff Sharkeya4620792011-05-20 15:29:23 -0700638 }
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700639
640 @Override public void onUidActive(int uid) throws RemoteException {
641 }
642
643 @Override public void onUidIdle(int uid) throws RemoteException {
644 }
Jeff Sharkeya4620792011-05-20 15:29:23 -0700645 };
646
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700647 final private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() {
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700648 @Override
649 public void onReceive(Context context, Intent intent) {
650 // on background handler thread, and POWER_SAVE_WHITELIST_CHANGED is protected
651 synchronized (mRulesLock) {
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700652 updatePowerSaveWhitelistLocked();
653 updateRulesForGlobalChangeLocked(false);
Dianne Hackborn0b4daca2015-04-27 09:47:32 -0700654 }
655 }
656 };
657
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700658 final private Runnable mTempPowerSaveChangedCallback = new Runnable() {
659 @Override
660 public void run() {
661 synchronized (mRulesLock) {
662 updatePowerSaveTempWhitelistLocked();
663 updateRulesForTempWhitelistChangeLocked();
664 purgePowerSaveTempWhitelistLocked();
665 }
666 }
667 };
668
669 final private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
Jeff Sharkeya4620792011-05-20 15:29:23 -0700670 @Override
671 public void onReceive(Context context, Intent intent) {
Jeff Sharkey29afa142012-12-04 17:21:21 -0800672 // screen-related broadcasts are protected by system, no need
673 // for permissions check.
674 mHandler.obtainMessage(MSG_SCREEN_ON_CHANGED).sendToTarget();
Jeff Sharkeya4620792011-05-20 15:29:23 -0700675 }
676 };
677
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700678 final private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
Jeff Sharkeyb09540f2011-06-19 01:08:12 -0700679 @Override
680 public void onReceive(Context context, Intent intent) {
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -0700681 // on background handler thread, and PACKAGE_ADDED is protected
Jeff Sharkey02e21d62011-07-17 15:53:33 -0700682
683 final String action = intent.getAction();
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -0700684 final int uid = intent.getIntExtra(EXTRA_UID, -1);
685 if (uid == -1) return;
Jeff Sharkey8a8b5812012-03-21 18:13:36 -0700686
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -0700687 if (ACTION_PACKAGE_ADDED.equals(action)) {
688 // update rules for UID, since it might be subject to
689 // global background data policy
690 if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
691 synchronized (mRulesLock) {
Felipe Lemef28983d2016-03-25 12:18:23 -0700692 updateRestrictionRulesForUidLocked(uid);
Jeff Sharkey02e21d62011-07-17 15:53:33 -0700693 }
Jeff Sharkeyb09540f2011-06-19 01:08:12 -0700694 }
695 }
696 };
697
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700698 final private BroadcastReceiver mUidRemovedReceiver = new BroadcastReceiver() {
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -0700699 @Override
700 public void onReceive(Context context, Intent intent) {
701 // on background handler thread, and UID_REMOVED is protected
702
703 final int uid = intent.getIntExtra(EXTRA_UID, -1);
704 if (uid == -1) return;
705
706 // remove any policy and update rules to clean up
707 if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
708 synchronized (mRulesLock) {
709 mUidPolicy.delete(uid);
Felipe Lemef28983d2016-03-25 12:18:23 -0700710 updateRuleForRestrictBackgroundLocked(uid);
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -0700711 writePolicyLocked();
712 }
713 }
714 };
715
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700716 final private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -0700717 @Override
718 public void onReceive(Context context, Intent intent) {
719 // on background handler thread, and USER_ADDED and USER_REMOVED
720 // broadcasts are protected
721
722 final String action = intent.getAction();
723 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
724 if (userId == -1) return;
725
Amith Yamasani15e472352015-04-24 19:06:07 -0700726 switch (action) {
727 case ACTION_USER_REMOVED:
728 case ACTION_USER_ADDED:
729 synchronized (mRulesLock) {
Fyodor Kupolova31c5912016-01-22 11:26:09 -0800730 // Remove any persistable state for the given user; both cleaning up after a
Amith Yamasani15e472352015-04-24 19:06:07 -0700731 // USER_REMOVED, and one last sanity check during USER_ADDED
Fyodor Kupolova31c5912016-01-22 11:26:09 -0800732 removeUserStateLocked(userId);
Amith Yamasani15e472352015-04-24 19:06:07 -0700733 // Update global restrict for new user
734 updateRulesForGlobalChangeLocked(true);
735 }
736 break;
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -0700737 }
738 }
739 };
740
Jeff Sharkey21c9c452011-06-07 12:26:43 -0700741 /**
Jeff Sharkey497e4432011-06-14 17:27:29 -0700742 * Receiver that watches for {@link INetworkStatsService} updates, which we
743 * use to check against {@link NetworkPolicy#warningBytes}.
744 */
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700745 final private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() {
Jeff Sharkey497e4432011-06-14 17:27:29 -0700746 @Override
747 public void onReceive(Context context, Intent intent) {
748 // on background handler thread, and verified
749 // READ_NETWORK_USAGE_HISTORY permission above.
750
Jeff Sharkey684c54a2011-11-16 17:46:30 -0800751 maybeRefreshTrustedTime();
Jeff Sharkey497e4432011-06-14 17:27:29 -0700752 synchronized (mRulesLock) {
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700753 updateNetworkEnabledLocked();
Jeff Sharkey497e4432011-06-14 17:27:29 -0700754 updateNotificationsLocked();
755 }
756 }
757 };
758
759 /**
Jeff Sharkey3a844fc2011-08-16 14:37:57 -0700760 * Receiver that watches for {@link Notification} control of
761 * {@link #mRestrictBackground}.
762 */
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700763 final private BroadcastReceiver mAllowReceiver = new BroadcastReceiver() {
Jeff Sharkey3a844fc2011-08-16 14:37:57 -0700764 @Override
765 public void onReceive(Context context, Intent intent) {
766 // on background handler thread, and verified MANAGE_NETWORK_POLICY
767 // permission above.
768
769 setRestrictBackground(false);
770 }
771 };
772
773 /**
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -0800774 * Receiver that watches for {@link Notification} control of
775 * {@link NetworkPolicy#lastWarningSnooze}.
776 */
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700777 final private BroadcastReceiver mSnoozeWarningReceiver = new BroadcastReceiver() {
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -0800778 @Override
779 public void onReceive(Context context, Intent intent) {
780 // on background handler thread, and verified MANAGE_NETWORK_POLICY
781 // permission above.
782
783 final NetworkTemplate template = intent.getParcelableExtra(EXTRA_NETWORK_TEMPLATE);
784 performSnooze(template, TYPE_WARNING);
785 }
786 };
787
788 /**
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -0700789 * Receiver that watches for {@link WifiConfiguration} to be changed.
790 */
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700791 final private BroadcastReceiver mWifiConfigReceiver = new BroadcastReceiver() {
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -0700792 @Override
793 public void onReceive(Context context, Intent intent) {
794 // on background handler thread, and verified CONNECTIVITY_INTERNAL
795 // permission above.
796
797 final int reason = intent.getIntExtra(EXTRA_CHANGE_REASON, CHANGE_REASON_ADDED);
798 if (reason == CHANGE_REASON_REMOVED) {
799 final WifiConfiguration config = intent.getParcelableExtra(
800 EXTRA_WIFI_CONFIGURATION);
Irfan Sheriff00a10a12012-04-27 21:24:17 -0700801 if (config.SSID != null) {
Jeff Sharkey2e4dce02012-12-18 17:06:06 -0800802 final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(config.SSID);
Irfan Sheriff00a10a12012-04-27 21:24:17 -0700803 synchronized (mRulesLock) {
804 if (mNetworkPolicy.containsKey(template)) {
805 mNetworkPolicy.remove(template);
806 writePolicyLocked();
807 }
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -0700808 }
809 }
810 }
811 }
812 };
813
814 /**
815 * Receiver that watches {@link WifiInfo} state changes to infer metered
816 * state. Ignores hints when policy is user-defined.
817 */
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700818 final private BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -0700819 @Override
820 public void onReceive(Context context, Intent intent) {
821 // on background handler thread, and verified CONNECTIVITY_INTERNAL
822 // permission above.
823
824 // ignore when not connected
825 final NetworkInfo netInfo = intent.getParcelableExtra(EXTRA_NETWORK_INFO);
826 if (!netInfo.isConnected()) return;
827
828 final WifiInfo info = intent.getParcelableExtra(EXTRA_WIFI_INFO);
829 final boolean meteredHint = info.getMeteredHint();
830
Jeff Sharkey2e4dce02012-12-18 17:06:06 -0800831 final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(info.getSSID());
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -0700832 synchronized (mRulesLock) {
833 NetworkPolicy policy = mNetworkPolicy.get(template);
834 if (policy == null && meteredHint) {
835 // policy doesn't exist, and AP is hinting that it's
836 // metered: create an inferred policy.
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800837 policy = newWifiPolicy(template, meteredHint);
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -0700838 addNetworkPolicyLocked(policy);
839
840 } else if (policy != null && policy.inferred) {
841 // policy exists, and was inferred: update its current
842 // metered state.
843 policy.metered = meteredHint;
844
845 // since this is inferred for each wifi session, just update
846 // rules without persisting.
847 updateNetworkRulesLocked();
848 }
849 }
850 }
851 };
852
Felipe Lemeb1a65ee2016-02-08 10:12:01 -0800853 static NetworkPolicy newWifiPolicy(NetworkTemplate template, boolean metered) {
854 return new NetworkPolicy(template, CYCLE_NONE, Time.TIMEZONE_UTC,
855 WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER,
856 metered, true);
857 }
858
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -0700859 /**
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700860 * Observer that watches for {@link INetworkManagementService} alerts.
861 */
Dianne Hackbornfd854ee2015-07-13 18:00:37 -0700862 final private INetworkManagementEventObserver mAlertObserver
863 = new BaseNetworkObserver() {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700864 @Override
865 public void limitReached(String limitName, String iface) {
866 // only someone like NMS should be calling us
867 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
868
Jeff Sharkey7e25b0e2011-11-08 15:43:12 -0800869 if (!LIMIT_GLOBAL_ALERT.equals(limitName)) {
870 mHandler.obtainMessage(MSG_LIMIT_REACHED, iface).sendToTarget();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700871 }
872 }
873 };
874
875 /**
Jeff Sharkey497e4432011-06-14 17:27:29 -0700876 * Check {@link NetworkPolicy} against current {@link INetworkStatsService}
877 * to show visible notifications as needed.
878 */
Dianne Hackborn497175b2014-07-01 12:56:08 -0700879 void updateNotificationsLocked() {
Jeff Sharkey497e4432011-06-14 17:27:29 -0700880 if (LOGV) Slog.v(TAG, "updateNotificationsLocked()");
881
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700882 // keep track of previously active notifications
Dianne Hackborn497175b2014-07-01 12:56:08 -0700883 final ArraySet<String> beforeNotifs = new ArraySet<String>(mActiveNotifs);
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700884 mActiveNotifs.clear();
Jeff Sharkey497e4432011-06-14 17:27:29 -0700885
886 // TODO: when switching to kernel notifications, compute next future
887 // cycle boundary to recompute notifications.
888
Jeff Sharkey02e21d62011-07-17 15:53:33 -0700889 // examine stats for each active policy
Jeff Sharkey684c54a2011-11-16 17:46:30 -0800890 final long currentTime = currentTimeMillis();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700891 for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
892 final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700893 // ignore policies that aren't relevant to user
894 if (!isTemplateRelevant(policy.template)) continue;
Jeff Sharkey8fc27e82012-04-04 20:40:58 -0700895 if (!policy.hasCycle()) continue;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700896
Jeff Sharkey497e4432011-06-14 17:27:29 -0700897 final long start = computeLastCycleBoundary(currentTime, policy);
898 final long end = currentTime;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700899 final long totalBytes = getTotalBytes(policy.template, start, end);
Jeff Sharkey497e4432011-06-14 17:27:29 -0700900
Jeff Sharkey50e7e512011-10-10 16:50:35 -0700901 if (policy.isOverLimit(totalBytes)) {
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -0800902 if (policy.lastLimitSnooze >= start) {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700903 enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
904 } else {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700905 enqueueNotification(policy, TYPE_LIMIT, totalBytes);
906 notifyOverLimitLocked(policy.template);
907 }
908
Jeff Sharkey497e4432011-06-14 17:27:29 -0700909 } else {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700910 notifyUnderLimitLocked(policy.template);
Jeff Sharkey497e4432011-06-14 17:27:29 -0700911
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -0800912 if (policy.isOverWarning(totalBytes) && policy.lastWarningSnooze < start) {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700913 enqueueNotification(policy, TYPE_WARNING, totalBytes);
Jeff Sharkey497e4432011-06-14 17:27:29 -0700914 }
915 }
Jeff Sharkey02e21d62011-07-17 15:53:33 -0700916 }
917
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700918 // cancel stale notifications that we didn't renew above
Dianne Hackborn497175b2014-07-01 12:56:08 -0700919 for (int i = beforeNotifs.size()-1; i >= 0; i--) {
920 final String tag = beforeNotifs.valueAt(i);
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700921 if (!mActiveNotifs.contains(tag)) {
922 cancelNotification(tag);
923 }
924 }
925 }
926
927 /**
928 * Test if given {@link NetworkTemplate} is relevant to user based on
Jeff Sharkey8fc27e82012-04-04 20:40:58 -0700929 * current device state, such as when
930 * {@link TelephonyManager#getSubscriberId()} matches. This is regardless of
931 * data connection status.
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700932 */
933 private boolean isTemplateRelevant(NetworkTemplate template) {
Jeff Sharkey32566012014-12-02 18:30:14 -0800934 if (template.isMatchRuleMobile()) {
935 final TelephonyManager tele = TelephonyManager.from(mContext);
936 final SubscriptionManager sub = SubscriptionManager.from(mContext);
Jeff Sharkey8fc27e82012-04-04 20:40:58 -0700937
Jeff Sharkey32566012014-12-02 18:30:14 -0800938 // Mobile template is relevant when any active subscriber matches
939 final int[] subIds = sub.getActiveSubscriptionIdList();
940 for (int subId : subIds) {
941 final String subscriberId = tele.getSubscriberId(subId);
942 final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
943 TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false);
944 if (template.matches(probeIdent)) {
945 return true;
Jeff Sharkey3a66cf32012-03-20 17:00:01 -0700946 }
Jeff Sharkey32566012014-12-02 18:30:14 -0800947 }
948 return false;
949 } else {
950 return true;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -0700951 }
Jeff Sharkey497e4432011-06-14 17:27:29 -0700952 }
953
954 /**
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700955 * Notify that given {@link NetworkTemplate} is over
956 * {@link NetworkPolicy#limitBytes}, potentially showing dialog to user.
957 */
958 private void notifyOverLimitLocked(NetworkTemplate template) {
959 if (!mOverLimitNotified.contains(template)) {
960 mContext.startActivity(buildNetworkOverLimitIntent(template));
961 mOverLimitNotified.add(template);
962 }
963 }
964
965 private void notifyUnderLimitLocked(NetworkTemplate template) {
966 mOverLimitNotified.remove(template);
967 }
968
969 /**
Jeff Sharkey497e4432011-06-14 17:27:29 -0700970 * Build unique tag that identifies an active {@link NetworkPolicy}
971 * notification of a specific type, like {@link #TYPE_LIMIT}.
972 */
973 private String buildNotificationTag(NetworkPolicy policy, int type) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700974 return TAG + ":" + policy.template.hashCode() + ":" + type;
Jeff Sharkey497e4432011-06-14 17:27:29 -0700975 }
976
977 /**
978 * Show notification for combined {@link NetworkPolicy} and specific type,
979 * like {@link #TYPE_LIMIT}. Okay to call multiple times.
980 */
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700981 private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes) {
Jeff Sharkey497e4432011-06-14 17:27:29 -0700982 final String tag = buildNotificationTag(policy, type);
983 final Notification.Builder builder = new Notification.Builder(mContext);
984 builder.setOnlyAlertOnce(true);
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -0800985 builder.setWhen(0L);
Alan Viverette4a357cd2015-03-18 18:37:18 -0700986 builder.setColor(mContext.getColor(
Selim Cinek255dd042014-08-19 22:29:02 +0200987 com.android.internal.R.color.system_notification_accent_color));
Jeff Sharkey497e4432011-06-14 17:27:29 -0700988
989 final Resources res = mContext.getResources();
990 switch (type) {
991 case TYPE_WARNING: {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700992 final CharSequence title = res.getText(R.string.data_usage_warning_title);
Jeff Sharkey8ca953d2011-09-14 19:56:11 -0700993 final CharSequence body = res.getString(R.string.data_usage_warning_body);
Jeff Sharkey497e4432011-06-14 17:27:29 -0700994
Jeff Sharkey50e7e512011-10-10 16:50:35 -0700995 builder.setSmallIcon(R.drawable.stat_notify_error);
Jeff Sharkey497e4432011-06-14 17:27:29 -0700996 builder.setTicker(title);
997 builder.setContentTitle(title);
998 builder.setContentText(body);
Jeff Sharkey14711eb2011-06-15 10:29:17 -0700999
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001000 final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template);
1001 builder.setDeleteIntent(PendingIntent.getBroadcast(
1002 mContext, 0, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
1003
1004 final Intent viewIntent = buildViewDataUsageIntent(policy.template);
Jeff Sharkey14711eb2011-06-15 10:29:17 -07001005 builder.setContentIntent(PendingIntent.getActivity(
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001006 mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT));
1007
Jeff Sharkey497e4432011-06-14 17:27:29 -07001008 break;
1009 }
1010 case TYPE_LIMIT: {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001011 final CharSequence body = res.getText(R.string.data_usage_limit_body);
1012
1013 final CharSequence title;
John Spurlockaedebda2014-07-14 14:36:32 -04001014 int icon = R.drawable.stat_notify_disabled_data;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001015 switch (policy.template.getMatchRule()) {
1016 case MATCH_MOBILE_3G_LOWER:
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001017 title = res.getText(R.string.data_usage_3g_limit_title);
Jeff Sharkey497e4432011-06-14 17:27:29 -07001018 break;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001019 case MATCH_MOBILE_4G:
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001020 title = res.getText(R.string.data_usage_4g_limit_title);
Jeff Sharkey497e4432011-06-14 17:27:29 -07001021 break;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001022 case MATCH_MOBILE_ALL:
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001023 title = res.getText(R.string.data_usage_mobile_limit_title);
Jeff Sharkey497e4432011-06-14 17:27:29 -07001024 break;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001025 case MATCH_WIFI:
1026 title = res.getText(R.string.data_usage_wifi_limit_title);
John Spurlockaedebda2014-07-14 14:36:32 -04001027 icon = R.drawable.stat_notify_error;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001028 break;
1029 default:
1030 title = null;
1031 break;
Jeff Sharkey497e4432011-06-14 17:27:29 -07001032 }
1033
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001034 builder.setOngoing(true);
John Spurlockaedebda2014-07-14 14:36:32 -04001035 builder.setSmallIcon(icon);
Jeff Sharkey497e4432011-06-14 17:27:29 -07001036 builder.setTicker(title);
1037 builder.setContentTitle(title);
1038 builder.setContentText(body);
Jeff Sharkey14711eb2011-06-15 10:29:17 -07001039
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001040 final Intent intent = buildNetworkOverLimitIntent(policy.template);
1041 builder.setContentIntent(PendingIntent.getActivity(
1042 mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
1043 break;
1044 }
1045 case TYPE_LIMIT_SNOOZED: {
1046 final long overBytes = totalBytes - policy.limitBytes;
1047 final CharSequence body = res.getString(R.string.data_usage_limit_snoozed_body,
1048 Formatter.formatFileSize(mContext, overBytes));
1049
1050 final CharSequence title;
1051 switch (policy.template.getMatchRule()) {
1052 case MATCH_MOBILE_3G_LOWER:
1053 title = res.getText(R.string.data_usage_3g_limit_snoozed_title);
1054 break;
1055 case MATCH_MOBILE_4G:
1056 title = res.getText(R.string.data_usage_4g_limit_snoozed_title);
1057 break;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001058 case MATCH_MOBILE_ALL:
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001059 title = res.getText(R.string.data_usage_mobile_limit_snoozed_title);
1060 break;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001061 case MATCH_WIFI:
1062 title = res.getText(R.string.data_usage_wifi_limit_snoozed_title);
1063 break;
1064 default:
1065 title = null;
1066 break;
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001067 }
1068
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001069 builder.setOngoing(true);
Jeff Sharkey50e7e512011-10-10 16:50:35 -07001070 builder.setSmallIcon(R.drawable.stat_notify_error);
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001071 builder.setTicker(title);
1072 builder.setContentTitle(title);
1073 builder.setContentText(body);
1074
1075 final Intent intent = buildViewDataUsageIntent(policy.template);
Jeff Sharkey14711eb2011-06-15 10:29:17 -07001076 builder.setContentIntent(PendingIntent.getActivity(
1077 mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
Jeff Sharkey497e4432011-06-14 17:27:29 -07001078 break;
1079 }
1080 }
1081
1082 // TODO: move to NotificationManager once we can mock it
1083 try {
1084 final String packageName = mContext.getPackageName();
1085 final int[] idReceived = new int[1];
1086 mNotifManager.enqueueNotificationWithTag(
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001087 packageName, packageName, tag, 0x0, builder.getNotification(), idReceived,
Xiaohui Chenbe3b0672015-09-02 13:29:22 -07001088 UserHandle.USER_ALL);
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001089 mActiveNotifs.add(tag);
Jeff Sharkey497e4432011-06-14 17:27:29 -07001090 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001091 // ignored; service lives in system_server
Jeff Sharkey497e4432011-06-14 17:27:29 -07001092 }
1093 }
1094
Jeff Sharkey3a844fc2011-08-16 14:37:57 -07001095 private void cancelNotification(String tag) {
1096 // TODO: move to NotificationManager once we can mock it
1097 try {
1098 final String packageName = mContext.getPackageName();
1099 mNotifManager.cancelNotificationWithTag(
Xiaohui Chenbe3b0672015-09-02 13:29:22 -07001100 packageName, tag, 0x0, UserHandle.USER_ALL);
Jeff Sharkey497e4432011-06-14 17:27:29 -07001101 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001102 // ignored; service lives in system_server
Jeff Sharkey497e4432011-06-14 17:27:29 -07001103 }
1104 }
1105
1106 /**
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001107 * Receiver that watches for {@link IConnectivityManager} to claim network
Jeff Sharkey22c055e2011-06-12 21:13:51 -07001108 * interfaces. Used to apply {@link NetworkPolicy} to matching networks.
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001109 */
Jeff Sharkeyb09540f2011-06-19 01:08:12 -07001110 private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001111 @Override
1112 public void onReceive(Context context, Intent intent) {
1113 // on background handler thread, and verified CONNECTIVITY_INTERNAL
1114 // permission above.
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001115
1116 maybeRefreshTrustedTime();
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001117 synchronized (mRulesLock) {
Jeff Sharkey22c055e2011-06-12 21:13:51 -07001118 ensureActiveMobilePolicyLocked();
Jeff Sharkey32566012014-12-02 18:30:14 -08001119 normalizePoliciesLocked();
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001120 updateNetworkEnabledLocked();
Jeff Sharkey02e21d62011-07-17 15:53:33 -07001121 updateNetworkRulesLocked();
1122 updateNotificationsLocked();
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001123 }
1124 }
1125 };
1126
1127 /**
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001128 * Proactively control network data connections when they exceed
1129 * {@link NetworkPolicy#limitBytes}.
1130 */
Dianne Hackborn497175b2014-07-01 12:56:08 -07001131 void updateNetworkEnabledLocked() {
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001132 if (LOGV) Slog.v(TAG, "updateNetworkEnabledLocked()");
1133
1134 // TODO: reset any policy-disabled networks when any policy is removed
1135 // completely, which is currently rare case.
1136
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001137 final long currentTime = currentTimeMillis();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001138 for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
1139 final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001140 // shortcut when policy has no limit
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07001141 if (policy.limitBytes == LIMIT_DISABLED || !policy.hasCycle()) {
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001142 setNetworkTemplateEnabled(policy.template, true);
1143 continue;
1144 }
1145
1146 final long start = computeLastCycleBoundary(currentTime, policy);
1147 final long end = currentTime;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001148 final long totalBytes = getTotalBytes(policy.template, start, end);
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001149
1150 // disable data connection when over limit and not snoozed
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001151 final boolean overLimitWithoutSnooze = policy.isOverLimit(totalBytes)
1152 && policy.lastLimitSnooze < start;
1153 final boolean networkEnabled = !overLimitWithoutSnooze;
Jeff Sharkey8e9992a2011-08-23 18:37:23 -07001154
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001155 setNetworkTemplateEnabled(policy.template, networkEnabled);
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001156 }
1157 }
1158
1159 /**
Jeff Sharkey32566012014-12-02 18:30:14 -08001160 * Proactively disable networks that match the given
1161 * {@link NetworkTemplate}.
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001162 */
1163 private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) {
Jeff Sharkey32566012014-12-02 18:30:14 -08001164 // TODO: reach into ConnectivityManager to proactively disable bringing
1165 // up this network, since we know that traffic will be blocked.
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001166 }
1167
1168 /**
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001169 * Examine all connected {@link NetworkState}, looking for
1170 * {@link NetworkPolicy} that need to be enforced. When matches found, set
1171 * remaining quota based on usage cycle and historical stats.
1172 */
Dianne Hackborn497175b2014-07-01 12:56:08 -07001173 void updateNetworkRulesLocked() {
Jeff Sharkey32566012014-12-02 18:30:14 -08001174 if (LOGV) Slog.v(TAG, "updateNetworkRulesLocked()");
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001175
1176 final NetworkState[] states;
1177 try {
1178 states = mConnManager.getAllNetworkState();
1179 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001180 // ignored; service lives in system_server
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001181 return;
1182 }
1183
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -07001184 // First, generate identities of all connected networks so we can
1185 // quickly compare them against all defined policies below.
1186 final ArrayList<Pair<String, NetworkIdentity>> connIdents = new ArrayList<>(states.length);
Dianne Hackborn497175b2014-07-01 12:56:08 -07001187 final ArraySet<String> connIfaces = new ArraySet<String>(states.length);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001188 for (NetworkState state : states) {
Wei Liub8eaf452016-01-25 10:32:27 -08001189 if (state.networkInfo != null && state.networkInfo.isConnected()) {
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001190 final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -07001191
1192 final String baseIface = state.linkProperties.getInterfaceName();
Jeff Sharkey9da2f1e2014-08-14 12:55:00 -07001193 if (baseIface != null) {
1194 connIdents.add(Pair.create(baseIface, ident));
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -07001195 }
1196
1197 // Stacked interfaces are considered to have same identity as
1198 // their parent network.
1199 final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
1200 for (LinkProperties stackedLink : stackedLinks) {
1201 final String stackedIface = stackedLink.getInterfaceName();
Jeff Sharkey9da2f1e2014-08-14 12:55:00 -07001202 if (stackedIface != null) {
1203 connIdents.add(Pair.create(stackedIface, ident));
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -07001204 }
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001205 }
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001206 }
1207 }
1208
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -07001209 // Apply policies against all connected interfaces found above
Jeff Sharkey02e21d62011-07-17 15:53:33 -07001210 mNetworkRules.clear();
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001211 final ArrayList<String> ifaceList = Lists.newArrayList();
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -07001212 for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001213 final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001214
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001215 ifaceList.clear();
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -07001216 for (int j = connIdents.size() - 1; j >= 0; j--) {
1217 final Pair<String, NetworkIdentity> ident = connIdents.get(j);
1218 if (policy.template.matches(ident.second)) {
1219 ifaceList.add(ident.first);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001220 }
1221 }
1222
1223 if (ifaceList.size() > 0) {
1224 final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
Jeff Sharkey02e21d62011-07-17 15:53:33 -07001225 mNetworkRules.put(policy, ifaces);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001226 }
1227 }
1228
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -07001229 long lowestRule = Long.MAX_VALUE;
Dianne Hackborn497175b2014-07-01 12:56:08 -07001230 final ArraySet<String> newMeteredIfaces = new ArraySet<String>(states.length);
Jeff Sharkeyfdfef572011-06-16 15:07:48 -07001231
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001232 // apply each policy that we found ifaces for; compute remaining data
1233 // based on current cycle and historical stats, and push to kernel.
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001234 final long currentTime = currentTimeMillis();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001235 for (int i = mNetworkRules.size()-1; i >= 0; i--) {
1236 final NetworkPolicy policy = mNetworkRules.keyAt(i);
1237 final String[] ifaces = mNetworkRules.valueAt(i);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001238
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07001239 final long start;
1240 final long totalBytes;
1241 if (policy.hasCycle()) {
1242 start = computeLastCycleBoundary(currentTime, policy);
1243 totalBytes = getTotalBytes(policy.template, start, currentTime);
1244 } else {
1245 start = Long.MAX_VALUE;
1246 totalBytes = 0;
1247 }
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001248
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001249 if (LOGD) {
Felipe Leme03e689d2016-03-02 16:17:38 -08001250 Slog.d(TAG, "applying policy " + policy + " to ifaces " + Arrays.toString(ifaces));
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001251 }
1252
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -07001253 final boolean hasWarning = policy.warningBytes != LIMIT_DISABLED;
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001254 final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED;
Jeff Sharkeyf60d0af2011-11-30 15:28:02 -08001255 if (hasLimit || policy.metered) {
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001256 final long quotaBytes;
Jeff Sharkeyf60d0af2011-11-30 15:28:02 -08001257 if (!hasLimit) {
1258 // metered network, but no policy limit; we still need to
1259 // restrict apps, so push really high quota.
1260 quotaBytes = Long.MAX_VALUE;
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001261 } else if (policy.lastLimitSnooze >= start) {
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001262 // snoozing past quota, but we still need to restrict apps,
1263 // so push really high quota.
1264 quotaBytes = Long.MAX_VALUE;
1265 } else {
1266 // remaining "quota" bytes are based on total usage in
1267 // current cycle. kernel doesn't like 0-byte rules, so we
1268 // set 1-byte quota and disable the radio later.
1269 quotaBytes = Math.max(1, policy.limitBytes - totalBytes);
1270 }
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001271
1272 if (ifaces.length > 1) {
1273 // TODO: switch to shared quota once NMS supports
1274 Slog.w(TAG, "shared quota unsupported; generating rule for each iface");
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001275 }
1276
Jeff Sharkeyfdfef572011-06-16 15:07:48 -07001277 for (String iface : ifaces) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001278 removeInterfaceQuota(iface);
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001279 setInterfaceQuota(iface, quotaBytes);
1280 newMeteredIfaces.add(iface);
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001281 }
1282 }
Jeff Sharkeyac3fcb12012-05-02 18:11:52 -07001283
1284 // keep track of lowest warning or limit of active policies
1285 if (hasWarning && policy.warningBytes < lowestRule) {
1286 lowestRule = policy.warningBytes;
1287 }
1288 if (hasLimit && policy.limitBytes < lowestRule) {
1289 lowestRule = policy.limitBytes;
1290 }
1291 }
1292
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001293 for (int i = connIfaces.size()-1; i >= 0; i--) {
1294 String iface = connIfaces.valueAt(i);
1295 removeInterfaceQuota(iface);
1296 setInterfaceQuota(iface, Long.MAX_VALUE);
1297 newMeteredIfaces.add(iface);
1298 }
1299
Jeff Sharkeye19f39b2012-05-24 10:21:16 -07001300 mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
Jeff Sharkeyfdfef572011-06-16 15:07:48 -07001301
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001302 // remove quota on any trailing interfaces
Dianne Hackborn497175b2014-07-01 12:56:08 -07001303 for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
1304 final String iface = mMeteredIfaces.valueAt(i);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001305 if (!newMeteredIfaces.contains(iface)) {
1306 removeInterfaceQuota(iface);
1307 }
1308 }
1309 mMeteredIfaces = newMeteredIfaces;
1310
Jeff Sharkeyfdfef572011-06-16 15:07:48 -07001311 final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001312 mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
Jeff Sharkey22c055e2011-06-12 21:13:51 -07001313 }
1314
1315 /**
1316 * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
1317 * have at least a default mobile policy defined.
1318 */
1319 private void ensureActiveMobilePolicyLocked() {
1320 if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()");
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001321 if (mSuppressDefaultPolicy) return;
1322
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07001323 final TelephonyManager tele = TelephonyManager.from(mContext);
Jeff Sharkey32566012014-12-02 18:30:14 -08001324 final SubscriptionManager sub = SubscriptionManager.from(mContext);
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07001325
Jeff Sharkey32566012014-12-02 18:30:14 -08001326 final int[] subIds = sub.getActiveSubscriptionIdList();
1327 for (int subId : subIds) {
1328 final String subscriberId = tele.getSubscriberId(subId);
1329 ensureActiveMobilePolicyLocked(subscriberId);
1330 }
1331 }
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07001332
Jeff Sharkey32566012014-12-02 18:30:14 -08001333 private void ensureActiveMobilePolicyLocked(String subscriberId) {
1334 // Poke around to see if we already have a policy
1335 final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE,
1336 TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false);
1337 for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
1338 final NetworkTemplate template = mNetworkPolicy.keyAt(i);
1339 if (template.matches(probeIdent)) {
1340 if (LOGD) {
1341 Slog.d(TAG, "Found template " + template + " which matches subscriber "
1342 + NetworkIdentity.scrubSubscriberId(subscriberId));
1343 }
1344 return;
Jeff Sharkey22c055e2011-06-12 21:13:51 -07001345 }
1346 }
1347
Jeff Sharkey32566012014-12-02 18:30:14 -08001348 Slog.i(TAG, "No policy for subscriber " + NetworkIdentity.scrubSubscriberId(subscriberId)
1349 + "; generating default policy");
Jeff Sharkey22c055e2011-06-12 21:13:51 -07001350
Jeff Sharkey32566012014-12-02 18:30:14 -08001351 // Build default mobile policy, and assume usage cycle starts today
1352 final long warningBytes = mContext.getResources().getInteger(
1353 com.android.internal.R.integer.config_networkPolicyDefaultWarning) * MB_IN_BYTES;
Jeff Sharkey22c055e2011-06-12 21:13:51 -07001354
Jeff Sharkey32566012014-12-02 18:30:14 -08001355 final Time time = new Time();
1356 time.setToNow();
Jeff Sharkey9bf31502012-03-09 17:07:21 -08001357
Jeff Sharkey32566012014-12-02 18:30:14 -08001358 final int cycleDay = time.monthDay;
1359 final String cycleTimezone = time.timezone;
Jeff Sharkey22c055e2011-06-12 21:13:51 -07001360
Jeff Sharkey32566012014-12-02 18:30:14 -08001361 final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
1362 final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone,
1363 warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true);
1364 addNetworkPolicyLocked(policy);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001365 }
1366
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001367 private void readPolicyLocked() {
Jeff Sharkey22c055e2011-06-12 21:13:51 -07001368 if (LOGV) Slog.v(TAG, "readPolicyLocked()");
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001369
1370 // clear any existing policy and read from disk
Jeff Sharkey22c055e2011-06-12 21:13:51 -07001371 mNetworkPolicy.clear();
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001372 mUidPolicy.clear();
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001373
1374 FileInputStream fis = null;
1375 try {
1376 fis = mPolicyFile.openRead();
1377 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001378 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001379
1380 int type;
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001381 int version = VERSION_INIT;
Felipe Lemeb85a6372016-01-14 16:16:16 -08001382 boolean insideWhitelist = false;
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001383 while ((type = in.next()) != END_DOCUMENT) {
1384 final String tag = in.getName();
1385 if (type == START_TAG) {
1386 if (TAG_POLICY_LIST.equals(tag)) {
1387 version = readIntAttribute(in, ATTR_VERSION);
Jeff Sharkey46645002011-07-27 21:11:21 -07001388 if (version >= VERSION_ADDED_RESTRICT_BACKGROUND) {
1389 mRestrictBackground = readBooleanAttribute(
1390 in, ATTR_RESTRICT_BACKGROUND);
1391 } else {
Jeff Sharkey3a844fc2011-08-16 14:37:57 -07001392 mRestrictBackground = false;
Jeff Sharkey46645002011-07-27 21:11:21 -07001393 }
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001394
1395 } else if (TAG_NETWORK_POLICY.equals(tag)) {
1396 final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
1397 final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID);
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07001398 final String networkId;
1399 if (version >= VERSION_ADDED_NETWORK_ID) {
1400 networkId = in.getAttributeValue(null, ATTR_NETWORK_ID);
1401 } else {
1402 networkId = null;
1403 }
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001404 final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
Jeff Sharkey9bf31502012-03-09 17:07:21 -08001405 final String cycleTimezone;
1406 if (version >= VERSION_ADDED_TIMEZONE) {
1407 cycleTimezone = in.getAttributeValue(null, ATTR_CYCLE_TIMEZONE);
1408 } else {
1409 cycleTimezone = Time.TIMEZONE_UTC;
1410 }
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001411 final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
1412 final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001413 final long lastLimitSnooze;
1414 if (version >= VERSION_SPLIT_SNOOZE) {
1415 lastLimitSnooze = readLongAttribute(in, ATTR_LAST_LIMIT_SNOOZE);
1416 } else if (version >= VERSION_ADDED_SNOOZE) {
1417 lastLimitSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001418 } else {
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001419 lastLimitSnooze = SNOOZE_NEVER;
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001420 }
Jeff Sharkeyf60d0af2011-11-30 15:28:02 -08001421 final boolean metered;
1422 if (version >= VERSION_ADDED_METERED) {
1423 metered = readBooleanAttribute(in, ATTR_METERED);
1424 } else {
1425 switch (networkTemplate) {
1426 case MATCH_MOBILE_3G_LOWER:
1427 case MATCH_MOBILE_4G:
1428 case MATCH_MOBILE_ALL:
1429 metered = true;
1430 break;
1431 default:
1432 metered = false;
1433 }
1434 }
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001435 final long lastWarningSnooze;
1436 if (version >= VERSION_SPLIT_SNOOZE) {
1437 lastWarningSnooze = readLongAttribute(in, ATTR_LAST_WARNING_SNOOZE);
1438 } else {
1439 lastWarningSnooze = SNOOZE_NEVER;
1440 }
Jeff Sharkey837f9242012-03-20 16:52:20 -07001441 final boolean inferred;
1442 if (version >= VERSION_ADDED_INFERRED) {
1443 inferred = readBooleanAttribute(in, ATTR_INFERRED);
1444 } else {
1445 inferred = false;
1446 }
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001447
Jeff Sharkey32566012014-12-02 18:30:14 -08001448 final NetworkTemplate template = new NetworkTemplate(networkTemplate,
1449 subscriberId, networkId);
Jeff Sharkey7474fe7b2016-03-21 13:12:59 -06001450 if (template.isPersistable()) {
1451 mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay,
1452 cycleTimezone, warningBytes, limitBytes, lastWarningSnooze,
1453 lastLimitSnooze, metered, inferred));
1454 }
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001455
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001456 } else if (TAG_UID_POLICY.equals(tag)) {
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001457 final int uid = readIntAttribute(in, ATTR_UID);
1458 final int policy = readIntAttribute(in, ATTR_POLICY);
1459
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001460 if (UserHandle.isApp(uid)) {
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001461 setUidPolicyUncheckedLocked(uid, policy, false);
Jeff Sharkey497e4432011-06-14 17:27:29 -07001462 } else {
1463 Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
1464 }
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001465 } else if (TAG_APP_POLICY.equals(tag)) {
Jeff Sharkey8a8b5812012-03-21 18:13:36 -07001466 final int appId = readIntAttribute(in, ATTR_APP_ID);
1467 final int policy = readIntAttribute(in, ATTR_POLICY);
1468
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001469 // TODO: set for other users during upgrade
Xiaohui Chenbe3b0672015-09-02 13:29:22 -07001470 // app policy is deprecated so this is only used in pre system user split.
1471 final int uid = UserHandle.getUid(UserHandle.USER_SYSTEM, appId);
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001472 if (UserHandle.isApp(uid)) {
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001473 setUidPolicyUncheckedLocked(uid, policy, false);
Jeff Sharkey8a8b5812012-03-21 18:13:36 -07001474 } else {
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001475 Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
Jeff Sharkey8a8b5812012-03-21 18:13:36 -07001476 }
Felipe Lemeb85a6372016-01-14 16:16:16 -08001477 } else if (TAG_WHITELIST.equals(tag)) {
1478 insideWhitelist = true;
1479 } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) {
1480 final int uid = readIntAttribute(in, ATTR_UID);
1481 mRestrictBackgroundWhitelistUids.put(uid, true);
Felipe Lemea9505cc2016-02-26 10:28:41 -08001482 } else if (TAG_REVOKED_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) {
1483 final int uid = readIntAttribute(in, ATTR_UID);
1484 mRestrictBackgroundWhitelistRevokedUids.put(uid, true);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001485 }
Felipe Lemeb85a6372016-01-14 16:16:16 -08001486 } else if (type == END_TAG) {
1487 if (TAG_WHITELIST.equals(tag)) {
1488 insideWhitelist = false;
1489 }
1490
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001491 }
1492 }
1493
1494 } catch (FileNotFoundException e) {
1495 // missing policy is okay, probably first boot
Jeff Sharkey3a844fc2011-08-16 14:37:57 -07001496 upgradeLegacyBackgroundData();
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001497 } catch (IOException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001498 Log.wtf(TAG, "problem reading network policy", e);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001499 } catch (XmlPullParserException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001500 Log.wtf(TAG, "problem reading network policy", e);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001501 } finally {
1502 IoUtils.closeQuietly(fis);
1503 }
1504 }
1505
Jeff Sharkey3a844fc2011-08-16 14:37:57 -07001506 /**
1507 * Upgrade legacy background data flags, notifying listeners of one last
1508 * change to always-true.
1509 */
1510 private void upgradeLegacyBackgroundData() {
1511 mRestrictBackground = Settings.Secure.getInt(
1512 mContext.getContentResolver(), Settings.Secure.BACKGROUND_DATA, 1) != 1;
1513
1514 // kick off one last broadcast if restricted
1515 if (mRestrictBackground) {
1516 final Intent broadcast = new Intent(
1517 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001518 mContext.sendBroadcastAsUser(broadcast, UserHandle.ALL);
Jeff Sharkey3a844fc2011-08-16 14:37:57 -07001519 }
1520 }
1521
Dianne Hackborn497175b2014-07-01 12:56:08 -07001522 void writePolicyLocked() {
Jeff Sharkey22c055e2011-06-12 21:13:51 -07001523 if (LOGV) Slog.v(TAG, "writePolicyLocked()");
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001524
1525 FileOutputStream fos = null;
1526 try {
1527 fos = mPolicyFile.startWrite();
1528
1529 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001530 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001531 out.startDocument(null, true);
1532
1533 out.startTag(null, TAG_POLICY_LIST);
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07001534 writeIntAttribute(out, ATTR_VERSION, VERSION_LATEST);
Jeff Sharkey46645002011-07-27 21:11:21 -07001535 writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001536
1537 // write all known network policies
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001538 for (int i = 0; i < mNetworkPolicy.size(); i++) {
1539 final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001540 final NetworkTemplate template = policy.template;
Jeff Sharkey7474fe7b2016-03-21 13:12:59 -06001541 if (!template.isPersistable()) continue;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001542
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001543 out.startTag(null, TAG_NETWORK_POLICY);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001544 writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule());
1545 final String subscriberId = template.getSubscriberId();
1546 if (subscriberId != null) {
1547 out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001548 }
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07001549 final String networkId = template.getNetworkId();
1550 if (networkId != null) {
1551 out.attribute(null, ATTR_NETWORK_ID, networkId);
1552 }
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001553 writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
Jeff Sharkey9bf31502012-03-09 17:07:21 -08001554 out.attribute(null, ATTR_CYCLE_TIMEZONE, policy.cycleTimezone);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001555 writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
1556 writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001557 writeLongAttribute(out, ATTR_LAST_WARNING_SNOOZE, policy.lastWarningSnooze);
1558 writeLongAttribute(out, ATTR_LAST_LIMIT_SNOOZE, policy.lastLimitSnooze);
Jeff Sharkeyf60d0af2011-11-30 15:28:02 -08001559 writeBooleanAttribute(out, ATTR_METERED, policy.metered);
Jeff Sharkey837f9242012-03-20 16:52:20 -07001560 writeBooleanAttribute(out, ATTR_INFERRED, policy.inferred);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001561 out.endTag(null, TAG_NETWORK_POLICY);
1562 }
1563
1564 // write all known uid policies
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001565 for (int i = 0; i < mUidPolicy.size(); i++) {
1566 final int uid = mUidPolicy.keyAt(i);
1567 final int policy = mUidPolicy.valueAt(i);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001568
Jeff Sharkey497e4432011-06-14 17:27:29 -07001569 // skip writing empty policies
1570 if (policy == POLICY_NONE) continue;
1571
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001572 out.startTag(null, TAG_UID_POLICY);
1573 writeIntAttribute(out, ATTR_UID, uid);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001574 writeIntAttribute(out, ATTR_POLICY, policy);
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001575 out.endTag(null, TAG_UID_POLICY);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001576 }
1577
1578 out.endTag(null, TAG_POLICY_LIST);
Felipe Lemeb85a6372016-01-14 16:16:16 -08001579
1580 // write all whitelists
1581 out.startTag(null, TAG_WHITELIST);
1582
1583 // restrict background whitelist
Felipe Lemea9505cc2016-02-26 10:28:41 -08001584 int size = mRestrictBackgroundWhitelistUids.size();
Felipe Lemeb85a6372016-01-14 16:16:16 -08001585 for (int i = 0; i < size; i++) {
1586 final int uid = mRestrictBackgroundWhitelistUids.keyAt(i);
1587 out.startTag(null, TAG_RESTRICT_BACKGROUND);
1588 writeIntAttribute(out, ATTR_UID, uid);
1589 out.endTag(null, TAG_RESTRICT_BACKGROUND);
1590 }
1591
Felipe Lemea9505cc2016-02-26 10:28:41 -08001592 // revoked restrict background whitelist
1593 size = mRestrictBackgroundWhitelistRevokedUids.size();
1594 for (int i = 0; i < size; i++) {
1595 final int uid = mRestrictBackgroundWhitelistRevokedUids.keyAt(i);
1596 out.startTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
1597 writeIntAttribute(out, ATTR_UID, uid);
1598 out.endTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
1599 }
1600
Felipe Lemeb85a6372016-01-14 16:16:16 -08001601 out.endTag(null, TAG_WHITELIST);
1602
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001603 out.endDocument();
1604
1605 mPolicyFile.finishWrite(fos);
1606 } catch (IOException e) {
1607 if (fos != null) {
1608 mPolicyFile.failWrite(fos);
1609 }
1610 }
1611 }
1612
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -07001613 @Override
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001614 public void setUidPolicy(int uid, int policy) {
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001615 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
Jeff Sharkeya4620792011-05-20 15:29:23 -07001616
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001617 if (!UserHandle.isApp(uid)) {
1618 throw new IllegalArgumentException("cannot apply policy to UID " + uid);
Jeff Sharkey497e4432011-06-14 17:27:29 -07001619 }
1620
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001621 synchronized (mRulesLock) {
Julia Reynolds72f83d62015-07-27 15:10:42 -04001622 final long token = Binder.clearCallingIdentity();
1623 try {
1624 final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
1625 if (oldPolicy != policy) {
Felipe Leme923845f2016-03-02 13:42:48 -08001626 setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
Julia Reynolds72f83d62015-07-27 15:10:42 -04001627 }
1628 } finally {
1629 Binder.restoreCallingIdentity(token);
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001630 }
1631 }
Jeff Sharkey497e4432011-06-14 17:27:29 -07001632 }
1633
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001634 @Override
1635 public void addUidPolicy(int uid, int policy) {
1636 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -07001637
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001638 if (!UserHandle.isApp(uid)) {
1639 throw new IllegalArgumentException("cannot apply policy to UID " + uid);
1640 }
1641
1642 synchronized (mRulesLock) {
1643 final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
1644 policy |= oldPolicy;
1645 if (oldPolicy != policy) {
Felipe Leme923845f2016-03-02 13:42:48 -08001646 setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
Jeff Sharkey497e4432011-06-14 17:27:29 -07001647 }
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001648 }
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -07001649 }
1650
1651 @Override
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001652 public void removeUidPolicy(int uid, int policy) {
1653 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1654
1655 if (!UserHandle.isApp(uid)) {
1656 throw new IllegalArgumentException("cannot apply policy to UID " + uid);
1657 }
1658
1659 synchronized (mRulesLock) {
1660 final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
1661 policy = oldPolicy & ~policy;
1662 if (oldPolicy != policy) {
Felipe Leme923845f2016-03-02 13:42:48 -08001663 setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001664 }
1665 }
1666 }
1667
Felipe Leme923845f2016-03-02 13:42:48 -08001668 private void setUidPolicyUncheckedLocked(int uid, int oldPolicy, int policy, boolean persist) {
1669 setUidPolicyUncheckedLocked(uid, policy, persist);
1670
1671 // Checks if app was added or removed to the blacklist.
1672 if ((oldPolicy == POLICY_NONE && policy == POLICY_REJECT_METERED_BACKGROUND)
1673 || (oldPolicy == POLICY_REJECT_METERED_BACKGROUND && policy == POLICY_NONE)) {
1674 mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
1675 .sendToTarget();
1676 }
1677 }
1678
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001679 private void setUidPolicyUncheckedLocked(int uid, int policy, boolean persist) {
1680 mUidPolicy.put(uid, policy);
1681
1682 // uid policy changed, recompute rules and persist policy.
Felipe Lemef28983d2016-03-25 12:18:23 -07001683 updateRuleForRestrictBackgroundLocked(uid);
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001684 if (persist) {
1685 writePolicyLocked();
1686 }
1687 }
1688
1689 @Override
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001690 public int getUidPolicy(int uid) {
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001691 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1692
Jeff Sharkeya4620792011-05-20 15:29:23 -07001693 synchronized (mRulesLock) {
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001694 return mUidPolicy.get(uid, POLICY_NONE);
Jeff Sharkeya4620792011-05-20 15:29:23 -07001695 }
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -07001696 }
1697
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -07001698 @Override
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001699 public int[] getUidsWithPolicy(int policy) {
Jeff Sharkey854b2b12012-04-13 16:03:40 -07001700 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1701
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001702 int[] uids = new int[0];
Jeff Sharkey854b2b12012-04-13 16:03:40 -07001703 synchronized (mRulesLock) {
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001704 for (int i = 0; i < mUidPolicy.size(); i++) {
1705 final int uid = mUidPolicy.keyAt(i);
1706 final int uidPolicy = mUidPolicy.valueAt(i);
1707 if (uidPolicy == policy) {
1708 uids = appendInt(uids, uid);
Jeff Sharkey854b2b12012-04-13 16:03:40 -07001709 }
1710 }
1711 }
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001712 return uids;
1713 }
1714
1715 /**
Fyodor Kupolova31c5912016-01-22 11:26:09 -08001716 * Remove any persistable state associated with given {@link UserHandle}, persisting
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001717 * if any changes are made.
1718 */
Fyodor Kupolova31c5912016-01-22 11:26:09 -08001719 void removeUserStateLocked(int userId) {
1720 if (LOGV) Slog.v(TAG, "removeUserStateLocked()");
1721 boolean writePolicy = false;
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001722
Fyodor Kupolova31c5912016-01-22 11:26:09 -08001723 // Remove entries from restricted background UID whitelist
1724 int[] wlUids = new int[0];
1725 for (int i = 0; i < mRestrictBackgroundWhitelistUids.size(); i++) {
1726 final int uid = mRestrictBackgroundWhitelistUids.keyAt(i);
1727 if (UserHandle.getUserId(uid) == userId) {
1728 wlUids = appendInt(wlUids, uid);
1729 }
1730 }
1731
1732 if (wlUids.length > 0) {
1733 for (int uid : wlUids) {
Felipe Leme70c57c22016-03-29 10:45:13 -07001734 removeRestrictBackgroundWhitelistedUidLocked(uid, false, false);
Fyodor Kupolova31c5912016-01-22 11:26:09 -08001735 }
1736 writePolicy = true;
1737 }
Fyodor Kupolova31c5912016-01-22 11:26:09 -08001738 // Remove associated UID policies
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001739 int[] uids = new int[0];
1740 for (int i = 0; i < mUidPolicy.size(); i++) {
1741 final int uid = mUidPolicy.keyAt(i);
1742 if (UserHandle.getUserId(uid) == userId) {
1743 uids = appendInt(uids, uid);
1744 }
1745 }
1746
1747 if (uids.length > 0) {
1748 for (int uid : uids) {
1749 mUidPolicy.delete(uid);
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001750 }
Fyodor Kupolova31c5912016-01-22 11:26:09 -08001751 writePolicy = true;
1752 }
1753
Felipe Leme76010a32016-03-17 13:03:11 -07001754 updateRulesForGlobalChangeLocked(true);
1755
Fyodor Kupolova31c5912016-01-22 11:26:09 -08001756 if (writePolicy) {
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07001757 writePolicyLocked();
1758 }
Jeff Sharkey854b2b12012-04-13 16:03:40 -07001759 }
1760
1761 @Override
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -07001762 public void registerListener(INetworkPolicyListener listener) {
Jeff Sharkey1a303952011-06-16 13:04:20 -07001763 // TODO: create permission for observing network policy
1764 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1765
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -07001766 mListeners.register(listener);
1767
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001768 // TODO: consider dispatching existing rules to new listeners
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -07001769 }
1770
1771 @Override
1772 public void unregisterListener(INetworkPolicyListener listener) {
Jeff Sharkey1a303952011-06-16 13:04:20 -07001773 // TODO: create permission for observing network policy
1774 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1775
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -07001776 mListeners.unregister(listener);
1777 }
1778
Jeff Sharkey1b861272011-05-22 00:34:52 -07001779 @Override
Jeff Sharkey22c055e2011-06-12 21:13:51 -07001780 public void setNetworkPolicies(NetworkPolicy[] policies) {
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001781 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1782
Felipe Leme6a05eee2016-02-19 14:43:51 -08001783 final long token = Binder.clearCallingIdentity();
1784 try {
1785 maybeRefreshTrustedTime();
1786 synchronized (mRulesLock) {
1787 normalizePoliciesLocked(policies);
1788 updateNetworkEnabledLocked();
1789 updateNetworkRulesLocked();
1790 updateNotificationsLocked();
1791 writePolicyLocked();
1792 }
1793 } finally {
1794 Binder.restoreCallingIdentity(token);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001795 }
1796 }
1797
Dianne Hackborn497175b2014-07-01 12:56:08 -07001798 void addNetworkPolicyLocked(NetworkPolicy policy) {
Svet Ganov16a16892015-04-16 10:32:04 -07001799 NetworkPolicy[] policies = getNetworkPolicies(mContext.getOpPackageName());
Jeff Sharkey32566012014-12-02 18:30:14 -08001800 policies = ArrayUtils.appendElement(NetworkPolicy.class, policies, policy);
1801 setNetworkPolicies(policies);
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -07001802 }
1803
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001804 @Override
Svet Ganov16a16892015-04-16 10:32:04 -07001805 public NetworkPolicy[] getNetworkPolicies(String callingPackage) {
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001806 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
Amit Mahajan7c5befa2015-07-14 10:26:00 -07001807 try {
Amit Mahajana9e72a72015-07-30 16:04:13 -07001808 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, TAG);
1809 // SKIP checking run-time OP_READ_PHONE_STATE since caller or self has PRIVILEGED
1810 // permission
Amit Mahajan7c5befa2015-07-14 10:26:00 -07001811 } catch (SecurityException e) {
1812 mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001813
Amit Mahajan7c5befa2015-07-14 10:26:00 -07001814 if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
1815 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1816 return new NetworkPolicy[0];
1817 }
Svet Ganov16a16892015-04-16 10:32:04 -07001818 }
1819
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001820 synchronized (mRulesLock) {
Jeff Sharkey32566012014-12-02 18:30:14 -08001821 final int size = mNetworkPolicy.size();
1822 final NetworkPolicy[] policies = new NetworkPolicy[size];
1823 for (int i = 0; i < size; i++) {
1824 policies[i] = mNetworkPolicy.valueAt(i);
1825 }
1826 return policies;
1827 }
1828 }
1829
1830 private void normalizePoliciesLocked() {
Svet Ganov16a16892015-04-16 10:32:04 -07001831 normalizePoliciesLocked(getNetworkPolicies(mContext.getOpPackageName()));
Jeff Sharkey32566012014-12-02 18:30:14 -08001832 }
1833
1834 private void normalizePoliciesLocked(NetworkPolicy[] policies) {
1835 final TelephonyManager tele = TelephonyManager.from(mContext);
1836 final String[] merged = tele.getMergedSubscriberIds();
1837
1838 mNetworkPolicy.clear();
1839 for (NetworkPolicy policy : policies) {
1840 // When two normalized templates conflict, prefer the most
1841 // restrictive policy
1842 policy.template = NetworkTemplate.normalize(policy.template, merged);
1843 final NetworkPolicy existing = mNetworkPolicy.get(policy.template);
1844 if (existing == null || existing.compareTo(policy) > 0) {
1845 if (existing != null) {
1846 Slog.d(TAG, "Normalization replaced " + existing + " with " + policy);
1847 }
1848 mNetworkPolicy.put(policy.template, policy);
1849 }
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001850 }
1851 }
1852
1853 @Override
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001854 public void snoozeLimit(NetworkTemplate template) {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001855 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
Jeff Sharkey6c0b4f32012-06-12 21:06:30 -07001856
1857 final long token = Binder.clearCallingIdentity();
1858 try {
1859 performSnooze(template, TYPE_LIMIT);
1860 } finally {
1861 Binder.restoreCallingIdentity(token);
1862 }
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001863 }
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001864
Dianne Hackborn497175b2014-07-01 12:56:08 -07001865 void performSnooze(NetworkTemplate template, int type) {
Jeff Sharkey684c54a2011-11-16 17:46:30 -08001866 maybeRefreshTrustedTime();
1867 final long currentTime = currentTimeMillis();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001868 synchronized (mRulesLock) {
1869 // find and snooze local policy that matches
1870 final NetworkPolicy policy = mNetworkPolicy.get(template);
1871 if (policy == null) {
1872 throw new IllegalArgumentException("unable to find policy for " + template);
1873 }
1874
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08001875 switch (type) {
1876 case TYPE_WARNING:
1877 policy.lastWarningSnooze = currentTime;
1878 break;
1879 case TYPE_LIMIT:
1880 policy.lastLimitSnooze = currentTime;
1881 break;
1882 default:
1883 throw new IllegalArgumentException("unexpected type");
1884 }
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001885
Jeff Sharkey32566012014-12-02 18:30:14 -08001886 normalizePoliciesLocked();
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07001887 updateNetworkEnabledLocked();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001888 updateNetworkRulesLocked();
1889 updateNotificationsLocked();
1890 writePolicyLocked();
Jeff Sharkey21c9c452011-06-07 12:26:43 -07001891 }
1892 }
1893
1894 @Override
Jeff Sharkey46645002011-07-27 21:11:21 -07001895 public void setRestrictBackground(boolean restrictBackground) {
1896 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
Felipe Leme6a05eee2016-02-19 14:43:51 -08001897 final long token = Binder.clearCallingIdentity();
1898 try {
1899 maybeRefreshTrustedTime();
1900 synchronized (mRulesLock) {
Felipe Leme70c57c22016-03-29 10:45:13 -07001901 if (restrictBackground == mRestrictBackground) {
1902 // Ideally, UI should never allow this scenario...
1903 Slog.w(TAG, "setRestrictBackground: already " + restrictBackground);
1904 return;
1905 }
1906 setRestrictBackgroundLocked(restrictBackground);
Felipe Leme6a05eee2016-02-19 14:43:51 -08001907 }
Jeff Sharkey46645002011-07-27 21:11:21 -07001908
Felipe Leme6a05eee2016-02-19 14:43:51 -08001909 } finally {
1910 Binder.restoreCallingIdentity(token);
Jeff Sharkey46645002011-07-27 21:11:21 -07001911 }
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -08001912
1913 mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0)
1914 .sendToTarget();
Jeff Sharkey46645002011-07-27 21:11:21 -07001915 }
1916
Felipe Leme70c57c22016-03-29 10:45:13 -07001917 private void setRestrictBackgroundLocked(boolean restrictBackground) {
1918 final boolean oldRestrictBackground = mRestrictBackground;
1919 mRestrictBackground = restrictBackground;
1920 // Must whitelist foreground apps before turning data saver mode on.
1921 // TODO: there is no need to iterate through all apps here, just those in the foreground,
1922 // so it could call AM to get the UIDs of such apps, and iterate through them instead.
1923 updateRulesForRestrictBackgroundLocked();
1924 try {
1925 if (!mNetworkManager.setDataSaverModeEnabled(mRestrictBackground)) {
1926 Slog.e(TAG, "Could not change Data Saver Mode on NMS to " + mRestrictBackground);
1927 mRestrictBackground = oldRestrictBackground;
1928 // TODO: if it knew the foreground apps (see TODO above), it could call
1929 // updateRulesForRestrictBackgroundLocked() again to restore state.
1930 return;
1931 }
1932 } catch (RemoteException e) {
1933 // ignored; service lives in system_server
1934 }
1935 updateNotificationsLocked();
1936 writePolicyLocked();
1937 }
1938
Jeff Sharkey46645002011-07-27 21:11:21 -07001939 @Override
Felipe Lemeb85a6372016-01-14 16:16:16 -08001940 public void addRestrictBackgroundWhitelistedUid(int uid) {
1941 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
Felipe Leme70c57c22016-03-29 10:45:13 -07001942 final boolean oldStatus;
Felipe Leme01e05e72016-03-31 10:09:24 -07001943 final boolean needFirewallRules;
Felipe Lemeb85a6372016-01-14 16:16:16 -08001944 synchronized (mRulesLock) {
Felipe Leme70c57c22016-03-29 10:45:13 -07001945 oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
Felipe Leme47585ba2016-02-09 16:56:32 -08001946 if (oldStatus) {
1947 if (LOGD) Slog.d(TAG, "uid " + uid + " is already whitelisted");
1948 return;
1949 }
Felipe Leme01e05e72016-03-31 10:09:24 -07001950 needFirewallRules = isUidValidForWhitelistRules(uid);
Felipe Leme47585ba2016-02-09 16:56:32 -08001951 Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
Felipe Lemeb85a6372016-01-14 16:16:16 -08001952 mRestrictBackgroundWhitelistUids.append(uid, true);
Felipe Lemea9505cc2016-02-26 10:28:41 -08001953 if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
1954 && mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
1955 if (LOGD) Slog.d(TAG, "Removing uid " + uid
1956 + " from revoked restrict background whitelist");
1957 mRestrictBackgroundWhitelistRevokedUids.delete(uid);
1958 }
Felipe Leme01e05e72016-03-31 10:09:24 -07001959 if (needFirewallRules) {
1960 // Only update firewall rules if necessary...
1961 updateRuleForRestrictBackgroundLocked(uid);
1962 }
1963 // ...but always persists the whitelist request.
Felipe Lemeb85a6372016-01-14 16:16:16 -08001964 writePolicyLocked();
Felipe Lemeb85a6372016-01-14 16:16:16 -08001965 }
Felipe Leme01e05e72016-03-31 10:09:24 -07001966 if (mRestrictBackground && !oldStatus && needFirewallRules) {
Felipe Leme47585ba2016-02-09 16:56:32 -08001967 mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
1968 .sendToTarget();
1969 }
Felipe Lemeb85a6372016-01-14 16:16:16 -08001970 }
1971
1972 @Override
1973 public void removeRestrictBackgroundWhitelistedUid(int uid) {
1974 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
Felipe Leme47585ba2016-02-09 16:56:32 -08001975 final boolean changed;
Felipe Lemeb85a6372016-01-14 16:16:16 -08001976 synchronized (mRulesLock) {
Felipe Leme70c57c22016-03-29 10:45:13 -07001977 changed = removeRestrictBackgroundWhitelistedUidLocked(uid, false, true);
Felipe Lemeb85a6372016-01-14 16:16:16 -08001978 }
Felipe Leme47585ba2016-02-09 16:56:32 -08001979 if (changed) {
1980 mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
1981 .sendToTarget();
1982 }
Felipe Lemeb85a6372016-01-14 16:16:16 -08001983 }
1984
Felipe Leme70c57c22016-03-29 10:45:13 -07001985 /**
1986 * Removes a uid from the restricted background whitelist, returning whether its current
1987 * {@link ConnectivityManager.RestrictBackgroundStatus} changed.
1988 */
1989 private boolean removeRestrictBackgroundWhitelistedUidLocked(int uid, boolean uidDeleted,
1990 boolean updateNow) {
Felipe Leme47585ba2016-02-09 16:56:32 -08001991 final boolean oldStatus = mRestrictBackgroundWhitelistUids.get(uid);
1992 if (!oldStatus) {
1993 if (LOGD) Slog.d(TAG, "uid " + uid + " was not whitelisted before");
1994 return false;
1995 }
Felipe Leme01e05e72016-03-31 10:09:24 -07001996 final boolean needFirewallRules = uidDeleted || isUidValidForWhitelistRules(uid);
Felipe Leme47585ba2016-02-09 16:56:32 -08001997 Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
Felipe Lemeb85a6372016-01-14 16:16:16 -08001998 mRestrictBackgroundWhitelistUids.delete(uid);
Felipe Lemea9505cc2016-02-26 10:28:41 -08001999 if (mDefaultRestrictBackgroundWhitelistUids.get(uid)
2000 && !mRestrictBackgroundWhitelistRevokedUids.get(uid)) {
2001 if (LOGD) Slog.d(TAG, "Adding uid " + uid
2002 + " to revoked restrict background whitelist");
2003 mRestrictBackgroundWhitelistRevokedUids.append(uid, true);
2004 }
Felipe Leme01e05e72016-03-31 10:09:24 -07002005 if (needFirewallRules) {
2006 // Only update firewall rules if necessary...
2007 updateRuleForRestrictBackgroundLocked(uid, uidDeleted);
2008 }
Felipe Leme3f52cd52016-02-03 13:36:30 -08002009 if (updateNow) {
Felipe Leme01e05e72016-03-31 10:09:24 -07002010 // ...but always persists the whitelist request.
Fyodor Kupolova31c5912016-01-22 11:26:09 -08002011 writePolicyLocked();
2012 }
Felipe Leme70c57c22016-03-29 10:45:13 -07002013 // Status only changes if Data Saver is turned on (otherwise it is DISABLED, even if the
2014 // app was whitelisted before).
Felipe Leme01e05e72016-03-31 10:09:24 -07002015 return mRestrictBackground && needFirewallRules;
Felipe Lemeb85a6372016-01-14 16:16:16 -08002016 }
2017
2018 @Override
2019 public int[] getRestrictBackgroundWhitelistedUids() {
2020 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
2021 synchronized (mRulesLock) {
2022 final int size = mRestrictBackgroundWhitelistUids.size();
2023 final int[] whitelist = new int[size];
2024 for (int i = 0; i < size; i++) {
2025 whitelist[i] = mRestrictBackgroundWhitelistUids.keyAt(i);
2026 }
2027 if (LOGV) {
2028 Slog.v(TAG, "getRestrictBackgroundWhitelistedUids(): "
2029 + mRestrictBackgroundWhitelistUids);
2030 }
2031 return whitelist;
2032 }
2033 }
2034
2035 @Override
Felipe Leme1b103232016-01-22 09:44:57 -08002036 public int getRestrictBackgroundByCaller() {
2037 mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
2038 final int uid = Binder.getCallingUid();
Felipe Leme923845f2016-03-02 13:42:48 -08002039
Felipe Leme1b103232016-01-22 09:44:57 -08002040 synchronized (mRulesLock) {
Felipe Leme923845f2016-03-02 13:42:48 -08002041 // Must clear identity because getUidPolicy() is restricted to system.
2042 final long token = Binder.clearCallingIdentity();
2043 final int policy;
2044 try {
2045 policy = getUidPolicy(uid);
2046 } finally {
2047 Binder.restoreCallingIdentity(token);
2048 }
2049 if (policy == POLICY_REJECT_METERED_BACKGROUND) {
2050 // App is blacklisted.
2051 return RESTRICT_BACKGROUND_STATUS_ENABLED;
2052 }
Felipe Leme1b103232016-01-22 09:44:57 -08002053 if (!mRestrictBackground) {
2054 return RESTRICT_BACKGROUND_STATUS_DISABLED;
2055 }
2056 return mRestrictBackgroundWhitelistUids.get(uid)
2057 ? RESTRICT_BACKGROUND_STATUS_WHITELISTED
2058 : RESTRICT_BACKGROUND_STATUS_ENABLED;
2059 }
2060 }
2061
2062 @Override
Jeff Sharkey46645002011-07-27 21:11:21 -07002063 public boolean getRestrictBackground() {
2064 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
2065
2066 synchronized (mRulesLock) {
2067 return mRestrictBackground;
2068 }
2069 }
2070
Dianne Hackborn8ad2af72015-03-17 17:00:24 -07002071 @Override
2072 public void setDeviceIdleMode(boolean enabled) {
2073 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
2074
2075 synchronized (mRulesLock) {
2076 if (mDeviceIdleMode != enabled) {
2077 mDeviceIdleMode = enabled;
2078 if (mSystemReady) {
Jeff Sharkeydc988062015-09-14 10:09:47 -07002079 // Device idle change means we need to rebuild rules for all
2080 // known apps, so do a global refresh.
2081 updateRulesForGlobalChangeLocked(false);
Dianne Hackborn3b16cf42015-07-01 15:05:04 -07002082 }
2083 if (enabled) {
2084 EventLogTags.writeDeviceIdleOnPhase("net");
2085 } else {
2086 EventLogTags.writeDeviceIdleOffPhase("net");
Dianne Hackborn8ad2af72015-03-17 17:00:24 -07002087 }
2088 }
2089 }
2090 }
2091
Jeff Sharkeyf0ceede2011-08-02 17:22:34 -07002092 private NetworkPolicy findPolicyForNetworkLocked(NetworkIdentity ident) {
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07002093 for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
2094 NetworkPolicy policy = mNetworkPolicy.valueAt(i);
Jeff Sharkeyf0ceede2011-08-02 17:22:34 -07002095 if (policy.template.matches(ident)) {
2096 return policy;
2097 }
2098 }
2099 return null;
2100 }
2101
2102 @Override
2103 public NetworkQuotaInfo getNetworkQuotaInfo(NetworkState state) {
2104 mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
2105
2106 // only returns usage summary, so we don't require caller to have
2107 // READ_NETWORK_USAGE_HISTORY.
2108 final long token = Binder.clearCallingIdentity();
2109 try {
2110 return getNetworkQuotaInfoUnchecked(state);
2111 } finally {
2112 Binder.restoreCallingIdentity(token);
2113 }
2114 }
2115
2116 private NetworkQuotaInfo getNetworkQuotaInfoUnchecked(NetworkState state) {
2117 final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
2118
2119 final NetworkPolicy policy;
2120 synchronized (mRulesLock) {
2121 policy = findPolicyForNetworkLocked(ident);
2122 }
2123
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07002124 if (policy == null || !policy.hasCycle()) {
Jeff Sharkeyf0ceede2011-08-02 17:22:34 -07002125 // missing policy means we can't derive useful quota info
2126 return null;
2127 }
2128
Jeff Sharkey684c54a2011-11-16 17:46:30 -08002129 final long currentTime = currentTimeMillis();
Jeff Sharkeyf0ceede2011-08-02 17:22:34 -07002130
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07002131 // find total bytes used under policy
Jeff Sharkeyf0ceede2011-08-02 17:22:34 -07002132 final long start = computeLastCycleBoundary(currentTime, policy);
2133 final long end = currentTime;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07002134 final long totalBytes = getTotalBytes(policy.template, start, end);
Jeff Sharkeyf0ceede2011-08-02 17:22:34 -07002135
2136 // report soft and hard limits under policy
2137 final long softLimitBytes = policy.warningBytes != WARNING_DISABLED ? policy.warningBytes
2138 : NetworkQuotaInfo.NO_LIMIT;
2139 final long hardLimitBytes = policy.limitBytes != LIMIT_DISABLED ? policy.limitBytes
2140 : NetworkQuotaInfo.NO_LIMIT;
2141
2142 return new NetworkQuotaInfo(totalBytes, softLimitBytes, hardLimitBytes);
2143 }
2144
Jeff Sharkey46645002011-07-27 21:11:21 -07002145 @Override
Jeff Sharkey9f7cbf02012-04-12 18:34:54 -07002146 public boolean isNetworkMetered(NetworkState state) {
2147 final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
2148
Jeff Sharkeyf166f482012-04-30 15:59:21 -07002149 // roaming networks are always considered metered
2150 if (ident.getRoaming()) {
2151 return true;
2152 }
2153
Jeff Sharkey9f7cbf02012-04-12 18:34:54 -07002154 final NetworkPolicy policy;
2155 synchronized (mRulesLock) {
2156 policy = findPolicyForNetworkLocked(ident);
2157 }
2158
2159 if (policy != null) {
2160 return policy.metered;
2161 } else {
Wei Liub8eaf452016-01-25 10:32:27 -08002162 if (state.networkInfo == null) {
2163 return false;
2164 }
2165
Jeff Sharkey9f6e4ba2012-04-19 23:01:08 -07002166 final int type = state.networkInfo.getType();
2167 if (isNetworkTypeMobile(type) || type == TYPE_WIMAX) {
2168 return true;
2169 }
Jeff Sharkey9f7cbf02012-04-12 18:34:54 -07002170 return false;
2171 }
2172 }
2173
2174 @Override
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07002175 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
Jeff Sharkey75279902011-05-24 18:39:45 -07002176 mContext.enforceCallingOrSelfPermission(DUMP, TAG);
Jeff Sharkey1b861272011-05-22 00:34:52 -07002177
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07002178 final IndentingPrintWriter fout = new IndentingPrintWriter(writer, " ");
2179
Dianne Hackborn497175b2014-07-01 12:56:08 -07002180 final ArraySet<String> argSet = new ArraySet<String>(args.length);
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07002181 for (String arg : args) {
2182 argSet.add(arg);
2183 }
2184
Jeff Sharkey1b861272011-05-22 00:34:52 -07002185 synchronized (mRulesLock) {
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08002186 if (argSet.contains("--unsnooze")) {
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07002187 for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
2188 mNetworkPolicy.valueAt(i).clearSnooze();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07002189 }
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08002190
Jeff Sharkey32566012014-12-02 18:30:14 -08002191 normalizePoliciesLocked();
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08002192 updateNetworkEnabledLocked();
2193 updateNetworkRulesLocked();
2194 updateNotificationsLocked();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07002195 writePolicyLocked();
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08002196
2197 fout.println("Cleared snooze timestamps");
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07002198 return;
2199 }
2200
Dianne Hackborn8ad2af72015-03-17 17:00:24 -07002201 fout.print("System ready: "); fout.println(mSystemReady);
Jeff Sharkey46645002011-07-27 21:11:21 -07002202 fout.print("Restrict background: "); fout.println(mRestrictBackground);
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07002203 fout.print("Restrict power: "); fout.println(mRestrictPower);
Dianne Hackborn8ad2af72015-03-17 17:00:24 -07002204 fout.print("Device idle: "); fout.println(mDeviceIdleMode);
Jeff Sharkey21c9c452011-06-07 12:26:43 -07002205 fout.println("Network policies:");
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07002206 fout.increaseIndent();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07002207 for (int i = 0; i < mNetworkPolicy.size(); i++) {
2208 fout.println(mNetworkPolicy.valueAt(i).toString());
Jeff Sharkey21c9c452011-06-07 12:26:43 -07002209 }
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07002210 fout.decreaseIndent();
Jeff Sharkey21c9c452011-06-07 12:26:43 -07002211
Jeff Sharkeyeb2c2c72014-08-11 15:22:51 -07002212 fout.print("Metered ifaces: "); fout.println(String.valueOf(mMeteredIfaces));
2213
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07002214 fout.println("Policy for UIDs:");
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07002215 fout.increaseIndent();
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07002216 int size = mUidPolicy.size();
Jeff Sharkey8a8b5812012-03-21 18:13:36 -07002217 for (int i = 0; i < size; i++) {
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07002218 final int uid = mUidPolicy.keyAt(i);
2219 final int policy = mUidPolicy.valueAt(i);
2220 fout.print("UID=");
2221 fout.print(uid);
Jeff Sharkey8a8b5812012-03-21 18:13:36 -07002222 fout.print(" policy=");
Jeff Sharkeydc988062015-09-14 10:09:47 -07002223 fout.print(DebugUtils.flagsToString(NetworkPolicyManager.class, "POLICY_", policy));
Jeff Sharkey8a8b5812012-03-21 18:13:36 -07002224 fout.println();
2225 }
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07002226 fout.decreaseIndent();
Jeff Sharkey1b861272011-05-22 00:34:52 -07002227
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002228 size = mPowerSaveWhitelistExceptIdleAppIds.size();
2229 if (size > 0) {
2230 fout.println("Power save whitelist (except idle) app ids:");
2231 fout.increaseIndent();
2232 for (int i = 0; i < size; i++) {
2233 fout.print("UID=");
2234 fout.print(mPowerSaveWhitelistExceptIdleAppIds.keyAt(i));
2235 fout.print(": ");
2236 fout.print(mPowerSaveWhitelistExceptIdleAppIds.valueAt(i));
2237 fout.println();
2238 }
2239 fout.decreaseIndent();
2240 }
2241
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07002242 size = mPowerSaveWhitelistAppIds.size();
2243 if (size > 0) {
2244 fout.println("Power save whitelist app ids:");
2245 fout.increaseIndent();
2246 for (int i = 0; i < size; i++) {
2247 fout.print("UID=");
2248 fout.print(mPowerSaveWhitelistAppIds.keyAt(i));
2249 fout.print(": ");
2250 fout.print(mPowerSaveWhitelistAppIds.valueAt(i));
2251 fout.println();
2252 }
2253 fout.decreaseIndent();
2254 }
2255
Felipe Lemeb85a6372016-01-14 16:16:16 -08002256 size = mRestrictBackgroundWhitelistUids.size();
2257 if (size > 0) {
2258 fout.println("Restrict background whitelist uids:");
2259 fout.increaseIndent();
2260 for (int i = 0; i < size; i++) {
2261 fout.print("UID=");
2262 fout.print(mRestrictBackgroundWhitelistUids.keyAt(i));
2263 fout.println();
2264 }
2265 fout.decreaseIndent();
2266 }
2267
Felipe Lemea9505cc2016-02-26 10:28:41 -08002268 size = mDefaultRestrictBackgroundWhitelistUids.size();
2269 if (size > 0) {
2270 fout.println("Default restrict background whitelist uids:");
2271 fout.increaseIndent();
2272 for (int i = 0; i < size; i++) {
2273 fout.print("UID=");
2274 fout.print(mDefaultRestrictBackgroundWhitelistUids.keyAt(i));
2275 fout.println();
2276 }
2277 fout.decreaseIndent();
2278 }
2279
2280 size = mRestrictBackgroundWhitelistRevokedUids.size();
2281 if (size > 0) {
2282 fout.println("Default restrict background whitelist uids revoked by users:");
2283 fout.increaseIndent();
2284 for (int i = 0; i < size; i++) {
2285 fout.print("UID=");
2286 fout.print(mRestrictBackgroundWhitelistRevokedUids.keyAt(i));
2287 fout.println();
2288 }
2289 fout.decreaseIndent();
2290 }
2291
Jeff Sharkey1b861272011-05-22 00:34:52 -07002292 final SparseBooleanArray knownUids = new SparseBooleanArray();
Dianne Hackborn497175b2014-07-01 12:56:08 -07002293 collectKeys(mUidState, knownUids);
Jeff Sharkey1b861272011-05-22 00:34:52 -07002294 collectKeys(mUidRules, knownUids);
2295
Jeff Sharkey8a8b5812012-03-21 18:13:36 -07002296 fout.println("Status for known UIDs:");
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07002297 fout.increaseIndent();
Jeff Sharkey8a8b5812012-03-21 18:13:36 -07002298 size = knownUids.size();
Jeff Sharkey1b861272011-05-22 00:34:52 -07002299 for (int i = 0; i < size; i++) {
2300 final int uid = knownUids.keyAt(i);
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07002301 fout.print("UID=");
Jeff Sharkey1b861272011-05-22 00:34:52 -07002302 fout.print(uid);
2303
Jeff Sharkeydc988062015-09-14 10:09:47 -07002304 final int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
Dianne Hackborn497175b2014-07-01 12:56:08 -07002305 fout.print(" state=");
2306 fout.print(state);
Felipe Lemeef89c902016-03-30 15:11:31 -07002307 if (state <= ActivityManager.PROCESS_STATE_TOP) {
2308 fout.print(" (fg)");
2309 } else {
2310 fout.print(state <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
2311 ? " (fg svc)" : " (bg)");
2312 }
Dianne Hackborn497175b2014-07-01 12:56:08 -07002313
Jeff Sharkeydc988062015-09-14 10:09:47 -07002314 final int rule = mUidRules.get(uid, RULE_UNKNOWN);
2315 fout.print(" rule=");
Felipe Lemef28983d2016-03-25 12:18:23 -07002316 fout.print(ruleToString(rule));
Jeff Sharkey1b861272011-05-22 00:34:52 -07002317
2318 fout.println();
2319 }
Jeff Sharkey8fc27e82012-04-04 20:40:58 -07002320 fout.decreaseIndent();
Jeff Sharkey1b861272011-05-22 00:34:52 -07002321 }
2322 }
Jeff Sharkey9599cc52011-05-22 14:59:31 -07002323
Felipe Lemef28983d2016-03-25 12:18:23 -07002324 private String ruleToString(int rule) {
2325 return DebugUtils.valueToString(NetworkPolicyManager.class, "RULE_", rule);
2326 }
2327
Jeff Sharkey9599cc52011-05-22 14:59:31 -07002328 @Override
Felipe Leme50a235e2016-01-15 18:37:06 -08002329 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
2330 String[] args, ResultReceiver resultReceiver) throws RemoteException {
Felipe Lemeb1a65ee2016-02-08 10:12:01 -08002331 (new NetworkPolicyManagerShellCommand(mContext, this)).exec(
Felipe Leme50a235e2016-01-15 18:37:06 -08002332 this, in, out, err, args, resultReceiver);
2333 }
2334
2335 @Override
Jeff Sharkey9599cc52011-05-22 14:59:31 -07002336 public boolean isUidForeground(int uid) {
Jeff Sharkey497e4432011-06-14 17:27:29 -07002337 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
2338
Jeff Sharkey9599cc52011-05-22 14:59:31 -07002339 synchronized (mRulesLock) {
Dianne Hackborn497175b2014-07-01 12:56:08 -07002340 return isUidForegroundLocked(uid);
Jeff Sharkey9599cc52011-05-22 14:59:31 -07002341 }
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -07002342 }
2343
Felipe Lemef28983d2016-03-25 12:18:23 -07002344 private boolean isUidForegroundLocked(int uid) {
2345 return isUidStateForegroundLocked(
2346 mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY));
2347 }
2348
Felipe Lemeef89c902016-03-30 15:11:31 -07002349 private boolean isUidForegroundOnRestrictBackgroundLocked(int uid) {
2350 final int procState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
2351 return isProcStateAllowedWhileOnRestrictBackgroundLocked(procState);
2352 }
2353
Felipe Lemef28983d2016-03-25 12:18:23 -07002354 private boolean isUidStateForegroundLocked(int state) {
Dianne Hackborn497175b2014-07-01 12:56:08 -07002355 // only really in foreground when screen is also on
Felipe Lemef28983d2016-03-25 12:18:23 -07002356 return mScreenOn && state <= ActivityManager.PROCESS_STATE_TOP;
Dianne Hackborn497175b2014-07-01 12:56:08 -07002357 }
2358
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -07002359 /**
Dianne Hackbornd23e0d62015-05-15 16:36:12 -07002360 * Process state of UID changed; if needed, will trigger
Felipe Leme70c57c22016-03-29 10:45:13 -07002361 * {@link #updateRuleForRestrictBackgroundLocked(int)}.
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -07002362 */
Felipe Lemef28983d2016-03-25 12:18:23 -07002363 private void updateUidStateLocked(int uid, int uidState) {
Dianne Hackborn497175b2014-07-01 12:56:08 -07002364 final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
2365 if (oldUidState != uidState) {
2366 // state changed, push updated rules
2367 mUidState.put(uid, uidState);
Felipe Lemef28983d2016-03-25 12:18:23 -07002368 updateRestrictBackgroundRulesOnUidStatusChangedLocked(uid, oldUidState, uidState);
Felipe Leme011b98f2016-02-10 17:28:31 -08002369 if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
2370 != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
2371 if (mDeviceIdleMode) {
2372 updateRuleForDeviceIdleLocked(uid);
2373 }
2374 if (mRestrictPower) {
Felipe Lemef28983d2016-03-25 12:18:23 -07002375 updateRuleForRestrictPowerLocked(uid);
Felipe Leme011b98f2016-02-10 17:28:31 -08002376 }
Dianne Hackbornfd854ee2015-07-13 18:00:37 -07002377 }
Felipe Lemef28983d2016-03-25 12:18:23 -07002378 updateNetworkStats(uid, isUidStateForegroundLocked(uidState));
Dianne Hackbornd23e0d62015-05-15 16:36:12 -07002379 }
2380 }
2381
Felipe Lemef28983d2016-03-25 12:18:23 -07002382 private void removeUidStateLocked(int uid) {
Dianne Hackbornd23e0d62015-05-15 16:36:12 -07002383 final int index = mUidState.indexOfKey(uid);
2384 if (index >= 0) {
2385 final int oldUidState = mUidState.valueAt(index);
2386 mUidState.removeAt(index);
2387 if (oldUidState != ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
Felipe Lemef28983d2016-03-25 12:18:23 -07002388 updateRestrictBackgroundRulesOnUidStatusChangedLocked(uid, oldUidState,
Dianne Hackbornd23e0d62015-05-15 16:36:12 -07002389 ActivityManager.PROCESS_STATE_CACHED_EMPTY);
Dianne Hackbornfd854ee2015-07-13 18:00:37 -07002390 if (mDeviceIdleMode) {
Jeff Sharkeydc988062015-09-14 10:09:47 -07002391 updateRuleForDeviceIdleLocked(uid);
Dianne Hackbornfd854ee2015-07-13 18:00:37 -07002392 }
Felipe Leme011b98f2016-02-10 17:28:31 -08002393 if (mRestrictPower) {
Felipe Lemef28983d2016-03-25 12:18:23 -07002394 updateRuleForRestrictPowerLocked(uid);
Felipe Leme011b98f2016-02-10 17:28:31 -08002395 }
Felipe Lemef28983d2016-03-25 12:18:23 -07002396 updateNetworkStats(uid, false);
Dianne Hackborn497175b2014-07-01 12:56:08 -07002397 }
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -07002398 }
2399 }
2400
Felipe Lemef28983d2016-03-25 12:18:23 -07002401 // adjust stats accounting based on foreground status
2402 private void updateNetworkStats(int uid, boolean uidForeground) {
2403 try {
2404 mNetworkStats.setUidForeground(uid, uidForeground);
2405 } catch (RemoteException e) {
2406 // ignored; service lives in system_server
2407 }
2408 }
2409
2410 private void updateRestrictBackgroundRulesOnUidStatusChangedLocked(int uid, int oldUidState,
2411 int newUidState) {
Felipe Lemeef89c902016-03-30 15:11:31 -07002412 final boolean oldForeground =
2413 isProcStateAllowedWhileOnRestrictBackgroundLocked(oldUidState);
2414 final boolean newForeground =
2415 isProcStateAllowedWhileOnRestrictBackgroundLocked(newUidState);
Dianne Hackbornd23e0d62015-05-15 16:36:12 -07002416 if (oldForeground != newForeground) {
Felipe Lemef28983d2016-03-25 12:18:23 -07002417 updateRuleForRestrictBackgroundLocked(uid);
Dianne Hackbornd23e0d62015-05-15 16:36:12 -07002418 }
2419 }
2420
Jeff Sharkeya4620792011-05-20 15:29:23 -07002421 private void updateScreenOn() {
2422 synchronized (mRulesLock) {
2423 try {
Jeff Brown037c33e2014-04-09 00:31:55 -07002424 mScreenOn = mPowerManager.isInteractive();
Jeff Sharkeya4620792011-05-20 15:29:23 -07002425 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07002426 // ignored; service lives in system_server
Jeff Sharkeya4620792011-05-20 15:29:23 -07002427 }
Jeff Sharkey21c9c452011-06-07 12:26:43 -07002428 updateRulesForScreenLocked();
Jeff Sharkeya4620792011-05-20 15:29:23 -07002429 }
2430 }
2431
2432 /**
2433 * Update rules that might be changed by {@link #mScreenOn} value.
2434 */
Jeff Sharkey21c9c452011-06-07 12:26:43 -07002435 private void updateRulesForScreenLocked() {
Jeff Sharkeya4620792011-05-20 15:29:23 -07002436 // only update rules for anyone with foreground activities
Dianne Hackborn497175b2014-07-01 12:56:08 -07002437 final int size = mUidState.size();
Jeff Sharkeya4620792011-05-20 15:29:23 -07002438 for (int i = 0; i < size; i++) {
Felipe Lemeef89c902016-03-30 15:11:31 -07002439 if (mUidState.valueAt(i) <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
Dianne Hackborn497175b2014-07-01 12:56:08 -07002440 final int uid = mUidState.keyAt(i);
Felipe Lemef28983d2016-03-25 12:18:23 -07002441 updateRestrictionRulesForUidLocked(uid);
Jeff Sharkeya4620792011-05-20 15:29:23 -07002442 }
2443 }
2444 }
2445
Felipe Leme011b98f2016-02-10 17:28:31 -08002446 static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(int procState) {
Dianne Hackbornfd854ee2015-07-13 18:00:37 -07002447 return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
2448 }
2449
Felipe Lemeef89c902016-03-30 15:11:31 -07002450 static boolean isProcStateAllowedWhileOnRestrictBackgroundLocked(int procState) {
2451 return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
2452 }
2453
Felipe Leme011b98f2016-02-10 17:28:31 -08002454 void updateRulesForRestrictPowerLocked() {
2455 updateRulesForWhitelistedPowerSaveLocked(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
2456 mUidFirewallPowerSaveRules);
2457 }
2458
Felipe Lemef28983d2016-03-25 12:18:23 -07002459 void updateRuleForRestrictPowerLocked(int uid) {
Felipe Leme011b98f2016-02-10 17:28:31 -08002460 updateRulesForWhitelistedPowerSaveLocked(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
2461 }
2462
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07002463 void updateRulesForDeviceIdleLocked() {
Felipe Leme011b98f2016-02-10 17:28:31 -08002464 updateRulesForWhitelistedPowerSaveLocked(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
2465 mUidFirewallDozableRules);
2466 }
2467
2468 void updateRuleForDeviceIdleLocked(int uid) {
2469 updateRulesForWhitelistedPowerSaveLocked(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
2470 }
2471
Felipe Lemef28983d2016-03-25 12:18:23 -07002472 // NOTE: since both fw_dozable and fw_powersave uses the same map
2473 // (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
Felipe Leme011b98f2016-02-10 17:28:31 -08002474 private void updateRulesForWhitelistedPowerSaveLocked(boolean enabled, int chain,
2475 SparseIntArray rules) {
2476 if (enabled) {
2477 // Sync the whitelists before enabling the chain. We don't care about the rules if
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07002478 // we are disabling the chain.
Felipe Leme011b98f2016-02-10 17:28:31 -08002479 final SparseIntArray uidRules = rules;
Jeff Sharkeydc988062015-09-14 10:09:47 -07002480 uidRules.clear();
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07002481 final List<UserInfo> users = mUserManager.getUsers();
Dianne Hackbornfd854ee2015-07-13 18:00:37 -07002482 for (int ui = users.size() - 1; ui >= 0; ui--) {
2483 UserInfo user = users.get(ui);
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07002484 for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) {
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002485 if (mPowerSaveTempWhitelistAppIds.valueAt(i)) {
2486 int appId = mPowerSaveTempWhitelistAppIds.keyAt(i);
2487 int uid = UserHandle.getUid(user.id, appId);
2488 uidRules.put(uid, FIREWALL_RULE_ALLOW);
2489 }
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07002490 }
2491 for (int i = mPowerSaveWhitelistAppIds.size() - 1; i >= 0; i--) {
2492 int appId = mPowerSaveWhitelistAppIds.keyAt(i);
2493 int uid = UserHandle.getUid(user.id, appId);
2494 uidRules.put(uid, FIREWALL_RULE_ALLOW);
2495 }
2496 }
Dianne Hackbornfd854ee2015-07-13 18:00:37 -07002497 for (int i = mUidState.size() - 1; i >= 0; i--) {
Felipe Leme011b98f2016-02-10 17:28:31 -08002498 if (isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.valueAt(i))) {
Dianne Hackbornfd854ee2015-07-13 18:00:37 -07002499 uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
2500 }
2501 }
Felipe Leme011b98f2016-02-10 17:28:31 -08002502 setUidFirewallRules(chain, uidRules);
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07002503 }
Jeff Sharkeydc988062015-09-14 10:09:47 -07002504
Felipe Leme011b98f2016-02-10 17:28:31 -08002505 enableFirewallChainLocked(chain, enabled);
Xiaohui Chen8dca36d2015-06-19 12:44:59 -07002506 }
2507
Felipe Lemef28983d2016-03-25 12:18:23 -07002508 // NOTE: since both fw_dozable and fw_powersave uses the same map
2509 // (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
Felipe Leme011b98f2016-02-10 17:28:31 -08002510 private void updateRulesForWhitelistedPowerSaveLocked(int uid, boolean enabled, int chain) {
2511 if (enabled) {
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002512 int appId = UserHandle.getAppId(uid);
2513 if (mPowerSaveTempWhitelistAppIds.get(appId) || mPowerSaveWhitelistAppIds.get(appId)
Felipe Leme011b98f2016-02-10 17:28:31 -08002514 || isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid))) {
2515 setUidFirewallRule(chain, uid, FIREWALL_RULE_ALLOW);
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002516 } else {
Felipe Leme011b98f2016-02-10 17:28:31 -08002517 setUidFirewallRule(chain, uid, FIREWALL_RULE_DEFAULT);
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002518 }
2519 }
2520 }
2521
2522 void updateRulesForAppIdleLocked() {
Jeff Sharkeydc988062015-09-14 10:09:47 -07002523 final SparseIntArray uidRules = mUidFirewallStandbyRules;
2524 uidRules.clear();
2525
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002526 // Fully update the app idle firewall chain.
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002527 final List<UserInfo> users = mUserManager.getUsers();
2528 for (int ui = users.size() - 1; ui >= 0; ui--) {
2529 UserInfo user = users.get(ui);
2530 int[] idleUids = mUsageStats.getIdleUidsForUser(user.id);
2531 for (int uid : idleUids) {
2532 if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) {
Soi, Yoshinaria065da12015-12-22 12:02:18 +09002533 // quick check: if this uid doesn't have INTERNET permission, it
2534 // doesn't have network access anyway, so it is a waste to mess
2535 // with it here.
Amith Yamasani2a4ac4e2016-02-12 12:43:15 -08002536 if (hasInternetPermissions(uid)) {
2537 uidRules.put(uid, FIREWALL_RULE_DENY);
Soi, Yoshinaria065da12015-12-22 12:02:18 +09002538 }
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002539 }
2540 }
2541 }
Jeff Sharkeydc988062015-09-14 10:09:47 -07002542
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002543 setUidFirewallRules(FIREWALL_CHAIN_STANDBY, uidRules);
2544 }
2545
2546 void updateRuleForAppIdleLocked(int uid) {
Felipe Leme70c57c22016-03-29 10:45:13 -07002547 if (!isUidValidForBlacklistRules(uid)) return;
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002548
2549 int appId = UserHandle.getAppId(uid);
2550 if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid)) {
2551 setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DENY);
2552 } else {
2553 setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
2554 }
2555 }
2556
Xiaohui Chen8dca36d2015-06-19 12:44:59 -07002557 void updateRulesForAppIdleParoleLocked() {
2558 boolean enableChain = !mUsageStats.isAppIdleParoleOn();
2559 enableFirewallChainLocked(FIREWALL_CHAIN_STANDBY, enableChain);
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07002560 }
2561
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002562 /**
Dianne Hackborn8ad2af72015-03-17 17:00:24 -07002563 * Update rules that might be changed by {@link #mRestrictBackground},
2564 * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002565 */
Felipe Leme76010a32016-03-17 13:03:11 -07002566 private void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) {
Felipe Leme03e689d2016-03-02 16:17:38 -08002567 long start;
2568 if (LOGD) start = System.currentTimeMillis();
2569
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07002570 updateRulesForDeviceIdleLocked();
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002571 updateRulesForAppIdleLocked();
Felipe Leme011b98f2016-02-10 17:28:31 -08002572 updateRulesForRestrictPowerLocked();
Felipe Lemef28983d2016-03-25 12:18:23 -07002573 updateRulesForRestrictBackgroundLocked();
Felipe Leme70c57c22016-03-29 10:45:13 -07002574 setRestrictBackgroundLocked(mRestrictBackground);
Felipe Leme76010a32016-03-17 13:03:11 -07002575
2576 // If the set of restricted networks may have changed, re-evaluate those.
2577 if (restrictedNetworksChanged) {
2578 normalizePoliciesLocked();
2579 updateNetworkRulesLocked();
2580 }
2581 if (LOGD) {
2582 final long delta = System.currentTimeMillis() - start;
2583 Slog.d(TAG, "updateRulesForGlobalChangeLocked(" + restrictedNetworksChanged + ") took "
2584 + delta + "ms");
2585 }
2586 }
2587
Felipe Lemef28983d2016-03-25 12:18:23 -07002588 private void updateRulesForRestrictBackgroundLocked() {
Felipe Leme76010a32016-03-17 13:03:11 -07002589 final PackageManager pm = mContext.getPackageManager();
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07002590
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07002591 // update rules for all installed applications
Stuart Scotte3e314d2015-04-20 14:07:45 -07002592 final List<UserInfo> users = mUserManager.getUsers();
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07002593 final List<ApplicationInfo> apps = pm.getInstalledApplications(
Jeff Sharkey8a372a02016-03-16 16:25:45 -06002594 PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_DISABLED_COMPONENTS
2595 | PackageManager.MATCH_DIRECT_BOOT_AWARE
2596 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07002597
Felipe Leme03e689d2016-03-02 16:17:38 -08002598 final int usersSize = users.size();
2599 final int appsSize = apps.size();
2600 for (int i = 0; i < usersSize; i++) {
2601 final UserInfo user = users.get(i);
2602 for (int j = 0; j < appsSize; j++) {
2603 final ApplicationInfo app = apps.get(j);
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07002604 final int uid = UserHandle.getUid(user.id, app.uid);
Felipe Lemef28983d2016-03-25 12:18:23 -07002605 updateRuleForRestrictBackgroundLocked(uid);
Jeff Sharkeyd0c6ccb2012-09-14 16:26:37 -07002606 }
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002607 }
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002608 }
2609
Felipe Leme76010a32016-03-17 13:03:11 -07002610 private void updateRulesForTempWhitelistChangeLocked() {
Amith Yamasaniaf575b92015-05-29 15:35:26 -07002611 final List<UserInfo> users = mUserManager.getUsers();
Felipe Leme03e689d2016-03-02 16:17:38 -08002612 for (int i = 0; i < users.size(); i++) {
2613 final UserInfo user = users.get(i);
Rakesh Iyer4f3fc212016-03-03 20:16:41 -08002614 for (int j = mPowerSaveTempWhitelistAppIds.size() - 1; j >= 0; j--) {
Felipe Leme03e689d2016-03-02 16:17:38 -08002615 int appId = mPowerSaveTempWhitelistAppIds.keyAt(j);
Amith Yamasaniaf575b92015-05-29 15:35:26 -07002616 int uid = UserHandle.getUid(user.id, appId);
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002617 updateRuleForAppIdleLocked(uid);
2618 updateRuleForDeviceIdleLocked(uid);
Felipe Lemef28983d2016-03-25 12:18:23 -07002619 updateRuleForRestrictPowerLocked(uid);
Amith Yamasaniaf575b92015-05-29 15:35:26 -07002620 }
2621 }
2622 }
2623
Felipe Leme70c57c22016-03-29 10:45:13 -07002624 // TODO: the MEDIA / DRM restriction might not be needed anymore, in which case both
2625 // methods below could be merged into a isUidValidForRules() method.
2626 private boolean isUidValidForBlacklistRules(int uid) {
2627 // allow rules on specific system services, and any apps
Jeff Sharkey5294a2f2012-04-24 17:07:22 -07002628 if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID
Felipe Leme70c57c22016-03-29 10:45:13 -07002629 || (UserHandle.isApp(uid) && hasInternetPermissions(uid))) {
Jeff Sharkey5294a2f2012-04-24 17:07:22 -07002630 return true;
2631 }
2632
2633 return false;
2634 }
2635
Felipe Leme70c57c22016-03-29 10:45:13 -07002636 private boolean isUidValidForWhitelistRules(int uid) {
2637 return UserHandle.isApp(uid) && hasInternetPermissions(uid);
2638 }
2639
Amith Yamasani15e472352015-04-24 19:06:07 -07002640 private boolean isUidIdle(int uid) {
2641 final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
2642 final int userId = UserHandle.getUserId(uid);
2643
Jeff Sharkey377ded0f2016-01-10 13:15:41 -07002644 if (!ArrayUtils.isEmpty(packages)) {
2645 for (String packageName : packages) {
2646 if (!mUsageStats.isAppIdle(packageName, uid, userId)) {
2647 return false;
2648 }
Amith Yamasani15e472352015-04-24 19:06:07 -07002649 }
2650 }
2651 return true;
2652 }
2653
2654 /**
Felipe Leme47585ba2016-02-09 16:56:32 -08002655 * Checks if an uid has INTERNET permissions.
2656 * <p>
2657 * Useful for the cases where the lack of network access can simplify the rules.
Amith Yamasani15e472352015-04-24 19:06:07 -07002658 */
Felipe Leme47585ba2016-02-09 16:56:32 -08002659 private boolean hasInternetPermissions(int uid) {
Dianne Hackborn88e98df2015-03-23 13:29:14 -07002660 try {
Amith Yamasani2a4ac4e2016-02-12 12:43:15 -08002661 if (mIPm.checkUidPermission(Manifest.permission.INTERNET, uid)
Dianne Hackborn88e98df2015-03-23 13:29:14 -07002662 != PackageManager.PERMISSION_GRANTED) {
Felipe Leme47585ba2016-02-09 16:56:32 -08002663 return false;
Dianne Hackborn88e98df2015-03-23 13:29:14 -07002664 }
2665 } catch (RemoteException e) {
2666 }
Felipe Leme47585ba2016-02-09 16:56:32 -08002667 return true;
2668 }
2669
2670 /**
Felipe Lemef28983d2016-03-25 12:18:23 -07002671 * Applies network rules to bandwidth and firewall controllers based on uid policy.
Felipe Leme76010a32016-03-17 13:03:11 -07002672 *
Felipe Lemef28983d2016-03-25 12:18:23 -07002673 * <p>There are currently 2 types of restriction rules:
2674 * <ul>
2675 * <li>Battery Saver Mode (also referred as power save).
2676 * <li>Data Saver Mode (formerly known as restrict background data).
2677 * </ul>
Felipe Leme47585ba2016-02-09 16:56:32 -08002678 */
Felipe Lemef28983d2016-03-25 12:18:23 -07002679 private void updateRestrictionRulesForUidLocked(int uid) {
2680 updateRuleForRestrictPowerLocked(uid);
2681 updateRuleForRestrictBackgroundLocked(uid);
2682 }
2683
Felipe Leme70c57c22016-03-29 10:45:13 -07002684 /**
2685 * Applies network rules to bandwidth controllers based on process state and user-defined
2686 * restrictions (blacklist / whitelist).
2687 *
2688 * <p>
2689 * {@code netd} defines 3 firewall chains that govern whether an app has access to metered
2690 * networks:
2691 * <ul>
2692 * <li>@{code bw_penalty_box}: UIDs added to this chain do not have access (blacklist).
2693 * <li>@{code bw_happy_box}: UIDs added to this chain have access (whitelist), unless they're
2694 * also blacklisted.
2695 * <li>@{code bw_data_saver}: when enabled (through {@link #setRestrictBackground(boolean)}),
2696 * no UIDs other those whitelisted will have access.
2697 * <ul>
2698 *
2699 * <p>The @{code bw_penalty_box} and @{code bw_happy_box} are primarily managed through the
2700 * {@link #setUidPolicy(int, int)} and {@link #addRestrictBackgroundWhitelistedUid(int)} /
2701 * {@link #removeRestrictBackgroundWhitelistedUid(int)} methods (for blacklist and whitelist
2702 * respectively): these methods set the proper internal state (blacklist / whitelist), then call
2703 * this ({@link #updateRuleForRestrictBackgroundLocked(int)}) to propagate the rules to
2704 * {@link INetworkManagementService}, but this method should also be called in events (like
2705 * Data Saver Mode flips or UID state changes) that might affect the foreground app, since the
2706 * following rules should also be applied:
2707 *
2708 * <ul>
2709 * <li>When Data Saver mode is on, the foreground app should be temporarily added to
2710 * {@code bw_happy_box} before the @{code bw_data_saver} chain is enabled.
2711 * <li>If the foreground app is blacklisted by the user, it should be temporarily removed from
2712 * {@code bw_penalty_box}.
2713 * <li>When the app leaves foreground state, the temporary changes above should be reverted.
2714 * </ul>
2715 *
2716 * <p>For optimization, the rules are only applied on user apps that have internet access
2717 * permission, since there is no need to change the {@code iptables} rule if the app does not
2718 * have permission to use the internet.
2719 *
2720 * <p>The {@link #mUidRules} map is used to define the transtion of states of an UID.
2721 */
Felipe Lemef28983d2016-03-25 12:18:23 -07002722 private void updateRuleForRestrictBackgroundLocked(int uid) {
Felipe Leme70c57c22016-03-29 10:45:13 -07002723 updateRuleForRestrictBackgroundLocked(uid, false);
2724 }
2725
2726 /**
2727 * Overloaded version of {@link #updateRuleForRestrictBackgroundLocked(int)} called when an
2728 * app is removed - it ignores the UID validity check.
2729 */
2730 private void updateRuleForRestrictBackgroundLocked(int uid, boolean uidDeleted) {
2731 if (!uidDeleted && !isUidValidForWhitelistRules(uid)) {
2732 if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid);
2733 return;
2734 }
Dianne Hackborn88e98df2015-03-23 13:29:14 -07002735
Dianne Hackborn497175b2014-07-01 12:56:08 -07002736 final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
Felipe Lemeef89c902016-03-30 15:11:31 -07002737 final boolean isForeground = isUidForegroundOnRestrictBackgroundLocked(uid);
Felipe Leme70c57c22016-03-29 10:45:13 -07002738 final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
2739 final boolean isWhitelisted = mRestrictBackgroundWhitelistUids.get(uid);
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -07002740
Felipe Leme76010a32016-03-17 13:03:11 -07002741 int newRule = RULE_ALLOW_ALL;
Felipe Leme70c57c22016-03-29 10:45:13 -07002742 final int oldRule = mUidRules.get(uid);
Felipe Leme76010a32016-03-17 13:03:11 -07002743
Felipe Leme70c57c22016-03-29 10:45:13 -07002744 // First step: define the new rule based on user restrictions and foreground state.
2745 if (isForeground) {
2746 if (isBlacklisted || (mRestrictBackground && !isWhitelisted)) {
2747 newRule = RULE_TEMPORARY_ALLOW_METERED;
2748 }
2749 } else {
2750 if (isBlacklisted) {
Felipe Leme76010a32016-03-17 13:03:11 -07002751 newRule = RULE_REJECT_METERED;
Felipe Leme70c57c22016-03-29 10:45:13 -07002752 } else if (isWhitelisted) {
2753 newRule = RULE_ALLOW_METERED;
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07002754 }
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002755 }
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -07002756
Felipe Lemef28983d2016-03-25 12:18:23 -07002757 if (LOGV) {
Felipe Leme70c57c22016-03-29 10:45:13 -07002758 Log.v(TAG, "updateRuleForRestrictBackgroundLocked(" + uid + "):"
2759 + " isForeground=" +isForeground + ", isBlacklisted: " + isBlacklisted
2760 + ", isWhitelisted: " + isWhitelisted + ", newRule: " + ruleToString(newRule)
2761 + ", oldRule: " + ruleToString(oldRule));
Felipe Lemef28983d2016-03-25 12:18:23 -07002762 }
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -07002763
Felipe Leme70c57c22016-03-29 10:45:13 -07002764
Felipe Leme76010a32016-03-17 13:03:11 -07002765 if (newRule == RULE_ALLOW_ALL) {
Jeff Sharkey350083e2011-06-29 10:45:16 -07002766 mUidRules.delete(uid);
2767 } else {
Felipe Leme76010a32016-03-17 13:03:11 -07002768 mUidRules.put(uid, newRule);
Jeff Sharkey350083e2011-06-29 10:45:16 -07002769 }
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -07002770
Felipe Leme70c57c22016-03-29 10:45:13 -07002771 // Second step: apply bw changes based on change of state.
2772 if (newRule != oldRule) {
2773 if (newRule == RULE_TEMPORARY_ALLOW_METERED) {
2774 // Temporarily whitelist foreground app, removing from blacklist if necessary
2775 // (since bw_penalty_box prevails over bw_happy_box).
2776
2777 setMeteredNetworkWhitelist(uid, true);
2778 // TODO: if statement below is used to avoid an unnecessary call to netd / iptables,
2779 // but ideally it should be just:
2780 // setMeteredNetworkBlacklist(uid, isBlacklisted);
2781 if (isBlacklisted) {
2782 setMeteredNetworkBlacklist(uid, false);
2783 }
2784 } else if (oldRule == RULE_TEMPORARY_ALLOW_METERED) {
2785 // Remove temporary whitelist from app that is not on foreground anymore.
2786
2787 // TODO: if statements below are used to avoid unnecessary calls to netd / iptables,
2788 // but ideally they should be just:
2789 // setMeteredNetworkWhitelist(uid, isWhitelisted);
2790 // setMeteredNetworkBlacklist(uid, isBlacklisted);
2791 if (!isWhitelisted) {
2792 setMeteredNetworkWhitelist(uid, false);
2793 }
2794 if (isBlacklisted) {
2795 setMeteredNetworkBlacklist(uid, true);
2796 }
2797 } else if (newRule == RULE_REJECT_METERED || oldRule == RULE_REJECT_METERED) {
2798 // Flip state because app was explicitly added or removed to blacklist.
2799 setMeteredNetworkBlacklist(uid, isBlacklisted);
2800 if (oldRule == RULE_REJECT_METERED && isWhitelisted) {
2801 // Since blacklist prevails over whitelist, we need to handle the special case
2802 // where app is whitelisted and blacklisted at the same time (although such
2803 // scenario should be blocked by the UI), then blacklist is removed.
2804 setMeteredNetworkWhitelist(uid, isWhitelisted);
2805 }
2806 } else if (newRule == RULE_ALLOW_METERED || oldRule == RULE_ALLOW_METERED) {
2807 // Flip state because app was explicitly added or removed to whitelist.
2808 setMeteredNetworkWhitelist(uid, isWhitelisted);
2809 } else {
2810 // All scenarios should have been covered above
2811 Log.wtf(TAG, "Unexpected change of state for " + uid
2812 + ": foreground=" + isForeground + ", whitelisted=" + isWhitelisted
2813 + ", blacklisted=" + isBlacklisted + ", newRule="
2814 + ruleToString(newRule) + ", oldRule=" + ruleToString(oldRule));
2815 }
Felipe Lemef28983d2016-03-25 12:18:23 -07002816
2817 // dispatch changed rule to existing listeners
Felipe Leme76010a32016-03-17 13:03:11 -07002818 mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newRule).sendToTarget();
Amith Yamasani15e472352015-04-24 19:06:07 -07002819 }
Jeff Sharkey4414cea2011-06-24 17:05:24 -07002820 }
2821
Xiaohui Chen8dca36d2015-06-19 12:44:59 -07002822 private class AppIdleStateChangeListener
2823 extends UsageStatsManagerInternal.AppIdleStateChangeListener {
2824
2825 @Override
2826 public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
2827 try {
Jeff Sharkeyc5967e92016-01-07 18:50:29 -07002828 final int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
2829 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
Xiaohui Chen8dca36d2015-06-19 12:44:59 -07002830 synchronized (mRulesLock) {
Dianne Hackborn4a503b12015-08-06 22:19:06 -07002831 updateRuleForAppIdleLocked(uid);
Xiaohui Chen8dca36d2015-06-19 12:44:59 -07002832 }
2833 } catch (NameNotFoundException nnfe) {
Amith Yamasani15e472352015-04-24 19:06:07 -07002834 }
Xiaohui Chen8dca36d2015-06-19 12:44:59 -07002835 }
2836
2837 @Override
2838 public void onParoleStateChanged(boolean isParoleOn) {
2839 synchronized (mRulesLock) {
2840 updateRulesForAppIdleParoleLocked();
2841 }
Amith Yamasani15e472352015-04-24 19:06:07 -07002842 }
2843 }
2844
Jeff Sharkey4414cea2011-06-24 17:05:24 -07002845 private Handler.Callback mHandlerCallback = new Handler.Callback() {
Jeff Sharkeybfdd6802012-04-09 10:49:19 -07002846 @Override
Jeff Sharkey4414cea2011-06-24 17:05:24 -07002847 public boolean handleMessage(Message msg) {
2848 switch (msg.what) {
2849 case MSG_RULES_CHANGED: {
2850 final int uid = msg.arg1;
2851 final int uidRules = msg.arg2;
2852 final int length = mListeners.beginBroadcast();
2853 for (int i = 0; i < length; i++) {
2854 final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
2855 if (listener != null) {
2856 try {
2857 listener.onUidRulesChanged(uid, uidRules);
2858 } catch (RemoteException e) {
2859 }
2860 }
2861 }
2862 mListeners.finishBroadcast();
2863 return true;
2864 }
2865 case MSG_METERED_IFACES_CHANGED: {
2866 final String[] meteredIfaces = (String[]) msg.obj;
2867 final int length = mListeners.beginBroadcast();
2868 for (int i = 0; i < length; i++) {
2869 final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
2870 if (listener != null) {
2871 try {
2872 listener.onMeteredIfacesChanged(meteredIfaces);
2873 } catch (RemoteException e) {
2874 }
2875 }
2876 }
2877 mListeners.finishBroadcast();
2878 return true;
2879 }
Jeff Sharkey7e25b0e2011-11-08 15:43:12 -08002880 case MSG_LIMIT_REACHED: {
2881 final String iface = (String) msg.obj;
2882
Jeff Sharkey684c54a2011-11-16 17:46:30 -08002883 maybeRefreshTrustedTime();
Jeff Sharkey7e25b0e2011-11-08 15:43:12 -08002884 synchronized (mRulesLock) {
2885 if (mMeteredIfaces.contains(iface)) {
2886 try {
2887 // force stats update to make sure we have
2888 // numbers that caused alert to trigger.
2889 mNetworkStats.forceUpdate();
2890 } catch (RemoteException e) {
2891 // ignored; service lives in system_server
2892 }
2893
2894 updateNetworkEnabledLocked();
2895 updateNotificationsLocked();
2896 }
2897 }
2898 return true;
2899 }
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -08002900 case MSG_RESTRICT_BACKGROUND_CHANGED: {
2901 final boolean restrictBackground = msg.arg1 != 0;
2902 final int length = mListeners.beginBroadcast();
2903 for (int i = 0; i < length; i++) {
2904 final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
2905 if (listener != null) {
2906 try {
2907 listener.onRestrictBackgroundChanged(restrictBackground);
2908 } catch (RemoteException e) {
2909 }
2910 }
2911 }
2912 mListeners.finishBroadcast();
Felipe Leme9778f762016-01-27 14:46:39 -08002913 final Intent intent =
2914 new Intent(ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED);
2915 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
2916 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2917 return true;
2918 }
2919 case MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED: {
2920 final int uid = msg.arg1;
2921 final PackageManager pm = mContext.getPackageManager();
2922 final String[] packages = pm.getPackagesForUid(uid);
Felipe Leme86e5a012016-02-16 16:26:05 -08002923 if (packages != null) {
2924 final int userId = UserHandle.getUserId(uid);
2925 for (String packageName : packages) {
2926 final Intent intent = new Intent(
2927 ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED);
2928 intent.setPackage(packageName);
2929 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
2930 mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
2931 }
2932 } else {
2933 Slog.w(TAG, "no packages for uid " + uid);
Felipe Leme9778f762016-01-27 14:46:39 -08002934 }
Jeff Sharkeye19f39b2012-05-24 10:21:16 -07002935 return true;
2936 }
2937 case MSG_ADVISE_PERSIST_THRESHOLD: {
2938 final long lowestRule = (Long) msg.obj;
2939 try {
2940 // make sure stats are recorded frequently enough; we aim
2941 // for 2MB threshold for 2GB/month rules.
2942 final long persistThreshold = lowestRule / 1000;
2943 mNetworkStats.advisePersistThreshold(persistThreshold);
2944 } catch (RemoteException e) {
2945 // ignored; service lives in system_server
2946 }
2947 return true;
Jeff Sharkey1f8ea2d2012-02-07 12:05:43 -08002948 }
Jeff Sharkey0abe5562012-06-19 13:32:22 -07002949 case MSG_SCREEN_ON_CHANGED: {
2950 updateScreenOn();
2951 return true;
2952 }
Jeff Sharkey4414cea2011-06-24 17:05:24 -07002953 default: {
2954 return false;
Jeff Sharkeyaf11d482011-06-13 00:14:31 -07002955 }
2956 }
2957 }
Jeff Sharkey4414cea2011-06-24 17:05:24 -07002958 };
Jeff Sharkey22c055e2011-06-12 21:13:51 -07002959
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07002960 private void setInterfaceQuota(String iface, long quotaBytes) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002961 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07002962 mNetworkManager.setInterfaceQuota(iface, quotaBytes);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002963 } catch (IllegalStateException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07002964 Log.wtf(TAG, "problem setting interface quota", e);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002965 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07002966 // ignored; service lives in system_server
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002967 }
2968 }
2969
2970 private void removeInterfaceQuota(String iface) {
2971 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07002972 mNetworkManager.removeInterfaceQuota(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002973 } catch (IllegalStateException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07002974 Log.wtf(TAG, "problem removing interface quota", e);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002975 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07002976 // ignored; service lives in system_server
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07002977 }
2978 }
2979
Felipe Leme70c57c22016-03-29 10:45:13 -07002980 private void setMeteredNetworkBlacklist(int uid, boolean enable) {
2981 if (LOGV) Slog.v(TAG, "setMeteredNetworkBlacklist " + uid + ": " + enable);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002982 try {
Felipe Leme70c57c22016-03-29 10:45:13 -07002983 mNetworkManager.setUidMeteredNetworkBlacklist(uid, enable);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002984 } catch (IllegalStateException e) {
Felipe Leme70c57c22016-03-29 10:45:13 -07002985 Log.wtf(TAG, "problem setting blacklist (" + enable + ") rules for " + uid, e);
2986 } catch (RemoteException e) {
2987 // ignored; service lives in system_server
2988 }
2989 }
2990
2991 private void setMeteredNetworkWhitelist(int uid, boolean enable) {
2992 if (LOGV) Slog.v(TAG, "setMeteredNetworkWhitelist " + uid + ": " + enable);
2993 try {
2994 mNetworkManager.setUidMeteredNetworkWhitelist(uid, enable);
2995 } catch (IllegalStateException e) {
2996 Log.wtf(TAG, "problem setting whitelist (" + enable + ") rules for " + uid, e);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002997 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07002998 // ignored; service lives in system_server
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07002999 }
3000 }
3001
Amith Yamasani15e472352015-04-24 19:06:07 -07003002 /**
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07003003 * Set uid rules on a particular firewall chain. This is going to synchronize the rules given
3004 * here to netd. It will clean up dead rules and make sure the target chain only contains rules
3005 * specified here.
Amith Yamasani15e472352015-04-24 19:06:07 -07003006 */
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07003007 private void setUidFirewallRules(int chain, SparseIntArray uidRules) {
Amith Yamasani15e472352015-04-24 19:06:07 -07003008 try {
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07003009 int size = uidRules.size();
3010 int[] uids = new int[size];
3011 int[] rules = new int[size];
3012 for(int index = size - 1; index >= 0; --index) {
3013 uids[index] = uidRules.keyAt(index);
3014 rules[index] = uidRules.valueAt(index);
3015 }
3016 mNetworkManager.setFirewallUidRules(chain, uids, rules);
Amith Yamasani15e472352015-04-24 19:06:07 -07003017 } catch (IllegalStateException e) {
3018 Log.wtf(TAG, "problem setting firewall uid rules", e);
3019 } catch (RemoteException e) {
3020 // ignored; service lives in system_server
3021 }
3022 }
3023
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07003024 /**
3025 * Add or remove a uid to the firewall blacklist for all network ifaces.
3026 */
Dianne Hackborn4a503b12015-08-06 22:19:06 -07003027 private void setUidFirewallRule(int chain, int uid, int rule) {
Jeff Sharkeydc988062015-09-14 10:09:47 -07003028 if (chain == FIREWALL_CHAIN_DOZABLE) {
3029 mUidFirewallDozableRules.put(uid, rule);
3030 } else if (chain == FIREWALL_CHAIN_STANDBY) {
3031 mUidFirewallStandbyRules.put(uid, rule);
Felipe Leme011b98f2016-02-10 17:28:31 -08003032 } else if (chain == FIREWALL_CHAIN_POWERSAVE) {
3033 mUidFirewallPowerSaveRules.put(uid, rule);
Jeff Sharkeydc988062015-09-14 10:09:47 -07003034 }
3035
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07003036 try {
Dianne Hackborn4a503b12015-08-06 22:19:06 -07003037 mNetworkManager.setFirewallUidRule(chain, uid, rule);
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07003038 } catch (IllegalStateException e) {
3039 Log.wtf(TAG, "problem setting firewall uid rules", e);
3040 } catch (RemoteException e) {
3041 // ignored; service lives in system_server
3042 }
3043 }
3044
3045 /**
3046 * Add or remove a uid to the firewall blacklist for all network ifaces.
3047 */
Xiaohui Chen8dca36d2015-06-19 12:44:59 -07003048 private void enableFirewallChainLocked(int chain, boolean enable) {
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07003049 if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
3050 mFirewallChainStates.get(chain) == enable) {
3051 // All is the same, nothing to do.
3052 return;
3053 }
Xiaohui Chen8dca36d2015-06-19 12:44:59 -07003054 mFirewallChainStates.put(chain, enable);
Xiaohui Chenb41c9f72015-06-17 15:55:37 -07003055 try {
3056 mNetworkManager.setFirewallChainEnabled(chain, enable);
3057 } catch (IllegalStateException e) {
3058 Log.wtf(TAG, "problem enable firewall chain", e);
3059 } catch (RemoteException e) {
3060 // ignored; service lives in system_server
3061 }
3062 }
3063
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07003064 private long getTotalBytes(NetworkTemplate template, long start, long end) {
3065 try {
Jeff Sharkeyb52e3e52012-04-06 11:12:08 -07003066 return mNetworkStats.getNetworkTotalBytes(template, start, end);
Jeff Sharkey63abc372012-01-11 18:38:16 -08003067 } catch (RuntimeException e) {
3068 Slog.w(TAG, "problem reading network stats: " + e);
3069 return 0;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07003070 } catch (RemoteException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07003071 // ignored; service lives in system_server
3072 return 0;
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07003073 }
3074 }
3075
Jeff Sharkey8c1dc722012-05-04 14:49:37 -07003076 private boolean isBandwidthControlEnabled() {
3077 final long token = Binder.clearCallingIdentity();
3078 try {
3079 return mNetworkManager.isBandwidthControlEnabled();
3080 } catch (RemoteException e) {
3081 // ignored; service lives in system_server
3082 return false;
3083 } finally {
3084 Binder.restoreCallingIdentity(token);
3085 }
3086 }
3087
Jeff Sharkey684c54a2011-11-16 17:46:30 -08003088 /**
3089 * Try refreshing {@link #mTime} when stale.
3090 */
Dianne Hackborn497175b2014-07-01 12:56:08 -07003091 void maybeRefreshTrustedTime() {
Jeff Sharkey684c54a2011-11-16 17:46:30 -08003092 if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07003093 mTime.forceRefresh();
3094 }
Jeff Sharkey684c54a2011-11-16 17:46:30 -08003095 }
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07003096
Jeff Sharkey684c54a2011-11-16 17:46:30 -08003097 private long currentTimeMillis() {
Jeff Sharkey8e28b7d2011-08-19 02:24:24 -07003098 return mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
3099 }
3100
Jeff Sharkey3a844fc2011-08-16 14:37:57 -07003101 private static Intent buildAllowBackgroundDataIntent() {
3102 return new Intent(ACTION_ALLOW_BACKGROUND);
3103 }
3104
Jeff Sharkey0e2e5f82012-02-02 16:02:51 -08003105 private static Intent buildSnoozeWarningIntent(NetworkTemplate template) {
3106 final Intent intent = new Intent(ACTION_SNOOZE_WARNING);
3107 intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
3108 return intent;
3109 }
3110
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07003111 private static Intent buildNetworkOverLimitIntent(NetworkTemplate template) {
3112 final Intent intent = new Intent();
3113 intent.setComponent(new ComponentName(
3114 "com.android.systemui", "com.android.systemui.net.NetworkOverLimitActivity"));
3115 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3116 intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
3117 return intent;
3118 }
3119
3120 private static Intent buildViewDataUsageIntent(NetworkTemplate template) {
3121 final Intent intent = new Intent();
3122 intent.setComponent(new ComponentName(
3123 "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
3124 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
3125 intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
3126 return intent;
3127 }
3128
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -08003129 @VisibleForTesting
Jeff Sharkey163e6442011-10-31 16:37:52 -07003130 public void addIdleHandler(IdleHandler handler) {
3131 mHandler.getLooper().getQueue().addIdleHandler(handler);
3132 }
3133
Jeff Sharkey1b861272011-05-22 00:34:52 -07003134 private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
3135 final int size = source.size();
3136 for (int i = 0; i < size; i++) {
3137 target.put(source.keyAt(i), true);
3138 }
3139 }
3140
Stuart Scottf1fb3972015-04-02 18:00:02 -07003141 @Override
3142 public void factoryReset(String subscriber) {
3143 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
3144
Stuart Scotte3e314d2015-04-20 14:07:45 -07003145 if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
3146 return;
3147 }
3148
Stuart Scottf1fb3972015-04-02 18:00:02 -07003149 // Turn mobile data limit off
Stuart Scott9a9a1d92015-04-20 11:33:06 -07003150 NetworkPolicy[] policies = getNetworkPolicies(mContext.getOpPackageName());
Stuart Scottf1fb3972015-04-02 18:00:02 -07003151 NetworkTemplate template = NetworkTemplate.buildTemplateMobileAll(subscriber);
3152 for (NetworkPolicy policy : policies) {
3153 if (policy.template.equals(template)) {
3154 policy.limitBytes = NetworkPolicy.LIMIT_DISABLED;
3155 policy.inferred = false;
3156 policy.clearSnooze();
3157 }
3158 }
3159 setNetworkPolicies(policies);
3160
3161 // Turn restrict background data off
3162 setRestrictBackground(false);
3163
Stuart Scotte3e314d2015-04-20 14:07:45 -07003164 if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL)) {
3165 // Remove app's "restrict background data" flag
3166 for (int uid : getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) {
3167 setUidPolicy(uid, POLICY_NONE);
3168 }
Stuart Scottf1fb3972015-04-02 18:00:02 -07003169 }
3170 }
Felipe Lemeb85a6372016-01-14 16:16:16 -08003171
3172 private class MyPackageMonitor extends PackageMonitor {
3173
3174 @Override
3175 public void onPackageRemoved(String packageName, int uid) {
3176 if (LOGV) Slog.v(TAG, "onPackageRemoved: " + packageName + " ->" + uid);
3177 synchronized (mRulesLock) {
Felipe Leme70c57c22016-03-29 10:45:13 -07003178 removeRestrictBackgroundWhitelistedUidLocked(uid, true, true);
Felipe Lemeb85a6372016-01-14 16:16:16 -08003179 }
3180 }
Felipe Lemeb85a6372016-01-14 16:16:16 -08003181 }
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -07003182}