blob: 1a90a92449d318982389f130c6ee38c4535f4f4d [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 Sharkey1b861272011-05-22 00:34:52 -070019import static android.Manifest.permission.DUMP;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070020import static android.Manifest.permission.MANAGE_APP_TOKENS;
21import static android.Manifest.permission.UPDATE_DEVICE_STATS;
22import static android.net.NetworkPolicyManager.POLICY_NONE;
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -070023import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID_BACKGROUND;
24import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
25import static android.net.NetworkPolicyManager.RULE_REJECT_PAID;
Jeff Sharkey1b861272011-05-22 00:34:52 -070026import static android.net.NetworkPolicyManager.dumpPolicy;
27import static android.net.NetworkPolicyManager.dumpRules;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070028
Jeff Sharkeya4620792011-05-20 15:29:23 -070029import android.app.IActivityManager;
30import android.app.IProcessObserver;
31import android.content.BroadcastReceiver;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070032import android.content.Context;
Jeff Sharkeya4620792011-05-20 15:29:23 -070033import android.content.Intent;
34import android.content.IntentFilter;
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -070035import android.net.ConnectivityManager;
36import android.net.INetworkPolicyListener;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070037import android.net.INetworkPolicyManager;
Jeff Sharkey75279902011-05-24 18:39:45 -070038import android.net.INetworkStatsService;
Jeff Sharkeya4620792011-05-20 15:29:23 -070039import android.os.IPowerManager;
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -070040import android.os.RemoteCallbackList;
Jeff Sharkeya4620792011-05-20 15:29:23 -070041import android.os.RemoteException;
Jeff Sharkeya4620792011-05-20 15:29:23 -070042import android.util.Slog;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070043import android.util.SparseArray;
44import android.util.SparseBooleanArray;
45import android.util.SparseIntArray;
46
Jeff Sharkey1b861272011-05-22 00:34:52 -070047import java.io.FileDescriptor;
48import java.io.PrintWriter;
49
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070050/**
51 * Service that maintains low-level network policy rules and collects usage
52 * statistics to drive those rules.
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -070053 * <p>
54 * Derives active rules by combining a given policy with other system status,
55 * and delivers to listeners, such as {@link ConnectivityManager}, for
56 * enforcement.
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070057 */
58public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
59 private static final String TAG = "NetworkPolicy";
60 private static final boolean LOGD = true;
61
Jeff Sharkey75279902011-05-24 18:39:45 -070062 private final Context mContext;
63 private final IActivityManager mActivityManager;
64 private final IPowerManager mPowerManager;
65 private final INetworkStatsService mNetworkStats;
Jeff Sharkeya4620792011-05-20 15:29:23 -070066
Jeff Sharkey75279902011-05-24 18:39:45 -070067 private final Object mRulesLock = new Object();
Jeff Sharkeya4620792011-05-20 15:29:23 -070068
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -070069 private boolean mScreenOn;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070070
71 /** Current network policy for each UID. */
Jeff Sharkeya4620792011-05-20 15:29:23 -070072 private SparseIntArray mUidPolicy = new SparseIntArray();
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -070073 /** Current derived network rules for each UID. */
74 private SparseIntArray mUidRules = new SparseIntArray();
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070075
76 /** Foreground at both UID and PID granularity. */
Jeff Sharkeya4620792011-05-20 15:29:23 -070077 private SparseBooleanArray mUidForeground = new SparseBooleanArray();
78 private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
79 SparseBooleanArray>();
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070080
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -070081 private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
82 INetworkPolicyListener>();
83
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -070084 // TODO: save/restore policy information from disk
85
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -070086 // TODO: keep whitelist of system-critical services that should never have
87 // rules enforced, such as system, phone, and radio UIDs.
88
Jeff Sharkey75279902011-05-24 18:39:45 -070089 // TODO: keep record of billing cycle details, and limit rules
90 // TODO: keep map of interfaces-to-billing-relationship
91
Jeff Sharkeyd2a45872011-05-28 20:56:34 -070092 // TODO: dispatch callbacks through handler when locked
93
Jeff Sharkey75279902011-05-24 18:39:45 -070094 public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
95 IPowerManager powerManager, INetworkStatsService networkStats) {
Jeff Sharkeya4620792011-05-20 15:29:23 -070096 mContext = checkNotNull(context, "missing context");
97 mActivityManager = checkNotNull(activityManager, "missing activityManager");
98 mPowerManager = checkNotNull(powerManager, "missing powerManager");
Jeff Sharkey75279902011-05-24 18:39:45 -070099 mNetworkStats = checkNotNull(networkStats, "missing networkStats");
Jeff Sharkeya4620792011-05-20 15:29:23 -0700100 }
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700101
Jeff Sharkeya4620792011-05-20 15:29:23 -0700102 public void systemReady() {
Jeff Sharkey75279902011-05-24 18:39:45 -0700103 // TODO: read current policy from disk
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700104
Jeff Sharkeya4620792011-05-20 15:29:23 -0700105 updateScreenOn();
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700106
Jeff Sharkeya4620792011-05-20 15:29:23 -0700107 try {
108 mActivityManager.registerProcessObserver(mProcessObserver);
109 } catch (RemoteException e) {
110 // ouch, no foregroundActivities updates means some processes may
111 // never get network access.
112 Slog.e(TAG, "unable to register IProcessObserver", e);
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700113 }
Jeff Sharkeya4620792011-05-20 15:29:23 -0700114
115 // TODO: traverse existing processes to know foreground state, or have
116 // activitymanager dispatch current state when new observer attached.
117
118 final IntentFilter screenFilter = new IntentFilter();
119 screenFilter.addAction(Intent.ACTION_SCREEN_ON);
120 screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
121 mContext.registerReceiver(mScreenReceiver, screenFilter);
122
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700123 }
124
Jeff Sharkeya4620792011-05-20 15:29:23 -0700125 private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
126 @Override
127 public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
128 // only someone like AMS should only be calling us
Jeff Sharkey75279902011-05-24 18:39:45 -0700129 mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700130
Jeff Sharkeya4620792011-05-20 15:29:23 -0700131 synchronized (mRulesLock) {
132 // because a uid can have multiple pids running inside, we need to
133 // remember all pid states and summarize foreground at uid level.
134
135 // record foreground for this specific pid
136 SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
137 if (pidForeground == null) {
138 pidForeground = new SparseBooleanArray(2);
139 mUidPidForeground.put(uid, pidForeground);
140 }
141 pidForeground.put(pid, foregroundActivities);
142 computeUidForegroundL(uid);
143 }
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700144 }
Jeff Sharkeya4620792011-05-20 15:29:23 -0700145
146 @Override
147 public void onProcessDied(int pid, int uid) {
148 // only someone like AMS should only be calling us
Jeff Sharkey75279902011-05-24 18:39:45 -0700149 mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
Jeff Sharkeya4620792011-05-20 15:29:23 -0700150
151 synchronized (mRulesLock) {
152 // clear records and recompute, when they exist
153 final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
154 if (pidForeground != null) {
155 pidForeground.delete(pid);
156 computeUidForegroundL(uid);
157 }
158 }
159 }
160 };
161
162 private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
163 @Override
164 public void onReceive(Context context, Intent intent) {
165 synchronized (mRulesLock) {
166 // screen-related broadcasts are protected by system, no need
167 // for permissions check.
168 updateScreenOn();
169 }
170 }
171 };
172
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700173 @Override
174 public void setUidPolicy(int uid, int policy) {
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700175 // TODO: create permission for modifying data policy
Jeff Sharkey75279902011-05-24 18:39:45 -0700176 mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
Jeff Sharkeya4620792011-05-20 15:29:23 -0700177
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700178 final int oldPolicy;
Jeff Sharkeya4620792011-05-20 15:29:23 -0700179 synchronized (mRulesLock) {
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700180 oldPolicy = getUidPolicy(uid);
Jeff Sharkeya4620792011-05-20 15:29:23 -0700181 mUidPolicy.put(uid, policy);
Jeff Sharkey9599cc52011-05-22 14:59:31 -0700182 updateRulesForUidL(uid);
Jeff Sharkeya4620792011-05-20 15:29:23 -0700183 }
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700184
185 // TODO: consider dispatching BACKGROUND_DATA_SETTING broadcast
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700186 }
187
188 @Override
189 public int getUidPolicy(int uid) {
Jeff Sharkeya4620792011-05-20 15:29:23 -0700190 synchronized (mRulesLock) {
191 return mUidPolicy.get(uid, POLICY_NONE);
192 }
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700193 }
194
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700195 @Override
196 public void registerListener(INetworkPolicyListener listener) {
197 mListeners.register(listener);
198
199 synchronized (mRulesLock) {
200 // dispatch any existing rules to new listeners
201 final int size = mUidRules.size();
202 for (int i = 0; i < size; i++) {
203 final int uid = mUidRules.keyAt(i);
204 final int uidRules = mUidRules.valueAt(i);
205 if (uidRules != RULE_ALLOW_ALL) {
206 try {
207 listener.onRulesChanged(uid, uidRules);
208 } catch (RemoteException e) {
209 }
210 }
211 }
212 }
213 }
214
215 @Override
216 public void unregisterListener(INetworkPolicyListener listener) {
217 mListeners.unregister(listener);
218 }
219
Jeff Sharkey1b861272011-05-22 00:34:52 -0700220 @Override
221 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
Jeff Sharkey75279902011-05-24 18:39:45 -0700222 mContext.enforceCallingOrSelfPermission(DUMP, TAG);
Jeff Sharkey1b861272011-05-22 00:34:52 -0700223
224 synchronized (mRulesLock) {
225 fout.println("Policy status for known UIDs:");
226
227 final SparseBooleanArray knownUids = new SparseBooleanArray();
228 collectKeys(mUidPolicy, knownUids);
229 collectKeys(mUidForeground, knownUids);
230 collectKeys(mUidRules, knownUids);
231
232 final int size = knownUids.size();
233 for (int i = 0; i < size; i++) {
234 final int uid = knownUids.keyAt(i);
235 fout.print(" UID=");
236 fout.print(uid);
237
238 fout.print(" policy=");
239 final int policyIndex = mUidPolicy.indexOfKey(uid);
240 if (policyIndex < 0) {
241 fout.print("UNKNOWN");
242 } else {
243 dumpPolicy(fout, mUidPolicy.valueAt(policyIndex));
244 }
245
246 fout.print(" foreground=");
247 final int foregroundIndex = mUidPidForeground.indexOfKey(uid);
248 if (foregroundIndex < 0) {
249 fout.print("UNKNOWN");
250 } else {
251 dumpSparseBooleanArray(fout, mUidPidForeground.valueAt(foregroundIndex));
252 }
253
254 fout.print(" rules=");
255 final int rulesIndex = mUidRules.indexOfKey(uid);
256 if (rulesIndex < 0) {
257 fout.print("UNKNOWN");
258 } else {
259 dumpRules(fout, mUidRules.valueAt(rulesIndex));
260 }
261
262 fout.println();
263 }
264 }
265 }
Jeff Sharkey9599cc52011-05-22 14:59:31 -0700266
267 @Override
268 public boolean isUidForeground(int uid) {
269 synchronized (mRulesLock) {
270 // only really in foreground when screen is also on
271 return mUidForeground.get(uid, false) && mScreenOn;
272 }
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700273 }
274
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700275 /**
276 * Foreground for PID changed; recompute foreground at UID level. If
Jeff Sharkeya4620792011-05-20 15:29:23 -0700277 * changed, will trigger {@link #updateRulesForUidL(int)}.
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700278 */
Jeff Sharkeya4620792011-05-20 15:29:23 -0700279 private void computeUidForegroundL(int uid) {
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700280 final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
281
282 // current pid is dropping foreground; examine other pids
283 boolean uidForeground = false;
284 final int size = pidForeground.size();
285 for (int i = 0; i < size; i++) {
286 if (pidForeground.valueAt(i)) {
287 uidForeground = true;
288 break;
289 }
290 }
291
292 final boolean oldUidForeground = mUidForeground.get(uid, false);
293 if (oldUidForeground != uidForeground) {
294 // foreground changed, push updated rules
295 mUidForeground.put(uid, uidForeground);
Jeff Sharkeya4620792011-05-20 15:29:23 -0700296 updateRulesForUidL(uid);
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700297 }
298 }
299
Jeff Sharkeya4620792011-05-20 15:29:23 -0700300 private void updateScreenOn() {
301 synchronized (mRulesLock) {
302 try {
303 mScreenOn = mPowerManager.isScreenOn();
304 } catch (RemoteException e) {
305 }
306 updateRulesForScreenL();
307 }
308 }
309
310 /**
311 * Update rules that might be changed by {@link #mScreenOn} value.
312 */
313 private void updateRulesForScreenL() {
314 // only update rules for anyone with foreground activities
315 final int size = mUidForeground.size();
316 for (int i = 0; i < size; i++) {
317 if (mUidForeground.valueAt(i)) {
318 final int uid = mUidForeground.keyAt(i);
319 updateRulesForUidL(uid);
320 }
321 }
322 }
323
324 private void updateRulesForUidL(int uid) {
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700325 final int uidPolicy = getUidPolicy(uid);
Jeff Sharkey9599cc52011-05-22 14:59:31 -0700326 final boolean uidForeground = isUidForeground(uid);
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700327
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700328 // derive active rules based on policy and active state
329 int uidRules = RULE_ALLOW_ALL;
330 if (!uidForeground && (uidPolicy & POLICY_REJECT_PAID_BACKGROUND) != 0) {
331 // uid in background, and policy says to block paid data
332 uidRules = RULE_REJECT_PAID;
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700333 }
334
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700335 // TODO: only dispatch when rules actually change
336
337 // record rule locally to dispatch to new listeners
338 mUidRules.put(uid, uidRules);
339
340 // dispatch changed rule to existing listeners
341 final int length = mListeners.beginBroadcast();
342 for (int i = 0; i < length; i++) {
343 final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
344 if (listener != null) {
345 try {
346 listener.onRulesChanged(uid, uidRules);
347 } catch (RemoteException e) {
348 }
349 }
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700350 }
Jeff Sharkeyc006f1a2011-05-19 17:12:49 -0700351 mListeners.finishBroadcast();
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700352 }
353
Jeff Sharkeya4620792011-05-20 15:29:23 -0700354 private static <T> T checkNotNull(T value, String message) {
355 if (value == null) {
356 throw new NullPointerException(message);
357 }
358 return value;
359 }
Jeff Sharkey75279902011-05-24 18:39:45 -0700360
Jeff Sharkey1b861272011-05-22 00:34:52 -0700361 private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
362 final int size = source.size();
363 for (int i = 0; i < size; i++) {
364 target.put(source.keyAt(i), true);
365 }
366 }
367
368 private static void collectKeys(SparseBooleanArray source, SparseBooleanArray target) {
369 final int size = source.size();
370 for (int i = 0; i < size; i++) {
371 target.put(source.keyAt(i), true);
372 }
373 }
374
375 private static void dumpSparseBooleanArray(PrintWriter fout, SparseBooleanArray value) {
376 fout.print("[");
377 final int size = value.size();
378 for (int i = 0; i < size; i++) {
379 fout.print(value.keyAt(i) + "=" + value.valueAt(i));
380 if (i < size - 1) fout.print(",");
381 }
382 fout.print("]");
383 }
Jeff Sharkeyd5cdd592011-05-03 20:27:17 -0700384}