NetworkPolicyManagerService.java revision 50fd36d7c38c40b087c8f3e3172478abe0c051d9
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.CONNECTIVITY_INTERNAL; 20import static android.Manifest.permission.DUMP; 21import static android.Manifest.permission.MANAGE_APP_TOKENS; 22import static android.Manifest.permission.MANAGE_NETWORK_POLICY; 23import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; 24import static android.Manifest.permission.READ_PHONE_STATE; 25import static android.content.Intent.ACTION_UID_REMOVED; 26import static android.content.Intent.EXTRA_UID; 27import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; 28import static android.net.ConnectivityManager.TYPE_MOBILE; 29import static android.net.NetworkPolicy.LIMIT_DISABLED; 30import static android.net.NetworkPolicy.WARNING_DISABLED; 31import static android.net.NetworkPolicyManager.ACTION_DATA_USAGE_LIMIT; 32import static android.net.NetworkPolicyManager.ACTION_DATA_USAGE_WARNING; 33import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE; 34import static android.net.NetworkPolicyManager.POLICY_NONE; 35import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; 36import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; 37import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; 38import static android.net.NetworkPolicyManager.computeLastCycleBoundary; 39import static android.net.NetworkPolicyManager.dumpPolicy; 40import static android.net.NetworkPolicyManager.dumpRules; 41import static android.net.NetworkPolicyManager.isUidValidForPolicy; 42import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER; 43import static android.net.NetworkTemplate.MATCH_MOBILE_4G; 44import static android.net.NetworkTemplate.MATCH_MOBILE_ALL; 45import static android.text.format.DateUtils.DAY_IN_MILLIS; 46import static com.android.internal.util.Preconditions.checkNotNull; 47import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED; 48import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 49import static org.xmlpull.v1.XmlPullParser.START_TAG; 50 51import android.app.IActivityManager; 52import android.app.INotificationManager; 53import android.app.IProcessObserver; 54import android.app.Notification; 55import android.app.PendingIntent; 56import android.content.BroadcastReceiver; 57import android.content.Context; 58import android.content.Intent; 59import android.content.IntentFilter; 60import android.content.res.Resources; 61import android.net.ConnectivityManager; 62import android.net.IConnectivityManager; 63import android.net.INetworkPolicyListener; 64import android.net.INetworkPolicyManager; 65import android.net.INetworkStatsService; 66import android.net.NetworkIdentity; 67import android.net.NetworkPolicy; 68import android.net.NetworkState; 69import android.net.NetworkStats; 70import android.net.NetworkTemplate; 71import android.os.Environment; 72import android.os.Handler; 73import android.os.HandlerThread; 74import android.os.INetworkManagementService; 75import android.os.IPowerManager; 76import android.os.Message; 77import android.os.RemoteCallbackList; 78import android.os.RemoteException; 79import android.telephony.TelephonyManager; 80import android.text.format.Formatter; 81import android.text.format.Time; 82import android.util.NtpTrustedTime; 83import android.util.Slog; 84import android.util.SparseArray; 85import android.util.SparseBooleanArray; 86import android.util.SparseIntArray; 87import android.util.TrustedTime; 88import android.util.Xml; 89 90import com.android.internal.R; 91import com.android.internal.os.AtomicFile; 92import com.android.internal.util.FastXmlSerializer; 93import com.google.android.collect.Lists; 94import com.google.android.collect.Maps; 95import com.google.android.collect.Sets; 96 97import org.xmlpull.v1.XmlPullParser; 98import org.xmlpull.v1.XmlPullParserException; 99import org.xmlpull.v1.XmlSerializer; 100 101import java.io.File; 102import java.io.FileDescriptor; 103import java.io.FileInputStream; 104import java.io.FileNotFoundException; 105import java.io.FileOutputStream; 106import java.io.IOException; 107import java.io.PrintWriter; 108import java.net.ProtocolException; 109import java.util.ArrayList; 110import java.util.Arrays; 111import java.util.HashMap; 112import java.util.HashSet; 113 114import libcore.io.IoUtils; 115 116/** 117 * Service that maintains low-level network policy rules and collects usage 118 * statistics to drive those rules. 119 * <p> 120 * Derives active rules by combining a given policy with other system status, 121 * and delivers to listeners, such as {@link ConnectivityManager}, for 122 * enforcement. 123 */ 124public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 125 private static final String TAG = "NetworkPolicy"; 126 private static final boolean LOGD = true; 127 private static final boolean LOGV = false; 128 129 private static final int VERSION_CURRENT = 1; 130 131 private static final long KB_IN_BYTES = 1024; 132 private static final long MB_IN_BYTES = KB_IN_BYTES * 1024; 133 private static final long GB_IN_BYTES = MB_IN_BYTES * 1024; 134 135 private static final int TYPE_WARNING = 0x1; 136 private static final int TYPE_LIMIT = 0x2; 137 138 private static final String TAG_POLICY_LIST = "policy-list"; 139 private static final String TAG_NETWORK_POLICY = "network-policy"; 140 private static final String TAG_UID_POLICY = "uid-policy"; 141 142 private static final String ATTR_VERSION = "version"; 143 private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate"; 144 private static final String ATTR_SUBSCRIBER_ID = "subscriberId"; 145 private static final String ATTR_CYCLE_DAY = "cycleDay"; 146 private static final String ATTR_WARNING_BYTES = "warningBytes"; 147 private static final String ATTR_LIMIT_BYTES = "limitBytes"; 148 private static final String ATTR_UID = "uid"; 149 private static final String ATTR_POLICY = "policy"; 150 151 private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS; 152 153 private static final int MSG_RULES_CHANGED = 0x1; 154 private static final int MSG_METERED_IFACES_CHANGED = 0x2; 155 156 private final Context mContext; 157 private final IActivityManager mActivityManager; 158 private final IPowerManager mPowerManager; 159 private final INetworkStatsService mNetworkStats; 160 private final INetworkManagementService mNetworkManagement; 161 private final TrustedTime mTime; 162 163 private IConnectivityManager mConnManager; 164 private INotificationManager mNotifManager; 165 166 private final Object mRulesLock = new Object(); 167 168 private boolean mScreenOn; 169 170 /** Current policy for network templates. */ 171 private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList(); 172 173 /** Current policy for each UID. */ 174 private SparseIntArray mUidPolicy = new SparseIntArray(); 175 /** Current derived network rules for each UID. */ 176 private SparseIntArray mUidRules = new SparseIntArray(); 177 178 /** Set of ifaces that are metered. */ 179 private HashSet<String> mMeteredIfaces = Sets.newHashSet(); 180 181 /** Foreground at both UID and PID granularity. */ 182 private SparseBooleanArray mUidForeground = new SparseBooleanArray(); 183 private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray< 184 SparseBooleanArray>(); 185 186 private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList< 187 INetworkPolicyListener>(); 188 189 private final HandlerThread mHandlerThread; 190 private final Handler mHandler; 191 192 private final AtomicFile mPolicyFile; 193 194 // TODO: keep whitelist of system-critical services that should never have 195 // rules enforced, such as system, phone, and radio UIDs. 196 197 public NetworkPolicyManagerService(Context context, IActivityManager activityManager, 198 IPowerManager powerManager, INetworkStatsService networkStats, 199 INetworkManagementService networkManagement) { 200 // TODO: move to using cached NtpTrustedTime 201 this(context, activityManager, powerManager, networkStats, 202 networkManagement, new NtpTrustedTime(), 203 getSystemDir()); 204 } 205 206 private static File getSystemDir() { 207 return new File(Environment.getDataDirectory(), "system"); 208 } 209 210 public NetworkPolicyManagerService(Context context, IActivityManager activityManager, 211 IPowerManager powerManager, INetworkStatsService networkStats, 212 INetworkManagementService networkManagement, 213 TrustedTime time, File systemDir) { 214 mContext = checkNotNull(context, "missing context"); 215 mActivityManager = checkNotNull(activityManager, "missing activityManager"); 216 mPowerManager = checkNotNull(powerManager, "missing powerManager"); 217 mNetworkStats = checkNotNull(networkStats, "missing networkStats"); 218 mNetworkManagement = checkNotNull(networkManagement, "missing networkManagementService"); 219 mTime = checkNotNull(time, "missing TrustedTime"); 220 221 mHandlerThread = new HandlerThread(TAG); 222 mHandlerThread.start(); 223 mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback); 224 225 mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml")); 226 } 227 228 public void bindConnectivityManager(IConnectivityManager connManager) { 229 mConnManager = checkNotNull(connManager, "missing IConnectivityManager"); 230 } 231 232 public void bindNotificationManager(INotificationManager notifManager) { 233 mNotifManager = checkNotNull(notifManager, "missing INotificationManager"); 234 } 235 236 public void systemReady() { 237 synchronized (mRulesLock) { 238 // read policy from disk 239 readPolicyLocked(); 240 updateNotificationsLocked(); 241 } 242 243 updateScreenOn(); 244 245 try { 246 mActivityManager.registerProcessObserver(mProcessObserver); 247 } catch (RemoteException e) { 248 // ouch, no foregroundActivities updates means some processes may 249 // never get network access. 250 Slog.e(TAG, "unable to register IProcessObserver", e); 251 } 252 253 // TODO: traverse existing processes to know foreground state, or have 254 // activitymanager dispatch current state when new observer attached. 255 256 final IntentFilter screenFilter = new IntentFilter(); 257 screenFilter.addAction(Intent.ACTION_SCREEN_ON); 258 screenFilter.addAction(Intent.ACTION_SCREEN_OFF); 259 mContext.registerReceiver(mScreenReceiver, screenFilter); 260 261 // watch for network interfaces to be claimed 262 final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION); 263 mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); 264 265 // listen for uid removal to clean policy 266 final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED); 267 mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler); 268 269 // listen for warning polling events; currently dispatched by 270 final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED); 271 mContext.registerReceiver( 272 mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler); 273 274 } 275 276 private IProcessObserver mProcessObserver = new IProcessObserver.Stub() { 277 @Override 278 public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) { 279 // only someone like AMS should only be calling us 280 mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG); 281 282 synchronized (mRulesLock) { 283 // because a uid can have multiple pids running inside, we need to 284 // remember all pid states and summarize foreground at uid level. 285 286 // record foreground for this specific pid 287 SparseBooleanArray pidForeground = mUidPidForeground.get(uid); 288 if (pidForeground == null) { 289 pidForeground = new SparseBooleanArray(2); 290 mUidPidForeground.put(uid, pidForeground); 291 } 292 pidForeground.put(pid, foregroundActivities); 293 computeUidForegroundLocked(uid); 294 } 295 } 296 297 @Override 298 public void onProcessDied(int pid, int uid) { 299 // only someone like AMS should only be calling us 300 mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG); 301 302 synchronized (mRulesLock) { 303 // clear records and recompute, when they exist 304 final SparseBooleanArray pidForeground = mUidPidForeground.get(uid); 305 if (pidForeground != null) { 306 pidForeground.delete(pid); 307 computeUidForegroundLocked(uid); 308 } 309 } 310 } 311 }; 312 313 private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() { 314 @Override 315 public void onReceive(Context context, Intent intent) { 316 synchronized (mRulesLock) { 317 // screen-related broadcasts are protected by system, no need 318 // for permissions check. 319 updateScreenOn(); 320 } 321 } 322 }; 323 324 private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() { 325 @Override 326 public void onReceive(Context context, Intent intent) { 327 // on background handler thread, and UID_REMOVED is protected 328 // broadcast. 329 final int uid = intent.getIntExtra(EXTRA_UID, 0); 330 synchronized (mRulesLock) { 331 // remove any policy and update rules to clean up 332 mUidPolicy.delete(uid); 333 updateRulesForUidLocked(uid); 334 writePolicyLocked(); 335 } 336 } 337 }; 338 339 /** 340 * Receiver that watches for {@link INetworkStatsService} updates, which we 341 * use to check against {@link NetworkPolicy#warningBytes}. 342 */ 343 private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() { 344 @Override 345 public void onReceive(Context context, Intent intent) { 346 // on background handler thread, and verified 347 // READ_NETWORK_USAGE_HISTORY permission above. 348 349 synchronized (mRulesLock) { 350 updateNotificationsLocked(); 351 } 352 } 353 }; 354 355 /** 356 * Check {@link NetworkPolicy} against current {@link INetworkStatsService} 357 * to show visible notifications as needed. 358 */ 359 private void updateNotificationsLocked() { 360 if (LOGV) Slog.v(TAG, "updateNotificationsLocked()"); 361 362 // try refreshing time source when stale 363 if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) { 364 mTime.forceRefresh(); 365 } 366 367 final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() 368 : System.currentTimeMillis(); 369 370 // TODO: when switching to kernel notifications, compute next future 371 // cycle boundary to recompute notifications. 372 373 // examine stats for each policy defined 374 for (NetworkPolicy policy : mNetworkPolicy) { 375 final long start = computeLastCycleBoundary(currentTime, policy); 376 final long end = currentTime; 377 378 final long total; 379 try { 380 final NetworkStats stats = mNetworkStats.getSummaryForNetwork( 381 policy.template, start, end); 382 total = stats.rx[0] + stats.tx[0]; 383 } catch (RemoteException e) { 384 Slog.w(TAG, "problem reading summary for template " + policy.template); 385 continue; 386 } 387 388 if (policy.limitBytes != LIMIT_DISABLED && total >= policy.limitBytes) { 389 cancelNotification(policy, TYPE_WARNING); 390 enqueueNotification(policy, TYPE_LIMIT); 391 } else { 392 cancelNotification(policy, TYPE_LIMIT); 393 394 if (policy.warningBytes != WARNING_DISABLED && total >= policy.warningBytes) { 395 enqueueNotification(policy, TYPE_WARNING); 396 } else { 397 cancelNotification(policy, TYPE_WARNING); 398 } 399 } 400 } 401 } 402 403 /** 404 * Build unique tag that identifies an active {@link NetworkPolicy} 405 * notification of a specific type, like {@link #TYPE_LIMIT}. 406 */ 407 private String buildNotificationTag(NetworkPolicy policy, int type) { 408 return TAG + ":" + policy.template.hashCode() + ":" + type; 409 } 410 411 /** 412 * Show notification for combined {@link NetworkPolicy} and specific type, 413 * like {@link #TYPE_LIMIT}. Okay to call multiple times. 414 */ 415 private void enqueueNotification(NetworkPolicy policy, int type) { 416 final String tag = buildNotificationTag(policy, type); 417 final Notification.Builder builder = new Notification.Builder(mContext); 418 builder.setOnlyAlertOnce(true); 419 builder.setOngoing(true); 420 421 final Resources res = mContext.getResources(); 422 switch (type) { 423 case TYPE_WARNING: { 424 final String title = res.getString(R.string.data_usage_warning_title); 425 final String body = res.getString(R.string.data_usage_warning_body, 426 Formatter.formatFileSize(mContext, policy.warningBytes)); 427 428 builder.setSmallIcon(R.drawable.ic_menu_info_details); 429 builder.setTicker(title); 430 builder.setContentTitle(title); 431 builder.setContentText(body); 432 433 final Intent intent = new Intent(ACTION_DATA_USAGE_WARNING); 434 intent.addCategory(Intent.CATEGORY_DEFAULT); 435 intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.template.getMatchRule()); 436 builder.setContentIntent(PendingIntent.getActivity( 437 mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); 438 break; 439 } 440 case TYPE_LIMIT: { 441 final String title; 442 final String body = res.getString(R.string.data_usage_limit_body); 443 switch (policy.template.getMatchRule()) { 444 case MATCH_MOBILE_3G_LOWER: 445 title = res.getString(R.string.data_usage_3g_limit_title); 446 break; 447 case MATCH_MOBILE_4G: 448 title = res.getString(R.string.data_usage_4g_limit_title); 449 break; 450 default: 451 title = res.getString(R.string.data_usage_mobile_limit_title); 452 break; 453 } 454 455 builder.setSmallIcon(com.android.internal.R.drawable.ic_menu_block); 456 builder.setTicker(title); 457 builder.setContentTitle(title); 458 builder.setContentText(body); 459 460 final Intent intent = new Intent(ACTION_DATA_USAGE_LIMIT); 461 intent.addCategory(Intent.CATEGORY_DEFAULT); 462 intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.template.getMatchRule()); 463 builder.setContentIntent(PendingIntent.getActivity( 464 mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); 465 break; 466 } 467 } 468 469 // TODO: move to NotificationManager once we can mock it 470 try { 471 final String packageName = mContext.getPackageName(); 472 final int[] idReceived = new int[1]; 473 mNotifManager.enqueueNotificationWithTag( 474 packageName, tag, 0x0, builder.getNotification(), idReceived); 475 } catch (RemoteException e) { 476 Slog.w(TAG, "problem during enqueueNotification: " + e); 477 } 478 } 479 480 /** 481 * Cancel any notification for combined {@link NetworkPolicy} and specific 482 * type, like {@link #TYPE_LIMIT}. 483 */ 484 private void cancelNotification(NetworkPolicy policy, int type) { 485 final String tag = buildNotificationTag(policy, type); 486 487 // TODO: move to NotificationManager once we can mock it 488 try { 489 final String packageName = mContext.getPackageName(); 490 mNotifManager.cancelNotificationWithTag(packageName, tag, 0x0); 491 } catch (RemoteException e) { 492 Slog.w(TAG, "problem during enqueueNotification: " + e); 493 } 494 } 495 496 /** 497 * Receiver that watches for {@link IConnectivityManager} to claim network 498 * interfaces. Used to apply {@link NetworkPolicy} to matching networks. 499 */ 500 private BroadcastReceiver mConnReceiver = new BroadcastReceiver() { 501 @Override 502 public void onReceive(Context context, Intent intent) { 503 // on background handler thread, and verified CONNECTIVITY_INTERNAL 504 // permission above. 505 synchronized (mRulesLock) { 506 ensureActiveMobilePolicyLocked(); 507 updateIfacesLocked(); 508 } 509 } 510 }; 511 512 /** 513 * Examine all connected {@link NetworkState}, looking for 514 * {@link NetworkPolicy} that need to be enforced. When matches found, set 515 * remaining quota based on usage cycle and historical stats. 516 */ 517 private void updateIfacesLocked() { 518 if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); 519 520 final NetworkState[] states; 521 try { 522 states = mConnManager.getAllNetworkState(); 523 } catch (RemoteException e) { 524 Slog.w(TAG, "problem reading network state"); 525 return; 526 } 527 528 // first, derive identity for all connected networks, which can be used 529 // to match against templates. 530 final HashMap<NetworkIdentity, String> networks = Maps.newHashMap(); 531 for (NetworkState state : states) { 532 // stash identity and iface away for later use 533 if (state.networkInfo.isConnected()) { 534 final String iface = state.linkProperties.getInterfaceName(); 535 final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state); 536 networks.put(ident, iface); 537 } 538 } 539 540 // build list of rules and ifaces to enforce them against 541 final HashMap<NetworkPolicy, String[]> rules = Maps.newHashMap(); 542 final ArrayList<String> ifaceList = Lists.newArrayList(); 543 for (NetworkPolicy policy : mNetworkPolicy) { 544 545 // collect all active ifaces that match this template 546 ifaceList.clear(); 547 for (NetworkIdentity ident : networks.keySet()) { 548 if (policy.template.matches(ident)) { 549 final String iface = networks.get(ident); 550 ifaceList.add(iface); 551 } 552 } 553 554 if (ifaceList.size() > 0) { 555 final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]); 556 rules.put(policy, ifaces); 557 } 558 } 559 560 // try refreshing time source when stale 561 if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) { 562 mTime.forceRefresh(); 563 } 564 565 final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() 566 : System.currentTimeMillis(); 567 568 mMeteredIfaces.clear(); 569 570 // apply each policy that we found ifaces for; compute remaining data 571 // based on current cycle and historical stats, and push to kernel. 572 for (NetworkPolicy policy : rules.keySet()) { 573 final String[] ifaces = rules.get(policy); 574 575 final long start = computeLastCycleBoundary(currentTime, policy); 576 final long end = currentTime; 577 578 final NetworkStats stats; 579 final long total; 580 try { 581 stats = mNetworkStats.getSummaryForNetwork(policy.template, start, end); 582 total = stats.rx[0] + stats.tx[0]; 583 } catch (RemoteException e) { 584 Slog.w(TAG, "problem reading summary for template " + policy.template); 585 continue; 586 } 587 588 if (LOGD) { 589 Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces " 590 + Arrays.toString(ifaces)); 591 } 592 593 // TODO: register for warning notification trigger through NMS 594 595 if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) { 596 // remaining "quota" is based on usage in current cycle 597 final long quota = Math.max(0, policy.limitBytes - total); 598 if (LOGD) { 599 Slog.d(TAG, "Applying quota rules for ifaces=" + Arrays.toString(ifaces) 600 + " LIMIT=" + policy.limitBytes + " TOTAL=" 601 + total + " QUOTA=" + quota); 602 } 603 604 setQuotaOnIfaceList(ifaces, quota); 605 606 for (String iface : ifaces) { 607 mMeteredIfaces.add(iface); 608 } 609 } 610 } 611 612 final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]); 613 mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget(); 614 } 615 616 private void setQuotaOnIfaceList(String[] ifaces, long quota) { 617 try { 618 mNetworkManagement.setInterfaceQuota(ifaces, quota); 619 } catch (IllegalStateException e) { 620 Slog.e(TAG, "IllegalStateException in setQuotaOnIfaceList " + e); 621 } catch (RemoteException e) { 622 Slog.e(TAG, "Remote Exception in setQuotaOnIfaceList " + e); 623 } 624 } 625 626 private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) { 627 // TODO: connect over to NMS 628 // ndc bandwidth app <uid> naughty 629 try { 630 if (LOGD) { 631 Slog.d(TAG, "setUidNetworkRules() with uid=" + uid 632 + ", rejectOnQuotaInterfaces=" + rejectOnQuotaInterfaces); 633 } 634 mNetworkManagement.setUidNetworkRules(uid, rejectOnQuotaInterfaces); 635 } catch (IllegalStateException e) { 636 Slog.e(TAG, "IllegalStateException in setUidNetworkRules " + e); 637 } catch (RemoteException e) { 638 Slog.e(TAG, "Remote Exception in setUidNetworkRules " + e); 639 } 640 } 641 642 /** 643 * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we 644 * have at least a default mobile policy defined. 645 */ 646 private void ensureActiveMobilePolicyLocked() { 647 if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()"); 648 final String subscriberId = getActiveSubscriberId(); 649 final NetworkIdentity probeIdent = new NetworkIdentity( 650 TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, false); 651 652 // examine to see if any policy is defined for active mobile 653 boolean mobileDefined = false; 654 for (NetworkPolicy policy : mNetworkPolicy) { 655 if (policy.template.matches(probeIdent)) { 656 mobileDefined = true; 657 } 658 } 659 660 if (!mobileDefined) { 661 Slog.i(TAG, "no policy for active mobile network; generating default policy"); 662 663 // default mobile policy has combined 4GB warning, and assume usage 664 // cycle starts today today. 665 666 // TODO: move this policy definition to overlay or secure setting 667 final Time time = new Time(Time.TIMEZONE_UTC); 668 time.setToNow(); 669 final int cycleDay = time.monthDay; 670 671 final NetworkTemplate template = new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId); 672 mNetworkPolicy.add( 673 new NetworkPolicy(template, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED)); 674 writePolicyLocked(); 675 } 676 } 677 678 private void readPolicyLocked() { 679 if (LOGV) Slog.v(TAG, "readPolicyLocked()"); 680 681 // clear any existing policy and read from disk 682 mNetworkPolicy.clear(); 683 mUidPolicy.clear(); 684 685 FileInputStream fis = null; 686 try { 687 fis = mPolicyFile.openRead(); 688 final XmlPullParser in = Xml.newPullParser(); 689 in.setInput(fis, null); 690 691 int type; 692 int version = VERSION_CURRENT; 693 while ((type = in.next()) != END_DOCUMENT) { 694 final String tag = in.getName(); 695 if (type == START_TAG) { 696 if (TAG_POLICY_LIST.equals(tag)) { 697 version = readIntAttribute(in, ATTR_VERSION); 698 699 } else if (TAG_NETWORK_POLICY.equals(tag)) { 700 final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE); 701 final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID); 702 final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY); 703 final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES); 704 final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES); 705 706 final NetworkTemplate template = new NetworkTemplate( 707 networkTemplate, subscriberId); 708 mNetworkPolicy.add( 709 new NetworkPolicy(template, cycleDay, warningBytes, limitBytes)); 710 711 } else if (TAG_UID_POLICY.equals(tag)) { 712 final int uid = readIntAttribute(in, ATTR_UID); 713 final int policy = readIntAttribute(in, ATTR_POLICY); 714 715 if (isUidValidForPolicy(mContext, uid)) { 716 setUidPolicyUnchecked(uid, policy, false); 717 } else { 718 Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring"); 719 } 720 } 721 } 722 } 723 724 } catch (FileNotFoundException e) { 725 // missing policy is okay, probably first boot 726 } catch (IOException e) { 727 Slog.e(TAG, "problem reading network stats", e); 728 } catch (XmlPullParserException e) { 729 Slog.e(TAG, "problem reading network stats", e); 730 } finally { 731 IoUtils.closeQuietly(fis); 732 } 733 } 734 735 private void writePolicyLocked() { 736 if (LOGV) Slog.v(TAG, "writePolicyLocked()"); 737 738 FileOutputStream fos = null; 739 try { 740 fos = mPolicyFile.startWrite(); 741 742 XmlSerializer out = new FastXmlSerializer(); 743 out.setOutput(fos, "utf-8"); 744 out.startDocument(null, true); 745 746 out.startTag(null, TAG_POLICY_LIST); 747 writeIntAttribute(out, ATTR_VERSION, VERSION_CURRENT); 748 749 // write all known network policies 750 for (NetworkPolicy policy : mNetworkPolicy) { 751 final NetworkTemplate template = policy.template; 752 753 out.startTag(null, TAG_NETWORK_POLICY); 754 writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule()); 755 final String subscriberId = template.getSubscriberId(); 756 if (subscriberId != null) { 757 out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId); 758 } 759 writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay); 760 writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes); 761 writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes); 762 out.endTag(null, TAG_NETWORK_POLICY); 763 } 764 765 // write all known uid policies 766 for (int i = 0; i < mUidPolicy.size(); i++) { 767 final int uid = mUidPolicy.keyAt(i); 768 final int policy = mUidPolicy.valueAt(i); 769 770 // skip writing empty policies 771 if (policy == POLICY_NONE) continue; 772 773 out.startTag(null, TAG_UID_POLICY); 774 writeIntAttribute(out, ATTR_UID, uid); 775 writeIntAttribute(out, ATTR_POLICY, policy); 776 out.endTag(null, TAG_UID_POLICY); 777 } 778 779 out.endTag(null, TAG_POLICY_LIST); 780 out.endDocument(); 781 782 mPolicyFile.finishWrite(fos); 783 } catch (IOException e) { 784 if (fos != null) { 785 mPolicyFile.failWrite(fos); 786 } 787 } 788 } 789 790 @Override 791 public void setUidPolicy(int uid, int policy) { 792 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 793 794 if (!isUidValidForPolicy(mContext, uid)) { 795 throw new IllegalArgumentException("cannot apply policy to UID " + uid); 796 } 797 798 setUidPolicyUnchecked(uid, policy, true); 799 } 800 801 private void setUidPolicyUnchecked(int uid, int policy, boolean persist) { 802 final int oldPolicy; 803 synchronized (mRulesLock) { 804 oldPolicy = getUidPolicy(uid); 805 mUidPolicy.put(uid, policy); 806 807 // uid policy changed, recompute rules and persist policy. 808 updateRulesForUidLocked(uid); 809 if (persist) { 810 writePolicyLocked(); 811 } 812 } 813 } 814 815 @Override 816 public int getUidPolicy(int uid) { 817 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 818 819 synchronized (mRulesLock) { 820 return mUidPolicy.get(uid, POLICY_NONE); 821 } 822 } 823 824 @Override 825 public void registerListener(INetworkPolicyListener listener) { 826 // TODO: create permission for observing network policy 827 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 828 829 mListeners.register(listener); 830 831 // TODO: consider dispatching existing rules to new listeners 832 } 833 834 @Override 835 public void unregisterListener(INetworkPolicyListener listener) { 836 // TODO: create permission for observing network policy 837 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 838 839 mListeners.unregister(listener); 840 } 841 842 @Override 843 public void setNetworkPolicies(NetworkPolicy[] policies) { 844 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 845 846 synchronized (mRulesLock) { 847 mNetworkPolicy.clear(); 848 for (NetworkPolicy policy : policies) { 849 mNetworkPolicy.add(policy); 850 } 851 852 updateIfacesLocked(); 853 updateNotificationsLocked(); 854 writePolicyLocked(); 855 } 856 } 857 858 @Override 859 public NetworkPolicy[] getNetworkPolicies() { 860 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 861 mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG); 862 863 synchronized (mRulesLock) { 864 return mNetworkPolicy.toArray(new NetworkPolicy[mNetworkPolicy.size()]); 865 } 866 } 867 868 @Override 869 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 870 mContext.enforceCallingOrSelfPermission(DUMP, TAG); 871 872 synchronized (mRulesLock) { 873 fout.println("Network policies:"); 874 for (NetworkPolicy policy : mNetworkPolicy) { 875 fout.print(" "); fout.println(policy.toString()); 876 } 877 878 fout.println("Policy status for known UIDs:"); 879 880 final SparseBooleanArray knownUids = new SparseBooleanArray(); 881 collectKeys(mUidPolicy, knownUids); 882 collectKeys(mUidForeground, knownUids); 883 collectKeys(mUidRules, knownUids); 884 885 final int size = knownUids.size(); 886 for (int i = 0; i < size; i++) { 887 final int uid = knownUids.keyAt(i); 888 fout.print(" UID="); 889 fout.print(uid); 890 891 fout.print(" policy="); 892 final int policyIndex = mUidPolicy.indexOfKey(uid); 893 if (policyIndex < 0) { 894 fout.print("UNKNOWN"); 895 } else { 896 dumpPolicy(fout, mUidPolicy.valueAt(policyIndex)); 897 } 898 899 fout.print(" foreground="); 900 final int foregroundIndex = mUidPidForeground.indexOfKey(uid); 901 if (foregroundIndex < 0) { 902 fout.print("UNKNOWN"); 903 } else { 904 dumpSparseBooleanArray(fout, mUidPidForeground.valueAt(foregroundIndex)); 905 } 906 907 fout.print(" rules="); 908 final int rulesIndex = mUidRules.indexOfKey(uid); 909 if (rulesIndex < 0) { 910 fout.print("UNKNOWN"); 911 } else { 912 dumpRules(fout, mUidRules.valueAt(rulesIndex)); 913 } 914 915 fout.println(); 916 } 917 } 918 } 919 920 @Override 921 public boolean isUidForeground(int uid) { 922 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 923 924 synchronized (mRulesLock) { 925 // only really in foreground when screen is also on 926 return mUidForeground.get(uid, false) && mScreenOn; 927 } 928 } 929 930 /** 931 * Foreground for PID changed; recompute foreground at UID level. If 932 * changed, will trigger {@link #updateRulesForUidLocked(int)}. 933 */ 934 private void computeUidForegroundLocked(int uid) { 935 final SparseBooleanArray pidForeground = mUidPidForeground.get(uid); 936 937 // current pid is dropping foreground; examine other pids 938 boolean uidForeground = false; 939 final int size = pidForeground.size(); 940 for (int i = 0; i < size; i++) { 941 if (pidForeground.valueAt(i)) { 942 uidForeground = true; 943 break; 944 } 945 } 946 947 final boolean oldUidForeground = mUidForeground.get(uid, false); 948 if (oldUidForeground != uidForeground) { 949 // foreground changed, push updated rules 950 mUidForeground.put(uid, uidForeground); 951 updateRulesForUidLocked(uid); 952 } 953 } 954 955 private void updateScreenOn() { 956 synchronized (mRulesLock) { 957 try { 958 mScreenOn = mPowerManager.isScreenOn(); 959 } catch (RemoteException e) { 960 } 961 updateRulesForScreenLocked(); 962 } 963 } 964 965 /** 966 * Update rules that might be changed by {@link #mScreenOn} value. 967 */ 968 private void updateRulesForScreenLocked() { 969 // only update rules for anyone with foreground activities 970 final int size = mUidForeground.size(); 971 for (int i = 0; i < size; i++) { 972 if (mUidForeground.valueAt(i)) { 973 final int uid = mUidForeground.keyAt(i); 974 updateRulesForUidLocked(uid); 975 } 976 } 977 } 978 979 private void updateRulesForUidLocked(int uid) { 980 final int uidPolicy = getUidPolicy(uid); 981 final boolean uidForeground = isUidForeground(uid); 982 983 // derive active rules based on policy and active state 984 int uidRules = RULE_ALLOW_ALL; 985 if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) { 986 // uid in background, and policy says to block metered data 987 uidRules = RULE_REJECT_METERED; 988 } 989 990 // TODO: only dispatch when rules actually change 991 992 // record rule locally to dispatch to new listeners 993 mUidRules.put(uid, uidRules); 994 995 final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0; 996 setUidNetworkRules(uid, rejectMetered); 997 998 // dispatch changed rule to existing listeners 999 mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget(); 1000 } 1001 1002 private Handler.Callback mHandlerCallback = new Handler.Callback() { 1003 /** {@inheritDoc} */ 1004 public boolean handleMessage(Message msg) { 1005 switch (msg.what) { 1006 case MSG_RULES_CHANGED: { 1007 final int uid = msg.arg1; 1008 final int uidRules = msg.arg2; 1009 final int length = mListeners.beginBroadcast(); 1010 for (int i = 0; i < length; i++) { 1011 final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); 1012 if (listener != null) { 1013 try { 1014 listener.onUidRulesChanged(uid, uidRules); 1015 } catch (RemoteException e) { 1016 } 1017 } 1018 } 1019 mListeners.finishBroadcast(); 1020 return true; 1021 } 1022 case MSG_METERED_IFACES_CHANGED: { 1023 final String[] meteredIfaces = (String[]) msg.obj; 1024 final int length = mListeners.beginBroadcast(); 1025 for (int i = 0; i < length; i++) { 1026 final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); 1027 if (listener != null) { 1028 try { 1029 listener.onMeteredIfacesChanged(meteredIfaces); 1030 } catch (RemoteException e) { 1031 } 1032 } 1033 } 1034 mListeners.finishBroadcast(); 1035 return true; 1036 } 1037 default: { 1038 return false; 1039 } 1040 } 1041 } 1042 }; 1043 1044 private String getActiveSubscriberId() { 1045 final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService( 1046 Context.TELEPHONY_SERVICE); 1047 return telephony.getSubscriberId(); 1048 } 1049 1050 private static void collectKeys(SparseIntArray source, SparseBooleanArray target) { 1051 final int size = source.size(); 1052 for (int i = 0; i < size; i++) { 1053 target.put(source.keyAt(i), true); 1054 } 1055 } 1056 1057 private static void collectKeys(SparseBooleanArray source, SparseBooleanArray target) { 1058 final int size = source.size(); 1059 for (int i = 0; i < size; i++) { 1060 target.put(source.keyAt(i), true); 1061 } 1062 } 1063 1064 private static void dumpSparseBooleanArray(PrintWriter fout, SparseBooleanArray value) { 1065 fout.print("["); 1066 final int size = value.size(); 1067 for (int i = 0; i < size; i++) { 1068 fout.print(value.keyAt(i) + "=" + value.valueAt(i)); 1069 if (i < size - 1) fout.print(","); 1070 } 1071 fout.print("]"); 1072 } 1073 1074 private static int readIntAttribute(XmlPullParser in, String name) throws IOException { 1075 final String value = in.getAttributeValue(null, name); 1076 try { 1077 return Integer.parseInt(value); 1078 } catch (NumberFormatException e) { 1079 throw new ProtocolException("problem parsing " + name + "=" + value + " as int"); 1080 } 1081 } 1082 1083 private static long readLongAttribute(XmlPullParser in, String name) throws IOException { 1084 final String value = in.getAttributeValue(null, name); 1085 try { 1086 return Long.parseLong(value); 1087 } catch (NumberFormatException e) { 1088 throw new ProtocolException("problem parsing " + name + "=" + value + " as int"); 1089 } 1090 } 1091 1092 private static void writeIntAttribute(XmlSerializer out, String name, int value) 1093 throws IOException { 1094 out.attribute(null, name, Integer.toString(value)); 1095 } 1096 1097 private static void writeLongAttribute(XmlSerializer out, String name, long value) 1098 throws IOException { 1099 out.attribute(null, name, Long.toString(value)); 1100 } 1101 1102} 1103