NetworkPolicyManagerService.java revision 8fc27e8b87bd1def854a03d84009143b315d4176
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.ACCESS_NETWORK_STATE; 20import static android.Manifest.permission.CONNECTIVITY_INTERNAL; 21import static android.Manifest.permission.DUMP; 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_PACKAGE_ADDED; 26import static android.content.Intent.ACTION_UID_REMOVED; 27import static android.content.Intent.EXTRA_UID; 28import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; 29import static android.net.ConnectivityManager.TYPE_ETHERNET; 30import static android.net.ConnectivityManager.TYPE_MOBILE; 31import static android.net.ConnectivityManager.TYPE_WIFI; 32import static android.net.ConnectivityManager.TYPE_WIMAX; 33import static android.net.NetworkPolicy.LIMIT_DISABLED; 34import static android.net.NetworkPolicy.SNOOZE_NEVER; 35import static android.net.NetworkPolicy.WARNING_DISABLED; 36import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE; 37import static android.net.NetworkPolicyManager.POLICY_NONE; 38import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; 39import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; 40import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; 41import static android.net.NetworkPolicyManager.computeLastCycleBoundary; 42import static android.net.NetworkPolicyManager.dumpPolicy; 43import static android.net.NetworkPolicyManager.dumpRules; 44import static android.net.NetworkTemplate.MATCH_ETHERNET; 45import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER; 46import static android.net.NetworkTemplate.MATCH_MOBILE_4G; 47import static android.net.NetworkTemplate.MATCH_MOBILE_ALL; 48import static android.net.NetworkTemplate.MATCH_WIFI; 49import static android.net.NetworkTemplate.buildTemplateMobileAll; 50import static android.net.TrafficStats.MB_IN_BYTES; 51import static android.telephony.TelephonyManager.SIM_STATE_READY; 52import static android.text.format.DateUtils.DAY_IN_MILLIS; 53import static com.android.internal.util.Preconditions.checkNotNull; 54import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; 55import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readBooleanAttribute; 56import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readIntAttribute; 57import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readLongAttribute; 58import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeBooleanAttribute; 59import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeIntAttribute; 60import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeLongAttribute; 61import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED; 62import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 63import static org.xmlpull.v1.XmlPullParser.START_TAG; 64 65import android.app.IActivityManager; 66import android.app.INotificationManager; 67import android.app.IProcessObserver; 68import android.app.Notification; 69import android.app.PendingIntent; 70import android.content.BroadcastReceiver; 71import android.content.ComponentName; 72import android.content.Context; 73import android.content.Intent; 74import android.content.IntentFilter; 75import android.content.pm.ApplicationInfo; 76import android.content.pm.PackageManager; 77import android.content.pm.UserInfo; 78import android.content.res.Resources; 79import android.net.ConnectivityManager; 80import android.net.IConnectivityManager; 81import android.net.INetworkManagementEventObserver; 82import android.net.INetworkPolicyListener; 83import android.net.INetworkPolicyManager; 84import android.net.INetworkStatsService; 85import android.net.NetworkIdentity; 86import android.net.NetworkPolicy; 87import android.net.NetworkQuotaInfo; 88import android.net.NetworkState; 89import android.net.NetworkTemplate; 90import android.os.Binder; 91import android.os.Environment; 92import android.os.Handler; 93import android.os.HandlerThread; 94import android.os.INetworkManagementService; 95import android.os.IPowerManager; 96import android.os.Message; 97import android.os.MessageQueue.IdleHandler; 98import android.os.RemoteCallbackList; 99import android.os.RemoteException; 100import android.os.UserId; 101import android.provider.Settings; 102import android.telephony.TelephonyManager; 103import android.text.format.Formatter; 104import android.text.format.Time; 105import android.util.Log; 106import android.util.NtpTrustedTime; 107import android.util.Slog; 108import android.util.SparseArray; 109import android.util.SparseBooleanArray; 110import android.util.SparseIntArray; 111import android.util.TrustedTime; 112import android.util.Xml; 113 114import com.android.internal.R; 115import com.android.internal.os.AtomicFile; 116import com.android.internal.util.FastXmlSerializer; 117import com.android.internal.util.IndentingPrintWriter; 118import com.android.internal.util.Objects; 119import com.google.android.collect.Lists; 120import com.google.android.collect.Maps; 121import com.google.android.collect.Sets; 122 123import org.xmlpull.v1.XmlPullParser; 124import org.xmlpull.v1.XmlPullParserException; 125import org.xmlpull.v1.XmlSerializer; 126 127import java.io.File; 128import java.io.FileDescriptor; 129import java.io.FileInputStream; 130import java.io.FileNotFoundException; 131import java.io.FileOutputStream; 132import java.io.IOException; 133import java.io.PrintWriter; 134import java.net.ProtocolException; 135import java.util.ArrayList; 136import java.util.Arrays; 137import java.util.HashMap; 138import java.util.HashSet; 139import java.util.List; 140import java.util.Map; 141 142import libcore.io.IoUtils; 143 144/** 145 * Service that maintains low-level network policy rules, using 146 * {@link NetworkStatsService} statistics to drive those rules. 147 * <p> 148 * Derives active rules by combining a given policy with other system status, 149 * and delivers to listeners, such as {@link ConnectivityManager}, for 150 * enforcement. 151 */ 152public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 153 private static final String TAG = "NetworkPolicy"; 154 private static final boolean LOGD = true; 155 private static final boolean LOGV = false; 156 157 private static final int VERSION_INIT = 1; 158 private static final int VERSION_ADDED_SNOOZE = 2; 159 private static final int VERSION_ADDED_RESTRICT_BACKGROUND = 3; 160 private static final int VERSION_ADDED_METERED = 4; 161 private static final int VERSION_SPLIT_SNOOZE = 5; 162 private static final int VERSION_ADDED_TIMEZONE = 6; 163 private static final int VERSION_ADDED_INFERRED = 7; 164 private static final int VERSION_SWITCH_APP_ID = 8; 165 private static final int VERSION_ADDED_NETWORK_ID = 9; 166 private static final int VERSION_LATEST = VERSION_ADDED_NETWORK_ID; 167 168 // @VisibleForTesting 169 public static final int TYPE_WARNING = 0x1; 170 public static final int TYPE_LIMIT = 0x2; 171 public static final int TYPE_LIMIT_SNOOZED = 0x3; 172 173 private static final String TAG_POLICY_LIST = "policy-list"; 174 private static final String TAG_NETWORK_POLICY = "network-policy"; 175 private static final String TAG_UID_POLICY = "uid-policy"; 176 private static final String TAG_APP_POLICY = "app-policy"; 177 178 private static final String ATTR_VERSION = "version"; 179 private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground"; 180 private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate"; 181 private static final String ATTR_SUBSCRIBER_ID = "subscriberId"; 182 private static final String ATTR_NETWORK_ID = "networkId"; 183 private static final String ATTR_CYCLE_DAY = "cycleDay"; 184 private static final String ATTR_CYCLE_TIMEZONE = "cycleTimezone"; 185 private static final String ATTR_WARNING_BYTES = "warningBytes"; 186 private static final String ATTR_LIMIT_BYTES = "limitBytes"; 187 private static final String ATTR_LAST_SNOOZE = "lastSnooze"; 188 private static final String ATTR_LAST_WARNING_SNOOZE = "lastWarningSnooze"; 189 private static final String ATTR_LAST_LIMIT_SNOOZE = "lastLimitSnooze"; 190 private static final String ATTR_METERED = "metered"; 191 private static final String ATTR_INFERRED = "inferred"; 192 private static final String ATTR_UID = "uid"; 193 private static final String ATTR_APP_ID = "appId"; 194 private static final String ATTR_POLICY = "policy"; 195 196 private static final String TAG_ALLOW_BACKGROUND = TAG + ":allowBackground"; 197 198 // @VisibleForTesting 199 public static final String ACTION_ALLOW_BACKGROUND = 200 "com.android.server.net.action.ALLOW_BACKGROUND"; 201 public static final String ACTION_SNOOZE_WARNING = 202 "com.android.server.net.action.SNOOZE_WARNING"; 203 204 private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS; 205 206 private static final int MSG_RULES_CHANGED = 1; 207 private static final int MSG_METERED_IFACES_CHANGED = 2; 208 private static final int MSG_FOREGROUND_ACTIVITIES_CHANGED = 3; 209 private static final int MSG_PROCESS_DIED = 4; 210 private static final int MSG_LIMIT_REACHED = 5; 211 private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6; 212 213 private final Context mContext; 214 private final IActivityManager mActivityManager; 215 private final IPowerManager mPowerManager; 216 private final INetworkStatsService mNetworkStats; 217 private final INetworkManagementService mNetworkManager; 218 private final TrustedTime mTime; 219 220 private IConnectivityManager mConnManager; 221 private INotificationManager mNotifManager; 222 223 private final Object mRulesLock = new Object(); 224 225 private volatile boolean mScreenOn; 226 private volatile boolean mRestrictBackground; 227 228 private final boolean mSuppressDefaultPolicy; 229 230 /** Defined network policies. */ 231 private HashMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = Maps.newHashMap(); 232 /** Currently active network rules for ifaces. */ 233 private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap(); 234 235 /** Defined app policies. */ 236 private SparseIntArray mAppPolicy = new SparseIntArray(); 237 /** Currently derived rules for each UID. */ 238 private SparseIntArray mUidRules = new SparseIntArray(); 239 240 /** Set of ifaces that are metered. */ 241 private HashSet<String> mMeteredIfaces = Sets.newHashSet(); 242 /** Set of over-limit templates that have been notified. */ 243 private HashSet<NetworkTemplate> mOverLimitNotified = Sets.newHashSet(); 244 245 /** Set of currently active {@link Notification} tags. */ 246 private HashSet<String> mActiveNotifs = Sets.newHashSet(); 247 248 /** Foreground at both UID and PID granularity. */ 249 private SparseBooleanArray mUidForeground = new SparseBooleanArray(); 250 private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray< 251 SparseBooleanArray>(); 252 253 private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList< 254 INetworkPolicyListener>(); 255 256 private final HandlerThread mHandlerThread; 257 private final Handler mHandler; 258 259 private final AtomicFile mPolicyFile; 260 261 // TODO: keep whitelist of system-critical services that should never have 262 // rules enforced, such as system, phone, and radio UIDs. 263 264 // TODO: migrate notifications to SystemUI 265 266 public NetworkPolicyManagerService(Context context, IActivityManager activityManager, 267 IPowerManager powerManager, INetworkStatsService networkStats, 268 INetworkManagementService networkManagement) { 269 this(context, activityManager, powerManager, networkStats, networkManagement, 270 NtpTrustedTime.getInstance(context), getSystemDir(), false); 271 } 272 273 private static File getSystemDir() { 274 return new File(Environment.getDataDirectory(), "system"); 275 } 276 277 public NetworkPolicyManagerService(Context context, IActivityManager activityManager, 278 IPowerManager powerManager, INetworkStatsService networkStats, 279 INetworkManagementService networkManagement, TrustedTime time, File systemDir, 280 boolean suppressDefaultPolicy) { 281 mContext = checkNotNull(context, "missing context"); 282 mActivityManager = checkNotNull(activityManager, "missing activityManager"); 283 mPowerManager = checkNotNull(powerManager, "missing powerManager"); 284 mNetworkStats = checkNotNull(networkStats, "missing networkStats"); 285 mNetworkManager = checkNotNull(networkManagement, "missing networkManagement"); 286 mTime = checkNotNull(time, "missing TrustedTime"); 287 288 mHandlerThread = new HandlerThread(TAG); 289 mHandlerThread.start(); 290 mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback); 291 292 mSuppressDefaultPolicy = suppressDefaultPolicy; 293 294 mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml")); 295 } 296 297 public void bindConnectivityManager(IConnectivityManager connManager) { 298 mConnManager = checkNotNull(connManager, "missing IConnectivityManager"); 299 } 300 301 public void bindNotificationManager(INotificationManager notifManager) { 302 mNotifManager = checkNotNull(notifManager, "missing INotificationManager"); 303 } 304 305 public void systemReady() { 306 synchronized (mRulesLock) { 307 // read policy from disk 308 readPolicyLocked(); 309 310 if (mRestrictBackground) { 311 updateRulesForRestrictBackgroundLocked(); 312 updateNotificationsLocked(); 313 } 314 } 315 316 updateScreenOn(); 317 318 try { 319 mActivityManager.registerProcessObserver(mProcessObserver); 320 mNetworkManager.registerObserver(mAlertObserver); 321 } catch (RemoteException e) { 322 // ignored; both services live in system_server 323 } 324 325 // TODO: traverse existing processes to know foreground state, or have 326 // activitymanager dispatch current state when new observer attached. 327 328 final IntentFilter screenFilter = new IntentFilter(); 329 screenFilter.addAction(Intent.ACTION_SCREEN_ON); 330 screenFilter.addAction(Intent.ACTION_SCREEN_OFF); 331 mContext.registerReceiver(mScreenReceiver, screenFilter, null, mHandler); 332 333 // watch for network interfaces to be claimed 334 final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE); 335 mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); 336 337 // listen for package/uid changes to update policy 338 final IntentFilter packageFilter = new IntentFilter(); 339 packageFilter.addAction(ACTION_PACKAGE_ADDED); 340 packageFilter.addAction(ACTION_UID_REMOVED); 341 mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler); 342 343 // listen for stats update events 344 final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED); 345 mContext.registerReceiver( 346 mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler); 347 348 // listen for restrict background changes from notifications 349 final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND); 350 mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler); 351 352 // listen for snooze warning from notifications 353 final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING); 354 mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter, 355 MANAGE_NETWORK_POLICY, mHandler); 356 357 } 358 359 private IProcessObserver mProcessObserver = new IProcessObserver.Stub() { 360 @Override 361 public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) { 362 mHandler.obtainMessage(MSG_FOREGROUND_ACTIVITIES_CHANGED, 363 pid, uid, foregroundActivities).sendToTarget(); 364 } 365 366 @Override 367 public void onProcessDied(int pid, int uid) { 368 mHandler.obtainMessage(MSG_PROCESS_DIED, pid, uid).sendToTarget(); 369 } 370 }; 371 372 private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() { 373 @Override 374 public void onReceive(Context context, Intent intent) { 375 synchronized (mRulesLock) { 376 // screen-related broadcasts are protected by system, no need 377 // for permissions check. 378 updateScreenOn(); 379 } 380 } 381 }; 382 383 private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { 384 @Override 385 public void onReceive(Context context, Intent intent) { 386 // on background handler thread, and PACKAGE_ADDED and UID_REMOVED 387 // are protected broadcasts. 388 389 final String action = intent.getAction(); 390 final int uid = intent.getIntExtra(EXTRA_UID, 0); 391 final int appId = UserId.getAppId(uid); 392 synchronized (mRulesLock) { 393 if (ACTION_PACKAGE_ADDED.equals(action)) { 394 // NOTE: PACKAGE_ADDED is currently only sent once, and is 395 // not broadcast when users are added. 396 397 // update rules for UID, since it might be subject to 398 // global background data policy. 399 if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid); 400 updateRulesForAppLocked(appId); 401 402 } else if (ACTION_UID_REMOVED.equals(action)) { 403 // NOTE: UID_REMOVED is currently only sent once, and is not 404 // broadcast when users are removed. 405 406 // remove any policy and update rules to clean up. 407 if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid); 408 409 mAppPolicy.delete(appId); 410 updateRulesForAppLocked(appId); 411 writePolicyLocked(); 412 } 413 } 414 } 415 }; 416 417 /** 418 * Receiver that watches for {@link INetworkStatsService} updates, which we 419 * use to check against {@link NetworkPolicy#warningBytes}. 420 */ 421 private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() { 422 @Override 423 public void onReceive(Context context, Intent intent) { 424 // on background handler thread, and verified 425 // READ_NETWORK_USAGE_HISTORY permission above. 426 427 maybeRefreshTrustedTime(); 428 synchronized (mRulesLock) { 429 updateNetworkEnabledLocked(); 430 updateNotificationsLocked(); 431 } 432 } 433 }; 434 435 /** 436 * Receiver that watches for {@link Notification} control of 437 * {@link #mRestrictBackground}. 438 */ 439 private BroadcastReceiver mAllowReceiver = new BroadcastReceiver() { 440 @Override 441 public void onReceive(Context context, Intent intent) { 442 // on background handler thread, and verified MANAGE_NETWORK_POLICY 443 // permission above. 444 445 setRestrictBackground(false); 446 } 447 }; 448 449 /** 450 * Receiver that watches for {@link Notification} control of 451 * {@link NetworkPolicy#lastWarningSnooze}. 452 */ 453 private BroadcastReceiver mSnoozeWarningReceiver = new BroadcastReceiver() { 454 @Override 455 public void onReceive(Context context, Intent intent) { 456 // on background handler thread, and verified MANAGE_NETWORK_POLICY 457 // permission above. 458 459 final NetworkTemplate template = intent.getParcelableExtra(EXTRA_NETWORK_TEMPLATE); 460 performSnooze(template, TYPE_WARNING); 461 } 462 }; 463 464 /** 465 * Observer that watches for {@link INetworkManagementService} alerts. 466 */ 467 private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() { 468 @Override 469 public void limitReached(String limitName, String iface) { 470 // only someone like NMS should be calling us 471 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 472 473 if (!LIMIT_GLOBAL_ALERT.equals(limitName)) { 474 mHandler.obtainMessage(MSG_LIMIT_REACHED, iface).sendToTarget(); 475 } 476 } 477 }; 478 479 /** 480 * Check {@link NetworkPolicy} against current {@link INetworkStatsService} 481 * to show visible notifications as needed. 482 */ 483 private void updateNotificationsLocked() { 484 if (LOGV) Slog.v(TAG, "updateNotificationsLocked()"); 485 486 // keep track of previously active notifications 487 final HashSet<String> beforeNotifs = Sets.newHashSet(); 488 beforeNotifs.addAll(mActiveNotifs); 489 mActiveNotifs.clear(); 490 491 // TODO: when switching to kernel notifications, compute next future 492 // cycle boundary to recompute notifications. 493 494 // examine stats for each active policy 495 final long currentTime = currentTimeMillis(); 496 for (NetworkPolicy policy : mNetworkPolicy.values()) { 497 // ignore policies that aren't relevant to user 498 if (!isTemplateRelevant(policy.template)) continue; 499 if (!policy.hasCycle()) continue; 500 501 final long start = computeLastCycleBoundary(currentTime, policy); 502 final long end = currentTime; 503 final long totalBytes = getTotalBytes(policy.template, start, end); 504 505 if (policy.isOverLimit(totalBytes)) { 506 if (policy.lastLimitSnooze >= start) { 507 enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes); 508 } else { 509 enqueueNotification(policy, TYPE_LIMIT, totalBytes); 510 notifyOverLimitLocked(policy.template); 511 } 512 513 } else { 514 notifyUnderLimitLocked(policy.template); 515 516 if (policy.isOverWarning(totalBytes) && policy.lastWarningSnooze < start) { 517 enqueueNotification(policy, TYPE_WARNING, totalBytes); 518 } 519 } 520 } 521 522 // ongoing notification when restricting background data 523 if (mRestrictBackground) { 524 enqueueRestrictedNotification(TAG_ALLOW_BACKGROUND); 525 } 526 527 // cancel stale notifications that we didn't renew above 528 for (String tag : beforeNotifs) { 529 if (!mActiveNotifs.contains(tag)) { 530 cancelNotification(tag); 531 } 532 } 533 } 534 535 /** 536 * Test if given {@link NetworkTemplate} is relevant to user based on 537 * current device state, such as when 538 * {@link TelephonyManager#getSubscriberId()} matches. This is regardless of 539 * data connection status. 540 */ 541 private boolean isTemplateRelevant(NetworkTemplate template) { 542 final TelephonyManager tele = TelephonyManager.from(mContext); 543 544 switch (template.getMatchRule()) { 545 case MATCH_MOBILE_3G_LOWER: 546 case MATCH_MOBILE_4G: 547 case MATCH_MOBILE_ALL: 548 // mobile templates are relevant when SIM is ready and 549 // subscriberId matches. 550 if (tele.getSimState() == SIM_STATE_READY) { 551 return Objects.equal(tele.getSubscriberId(), template.getSubscriberId()); 552 } else { 553 return false; 554 } 555 } 556 return true; 557 } 558 559 /** 560 * Notify that given {@link NetworkTemplate} is over 561 * {@link NetworkPolicy#limitBytes}, potentially showing dialog to user. 562 */ 563 private void notifyOverLimitLocked(NetworkTemplate template) { 564 if (!mOverLimitNotified.contains(template)) { 565 mContext.startActivity(buildNetworkOverLimitIntent(template)); 566 mOverLimitNotified.add(template); 567 } 568 } 569 570 private void notifyUnderLimitLocked(NetworkTemplate template) { 571 mOverLimitNotified.remove(template); 572 } 573 574 /** 575 * Build unique tag that identifies an active {@link NetworkPolicy} 576 * notification of a specific type, like {@link #TYPE_LIMIT}. 577 */ 578 private String buildNotificationTag(NetworkPolicy policy, int type) { 579 return TAG + ":" + policy.template.hashCode() + ":" + type; 580 } 581 582 /** 583 * Show notification for combined {@link NetworkPolicy} and specific type, 584 * like {@link #TYPE_LIMIT}. Okay to call multiple times. 585 */ 586 private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes) { 587 final String tag = buildNotificationTag(policy, type); 588 final Notification.Builder builder = new Notification.Builder(mContext); 589 builder.setOnlyAlertOnce(true); 590 builder.setWhen(0L); 591 592 final Resources res = mContext.getResources(); 593 switch (type) { 594 case TYPE_WARNING: { 595 final CharSequence title = res.getText(R.string.data_usage_warning_title); 596 final CharSequence body = res.getString(R.string.data_usage_warning_body); 597 598 builder.setSmallIcon(R.drawable.stat_notify_error); 599 builder.setTicker(title); 600 builder.setContentTitle(title); 601 builder.setContentText(body); 602 603 final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template); 604 builder.setDeleteIntent(PendingIntent.getBroadcast( 605 mContext, 0, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT)); 606 607 final Intent viewIntent = buildViewDataUsageIntent(policy.template); 608 builder.setContentIntent(PendingIntent.getActivity( 609 mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT)); 610 611 break; 612 } 613 case TYPE_LIMIT: { 614 final CharSequence body = res.getText(R.string.data_usage_limit_body); 615 616 final CharSequence title; 617 switch (policy.template.getMatchRule()) { 618 case MATCH_MOBILE_3G_LOWER: 619 title = res.getText(R.string.data_usage_3g_limit_title); 620 break; 621 case MATCH_MOBILE_4G: 622 title = res.getText(R.string.data_usage_4g_limit_title); 623 break; 624 case MATCH_MOBILE_ALL: 625 title = res.getText(R.string.data_usage_mobile_limit_title); 626 break; 627 case MATCH_WIFI: 628 title = res.getText(R.string.data_usage_wifi_limit_title); 629 break; 630 default: 631 title = null; 632 break; 633 } 634 635 builder.setOngoing(true); 636 builder.setSmallIcon(R.drawable.stat_notify_disabled); 637 builder.setTicker(title); 638 builder.setContentTitle(title); 639 builder.setContentText(body); 640 641 final Intent intent = buildNetworkOverLimitIntent(policy.template); 642 builder.setContentIntent(PendingIntent.getActivity( 643 mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); 644 break; 645 } 646 case TYPE_LIMIT_SNOOZED: { 647 final long overBytes = totalBytes - policy.limitBytes; 648 final CharSequence body = res.getString(R.string.data_usage_limit_snoozed_body, 649 Formatter.formatFileSize(mContext, overBytes)); 650 651 final CharSequence title; 652 switch (policy.template.getMatchRule()) { 653 case MATCH_MOBILE_3G_LOWER: 654 title = res.getText(R.string.data_usage_3g_limit_snoozed_title); 655 break; 656 case MATCH_MOBILE_4G: 657 title = res.getText(R.string.data_usage_4g_limit_snoozed_title); 658 break; 659 case MATCH_MOBILE_ALL: 660 title = res.getText(R.string.data_usage_mobile_limit_snoozed_title); 661 break; 662 case MATCH_WIFI: 663 title = res.getText(R.string.data_usage_wifi_limit_snoozed_title); 664 break; 665 default: 666 title = null; 667 break; 668 } 669 670 builder.setOngoing(true); 671 builder.setSmallIcon(R.drawable.stat_notify_error); 672 builder.setTicker(title); 673 builder.setContentTitle(title); 674 builder.setContentText(body); 675 676 final Intent intent = buildViewDataUsageIntent(policy.template); 677 builder.setContentIntent(PendingIntent.getActivity( 678 mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); 679 break; 680 } 681 } 682 683 // TODO: move to NotificationManager once we can mock it 684 try { 685 final String packageName = mContext.getPackageName(); 686 final int[] idReceived = new int[1]; 687 mNotifManager.enqueueNotificationWithTag( 688 packageName, tag, 0x0, builder.getNotification(), idReceived); 689 mActiveNotifs.add(tag); 690 } catch (RemoteException e) { 691 // ignored; service lives in system_server 692 } 693 } 694 695 /** 696 * Show ongoing notification to reflect that {@link #mRestrictBackground} 697 * has been enabled. 698 */ 699 private void enqueueRestrictedNotification(String tag) { 700 final Resources res = mContext.getResources(); 701 final Notification.Builder builder = new Notification.Builder(mContext); 702 703 final CharSequence title = res.getText(R.string.data_usage_restricted_title); 704 final CharSequence body = res.getString(R.string.data_usage_restricted_body); 705 706 builder.setOnlyAlertOnce(true); 707 builder.setOngoing(true); 708 builder.setSmallIcon(R.drawable.stat_notify_error); 709 builder.setTicker(title); 710 builder.setContentTitle(title); 711 builder.setContentText(body); 712 713 final Intent intent = buildAllowBackgroundDataIntent(); 714 builder.setContentIntent( 715 PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); 716 717 // TODO: move to NotificationManager once we can mock it 718 try { 719 final String packageName = mContext.getPackageName(); 720 final int[] idReceived = new int[1]; 721 mNotifManager.enqueueNotificationWithTag(packageName, tag, 722 0x0, builder.getNotification(), idReceived); 723 mActiveNotifs.add(tag); 724 } catch (RemoteException e) { 725 // ignored; service lives in system_server 726 } 727 } 728 729 private void cancelNotification(String tag) { 730 // TODO: move to NotificationManager once we can mock it 731 try { 732 final String packageName = mContext.getPackageName(); 733 mNotifManager.cancelNotificationWithTag( 734 packageName, tag, 0x0); 735 } catch (RemoteException e) { 736 // ignored; service lives in system_server 737 } 738 } 739 740 /** 741 * Receiver that watches for {@link IConnectivityManager} to claim network 742 * interfaces. Used to apply {@link NetworkPolicy} to matching networks. 743 */ 744 private BroadcastReceiver mConnReceiver = new BroadcastReceiver() { 745 @Override 746 public void onReceive(Context context, Intent intent) { 747 // on background handler thread, and verified CONNECTIVITY_INTERNAL 748 // permission above. 749 750 maybeRefreshTrustedTime(); 751 synchronized (mRulesLock) { 752 ensureActiveMobilePolicyLocked(); 753 updateNetworkEnabledLocked(); 754 updateNetworkRulesLocked(); 755 updateNotificationsLocked(); 756 } 757 } 758 }; 759 760 /** 761 * Proactively control network data connections when they exceed 762 * {@link NetworkPolicy#limitBytes}. 763 */ 764 private void updateNetworkEnabledLocked() { 765 if (LOGV) Slog.v(TAG, "updateNetworkEnabledLocked()"); 766 767 // TODO: reset any policy-disabled networks when any policy is removed 768 // completely, which is currently rare case. 769 770 final long currentTime = currentTimeMillis(); 771 for (NetworkPolicy policy : mNetworkPolicy.values()) { 772 // shortcut when policy has no limit 773 if (policy.limitBytes == LIMIT_DISABLED || !policy.hasCycle()) { 774 setNetworkTemplateEnabled(policy.template, true); 775 continue; 776 } 777 778 final long start = computeLastCycleBoundary(currentTime, policy); 779 final long end = currentTime; 780 final long totalBytes = getTotalBytes(policy.template, start, end); 781 782 // disable data connection when over limit and not snoozed 783 final boolean overLimitWithoutSnooze = policy.isOverLimit(totalBytes) 784 && policy.lastLimitSnooze < start; 785 final boolean networkEnabled = !overLimitWithoutSnooze; 786 787 setNetworkTemplateEnabled(policy.template, networkEnabled); 788 } 789 } 790 791 /** 792 * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)} 793 * for the given {@link NetworkTemplate}. 794 */ 795 private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) { 796 final TelephonyManager tele = TelephonyManager.from(mContext); 797 798 switch (template.getMatchRule()) { 799 case MATCH_MOBILE_3G_LOWER: 800 case MATCH_MOBILE_4G: 801 case MATCH_MOBILE_ALL: 802 // TODO: offer more granular control over radio states once 803 // 4965893 is available. 804 if (tele.getSimState() == SIM_STATE_READY 805 && Objects.equal(tele.getSubscriberId(), template.getSubscriberId())) { 806 setPolicyDataEnable(TYPE_MOBILE, enabled); 807 setPolicyDataEnable(TYPE_WIMAX, enabled); 808 } 809 break; 810 case MATCH_WIFI: 811 setPolicyDataEnable(TYPE_WIFI, enabled); 812 break; 813 case MATCH_ETHERNET: 814 setPolicyDataEnable(TYPE_ETHERNET, enabled); 815 break; 816 default: 817 throw new IllegalArgumentException("unexpected template"); 818 } 819 } 820 821 /** 822 * Examine all connected {@link NetworkState}, looking for 823 * {@link NetworkPolicy} that need to be enforced. When matches found, set 824 * remaining quota based on usage cycle and historical stats. 825 */ 826 private void updateNetworkRulesLocked() { 827 if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); 828 829 final NetworkState[] states; 830 try { 831 states = mConnManager.getAllNetworkState(); 832 } catch (RemoteException e) { 833 // ignored; service lives in system_server 834 return; 835 } 836 837 // first, derive identity for all connected networks, which can be used 838 // to match against templates. 839 final HashMap<NetworkIdentity, String> networks = Maps.newHashMap(); 840 for (NetworkState state : states) { 841 // stash identity and iface away for later use 842 if (state.networkInfo.isConnected()) { 843 final String iface = state.linkProperties.getInterfaceName(); 844 final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state); 845 networks.put(ident, iface); 846 } 847 } 848 849 // build list of rules and ifaces to enforce them against 850 mNetworkRules.clear(); 851 final ArrayList<String> ifaceList = Lists.newArrayList(); 852 for (NetworkPolicy policy : mNetworkPolicy.values()) { 853 854 // collect all active ifaces that match this template 855 ifaceList.clear(); 856 for (Map.Entry<NetworkIdentity, String> entry : networks.entrySet()) { 857 final NetworkIdentity ident = entry.getKey(); 858 if (policy.template.matches(ident)) { 859 final String iface = entry.getValue(); 860 ifaceList.add(iface); 861 } 862 } 863 864 if (ifaceList.size() > 0) { 865 final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]); 866 mNetworkRules.put(policy, ifaces); 867 } 868 } 869 870 final HashSet<String> newMeteredIfaces = Sets.newHashSet(); 871 872 // apply each policy that we found ifaces for; compute remaining data 873 // based on current cycle and historical stats, and push to kernel. 874 final long currentTime = currentTimeMillis(); 875 for (NetworkPolicy policy : mNetworkRules.keySet()) { 876 final String[] ifaces = mNetworkRules.get(policy); 877 878 final long start; 879 final long totalBytes; 880 if (policy.hasCycle()) { 881 start = computeLastCycleBoundary(currentTime, policy); 882 totalBytes = getTotalBytes(policy.template, start, currentTime); 883 } else { 884 start = Long.MAX_VALUE; 885 totalBytes = 0; 886 } 887 888 if (LOGD) { 889 Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces " 890 + Arrays.toString(ifaces)); 891 } 892 893 final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED; 894 if (hasLimit || policy.metered) { 895 final long quotaBytes; 896 if (!hasLimit) { 897 // metered network, but no policy limit; we still need to 898 // restrict apps, so push really high quota. 899 quotaBytes = Long.MAX_VALUE; 900 } else if (policy.lastLimitSnooze >= start) { 901 // snoozing past quota, but we still need to restrict apps, 902 // so push really high quota. 903 quotaBytes = Long.MAX_VALUE; 904 } else { 905 // remaining "quota" bytes are based on total usage in 906 // current cycle. kernel doesn't like 0-byte rules, so we 907 // set 1-byte quota and disable the radio later. 908 quotaBytes = Math.max(1, policy.limitBytes - totalBytes); 909 } 910 911 if (ifaces.length > 1) { 912 // TODO: switch to shared quota once NMS supports 913 Slog.w(TAG, "shared quota unsupported; generating rule for each iface"); 914 } 915 916 for (String iface : ifaces) { 917 removeInterfaceQuota(iface); 918 setInterfaceQuota(iface, quotaBytes); 919 newMeteredIfaces.add(iface); 920 } 921 } 922 } 923 924 // remove quota on any trailing interfaces 925 for (String iface : mMeteredIfaces) { 926 if (!newMeteredIfaces.contains(iface)) { 927 removeInterfaceQuota(iface); 928 } 929 } 930 mMeteredIfaces = newMeteredIfaces; 931 932 final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]); 933 mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget(); 934 } 935 936 /** 937 * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we 938 * have at least a default mobile policy defined. 939 */ 940 private void ensureActiveMobilePolicyLocked() { 941 if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()"); 942 if (mSuppressDefaultPolicy) return; 943 944 final TelephonyManager tele = TelephonyManager.from(mContext); 945 946 // avoid creating policy when SIM isn't ready 947 if (tele.getSimState() != SIM_STATE_READY) return; 948 949 final String subscriberId = tele.getSubscriberId(); 950 final NetworkIdentity probeIdent = new NetworkIdentity( 951 TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false); 952 953 // examine to see if any policy is defined for active mobile 954 boolean mobileDefined = false; 955 for (NetworkPolicy policy : mNetworkPolicy.values()) { 956 if (policy.template.matches(probeIdent)) { 957 mobileDefined = true; 958 } 959 } 960 961 if (!mobileDefined) { 962 Slog.i(TAG, "no policy for active mobile network; generating default policy"); 963 964 // build default mobile policy, and assume usage cycle starts today 965 final long warningBytes = mContext.getResources().getInteger( 966 com.android.internal.R.integer.config_networkPolicyDefaultWarning) 967 * MB_IN_BYTES; 968 969 final Time time = new Time(); 970 time.setToNow(); 971 972 final int cycleDay = time.monthDay; 973 final String cycleTimezone = time.timezone; 974 975 final NetworkTemplate template = buildTemplateMobileAll(subscriberId); 976 mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, cycleTimezone, 977 warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true)); 978 writePolicyLocked(); 979 } 980 } 981 982 private void readPolicyLocked() { 983 if (LOGV) Slog.v(TAG, "readPolicyLocked()"); 984 985 // clear any existing policy and read from disk 986 mNetworkPolicy.clear(); 987 mAppPolicy.clear(); 988 989 FileInputStream fis = null; 990 try { 991 fis = mPolicyFile.openRead(); 992 final XmlPullParser in = Xml.newPullParser(); 993 in.setInput(fis, null); 994 995 int type; 996 int version = VERSION_INIT; 997 while ((type = in.next()) != END_DOCUMENT) { 998 final String tag = in.getName(); 999 if (type == START_TAG) { 1000 if (TAG_POLICY_LIST.equals(tag)) { 1001 version = readIntAttribute(in, ATTR_VERSION); 1002 if (version >= VERSION_ADDED_RESTRICT_BACKGROUND) { 1003 mRestrictBackground = readBooleanAttribute( 1004 in, ATTR_RESTRICT_BACKGROUND); 1005 } else { 1006 mRestrictBackground = false; 1007 } 1008 1009 } else if (TAG_NETWORK_POLICY.equals(tag)) { 1010 final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE); 1011 final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID); 1012 final String networkId; 1013 if (version >= VERSION_ADDED_NETWORK_ID) { 1014 networkId = in.getAttributeValue(null, ATTR_NETWORK_ID); 1015 } else { 1016 networkId = null; 1017 } 1018 final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY); 1019 final String cycleTimezone; 1020 if (version >= VERSION_ADDED_TIMEZONE) { 1021 cycleTimezone = in.getAttributeValue(null, ATTR_CYCLE_TIMEZONE); 1022 } else { 1023 cycleTimezone = Time.TIMEZONE_UTC; 1024 } 1025 final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES); 1026 final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES); 1027 final long lastLimitSnooze; 1028 if (version >= VERSION_SPLIT_SNOOZE) { 1029 lastLimitSnooze = readLongAttribute(in, ATTR_LAST_LIMIT_SNOOZE); 1030 } else if (version >= VERSION_ADDED_SNOOZE) { 1031 lastLimitSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE); 1032 } else { 1033 lastLimitSnooze = SNOOZE_NEVER; 1034 } 1035 final boolean metered; 1036 if (version >= VERSION_ADDED_METERED) { 1037 metered = readBooleanAttribute(in, ATTR_METERED); 1038 } else { 1039 switch (networkTemplate) { 1040 case MATCH_MOBILE_3G_LOWER: 1041 case MATCH_MOBILE_4G: 1042 case MATCH_MOBILE_ALL: 1043 metered = true; 1044 break; 1045 default: 1046 metered = false; 1047 } 1048 } 1049 final long lastWarningSnooze; 1050 if (version >= VERSION_SPLIT_SNOOZE) { 1051 lastWarningSnooze = readLongAttribute(in, ATTR_LAST_WARNING_SNOOZE); 1052 } else { 1053 lastWarningSnooze = SNOOZE_NEVER; 1054 } 1055 final boolean inferred; 1056 if (version >= VERSION_ADDED_INFERRED) { 1057 inferred = readBooleanAttribute(in, ATTR_INFERRED); 1058 } else { 1059 inferred = false; 1060 } 1061 1062 final NetworkTemplate template = new NetworkTemplate( 1063 networkTemplate, subscriberId, networkId); 1064 mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, 1065 cycleTimezone, warningBytes, limitBytes, lastWarningSnooze, 1066 lastLimitSnooze, metered, inferred)); 1067 1068 } else if (TAG_UID_POLICY.equals(tag) && version < VERSION_SWITCH_APP_ID) { 1069 final int uid = readIntAttribute(in, ATTR_UID); 1070 final int policy = readIntAttribute(in, ATTR_POLICY); 1071 1072 final int appId = UserId.getAppId(uid); 1073 if (UserId.isApp(appId)) { 1074 setAppPolicyUnchecked(appId, policy, false); 1075 } else { 1076 Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring"); 1077 } 1078 } else if (TAG_APP_POLICY.equals(tag) && version >= VERSION_SWITCH_APP_ID) { 1079 final int appId = readIntAttribute(in, ATTR_APP_ID); 1080 final int policy = readIntAttribute(in, ATTR_POLICY); 1081 1082 if (UserId.isApp(appId)) { 1083 setAppPolicyUnchecked(appId, policy, false); 1084 } else { 1085 Slog.w(TAG, "unable to apply policy to appId " + appId + "; ignoring"); 1086 } 1087 } 1088 } 1089 } 1090 1091 } catch (FileNotFoundException e) { 1092 // missing policy is okay, probably first boot 1093 upgradeLegacyBackgroundData(); 1094 } catch (IOException e) { 1095 Log.wtf(TAG, "problem reading network policy", e); 1096 } catch (XmlPullParserException e) { 1097 Log.wtf(TAG, "problem reading network policy", e); 1098 } finally { 1099 IoUtils.closeQuietly(fis); 1100 } 1101 } 1102 1103 /** 1104 * Upgrade legacy background data flags, notifying listeners of one last 1105 * change to always-true. 1106 */ 1107 private void upgradeLegacyBackgroundData() { 1108 mRestrictBackground = Settings.Secure.getInt( 1109 mContext.getContentResolver(), Settings.Secure.BACKGROUND_DATA, 1) != 1; 1110 1111 // kick off one last broadcast if restricted 1112 if (mRestrictBackground) { 1113 final Intent broadcast = new Intent( 1114 ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); 1115 mContext.sendBroadcast(broadcast); 1116 } 1117 } 1118 1119 private void writePolicyLocked() { 1120 if (LOGV) Slog.v(TAG, "writePolicyLocked()"); 1121 1122 FileOutputStream fos = null; 1123 try { 1124 fos = mPolicyFile.startWrite(); 1125 1126 XmlSerializer out = new FastXmlSerializer(); 1127 out.setOutput(fos, "utf-8"); 1128 out.startDocument(null, true); 1129 1130 out.startTag(null, TAG_POLICY_LIST); 1131 writeIntAttribute(out, ATTR_VERSION, VERSION_LATEST); 1132 writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground); 1133 1134 // write all known network policies 1135 for (NetworkPolicy policy : mNetworkPolicy.values()) { 1136 final NetworkTemplate template = policy.template; 1137 1138 out.startTag(null, TAG_NETWORK_POLICY); 1139 writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule()); 1140 final String subscriberId = template.getSubscriberId(); 1141 if (subscriberId != null) { 1142 out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId); 1143 } 1144 final String networkId = template.getNetworkId(); 1145 if (networkId != null) { 1146 out.attribute(null, ATTR_NETWORK_ID, networkId); 1147 } 1148 writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay); 1149 out.attribute(null, ATTR_CYCLE_TIMEZONE, policy.cycleTimezone); 1150 writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes); 1151 writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes); 1152 writeLongAttribute(out, ATTR_LAST_WARNING_SNOOZE, policy.lastWarningSnooze); 1153 writeLongAttribute(out, ATTR_LAST_LIMIT_SNOOZE, policy.lastLimitSnooze); 1154 writeBooleanAttribute(out, ATTR_METERED, policy.metered); 1155 writeBooleanAttribute(out, ATTR_INFERRED, policy.inferred); 1156 out.endTag(null, TAG_NETWORK_POLICY); 1157 } 1158 1159 // write all known uid policies 1160 for (int i = 0; i < mAppPolicy.size(); i++) { 1161 final int appId = mAppPolicy.keyAt(i); 1162 final int policy = mAppPolicy.valueAt(i); 1163 1164 // skip writing empty policies 1165 if (policy == POLICY_NONE) continue; 1166 1167 out.startTag(null, TAG_APP_POLICY); 1168 writeIntAttribute(out, ATTR_APP_ID, appId); 1169 writeIntAttribute(out, ATTR_POLICY, policy); 1170 out.endTag(null, TAG_APP_POLICY); 1171 } 1172 1173 out.endTag(null, TAG_POLICY_LIST); 1174 out.endDocument(); 1175 1176 mPolicyFile.finishWrite(fos); 1177 } catch (IOException e) { 1178 if (fos != null) { 1179 mPolicyFile.failWrite(fos); 1180 } 1181 } 1182 } 1183 1184 @Override 1185 public void setAppPolicy(int appId, int policy) { 1186 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 1187 1188 if (!UserId.isApp(appId)) { 1189 throw new IllegalArgumentException("cannot apply policy to appId " + appId); 1190 } 1191 1192 setAppPolicyUnchecked(appId, policy, true); 1193 } 1194 1195 private void setAppPolicyUnchecked(int appId, int policy, boolean persist) { 1196 final int oldPolicy; 1197 synchronized (mRulesLock) { 1198 oldPolicy = getAppPolicy(appId); 1199 mAppPolicy.put(appId, policy); 1200 1201 // uid policy changed, recompute rules and persist policy. 1202 updateRulesForAppLocked(appId); 1203 if (persist) { 1204 writePolicyLocked(); 1205 } 1206 } 1207 } 1208 1209 @Override 1210 public int getAppPolicy(int appId) { 1211 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 1212 1213 synchronized (mRulesLock) { 1214 return mAppPolicy.get(appId, POLICY_NONE); 1215 } 1216 } 1217 1218 @Override 1219 public void registerListener(INetworkPolicyListener listener) { 1220 // TODO: create permission for observing network policy 1221 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1222 1223 mListeners.register(listener); 1224 1225 // TODO: consider dispatching existing rules to new listeners 1226 } 1227 1228 @Override 1229 public void unregisterListener(INetworkPolicyListener listener) { 1230 // TODO: create permission for observing network policy 1231 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); 1232 1233 mListeners.unregister(listener); 1234 } 1235 1236 @Override 1237 public void setNetworkPolicies(NetworkPolicy[] policies) { 1238 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 1239 1240 maybeRefreshTrustedTime(); 1241 synchronized (mRulesLock) { 1242 mNetworkPolicy.clear(); 1243 for (NetworkPolicy policy : policies) { 1244 mNetworkPolicy.put(policy.template, policy); 1245 } 1246 1247 updateNetworkEnabledLocked(); 1248 updateNetworkRulesLocked(); 1249 updateNotificationsLocked(); 1250 writePolicyLocked(); 1251 } 1252 } 1253 1254 @Override 1255 public NetworkPolicy[] getNetworkPolicies() { 1256 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 1257 mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG); 1258 1259 synchronized (mRulesLock) { 1260 return mNetworkPolicy.values().toArray(new NetworkPolicy[mNetworkPolicy.size()]); 1261 } 1262 } 1263 1264 @Override 1265 public void snoozeLimit(NetworkTemplate template) { 1266 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 1267 performSnooze(template, TYPE_LIMIT); 1268 } 1269 1270 private void performSnooze(NetworkTemplate template, int type) { 1271 maybeRefreshTrustedTime(); 1272 final long currentTime = currentTimeMillis(); 1273 synchronized (mRulesLock) { 1274 // find and snooze local policy that matches 1275 final NetworkPolicy policy = mNetworkPolicy.get(template); 1276 if (policy == null) { 1277 throw new IllegalArgumentException("unable to find policy for " + template); 1278 } 1279 1280 switch (type) { 1281 case TYPE_WARNING: 1282 policy.lastWarningSnooze = currentTime; 1283 break; 1284 case TYPE_LIMIT: 1285 policy.lastLimitSnooze = currentTime; 1286 break; 1287 default: 1288 throw new IllegalArgumentException("unexpected type"); 1289 } 1290 1291 updateNetworkEnabledLocked(); 1292 updateNetworkRulesLocked(); 1293 updateNotificationsLocked(); 1294 writePolicyLocked(); 1295 } 1296 } 1297 1298 @Override 1299 public void setRestrictBackground(boolean restrictBackground) { 1300 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 1301 1302 maybeRefreshTrustedTime(); 1303 synchronized (mRulesLock) { 1304 mRestrictBackground = restrictBackground; 1305 updateRulesForRestrictBackgroundLocked(); 1306 updateNotificationsLocked(); 1307 writePolicyLocked(); 1308 } 1309 1310 mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0) 1311 .sendToTarget(); 1312 } 1313 1314 @Override 1315 public boolean getRestrictBackground() { 1316 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 1317 1318 synchronized (mRulesLock) { 1319 return mRestrictBackground; 1320 } 1321 } 1322 1323 private NetworkPolicy findPolicyForNetworkLocked(NetworkIdentity ident) { 1324 for (NetworkPolicy policy : mNetworkPolicy.values()) { 1325 if (policy.template.matches(ident)) { 1326 return policy; 1327 } 1328 } 1329 return null; 1330 } 1331 1332 @Override 1333 public NetworkQuotaInfo getNetworkQuotaInfo(NetworkState state) { 1334 mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG); 1335 1336 // only returns usage summary, so we don't require caller to have 1337 // READ_NETWORK_USAGE_HISTORY. 1338 final long token = Binder.clearCallingIdentity(); 1339 try { 1340 return getNetworkQuotaInfoUnchecked(state); 1341 } finally { 1342 Binder.restoreCallingIdentity(token); 1343 } 1344 } 1345 1346 private NetworkQuotaInfo getNetworkQuotaInfoUnchecked(NetworkState state) { 1347 final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state); 1348 1349 final NetworkPolicy policy; 1350 synchronized (mRulesLock) { 1351 policy = findPolicyForNetworkLocked(ident); 1352 } 1353 1354 if (policy == null || !policy.hasCycle()) { 1355 // missing policy means we can't derive useful quota info 1356 return null; 1357 } 1358 1359 final long currentTime = currentTimeMillis(); 1360 1361 // find total bytes used under policy 1362 final long start = computeLastCycleBoundary(currentTime, policy); 1363 final long end = currentTime; 1364 final long totalBytes = getTotalBytes(policy.template, start, end); 1365 1366 // report soft and hard limits under policy 1367 final long softLimitBytes = policy.warningBytes != WARNING_DISABLED ? policy.warningBytes 1368 : NetworkQuotaInfo.NO_LIMIT; 1369 final long hardLimitBytes = policy.limitBytes != LIMIT_DISABLED ? policy.limitBytes 1370 : NetworkQuotaInfo.NO_LIMIT; 1371 1372 return new NetworkQuotaInfo(totalBytes, softLimitBytes, hardLimitBytes); 1373 } 1374 1375 @Override 1376 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 1377 mContext.enforceCallingOrSelfPermission(DUMP, TAG); 1378 1379 final IndentingPrintWriter fout = new IndentingPrintWriter(writer, " "); 1380 1381 final HashSet<String> argSet = new HashSet<String>(); 1382 for (String arg : args) { 1383 argSet.add(arg); 1384 } 1385 1386 synchronized (mRulesLock) { 1387 if (argSet.contains("--unsnooze")) { 1388 for (NetworkPolicy policy : mNetworkPolicy.values()) { 1389 policy.clearSnooze(); 1390 } 1391 1392 updateNetworkEnabledLocked(); 1393 updateNetworkRulesLocked(); 1394 updateNotificationsLocked(); 1395 writePolicyLocked(); 1396 1397 fout.println("Cleared snooze timestamps"); 1398 return; 1399 } 1400 1401 fout.print("Restrict background: "); fout.println(mRestrictBackground); 1402 fout.println("Network policies:"); 1403 fout.increaseIndent(); 1404 for (NetworkPolicy policy : mNetworkPolicy.values()) { 1405 fout.println(policy.toString()); 1406 } 1407 fout.decreaseIndent(); 1408 1409 fout.println("Policy for apps:"); 1410 fout.increaseIndent(); 1411 int size = mAppPolicy.size(); 1412 for (int i = 0; i < size; i++) { 1413 final int appId = mAppPolicy.keyAt(i); 1414 final int policy = mAppPolicy.valueAt(i); 1415 fout.print("appId="); 1416 fout.print(appId); 1417 fout.print(" policy="); 1418 dumpPolicy(fout, policy); 1419 fout.println(); 1420 } 1421 fout.decreaseIndent(); 1422 1423 final SparseBooleanArray knownUids = new SparseBooleanArray(); 1424 collectKeys(mUidForeground, knownUids); 1425 collectKeys(mUidRules, knownUids); 1426 1427 fout.println("Status for known UIDs:"); 1428 fout.increaseIndent(); 1429 size = knownUids.size(); 1430 for (int i = 0; i < size; i++) { 1431 final int uid = knownUids.keyAt(i); 1432 fout.print("UID="); 1433 fout.print(uid); 1434 1435 fout.print(" foreground="); 1436 final int foregroundIndex = mUidPidForeground.indexOfKey(uid); 1437 if (foregroundIndex < 0) { 1438 fout.print("UNKNOWN"); 1439 } else { 1440 dumpSparseBooleanArray(fout, mUidPidForeground.valueAt(foregroundIndex)); 1441 } 1442 1443 fout.print(" rules="); 1444 final int rulesIndex = mUidRules.indexOfKey(uid); 1445 if (rulesIndex < 0) { 1446 fout.print("UNKNOWN"); 1447 } else { 1448 dumpRules(fout, mUidRules.valueAt(rulesIndex)); 1449 } 1450 1451 fout.println(); 1452 } 1453 fout.decreaseIndent(); 1454 } 1455 } 1456 1457 @Override 1458 public boolean isUidForeground(int uid) { 1459 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); 1460 1461 synchronized (mRulesLock) { 1462 // only really in foreground when screen is also on 1463 return mUidForeground.get(uid, false) && mScreenOn; 1464 } 1465 } 1466 1467 /** 1468 * Foreground for PID changed; recompute foreground at UID level. If 1469 * changed, will trigger {@link #updateRulesForUidLocked(int)}. 1470 */ 1471 private void computeUidForegroundLocked(int uid) { 1472 final SparseBooleanArray pidForeground = mUidPidForeground.get(uid); 1473 1474 // current pid is dropping foreground; examine other pids 1475 boolean uidForeground = false; 1476 final int size = pidForeground.size(); 1477 for (int i = 0; i < size; i++) { 1478 if (pidForeground.valueAt(i)) { 1479 uidForeground = true; 1480 break; 1481 } 1482 } 1483 1484 final boolean oldUidForeground = mUidForeground.get(uid, false); 1485 if (oldUidForeground != uidForeground) { 1486 // foreground changed, push updated rules 1487 mUidForeground.put(uid, uidForeground); 1488 updateRulesForUidLocked(uid); 1489 } 1490 } 1491 1492 private void updateScreenOn() { 1493 synchronized (mRulesLock) { 1494 try { 1495 mScreenOn = mPowerManager.isScreenOn(); 1496 } catch (RemoteException e) { 1497 // ignored; service lives in system_server 1498 } 1499 updateRulesForScreenLocked(); 1500 } 1501 } 1502 1503 /** 1504 * Update rules that might be changed by {@link #mScreenOn} value. 1505 */ 1506 private void updateRulesForScreenLocked() { 1507 // only update rules for anyone with foreground activities 1508 final int size = mUidForeground.size(); 1509 for (int i = 0; i < size; i++) { 1510 if (mUidForeground.valueAt(i)) { 1511 final int uid = mUidForeground.keyAt(i); 1512 updateRulesForUidLocked(uid); 1513 } 1514 } 1515 } 1516 1517 /** 1518 * Update rules that might be changed by {@link #mRestrictBackground} value. 1519 */ 1520 private void updateRulesForRestrictBackgroundLocked() { 1521 // update rules for all installed applications 1522 final PackageManager pm = mContext.getPackageManager(); 1523 final List<ApplicationInfo> apps = pm.getInstalledApplications(0); 1524 for (ApplicationInfo app : apps) { 1525 final int appId = UserId.getAppId(app.uid); 1526 updateRulesForAppLocked(appId); 1527 } 1528 1529 // and catch system UIDs 1530 // TODO: keep in sync with android_filesystem_config.h 1531 for (int uid = 1000; uid <= 1025; uid++) { 1532 updateRulesForUidLocked(uid); 1533 } 1534 for (int uid = 2000; uid <= 2002; uid++) { 1535 updateRulesForUidLocked(uid); 1536 } 1537 for (int uid = 3000; uid <= 3007; uid++) { 1538 updateRulesForUidLocked(uid); 1539 } 1540 for (int uid = 9998; uid <= 9999; uid++) { 1541 updateRulesForUidLocked(uid); 1542 } 1543 } 1544 1545 private void updateRulesForAppLocked(int appId) { 1546 for (UserInfo user : mContext.getPackageManager().getUsers()) { 1547 final int uid = UserId.getUid(user.id, appId); 1548 updateRulesForUidLocked(uid); 1549 } 1550 } 1551 1552 private void updateRulesForUidLocked(int uid) { 1553 final int appId = UserId.getAppId(uid); 1554 final int appPolicy = getAppPolicy(appId); 1555 final boolean uidForeground = isUidForeground(uid); 1556 1557 // derive active rules based on policy and active state 1558 int uidRules = RULE_ALLOW_ALL; 1559 if (!uidForeground && (appPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) { 1560 // uid in background, and policy says to block metered data 1561 uidRules = RULE_REJECT_METERED; 1562 } 1563 if (!uidForeground && mRestrictBackground) { 1564 // uid in background, and global background disabled 1565 uidRules = RULE_REJECT_METERED; 1566 } 1567 1568 // TODO: only dispatch when rules actually change 1569 1570 if (uidRules == RULE_ALLOW_ALL) { 1571 mUidRules.delete(uid); 1572 } else { 1573 mUidRules.put(uid, uidRules); 1574 } 1575 1576 final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0; 1577 setUidNetworkRules(uid, rejectMetered); 1578 1579 // dispatch changed rule to existing listeners 1580 mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget(); 1581 1582 try { 1583 // adjust stats accounting based on foreground status 1584 mNetworkStats.setUidForeground(uid, uidForeground); 1585 } catch (RemoteException e) { 1586 // ignored; service lives in system_server 1587 } 1588 } 1589 1590 private Handler.Callback mHandlerCallback = new Handler.Callback() { 1591 /** {@inheritDoc} */ 1592 public boolean handleMessage(Message msg) { 1593 switch (msg.what) { 1594 case MSG_RULES_CHANGED: { 1595 final int uid = msg.arg1; 1596 final int uidRules = msg.arg2; 1597 final int length = mListeners.beginBroadcast(); 1598 for (int i = 0; i < length; i++) { 1599 final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); 1600 if (listener != null) { 1601 try { 1602 listener.onUidRulesChanged(uid, uidRules); 1603 } catch (RemoteException e) { 1604 } 1605 } 1606 } 1607 mListeners.finishBroadcast(); 1608 return true; 1609 } 1610 case MSG_METERED_IFACES_CHANGED: { 1611 final String[] meteredIfaces = (String[]) msg.obj; 1612 final int length = mListeners.beginBroadcast(); 1613 for (int i = 0; i < length; i++) { 1614 final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); 1615 if (listener != null) { 1616 try { 1617 listener.onMeteredIfacesChanged(meteredIfaces); 1618 } catch (RemoteException e) { 1619 } 1620 } 1621 } 1622 mListeners.finishBroadcast(); 1623 return true; 1624 } 1625 case MSG_FOREGROUND_ACTIVITIES_CHANGED: { 1626 final int pid = msg.arg1; 1627 final int uid = msg.arg2; 1628 final boolean foregroundActivities = (Boolean) msg.obj; 1629 1630 synchronized (mRulesLock) { 1631 // because a uid can have multiple pids running inside, we need to 1632 // remember all pid states and summarize foreground at uid level. 1633 1634 // record foreground for this specific pid 1635 SparseBooleanArray pidForeground = mUidPidForeground.get(uid); 1636 if (pidForeground == null) { 1637 pidForeground = new SparseBooleanArray(2); 1638 mUidPidForeground.put(uid, pidForeground); 1639 } 1640 pidForeground.put(pid, foregroundActivities); 1641 computeUidForegroundLocked(uid); 1642 } 1643 return true; 1644 } 1645 case MSG_PROCESS_DIED: { 1646 final int pid = msg.arg1; 1647 final int uid = msg.arg2; 1648 1649 synchronized (mRulesLock) { 1650 // clear records and recompute, when they exist 1651 final SparseBooleanArray pidForeground = mUidPidForeground.get(uid); 1652 if (pidForeground != null) { 1653 pidForeground.delete(pid); 1654 computeUidForegroundLocked(uid); 1655 } 1656 } 1657 return true; 1658 } 1659 case MSG_LIMIT_REACHED: { 1660 final String iface = (String) msg.obj; 1661 1662 maybeRefreshTrustedTime(); 1663 synchronized (mRulesLock) { 1664 if (mMeteredIfaces.contains(iface)) { 1665 try { 1666 // force stats update to make sure we have 1667 // numbers that caused alert to trigger. 1668 mNetworkStats.forceUpdate(); 1669 } catch (RemoteException e) { 1670 // ignored; service lives in system_server 1671 } 1672 1673 updateNetworkEnabledLocked(); 1674 updateNotificationsLocked(); 1675 } 1676 } 1677 return true; 1678 } 1679 case MSG_RESTRICT_BACKGROUND_CHANGED: { 1680 final boolean restrictBackground = msg.arg1 != 0; 1681 final int length = mListeners.beginBroadcast(); 1682 for (int i = 0; i < length; i++) { 1683 final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); 1684 if (listener != null) { 1685 try { 1686 listener.onRestrictBackgroundChanged(restrictBackground); 1687 } catch (RemoteException e) { 1688 } 1689 } 1690 } 1691 mListeners.finishBroadcast(); 1692 } 1693 default: { 1694 return false; 1695 } 1696 } 1697 } 1698 }; 1699 1700 private void setInterfaceQuota(String iface, long quotaBytes) { 1701 try { 1702 mNetworkManager.setInterfaceQuota(iface, quotaBytes); 1703 } catch (IllegalStateException e) { 1704 Log.wtf(TAG, "problem setting interface quota", e); 1705 } catch (RemoteException e) { 1706 // ignored; service lives in system_server 1707 } 1708 } 1709 1710 private void removeInterfaceQuota(String iface) { 1711 try { 1712 mNetworkManager.removeInterfaceQuota(iface); 1713 } catch (IllegalStateException e) { 1714 Log.wtf(TAG, "problem removing interface quota", e); 1715 } catch (RemoteException e) { 1716 // ignored; service lives in system_server 1717 } 1718 } 1719 1720 private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) { 1721 try { 1722 mNetworkManager.setUidNetworkRules(uid, rejectOnQuotaInterfaces); 1723 } catch (IllegalStateException e) { 1724 Log.wtf(TAG, "problem setting uid rules", e); 1725 } catch (RemoteException e) { 1726 // ignored; service lives in system_server 1727 } 1728 } 1729 1730 /** 1731 * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}. 1732 */ 1733 private void setPolicyDataEnable(int networkType, boolean enabled) { 1734 try { 1735 mConnManager.setPolicyDataEnable(networkType, enabled); 1736 } catch (RemoteException e) { 1737 // ignored; service lives in system_server 1738 } 1739 } 1740 1741 private long getTotalBytes(NetworkTemplate template, long start, long end) { 1742 try { 1743 return mNetworkStats.getSummaryForNetwork(template, start, end).getTotalBytes(); 1744 } catch (RuntimeException e) { 1745 Slog.w(TAG, "problem reading network stats: " + e); 1746 return 0; 1747 } catch (RemoteException e) { 1748 // ignored; service lives in system_server 1749 return 0; 1750 } 1751 } 1752 1753 /** 1754 * Try refreshing {@link #mTime} when stale. 1755 */ 1756 private void maybeRefreshTrustedTime() { 1757 if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) { 1758 mTime.forceRefresh(); 1759 } 1760 } 1761 1762 private long currentTimeMillis() { 1763 return mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); 1764 } 1765 1766 private static Intent buildAllowBackgroundDataIntent() { 1767 return new Intent(ACTION_ALLOW_BACKGROUND); 1768 } 1769 1770 private static Intent buildSnoozeWarningIntent(NetworkTemplate template) { 1771 final Intent intent = new Intent(ACTION_SNOOZE_WARNING); 1772 intent.putExtra(EXTRA_NETWORK_TEMPLATE, template); 1773 return intent; 1774 } 1775 1776 private static Intent buildNetworkOverLimitIntent(NetworkTemplate template) { 1777 final Intent intent = new Intent(); 1778 intent.setComponent(new ComponentName( 1779 "com.android.systemui", "com.android.systemui.net.NetworkOverLimitActivity")); 1780 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1781 intent.putExtra(EXTRA_NETWORK_TEMPLATE, template); 1782 return intent; 1783 } 1784 1785 private static Intent buildViewDataUsageIntent(NetworkTemplate template) { 1786 final Intent intent = new Intent(); 1787 intent.setComponent(new ComponentName( 1788 "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity")); 1789 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1790 intent.putExtra(EXTRA_NETWORK_TEMPLATE, template); 1791 return intent; 1792 } 1793 1794 // @VisibleForTesting 1795 public void addIdleHandler(IdleHandler handler) { 1796 mHandler.getLooper().getQueue().addIdleHandler(handler); 1797 } 1798 1799 public static boolean isAirplaneModeOn(Context context) { 1800 return Settings.System.getInt( 1801 context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0; 1802 } 1803 1804 private static void collectKeys(SparseIntArray source, SparseBooleanArray target) { 1805 final int size = source.size(); 1806 for (int i = 0; i < size; i++) { 1807 target.put(source.keyAt(i), true); 1808 } 1809 } 1810 1811 private static void collectKeys(SparseBooleanArray source, SparseBooleanArray target) { 1812 final int size = source.size(); 1813 for (int i = 0; i < size; i++) { 1814 target.put(source.keyAt(i), true); 1815 } 1816 } 1817 1818 private static void dumpSparseBooleanArray(PrintWriter fout, SparseBooleanArray value) { 1819 fout.print("["); 1820 final int size = value.size(); 1821 for (int i = 0; i < size; i++) { 1822 fout.print(value.keyAt(i) + "=" + value.valueAt(i)); 1823 if (i < size - 1) fout.print(","); 1824 } 1825 fout.print("]"); 1826 } 1827 1828 public static class XmlUtils { 1829 public static int readIntAttribute(XmlPullParser in, String name) throws IOException { 1830 final String value = in.getAttributeValue(null, name); 1831 try { 1832 return Integer.parseInt(value); 1833 } catch (NumberFormatException e) { 1834 throw new ProtocolException("problem parsing " + name + "=" + value + " as int"); 1835 } 1836 } 1837 1838 public static void writeIntAttribute(XmlSerializer out, String name, int value) 1839 throws IOException { 1840 out.attribute(null, name, Integer.toString(value)); 1841 } 1842 1843 public static long readLongAttribute(XmlPullParser in, String name) throws IOException { 1844 final String value = in.getAttributeValue(null, name); 1845 try { 1846 return Long.parseLong(value); 1847 } catch (NumberFormatException e) { 1848 throw new ProtocolException("problem parsing " + name + "=" + value + " as long"); 1849 } 1850 } 1851 1852 public static void writeLongAttribute(XmlSerializer out, String name, long value) 1853 throws IOException { 1854 out.attribute(null, name, Long.toString(value)); 1855 } 1856 1857 public static boolean readBooleanAttribute(XmlPullParser in, String name) { 1858 final String value = in.getAttributeValue(null, name); 1859 return Boolean.parseBoolean(value); 1860 } 1861 1862 public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value) 1863 throws IOException { 1864 out.attribute(null, name, Boolean.toString(value)); 1865 } 1866 } 1867} 1868