NetworkPolicyManagerService.java revision 1b861278a2051f53ce7955fb7992fa536dc975d9
1/* 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 19import static android.Manifest.permission.DUMP; 20import static android.Manifest.permission.MANAGE_APP_TOKENS; 21import static android.Manifest.permission.UPDATE_DEVICE_STATS; 22import static android.net.NetworkPolicyManager.POLICY_NONE; 23import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID_BACKGROUND; 24import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; 25import static android.net.NetworkPolicyManager.RULE_REJECT_PAID; 26import static android.net.NetworkPolicyManager.dumpPolicy; 27import static android.net.NetworkPolicyManager.dumpRules; 28 29import android.app.IActivityManager; 30import android.app.IProcessObserver; 31import android.content.BroadcastReceiver; 32import android.content.Context; 33import android.content.Intent; 34import android.content.IntentFilter; 35import android.net.ConnectivityManager; 36import android.net.INetworkPolicyListener; 37import android.net.INetworkPolicyManager; 38import android.os.IPowerManager; 39import android.os.RemoteCallbackList; 40import android.os.RemoteException; 41import android.util.Log; 42import android.util.Slog; 43import android.util.SparseArray; 44import android.util.SparseBooleanArray; 45import android.util.SparseIntArray; 46 47import java.io.FileDescriptor; 48import java.io.PrintWriter; 49 50/** 51 * Service that maintains low-level network policy rules and collects usage 52 * statistics to drive those rules. 53 * <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. 57 */ 58public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 59 private static final String TAG = "NetworkPolicy"; 60 private static final boolean LOGD = true; 61 62 private Context mContext; 63 private IActivityManager mActivityManager; 64 private IPowerManager mPowerManager; 65 66 private Object mRulesLock = new Object(); 67 68 private boolean mScreenOn; 69 70 /** Current network policy for each UID. */ 71 private SparseIntArray mUidPolicy = new SparseIntArray(); 72 /** Current derived network rules for each UID. */ 73 private SparseIntArray mUidRules = new SparseIntArray(); 74 75 /** Foreground at both UID and PID granularity. */ 76 private SparseBooleanArray mUidForeground = new SparseBooleanArray(); 77 private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray< 78 SparseBooleanArray>(); 79 80 private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList< 81 INetworkPolicyListener>(); 82 83 // TODO: periodically poll network stats and write to disk 84 // TODO: save/restore policy information from disk 85 86 // TODO: keep whitelist of system-critical services that should never have 87 // rules enforced, such as system, phone, and radio UIDs. 88 89 public NetworkPolicyManagerService( 90 Context context, IActivityManager activityManager, IPowerManager powerManager) { 91 mContext = checkNotNull(context, "missing context"); 92 mActivityManager = checkNotNull(activityManager, "missing activityManager"); 93 mPowerManager = checkNotNull(powerManager, "missing powerManager"); 94 } 95 96 public void systemReady() { 97 // TODO: read current policy+stats from disk and generate NMS rules 98 99 updateScreenOn(); 100 101 try { 102 mActivityManager.registerProcessObserver(mProcessObserver); 103 } catch (RemoteException e) { 104 // ouch, no foregroundActivities updates means some processes may 105 // never get network access. 106 Slog.e(TAG, "unable to register IProcessObserver", e); 107 } 108 109 // TODO: traverse existing processes to know foreground state, or have 110 // activitymanager dispatch current state when new observer attached. 111 112 final IntentFilter screenFilter = new IntentFilter(); 113 screenFilter.addAction(Intent.ACTION_SCREEN_ON); 114 screenFilter.addAction(Intent.ACTION_SCREEN_OFF); 115 mContext.registerReceiver(mScreenReceiver, screenFilter); 116 117 final IntentFilter shutdownFilter = new IntentFilter(); 118 shutdownFilter.addAction(Intent.ACTION_SHUTDOWN); 119 mContext.registerReceiver(mShutdownReceiver, shutdownFilter); 120 121 } 122 123 private IProcessObserver mProcessObserver = new IProcessObserver.Stub() { 124 @Override 125 public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) { 126 // only someone like AMS should only be calling us 127 mContext.enforceCallingOrSelfPermission( 128 MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission"); 129 130 synchronized (mRulesLock) { 131 // because a uid can have multiple pids running inside, we need to 132 // remember all pid states and summarize foreground at uid level. 133 134 // record foreground for this specific pid 135 SparseBooleanArray pidForeground = mUidPidForeground.get(uid); 136 if (pidForeground == null) { 137 pidForeground = new SparseBooleanArray(2); 138 mUidPidForeground.put(uid, pidForeground); 139 } 140 pidForeground.put(pid, foregroundActivities); 141 computeUidForegroundL(uid); 142 } 143 } 144 145 @Override 146 public void onProcessDied(int pid, int uid) { 147 // only someone like AMS should only be calling us 148 mContext.enforceCallingOrSelfPermission( 149 MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission"); 150 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 173 private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() { 174 @Override 175 public void onReceive(Context context, Intent intent) { 176 // TODO: persist any pending stats during clean shutdown 177 Log.d(TAG, "persisting stats"); 178 } 179 }; 180 181 @Override 182 public void setUidPolicy(int uid, int policy) { 183 // TODO: create permission for modifying data policy 184 mContext.enforceCallingOrSelfPermission( 185 UPDATE_DEVICE_STATS, "requires UPDATE_DEVICE_STATS permission"); 186 187 final int oldPolicy; 188 synchronized (mRulesLock) { 189 oldPolicy = getUidPolicy(uid); 190 mUidPolicy.put(uid, policy); 191 } 192 193 // TODO: consider dispatching BACKGROUND_DATA_SETTING broadcast 194 } 195 196 @Override 197 public int getUidPolicy(int uid) { 198 synchronized (mRulesLock) { 199 return mUidPolicy.get(uid, POLICY_NONE); 200 } 201 } 202 203 @Override 204 public void registerListener(INetworkPolicyListener listener) { 205 mListeners.register(listener); 206 207 synchronized (mRulesLock) { 208 // dispatch any existing rules to new listeners 209 final int size = mUidRules.size(); 210 for (int i = 0; i < size; i++) { 211 final int uid = mUidRules.keyAt(i); 212 final int uidRules = mUidRules.valueAt(i); 213 if (uidRules != RULE_ALLOW_ALL) { 214 try { 215 listener.onRulesChanged(uid, uidRules); 216 } catch (RemoteException e) { 217 } 218 } 219 } 220 } 221 } 222 223 @Override 224 public void unregisterListener(INetworkPolicyListener listener) { 225 mListeners.unregister(listener); 226 } 227 228 @Override 229 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 230 mContext.enforceCallingOrSelfPermission(DUMP, "requires DUMP permission"); 231 232 synchronized (mRulesLock) { 233 fout.println("Policy status for known UIDs:"); 234 235 final SparseBooleanArray knownUids = new SparseBooleanArray(); 236 collectKeys(mUidPolicy, knownUids); 237 collectKeys(mUidForeground, knownUids); 238 collectKeys(mUidRules, knownUids); 239 240 final int size = knownUids.size(); 241 for (int i = 0; i < size; i++) { 242 final int uid = knownUids.keyAt(i); 243 fout.print(" UID="); 244 fout.print(uid); 245 246 fout.print(" policy="); 247 final int policyIndex = mUidPolicy.indexOfKey(uid); 248 if (policyIndex < 0) { 249 fout.print("UNKNOWN"); 250 } else { 251 dumpPolicy(fout, mUidPolicy.valueAt(policyIndex)); 252 } 253 254 fout.print(" foreground="); 255 final int foregroundIndex = mUidPidForeground.indexOfKey(uid); 256 if (foregroundIndex < 0) { 257 fout.print("UNKNOWN"); 258 } else { 259 dumpSparseBooleanArray(fout, mUidPidForeground.valueAt(foregroundIndex)); 260 } 261 262 fout.print(" rules="); 263 final int rulesIndex = mUidRules.indexOfKey(uid); 264 if (rulesIndex < 0) { 265 fout.print("UNKNOWN"); 266 } else { 267 dumpRules(fout, mUidRules.valueAt(rulesIndex)); 268 } 269 270 fout.println(); 271 } 272 } 273 } 274 275 private boolean isUidForegroundL(int uid) { 276 // only really in foreground when screen is also on 277 return mUidForeground.get(uid, false) && mScreenOn; 278 } 279 280 /** 281 * Foreground for PID changed; recompute foreground at UID level. If 282 * changed, will trigger {@link #updateRulesForUidL(int)}. 283 */ 284 private void computeUidForegroundL(int uid) { 285 final SparseBooleanArray pidForeground = mUidPidForeground.get(uid); 286 287 // current pid is dropping foreground; examine other pids 288 boolean uidForeground = false; 289 final int size = pidForeground.size(); 290 for (int i = 0; i < size; i++) { 291 if (pidForeground.valueAt(i)) { 292 uidForeground = true; 293 break; 294 } 295 } 296 297 final boolean oldUidForeground = mUidForeground.get(uid, false); 298 if (oldUidForeground != uidForeground) { 299 // foreground changed, push updated rules 300 mUidForeground.put(uid, uidForeground); 301 updateRulesForUidL(uid); 302 } 303 } 304 305 private void updateScreenOn() { 306 synchronized (mRulesLock) { 307 try { 308 mScreenOn = mPowerManager.isScreenOn(); 309 } catch (RemoteException e) { 310 } 311 updateRulesForScreenL(); 312 } 313 } 314 315 /** 316 * Update rules that might be changed by {@link #mScreenOn} value. 317 */ 318 private void updateRulesForScreenL() { 319 // only update rules for anyone with foreground activities 320 final int size = mUidForeground.size(); 321 for (int i = 0; i < size; i++) { 322 if (mUidForeground.valueAt(i)) { 323 final int uid = mUidForeground.keyAt(i); 324 updateRulesForUidL(uid); 325 } 326 } 327 } 328 329 private void updateRulesForUidL(int uid) { 330 final int uidPolicy = getUidPolicy(uid); 331 final boolean uidForeground = isUidForegroundL(uid); 332 333 // derive active rules based on policy and active state 334 int uidRules = RULE_ALLOW_ALL; 335 if (!uidForeground && (uidPolicy & POLICY_REJECT_PAID_BACKGROUND) != 0) { 336 // uid in background, and policy says to block paid data 337 uidRules = RULE_REJECT_PAID; 338 } 339 340 // TODO: only dispatch when rules actually change 341 342 // record rule locally to dispatch to new listeners 343 mUidRules.put(uid, uidRules); 344 345 // dispatch changed rule to existing listeners 346 final int length = mListeners.beginBroadcast(); 347 for (int i = 0; i < length; i++) { 348 final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); 349 if (listener != null) { 350 try { 351 listener.onRulesChanged(uid, uidRules); 352 } catch (RemoteException e) { 353 } 354 } 355 } 356 mListeners.finishBroadcast(); 357 } 358 359 private static <T> T checkNotNull(T value, String message) { 360 if (value == null) { 361 throw new NullPointerException(message); 362 } 363 return value; 364 } 365 366 private static void collectKeys(SparseIntArray source, SparseBooleanArray target) { 367 final int size = source.size(); 368 for (int i = 0; i < size; i++) { 369 target.put(source.keyAt(i), true); 370 } 371 } 372 373 private static void collectKeys(SparseBooleanArray source, SparseBooleanArray target) { 374 final int size = source.size(); 375 for (int i = 0; i < size; i++) { 376 target.put(source.keyAt(i), true); 377 } 378 } 379 380 private static void dumpSparseBooleanArray(PrintWriter fout, SparseBooleanArray value) { 381 fout.print("["); 382 final int size = value.size(); 383 for (int i = 0; i < size; i++) { 384 fout.print(value.keyAt(i) + "=" + value.valueAt(i)); 385 if (i < size - 1) fout.print(","); 386 } 387 fout.print("]"); 388 } 389} 390