1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.settings.datausage; 16 17 import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND; 18 import static android.net.NetworkPolicyManager.POLICY_NONE; 19 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; 20 21 import android.content.Context; 22 import android.net.INetworkPolicyListener; 23 import android.net.NetworkPolicyManager; 24 import android.os.RemoteException; 25 import android.util.SparseIntArray; 26 27 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 28 import com.android.settings.overlay.FeatureFactory; 29 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 30 import com.android.settingslib.utils.ThreadUtils; 31 32 import java.util.ArrayList; 33 34 public class DataSaverBackend { 35 36 private static final String TAG = "DataSaverBackend"; 37 38 private final Context mContext; 39 private final MetricsFeatureProvider mMetricsFeatureProvider; 40 41 private final NetworkPolicyManager mPolicyManager; 42 private final ArrayList<Listener> mListeners = new ArrayList<>(); 43 private SparseIntArray mUidPolicies = new SparseIntArray(); 44 private boolean mWhitelistInitialized; 45 private boolean mBlacklistInitialized; 46 47 // TODO: Staticize into only one. 48 public DataSaverBackend(Context context) { 49 mContext = context; 50 mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); 51 mPolicyManager = NetworkPolicyManager.from(context); 52 } 53 54 public void addListener(Listener listener) { 55 mListeners.add(listener); 56 if (mListeners.size() == 1) { 57 mPolicyManager.registerListener(mPolicyListener); 58 } 59 listener.onDataSaverChanged(isDataSaverEnabled()); 60 } 61 62 public void remListener(Listener listener) { 63 mListeners.remove(listener); 64 if (mListeners.size() == 0) { 65 mPolicyManager.unregisterListener(mPolicyListener); 66 } 67 } 68 69 public boolean isDataSaverEnabled() { 70 return mPolicyManager.getRestrictBackground(); 71 } 72 73 public void setDataSaverEnabled(boolean enabled) { 74 mPolicyManager.setRestrictBackground(enabled); 75 mMetricsFeatureProvider.action( 76 mContext, MetricsEvent.ACTION_DATA_SAVER_MODE, enabled ? 1 : 0); 77 } 78 79 public void refreshWhitelist() { 80 loadWhitelist(); 81 } 82 83 public void setIsWhitelisted(int uid, String packageName, boolean whitelisted) { 84 final int policy = whitelisted ? POLICY_ALLOW_METERED_BACKGROUND : POLICY_NONE; 85 mPolicyManager.setUidPolicy(uid, policy); 86 mUidPolicies.put(uid, policy); 87 if (whitelisted) { 88 mMetricsFeatureProvider.action( 89 mContext, MetricsEvent.ACTION_DATA_SAVER_WHITELIST, packageName); 90 } 91 } 92 93 public boolean isWhitelisted(int uid) { 94 loadWhitelist(); 95 return mUidPolicies.get(uid, POLICY_NONE) == POLICY_ALLOW_METERED_BACKGROUND; 96 } 97 98 public int getWhitelistedCount() { 99 int count = 0; 100 loadWhitelist(); 101 for (int i = 0; i < mUidPolicies.size(); i++) { 102 if (mUidPolicies.valueAt(i) == POLICY_ALLOW_METERED_BACKGROUND) { 103 count++; 104 } 105 } 106 return count; 107 } 108 109 private void loadWhitelist() { 110 if (mWhitelistInitialized) return; 111 112 for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND)) { 113 mUidPolicies.put(uid, POLICY_ALLOW_METERED_BACKGROUND); 114 } 115 mWhitelistInitialized = true; 116 } 117 118 public void refreshBlacklist() { 119 loadBlacklist(); 120 } 121 122 public void setIsBlacklisted(int uid, String packageName, boolean blacklisted) { 123 final int policy = blacklisted ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE; 124 mPolicyManager.setUidPolicy(uid, policy); 125 mUidPolicies.put(uid, policy); 126 if (blacklisted) { 127 mMetricsFeatureProvider.action( 128 mContext, MetricsEvent.ACTION_DATA_SAVER_BLACKLIST, packageName); 129 } 130 } 131 132 public boolean isBlacklisted(int uid) { 133 loadBlacklist(); 134 return mUidPolicies.get(uid, POLICY_NONE) == POLICY_REJECT_METERED_BACKGROUND; 135 } 136 137 private void loadBlacklist() { 138 if (mBlacklistInitialized) return; 139 for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) { 140 mUidPolicies.put(uid, POLICY_REJECT_METERED_BACKGROUND); 141 } 142 mBlacklistInitialized = true; 143 } 144 145 private void handleRestrictBackgroundChanged(boolean isDataSaving) { 146 for (int i = 0; i < mListeners.size(); i++) { 147 mListeners.get(i).onDataSaverChanged(isDataSaving); 148 } 149 } 150 151 private void handleWhitelistChanged(int uid, boolean isWhitelisted) { 152 for (int i = 0; i < mListeners.size(); i++) { 153 mListeners.get(i).onWhitelistStatusChanged(uid, isWhitelisted); 154 } 155 } 156 157 private void handleBlacklistChanged(int uid, boolean isBlacklisted) { 158 for (int i = 0; i < mListeners.size(); i++) { 159 mListeners.get(i).onBlacklistStatusChanged(uid, isBlacklisted); 160 } 161 } 162 163 private void handleUidPoliciesChanged(int uid, int newPolicy) { 164 loadWhitelist(); 165 loadBlacklist(); 166 167 final int oldPolicy = mUidPolicies.get(uid, POLICY_NONE); 168 if (newPolicy == POLICY_NONE) { 169 mUidPolicies.delete(uid); 170 } else { 171 mUidPolicies.put(uid, newPolicy); 172 } 173 174 final boolean wasWhitelisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND; 175 final boolean wasBlacklisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND; 176 final boolean isWhitelisted = newPolicy == POLICY_ALLOW_METERED_BACKGROUND; 177 final boolean isBlacklisted = newPolicy == POLICY_REJECT_METERED_BACKGROUND; 178 179 if (wasWhitelisted != isWhitelisted) { 180 handleWhitelistChanged(uid, isWhitelisted); 181 } 182 183 if (wasBlacklisted != isBlacklisted) { 184 handleBlacklistChanged(uid, isBlacklisted); 185 } 186 187 } 188 189 private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { 190 @Override 191 public void onUidRulesChanged(int uid, int uidRules) throws RemoteException { 192 } 193 194 @Override 195 public void onUidPoliciesChanged(final int uid, final int uidPolicies) { 196 ThreadUtils.postOnMainThread(() -> handleUidPoliciesChanged(uid, uidPolicies)); 197 } 198 199 @Override 200 public void onMeteredIfacesChanged(String[] strings) throws RemoteException { 201 } 202 203 @Override 204 public void onRestrictBackgroundChanged(final boolean isDataSaving) throws RemoteException { 205 ThreadUtils.postOnMainThread(() -> handleRestrictBackgroundChanged(isDataSaving)); 206 } 207 208 @Override 209 public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) { 210 } 211 }; 212 213 public interface Listener { 214 void onDataSaverChanged(boolean isDataSaving); 215 void onWhitelistStatusChanged(int uid, boolean isWhitelisted); 216 void onBlacklistStatusChanged(int uid, boolean isBlacklisted); 217 } 218 } 219