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 android.content.Context;
18 import android.net.INetworkPolicyListener;
19 import android.net.INetworkPolicyManager;
20 import android.net.NetworkPolicyManager;
21 import android.os.Handler;
22 import android.os.RemoteException;
23 import android.os.ServiceManager;
24 import android.util.Log;
25 import android.util.SparseBooleanArray;
26 
27 import com.android.internal.logging.MetricsLogger;
28 import com.android.internal.logging.MetricsProto.MetricsEvent;
29 
30 import java.util.ArrayList;
31 
32 import static android.net.NetworkPolicyManager.POLICY_NONE;
33 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
34 
35 public class DataSaverBackend {
36 
37     private static final String TAG = "DataSaverBackend";
38 
39     private final Context mContext;
40 
41     private final Handler mHandler = new Handler();
42     private final NetworkPolicyManager mPolicyManager;
43     private final INetworkPolicyManager mIPolicyManager;
44     private final ArrayList<Listener> mListeners = new ArrayList<>();
45     private SparseBooleanArray mWhitelist;
46     private SparseBooleanArray mBlacklist;
47 
48     // TODO: Staticize into only one.
DataSaverBackend(Context context)49     public DataSaverBackend(Context context) {
50         mContext = context;
51         mIPolicyManager = INetworkPolicyManager.Stub.asInterface(
52                         ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
53         mPolicyManager = NetworkPolicyManager.from(context);
54     }
55 
addListener(Listener listener)56     public void addListener(Listener listener) {
57         mListeners.add(listener);
58         if (mListeners.size() == 1) {
59             mPolicyManager.registerListener(mPolicyListener);
60         }
61         listener.onDataSaverChanged(isDataSaverEnabled());
62     }
63 
remListener(Listener listener)64     public void remListener(Listener listener) {
65         mListeners.remove(listener);
66         if (mListeners.size() == 0) {
67             mPolicyManager.unregisterListener(mPolicyListener);
68         }
69     }
70 
isDataSaverEnabled()71     public boolean isDataSaverEnabled() {
72         return mPolicyManager.getRestrictBackground();
73     }
74 
setDataSaverEnabled(boolean enabled)75     public void setDataSaverEnabled(boolean enabled) {
76         mPolicyManager.setRestrictBackground(enabled);
77         MetricsLogger.action(mContext, MetricsEvent.ACTION_DATA_SAVER_MODE, enabled ? 1 : 0);
78     }
79 
refreshWhitelist()80     public void refreshWhitelist() {
81         loadWhitelist();
82     }
83 
setIsWhitelisted(int uid, String packageName, boolean whitelisted)84     public void setIsWhitelisted(int uid, String packageName, boolean whitelisted) {
85         mWhitelist.put(uid, whitelisted);
86         try {
87             if (whitelisted) {
88                 mIPolicyManager.addRestrictBackgroundWhitelistedUid(uid);
89             } else {
90                 mIPolicyManager.removeRestrictBackgroundWhitelistedUid(uid);
91             }
92         } catch (RemoteException e) {
93             Log.w(TAG, "Can't reach policy manager", e);
94         }
95         if (whitelisted) {
96             MetricsLogger.action(mContext, MetricsEvent.ACTION_DATA_SAVER_WHITELIST, packageName);
97         }
98     }
99 
isWhitelisted(int uid)100     public boolean isWhitelisted(int uid) {
101         if (mWhitelist == null) {
102             loadWhitelist();
103         }
104         return mWhitelist.get(uid);
105     }
106 
getWhitelistedCount()107     public int getWhitelistedCount() {
108         int count = 0;
109         if (mWhitelist == null) {
110             loadWhitelist();
111         }
112         for (int i = 0; i < mWhitelist.size(); i++) {
113             if (mWhitelist.valueAt(i)) {
114                 count++;
115             }
116         }
117         return count;
118     }
119 
loadWhitelist()120     private void loadWhitelist() {
121         mWhitelist = new SparseBooleanArray();
122         try {
123             for (int uid : mIPolicyManager.getRestrictBackgroundWhitelistedUids()) {
124                 mWhitelist.put(uid, true);
125             }
126         } catch (RemoteException e) {
127         }
128     }
129 
refreshBlacklist()130     public void refreshBlacklist() {
131         loadBlacklist();
132     }
133 
setIsBlacklisted(int uid, String packageName, boolean blacklisted)134     public void setIsBlacklisted(int uid, String packageName, boolean blacklisted) {
135         mPolicyManager.setUidPolicy(
136                 uid, blacklisted ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
137         if (blacklisted) {
138             MetricsLogger.action(mContext, MetricsEvent.ACTION_DATA_SAVER_BLACKLIST, packageName);
139         }
140     }
141 
isBlacklisted(int uid)142     public boolean isBlacklisted(int uid) {
143         if (mBlacklist == null) {
144             loadBlacklist();
145         }
146         return mBlacklist.get(uid);
147     }
148 
loadBlacklist()149     private void loadBlacklist() {
150         mBlacklist = new SparseBooleanArray();
151         try {
152             for (int uid : mIPolicyManager.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) {
153                 mBlacklist.put(uid, true);
154             }
155         } catch (RemoteException e) {
156         }
157     }
158 
handleRestrictBackgroundChanged(boolean isDataSaving)159     private void handleRestrictBackgroundChanged(boolean isDataSaving) {
160         for (int i = 0; i < mListeners.size(); i++) {
161             mListeners.get(i).onDataSaverChanged(isDataSaving);
162         }
163     }
164 
handleWhitelistChanged(int uid, boolean isWhitelisted)165     private void handleWhitelistChanged(int uid, boolean isWhitelisted) {
166         for (int i = 0; i < mListeners.size(); i++) {
167             mListeners.get(i).onWhitelistStatusChanged(uid, isWhitelisted);
168         }
169     }
170 
handleBlacklistChanged(int uid, boolean isBlacklisted)171     private void handleBlacklistChanged(int uid, boolean isBlacklisted) {
172         for (int i = 0; i < mListeners.size(); i++) {
173             mListeners.get(i).onBlacklistStatusChanged(uid, isBlacklisted);
174         }
175     }
176 
177     private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
178         @Override
179         public void onUidRulesChanged(final int uid, int uidRules) throws RemoteException {
180         }
181 
182         @Override
183         public void onRestrictBackgroundBlacklistChanged(int uid, boolean blacklisted) {
184             if (mBlacklist == null) {
185                 loadBlacklist();
186             }
187             mBlacklist.put(uid, blacklisted);
188             mHandler.post(new Runnable() {
189                 @Override
190                 public void run() {
191                     handleBlacklistChanged(uid, blacklisted);
192                 }
193             });
194         }
195 
196         @Override
197         public void onRestrictBackgroundWhitelistChanged(final int uid, final boolean whitelisted) {
198             if (mWhitelist == null) {
199                 loadWhitelist();
200             }
201             mWhitelist.put(uid, whitelisted);
202             mHandler.post(new Runnable() {
203                 @Override
204                 public void run() {
205                     handleWhitelistChanged(uid, whitelisted);
206                 }
207             });
208         }
209 
210         @Override
211         public void onMeteredIfacesChanged(String[] strings) throws RemoteException {
212         }
213 
214         @Override
215         public void onRestrictBackgroundChanged(final boolean isDataSaving) throws RemoteException {
216             mHandler.post(new Runnable() {
217                 @Override
218                 public void run() {
219                     handleRestrictBackgroundChanged(isDataSaving);
220                 }
221             });
222         }
223     };
224 
225     public interface Listener {
onDataSaverChanged(boolean isDataSaving)226         void onDataSaverChanged(boolean isDataSaving);
onWhitelistStatusChanged(int uid, boolean isWhitelisted)227         void onWhitelistStatusChanged(int uid, boolean isWhitelisted);
onBlacklistStatusChanged(int uid, boolean isBlacklisted)228         void onBlacklistStatusChanged(int uid, boolean isBlacklisted);
229     }
230 }
231